QUEUE.CPP 185 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /counterstrike/QUEUE.CPP 6 3/14/97 5:12p Steve_tall $ */
  19. /***************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * File Name : QUEUE.CPP *
  25. * *
  26. * Programmer : Bill R. Randolph *
  27. * *
  28. * Start Date : 11/28/95 *
  29. * *
  30. * Last Update : October 14, 1996 [BRR] *
  31. * *
  32. *-------------------------------------------------------------------------*
  33. * Functions for Queueing Events: *
  34. * Queue_Mission -- Queue a mega mission event. *
  35. * Queue_Options -- Queue the options event. *
  36. * Queue_Exit -- Add the exit game event to the queue. *
  37. * *
  38. * Functions for processing Queued Events: *
  39. * Queue_AI -- Process all queued events. *
  40. * Queue_AI_Normal -- Process all queued events. *
  41. * Queue_AI_Multiplayer -- Process all queued events. *
  42. * *
  43. * Main Multiplayer Queue Logic: *
  44. * Wait_For_Players -- Waits for other systems to come on-line *
  45. * Generate_Timing_Event -- computes & queues a RESPONSE_TIME event *
  46. * Process_Send_Period -- timing for sending packets every 'n' frames *
  47. * Send_Packets -- sends out events from the OutList *
  48. * Send_FrameSync -- Sends a FRAMESYNC packet *
  49. * Process_Receive_Packet -- processes an incoming packet *
  50. * Process_Serial_Packet -- Handles an incoming serial packet *
  51. * Can_Advance -- determines if it's OK to advance to the next frame *
  52. * Process_Reconnect_Dialog -- processes the reconnection dialog *
  53. * Handle_Timeout -- attempts to reconnect; if fails, bails. *
  54. * Stop_Game -- stops the game *
  55. * *
  56. * Packet Compression / Decompression: *
  57. * Build_Send_Packet -- Builds a big packet from a bunch of little ones. *
  58. * Add_Uncompressed_Events -- adds uncompressed events to a packet *
  59. * Add_Compressed_Events -- adds compressed events to a packet *
  60. * Breakup_Receive_Packet -- Splits a big packet into little ones. *
  61. * Extract_Uncompressed_Events -- extracts events from a packet *
  62. * Extract_Compressed_Events -- extracts events from a packet *
  63. * *
  64. * DoList Management: *
  65. * Execute_DoList -- Executes commands from the DoList *
  66. * Clean_DoList -- Cleans out old events from the DoList *
  67. * Queue_Record -- Records the DoList to disk *
  68. * Queue_Playback -- plays back queue entries from a record file *
  69. * *
  70. * Debugging: *
  71. * Compute_Game_CRC -- Computes a CRC value of the entire game. *
  72. * Add_CRC -- Adds a value to a CRC *
  73. * Print_CRCs -- Prints a data file for finding Sync Bugs *
  74. * Init_Queue_Mono -- inits mono display *
  75. * Update_Queue_Mono -- updates mono display *
  76. * Print_Framesync_Values -- displays frame-sync variables *
  77. * Check_Mirror -- Checks mirror memory *
  78. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  79. #include "function.h"
  80. #ifdef WOLAPI_INTEGRATION
  81. //#include "WolDebug.h"
  82. #include "WolapiOb.h"
  83. extern WolapiObject* pWolapi;
  84. bool bReconnectDialogCancelled;
  85. #endif
  86. /********************************** Defines *********************************/
  87. #define SHOW_MONO 0
  88. /********************************** Globals *********************************/
  89. //---------------------------------------------------------------------------
  90. // GameCRC is the current computed CRC value for this frame.
  91. // CRC[] is a record of our last 32 game CRC's.
  92. // ColorNames is for debug output in Print_CRCs
  93. //---------------------------------------------------------------------------
  94. static unsigned long GameCRC;
  95. static unsigned long CRC[32] =
  96. {0,0,0,0,0,0,0,0,0,0,
  97. 0,0,0,0,0,0,0,0,0,0,
  98. 0,0,0,0,0,0,0,0,0,0,
  99. 0,0};
  100. static char *ColorNames[8] = {
  101. "Yellow",
  102. "LtBlue",
  103. "Red",
  104. "Green",
  105. "Orange",
  106. "Grey",
  107. "Blue",
  108. "Brown"
  109. };
  110. //...........................................................................
  111. // Mono debugging variables:
  112. // NetMonoMode: 0 = show connection output, 1 = flowcount output
  113. // NewMonoMode: set by anything that toggles NetMonoMode; re-inits screen
  114. // IsMono: used for taking control of Mono screen away from the engine
  115. //...........................................................................
  116. int NetMonoMode = 1;
  117. int NewMonoMode = 1;
  118. static int IsMono = 0;
  119. //---------------------------------------------------------------------------
  120. // Several routines return various codes; here's an enum for all of them.
  121. //---------------------------------------------------------------------------
  122. typedef enum RetcodeEnum {
  123. RC_NORMAL, // no news is good news
  124. RC_PLAYER_READY, // a new player has been heard from
  125. RC_SCENARIO_MISMATCH, // scenario mismatch
  126. RC_DOLIST_FULL, // DoList is full
  127. RC_SERIAL_PROCESSED, // modem: SERIAL packet was processed
  128. RC_PLAYER_LEFT, // modem: other player left the game
  129. RC_HUNG_UP, // modem has hung up
  130. RC_NOT_RESPONDING, // other player not responding (timeout/hung up)
  131. RC_CANCEL, // user cancelled
  132. } RetcodeType;
  133. #ifdef FIXIT_CSII // checked - ajw 9/28/98
  134. extern void Enable_Secret_Units(void);
  135. #endif
  136. /********************************* Prototypes *******************************/
  137. //...........................................................................
  138. // Main multiplayer queue logic
  139. //...........................................................................
  140. static void Queue_AI_Normal(void);
  141. static void Queue_AI_Multiplayer(void);
  142. static RetcodeType Wait_For_Players(int first_time, ConnManClass *net,
  143. int resend_delta, int dialog_time, int timeout, char *multi_packet_buf,
  144. int my_sent, long *their_frame, unsigned short *their_sent,
  145. unsigned short *their_recv);
  146. static void Generate_Timing_Event(ConnManClass *net, int my_sent);
  147. static void Generate_Real_Timing_Event(ConnManClass *net, int my_sent);
  148. static void Generate_Process_Time_Event(ConnManClass *net);
  149. static int Process_Send_Period(ConnManClass *net); //, int init);
  150. static int Send_Packets(ConnManClass *net, char *multi_packet_buf,
  151. int multi_packet_max, int max_ahead, int my_sent);
  152. static void Send_FrameSync(ConnManClass *net, int cmd_count);
  153. static RetcodeType Process_Receive_Packet(ConnManClass *net,
  154. char *multi_packet_buf, int id, int packetlen, long *their_frame,
  155. unsigned short *their_sent, unsigned short *their_recv);
  156. static RetcodeType Process_Serial_Packet(char *multi_packet_buf,
  157. int first_time);
  158. static int Can_Advance(ConnManClass *net, int max_ahead, long *their_frame,
  159. unsigned short *their_sent, unsigned short *their_recv);
  160. static int Process_Reconnect_Dialog(CDTimerClass<SystemTimerClass> *timeout_timer,
  161. long *their_frame, int num_conn, int reconn, int fresh);
  162. static int Handle_Timeout(ConnManClass *net, long *their_frame,
  163. unsigned short *their_sent, unsigned short *their_recv);
  164. static void Stop_Game(void);
  165. //...........................................................................
  166. // Packet compression/decompression:
  167. //...........................................................................
  168. static int Build_Send_Packet(void *buf, int bufsize, int frame_delay,
  169. int num_cmds, int cap);
  170. int Add_Uncompressed_Events(void *buf, int bufsize, int frame_delay, int size,
  171. int cap);
  172. int Add_Compressed_Events(void *buf, int bufsize, int frame_delay, int size,
  173. int cap);
  174. static int Breakup_Receive_Packet(void *buf, int bufsize );
  175. int Extract_Uncompressed_Events(void *buf, int bufsize);
  176. int Extract_Compressed_Events(void *buf, int bufsize);
  177. //...........................................................................
  178. // DoList management:
  179. //...........................................................................
  180. static int Execute_DoList(int max_houses, HousesType base_house,
  181. ConnManClass *net, CDTimerClass<FrameTimerClass> *skip_crc,
  182. // ConnManClass *net, TCountDownTimerClass *skip_crc,
  183. long *their_frame, unsigned short *their_sent, unsigned short *their_recv);
  184. static void Clean_DoList(ConnManClass *net);
  185. static void Queue_Record(void);
  186. static void Queue_Playback(void);
  187. //...........................................................................
  188. // Debugging:
  189. //...........................................................................
  190. static void Compute_Game_CRC(void);
  191. void Add_CRC(unsigned long *crc, unsigned long val);
  192. static void Print_CRCs(EventClass *ev);
  193. static void Init_Queue_Mono(ConnManClass *net);
  194. static void Update_Queue_Mono(ConnManClass *net, int flow_index);
  195. static void Print_Framesync_Values(long curframe, unsigned long max_ahead,
  196. int num_connections, unsigned short *their_recv,
  197. unsigned short *their_sent, unsigned short my_sent);
  198. extern void Keyboard_Process(KeyNumType &input);
  199. void Dump_Packet_Too_Late_Stuff(EventClass *event, ConnManClass *net,
  200. long *their_frame, unsigned short *their_sent, unsigned short *their_recv);
  201. void Check_Mirror(void);
  202. /***************************************************************************
  203. * Queue_Mission -- Queue a mega mission event. *
  204. * *
  205. * This routine is called when the player causes a change to a game unit. *
  206. * The event that initiates the change is queued to as a result of a call *
  207. * to this routine. *
  208. * *
  209. * INPUT: *
  210. * whom Whom this mission request applies to (a friendly unit). *
  211. * mission The mission to assign to this object. *
  212. * target The target of this mission (if any). *
  213. * dest The movement destination for this mission (if any). *
  214. * *
  215. * OUTPUT: *
  216. * Was the mission request queued successfully? *
  217. * *
  218. * WARNINGS: *
  219. * none. *
  220. * *
  221. * HISTORY: *
  222. * 09/21/1995 JLB : Created. *
  223. *=========================================================================*/
  224. bool Queue_Mission(TargetClass whom, MissionType mission, TARGET target, TARGET destination)
  225. {
  226. if (! OutList.Add(EventClass(whom, mission, TargetClass(target), TargetClass(destination)))) {
  227. return(false);
  228. } else {
  229. return(true);
  230. }
  231. }
  232. /***********************************************************************************************
  233. * Queue_Mission -- Queue a mega mission event, formation override for common speed. *
  234. * *
  235. * This routine is called when the player causes a change to a game unit. The event that *
  236. * initiates the change is queued to as a result of a call to this routine. *
  237. * *
  238. * INPUT: whom -- Whom this mission request applies to (a friendly unit). *
  239. * *
  240. * mission -- The mission to assign to this object. *
  241. * *
  242. * target -- The target of this mission (if any). *
  243. * *
  244. * dest -- The movement destination for this mission (if any). *
  245. * *
  246. * speed -- The override speed for this unit. *
  247. * *
  248. * maxspeed -- The override maximum speed for this unit. *
  249. * *
  250. * OUTPUT: Was the mission request queued successfully? *
  251. * *
  252. * WARNINGS: none *
  253. * *
  254. * HISTORY: *
  255. * 09/21/1995 JLB : Created. *
  256. *=============================================================================================*/
  257. bool Queue_Mission(TargetClass whom, MissionType mission, TARGET target, TARGET destination, SpeedType speed, MPHType maxspeed)
  258. {
  259. if (! OutList.Add(EventClass(whom, mission, TargetClass(target), TargetClass(destination), speed, maxspeed))) {
  260. return(false);
  261. } else {
  262. return(true);
  263. }
  264. }
  265. /***************************************************************************
  266. * Queue_Options -- Queue the options event. *
  267. * *
  268. * INPUT: *
  269. * none. *
  270. * *
  271. * OUTPUT: *
  272. * Was the options screen event queued successfully? *
  273. * *
  274. * WARNINGS: *
  275. * none. *
  276. * *
  277. * HISTORY: *
  278. * 09/21/1995 JLB : Created. *
  279. *=========================================================================*/
  280. bool Queue_Options(void)
  281. {
  282. if (! OutList.Add(EventClass(EventClass::OPTIONS))) {
  283. return(false);
  284. }
  285. else {
  286. return(true);
  287. }
  288. } /* end of Queue_Options */
  289. /***************************************************************************
  290. * Queue_Exit -- Add the exit game event to the queue. *
  291. * *
  292. * INPUT: *
  293. * none. *
  294. * *
  295. * OUTPUT: *
  296. * Was the exit event queued successfully? *
  297. * *
  298. * WARNINGS: *
  299. * none. *
  300. * *
  301. * HISTORY: *
  302. * 09/21/1995 JLB : Created. *
  303. *=========================================================================*/
  304. bool Queue_Exit(void)
  305. {
  306. if (! OutList.Add(EventClass(EventClass::EXIT))) {
  307. return(false);
  308. }
  309. else {
  310. return(true);
  311. }
  312. } /* end of Queue_Exit */
  313. /***************************************************************************
  314. * Queue_AI -- Process all queued events. *
  315. * *
  316. * INPUT: *
  317. * none. *
  318. * *
  319. * OUTPUT: *
  320. * none. *
  321. * *
  322. * WARNINGS: *
  323. * none. *
  324. * *
  325. * HISTORY: *
  326. * 09/21/1995 JLB : Created. *
  327. *=========================================================================*/
  328. void Queue_AI(void)
  329. {
  330. if (Session.Play) {
  331. Queue_Playback();
  332. }
  333. else {
  334. switch (Session.Type) {
  335. case GAME_SKIRMISH:
  336. case GAME_NORMAL:
  337. Queue_AI_Normal();
  338. break;
  339. case GAME_MODEM:
  340. case GAME_NULL_MODEM:
  341. case GAME_IPX:
  342. case GAME_INTERNET:
  343. case GAME_TEN:
  344. case GAME_MPATH:
  345. Queue_AI_Multiplayer();
  346. break;
  347. }
  348. }
  349. } /* end of Queue_AI */
  350. /***************************************************************************
  351. * Queue_AI_Normal -- Process all queued events. *
  352. * *
  353. * This is the "normal" version of the queue management routine. It does *
  354. * the following: *
  355. * - Transfers items in the OutList to the DoList *
  356. * - Executes any commands in the DoList that are supposed to be done on *
  357. * this frame # *
  358. * - Cleans out the DoList *
  359. * *
  360. * INPUT: *
  361. * none. *
  362. * *
  363. * OUTPUT: *
  364. * none. *
  365. * *
  366. * WARNINGS: *
  367. * none. *
  368. * *
  369. * HISTORY: *
  370. * 09/21/1995 JLB : Created. *
  371. *=========================================================================*/
  372. static void Queue_AI_Normal(void)
  373. {
  374. //------------------------------------------------------------------------
  375. // Move events from the OutList (events generated by this player) into the
  376. // DoList (the list of events to execute).
  377. //------------------------------------------------------------------------
  378. while (OutList.Count) {
  379. OutList.First().IsExecuted = false;
  380. if (!DoList.Add(OutList.First())) {
  381. ;
  382. }
  383. #ifdef MIRROR_QUEUE
  384. MirrorList.Add(OutList.First());
  385. #endif
  386. OutList.Next();
  387. }
  388. //------------------------------------------------------------------------
  389. // Save the DoList to disk, if we're in "Record" mode
  390. //------------------------------------------------------------------------
  391. if (Session.Record) {
  392. Queue_Record();
  393. }
  394. //------------------------------------------------------------------------
  395. // Execute the DoList; if an error occurs, bail out.
  396. //------------------------------------------------------------------------
  397. if (!Execute_DoList(1, PlayerPtr->Class->House, NULL, NULL, NULL,
  398. NULL, NULL)) {
  399. GameActive = 0;
  400. return;
  401. }
  402. //------------------------------------------------------------------------
  403. // Clean out the DoList
  404. //------------------------------------------------------------------------
  405. Clean_DoList(NULL);
  406. } /* end of Queue_AI_Normal */
  407. /***************************************************************************
  408. * Queue_AI_Multiplayer -- Process all queued events. *
  409. * *
  410. * This is the network version of the queue management routine. It does *
  411. * the following: *
  412. * - If this is the 1st frame, waits for other systems to signal ready *
  413. * - Generates a timing event, to allow the connection time to be dynamic *
  414. * - Handles timing related to sending packets every 'n' frames *
  415. * - Sends outgoing events *
  416. * - Frame-syncs to the other systems (see below) *
  417. * - Executes & cleans out the DoList *
  418. * *
  419. * The Frame-Sync'ing logic is the heart & soul of network play. It works *
  420. * by ensuring that any system won't out-run the other system by more than *
  421. * 'Session.MaxAhead' frames; this in turn ensures that a packet's *
  422. * execution frame # won't have been passed by the time that packet is *
  423. * received by all systems. *
  424. * *
  425. * To achieve this, the system must keep track of all other system's *
  426. * current frame #'s; these are stored in an array called 'their_frame[]'. *
  427. * However, because current frame #'s are sent in FRAMEINFO packets, which *
  428. * don't require an ACK, and command packets are sent in packets requiring *
  429. * an ACK, it's possible for a command packet to get lost, and the next *
  430. * frame's FRAMEINFO packet to not get lost; the other system may then *
  431. * advance past the frame # the command is to execute on! So, to prevent *
  432. * this, all FRAMEINFO packets include a CommandCount field. This value *
  433. * tells the other system how many events it should have received by this *
  434. * time. This system can therefore keep track of how many commands it's *
  435. * actually received, and compare it to the CommandCount field, to see if *
  436. * it's missed an event packet. The # of events we've received from each *
  437. * system is stored in 'their_recv[]', and the # events they say they've *
  438. * sent is stored in 'their_sent[]'. *
  439. * *
  440. * Thus, two conditions must be met in order to advance to the next frame: *
  441. * - Our current frame # must be < their_frame + Session.MaxAhead *
  442. * - their_recv[i] must be >= their_sent[i] *
  443. * *
  444. * 'their_frame[] is updated by Process_Receive_Packet() *
  445. * 'their_recv[] is updated by Process_Receive_Packet() *
  446. * 'their_sent[] is updated by Process_Receive_Packet() *
  447. * 'my_sent' is updated by this routine. *
  448. * *
  449. * The order of the arrays their_frame[] etc is the same order the *
  450. * connections are created in. The Sender's ID is passed to *
  451. * Connection_Index() to obtain the array index. *
  452. * *
  453. * The only routines allowed to pop up dialogs are: *
  454. * Wait_For_Players() (only pops up the reconnect dialog) *
  455. * Execute_DoList() (tells if out of sync, or packet recv'd too late) *
  456. * *
  457. * Sign-off's are detected by: *
  458. * - Timing out while waiting for a packet *
  459. * - Detecting that the other player is now at the score screen or *
  460. * connection dialog (serial) *
  461. * - If we see an EventClass::EXIT event on the private channel *
  462. * *
  463. * The current communications protocol, COMM_PROTOCOL_MULTI_E_COMP, has *
  464. * the following properties: *
  465. * - It compresses packets, so that the minimum number of bytes are *
  466. * transmitted. Packets are compressed by extracting all info common to *
  467. * the events into the packet header, and then sending only the bytes *
  468. * relevant to each type of event. For instance, if 100 infantry guys *
  469. * are told to move to the same location, the command itself & the *
  470. * location will be included in the 1st movement command only; after *
  471. * that, there will be a rep count then 99 infantry TARGET numbers, *
  472. * identifying all the infantry told to move. *
  473. * - The protocol also only sends packets out every 'n' frames. This cuts *
  474. * the data rate dramatically. It means that 'Session.MaxAhead' must be *
  475. * divisible by 'n'; also, the minimum value for 'Session.MaxAhead' is *
  476. * 'n * 2', to give both sides some "breathing" room in case a FRAMEINFO *
  477. * packet gets missed. *
  478. * *
  479. * Note: For synchronization-waiting loops (like waiting to hear from all *
  480. * other players, waiting to advance to the next frame, etc), use *
  481. * Net.Num_Connections() rather than Session.NumPlayers; this reflects the *
  482. * actual # of connections, and can be "faked" into playing even when *
  483. * there aren't any other players actually there. A typical example of *
  484. * this is playing back a recorded game. For command-execution loops, use *
  485. * Session.NumPlayers. This ensures all commands get executed, even if *
  486. * there isn't a human generating those commands. *
  487. * *
  488. * The modem works a little differently from the network in this respect: *
  489. * - The connection has to stay "alive" even if the other player exits to *
  490. * the join dialog. This prevents each system from timing out & hanging *
  491. * the modem up. Thus, packets are sent back & forth & just thrown away,*
  492. * but each system knows the other is still there. Messages may be sent *
  493. * between systems, though. *
  494. * - Destroy_Null_Connection doesn't hang up the modem, so *
  495. * Num_Connections() still reports a value of 1 even though the other *
  496. * player has left. *
  497. * - Any waits on Num_Connections() must also check for *
  498. * Session.NumPlayers > 1, to keep from waiting forever if the other *
  499. * guy has left *
  500. * - Packets sent to a player who's left require no ACK *
  501. * *
  502. * INPUT: *
  503. * none. *
  504. * *
  505. * OUTPUT: *
  506. * none. *
  507. * *
  508. * WARNINGS: *
  509. * none. *
  510. * *
  511. * HISTORY: *
  512. * 11/21/1995 BRR : Created. *
  513. *=========================================================================*/
  514. static void Queue_AI_Multiplayer(void)
  515. {
  516. if(Session.Type == GAME_SKIRMISH) return;
  517. //........................................................................
  518. // Enums:
  519. //........................................................................
  520. enum {
  521. MIXFILE_RESEND_DELTA = 120, // ticks b/w resends
  522. MIXFILE_TIMEOUT = 3600*2, // timeout waiting for mixfiles.
  523. FRAMESYNC_DLG_TIME = (3*60), // time until displaying reconnect dialog
  524. FRAMESYNC_TIMEOUT = (15*60), // timeout waiting for frame sync packet
  525. };
  526. int timeout_factor = (Session.Type == GAME_INTERNET) ? 6 : 1;
  527. //........................................................................
  528. // Variables for sending, receiving & parsing packets:
  529. //........................................................................
  530. ConnManClass *net; // ptr to access all multiplayer functions
  531. EventClass packet; // for sending single frame-sync's
  532. char *multi_packet_buf; // buffer for sending/receiving
  533. int multi_packet_max; // max length of multi_packet_buf
  534. //........................................................................
  535. // Frame-sync'ing variables
  536. //........................................................................
  537. static long
  538. their_frame[MAX_PLAYERS - 1]; // other players' frame #'s
  539. static unsigned short
  540. their_sent[MAX_PLAYERS - 1]; // # cmds other player claims to have sent
  541. static unsigned short
  542. their_recv[MAX_PLAYERS - 1]; // # cmds actually received from others
  543. static unsigned short
  544. my_sent; // # cmds I've sent out
  545. //........................................................................
  546. // Timing variables
  547. //........................................................................
  548. static CDTimerClass<FrameTimerClass> skip_crc; // to delay the CRC check
  549. // static TCountDownTimerClass skip_crc; // to delay the CRC check
  550. //........................................................................
  551. // Other misc variables
  552. //........................................................................
  553. int i;
  554. RetcodeType rc;
  555. int reconnect_dlg = 0; // 1 = the reconnect dialog is displayed
  556. //------------------------------------------------------------------------
  557. // Initialize the packet buffer pointer & its max size
  558. //------------------------------------------------------------------------
  559. if (Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) {
  560. multi_packet_buf = NullModem.BuildBuf;
  561. multi_packet_max = NullModem.MaxLen - sizeof (CommHeaderType);
  562. net = &NullModem;
  563. } else if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) {
  564. multi_packet_buf = Session.MetaPacket;
  565. multi_packet_max = Session.MetaSize;
  566. net = &Ipx;
  567. }
  568. #if(TEN)
  569. else if (Session.Type == GAME_TEN) {
  570. multi_packet_buf = Session.TenPacket;
  571. multi_packet_max = Session.TenSize;
  572. net = Ten;
  573. }
  574. #endif
  575. #if(MPATH)
  576. else if (Session.Type == GAME_MPATH) {
  577. multi_packet_buf = Session.MPathPacket;
  578. multi_packet_max = Session.MPathSize;
  579. net = MPath;
  580. }
  581. #endif
  582. //------------------------------------------------------------------------
  583. // Debug stuff
  584. //------------------------------------------------------------------------
  585. Init_Queue_Mono(net);
  586. Update_Queue_Mono (net, 0);
  587. //------------------------------------------------------------------------
  588. // Compute the Game's CRC
  589. //------------------------------------------------------------------------
  590. Compute_Game_CRC();
  591. CRC[Frame & 0x001f] = GameCRC;
  592. //------------------------------------------------------------------------
  593. // If we've just started a game, or loaded a multiplayer game, we must
  594. // wait for all other systems to signal ready.
  595. //------------------------------------------------------------------------
  596. if (Frame==0 || Session.LoadGame) {
  597. //.....................................................................
  598. // Initialize static locals
  599. //.....................................................................
  600. for (i = 0; i < MAX_PLAYERS - 1; i++) {
  601. their_frame[i] = -1;
  602. their_sent[i] = 0;
  603. their_recv[i] = 0;
  604. }
  605. my_sent = 0;
  606. #ifdef FIXIT_MULTI_SAVE
  607. skip_crc = 32;
  608. #else
  609. skip_crc = Frame + 32;
  610. #endif // FIXIT_MULTI_SAVE
  611. for (i = 0; i < 32; i++)
  612. CRC[i] = 0;
  613. //.....................................................................
  614. // If we've loaded a saved game:
  615. // - If this game was saved as the result of a lost connection, clear
  616. // the CRC value so it will always match the other system's
  617. // - Otherwise, use the GameCRC value, so we'll compare save-game files
  618. // rather than scenario INI files
  619. //.....................................................................
  620. if (Session.LoadGame) {
  621. if (Session.EmergencySave)
  622. ScenarioCRC = 0;
  623. else
  624. ScenarioCRC = GameCRC;
  625. }
  626. //.....................................................................
  627. // Send our initial FRAMESYNC packet
  628. //.....................................................................
  629. Send_FrameSync(net, my_sent);
  630. //.....................................................................
  631. // Wait for the other guys
  632. //.....................................................................
  633. rc = Wait_For_Players (1, net, MIXFILE_RESEND_DELTA, FRAMESYNC_DLG_TIME*timeout_factor,
  634. MIXFILE_TIMEOUT, multi_packet_buf, my_sent, their_frame,
  635. their_sent, their_recv);
  636. if (rc != RC_NORMAL) {
  637. #ifdef WIN32
  638. if (Session.Type == GAME_INTERNET){
  639. Register_Game_End_Time();
  640. }
  641. #endif //WIN32
  642. if (rc == RC_NOT_RESPONDING) {
  643. WWMessageBox().Process (TXT_SYSTEM_NOT_RESPONDING);
  644. }
  645. else if (rc == RC_SCENARIO_MISMATCH) {
  646. WWMessageBox().Process (TXT_SCENARIOS_DO_NOT_MATCH);
  647. }
  648. else if (rc == RC_DOLIST_FULL) {
  649. WWMessageBox().Process(TXT_QUEUE_FULL);
  650. }
  651. Stop_Game();
  652. return;
  653. }
  654. //.....................................................................
  655. // Re-initialize frame numbers (in case somebody signed off while I was
  656. // waiting for MIX files to load; we would have fallen through, but
  657. // their frame # would still be -1).
  658. //.....................................................................
  659. for (i = 0; i < MAX_PLAYERS - 1; i++)
  660. their_frame[i] = 0;
  661. //.....................................................................
  662. // Reset the network response time computation, now that we're both
  663. // sending data again (loading MIX files will have introduced
  664. // deceptively large values).
  665. //.....................................................................
  666. net->Reset_Response_Time();
  667. //.....................................................................
  668. // Initialize the frame timers
  669. //.....................................................................
  670. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  671. Process_Send_Period(net);//, 1);
  672. }
  673. //.....................................................................
  674. // Turn off our special load-game flags
  675. //.....................................................................
  676. if (Session.LoadGame) {
  677. Session.EmergencySave = false;
  678. Session.LoadGame = false;
  679. }
  680. } // end of Frame 0 wait
  681. //------------------------------------------------------------------------
  682. // Adjust connection timing parameters every 128 frames.
  683. //------------------------------------------------------------------------
  684. else if ( (Frame & 0x007f) == 0) {
  685. //
  686. // If we're using the new spiffy protocol, do proper timing handling.
  687. // If we're the net "master", compute our desired frame rate & new
  688. // 'MaxAhead' value.
  689. //
  690. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  691. //
  692. // All systems will transmit their required process time.
  693. //
  694. Generate_Process_Time_Event(net);
  695. //
  696. // The game "host" will transmit timing adjustment events.
  697. //
  698. if (Session.Am_I_Master()) {
  699. Generate_Real_Timing_Event(net, my_sent);
  700. }
  701. } else {
  702. //
  703. // For the older protocols, do the old broken timing handling.
  704. //
  705. Generate_Timing_Event(net, my_sent);
  706. }
  707. }
  708. //------------------------------------------------------------------------
  709. // Only process every 'FrameSendRate' frames
  710. //------------------------------------------------------------------------
  711. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  712. if (!Process_Send_Period(net)) { //, 0)) {
  713. if (IsMono) {
  714. MonoClass::Disable();
  715. }
  716. return;
  717. }
  718. }
  719. //------------------------------------------------------------------------
  720. // Send our data packet(s); update my command-sent counter
  721. //------------------------------------------------------------------------
  722. my_sent += Send_Packets(net, multi_packet_buf, multi_packet_max,
  723. Session.MaxAhead, my_sent);
  724. //------------------------------------------------------------------------
  725. // If this is our first time through, we're done.
  726. //------------------------------------------------------------------------
  727. if (Frame==0) {
  728. if (IsMono) {
  729. MonoClass::Disable();
  730. }
  731. return;
  732. }
  733. //------------------------------------------------------------------------
  734. // Frame-sync'ing: wait until it's OK to advance to the next frame.
  735. //------------------------------------------------------------------------
  736. #ifdef FIXIT_VERSION_3
  737. int iFramesyncTimeout;
  738. if( Session.Type == GAME_INTERNET && pWolapi && pWolapi->GameInfoCurrent.iPlayerCount > 2 )
  739. // Shortened resync timeout for non-2 player games.
  740. iFramesyncTimeout = 5 * 60; // One minute.
  741. else
  742. iFramesyncTimeout = FRAMESYNC_TIMEOUT;
  743. rc = Wait_For_Players (0, net,
  744. (Session.MaxAhead << 3),
  745. MAX ( net->Response_Time() * 3, FRAMESYNC_DLG_TIME*timeout_factor ),
  746. iFramesyncTimeout * (2*timeout_factor),
  747. multi_packet_buf, my_sent, their_frame,
  748. their_sent, their_recv);
  749. #else
  750. rc = Wait_For_Players (0, net,
  751. (Session.MaxAhead << 3),
  752. MAX ( net->Response_Time() * 3, FRAMESYNC_DLG_TIME*timeout_factor ),
  753. FRAMESYNC_TIMEOUT* (2*timeout_factor),
  754. multi_packet_buf, my_sent, their_frame,
  755. their_sent, their_recv);
  756. #endif
  757. if (rc != RC_NORMAL) {
  758. #ifdef WIN32
  759. if (Session.Type == GAME_INTERNET){
  760. Register_Game_End_Time();
  761. #ifdef WOLAPI_INTEGRATION
  762. // New rule - if you cancel a waiting to reconnect dialog, you lose.
  763. bReconnectDialogCancelled = ( rc == RC_CANCEL );
  764. #endif
  765. }
  766. #endif //WIN32
  767. if (rc == RC_NOT_RESPONDING) {
  768. WWMessageBox().Process (TXT_SYSTEM_NOT_RESPONDING);
  769. }
  770. else if (rc == RC_SCENARIO_MISMATCH) {
  771. WWMessageBox().Process (TXT_SCENARIOS_DO_NOT_MATCH);
  772. }
  773. else if (rc == RC_DOLIST_FULL) {
  774. WWMessageBox().Process(TXT_QUEUE_FULL);
  775. }
  776. Stop_Game();
  777. return;
  778. }
  779. //------------------------------------------------------------------------
  780. // Save the DoList to disk, if we're in "Record" mode
  781. //------------------------------------------------------------------------
  782. if (Session.Record) {
  783. Queue_Record();
  784. }
  785. //------------------------------------------------------------------------
  786. // Execute the DoList; if an error occurs, bail out.
  787. //------------------------------------------------------------------------
  788. if (!Execute_DoList(Session.MaxPlayers, HOUSE_MULTI1, net, &skip_crc,
  789. their_frame, their_sent, their_recv)) {
  790. #ifdef WIN32
  791. if (Session.Type == GAME_INTERNET){
  792. Register_Game_End_Time();
  793. }
  794. #endif //WIN32
  795. Stop_Game();
  796. return;
  797. }
  798. //------------------------------------------------------------------------
  799. // Clean out the DoList
  800. //------------------------------------------------------------------------
  801. Clean_DoList(net);
  802. if (IsMono) {
  803. MonoClass::Disable();
  804. }
  805. } // end of Queue_AI_Multiplayer
  806. /***************************************************************************
  807. * Wait_For_Players -- Waits for other systems to come on-line *
  808. * *
  809. * This routine performs the most critical logic in multiplayer; that of *
  810. * synchronizing my frame number with those of the other systems. *
  811. * *
  812. * INPUT: *
  813. * first_time 1 = 1st time this routine is called *
  814. * net ptr to connection manager *
  815. * resend_delta time (ticks) between FRAMESYNC resends *
  816. * dialog_time time (ticks) until pop up a reconnect dialog *
  817. * timeout time (ticks) until we give up the ghost *
  818. * multi_packet_buf buffer to store packets in *
  819. * my_sent # commands I've sent so far *
  820. * their_frame array of their frame #'s *
  821. * their_sent array of their CommandCount values *
  822. * their_recv array of # cmds I've received from them *
  823. * *
  824. * OUTPUT: *
  825. * RC_NORMAL OK to advance to the next frame *
  826. * RC_CANCEL user hit 'Cancel' at the timeout countdown dlg *
  827. * RC_NOT_RESPONDING other player(s) not responding *
  828. * RC_SCENARIO_MISMATCH scenario's don't match (first_time only) *
  829. * RC_DOLIST_FULL DoList was full *
  830. * *
  831. * WARNINGS: *
  832. * none. *
  833. * *
  834. * HISTORY: *
  835. * 11/21/1995 BRR : Created. *
  836. *=========================================================================*/
  837. static RetcodeType Wait_For_Players(int first_time, ConnManClass *net,
  838. int resend_delta, int dialog_time, int timeout, char *multi_packet_buf,
  839. int my_sent, long *their_frame, unsigned short *their_sent,
  840. unsigned short *their_recv)
  841. {
  842. //........................................................................
  843. // Variables for sending, receiving & parsing packets:
  844. //........................................................................
  845. EventClass *event; // event ptr for parsing incoming packets
  846. int packetlen; // size of meta-packet sent, & received
  847. int id; // id of other player
  848. int messages_this_loop; // to limit # messages processed each loop
  849. int message_limit; // max # messages we'll read each frame
  850. //........................................................................
  851. // Variables used only if 'first_time':
  852. //........................................................................
  853. int num_ready; // # players signalling ready
  854. //........................................................................
  855. // Timing variables
  856. //........................................................................
  857. CDTimerClass<SystemTimerClass> retry_timer; // time between FRAMESYNC packet resends
  858. CDTimerClass<SystemTimerClass> dialog_timer; // time to pop up a dialog
  859. CDTimerClass<SystemTimerClass> timeout_timer; // general-purpose timeout
  860. //........................................................................
  861. // Dialog variables
  862. //........................................................................
  863. int reconnect_dlg = 0; // 1 = the reconnect dialog is displayed
  864. //........................................................................
  865. // Other misc variables
  866. //........................................................................
  867. KeyNumType input; // for user input
  868. int x,y; // for map input
  869. RetcodeType rc;
  870. //------------------------------------------------------------------------
  871. // Wait to hear from all other players
  872. //------------------------------------------------------------------------
  873. num_ready = 0;
  874. retry_timer = resend_delta; // time to retry
  875. dialog_timer = dialog_time; // time to show dlg
  876. timeout_timer = timeout; // time to bail out
  877. while (1) {
  878. Keyboard->Check();
  879. Update_Queue_Mono (net, 2);
  880. //---------------------------------------------------------------------
  881. // Resend a frame-sync packet if longer than one propagation delay goes
  882. // by; this prevents a "deadlock". If he's waiting for me to advance,
  883. // but has missed my last few FRAMEINFO packets, I may be waiting for
  884. // him to advance. Resending a FRAMESYNC ensures he knows what frame
  885. // number I'm on.
  886. //---------------------------------------------------------------------
  887. if (!retry_timer) {
  888. retry_timer = resend_delta; // time to retry
  889. Update_Queue_Mono (net, 3);
  890. Send_FrameSync(net, my_sent);
  891. }
  892. //---------------------------------------------------------------------
  893. // Service the connections
  894. //---------------------------------------------------------------------
  895. net->Service();
  896. //---------------------------------------------------------------------
  897. // Pop up a reconnect dialog if enough time goes by
  898. //---------------------------------------------------------------------
  899. if (!dialog_timer && SpecialDialog==SDLG_NONE) {
  900. if (reconnect_dlg == 0 && first_time == 0) {
  901. FILE *fp;
  902. int i;
  903. HouseClass *housep;
  904. fp = fopen("recon.txt","wt");
  905. if (fp) {
  906. fprintf(fp,"# Connections: %d\n",net->Num_Connections());
  907. fprintf(fp," My Frame #: %d\n",Frame);
  908. for (i = 0; i < net->Num_Connections(); i++) {
  909. housep = HouseClass::As_Pointer((HousesType)(net->Connection_ID(i)));
  910. fprintf(fp,"%15s: Their Sent:%d Their Recv:%d Their Frame:%d\n",
  911. housep->IniName, their_sent[i], their_recv[i], their_frame[i]);
  912. }
  913. fclose(fp);
  914. }
  915. #ifdef WOLAPI_INTEGRATION
  916. // "Reconnecting" dialog is about to be shown.
  917. // At this point, begin wolapi "disconnect pinging", if appropriate.
  918. if( Session.Type == GAME_INTERNET && pWolapi && pWolapi->GameInfoCurrent.bTournament )
  919. pWolapi->Init_DisconnectPinging();
  920. #endif
  921. }
  922. if (Process_Reconnect_Dialog(&timeout_timer, their_frame, // (Returns immediately.)
  923. net->Num_Connections(), (first_time==0), (reconnect_dlg==0))) {
  924. return (RC_CANCEL);
  925. }
  926. reconnect_dlg = 1;
  927. #ifdef WOLAPI_INTEGRATION
  928. // Continue wolapi "disconnect pinging", if appropriate.
  929. if( Session.Type == GAME_INTERNET && pWolapi && pWolapi->bDoingDisconnectPinging )
  930. pWolapi->Pump_DisconnectPinging();
  931. #endif
  932. }
  933. //---------------------------------------------------------------------
  934. // Exit if too much time goes by (the other system has crashed or
  935. // bailed)
  936. //---------------------------------------------------------------------
  937. if (!timeout_timer) {
  938. //..................................................................
  939. // For the first-time run, just give up; something's wrong.
  940. //..................................................................
  941. if (first_time) {
  942. return (RC_NOT_RESPONDING);
  943. }
  944. //..................................................................
  945. // Otherwise, we're in the middle of a game; so, the modem &
  946. // network must deal with a timeout differently.
  947. //..................................................................
  948. else {
  949. Update_Queue_Mono (net, 4);
  950. if (Handle_Timeout(net, their_frame, their_sent, their_recv)) {
  951. Map.Flag_To_Redraw(true); // erase modem reconnect dialog
  952. Map.Render();
  953. retry_timer = resend_delta;
  954. dialog_timer = dialog_time;
  955. timeout_timer = timeout;
  956. }
  957. #ifdef FIXIT_MULTI_SAVE
  958. #ifdef FIXIT_VERSION_3
  959. else if ((Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) ) {
  960. #else
  961. else if ((Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) &&
  962. PlayingAgainstVersion != VERSION_RED_ALERT_104) {
  963. #endif
  964. if (WWMessageBox().Process (TXT_ASK_EMERGENCY_SAVE_NOT_RESPONDING,
  965. TXT_YES, TXT_NO, TXT_NONE) == 0) {
  966. Session.EmergencySave = 1;
  967. //printf("Saving emergency game; frame:%d, CRC:%d\n",Frame,GameCRC);
  968. //Print_CRCs(NULL);
  969. //printf("Before Save: Count1:%d, Count2:%d, Seed:%d\n",
  970. // Scen.RandomNumber.Count1,
  971. // Scen.RandomNumber.Count2,
  972. // Scen.RandomNumber.Seed);
  973. Save_Game(-1, (char *)Text_String(TXT_MULTIPLAYER_GAME));
  974. //printf("After Save: Count1:%d, Count2:%d, Seed:%d\n",
  975. // Scen.RandomNumber.Count1,
  976. // Scen.RandomNumber.Count2,
  977. // Scen.RandomNumber.Seed);
  978. Session.EmergencySave = 0;
  979. }
  980. return (RC_CANCEL);
  981. }
  982. #endif // FIXIT_MULTI_SAVE
  983. else {
  984. return (RC_NOT_RESPONDING);
  985. }
  986. }
  987. }
  988. //---------------------------------------------------------------------
  989. // Check for an incoming message. We must still process commands
  990. // even if 'first_time' is set, in case the other system got my 1st
  991. // FRAMESYNC, but I didn't get his; he'll be at the next frame, and
  992. // may be sending commands.
  993. // We have to limit the number of incoming messages we handle; it's
  994. // possible to go into an infinite loop processing modem messages.
  995. // (This feature is disabled for Ten; we need to keep the TCP buffers
  996. // clear, so we read all the packets we can every time.)
  997. //---------------------------------------------------------------------
  998. messages_this_loop = 0;
  999. message_limit = 5;
  1000. if (Session.Type == GAME_TEN || Session.Type == GAME_MPATH) {
  1001. message_limit = 9999;
  1002. }
  1003. while ( (messages_this_loop++ < message_limit) &&
  1004. net->Get_Private_Message (multi_packet_buf, &packetlen, &id) ) {
  1005. Keyboard->Check();
  1006. Update_Queue_Mono (net, 5);
  1007. /*..................................................................
  1008. Get an event ptr to the incoming message
  1009. ..................................................................*/
  1010. event = (EventClass *)multi_packet_buf;
  1011. //------------------------------------------------------------------
  1012. // Special processing for a modem game: process SERIAL packets
  1013. //------------------------------------------------------------------
  1014. if (Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) {
  1015. rc = Process_Serial_Packet(multi_packet_buf, first_time);
  1016. //...............................................................
  1017. // SERIAL packet received & processed
  1018. //...............................................................
  1019. if (rc == RC_SERIAL_PROCESSED) {
  1020. net->Service();
  1021. retry_timer = resend_delta;
  1022. dialog_timer = dialog_time;
  1023. timeout_timer = timeout;
  1024. continue;
  1025. }
  1026. //...............................................................
  1027. // other player has left the game
  1028. //...............................................................
  1029. else if (rc == RC_PLAYER_LEFT) {
  1030. if (first_time) {
  1031. num_ready++;
  1032. }
  1033. break;
  1034. }
  1035. //...............................................................
  1036. // Connection was lost
  1037. //...............................................................
  1038. else if (rc == RC_HUNG_UP) {
  1039. #ifdef FIXIT_MULTI_SAVE
  1040. #ifndef FIXIT_VERSION_3
  1041. if (PlayingAgainstVersion != VERSION_RED_ALERT_104){
  1042. #endif
  1043. if (WWMessageBox().Process (TXT_ASK_EMERGENCY_SAVE_HUNG_UP,
  1044. TXT_YES, TXT_NO, TXT_NONE) == 0) {
  1045. Session.EmergencySave = 1;
  1046. //printf("Saving emergency game; frame:%d, CRC:%d\n",Frame,GameCRC);
  1047. //Print_CRCs(NULL);
  1048. //printf("Before Save: Count1:%d, Count2:%d, Seed:%d\n",
  1049. // Scen.RandomNumber.Count1,
  1050. // Scen.RandomNumber.Count2,
  1051. // Scen.RandomNumber.Seed);
  1052. Save_Game (-1, (char *)Text_String(TXT_MULTIPLAYER_GAME));
  1053. //printf("After Save: Count1:%d, Count2:%d, Seed:%d\n",
  1054. // Scen.RandomNumber.Count1,
  1055. // Scen.RandomNumber.Count2,
  1056. // Scen.RandomNumber.Seed);
  1057. Session.EmergencySave = 0;
  1058. }
  1059. return (RC_CANCEL);
  1060. #ifndef FIXIT_VERSION_3
  1061. }else{
  1062. return (RC_NOT_RESPONDING);
  1063. }
  1064. #endif
  1065. #else
  1066. return (RC_NOT_RESPONDING);
  1067. #endif // FIXIT_MULTI_SAVE
  1068. }
  1069. //...............................................................
  1070. // If it was any other type of serial packet, break
  1071. //...............................................................
  1072. else if (rc != RC_NORMAL) {
  1073. break;
  1074. }
  1075. }
  1076. //------------------------------------------------------------------
  1077. // Process the incoming packet
  1078. //------------------------------------------------------------------
  1079. rc = Process_Receive_Packet(net, multi_packet_buf, id, packetlen,
  1080. their_frame, their_sent, their_recv);
  1081. //..................................................................
  1082. // New player heard from
  1083. //..................................................................
  1084. if (rc == RC_PLAYER_READY) {
  1085. num_ready++;
  1086. }
  1087. //..................................................................
  1088. // Scenario's don't match
  1089. //..................................................................
  1090. else if (rc == RC_SCENARIO_MISMATCH) {
  1091. return (RC_SCENARIO_MISMATCH);
  1092. }
  1093. //..................................................................
  1094. // DoList was full
  1095. //..................................................................
  1096. else if (rc == RC_DOLIST_FULL) {
  1097. return (RC_DOLIST_FULL);
  1098. }
  1099. //..................................................................
  1100. // Service the connection, to clean out the receive queues
  1101. //..................................................................
  1102. net->Service();
  1103. }
  1104. //---------------------------------------------------------------------
  1105. // Debug output
  1106. //---------------------------------------------------------------------
  1107. Print_Framesync_Values(Frame, Session.MaxAhead, net->Num_Connections(),
  1108. their_recv, their_sent, my_sent);
  1109. //---------------------------------------------------------------------
  1110. // Attempt to advance to the next frame.
  1111. //---------------------------------------------------------------------
  1112. //.....................................................................
  1113. // For the first-time run, just check to see if we've heard from
  1114. // everyone.
  1115. //.....................................................................
  1116. if (first_time) {
  1117. if (num_ready >= net->Num_Connections()) {
  1118. break;
  1119. }
  1120. }
  1121. //.....................................................................
  1122. // For in-game processing, we have to check their_sent, their_recv,
  1123. // their_frame, etc.
  1124. //.....................................................................
  1125. else {
  1126. if (Can_Advance(net, Session.MaxAhead, their_frame, their_sent,
  1127. their_recv)) {
  1128. break;
  1129. }
  1130. }
  1131. //---------------------------------------------------------------------
  1132. // Service game stuff. Servicing the map's input, and rendering the
  1133. // map, allows the map to scroll even though we're hung up waiting for
  1134. // packets. Don't do this if 'first_time' is set, since users could be
  1135. // waiting a very long time for all systems to load the scenario, and
  1136. // it gets frustrating being able to scroll around without doing
  1137. // anything.
  1138. //---------------------------------------------------------------------
  1139. Call_Back();
  1140. if (!first_time && SpecialDialog == SDLG_NONE && reconnect_dlg==0) {
  1141. #ifdef WIN32
  1142. WWMouse->Erase_Mouse(&HidPage, TRUE);
  1143. #endif //WIN32
  1144. Map.Input(input, x, y);
  1145. if (input)
  1146. Keyboard_Process(input);
  1147. Map.Render();
  1148. }
  1149. } /* end of while */
  1150. //------------------------------------------------------------------------
  1151. // If the reconnect dialog was shown, force the map to redraw.
  1152. //------------------------------------------------------------------------
  1153. if (reconnect_dlg) {
  1154. Map.Flag_To_Redraw(true);
  1155. Map.Render();
  1156. }
  1157. return (RC_NORMAL);
  1158. } // end of Wait_For_Players
  1159. /***************************************************************************
  1160. * Generate_Timing_Event -- computes & queues a RESPONSE_TIME event *
  1161. * *
  1162. * This routine adjusts the connection timing on the local system; it also *
  1163. * optionally generates a RESPONSE_TIME event, to tell all systems to *
  1164. * dynamically adjust the current MaxAhead value. This allows both the *
  1165. * MaxAhead & the connection retry logic to have dynamic timing, to adjust *
  1166. * to varying line conditions. *
  1167. * *
  1168. * INPUT: *
  1169. * net ptr to connection manager *
  1170. * my_sent # commands I've sent out so far *
  1171. * *
  1172. * OUTPUT: *
  1173. * none. *
  1174. * *
  1175. * WARNINGS: *
  1176. * none. *
  1177. * *
  1178. * HISTORY: *
  1179. * 11/21/1995 BRR : Created. *
  1180. *=========================================================================*/
  1181. static void Generate_Timing_Event(ConnManClass *net, int my_sent)
  1182. {
  1183. unsigned long resp_time; // connection response time, in ticks
  1184. EventClass ev;
  1185. //
  1186. // For now, TEN & MPATH don't measure the net's response time, so there's
  1187. // no point in adjusting our timing. Do nothing.
  1188. //
  1189. if (Session.Type == GAME_TEN || Session.Type == GAME_MPATH) {
  1190. return;
  1191. }
  1192. //------------------------------------------------------------------------
  1193. // Measure the current connection response time. This time will be in
  1194. // 60ths of a second, and represents full round-trip time of a packet.
  1195. // To convert to one-way packet time, divide by 2; to convert to game
  1196. // frames, divide again by 4, assuming a game rate of 15 fps.
  1197. //------------------------------------------------------------------------
  1198. resp_time = net->Response_Time();
  1199. //------------------------------------------------------------------------
  1200. // Adjust my connection retry timing; only do this if I've sent out more
  1201. // than 5 commands, so I know I have a measure of the response time.
  1202. //------------------------------------------------------------------------
  1203. if (my_sent > 5) {
  1204. net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15);
  1205. //.....................................................................
  1206. // If I'm the network "master", I'm also responsible for updating the
  1207. // MaxAhead value on all systems, so do that here too.
  1208. //.....................................................................
  1209. if (Session.Am_I_Master()) {
  1210. ev.Type = EventClass::RESPONSE_TIME;
  1211. //..................................................................
  1212. // For multi-frame compressed events, the MaxAhead must be an even
  1213. // multiple of the FrameSendRate.
  1214. //..................................................................
  1215. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  1216. ev.Data.FrameInfo.Delay = max( ((((resp_time / 8) +
  1217. (Session.FrameSendRate - 1)) / Session.FrameSendRate) *
  1218. Session.FrameSendRate), (Session.FrameSendRate * 2) );
  1219. }
  1220. //..................................................................
  1221. // For sending packets every frame, just use the 1-way connection
  1222. // response time.
  1223. //..................................................................
  1224. else {
  1225. if (Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) {
  1226. ev.Data.FrameInfo.Delay = max( (resp_time / 8),
  1227. MODEM_MIN_MAX_AHEAD );
  1228. } else if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) {
  1229. ev.Data.FrameInfo.Delay = max( (resp_time / 8),
  1230. NETWORK_MIN_MAX_AHEAD );
  1231. }
  1232. else if (Session.Type == GAME_TEN || Session.Type == GAME_MPATH) {
  1233. ev.Data.FrameInfo.Delay = max( (resp_time / 8),
  1234. MODEM_MIN_MAX_AHEAD );
  1235. }
  1236. }
  1237. OutList.Add(ev);
  1238. }
  1239. }
  1240. } // end of Generate_Timing_Event
  1241. /***************************************************************************
  1242. * Generate_Real_Timing_Event -- Generates a TIMING event *
  1243. * *
  1244. * INPUT: *
  1245. * net ptr to connection manager *
  1246. * my_sent # commands I've sent out so far *
  1247. * *
  1248. * OUTPUT: *
  1249. * none. *
  1250. * *
  1251. * WARNINGS: *
  1252. * none. *
  1253. * *
  1254. * HISTORY: *
  1255. * 07/02/1996 BRR : Created. *
  1256. *=========================================================================*/
  1257. static void Generate_Real_Timing_Event(ConnManClass *net, int my_sent)
  1258. {
  1259. unsigned long resp_time; // connection response time, in ticks
  1260. EventClass ev;
  1261. int highest_ticks;
  1262. int i;
  1263. int specified_frame_rate;
  1264. int maxahead;
  1265. //
  1266. // If we haven't sent out at least 5 guaranteed-delivery packets, don't
  1267. // bother trying to measure our connection response time; just return.
  1268. //
  1269. if (my_sent < 5) {
  1270. return;
  1271. }
  1272. //
  1273. // Find the highest processing time we have stored
  1274. //
  1275. highest_ticks = 0;
  1276. for (i = 0; i < Session.Players.Count(); i++) {
  1277. //
  1278. // If we haven't heard from all systems yet, bail out.
  1279. //
  1280. if (Session.Players[i]->Player.ProcessTime == -1) {
  1281. return;
  1282. }
  1283. if (Session.Players[i]->Player.ProcessTime > highest_ticks) {
  1284. highest_ticks = Session.Players[i]->Player.ProcessTime;
  1285. }
  1286. }
  1287. //
  1288. // Compute our "desired" frame rate as the lower of:
  1289. // - What the user has dialed into the options screen
  1290. // - What we're really able to run at
  1291. //
  1292. if (highest_ticks == 0) {
  1293. Session.DesiredFrameRate = 60;
  1294. } else {
  1295. Session.DesiredFrameRate = 60 / highest_ticks;
  1296. }
  1297. if (Options.GameSpeed == 0) {
  1298. specified_frame_rate = 60;
  1299. } else {
  1300. specified_frame_rate = 60 / Options.GameSpeed;
  1301. }
  1302. Session.DesiredFrameRate = MIN (Session.DesiredFrameRate, specified_frame_rate);
  1303. //
  1304. // Measure the current connection response time. This time will be in
  1305. // 60ths of a second, and represents full round-trip time of a packet.
  1306. // To convert to one-way packet time, divide by 2; to convert to game
  1307. // frames, ....uh....
  1308. //
  1309. resp_time = net->Response_Time();
  1310. //
  1311. // Compute our new 'MaxAhead' value, based upon the response time of our
  1312. // connection and our desired frame rate.
  1313. // 'MaxAhead' in frames is:
  1314. //
  1315. // (resp_time / 2 ticks) * (1 sec/60 ticks) * (n Frames / sec)
  1316. //
  1317. // resp_time is divided by 2 because, as reported, it represents a round-
  1318. // trip, and we only want to use a one-way trip.
  1319. //
  1320. maxahead = (resp_time * Session.DesiredFrameRate) / (2 * 60);
  1321. //
  1322. // Now, we have to round 'maxahead' so it's an even multiple of our
  1323. // send rate. It also must be at least thrice the FrameSendRate.
  1324. // (Isn't "thrice" a cool word?)
  1325. //
  1326. maxahead = ((maxahead + Session.FrameSendRate - 1) / Session.FrameSendRate) * Session.FrameSendRate;
  1327. maxahead = MAX (maxahead, Session.FrameSendRate * 3);
  1328. ev.Type = EventClass::TIMING;
  1329. ev.Data.Timing.DesiredFrameRate = Session.DesiredFrameRate;
  1330. ev.Data.Timing.MaxAhead = maxahead;
  1331. OutList.Add(ev);
  1332. //
  1333. // Adjust my connection retry timing. These values set the retry timeout
  1334. // to just over one round-trip time, the 'maxretries' to -1, and the
  1335. // connection timeout to allow for about 4 retries.
  1336. //
  1337. //net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15);
  1338. if (Session.Type == GAME_INTERNET) {
  1339. net->Set_Timing (resp_time + 10, -1, ((resp_time + 10)* 8)+15);
  1340. }else{
  1341. net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15);
  1342. }
  1343. }
  1344. /***************************************************************************
  1345. * Generate_Process_Time_Event -- Generates a PROCESS_TIME event *
  1346. * *
  1347. * INPUT: *
  1348. * net ptr to connection manager *
  1349. * *
  1350. * OUTPUT: *
  1351. * none. *
  1352. * *
  1353. * WARNINGS: *
  1354. * none. *
  1355. * *
  1356. * HISTORY: *
  1357. * 07/02/1996 BRR : Created. *
  1358. *=========================================================================*/
  1359. static void Generate_Process_Time_Event(ConnManClass *net)
  1360. {
  1361. EventClass ev;
  1362. int avgticks;
  1363. unsigned long resp_time; // connection response time, in ticks
  1364. //
  1365. // Measure the current connection response time. This time will be in
  1366. // 60ths of a second, and represents full round-trip time of a packet.
  1367. // To convert to one-way packet time, divide by 2; to convert to game
  1368. // frames, ....uh....
  1369. //
  1370. resp_time = net->Response_Time();
  1371. //
  1372. // Adjust my connection retry timing. These values set the retry timeout
  1373. // to just over one round-trip time, the 'maxretries' to -1, and the
  1374. // connection timeout to allow for about 4 retries.
  1375. //
  1376. //net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15);
  1377. if (Session.Type == GAME_INTERNET) {
  1378. net->Set_Timing (resp_time + 10, -1, ((resp_time + 10)* 8)+15);
  1379. }else{
  1380. net->Set_Timing (resp_time + 10, -1, (resp_time * 4)+15);
  1381. }
  1382. if (IsMono) {
  1383. MonoClass::Enable();
  1384. Mono_Set_Cursor(0,23);
  1385. Mono_Printf("Processing Ticks:%03d Frames:%03d\n", Session.ProcessTicks,Session.ProcessFrames);
  1386. MonoClass::Disable();
  1387. }
  1388. avgticks = Session.ProcessTicks / Session.ProcessFrames;
  1389. ev.Type = EventClass::PROCESS_TIME;
  1390. ev.Data.ProcessTime.AverageTicks = avgticks;
  1391. OutList.Add(ev);
  1392. Session.ProcessTicks = 0;
  1393. Session.ProcessFrames = 0;
  1394. }
  1395. /***************************************************************************
  1396. * Process_Send_Period -- timing for sending packets every 'n' frames *
  1397. * *
  1398. * This function is for a CommProtocol of COMM_PROTOCOL_MULTI_E_COMP only. *
  1399. * It determines if it's time to send a packet or not. *
  1400. * *
  1401. * INPUT: *
  1402. * net ptr to connection manager *
  1403. * *
  1404. * OUTPUT: *
  1405. * 1 = it's time to send a packet; 0 = don't send a packet this frame. *
  1406. * *
  1407. * WARNINGS: *
  1408. * *
  1409. * HISTORY: *
  1410. * 11/21/1995 BRR : Created. *
  1411. *=========================================================================*/
  1412. static int Process_Send_Period(ConnManClass *net) //, int init)
  1413. {
  1414. //------------------------------------------------------------------------
  1415. // If the current frame # is not an even multiple of 'FrameSendRate', then
  1416. // it's not time to send a packet; just return.
  1417. //------------------------------------------------------------------------
  1418. if (Frame != (((Frame + (Session.FrameSendRate - 1)) /
  1419. Session.FrameSendRate) * Session.FrameSendRate) ) {
  1420. net->Service();
  1421. if (IsMono) {
  1422. MonoClass::Disable();
  1423. }
  1424. return (0);
  1425. }
  1426. return (1);
  1427. } // end of Process_Send_Period
  1428. /***************************************************************************
  1429. * Send_Packets -- sends out events from the OutList *
  1430. * *
  1431. * This routine computes how many events can be sent this frame, and then *
  1432. * builds the "meta-packet" & sends it. *
  1433. * *
  1434. * The 'cap' value is the max # of events we can send. Ideally, it should *
  1435. * be based upon the bandwidth of our connection. Currently, it's just *
  1436. * hardcoded to prevent the modem from having to resend "too much" data, *
  1437. * which is about 200 bytes per frame. *
  1438. * *
  1439. * INPUT: *
  1440. * net ptr to connection manager *
  1441. * multi_packet_buf buffer to store packets in *
  1442. * multi_packet_max max size of multi_packet_buf *
  1443. * max_ahead current game MaxAhead value *
  1444. * my_sent # commands I've sent this game *
  1445. * *
  1446. * OUTPUT: *
  1447. * # events sent, NOT including the FRAMEINFO event *
  1448. * *
  1449. * WARNINGS: *
  1450. * *
  1451. * HISTORY: *
  1452. * 11/21/1995 BRR : Created. *
  1453. *=========================================================================*/
  1454. static int Send_Packets(ConnManClass *net, char *multi_packet_buf,
  1455. int multi_packet_max, int max_ahead, int my_sent)
  1456. {
  1457. int cap; // max # events to send, NOT including FRAMEINFO event
  1458. int do_once; // true: only go through packet loop once
  1459. int ack_req; // 0 = no ack required on outgoing packet
  1460. int packetlen; // size of meta-packet sent
  1461. //------------------------------------------------------------------------
  1462. // Determine how many events it's OK to send this frame.
  1463. //------------------------------------------------------------------------
  1464. //........................................................................
  1465. // If we have 4 or more packets queued for sending, don't add any more
  1466. // this frame.
  1467. //........................................................................
  1468. if (net->Private_Num_Send() >= 4) {
  1469. cap = 0;
  1470. do_once = 1;
  1471. }
  1472. //........................................................................
  1473. // If there are 2 or more packets queued, the entire packet we send must
  1474. // fit within a single ComQueue buffer, so limit # events to 5.
  1475. // (The Modem connection manager has a max buffer size of 200 bytes, which
  1476. // is large enough for 6 uncompressed events, which leaves room for 5
  1477. // events plus a FRAMEINFO.)
  1478. //........................................................................
  1479. else if (net->Private_Num_Send() >= 2) {
  1480. cap = 5;
  1481. do_once = 1;
  1482. }
  1483. //........................................................................
  1484. // Otherwise, just send all events in the OutList
  1485. //........................................................................
  1486. else {
  1487. cap = OutList.Count;
  1488. do_once = 0;
  1489. }
  1490. //........................................................................
  1491. // Make sure we aren't sending more events than are in the OutList
  1492. //........................................................................
  1493. if (cap > OutList.Count) {
  1494. cap = OutList.Count;
  1495. }
  1496. //........................................................................
  1497. // Make sure we don't send so many events that our DoList fills up
  1498. //........................................................................
  1499. if (cap > (MAX_EVENTS * 64) - DoList.Count) {
  1500. cap = (MAX_EVENTS * 64) - DoList.Count;
  1501. }
  1502. //
  1503. // 10/21/96 5:12PM - ST
  1504. //
  1505. if (Session.Type == GAME_INTERNET || Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM){
  1506. cap = OutList.Count;
  1507. do_once = 0;
  1508. }
  1509. //------------------------------------------------------------------------
  1510. // Build our meta-packet & transmit it.
  1511. //------------------------------------------------------------------------
  1512. while (1) {
  1513. Keyboard->Check();
  1514. Update_Queue_Mono (net, 1);
  1515. //.....................................................................
  1516. // If there are no commands this frame, we'll just be sending a FRAMEINFO
  1517. // packet; no ack is required. For the modem's sake, check
  1518. // Session.NumPlayers; no ACK is needed if we're just sending to someone
  1519. // who's left the game.
  1520. //.....................................................................
  1521. if (cap == 0 || OutList.Count == 0 || Session.NumPlayers == 1) {
  1522. ack_req = 0;
  1523. }
  1524. else {
  1525. ack_req = 1;
  1526. }
  1527. //.....................................................................
  1528. // Build & send out our message
  1529. //.....................................................................
  1530. packetlen = Build_Send_Packet (multi_packet_buf, multi_packet_max,
  1531. max_ahead, my_sent, cap);
  1532. net->Send_Private_Message (multi_packet_buf, packetlen, ack_req);
  1533. //.....................................................................
  1534. // Call Service() to actually send the packet
  1535. //.....................................................................
  1536. net->Service();
  1537. //.....................................................................
  1538. // Stop if there's no more data to send, or if our send queue is
  1539. // filling up.
  1540. //.....................................................................
  1541. if (OutList.Count == 0 || do_once) {
  1542. break;
  1543. }
  1544. }
  1545. return (cap);
  1546. } // end of Send_Packets
  1547. /***************************************************************************
  1548. * Send_FrameSync -- Sends a FRAMESYNC packet *
  1549. * *
  1550. * This routine is used to periodically remind the other systems that *
  1551. * we're still here, and to tell them what frame # we're on, in case *
  1552. * they've missed my FRAMEINFO packets. *
  1553. * *
  1554. * INPUT: *
  1555. * net ptr to connection manager *
  1556. * cmd_count # commands I've sent so far *
  1557. * *
  1558. * OUTPUT: *
  1559. * none. *
  1560. * *
  1561. * WARNINGS: *
  1562. * none. *
  1563. * *
  1564. * HISTORY: *
  1565. * 11/21/1995 BRR : Created. *
  1566. *=========================================================================*/
  1567. static void Send_FrameSync(ConnManClass *net, int cmd_count)
  1568. {
  1569. EventClass packet;
  1570. //------------------------------------------------------------------------
  1571. // Build a frame-sync event to send. FRAMESYNC packets contain a
  1572. // scenario-based CRC rather than a game-state-based CRC, to let the
  1573. // games compare scenario CRC's on startup.
  1574. //------------------------------------------------------------------------
  1575. memset (&packet, 0, sizeof(EventClass));
  1576. packet.Type = EventClass::FRAMESYNC;
  1577. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  1578. packet.Frame = ((Frame + Session.MaxAhead + (Session.FrameSendRate - 1)) /
  1579. Session.FrameSendRate) * Session.FrameSendRate;
  1580. }
  1581. else {
  1582. packet.Frame = Frame + Session.MaxAhead;
  1583. }
  1584. packet.ID = PlayerPtr->ID;
  1585. packet.Data.FrameInfo.CRC = ScenarioCRC;
  1586. packet.Data.FrameInfo.CommandCount = cmd_count;
  1587. packet.Data.FrameInfo.Delay = Session.MaxAhead;
  1588. //------------------------------------------------------------------------
  1589. // Send the event. For modem, this just sends to the other player;
  1590. // for network, it sends to everyone we're connected to.
  1591. //------------------------------------------------------------------------
  1592. net->Send_Private_Message (&packet, (offsetof(EventClass, Data) +
  1593. size_of(EventClass, Data.FrameInfo)), 0 );
  1594. return;
  1595. } // end of Send_FrameSync
  1596. /***************************************************************************
  1597. * Process_Receive_Packet -- processes an incoming packet *
  1598. * *
  1599. * This routine receives a packet from another system, adds it to our *
  1600. * execution queue (the DoList), and updates my arrays of their frame #, *
  1601. * their commands-sent, and their commands-received. *
  1602. * *
  1603. * INPUT: *
  1604. * net ptr to connection manager *
  1605. * multi_packet_buf buffer containing packet(s) to parse *
  1606. * id id of sender *
  1607. * their_frame array containing frame #'s of other players *
  1608. * their_sent array containing command count of other players *
  1609. * their_recv array containing # recv'd cmds from other players *
  1610. * *
  1611. * OUTPUT: *
  1612. * RC_NORMAL: nothing unusual happened, although *
  1613. * their_sent or their_recv may have been *
  1614. * altered *
  1615. * RC_PLAYER_READY: player has been heard from for the 1st time; *
  1616. * this presumes that his original *
  1617. * 'their_frame[]' value was -1 when this *
  1618. * routine was called *
  1619. * RC_SCENARIO_MISMATCH: FRAMEINFO scenario CRC doesn't match; *
  1620. * normally only applies after loading a new *
  1621. * scenario or save-game *
  1622. * RC_DOLIST_FULL: fatal error; unable to add events to DoList *
  1623. * *
  1624. * WARNINGS: *
  1625. * none. *
  1626. * *
  1627. * HISTORY: *
  1628. * 11/21/1995 BRR : Created. *
  1629. *=========================================================================*/
  1630. static RetcodeType Process_Receive_Packet(ConnManClass *net,
  1631. char *multi_packet_buf, int id, int packetlen, long *their_frame,
  1632. unsigned short *their_sent, unsigned short *their_recv)
  1633. {
  1634. EventClass *event;
  1635. int index;
  1636. RetcodeType retcode = RC_NORMAL;
  1637. int i;
  1638. //------------------------------------------------------------------------
  1639. // Get an event ptr to the incoming message
  1640. //------------------------------------------------------------------------
  1641. event = (EventClass *)multi_packet_buf;
  1642. //------------------------------------------------------------------------
  1643. // Get the index of the sender
  1644. //------------------------------------------------------------------------
  1645. index = net->Connection_Index(id);
  1646. //------------------------------------------------------------------------
  1647. // Compute the other player's frame # (at the time this packet was sent)
  1648. //------------------------------------------------------------------------
  1649. if (their_frame[index] <
  1650. (int)(event->Frame - event->Data.FrameInfo.Delay)) {
  1651. //.....................................................................
  1652. // If the original frame # for this player is -1, it means we've heard
  1653. // from this player for the 1st time; return the appropriate value.
  1654. //.....................................................................
  1655. if (their_frame[index]==-1) {
  1656. retcode = RC_PLAYER_READY;
  1657. }
  1658. their_frame[index] = event->Frame - event->Data.FrameInfo.Delay;
  1659. }
  1660. //------------------------------------------------------------------------
  1661. // Extract the other player's CommandCount. This count will include
  1662. // the commands in this packet, if there are any.
  1663. //------------------------------------------------------------------------
  1664. if (event->Data.FrameInfo.CommandCount > their_sent[index]) {
  1665. if ( abs(their_sent[index] - event->Data.FrameInfo.CommandCount) > 500) {
  1666. FILE *fp;
  1667. fp = fopen("badcount.txt","wt");
  1668. if (fp) {
  1669. fprintf(fp,"Event Type:%s\n",EventClass::EventNames[event->Type]);
  1670. fprintf(fp,"Frame:%d ID:%d IsExec:%d\n",
  1671. event->Frame,
  1672. event->ID,
  1673. event->IsExecuted);
  1674. if (event->Type != EventClass::FRAMEINFO) {
  1675. fprintf(fp,"Wrong Event Type!\n");
  1676. } else {
  1677. fprintf(fp,"CRC:%x CommandCount:%d Delay:%d\n",
  1678. event->Data.FrameInfo.CRC,
  1679. event->Data.FrameInfo.CommandCount,
  1680. event->Data.FrameInfo.Delay);
  1681. }
  1682. }
  1683. }
  1684. their_sent[index] = event->Data.FrameInfo.CommandCount;
  1685. }
  1686. if (Debug_Print_Events) {
  1687. if (event->Type == EventClass::FRAMESYNC) {
  1688. printf("(%d) Received FRAMESYNC: ", Frame);
  1689. } else {
  1690. printf("(%d) Received FRAMEINFO: ", Frame);
  1691. }
  1692. printf("EvFrame:%d ID:%d CRC:%x CmdCount:%d Delay:%d\n",
  1693. event->Frame,
  1694. event->ID,
  1695. event->Data.FrameInfo.CRC,
  1696. event->Data.FrameInfo.CommandCount,
  1697. event->Data.FrameInfo.Delay);
  1698. }
  1699. //------------------------------------------------------------------------
  1700. // If this packet was not a FRAMESYNC packet:
  1701. // - Add the events in it to our DoList
  1702. // - Increment our commands-received counter by the number of non-
  1703. // FRAMEINFO packets received
  1704. //------------------------------------------------------------------------
  1705. if (event->Type != EventClass::FRAMESYNC) {
  1706. //.....................................................................
  1707. // Break up the packet into its component events. A returned packet
  1708. // count of -1 indicates a fatal queue-full error.
  1709. //.....................................................................
  1710. i = Breakup_Receive_Packet( multi_packet_buf, packetlen);
  1711. if (i==-1) {
  1712. return (RC_DOLIST_FULL);
  1713. }
  1714. //.....................................................................
  1715. // Compute the actual # commands in the packet by subtracting off the
  1716. // FRAMEINFO event
  1717. //.....................................................................
  1718. if ( (event->Type==EventClass::FRAMEINFO) && (i > 0)) {
  1719. i--;
  1720. }
  1721. their_recv[index] += i;
  1722. }
  1723. //------------------------------------------------------------------------
  1724. // If the event was a FRAMESYNC packet, there will be no commands to add,
  1725. // but we must check the ScenarioCRC value.
  1726. //------------------------------------------------------------------------
  1727. else if (event->Data.FrameInfo.CRC != ScenarioCRC) {
  1728. return (RC_SCENARIO_MISMATCH);
  1729. }
  1730. return (retcode);
  1731. } // end of Process_Receive_Packet
  1732. /***************************************************************************
  1733. * Process_Serial_Packet -- Handles an incoming serial packet *
  1734. * *
  1735. * This routine is needed because the modem classes don't support a *
  1736. * "global channel" like the network classes do, but that functionality is *
  1737. * still needed for modem communications. Specifically, the modem dialogs *
  1738. * transmit their own special packets back & forth, and messages are sent *
  1739. * using a special packet type. Thus, we have to call this routine when *
  1740. * we receive a modem packet, to allow it to process messages & dialog *
  1741. * packets. *
  1742. * *
  1743. * INPUT: *
  1744. * multi_packet_buf packet buffer to process *
  1745. * first_time 1 = this is the 1st game frame *
  1746. * *
  1747. * OUTPUT: *
  1748. * RC_NORMAL: this wasn't a SERIAL-type packet *
  1749. * RC_SERIAL_PROCESSED: this was a SERIAL-type packet, and was *
  1750. * processed; the other player is still connected, *
  1751. * even if he's not in the game. *
  1752. * RC_PLAYER_LEFT: other player has left the game *
  1753. * RC_HUNG_UP: we're getting our own packets back; thus, the *
  1754. * modem is mirroring our packets, which means the *
  1755. * modem hung up! *
  1756. * *
  1757. * WARNINGS: *
  1758. * none. *
  1759. * *
  1760. * HISTORY: *
  1761. * 11/21/1995 BRR : Created. *
  1762. *=========================================================================*/
  1763. static RetcodeType Process_Serial_Packet(char *multi_packet_buf,
  1764. int first_time)
  1765. {
  1766. SerialPacketType *serial_packet; // for parsing serial packets
  1767. int player_gone;
  1768. EventClass *event;
  1769. //------------------------------------------------------------------------
  1770. // Determine if this packet means that the other player has left the game
  1771. //------------------------------------------------------------------------
  1772. serial_packet = (SerialPacketType *)multi_packet_buf;
  1773. player_gone = 0;
  1774. //........................................................................
  1775. // On Frame 0, only a SIGN_OFF means the other player left; the other
  1776. // packet types may be left over from a previous session.
  1777. //........................................................................
  1778. if (first_time) {
  1779. if (serial_packet->Command == SERIAL_SIGN_OFF) {
  1780. player_gone = 1;
  1781. }
  1782. }
  1783. //........................................................................
  1784. // On subsequent frames, any of SIGN_OFF, TIMING, or SCORE_SCREEN means
  1785. // the other player is gone.
  1786. //........................................................................
  1787. else {
  1788. if (serial_packet->Command == SERIAL_SIGN_OFF ||
  1789. serial_packet->Command == SERIAL_TIMING ||
  1790. serial_packet->Command == SERIAL_SCORE_SCREEN ) {
  1791. player_gone = 1;
  1792. }
  1793. }
  1794. if (player_gone) {
  1795. Destroy_Null_Connection(serial_packet->ScenarioInfo.Color, 0);
  1796. return (RC_PLAYER_LEFT);
  1797. }
  1798. //------------------------------------------------------------------------
  1799. // Process an incoming message
  1800. //------------------------------------------------------------------------
  1801. if (serial_packet->Command == SERIAL_MESSAGE) {
  1802. if (!Session.Messages.Concat_Message(serial_packet->Name,
  1803. serial_packet->ID, serial_packet->Message.Message, Rule.MessageDelay * TICKS_PER_MINUTE)) {
  1804. #ifdef FIXIT_CSII // checked - ajw 9/28/98 - Appears to do nothing
  1805. char *ptr = &serial_packet->Message.Message[0];
  1806. if (!strncmp(ptr,"SECRET UNITS ON ",15) && NewUnitsEnabled) {
  1807. Enable_Secret_Units();
  1808. }
  1809. #endif
  1810. Session.Messages.Add_Message (serial_packet->Name,
  1811. serial_packet->ID, serial_packet->Message.Message,
  1812. (PlayerColorType)serial_packet->ID,
  1813. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, Rule.MessageDelay * TICKS_PER_MINUTE);
  1814. Sound_Effect(VOC_INCOMING_MESSAGE);
  1815. }
  1816. //.....................................................................
  1817. // Save this message in our last-message buffer
  1818. //.....................................................................
  1819. if (strlen (serial_packet->Message.Message)) {
  1820. strcpy (Session.LastMessage, serial_packet->Message.Message);
  1821. }
  1822. //.....................................................................
  1823. // Tell the map to do a partial update (just to force the
  1824. // messages to redraw).
  1825. //.....................................................................
  1826. //Map.Flag_To_Redraw(false);
  1827. Map.Flag_To_Redraw(true);
  1828. return (RC_SERIAL_PROCESSED);
  1829. }
  1830. //------------------------------------------------------------------------
  1831. // Any other SERIAL-type packet means the other player is still there;
  1832. // throw them away, but let the caller know the connection is OK.
  1833. //------------------------------------------------------------------------
  1834. if ( (serial_packet->Command >= SERIAL_CONNECT &&
  1835. serial_packet->Command < SERIAL_LAST_COMMAND) ||
  1836. (serial_packet->Command >= SERIAL_REQ_SCENARIO &&
  1837. serial_packet->Command <= SERIAL_NO_SCENARIO) ||
  1838. Session.NumPlayers == 1) {
  1839. return (RC_SERIAL_PROCESSED);
  1840. }
  1841. //........................................................................
  1842. // are we getting our own packets back??
  1843. //........................................................................
  1844. event = (EventClass *)multi_packet_buf;
  1845. if (event->Type <= EventClass::EMPTY || event->Type >= EventClass::LAST_EVENT) return (RC_SERIAL_PROCESSED);
  1846. if (event->ID == PlayerPtr->ID) {
  1847. return (RC_HUNG_UP);
  1848. }
  1849. return (RC_NORMAL);
  1850. } // end of Process_Serial_Packet
  1851. /***************************************************************************
  1852. * Can_Advance -- determines if it's OK to advance to the next frame *
  1853. * *
  1854. * This routine uses the current values stored in their_frame[], *
  1855. * their_send[], and their_recv[] to see if it's OK to advance to the next *
  1856. * game frame. We must not advance if: *
  1857. * - If our frame # would be too far ahead of the slowest player (the *
  1858. * lowest their_frame[] value). "Too far" means *
  1859. * (Frame >= their_frame + MaxAhead). *
  1860. * - our current command count doesn't match the sent command count of one *
  1861. * other player (meaning that we've missed a command packet from that *
  1862. * player, and thus the frame # we're receiving from him may be due to a *
  1863. * FRAMEINFO packet sent later than the command, so we shouldn't use *
  1864. * this frame # to see if we should advance; we should wait until we *
  1865. * have all the commands before we advance. *
  1866. * *
  1867. * Of course, this routine assumes the values in their_frame[] etc are *
  1868. * kept current by the caller. *
  1869. * *
  1870. * INPUT: *
  1871. * net ptr to connection manager *
  1872. * max_ahead max frames ahead *
  1873. * their_frame array of their frame #'s *
  1874. * their_sent array of their sent command count *
  1875. * their_recv array of their # received commands *
  1876. * *
  1877. * OUTPUT: *
  1878. * 1 = OK to advance; 0 = not OK *
  1879. * *
  1880. * WARNINGS: *
  1881. * none. *
  1882. * *
  1883. * HISTORY: *
  1884. * 11/21/1995 BRR : Created. *
  1885. *=========================================================================*/
  1886. static int Can_Advance(ConnManClass *net, int max_ahead, long *their_frame,
  1887. unsigned short *their_sent, unsigned short *their_recv)
  1888. {
  1889. long their_oldest_frame; // other players' oldest frame #
  1890. int count_ok; // true = my cmd count matches theirs
  1891. int i;
  1892. //------------------------------------------------------------------------
  1893. // Special case for modem: if the other player has left, go ahead and
  1894. // advance to the next frame; don't wait on him.
  1895. //------------------------------------------------------------------------
  1896. if (Session.NumPlayers == 1) {
  1897. return (1);
  1898. }
  1899. //------------------------------------------------------------------------
  1900. // Find the oldest frame # in 'their_frame'
  1901. //------------------------------------------------------------------------
  1902. their_oldest_frame = Frame + 1000;
  1903. for (i = 0; i < net->Num_Connections(); i++) {
  1904. if (their_frame[i] < their_oldest_frame)
  1905. their_oldest_frame = their_frame[i];
  1906. }
  1907. //------------------------------------------------------------------------
  1908. // I can advance to the next frame IF:
  1909. // 1) I'm less than a one-way propagation delay ahead of the other
  1910. // players' frame numbers, AND
  1911. // 2) their_recv[i] >= their_sent[i] (ie I've received all the commands
  1912. // the other players have sent so far).
  1913. //------------------------------------------------------------------------
  1914. count_ok = 1;
  1915. for (i = 0; i < net->Num_Connections(); i++) {
  1916. if (their_recv[i] < their_sent[i]) {
  1917. count_ok = 0;
  1918. break;
  1919. }
  1920. }
  1921. if (count_ok && (Frame < (their_oldest_frame + max_ahead))) {
  1922. return (1);
  1923. }
  1924. return (0);
  1925. } // end of Can_Advance
  1926. /***************************************************************************
  1927. * Process_Reconnect_Dialog -- processes the reconnection dialog *
  1928. * *
  1929. * This routine [re]draws the reconnection dialog; if 'reconn' is set, *
  1930. * it tells the user who we're trying to reconnect to; otherwise, is just *
  1931. * says something generic like "Waiting for connections". *
  1932. * *
  1933. * INPUT: *
  1934. * timeout_timer ptr to count down timer, showing time remaining *
  1935. * their_frame array of other players' frame #'s *
  1936. * num_conn # connections in 'their_frame' *
  1937. * reconn 1 = reconnect, 0 = waiting for first-time connection *
  1938. * fresh 1 = draw from scratch, 0 = only update time counter *
  1939. * *
  1940. * OUTPUT: *
  1941. * 1 = user wants to cancel, 0 = not *
  1942. * *
  1943. * WARNINGS: *
  1944. * *
  1945. * HISTORY: *
  1946. * 11/21/1995 BRR : Created. *
  1947. *=========================================================================*/
  1948. static int Process_Reconnect_Dialog(CDTimerClass<SystemTimerClass> *timeout_timer,
  1949. long *their_frame, int num_conn, int reconn, int fresh)
  1950. {
  1951. static int displayed_time = 0; // time value currently displayed
  1952. int new_time;
  1953. int oldest_index; // index of person requiring a reconnect
  1954. int i,j;
  1955. //------------------------------------------------------------------------
  1956. // Convert the timer to seconds
  1957. //------------------------------------------------------------------------
  1958. new_time = *timeout_timer / 60;
  1959. //------------------------------------------------------------------------
  1960. // If the timer has changed, or 'fresh' is set, redraw the dialog
  1961. //------------------------------------------------------------------------
  1962. if (fresh || (new_time != displayed_time)) {
  1963. //.....................................................................
  1964. // Find the index of the person we're trying to reconnect to
  1965. //.....................................................................
  1966. if (reconn) {
  1967. j = 0x7fffffff;
  1968. oldest_index = 0;
  1969. for (i = 0; i < num_conn; i++) {
  1970. if (their_frame[i] < j) {
  1971. j = their_frame[i];
  1972. oldest_index = i;
  1973. }
  1974. }
  1975. }
  1976. Net_Reconnect_Dialog(reconn, fresh, oldest_index, new_time);
  1977. }
  1978. displayed_time = new_time;
  1979. //........................................................................
  1980. // If user hits ESC, bail out
  1981. //........................................................................
  1982. if (Keyboard->Check()) {
  1983. if (Keyboard->Get() == KN_ESC) {
  1984. return (1);
  1985. }
  1986. }
  1987. return (0);
  1988. } // end of Process_Reconnect_Dialog
  1989. /***************************************************************************
  1990. * Handle_Timeout -- handles a timeout in the wait-for-players loop *
  1991. * *
  1992. * This routine "gracefully" handles a timeout in the frame-sync loop. *
  1993. * The timeout must be handled differently by a modem game or network *
  1994. * game. *
  1995. * *
  1996. * The modem game must detect if the other player is still connected *
  1997. * physically, even if he's not playing the game any more; if so, this *
  1998. * routine returns an OK status. If the other player isn't even *
  1999. * physically connected, an error is returned. *
  2000. * *
  2001. * The network game must find the connection that's causing the timeout, *
  2002. * and destroy it. The game continues, even if there are no more human *
  2003. * players left. *
  2004. * *
  2005. * INPUT: *
  2006. * net ptr to connection manager *
  2007. * their_frame array containing frame #'s of other players *
  2008. * their_sent array containing command count of other players *
  2009. * their_recv array containing # recv'd cmds from other players *
  2010. * *
  2011. * OUTPUT: *
  2012. * 1 = it's OK; reset timeout timers & keep processing *
  2013. * 0 = game over, man *
  2014. * *
  2015. * WARNINGS: *
  2016. * *
  2017. * HISTORY: *
  2018. * 11/21/1995 BRR : Created. *
  2019. *=========================================================================*/
  2020. static int Handle_Timeout(ConnManClass *net, long *their_frame,
  2021. unsigned short *their_sent, unsigned short *their_recv)
  2022. {
  2023. int oldest_index; // index of person requiring a reconnect
  2024. int i,j;
  2025. int id;
  2026. //------------------------------------------------------------------------
  2027. // For modem, attempt to reconnect; if that fails, save the game & bail.
  2028. //------------------------------------------------------------------------
  2029. if (Session.Type == GAME_MODEM || Session.Type == GAME_NULL_MODEM) {
  2030. if ( net->Num_Connections() ) {
  2031. if (!Reconnect_Modem()) {
  2032. #ifndef FIXIT_MULTI_SAVE
  2033. //...............................................................
  2034. // Set 'Session.EmergencySave', so when this game is loaded, we
  2035. // won't check the CRC of the game state (this system & the
  2036. // other may be on different frames, in which case the CRC
  2037. // won't match).
  2038. //...............................................................
  2039. Session.EmergencySave = 1;
  2040. //Save_Game (-1, (char *)Text_String(TXT_MULTIPLAYER_GAME));
  2041. Session.EmergencySave = 0;
  2042. #endif // FIXIT_MULTI_SAVE
  2043. return (0);
  2044. } else {
  2045. return (1);
  2046. }
  2047. }
  2048. }
  2049. //------------------------------------------------------------------------
  2050. // For network, destroy the oldest connection
  2051. //------------------------------------------------------------------------
  2052. else if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET ||
  2053. Session.Type == GAME_TEN || Session.Type == GAME_MPATH) {
  2054. j = 0x7fffffff;
  2055. oldest_index = 0;
  2056. for (i = 0; i < net->Num_Connections(); i++) {
  2057. if (their_frame[i] < j) {
  2058. j = their_frame[i];
  2059. oldest_index = i;
  2060. }
  2061. }
  2062. id = net->Connection_ID(oldest_index);
  2063. #ifdef WIN32
  2064. /*
  2065. ** Send the game statistics packet now if the game is effectivly over
  2066. */
  2067. if (Session.Players.Count() == 2 &&
  2068. Session.Type == GAME_INTERNET &&
  2069. !GameStatisticsPacketSent) {
  2070. Register_Game_End_Time();
  2071. ConnectionLost = true;
  2072. Send_Statistics_Packet(); // Disconnect, and I'll be the only one left.
  2073. }
  2074. #endif //WIN32
  2075. if (id != ConnManClass::CONNECTION_NONE) {
  2076. for (i = oldest_index; i < net->Num_Connections() - 1; i++) {
  2077. their_frame[i] = their_frame[i+1];
  2078. their_sent[i] = their_sent[i+1];
  2079. their_recv[i] = their_recv[i+1];
  2080. }
  2081. if (Session.Type == GAME_IPX || Session.Type == GAME_INTERNET) {
  2082. Destroy_Connection(id,1);
  2083. }
  2084. #if(TEN)
  2085. else if (Session.Type == GAME_TEN) {
  2086. Destroy_TEN_Connection(id,1);
  2087. }
  2088. #endif
  2089. #if(MPATH)
  2090. else if (Session.Type == GAME_MPATH) {
  2091. Destroy_MPATH_Connection(id,1);
  2092. }
  2093. #endif
  2094. }
  2095. }
  2096. return (1);
  2097. } // end of Handle_Timeout
  2098. /***************************************************************************
  2099. * Stop_Game -- stops the game *
  2100. * *
  2101. * This routine clears any global flags that need it, in preparation for *
  2102. * halting the game prematurely. *
  2103. * *
  2104. * INPUT: *
  2105. * none. *
  2106. * *
  2107. * OUTPUT: *
  2108. * none. *
  2109. * *
  2110. * WARNINGS: *
  2111. * none. *
  2112. * *
  2113. * HISTORY: *
  2114. * 11/22/1995 BRR : Created. *
  2115. *=========================================================================*/
  2116. static void Stop_Game(void)
  2117. {
  2118. Session.LoadGame = false;
  2119. Session.EmergencySave = false;
  2120. GameActive = 0;
  2121. if (IsMono) {
  2122. MonoClass::Disable();
  2123. }
  2124. #ifdef WIN32
  2125. if (Session.Type == GAME_INTERNET){
  2126. ConnectionLost = true;
  2127. Send_Statistics_Packet(); // Stop_Game()
  2128. }
  2129. #endif //WIN32
  2130. return;
  2131. } // end of Stop_Game
  2132. /***************************************************************************
  2133. * Build_Send_Packet -- Builds a big packet from a bunch of little ones. *
  2134. * *
  2135. * This routine takes events from the OutList, and puts them into a *
  2136. * "meta-packet", which is transmitted to all systems we're connected to. *
  2137. * Also, these events are added to our own DoList. *
  2138. * *
  2139. * Every Meta-Packet we send uses a FRAMEINFO packet as a header; this *
  2140. * tells the other systems what frame we're on, as well as serving as a *
  2141. * standard packet header. *
  2142. * *
  2143. * INPUT: *
  2144. * buf buffer to store packet in *
  2145. * bufsize max size of buffer *
  2146. * frame_delay desired frame delay to attach to all outgoing packets *
  2147. * num_cmds value to use for the CommandCount field *
  2148. * cap max # events to send *
  2149. * *
  2150. * OUTPUT: *
  2151. * new size of packet *
  2152. * *
  2153. * WARNINGS: *
  2154. * 'num_cmds' should be the total of of commands, including all those sent *
  2155. * this frame! *
  2156. * *
  2157. * HISTORY: *
  2158. * 11/21/1995 BRR : Created. *
  2159. *=========================================================================*/
  2160. static int Build_Send_Packet(void *buf, int bufsize, int frame_delay,
  2161. int num_cmds, int cap)
  2162. {
  2163. int size = 0;
  2164. EventClass *finfo;
  2165. //------------------------------------------------------------------------
  2166. // All events start with a FRAMEINFO event; fill this part in.
  2167. //------------------------------------------------------------------------
  2168. //........................................................................
  2169. // Set the event type
  2170. //........................................................................
  2171. finfo = (EventClass *)buf;
  2172. finfo->Type = EventClass::FRAMEINFO;
  2173. //........................................................................
  2174. // Set the frame to execute this event on; this is protocol-specific
  2175. //........................................................................
  2176. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  2177. finfo->Frame = ((Frame + frame_delay + (Session.FrameSendRate - 1)) /
  2178. Session.FrameSendRate) * Session.FrameSendRate;
  2179. }
  2180. else {
  2181. finfo->Frame = Frame + frame_delay;
  2182. }
  2183. //........................................................................
  2184. // Fill in the rest of the event
  2185. //........................................................................
  2186. finfo->ID = PlayerPtr->ID;
  2187. finfo->Data.FrameInfo.CRC = GameCRC;
  2188. finfo->Data.FrameInfo.CommandCount = num_cmds;
  2189. finfo->Data.FrameInfo.Delay = frame_delay;
  2190. //------------------------------------------------------------------------
  2191. // Initialize the # of bytes processed; this is protocol-specific
  2192. //------------------------------------------------------------------------
  2193. if (Session.CommProtocol==COMM_PROTOCOL_SINGLE_NO_COMP) {
  2194. size += sizeof(EventClass);
  2195. }
  2196. else {
  2197. size += (offsetof(EventClass, Data) +
  2198. size_of(EventClass, Data.FrameInfo));
  2199. }
  2200. //------------------------------------------------------------------------
  2201. // Transfer all events from the OutList into the DoList, building our
  2202. // packet while we go.
  2203. //------------------------------------------------------------------------
  2204. switch (Session.CommProtocol) {
  2205. //.....................................................................
  2206. // COMM_PROTOCOL_SINGLE_NO_COMP:
  2207. // We'll send at least a FRAMEINFO every single frame, no compression
  2208. //.....................................................................
  2209. case (COMM_PROTOCOL_SINGLE_NO_COMP):
  2210. size = Add_Uncompressed_Events(buf, bufsize, frame_delay, size, cap);
  2211. break;
  2212. //.....................................................................
  2213. // COMM_PROTOCOL_SINGLE_E_COMP:
  2214. // Compress a group of packets into our send buffer; send out
  2215. // compressed packets every frame.
  2216. // COMM_PROTOCOL_MULTI_E_COMP:
  2217. // Compress a group of packets into our send buffer; send out
  2218. // compressed packets every 'n' frames.
  2219. //.....................................................................
  2220. case (COMM_PROTOCOL_SINGLE_E_COMP):
  2221. case (COMM_PROTOCOL_MULTI_E_COMP):
  2222. size = Add_Compressed_Events(buf, bufsize, frame_delay, size, cap);
  2223. break;
  2224. //.....................................................................
  2225. // Default: We have no idea what to do, so do nothing.
  2226. //.....................................................................
  2227. default:
  2228. size = 0;
  2229. break;
  2230. }
  2231. return( size );
  2232. } /* end of Build_Send_Packet */
  2233. /***************************************************************************
  2234. * Add_Uncompressed_Events -- adds uncompressed events to a packet *
  2235. * *
  2236. * INPUT: *
  2237. * buf buffer to store packet in *
  2238. * bufsize max size of buffer *
  2239. * frame_delay desired frame delay to attach to all outgoing packets *
  2240. * size current packet size *
  2241. * cap max # events to process *
  2242. * *
  2243. * OUTPUT: *
  2244. * new size value *
  2245. * *
  2246. * WARNINGS: *
  2247. * This routine MUST check to be sure it doesn't overflow the buffer. *
  2248. * *
  2249. * HISTORY: *
  2250. * 11/21/1995 DRD : Created. *
  2251. *=========================================================================*/
  2252. static int Add_Uncompressed_Events(void *buf, int bufsize, int frame_delay,
  2253. int size, int cap)
  2254. {
  2255. int num = 0; // # of events processed
  2256. int ev_size; // size of event we're adding
  2257. //------------------------------------------------------------------------
  2258. // Loop until there are no more events, or we've processed our max # of
  2259. // events, or the buffer is full.
  2260. //------------------------------------------------------------------------
  2261. while (OutList.Count && (num < cap)) {
  2262. Keyboard->Check();
  2263. if (OutList.First().Type==EventClass::ADDPLAYER) {
  2264. ev_size = sizeof(EventClass) + OutList.First().Data.Variable.Size;
  2265. }
  2266. else {
  2267. ev_size = sizeof(EventClass);
  2268. }
  2269. //.....................................................................
  2270. // Will the next event exceed the size of the buffer? If so, break.
  2271. //.....................................................................
  2272. if ( (size + ev_size) > bufsize ) {
  2273. return (size);
  2274. }
  2275. //.....................................................................
  2276. // Set the event's frame delay
  2277. //.....................................................................
  2278. OutList.First().Frame = Frame + frame_delay;
  2279. //.....................................................................
  2280. // Set the event's ID
  2281. //.....................................................................
  2282. OutList.First().ID = PlayerPtr->ID;
  2283. //.....................................................................
  2284. // Transfer the event in OutList to DoList, un-queue the OutList
  2285. // event. If the DoList is full, stop transferring immediately.
  2286. //.....................................................................
  2287. OutList.First().IsExecuted = 0;
  2288. if (!DoList.Add(OutList.First())) {
  2289. return (size);
  2290. }
  2291. #ifdef MIRROR_QUEUE
  2292. MirrorList.Add(OutList.First());
  2293. #endif
  2294. //.....................................................................
  2295. // Add event to the send packet
  2296. //.....................................................................
  2297. if (OutList.First().Type==EventClass::ADDPLAYER) {
  2298. memcpy ( ((char *)buf) + size, &OutList.First(), sizeof(EventClass) );
  2299. size += sizeof(EventClass);
  2300. memcpy ( ((char *)buf) + size,
  2301. OutList.First().Data.Variable.Pointer,
  2302. OutList.First().Data.Variable.Size);
  2303. size += OutList.First().Data.Variable.Size;
  2304. }
  2305. else {
  2306. memcpy ( ((char *)buf) + size, &OutList.First(), sizeof(EventClass) );
  2307. size += sizeof(EventClass);
  2308. }
  2309. //.....................................................................
  2310. // Increment our event counter; delete the last event from the queue
  2311. //.....................................................................
  2312. num++;
  2313. OutList.Next();
  2314. }
  2315. return (size);
  2316. } // end of Add_Uncompressed_Events
  2317. /***************************************************************************
  2318. * Add_Compressed_Events -- adds an compressed events to a packet *
  2319. * *
  2320. * INPUT: *
  2321. * buf buffer to store packet in *
  2322. * bufsize max size of buffer *
  2323. * frame_delay desired frame delay to attach to all outgoing packets *
  2324. * size reference to current packet size *
  2325. * cap max # events to process *
  2326. * *
  2327. * OUTPUT: *
  2328. * new size value *
  2329. * *
  2330. * WARNINGS: *
  2331. * This routine MUST check to be sure it doesn't overflow the buffer. *
  2332. * *
  2333. * HISTORY: *
  2334. * 11/21/1995 DRD : Created. *
  2335. *=========================================================================*/
  2336. static int Add_Compressed_Events(void *buf, int bufsize, int frame_delay,
  2337. int size, int cap)
  2338. {
  2339. int num = 0; // # of events processed
  2340. EventClass::EventType eventtype; // type of event being compressed
  2341. EventClass prevevent; // last event processed
  2342. int datasize; // size of element plucked from event union
  2343. int storedsize; // actual # bytes stored from event
  2344. unsigned char *unitsptr = NULL; // ptr to buffer pos to store mega. rep count
  2345. unsigned char numunits = 0; // megamission rep count value
  2346. bool missiondup = false; // flag: is this event a megamission repeat?
  2347. //------------------------------------------------------------------------
  2348. // clear previous event
  2349. //------------------------------------------------------------------------
  2350. memset (&prevevent, 0, sizeof(EventClass));
  2351. if (Debug_Print_Events) {
  2352. printf("\n(%d) Building Send Packet\n", Frame);
  2353. }
  2354. //------------------------------------------------------------------------
  2355. // Loop until there are no more events, we've processed our max # of
  2356. // events, or the buffer is full.
  2357. //------------------------------------------------------------------------
  2358. while (OutList.Count && (num < cap)) {
  2359. Keyboard->Check();
  2360. eventtype = OutList.First().Type;
  2361. datasize = EventClass::EventLength[ eventtype ];
  2362. //.....................................................................
  2363. // For a variable-sized event, pull the size from the event; otherwise,
  2364. // the size will be the data element size plus the event type value.
  2365. // (The other data elements in the event, Frame, ID, etc, are stored
  2366. // in the packet header.)
  2367. //.....................................................................
  2368. if (eventtype==EventClass::ADDPLAYER) {
  2369. storedsize = datasize + sizeof (EventClass::EventType) +
  2370. OutList.First().Data.Variable.Size;
  2371. }
  2372. else {
  2373. storedsize = datasize + sizeof (EventClass::EventType);
  2374. }
  2375. //.....................................................................
  2376. // MegaMission compression: MegaMissions are stored as:
  2377. // EventType
  2378. // Rep Count
  2379. // MegaMission structure (event # 1 only)
  2380. // Whom #2
  2381. // Whom #3
  2382. // Whom #4
  2383. // ...
  2384. // Whom #n
  2385. //.....................................................................
  2386. if (prevevent.Type == EventClass::MEGAMISSION) {
  2387. //..................................................................
  2388. // If previous & current events are both MegaMissions:
  2389. //..................................................................
  2390. if (eventtype == EventClass::MEGAMISSION) {
  2391. //...............................................................
  2392. // If the Mission, Target, & Destination are the same, compress
  2393. // the events into one:
  2394. // - Change datasize to the size of the 'Whom' field only
  2395. // - set total # bytes to store to the size of the 'Whom' only
  2396. // - increment the MegaMission rep count
  2397. // - set the MegaMission rep flag
  2398. //...............................................................
  2399. if (OutList.First().Data.MegaMission.Mission ==
  2400. prevevent.Data.MegaMission.Mission &&
  2401. OutList.First().Data.MegaMission.Target ==
  2402. prevevent.Data.MegaMission.Target &&
  2403. OutList.First().Data.MegaMission.Destination ==
  2404. prevevent.Data.MegaMission.Destination) {
  2405. if (Debug_Print_Events) {
  2406. printf(" adding Whom:%x (%x) Mission:%s Target:%x (%x) Dest:%x (%x)\n",
  2407. OutList.First().Data.MegaMission.Whom.As_TARGET(),
  2408. OutList.First().Data.MegaMission.Whom,
  2409. MissionClass::Mission_Name(OutList.First().Data.MegaMission.Mission),
  2410. OutList.First().Data.MegaMission.Target.As_TARGET(),
  2411. OutList.First().Data.MegaMission.Target,
  2412. OutList.First().Data.MegaMission.Destination.As_TARGET(),
  2413. OutList.First().Data.MegaMission.Destination);
  2414. }
  2415. datasize = sizeof(prevevent.Data.MegaMission.Whom);
  2416. storedsize = datasize;
  2417. numunits++;
  2418. missiondup = true;
  2419. }
  2420. //...............................................................
  2421. // Data doesn't match; start a new run of MegaMissions:
  2422. // - Store previous MegaMission rep count
  2423. // - Init 'unitsptr' to buffer pos after next EventType
  2424. // - set total # bytes to store to 'datasize' + sizeof(EventType) +
  2425. // sizeof (numunits)
  2426. // - init the MegaMission rep count to 1
  2427. // - clear the MegaMission rep flag
  2428. //...............................................................
  2429. else {
  2430. if (Debug_Print_Events) {
  2431. printf(" New MEGAMISSION run:\n");
  2432. }
  2433. *unitsptr = numunits;
  2434. unitsptr = ((unsigned char *)buf) + size +
  2435. sizeof(EventClass::EventType);
  2436. storedsize += sizeof(numunits);
  2437. numunits = 1;
  2438. missiondup = false;
  2439. }
  2440. }
  2441. //..................................................................
  2442. // Previous event was a MegaMission, but this one isn't: end the
  2443. // run of MegaMissions:
  2444. // - Store previous MegaMission rep count
  2445. // - Clear variables
  2446. //..................................................................
  2447. else {
  2448. *unitsptr = numunits; // save # events in our run
  2449. unitsptr = NULL; // init other values
  2450. numunits = 0;
  2451. missiondup = false;
  2452. }
  2453. }
  2454. //.....................................................................
  2455. // The previous event is not a MEGAMISSION but the current event is:
  2456. // Set up a new run of MegaMissions:
  2457. // - Init 'unitsptr' to buffer pos after next EventType
  2458. // - set total # bytes to store to 'datasize' + sizeof(EventType) +
  2459. // sizeof (numunits)
  2460. // - init the MegaMission rep count to 1
  2461. // - clear the MegaMission rep flag
  2462. //.....................................................................
  2463. else if (eventtype == EventClass::MEGAMISSION) {
  2464. if (Debug_Print_Events) {
  2465. printf(" New MEGAMISSION run:\n");
  2466. }
  2467. unitsptr = ((unsigned char *)buf) + size +
  2468. sizeof(EventClass::EventType);
  2469. storedsize += sizeof(numunits);
  2470. numunits = 1;
  2471. missiondup = false;
  2472. }
  2473. //.....................................................................
  2474. // Will the next event exceed the size of the buffer? If so,
  2475. // stop compressing.
  2476. //.....................................................................
  2477. if ( (size + storedsize) > bufsize )
  2478. break;
  2479. //.....................................................................
  2480. // Set the event's frame delay (this is protocol-dependent)
  2481. //.....................................................................
  2482. if (Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  2483. OutList.First().Frame = ((Frame + frame_delay +
  2484. (Session.FrameSendRate - 1)) / Session.FrameSendRate) *
  2485. Session.FrameSendRate;
  2486. }
  2487. else {
  2488. OutList.First().Frame = Frame + frame_delay;
  2489. }
  2490. //.....................................................................
  2491. // Set the event's ID
  2492. //.....................................................................
  2493. OutList.First().ID = PlayerPtr->ID;
  2494. //.....................................................................
  2495. // Transfer the event in OutList to DoList, un-queue the OutList event.
  2496. // If the DoList is full, stop transferring immediately.
  2497. //.....................................................................
  2498. OutList.First().IsExecuted = 0;
  2499. if ( !DoList.Add( OutList.First() ) ) {
  2500. break;
  2501. }
  2502. #ifdef MIRROR_QUEUE
  2503. MirrorList.Add(OutList.First());
  2504. #endif
  2505. //---------------------------------------------------------------------
  2506. // Compress the event into the send packet buffer
  2507. //---------------------------------------------------------------------
  2508. switch ( eventtype ) {
  2509. //..................................................................
  2510. // RESPONSE_TIME: just use the Delay field of the FrameInfo union
  2511. //..................................................................
  2512. case (EventClass::RESPONSE_TIME):
  2513. *(EventClass::EventType *)( ((char *)buf) + size) = eventtype;
  2514. memcpy ( ((char *)buf) + size + sizeof(EventClass::EventType),
  2515. &OutList.First().Data.FrameInfo.Delay, datasize );
  2516. size += (datasize + sizeof(EventClass::EventType));
  2517. break;
  2518. //..................................................................
  2519. // MEGAMISSION:
  2520. //..................................................................
  2521. case (EventClass::MEGAMISSION):
  2522. //...............................................................
  2523. // Repeated mission in a run:
  2524. // - Update the rep count (in case we break out)
  2525. // - Copy the Whom field only
  2526. //...............................................................
  2527. if (missiondup) {
  2528. *unitsptr = numunits;
  2529. memcpy ( ((char *)buf) + size,
  2530. &OutList.First().Data.MegaMission.Whom, datasize );
  2531. size += datasize;
  2532. }
  2533. //...............................................................
  2534. // 1st mission in a run:
  2535. // - Init the rep count (in case we break out)
  2536. // - Set the EventType
  2537. // - Copy the MegaMission structure, leaving room for 'numunits'
  2538. //...............................................................
  2539. else {
  2540. *unitsptr = numunits;
  2541. *(EventClass::EventType *)( ((char *)buf) + size) = eventtype;
  2542. memcpy ( ((char *)buf) + size +
  2543. sizeof(EventClass::EventType) + sizeof(numunits),
  2544. &OutList.First().Data.MegaMission, datasize );
  2545. size += (datasize + sizeof(EventClass::EventType) + sizeof(numunits));
  2546. }
  2547. break;
  2548. //..................................................................
  2549. // Variable-sized packets: Copy the packet Size & the buffer
  2550. //..................................................................
  2551. case (EventClass::ADDPLAYER):
  2552. *(EventClass::EventType *)( ((char *)buf) + size) = eventtype;
  2553. memcpy ( ((char *)buf) + size + sizeof(EventClass::EventType),
  2554. &OutList.First().Data.Variable.Size, datasize );
  2555. size += (datasize + sizeof(EventClass::EventType));
  2556. memcpy ( ((char *)buf) + size,
  2557. OutList.First().Data.Variable.Pointer,
  2558. OutList.First().Data.Variable.Size);
  2559. size += OutList.First().Data.Variable.Size;
  2560. break;
  2561. //..................................................................
  2562. // Default case: Just copy over the data field from the union
  2563. //..................................................................
  2564. default:
  2565. *(EventClass::EventType *)( ((char *)buf) + size) = eventtype;
  2566. memcpy ( ((char *)buf) + size + sizeof(EventClass::EventType),
  2567. &OutList.First().Data, datasize );
  2568. size += (datasize + sizeof(EventClass::EventType));
  2569. break;
  2570. }
  2571. //---------------------------------------------------------------------
  2572. // update # events processed
  2573. //---------------------------------------------------------------------
  2574. num++;
  2575. //---------------------------------------------------------------------
  2576. // Update 'prevevent'
  2577. //---------------------------------------------------------------------
  2578. memcpy ( &prevevent, &OutList.First(), sizeof(EventClass) );
  2579. //---------------------------------------------------------------------
  2580. // Go to the next event to process
  2581. //---------------------------------------------------------------------
  2582. OutList.Next();
  2583. }
  2584. if (Debug_Print_Events) {
  2585. printf("\n");
  2586. }
  2587. return (size);
  2588. } // end of Add_Compressed_Events
  2589. /***************************************************************************
  2590. * Breakup_Receive_Packet -- Splits a big packet into little ones. *
  2591. * *
  2592. * INPUT: *
  2593. * buf buffer to break up *
  2594. * bufsize length of buffer *
  2595. * *
  2596. * OUTPUT: *
  2597. * # events added to queue, -1 if fatal error (queue is full) *
  2598. * (return value includes any FRAMEINFO packets encountered; *
  2599. * FRAMESYNC's are ignored) *
  2600. * *
  2601. * WARNINGS: *
  2602. * none. *
  2603. * *
  2604. * HISTORY: *
  2605. * 11/21/1995 BRR : Created. *
  2606. *=========================================================================*/
  2607. static int Breakup_Receive_Packet(void *buf, int bufsize )
  2608. {
  2609. int count = 0;
  2610. /*
  2611. ** is there enough leftover for another record
  2612. */
  2613. switch (Session.CommProtocol) {
  2614. case (COMM_PROTOCOL_SINGLE_NO_COMP):
  2615. count = Extract_Uncompressed_Events(buf, bufsize);
  2616. break;
  2617. default:
  2618. count = Extract_Compressed_Events(buf, bufsize);
  2619. break;
  2620. }
  2621. return (count);
  2622. } /* end of Breakup_Receive_Packet */
  2623. /***************************************************************************
  2624. * Extract_Uncompressed_Events -- extracts events from a packet *
  2625. * *
  2626. * INPUT: *
  2627. * buf buffer containing events to extract *
  2628. * bufsize length of 'buf' *
  2629. * *
  2630. * OUTPUT: *
  2631. * # events extracted *
  2632. * *
  2633. * WARNINGS: *
  2634. * none. *
  2635. * *
  2636. * HISTORY: *
  2637. * 11/21/1995 DRD : Created. *
  2638. *=========================================================================*/
  2639. static int Extract_Uncompressed_Events(void *buf, int bufsize)
  2640. {
  2641. int count = 0;
  2642. int pos = 0;
  2643. int leftover = bufsize;
  2644. EventClass *event;
  2645. //------------------------------------------------------------------------
  2646. // Loop until there are no more events in the packet
  2647. //------------------------------------------------------------------------
  2648. while (leftover >= sizeof(EventClass) ) {
  2649. Keyboard->Check();
  2650. event = (EventClass *)(((char *)buf) + pos);
  2651. //.....................................................................
  2652. // add event to the DoList, only if it's not a FRAMESYNC
  2653. // (but FRAMEINFO's do get added.)
  2654. //.....................................................................
  2655. if (event->Type != EventClass::FRAMESYNC) {
  2656. event->IsExecuted = 0;
  2657. //..................................................................
  2658. // Special processing for variable-sized events
  2659. //..................................................................
  2660. if (event->Type == EventClass::ADDPLAYER) {
  2661. event->Data.Variable.Pointer = new char[event->Data.Variable.Size];
  2662. memcpy (event->Data.Variable.Pointer,
  2663. ((char *)buf) + sizeof(EventClass),
  2664. event->Data.Variable.Size);
  2665. pos += event->Data.Variable.Size;
  2666. leftover -= event->Data.Variable.Size;
  2667. }
  2668. if (!DoList.Add( *event )) {
  2669. if (event->Type == EventClass::ADDPLAYER) {
  2670. delete [] event->Data.Variable.Pointer;
  2671. }
  2672. return (-1);
  2673. }
  2674. #ifdef MIRROR_QUEUE
  2675. MirrorList.Add(*event);
  2676. #endif
  2677. //..................................................................
  2678. // Keep count of how many events we add to the queue
  2679. //..................................................................
  2680. count++;
  2681. }
  2682. //.....................................................................
  2683. // Point to the next position in the buffer; decrement our 'leftover'
  2684. //.....................................................................
  2685. pos += sizeof(EventClass);
  2686. leftover -= sizeof(EventClass);
  2687. }
  2688. return (count);
  2689. } // end of Extract_Uncompressed_Events
  2690. /***************************************************************************
  2691. * Extract_Compressed_Events -- extracts events from a packet *
  2692. * *
  2693. * INPUT: *
  2694. * buf buffer containing events to extract *
  2695. * bufsize length of 'buf' *
  2696. * *
  2697. * OUTPUT: *
  2698. * # events extracted *
  2699. * *
  2700. * WARNINGS: *
  2701. * none. *
  2702. * *
  2703. * HISTORY: *
  2704. * 11/21/1995 DRD : Created. *
  2705. *=========================================================================*/
  2706. static int Extract_Compressed_Events(void *buf, int bufsize)
  2707. {
  2708. int pos = 0; // current buffer parsing position
  2709. int leftover = bufsize; // # bytes left to process
  2710. EventClass *event; // event ptr for parsing buffer
  2711. int count = 0; // # events processed
  2712. int datasize = 0; // size of data to copy
  2713. EventClass eventdata; // stores Frame, ID, etc
  2714. unsigned char numunits = 0; // # units stored in compressed MegaMissions
  2715. //------------------------------------------------------------------------
  2716. // Clear work event structure
  2717. //------------------------------------------------------------------------
  2718. memset (&eventdata, 0, sizeof(EventClass));
  2719. //------------------------------------------------------------------------
  2720. // Assume the first event is a FRAMEINFO event
  2721. // Init 'datasize' to the amount of data to copy, minus the EventType value
  2722. // For the 1st packet only, this will include all info before the Data
  2723. // union, plus the size of the FrameInfo structure, minus the EventType size.
  2724. //------------------------------------------------------------------------
  2725. datasize = (offsetof(EventClass, Data) +
  2726. size_of(EventClass, Data.FrameInfo)) - sizeof(EventClass::EventType);
  2727. event = (EventClass *)(((char *)buf) + pos);
  2728. while (leftover >= (datasize + sizeof(EventClass::EventType)) ) {
  2729. Keyboard->Check();
  2730. //.....................................................................
  2731. // add event to the DoList, only if it's not a FRAMESYNC
  2732. // (but FRAMEINFO's do get added.)
  2733. //.....................................................................
  2734. if (event->Type != EventClass::FRAMESYNC) {
  2735. //..................................................................
  2736. // initialize the common data from the FRAMEINFO event
  2737. // keeping IsExecuted 0
  2738. //..................................................................
  2739. if (event->Type == EventClass::FRAMEINFO) {
  2740. eventdata.Frame = event->Frame;
  2741. eventdata.ID = event->ID;
  2742. //...............................................................
  2743. // Adjust position past the common data
  2744. //...............................................................
  2745. pos += (offsetof(EventClass, Data) -
  2746. sizeof(EventClass::EventType));
  2747. leftover -= (offsetof(EventClass, Data) -
  2748. sizeof(EventClass::EventType));
  2749. }
  2750. //..................................................................
  2751. // if MEGAMISSION event get the number of units (events to generate)
  2752. //..................................................................
  2753. else if (event->Type == EventClass::MEGAMISSION) {
  2754. numunits = *(((unsigned char *)buf) + pos + sizeof(eventdata.Type));
  2755. pos += sizeof(numunits);
  2756. leftover -= sizeof(numunits);
  2757. }
  2758. //..................................................................
  2759. // clear the union data portion of the event
  2760. //..................................................................
  2761. memset (&eventdata.Data, 0, sizeof(eventdata.Data));
  2762. eventdata.Type = event->Type;
  2763. datasize = EventClass::EventLength[ eventdata.Type ];
  2764. switch (eventdata.Type) {
  2765. case (EventClass::RESPONSE_TIME):
  2766. memcpy ( &eventdata.Data.FrameInfo.Delay,
  2767. ((char *)buf) + pos + sizeof(EventClass::EventType),
  2768. datasize );
  2769. break;
  2770. case (EventClass::ADDPLAYER):
  2771. memcpy ( &eventdata.Data.Variable.Size,
  2772. ((char *)buf) + pos + sizeof(EventClass::EventType),
  2773. datasize );
  2774. eventdata.Data.Variable.Pointer =
  2775. new char[eventdata.Data.Variable.Size];
  2776. memcpy (eventdata.Data.Variable.Pointer,
  2777. ((char *)buf) + pos + sizeof(EventClass::EventType) + datasize,
  2778. eventdata.Data.Variable.Size);
  2779. pos += eventdata.Data.Variable.Size;
  2780. leftover -= eventdata.Data.Variable.Size;
  2781. break;
  2782. case (EventClass::MEGAMISSION):
  2783. memcpy ( &eventdata.Data.MegaMission,
  2784. ((char *)buf) + pos + sizeof(EventClass::EventType),
  2785. datasize );
  2786. if (numunits > 1) {
  2787. pos += (datasize + sizeof(EventClass::EventType));
  2788. leftover -= (datasize + sizeof(EventClass::EventType));
  2789. datasize = sizeof(eventdata.Data.MegaMission.Whom);
  2790. while (numunits) {
  2791. Keyboard->Check();
  2792. if ( !DoList.Add( eventdata ) ) {
  2793. return (-1);
  2794. }
  2795. #ifdef MIRROR_QUEUE
  2796. MirrorList.Add( eventdata );
  2797. #endif
  2798. //......................................................
  2799. // Keep count of how many events we add to the queue
  2800. //......................................................
  2801. count++;
  2802. numunits--;
  2803. memcpy ( &eventdata.Data.MegaMission.Whom,
  2804. ((char *)buf) + pos, datasize );
  2805. //......................................................
  2806. // if one unit left fall thru to normal code
  2807. //......................................................
  2808. if (numunits == 1) {
  2809. datasize -= sizeof(EventClass::EventType);
  2810. break;
  2811. }
  2812. else {
  2813. pos += datasize;
  2814. leftover -= datasize;
  2815. }
  2816. }
  2817. }
  2818. break;
  2819. default:
  2820. memcpy ( &eventdata.Data,
  2821. ((char *)buf) + pos + sizeof(EventClass::EventType),
  2822. datasize );
  2823. break;
  2824. }
  2825. if ( !DoList.Add( eventdata ) ) {
  2826. if (eventdata.Type == EventClass::ADDPLAYER) {
  2827. delete [] eventdata.Data.Variable.Pointer;
  2828. }
  2829. return (-1);
  2830. }
  2831. #ifdef MIRROR_QUEUE
  2832. MirrorList.Add( eventdata );
  2833. #endif
  2834. //..................................................................
  2835. // Keep count of how many events we add to the queue
  2836. //..................................................................
  2837. count++;
  2838. pos += (datasize + sizeof(EventClass::EventType));
  2839. leftover -= (datasize + sizeof(EventClass::EventType));
  2840. if (leftover) {
  2841. event = (EventClass *)(((char *)buf) + pos);
  2842. datasize = EventClass::EventLength[ event->Type ];
  2843. if (event->Type == EventClass::MEGAMISSION) {
  2844. datasize += sizeof(numunits);
  2845. }
  2846. }
  2847. }
  2848. //.....................................................................
  2849. // FRAMESYNC event: This >should< be the only event in the buffer,
  2850. // and it will be uncompressed.
  2851. //.....................................................................
  2852. else {
  2853. pos += (datasize + sizeof(EventClass::EventType));
  2854. leftover -= (datasize + sizeof(EventClass::EventType));
  2855. event = (EventClass *)(((char *)buf) + pos);
  2856. //..................................................................
  2857. // size of FRAMESYNC event - EventType size
  2858. //..................................................................
  2859. datasize = (offsetof(EventClass, Data) +
  2860. size_of(EventClass, Data.FrameInfo)) -
  2861. sizeof(EventClass::EventType);
  2862. }
  2863. }
  2864. return (count);
  2865. } // end of Extract_Compressed_Events
  2866. /***************************************************************************
  2867. * Execute_DoList -- Executes commands from the DoList *
  2868. * *
  2869. * This routine executes any events in the DoList that need to be executed *
  2870. * on the current game frame. The events must be executed in a special *
  2871. * order, so that all systems execute all events in exactly the same *
  2872. * order. *
  2873. * *
  2874. * This routine also handles checking the Game CRC sent by other systems *
  2875. * against my own, to be sure we're still in sync. *
  2876. * *
  2877. * INPUT: *
  2878. * max_houses # houses to execute commands for *
  2879. * base_house HousesType to start with *
  2880. * net ptr to connection manager; NULL if none *
  2881. * skip_crc a frame-based countdown timer; if it's non-zero, the *
  2882. * CRC check will be skipped. Ignored if NULL. *
  2883. * their_frame array of their frame #'s *
  2884. * their_sent array of # commands they've sent *
  2885. * their_recv array of # commands I've received from them *
  2886. * *
  2887. * (their_xxx are ignored if 'net' is NULL.) *
  2888. * *
  2889. * OUTPUT: *
  2890. * 1 = OK, 0 = some error occurred (CRC error, packet rcv'd too late.) *
  2891. * *
  2892. * WARNINGS: *
  2893. * *
  2894. * HISTORY: *
  2895. * 11/21/1995 BRR : Created. *
  2896. *=========================================================================*/
  2897. static int Execute_DoList(int max_houses, HousesType base_house,
  2898. ConnManClass *net, CDTimerClass<FrameTimerClass> *skip_crc,
  2899. long *their_frame, unsigned short *their_sent, unsigned short *their_recv)
  2900. {
  2901. HousesType house;
  2902. HouseClass *hptr;
  2903. int i,j,k;
  2904. int index;
  2905. int check_crc;
  2906. Check_Mirror();
  2907. #if(TIMING_FIX)
  2908. //
  2909. // If MPlayerMaxAhead is recomputed such that it increases, the systems
  2910. // may try to free-run to the new MaxAhead value. If so, they may miss
  2911. // an event that was generated after the TIMING event was created, but
  2912. // before it executed; this event will be scheduled with the older,
  2913. // shorter MaxAhead value. If a system doesn't receive this event, it
  2914. // may execute past the frame it's scheduled to execute on, creating
  2915. // a Packet-Recieved-Too-Late error. To prevent this, find any events
  2916. // that are scheduled to execute during this "period of vulnerability",
  2917. // and re-schedule for the end of that period.
  2918. //
  2919. for (j = 0; j < DoList.Count; j++) {
  2920. if (DoList[j].Type != EventClass::FRAMEINFO &&
  2921. DoList[j].Frame > NewMaxAheadFrame1 &&
  2922. DoList[j].Frame < NewMaxAheadFrame2) {
  2923. DoList[j].Frame = NewMaxAheadFrame2;
  2924. #ifdef MIRROR_QUEUE
  2925. MirrorList[j].Frame = NewMaxAheadFrame2;
  2926. #endif
  2927. }
  2928. }
  2929. #endif
  2930. //------------------------------------------------------------------------
  2931. // Execute the DoList. Events must be executed in the same order on all
  2932. // systems; so, execute them in the order of the HouseClass array. This
  2933. // array is stored in the same order on all systems.
  2934. //------------------------------------------------------------------------
  2935. for (i = 0; i < max_houses; i++) {
  2936. //.....................................................................
  2937. // Convert our index into a HousesType value
  2938. //.....................................................................
  2939. house = (HousesType)(i + base_house);
  2940. hptr = HouseClass::As_Pointer(house);
  2941. //.....................................................................
  2942. // If for some reason this house doesn't exist, skip it.
  2943. // Also, if this house has exited the game, skip it. (The user can
  2944. // generate events after he exits, because the exit event is scheduled
  2945. // at least FrameSendRate*3 frames ahead. If one system gets these
  2946. // packets & another system doesn't, they'll go out of sync because
  2947. // they aren't checking the CommandCount for that house, since that
  2948. // house isn't connected any more.)
  2949. //.....................................................................
  2950. if (!hptr) {
  2951. continue;
  2952. }
  2953. if (!hptr->IsHuman) {
  2954. continue;
  2955. }
  2956. //.....................................................................
  2957. // Loop through all events
  2958. //.....................................................................
  2959. for (j = 0; j < DoList.Count; j++) {
  2960. if (net)
  2961. Update_Queue_Mono (net, 6);
  2962. //..................................................................
  2963. // If this event was from the currently-executing player ID, and it's
  2964. // time to execute it, execute it.
  2965. //..................................................................
  2966. if (DoList[j].ID == hptr->ID && Frame >= DoList[j].Frame &&
  2967. !DoList[j].IsExecuted) {
  2968. //...............................................................
  2969. // Error if it's too late to execute this packet!
  2970. // (Hack: disable this check for solo or skirmish mode.)
  2971. //...............................................................
  2972. if (Frame > DoList[j].Frame && DoList[j].Type !=
  2973. EventClass::FRAMEINFO && Session.Type != GAME_NORMAL &&
  2974. Session.Type != GAME_SKIRMISH) {
  2975. #if(TEN)
  2976. Send_TEN_Packet_Too_Late();
  2977. #endif // TEN
  2978. #if(MPATH)
  2979. //Send_MPATH_Packet_Too_Late();
  2980. #endif // MPATH
  2981. Dump_Packet_Too_Late_Stuff(&DoList[j], net, their_frame,
  2982. their_sent, their_recv);
  2983. WWMessageBox().Process (TXT_PACKET_TOO_LATE);
  2984. return (0);
  2985. }
  2986. //...............................................................
  2987. // Only execute EXIT & OPTIONS commands if they're from myself.
  2988. //...............................................................
  2989. if (DoList[j].Type==EventClass::EXIT ||
  2990. DoList[j].Type==EventClass::OPTIONS) {
  2991. #ifdef WIN32
  2992. if (DoList[j].Type==EventClass::EXIT) {
  2993. /*
  2994. ** Flag that this house lost because it quit.
  2995. */
  2996. HousesType quithouse;
  2997. HouseClass *quithptr;
  2998. for (int player = 0; player < max_houses ; player++) {
  2999. quithouse = (HousesType)(player + base_house);
  3000. quithptr = HouseClass::As_Pointer(quithouse);
  3001. if (!quithptr) {
  3002. continue;
  3003. }
  3004. if (quithptr->ID == DoList[j].ID) {
  3005. quithptr->IsGiverUpper = true;
  3006. break;
  3007. }
  3008. }
  3009. /*
  3010. ** Send the game statistics packet now since the game is effectivly over
  3011. */
  3012. if (Session.Players.Count() == 2 &&
  3013. Session.Type == GAME_INTERNET &&
  3014. !GameStatisticsPacketSent) {
  3015. Register_Game_End_Time();
  3016. Send_Statistics_Packet(); // Event - player aborted, and there were only 2 left.
  3017. }
  3018. }
  3019. #endif //WIN32
  3020. if (Debug_Print_Events) {
  3021. if (DoList[j].Type==EventClass::EXIT) {
  3022. printf("(%d) Executing EXIT, ID:%d (%s), EvFrame:%d\n",
  3023. Frame,
  3024. DoList[j].ID,
  3025. (HouseClass::As_Pointer((HousesType)(DoList[j].ID)))->IniName,
  3026. DoList[j].Frame);
  3027. }
  3028. }
  3029. if (DoList[j].ID == PlayerPtr->ID) {
  3030. DoList[j].Execute();
  3031. } else if (DoList[j].Type==EventClass::EXIT) {
  3032. //............................................................
  3033. // If this EXIT event isn't from myself, destroy the connection
  3034. // for that player. The HousesType for this event is the
  3035. // connection ID.
  3036. //............................................................
  3037. if (Session.Type == GAME_MODEM ||
  3038. Session.Type == GAME_NULL_MODEM) {
  3039. Destroy_Null_Connection( house, 0 );
  3040. } else if ((Session.Type == GAME_IPX ||
  3041. Session.Type == GAME_INTERNET ||
  3042. Session.Type == GAME_TEN ||
  3043. Session.Type == GAME_MPATH) && net) {
  3044. index = net->Connection_Index (house);
  3045. if (index != -1) {
  3046. for (k = index; k < net->Num_Connections() - 1; k++) {
  3047. their_frame[k] = their_frame[k+1];
  3048. their_sent[k] = their_sent[k+1];
  3049. their_recv[k] = their_recv[k+1];
  3050. }
  3051. if (Session.Type == GAME_IPX ||
  3052. Session.Type == GAME_INTERNET) {
  3053. Destroy_Connection(house,0);
  3054. }
  3055. #if(TEN)
  3056. else if (Session.Type == GAME_TEN) {
  3057. Destroy_TEN_Connection(house,0);
  3058. }
  3059. #endif // TEN
  3060. #if(MPATH)
  3061. else if (Session.Type == GAME_MPATH) {
  3062. Destroy_MPATH_Connection(house,0);
  3063. }
  3064. #endif // MPATH
  3065. }
  3066. }
  3067. //
  3068. // Special case for recording playback: turn the house over
  3069. // to the computer.
  3070. //
  3071. if (Session.Play && DoList[j].Type==EventClass::EXIT) {
  3072. hptr->IsHuman = false;
  3073. hptr->IQ = Rule.MaxIQ;
  3074. hptr->Computer_Paranoid();
  3075. strcpy (hptr->IniName,Text_String(TXT_COMPUTER));
  3076. Session.NumPlayers--;
  3077. }
  3078. }
  3079. }
  3080. //...............................................................
  3081. // For a FRAMEINFO event, check the CRC value.
  3082. //...............................................................
  3083. else if (DoList[j].Type == EventClass::FRAMEINFO) {
  3084. //............................................................
  3085. // Skip the CRC check if we're less than 32 frames into the game;
  3086. // this will prevent a newly-loaded modem game from instantly
  3087. // going out of sync, if the games were saved at different
  3088. // frame numbers.
  3089. //............................................................
  3090. if (!skip_crc || *skip_crc == 0) {
  3091. check_crc = 1;
  3092. }
  3093. else {
  3094. check_crc = 0;
  3095. }
  3096. if (check_crc
  3097. && DoList[j].Frame == Frame
  3098. && DoList[j].Data.FrameInfo.Delay < 32) {
  3099. index = ((DoList[j].Frame - DoList[j].Data.FrameInfo.Delay) &
  3100. 0x001f);
  3101. if (CRC[index] != DoList[j].Data.FrameInfo.CRC) {
  3102. Print_CRCs(&DoList[j]);
  3103. #if(TEN)
  3104. Send_TEN_Out_Of_Sync();
  3105. #endif // TEN
  3106. #if(MPATH)
  3107. //Send_MPATH_Out_Of_Sync();
  3108. #endif // MPATH
  3109. if (WWMessageBox().Process (TXT_OUT_OF_SYNC,
  3110. TXT_CONTINUE, TXT_STOP) == 0) {
  3111. if (Session.Type == GAME_MODEM ||
  3112. Session.Type == GAME_NULL_MODEM) {
  3113. Destroy_Null_Connection( house, -1 );
  3114. Shutdown_Modem();
  3115. Session.Type = GAME_NORMAL;
  3116. }
  3117. else if ((Session.Type == GAME_IPX ||
  3118. Session.Type == GAME_INTERNET) && net) {
  3119. while (net->Num_Connections()) {
  3120. Keyboard->Check();
  3121. Destroy_Connection (net->Connection_ID(0), -1);
  3122. }
  3123. }
  3124. #if(TEN)
  3125. else if (Session.Type == GAME_TEN && net) {
  3126. while (net->Num_Connections()) {
  3127. Destroy_TEN_Connection (net->Connection_ID(0), -1);
  3128. }
  3129. }
  3130. #endif
  3131. #if(MPATH)
  3132. else if (Session.Type == GAME_MPATH && net) {
  3133. while (net->Num_Connections()) {
  3134. Destroy_MPATH_Connection (net->Connection_ID(0), -1);
  3135. }
  3136. }
  3137. #endif
  3138. Map.Flag_To_Redraw(true);
  3139. }
  3140. else {
  3141. return (0);
  3142. }
  3143. return (1);
  3144. }
  3145. }
  3146. }
  3147. //...............................................................
  3148. // Execute other commands
  3149. //...............................................................
  3150. else {
  3151. DoList[j].Execute();
  3152. }
  3153. //...............................................................
  3154. // Mark this event as executed.
  3155. //...............................................................
  3156. DoList[j].IsExecuted = 1;
  3157. #ifdef MIRROR_QUEUE
  3158. MirrorList[j].IsExecuted = 1;
  3159. #endif
  3160. }
  3161. }
  3162. }
  3163. return (1);
  3164. } // end of Execute_DoList
  3165. /***************************************************************************
  3166. * Clean_DoList -- Cleans out old events from the DoList *
  3167. * *
  3168. * Currently, an event can only be removed from the DoList if it's at the *
  3169. * head of the list; and event can't be removed from the middle. So, *
  3170. * this routine loops as long as the next event in the DoList has been *
  3171. * executed, it's removed. *
  3172. * *
  3173. * INPUT: *
  3174. * net ptr to connection manager; ignored if NULL *
  3175. * *
  3176. * OUTPUT: *
  3177. * none. *
  3178. * *
  3179. * WARNINGS: *
  3180. * none. *
  3181. * *
  3182. * HISTORY: *
  3183. * 11/21/1995 BRR : Created. *
  3184. *=========================================================================*/
  3185. static void Clean_DoList(ConnManClass *net)
  3186. {
  3187. while (DoList.Count) {
  3188. Keyboard->Check();
  3189. if (net)
  3190. Update_Queue_Mono (net, 7);
  3191. //.....................................................................
  3192. // Discard events that have been executed, OR it's too late to execute.
  3193. // (This happens if another player exits the game; he'll leave FRAMEINFO
  3194. // events lying around in my queue. They won't have been "executed",
  3195. // because his IPX connection was destroyed.)
  3196. //.....................................................................
  3197. if ( (DoList.First().IsExecuted) || (Frame > DoList.First().Frame) ) {
  3198. DoList.Next();
  3199. #ifdef MIRROR_QUEUE
  3200. MirrorList.Next();
  3201. #endif
  3202. }
  3203. else {
  3204. break;
  3205. }
  3206. }
  3207. } // end of Clean_DoList
  3208. /***************************************************************************
  3209. * Queue_Record -- Records the DoList to disk *
  3210. * *
  3211. * This routine just saves any events in the DoList to disk; we can later *
  3212. * "play back" the recording just be pulling events from disk rather than *
  3213. * from the network! *
  3214. * *
  3215. * INPUT: *
  3216. * none. *
  3217. * *
  3218. * OUTPUT: *
  3219. * none. *
  3220. * *
  3221. * WARNINGS: *
  3222. * none. *
  3223. * *
  3224. * HISTORY: *
  3225. * 08/14/1995 BRR : Created. *
  3226. *=========================================================================*/
  3227. static void Queue_Record(void)
  3228. {
  3229. int i,j;
  3230. //------------------------------------------------------------------------
  3231. // Compute # of events to save this frame
  3232. //------------------------------------------------------------------------
  3233. j = 0;
  3234. for (i = 0; i < DoList.Count; i++) {
  3235. if (Frame == DoList[i].Frame && !DoList[i].IsExecuted) {
  3236. j++;
  3237. }
  3238. }
  3239. //------------------------------------------------------------------------
  3240. // Save the # of events, then all events.
  3241. //------------------------------------------------------------------------
  3242. Session.RecordFile.Write (&j,sizeof(j));
  3243. for (i = 0; i < DoList.Count; i++) {
  3244. if (Frame == DoList[i].Frame && !DoList[i].IsExecuted) {
  3245. Session.RecordFile.Write (&DoList[i],sizeof (EventClass));
  3246. j--;
  3247. }
  3248. }
  3249. } /* end of Queue_Record */
  3250. /***************************************************************************
  3251. * Queue_Playback -- plays back queue entries from a record file *
  3252. * *
  3253. * This routine reads events from disk, putting them into the DoList; *
  3254. * it then executes the DoList just like the network version does. The *
  3255. * result is that the game "plays back" like a recording. *
  3256. * *
  3257. * This routine detects mouse motion and stops playback, so it can work *
  3258. * like an "attract" mode, showing a demo of the game itself. *
  3259. * *
  3260. * INPUT: *
  3261. * none. *
  3262. * *
  3263. * OUTPUT: *
  3264. * none. *
  3265. * *
  3266. * WARNINGS: *
  3267. * none. *
  3268. * *
  3269. * HISTORY: *
  3270. * 05/15/1995 BRR : Created. *
  3271. *=========================================================================*/
  3272. static void Queue_Playback(void)
  3273. {
  3274. int numevents;
  3275. EventClass event;
  3276. int i;
  3277. int ok;
  3278. static int mx,my;
  3279. int max_houses;
  3280. HousesType base_house;
  3281. int key;
  3282. int testframe;
  3283. //------------------------------------------------------------------------
  3284. // If the user hits ESC, stop the playback
  3285. //------------------------------------------------------------------------
  3286. if (Keyboard->Check()) {
  3287. key = Keyboard->Get();
  3288. if (key == KA_ESC || Session.Attract) {
  3289. GameActive = 0;
  3290. return;
  3291. }
  3292. }
  3293. //------------------------------------------------------------------------
  3294. // If we're in "Attract" mode, and the user moves the mouse, stop the
  3295. // playback.
  3296. //------------------------------------------------------------------------
  3297. if (Session.Attract && Frame > 0 &&
  3298. (mx != Get_Mouse_X() || my != Get_Mouse_Y())) {
  3299. GameActive = 0;
  3300. return;
  3301. }
  3302. mx = Get_Mouse_X();
  3303. my = Get_Mouse_Y();
  3304. //------------------------------------------------------------------------
  3305. // Compute the Game's CRC
  3306. //------------------------------------------------------------------------
  3307. Compute_Game_CRC();
  3308. CRC[Frame & 0x001f] = GameCRC;
  3309. //------------------------------------------------------------------------
  3310. // If we've reached the CRC print frame, do so & exit
  3311. //------------------------------------------------------------------------
  3312. if (Frame >= Session.TrapPrintCRC) {
  3313. Print_CRCs(NULL);
  3314. //Prog_End();
  3315. Emergency_Exit(0);
  3316. }
  3317. //------------------------------------------------------------------------
  3318. // Don't read anything the first time through (since the Queue_AI_Network
  3319. // routine didn't write anything the first time through); do this after the
  3320. // CRC is computed, since we'll still need a CRC for Frame 0.
  3321. //------------------------------------------------------------------------
  3322. if (Frame==0 && Session.Type!=GAME_NORMAL) {
  3323. return;
  3324. }
  3325. //------------------------------------------------------------------------
  3326. // Only process every 'FrameSendRate' frames
  3327. //------------------------------------------------------------------------
  3328. testframe = ((Frame + (Session.FrameSendRate - 1)) /
  3329. Session.FrameSendRate) * Session.FrameSendRate;
  3330. if ( (Session.Type != GAME_NORMAL && Session.Type != GAME_SKIRMISH) &&
  3331. Session.CommProtocol == COMM_PROTOCOL_MULTI_E_COMP) {
  3332. if (Frame != testframe) {
  3333. return;
  3334. }
  3335. }
  3336. //------------------------------------------------------------------------
  3337. // Read the DoList from disk
  3338. //------------------------------------------------------------------------
  3339. ok = 1;
  3340. if (Session.RecordFile.Read (&numevents, sizeof(numevents)) ==
  3341. sizeof(numevents)) {
  3342. for (i = 0; i < numevents; i++) {
  3343. if (Session.RecordFile.Read (&event, sizeof(EventClass)) ==
  3344. sizeof(EventClass)) {
  3345. event.IsExecuted = 0;
  3346. DoList.Add (event);
  3347. #ifdef MIRROR_QUEUE
  3348. MirrorList.Add(event);
  3349. #endif
  3350. }
  3351. else {
  3352. ok = 0;
  3353. break;
  3354. }
  3355. }
  3356. }
  3357. else {
  3358. ok = 0;
  3359. }
  3360. if (!ok) {
  3361. GameActive = 0;
  3362. return;
  3363. }
  3364. //------------------------------------------------------------------------
  3365. // Execute the DoList; if an error occurs, bail out.
  3366. //------------------------------------------------------------------------
  3367. if (Session.Type == GAME_NORMAL) {
  3368. max_houses = 1;
  3369. base_house = PlayerPtr->Class->House;
  3370. }
  3371. else {
  3372. max_houses = Session.MaxPlayers;
  3373. base_house = HOUSE_MULTI1;
  3374. }
  3375. if (!Execute_DoList(max_houses, base_house, NULL, NULL, NULL, NULL, NULL)) {
  3376. GameActive = 0;
  3377. return;
  3378. }
  3379. //------------------------------------------------------------------------
  3380. // Clean out the DoList
  3381. //------------------------------------------------------------------------
  3382. Clean_DoList(NULL);
  3383. } /* end of Queue_Playback */
  3384. /***************************************************************************
  3385. * Compute_Game_CRC -- Computes a CRC value of the entire game. *
  3386. * *
  3387. * INPUT: *
  3388. * none. *
  3389. * *
  3390. * OUTPUT: *
  3391. * none. *
  3392. * *
  3393. * WARNINGS: *
  3394. * none. *
  3395. * *
  3396. * HISTORY: *
  3397. * 05/09/1995 BRR : Created. *
  3398. *=========================================================================*/
  3399. static void Compute_Game_CRC(void)
  3400. {
  3401. int i,j;
  3402. VesselClass *vessp;
  3403. InfantryClass *infp;
  3404. UnitClass *unitp;
  3405. BuildingClass *bldgp;
  3406. ObjectClass *objp;
  3407. HouseClass *housep;
  3408. GameCRC = 0;
  3409. //------------------------------------------------------------------------
  3410. // Infantry
  3411. //------------------------------------------------------------------------
  3412. for (i = 0; i < Infantry.Count(); i++) {
  3413. infp = (InfantryClass *)Infantry.Active_Ptr(i);
  3414. Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing);
  3415. Add_CRC (&GameCRC, (int)infp->Speed + (int)infp->NavCom);
  3416. Add_CRC (&GameCRC, (int)infp->Mission + (int)infp->TarCom);
  3417. }
  3418. //------------------------------------------------------------------------
  3419. // Units
  3420. //------------------------------------------------------------------------
  3421. for (i = 0; i < Units.Count(); i++) {
  3422. unitp = (UnitClass *)Units.Active_Ptr(i);
  3423. Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing +
  3424. (int)unitp->SecondaryFacing);
  3425. }
  3426. //------------------------------------------------------------------------
  3427. // Shippies
  3428. //------------------------------------------------------------------------
  3429. for (i = 0; i < Vessels.Count(); i++) {
  3430. vessp = (VesselClass *)Vessels.Active_Ptr(i);
  3431. Add_CRC (&GameCRC, (int)vessp->Coord + (int)vessp->PrimaryFacing);
  3432. Add_CRC (&GameCRC, (int)vessp->Speed + (int)vessp->NavCom);
  3433. Add_CRC (&GameCRC, (int)vessp->Strength);
  3434. Add_CRC (&GameCRC, (int)vessp->Mission + (int)vessp->TarCom);
  3435. }
  3436. //------------------------------------------------------------------------
  3437. // Buildings
  3438. //------------------------------------------------------------------------
  3439. for (i = 0; i < Buildings.Count(); i++) {
  3440. bldgp = (BuildingClass *)Buildings.Active_Ptr(i);
  3441. Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing);
  3442. }
  3443. //------------------------------------------------------------------------
  3444. // Houses
  3445. //------------------------------------------------------------------------
  3446. for (i = 0; i < Houses.Count(); i++) {
  3447. housep = (HouseClass *)Houses.Active_Ptr(i);
  3448. Add_CRC (&GameCRC, (int)housep->Credits + (int)housep->Power +
  3449. (int)housep->Drain);
  3450. }
  3451. //------------------------------------------------------------------------
  3452. // Map Layers
  3453. //------------------------------------------------------------------------
  3454. for (i = 0; i < LAYER_COUNT; i++) {
  3455. for (j = 0; j < Map.Layer[i].Count(); j++) {
  3456. objp = Map.Layer[i][j];
  3457. Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I());
  3458. }
  3459. }
  3460. //------------------------------------------------------------------------
  3461. // Logic Layers
  3462. //------------------------------------------------------------------------
  3463. for (i = 0; i < Logic.Count(); i++) {
  3464. objp = Logic[i];
  3465. Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I());
  3466. }
  3467. //------------------------------------------------------------------------
  3468. // A random #
  3469. //------------------------------------------------------------------------
  3470. // Add_CRC(&GameCRC, Scen.RandomNumber.Seed);
  3471. Add_CRC(&GameCRC, Scen.RandomNumber);
  3472. } /* end of Compute_Game_CRC */
  3473. /***************************************************************************
  3474. * Add_CRC -- Adds a value to a CRC *
  3475. * *
  3476. * INPUT: *
  3477. * crc ptr to crc *
  3478. * val value to add *
  3479. * *
  3480. * OUTPUT: *
  3481. * none *
  3482. * *
  3483. * WARNINGS: *
  3484. * none *
  3485. * *
  3486. * HISTORY: *
  3487. * 05/09/1995 BRR : Created. *
  3488. *=========================================================================*/
  3489. void Add_CRC(unsigned long *crc, unsigned long val)
  3490. {
  3491. int hibit;
  3492. if ( (*crc) & 0x80000000) {
  3493. hibit = 1;
  3494. }
  3495. else {
  3496. hibit = 0;
  3497. }
  3498. (*crc) <<= 1;
  3499. (*crc) += val;
  3500. (*crc) += hibit;
  3501. } /* end of Add_CRC */
  3502. /***************************************************************************
  3503. * Print_CRCs -- Prints a data file for finding Sync Bugs *
  3504. * *
  3505. * INPUT: *
  3506. * ev -- event to display *
  3507. * *
  3508. * OUTPUT: *
  3509. * none *
  3510. * *
  3511. * WARNINGS: *
  3512. * none *
  3513. * *
  3514. * HISTORY: *
  3515. * 05/09/1995 BRR : Created. *
  3516. *=========================================================================*/
  3517. static void Print_CRCs(EventClass *ev)
  3518. {
  3519. int i,j;
  3520. InfantryClass *infp;
  3521. UnitClass *unitp;
  3522. VesselClass *vesselp;
  3523. BuildingClass *bldgp;
  3524. ObjectClass *objp;
  3525. FILE *fp;
  3526. HouseClass *housep;
  3527. HousesType house;
  3528. int color;
  3529. Mono_Clear_Screen();
  3530. Mono_Set_Cursor (0,0);
  3531. fp = fopen("OUT.TXT","wt");
  3532. if (fp==NULL) {
  3533. return;
  3534. }
  3535. for (i = 0; i < 32; i++) {
  3536. fprintf(fp,"CRC[%d]=%x\n",i,CRC[i]);
  3537. }
  3538. //
  3539. // Houses
  3540. //
  3541. for (house = HOUSE_MULTI1; house <= HOUSE_MULTI8; house++) {
  3542. GameCRC = 0;
  3543. housep = HouseClass::As_Pointer (house);
  3544. if (housep) {
  3545. HousesType actlike = housep->ActLike;
  3546. color = housep->RemapColor;
  3547. fprintf(fp,"%s: IsHuman:%d Color:%s ID:%d ActLike:%s\n",
  3548. housep->IniName,
  3549. housep->IsHuman,
  3550. ColorNames[color],
  3551. housep->ID,
  3552. HouseClass::As_Pointer(actlike)->Class->Name());
  3553. Add_CRC (&GameCRC, (int)housep->Credits + (int)housep->Power +
  3554. (int)housep->Drain);
  3555. Mono_Printf("House %s:%x\n",housep->Class->Name(),GameCRC);
  3556. }
  3557. }
  3558. //
  3559. // Infantry
  3560. //
  3561. for (house = HOUSE_MULTI1; house <= HOUSE_MULTI8; house++) {
  3562. housep = HouseClass::As_Pointer (house);
  3563. if (housep) {
  3564. GameCRC = 0;
  3565. fprintf(fp,"-------------------- %s Infantry -------------------\n",
  3566. housep->Class->Name());
  3567. for (i = 0; i < Infantry.Count(); i++) {
  3568. infp = (InfantryClass *)Infantry.Active_Ptr(i);
  3569. if (infp->Owner()==house) {
  3570. Add_CRC (&GameCRC, (int)infp->Coord + (int)infp->PrimaryFacing);
  3571. Add_CRC (&GameCRC, (int)infp->Speed + (int)infp->NavCom);
  3572. Add_CRC (&GameCRC, (int)infp->Mission + (int)infp->TarCom);
  3573. fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d Tgt:%x Speed:%d NavCom:%x\n",
  3574. infp->Coord,(int)infp->PrimaryFacing,infp->Get_Mission(),
  3575. infp->Class->Type, infp->As_Target(), infp->Speed, infp->NavCom);
  3576. }
  3577. }
  3578. Mono_Printf("%s Infantry:%x\n",housep->Class->Name(),GameCRC);
  3579. }
  3580. }
  3581. //
  3582. // Units
  3583. //
  3584. for (house = HOUSE_MULTI1; house <= HOUSE_MULTI8; house++) {
  3585. housep = HouseClass::As_Pointer (house);
  3586. if (housep) {
  3587. GameCRC = 0;
  3588. fprintf(fp,"-------------------- %s Units -------------------\n",
  3589. housep->Class->Name());
  3590. for (i = 0; i < Units.Count(); i++) {
  3591. unitp = (UnitClass *)Units.Active_Ptr(i);
  3592. if (unitp->Owner()==house) {
  3593. Add_CRC (&GameCRC, (int)unitp->Coord + (int)unitp->PrimaryFacing +
  3594. (int)unitp->SecondaryFacing);
  3595. fprintf(fp,
  3596. "COORD:%x Facing:%d Facing2:%d Mission:%d Type:%d Tgt:%x\n",
  3597. unitp->Coord,(int)unitp->PrimaryFacing,
  3598. (int)unitp->SecondaryFacing,unitp->Get_Mission(),
  3599. unitp->Class->Type, unitp->As_Target());
  3600. }
  3601. }
  3602. Mono_Printf("%s Units:%x\n",housep->Class->Name(),GameCRC);
  3603. }
  3604. }
  3605. //
  3606. // Vessels
  3607. //
  3608. for (house = HOUSE_MULTI1; house <= HOUSE_MULTI8; house++) {
  3609. housep = HouseClass::As_Pointer (house);
  3610. if (housep) {
  3611. GameCRC = 0;
  3612. fprintf(fp,"-------------------- %s Vessels -------------------\n",
  3613. housep->Class->Name());
  3614. for (i = 0; i < Vessels.Count(); i++) {
  3615. vesselp = (VesselClass *)Vessels.Active_Ptr(i);
  3616. if (vesselp->Owner()==house) {
  3617. Add_CRC (&GameCRC, (int)vesselp->Coord + (int)vesselp->PrimaryFacing);
  3618. Add_CRC (&GameCRC, (int)vesselp->Speed + (int)vesselp->NavCom);
  3619. Add_CRC (&GameCRC, (int)vesselp->Strength);
  3620. Add_CRC (&GameCRC, (int)vesselp->Mission + (int)vesselp->TarCom);
  3621. fprintf(fp,
  3622. "COORD:%x Facing:%d Mission:%d Strength:%d Type:%d Tgt:%x\n",
  3623. vesselp->Coord,(int)vesselp->PrimaryFacing,
  3624. vesselp->Get_Mission(), vesselp->Strength,
  3625. vesselp->Class->Type, vesselp->As_Target());
  3626. }
  3627. }
  3628. Mono_Printf("%s Vessels:%x\n",housep->Class->Name(),GameCRC);
  3629. }
  3630. }
  3631. //
  3632. // Buildings
  3633. //
  3634. for (house = HOUSE_MULTI1; house <= HOUSE_MULTI8; house++) {
  3635. housep = HouseClass::As_Pointer (house);
  3636. if (housep) {
  3637. GameCRC = 0;
  3638. fprintf(fp,"-------------------- %s Buildings -------------------\n",
  3639. housep->Class->Name());
  3640. for (i = 0; i < Buildings.Count(); i++) {
  3641. bldgp = (BuildingClass *)Buildings.Active_Ptr(i);
  3642. if (bldgp->Owner()==house) {
  3643. Add_CRC (&GameCRC, (int)bldgp->Coord + (int)bldgp->PrimaryFacing);
  3644. fprintf(fp,"COORD:%x Facing:%d Mission:%d Type:%d Tgt:%x\n",
  3645. bldgp->Coord,(int)bldgp->PrimaryFacing,bldgp->Get_Mission(),
  3646. bldgp->Class->Type, bldgp->As_Target());
  3647. }
  3648. }
  3649. Mono_Printf("%s Buildings:%x\n",housep->Class->Name(),GameCRC);
  3650. }
  3651. }
  3652. //
  3653. // Animations
  3654. //
  3655. AnimClass *animp;
  3656. fprintf(fp,"-------------------- Animations -------------------\n");
  3657. for (i = 0; i < Anims.Count(); i++) {
  3658. animp = (AnimClass *)Anims.Active_Ptr(i);
  3659. fprintf(fp,"Target:%x OwnerHouse:%d Loops:%d\n",
  3660. animp->xObject,
  3661. animp->OwnerHouse,
  3662. animp->Loops);
  3663. }
  3664. //------------------------------------------------------------------------
  3665. // Map Layers
  3666. //------------------------------------------------------------------------
  3667. GameCRC = 0;
  3668. for (i = 0; i < LAYER_COUNT; i++) {
  3669. fprintf(fp,">>>> MAP LAYER %d <<<<\n",i);
  3670. for (j = 0; j < Map.Layer[i].Count(); j++) {
  3671. objp = Map.Layer[i][j];
  3672. Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I());
  3673. fprintf(fp,"Object %d: %x ",j,objp->Coord);
  3674. if (objp->What_Am_I() == RTTI_AIRCRAFT)
  3675. fprintf(fp,"Aircraft (Type:%d) ",
  3676. (AircraftType)(*((AircraftClass *)objp)));
  3677. else if (objp->What_Am_I() == RTTI_ANIM)
  3678. fprintf(fp,"Anim (Type:%d) ",
  3679. (AnimType)(*((AnimClass *)objp)));
  3680. else if (objp->What_Am_I() == RTTI_BUILDING)
  3681. fprintf(fp,"Building (Type:%d) ",
  3682. (StructType)(*((BuildingClass *)objp)));
  3683. else if (objp->What_Am_I() == RTTI_BULLET)
  3684. fprintf(fp,"Bullet (Type:%d) ",
  3685. (BulletType)(*((BulletClass *)objp)));
  3686. else if (objp->What_Am_I() == RTTI_INFANTRY)
  3687. fprintf(fp,"Infantry (Type:%d) ",
  3688. (InfantryType)(*((InfantryClass *)objp)));
  3689. else if (objp->What_Am_I() == RTTI_OVERLAY)
  3690. fprintf(fp,"Overlay (Type:%d) ",
  3691. (OverlayType)(*((OverlayClass *)objp)));
  3692. else if (objp->What_Am_I() == RTTI_SMUDGE)
  3693. fprintf(fp,"Smudge (Type:%d) ",
  3694. (SmudgeType)(*((SmudgeClass *)objp)));
  3695. else if (objp->What_Am_I() == RTTI_TEMPLATE)
  3696. fprintf(fp,"Template (Type:%d) ",
  3697. (TemplateType)(*((TemplateClass *)objp)));
  3698. else if (objp->What_Am_I() == RTTI_TERRAIN)
  3699. fprintf(fp,"Terrain (Type:%d) ",
  3700. (TerrainType)(*((TerrainClass *)objp)));
  3701. else if (objp->What_Am_I() == RTTI_UNIT)
  3702. fprintf(fp,"Unit (Type:%d) ",
  3703. (UnitType)(*((UnitClass *)objp)));
  3704. else if (objp->What_Am_I() == RTTI_VESSEL)
  3705. fprintf(fp,"Vessel (Type:%d) ",
  3706. (VesselType)(*((VesselClass *)objp)));
  3707. house = objp->Owner();
  3708. if (house!=HOUSE_NONE) {
  3709. housep = HouseClass::As_Pointer (house);
  3710. fprintf(fp,"Owner: %s\n",housep->Class->IniName);
  3711. }
  3712. else {
  3713. fprintf(fp,"Owner: NONE\n");
  3714. }
  3715. }
  3716. }
  3717. Mono_Printf("Map Layers:%x \n",GameCRC);
  3718. //------------------------------------------------------------------------
  3719. // Logic Layers
  3720. //------------------------------------------------------------------------
  3721. GameCRC = 0;
  3722. fprintf(fp,">>>> LOGIC LAYER <<<<\n");
  3723. for (i = 0; i < Logic.Count(); i++) {
  3724. objp = Logic[i];
  3725. Add_CRC (&GameCRC, (int)objp->Coord + (int)objp->What_Am_I());
  3726. fprintf(fp,"Object %d: %x ",i,objp->Coord);
  3727. if (objp->What_Am_I() == RTTI_AIRCRAFT)
  3728. fprintf(fp,"Aircraft (Type:%d) ",
  3729. (AircraftType)(*((AircraftClass *)objp)));
  3730. else if (objp->What_Am_I() == RTTI_ANIM)
  3731. fprintf(fp,"Anim (Type:%d) ",
  3732. (AnimType)(*((AnimClass *)objp)));
  3733. else if (objp->What_Am_I() == RTTI_BUILDING)
  3734. fprintf(fp,"Building (Type:%d) ",
  3735. (StructType)(*((BuildingClass *)objp)));
  3736. else if (objp->What_Am_I() == RTTI_BULLET)
  3737. fprintf(fp,"Bullet (Type:%d) ",
  3738. (BulletType)(*((BulletClass *)objp)));
  3739. else if (objp->What_Am_I() == RTTI_INFANTRY)
  3740. fprintf(fp,"Infantry (Type:%d) ",
  3741. (InfantryType)(*((InfantryClass *)objp)));
  3742. else if (objp->What_Am_I() == RTTI_OVERLAY)
  3743. fprintf(fp,"Overlay (Type:%d) ",
  3744. (OverlayType)(*((OverlayClass *)objp)));
  3745. else if (objp->What_Am_I() == RTTI_SMUDGE)
  3746. fprintf(fp,"Smudge (Type:%d) ",
  3747. (SmudgeType)(*((SmudgeClass *)objp)));
  3748. else if (objp->What_Am_I() == RTTI_TEMPLATE)
  3749. fprintf(fp,"Template (Type:%d) ",
  3750. (TemplateType)(*((TemplateClass *)objp)));
  3751. else if (objp->What_Am_I() == RTTI_TERRAIN)
  3752. fprintf(fp,"Terrain (Type:%d) ",
  3753. (TerrainType)(*((TerrainClass *)objp)));
  3754. else if (objp->What_Am_I() == RTTI_UNIT)
  3755. fprintf(fp,"Unit (Type:%d) ",
  3756. (UnitType)(*((UnitClass *)objp)));
  3757. house = objp->Owner();
  3758. if (house!=HOUSE_NONE) {
  3759. housep = HouseClass::As_Pointer (house);
  3760. fprintf(fp,"Owner: %s\n",housep->Class->IniName);
  3761. }
  3762. else {
  3763. fprintf(fp,"Owner: NONE\n");
  3764. }
  3765. }
  3766. Mono_Printf("Logic:%x \n",GameCRC);
  3767. //------------------------------------------------------------------------
  3768. // Random # generator, frame #
  3769. //------------------------------------------------------------------------
  3770. Mono_Printf("Random Number:%x \n",Scen.RandomNumber.Seed);
  3771. #ifdef RANDOM_COUNT
  3772. fprintf(fp,"\nRandom Number:%x (Count1:%d, Count2:%d)\n",
  3773. Scen.RandomNumber.Seed,
  3774. Scen.RandomNumber.Count1,
  3775. Scen.RandomNumber.Count2);
  3776. #else
  3777. fprintf(fp,"\nRandom Number:%x\n",Scen.RandomNumber.Seed);
  3778. #endif
  3779. Mono_Printf("My Frame:%d \n",Frame);
  3780. fprintf(fp,"My Frame:%d\n",Frame);
  3781. if (ev) {
  3782. fprintf(fp,"\n");
  3783. fprintf(fp,"Offending event:\n");
  3784. fprintf(fp," Type: %d\n",ev->Type);
  3785. fprintf(fp," Frame: %d\n",ev->Frame);
  3786. fprintf(fp," ID: %x\n",ev->ID);
  3787. fprintf(fp," CRC: %x\n",ev->Data.FrameInfo.CRC);
  3788. fprintf(fp," CommandCount: %d\n",ev->Data.FrameInfo.CommandCount);
  3789. fprintf(fp," Delay: %d\n",ev->Data.FrameInfo.Delay);
  3790. }
  3791. fclose(fp);
  3792. } /* end of Print_CRCs */
  3793. /***************************************************************************
  3794. * Init_Queue_Mono -- inits mono display *
  3795. * *
  3796. * This routine steals control of the mono screen away from the rest of *
  3797. * the engine, by setting the global IsMono; if IsMono is set, the other *
  3798. * routines in this module turn off the Mono display when they're done *
  3799. * with it, so the rest of the engine won't over-write what we're writing. *
  3800. * *
  3801. * INPUT: *
  3802. * net ptr to connection manager *
  3803. * *
  3804. * OUTPUT: *
  3805. * none. *
  3806. * *
  3807. * WARNINGS: *
  3808. * none. *
  3809. * *
  3810. * HISTORY: *
  3811. * 11/21/1995 BRR : Created. *
  3812. *=========================================================================*/
  3813. static void Init_Queue_Mono(ConnManClass *net)
  3814. {
  3815. #if(SHOW_MONO)
  3816. //------------------------------------------------------------------------
  3817. // Set 'IsMono' so we can steal the mono screen from the engine
  3818. //------------------------------------------------------------------------
  3819. if ((Frame==0 || Session.LoadGame) && MonoClass::Is_Enabled()) {
  3820. IsMono = true;
  3821. }
  3822. //------------------------------------------------------------------------
  3823. // Enable mono output for our stuff; we must Disable it before we return
  3824. // control to the engine.
  3825. //------------------------------------------------------------------------
  3826. if (IsMono)
  3827. MonoClass::Enable();
  3828. if (net->Num_Connections() > 0) {
  3829. //.....................................................................
  3830. // Network mono debugging screen
  3831. //.....................................................................
  3832. if (NetMonoMode==0) {
  3833. if (Frame==0 || Session.LoadGame || NewMonoMode) {
  3834. net->Configure_Debug (0, sizeof (CommHeaderType),
  3835. sizeof(EventClass::EventType), EventClass::EventNames, 0, 27);
  3836. net->Mono_Debug_Print (0,1);
  3837. NewMonoMode = 0;
  3838. }
  3839. else {
  3840. net->Mono_Debug_Print (0,0);
  3841. }
  3842. }
  3843. //.....................................................................
  3844. // Flow control debugging output
  3845. //.....................................................................
  3846. else {
  3847. if (NewMonoMode) {
  3848. Mono_Clear_Screen();
  3849. Mono_Printf(" Queue AI:\n"); // flowcount[0]
  3850. Mono_Printf(" Build Packet Loop:\n"); // flowcount[1]
  3851. Mono_Printf(" Frame Sync:\n"); // flowcount[2]
  3852. Mono_Printf(" Frame Sync Resend:\n"); // flowcount[3]
  3853. Mono_Printf(" Frame Sync Timeout:\n"); // flowcount[4]
  3854. Mono_Printf(" Frame Sync New Message:\n"); // flowcount[5]
  3855. Mono_Printf(" DoList Execution:\n"); // flowcount[6]
  3856. Mono_Printf(" DoList Cleaning:\n"); // flowcount[7]
  3857. Mono_Printf("\n");
  3858. Mono_Printf(" Frame:\n");
  3859. Mono_Printf(" Session.MaxAhead:\n");
  3860. Mono_Printf(" their_recv:\n");
  3861. Mono_Printf(" their_sent:\n");
  3862. Mono_Printf(" my_sent:\n");
  3863. NewMonoMode = 0;
  3864. }
  3865. }
  3866. }
  3867. #else
  3868. net = net;
  3869. #endif
  3870. } // end of Init_Queue_Mono
  3871. /***************************************************************************
  3872. * Update_Queue_Mono -- updates mono display *
  3873. * *
  3874. * INPUT: *
  3875. * net ptr to connection manager *
  3876. * flow_index index # for flow-count updates *
  3877. * -1: display *
  3878. * *
  3879. * OUTPUT: *
  3880. * none. *
  3881. * *
  3882. * WARNINGS: *
  3883. * none. *
  3884. * *
  3885. * HISTORY: *
  3886. * 11/21/1995 BRR : Created. *
  3887. *=========================================================================*/
  3888. static void Update_Queue_Mono(ConnManClass *net, int flow_index)
  3889. {
  3890. #if(SHOW_MONO)
  3891. static int flowcount[20] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  3892. //------------------------------------------------------------------------
  3893. // If 'NetMonoMode' is 1, display flowcount info
  3894. //------------------------------------------------------------------------
  3895. if (NetMonoMode==1) {
  3896. if (flow_index >= 0 && flow_index < 20) {
  3897. Mono_Set_Cursor(35,flow_index);
  3898. flowcount[flow_index]++;
  3899. Mono_Printf("%d",flowcount[flow_index]);
  3900. }
  3901. }
  3902. //------------------------------------------------------------------------
  3903. // Otherwise, display the connection debug screen
  3904. //------------------------------------------------------------------------
  3905. else {
  3906. net->Mono_Debug_Print (0,0);
  3907. }
  3908. #else
  3909. flow_index = flow_index;
  3910. net = net;
  3911. #endif
  3912. } // end of Update_Queue_Mono
  3913. /***************************************************************************
  3914. * Print_Framesync_Values -- displays frame-sync variables *
  3915. * *
  3916. * INPUT: *
  3917. * curframe current game Frame # *
  3918. * max_ahead max-ahead value *
  3919. * num_connections # connections *
  3920. * their_recv # commands I've received from my connections *
  3921. * their_sent # commands each connection claims to have sent *
  3922. * my_sent # commands I've sent *
  3923. * *
  3924. * OUTPUT: *
  3925. * none. *
  3926. * *
  3927. * WARNINGS: *
  3928. * none. *
  3929. * *
  3930. * HISTORY: *
  3931. * 11/21/1995 BRR : Created. *
  3932. *=========================================================================*/
  3933. static void Print_Framesync_Values(long curframe, unsigned long max_ahead,
  3934. int num_connections, unsigned short *their_recv,
  3935. unsigned short *their_sent, unsigned short my_sent)
  3936. {
  3937. #if(SHOW_MONO)
  3938. int i;
  3939. if (NetMonoMode==1) {
  3940. Mono_Set_Cursor(35,9);
  3941. Mono_Printf("%d",curframe);
  3942. Mono_Set_Cursor(35,10);
  3943. Mono_Printf("%d",max_ahead);
  3944. for (i = 0; i < num_connections; i++) {
  3945. Mono_Set_Cursor(35 + i*5,11);
  3946. Mono_Printf("%4d",(int)their_recv[i]);
  3947. }
  3948. for (i = 0; i < num_connections; i++) {
  3949. Mono_Set_Cursor(35 + i*5,12);
  3950. Mono_Printf("%4d",(int)their_sent[i]);
  3951. }
  3952. Mono_Set_Cursor(35,13);
  3953. Mono_Printf("%4d",(int)my_sent);
  3954. }
  3955. #else
  3956. curframe = curframe;
  3957. max_ahead = max_ahead;
  3958. num_connections = num_connections;
  3959. their_recv = their_recv;
  3960. their_sent = their_sent;
  3961. my_sent = my_sent;
  3962. #endif
  3963. } // end of Print_Framesync_Values
  3964. /***************************************************************************
  3965. * Dump_Packet_Too_Late_Stuff -- Dumps a debug file to disk *
  3966. * *
  3967. * INPUT: *
  3968. * event ptr to event to print *
  3969. * *
  3970. * OUTPUT: *
  3971. * none. *
  3972. * *
  3973. * WARNINGS: *
  3974. * none. *
  3975. * *
  3976. * HISTORY: *
  3977. * 06/28/1996 BRR : Created. *
  3978. *=========================================================================*/
  3979. void Dump_Packet_Too_Late_Stuff(EventClass *event, ConnManClass *net,
  3980. long *their_frame, unsigned short *their_sent, unsigned short *their_recv)
  3981. {
  3982. FILE *fp;
  3983. int i;
  3984. HousesType house;
  3985. fp = fopen("toolate.txt", "wt");
  3986. if (!fp) {
  3987. return;
  3988. }
  3989. fprintf(fp,"----------------- Event data: ----------------------\n");
  3990. fprintf(fp,"Type: %s\n",EventClass::EventNames[event->Type]);
  3991. fprintf(fp,"Frame: %d\n",event->Frame);
  3992. fprintf(fp,"ID: %d\n",event->ID);
  3993. for (i = 0; i < Session.Players.Count(); i++) {
  3994. if (event->ID == Session.Players[i]->Player.ID) {
  3995. fprintf(fp,"Player's Name: %s",Session.Players[i]->Name);
  3996. }
  3997. }
  3998. fprintf(fp,"\n");
  3999. fprintf(fp,"--------------------- My data: ---------------------\n");
  4000. fprintf(fp,"My Frame:%d\n",Frame);
  4001. fprintf(fp,"My MaxAhead:%d\n",Session.MaxAhead);
  4002. if (net) {
  4003. fprintf(fp,"-------------------- Frame Stats: ------------------\n");
  4004. fprintf(fp,"Name ID TheirFrame TheirSent TheirRecv\n");
  4005. for (i = 0; i < net->Num_Connections(); i++) {
  4006. house = (HousesType)(net->Connection_ID(i));
  4007. fprintf(fp,"%12s %2d %6d %6d %6d\n",
  4008. (HouseClass::As_Pointer(house))->IniName,
  4009. net->Connection_ID(i),
  4010. their_frame[i],
  4011. their_sent[i],
  4012. their_recv[i]);
  4013. }
  4014. }
  4015. fclose(fp);
  4016. }
  4017. /***************************************************************************
  4018. * Check_Mirror -- Checks mirror memory *
  4019. * *
  4020. * INPUT: *
  4021. * none. *
  4022. * *
  4023. * OUTPUT: *
  4024. * none. *
  4025. * *
  4026. * WARNINGS: *
  4027. * none. *
  4028. * *
  4029. * HISTORY: *
  4030. * 10/14/1996 BRR : Created. *
  4031. *=========================================================================*/
  4032. void Check_Mirror(void)
  4033. {
  4034. #ifdef MIRROR_QUEUE
  4035. int i;
  4036. char txt[80];
  4037. unsigned long *ptr;
  4038. int found_5s = 0;
  4039. ptr = (unsigned long *)(DoList.Get_Array());
  4040. for (i = 0; i < (MAX_EVENTS * 64 * sizeof(EventClass)) /
  4041. sizeof(unsigned long); i++) {
  4042. if (ptr[i] == 0x55555555) {
  4043. sprintf(txt,"55555555 found in DoList! Addr:%p", &(ptr[i]));
  4044. WWMessageBox().Process (txt);
  4045. found_5s = 1;
  4046. }
  4047. }
  4048. ptr = (unsigned long *)(MirrorList.Get_Array());
  4049. for (i = 0; i < (MAX_EVENTS * 64 * sizeof(EventClass)) /
  4050. sizeof(unsigned long); i++) {
  4051. if (ptr[i] == 0x55555555) {
  4052. sprintf(txt,"55555555 found in MirrorList! Addr:%p", &(ptr[i]));
  4053. WWMessageBox().Process (txt);
  4054. found_5s = 1;
  4055. }
  4056. }
  4057. ptr = (unsigned long *)(DoList.Get_Array());
  4058. for (i = 0; i < (MAX_EVENTS * 64 * sizeof(EventClass)) /
  4059. sizeof(unsigned long); i++) {
  4060. if (ptr[i] == 0xAAAAAAAA) {
  4061. sprintf(txt,"AAAAAAAA found in DoList! Addr:%p", &(ptr[i]));
  4062. WWMessageBox().Process (txt);
  4063. found_5s = 1;
  4064. }
  4065. }
  4066. ptr = (unsigned long *)(MirrorList.Get_Array());
  4067. for (i = 0; i < (MAX_EVENTS * 64 * sizeof(EventClass)) /
  4068. sizeof(unsigned long); i++) {
  4069. if (ptr[i] == 0xAAAAAAAA) {
  4070. sprintf(txt,"AAAAAAAA found in MirrorList! Addr:%p", &(ptr[i]));
  4071. WWMessageBox().Process (txt);
  4072. found_5s = 1;
  4073. }
  4074. }
  4075. for (i = 0; i < DoList.Count; i++) {
  4076. if (memcmp(&DoList[i], &MirrorList[i], sizeof(EventClass)) != 0) {
  4077. sprintf(txt,"Queue Memory Trashed! Head:%d Tail:%d, Addr:%p or %p",
  4078. DoList.Get_Head(),
  4079. DoList.Get_Tail(),
  4080. DoList.Get_Array() + i,
  4081. MirrorList.Get_Array() + i);
  4082. WWMessageBox().Process (txt);
  4083. //Prog_End();
  4084. Emergency_Exit(0);
  4085. }
  4086. }
  4087. if (found_5s) {
  4088. //Prog_End();
  4089. Emergency_Exit(0);
  4090. }
  4091. #endif
  4092. } // end of Check_Mirror
  4093. /*************************** end of queue.cpp ******************************/