NETDLG.CPP 207 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: F:\projects\c&c\vcs\code\netdlg.cpv 2.17 16 Oct 1995 16:52:26 JOE_BOSTIC $ */
  15. /***********************************************************************************************
  16. *** 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 ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : NETDLG.CPP *
  22. * *
  23. * Programmer : Bill Randolph *
  24. * *
  25. * Start Date : January 23, 1995 *
  26. * *
  27. * Last Update : July 8, 1995 [BRR] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * *
  31. * These routines establish & maintain peer-to-peer connections between this system *
  32. * and all others in the game. Each system finds out the IPX address of the others, *
  33. * and forms a direct connection (IPXConnectionClass) to that system. Systems are *
  34. * found out via broadcast queries. Every system broadcasts its queries, and every *
  35. * system replies to queries it receives. At the point when the game owner signals *
  36. * 'OK', every system must know about all the other systems in the game. *
  37. * *
  38. * How Bridges are handled: *
  39. * Currently, bridges are handled by specifying the destination IPX address of the *
  40. * "server" (game owner's system) on the command-line. This address is used to *
  41. * derive a broadcast address to that destination network, and this system's queries *
  42. * are broadcast over its network & the server's network; replies to the queries come *
  43. * with each system's IPX address attached, so once we have the address, we can form *
  44. * a connection with any system on the bridged net. *
  45. * *
  46. * The flaw in this plan is that we can only cross one bridge. If there are 3 nets *
  47. * bridged (A, B, & C), and the server is on net B, and we're on net A, our broadcasts *
  48. * will reach nets A & B, but not C. The way to circumvent this (if it becomes a problem) *
  49. * would be to have the server tell us what other systems are in its game, not each *
  50. * individual player's system. Thus, each system would find out about all the other systems *
  51. * by interacting with the game's owner system (this would be more involved than what *
  52. * I'm doing here). *
  53. * *
  54. * Here's a list of all the different packets sent over the Global Channel: *
  55. * *
  56. * NET_QUERY_GAME *
  57. * (no other data) *
  58. * NET_ANSWER_GAME *
  59. * Name: game owner's name *
  60. * GameInfo: game's version & open state *
  61. * NET_QUERY_PLAYER *
  62. * Name: name of game we want players to respond for *
  63. * NET_ANSWER_PLAYER *
  64. * Name: player's name *
  65. * PlayerInfo: info about player *
  66. * NET_QUERY_JOIN *
  67. * Name: name of player wanting to join *
  68. * PlayerInfo: player's requested house & color *
  69. * NET_CONFIRM_JOIN *
  70. * PlayerInfo: approves player's house & color *
  71. * NET_REJECT_JOIN *
  72. * (no other data) *
  73. * NET_GAME_OPTIONS *
  74. * ScenarioInfo: info about scenario *
  75. * NET_SIGN_OFF *
  76. * Name: name of player signing off *
  77. * NET_PING *
  78. * (no other data) *
  79. * NET_GO *
  80. * Delay: value of one-way response time, in frames *
  81. * *
  82. *---------------------------------------------------------------------------------------------*
  83. * Functions: *
  84. * Clear_Game_List -- Clears the game-name listbox & 'Games' Vector *
  85. * Clear_Player_List -- Clears the player-name listbox & Vector *
  86. * Destroy_Connection -- destroys the given connection *
  87. * Get_Join_Responses -- sends queries for the Join Dialog *
  88. * Get_NewGame_Responses -- processes packets for New Game dialog *
  89. * Init_Network -- initializes network stuff *
  90. * Net_Join_Dialog -- lets user join an existing game, or start a new one *
  91. * Net_New_Dialog -- lets user start a new game *
  92. * Process_Global_Packet -- responds to remote queries *
  93. * Remote_Connect -- handles connecting this user to others *
  94. * Request_To_Join -- Sends a JOIN request packet to game owner *
  95. * Send_Join_Queries -- sends queries for the Join Dialog *
  96. * Shutdown_Network -- shuts down network stuff *
  97. * Compute_Name_CRC -- computes CRC from char string *
  98. * Net_Reconnect_Dialog -- Draws/updates the network reconnect dialog *
  99. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  100. #include "function.h"
  101. #include <time.h>
  102. #include "tcpip.h"
  103. #include "ccdde.h"
  104. #define SHOW_MONO 0
  105. // ST = 12/17/2018 5:44PM
  106. #ifndef TickCount
  107. extern TimerClass TickCount;
  108. #endif
  109. #ifndef DEMO
  110. /*---------------------------------------------------------------------------
  111. The possible states of the join-game dialog
  112. ---------------------------------------------------------------------------*/
  113. typedef enum {
  114. JOIN_REJECTED = -1, // we've been rejected
  115. JOIN_NOTHING, // we're not trying to join a game
  116. JOIN_WAIT_CONFIRM, // we're asking to join, & waiting for confirmation
  117. JOIN_CONFIRMED, // we've been confirmed
  118. JOIN_GAME_START, // the game we've joined is starting
  119. } JoinStateType;
  120. /*---------------------------------------------------------------------------
  121. The possible return codes from Get_Join_Responses()
  122. ---------------------------------------------------------------------------*/
  123. typedef enum {
  124. EV_NONE, // nothing happened
  125. EV_STATE_CHANGE, // Join dialog is in a new state
  126. EV_NEW_GAME, // a new game was detected
  127. EV_NEW_PLAYER, // a new player was detected
  128. EV_PLAYER_SIGNOFF, // a player has signed off
  129. EV_GAME_SIGNOFF, // a gamed owner has signed off
  130. EV_GAME_OPTIONS, // a game options packet was received
  131. EV_MESSAGE, // a message was received
  132. } JoinEventType;
  133. /*
  134. ******************************** Prototypes *********************************
  135. */
  136. static int Net_Join_Dialog(void);
  137. static void Clear_Game_List (ListClass *gamelist);
  138. static void Clear_Player_List (ListClass *playerlist);
  139. static int Request_To_Join (char *playername, int join_index, ListClass *playerlist,
  140. HousesType house, int color);
  141. static void Send_Join_Queries(int curgame, int gamenow, int playernow);
  142. static JoinEventType Get_Join_Responses(JoinStateType *joinstate, ListClass *gamelist,
  143. ColorListClass *playerlist, int join_index);
  144. static int Net_New_Dialog(void);
  145. static JoinEventType Get_NewGame_Responses(ColorListClass *playerlist);
  146. static int Net_Fake_New_Dialog(void);
  147. static int Net_Fake_Join_Dialog(void);
  148. /***********************************************************************************************
  149. * Init_Network -- initializes network stuff *
  150. * *
  151. * INPUT: *
  152. * none. *
  153. * *
  154. * OUTPUT: *
  155. * true = Initialization OK, false = error *
  156. * *
  157. * WARNINGS: *
  158. * none. *
  159. * *
  160. * HISTORY: *
  161. * 02/14/1995 BR : Created. *
  162. *=============================================================================================*/
  163. bool Init_Network (void)
  164. {
  165. NetNumType net;
  166. NetNodeType node;
  167. /*------------------------------------------------------------------------
  168. This call allocates all necessary queue buffers, allocates Real-mode
  169. memory, and commands IPX to start listening on the Global Channel.
  170. ------------------------------------------------------------------------*/
  171. if (!Ipx.Init())
  172. return(false);
  173. /*------------------------------------------------------------------------
  174. Allocate our "meta-packet" buffer
  175. ------------------------------------------------------------------------*/
  176. if (!MetaPacket) {
  177. MetaPacket = new char [sizeof (EventClass) * MAX_EVENTS];
  178. }
  179. /*------------------------------------------------------------------------
  180. Set up the IPX manager to cross a bridge
  181. ------------------------------------------------------------------------*/
  182. if (!(GameToPlay == GAME_INTERNET)){
  183. if (IsBridge) {
  184. BridgeNet.Get_Address(net,node);
  185. Ipx.Set_Bridge(net);
  186. }
  187. }
  188. return(true);
  189. } /* end of Init_Network */
  190. /***********************************************************************************************
  191. * Shutdown_Network -- shuts down network stuff *
  192. * *
  193. * INPUT: *
  194. * none. *
  195. * *
  196. * OUTPUT: *
  197. * none. *
  198. * *
  199. * WARNINGS: *
  200. * none. *
  201. * *
  202. * HISTORY: *
  203. * 02/14/1995 BR : Created. *
  204. *=============================================================================================*/
  205. void Shutdown_Network (void)
  206. {
  207. //
  208. // Note: The thought behind this section of code was that if the program
  209. // terminates early, without an EventClass::EXIT event, it still needs to
  210. // tell the other systems that it's gone, so it would send a SIGN_OFF packet.
  211. // BUT, this causes a sync bug if the systems are running slow and this system
  212. // is running ahead of the others; it will send the NET_SIGN_OFF >>before<<
  213. // the other system execute their EventClass::EXIT event, and the other systems
  214. // will kill the connection at some random Frame # & turn my stuff over to
  215. // the computer possibly at different times.
  216. // BRR, 10/29/96
  217. //
  218. #if (0)
  219. /*------------------------------------------------------------------------
  220. Broadcast a sign-off packet, by sending the packet over the Global Channel,
  221. telling the IPX Manager that no ACK is required, and specifying a NULL
  222. destination address.
  223. ------------------------------------------------------------------------*/
  224. memset (&GPacket, 0, sizeof(GlobalPacketType));
  225. GPacket.Command = NET_SIGN_OFF;
  226. strcpy (GPacket.Name, MPlayerName);
  227. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL);
  228. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL);
  229. if (IsBridge && !Winsock.Get_Connected()) {
  230. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, &BridgeNet);
  231. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, &BridgeNet);
  232. }
  233. /*------------------------------------------------------------------------
  234. Wait for the packets to finish going out (or the Global Channel times out)
  235. ------------------------------------------------------------------------*/
  236. for (;;) {
  237. if (Ipx.Global_Num_Send()==0) {
  238. break;
  239. }
  240. Ipx.Service();
  241. }
  242. #endif //(0)
  243. /*------------------------------------------------------------------------
  244. Delete our "meta-packet"
  245. ------------------------------------------------------------------------*/
  246. delete [] MetaPacket;
  247. MetaPacket = 0;
  248. /*------------------------------------------------------------------------
  249. If I was in a game, I'm not now, so clear the game name
  250. ------------------------------------------------------------------------*/
  251. MPlayerGameName[0] = 0;
  252. }
  253. /***********************************************************************************************
  254. * Process_Global_Packet -- responds to remote queries *
  255. * *
  256. * The only commands from other systems this routine responds to are NET_QUERY_GAME *
  257. * and NET_QUERY_PLAYER. The other commands are too context-specific to be able *
  258. * to handle here, such as joining the game or signing off; but this routine handles *
  259. * the majority of the program's needs. *
  260. * *
  261. * INPUT: *
  262. * packet ptr to packet to process *
  263. * address source address of sender *
  264. * *
  265. * OUTPUT: *
  266. * true = packet was processed, false = wasn't *
  267. * *
  268. * WARNINGS: *
  269. * MPlayerName & MPlayerGameName must have been filled in before this function *
  270. * can be called. *
  271. * *
  272. * HISTORY: *
  273. * 02/15/1995 BR : Created. *
  274. *=============================================================================================*/
  275. bool Process_Global_Packet(GlobalPacketType *packet, IPXAddressClass *address)
  276. {
  277. GlobalPacketType mypacket;
  278. /*
  279. ---------------- Another system asking what game this is -----------------
  280. */
  281. if (packet->Command==NET_QUERY_GAME && NetStealth==0) {
  282. /*.....................................................................
  283. If the game is closed, let every player respond, and let the sender of
  284. the query sort it all out. This way, if the game's host exits the game,
  285. the game still shows up on other players' dialogs.
  286. If the game is open, only the game owner may respond.
  287. .....................................................................*/
  288. if (strlen(MPlayerName) > 0 && strlen(MPlayerGameName) > 0 &&
  289. ((!NetOpen) || (NetOpen && !strcmp(MPlayerName,MPlayerGameName)))) {
  290. memset (packet, 0, sizeof(GlobalPacketType));
  291. mypacket.Command = NET_ANSWER_GAME;
  292. strcpy(mypacket.Name, MPlayerGameName);
  293. #ifdef PATCH
  294. if (IsV107) {
  295. mypacket.GameInfo.Version = 1;
  296. } else {
  297. mypacket.GameInfo.Version = 2;
  298. }
  299. #else
  300. mypacket.GameInfo.Version = Version_Number();
  301. #endif
  302. mypacket.GameInfo.IsOpen = NetOpen;
  303. Ipx.Send_Global_Message (&mypacket, sizeof(GlobalPacketType), 1,
  304. address);
  305. }
  306. return(true);
  307. } else {
  308. /*
  309. ----------------- Another system asking what player I am -----------------
  310. */
  311. if (packet->Command==NET_QUERY_PLAYER &&
  312. !strcmp (packet->Name, MPlayerGameName) &&
  313. (strlen(MPlayerGameName) > 0) && NetStealth==0) {
  314. memset (packet, 0, sizeof(GlobalPacketType));
  315. mypacket.Command = NET_ANSWER_PLAYER;
  316. strcpy(mypacket.Name, MPlayerName);
  317. mypacket.PlayerInfo.House = MPlayerHouse;
  318. mypacket.PlayerInfo.Color = MPlayerColorIdx;
  319. mypacket.PlayerInfo.NameCRC = Compute_Name_CRC(MPlayerGameName);
  320. Ipx.Send_Global_Message (&mypacket, sizeof(GlobalPacketType), 1, address);
  321. return(true);
  322. }
  323. }
  324. return(false);
  325. }
  326. /***********************************************************************************************
  327. * Destroy_Connection -- destroys the given connection *
  328. * *
  329. * Call this routine when a connection goes bad, or another player signs off. *
  330. * *
  331. * INPUT: *
  332. * id connection ID to destroy *
  333. * error 0 = user signed off; 1 = connection error; otherwise, no error is shown. *
  334. * *
  335. * OUTPUT: *
  336. * none. *
  337. * *
  338. * WARNINGS: *
  339. * none. *
  340. * *
  341. * HISTORY: *
  342. * 04/22/1995 BR : Created. *
  343. *=============================================================================================*/
  344. void Destroy_Connection(int id, int error)
  345. {
  346. int i,j;
  347. HousesType house;
  348. HouseClass *housep;
  349. char txt[80];
  350. /*------------------------------------------------------------------------
  351. Create a message to display to the user
  352. ------------------------------------------------------------------------*/
  353. txt[0] = '\0';
  354. if (error==1) {
  355. sprintf(txt,Text_String(TXT_CONNECTION_LOST),Ipx.Connection_Name(id));
  356. } else if (error==0) {
  357. sprintf(txt,Text_String(TXT_LEFT_GAME),Ipx.Connection_Name(id));
  358. }
  359. if (strlen(txt)) {
  360. Messages.Add_Message (txt,
  361. MPlayerTColors[MPlayerID_To_ColorIndex((unsigned char)id)],
  362. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, 0, 0);
  363. Map.Flag_To_Redraw(false);
  364. }
  365. /*------------------------------------------------------------------------
  366. Delete the IPX connection, shift the MPlayerID's & MPlayerHouses' back one.
  367. ------------------------------------------------------------------------*/
  368. Ipx.Delete_Connection(id);
  369. for (i = 0; i < MPlayerCount; i++) {
  370. if (MPlayerID[i] == (unsigned char)id) {
  371. /*..................................................................
  372. Turn the player's house over to the computer's AI
  373. ..................................................................*/
  374. house = MPlayerHouses[i];
  375. housep = HouseClass::As_Pointer (house);
  376. housep->IsHuman = false;
  377. housep->IsStarted = true;
  378. /*..................................................................
  379. Move arrays back by one
  380. ..................................................................*/
  381. for (j = i; j < MPlayerCount - 1; j++) {
  382. MPlayerID[j] = MPlayerID[j + 1];
  383. MPlayerHouses[j] = MPlayerHouses[j + 1];
  384. strcpy (MPlayerNames[j], MPlayerNames[j+1]);
  385. TheirProcessTime[j] = TheirProcessTime[j+1];
  386. }
  387. }
  388. }
  389. MPlayerCount--;
  390. /*------------------------------------------------------------------------
  391. If we're the last player left, tell the user.
  392. ------------------------------------------------------------------------*/
  393. if (MPlayerCount == 1) {
  394. sprintf(txt,"%s",Text_String(TXT_JUST_YOU_AND_ME));
  395. Messages.Add_Message (txt,
  396. MPlayerTColors[MPlayerID_To_ColorIndex((unsigned char)id)],
  397. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, 0, 0);
  398. Map.Flag_To_Redraw(false);
  399. }
  400. } /* end of Destroy_Connection */
  401. /***********************************************************************************************
  402. * Remote_Connect -- handles connecting this user to others *
  403. * *
  404. * INPUT: *
  405. * none. *
  406. * *
  407. * OUTPUT: *
  408. * true = connections established; false = not *
  409. * *
  410. * WARNINGS: *
  411. * none. *
  412. * *
  413. * HISTORY: *
  414. * 02/14/1995 BR : Created. *
  415. *=============================================================================================*/
  416. bool Remote_Connect(void)
  417. {
  418. int rc;
  419. int stealth; // original state of NetStealth flag
  420. /*------------------------------------------------------------------------
  421. Init network timing parameters; these values should work for both a "real"
  422. network, and a simulated modem network (ie Kali)
  423. ------------------------------------------------------------------------*/
  424. Ipx.Set_Timing ( 30, // retry 2 times per second
  425. -1, // ignore max retries
  426. 600); // give up after 10 seconds
  427. /*------------------------------------------------------------------------
  428. Save the original value of the NetStealth flag, so we can turn stealth
  429. off for now (during this portion of the dialogs, we must show ourselves)
  430. ------------------------------------------------------------------------*/
  431. stealth = NetStealth;
  432. NetStealth = 0;
  433. /*------------------------------------------------------------------------
  434. Init my game name to 0-length, since I haven't joined any game yet.
  435. ------------------------------------------------------------------------*/
  436. MPlayerGameName[0] = 0;
  437. /*------------------------------------------------------------------------
  438. The game is now "open" for joining. Close it as soon as we exit this
  439. routine.
  440. ------------------------------------------------------------------------*/
  441. NetOpen = 1;
  442. /*------------------------------------------------------------------------
  443. Read the default values from the INI file
  444. ------------------------------------------------------------------------*/
  445. Read_MultiPlayer_Settings ();
  446. /*------------------------------------------------------------------------
  447. Keep looping until something useful happens.
  448. ------------------------------------------------------------------------*/
  449. while (1) {
  450. /*---------------------------------------------------------------------
  451. Pop up the network Join/New dialog
  452. ---------------------------------------------------------------------*/
  453. rc = Net_Join_Dialog();
  454. /*---------------------------------------------------------------------
  455. -1 = user selected Cancel
  456. ---------------------------------------------------------------------*/
  457. if (rc==-1) {
  458. NetStealth = stealth;
  459. NetOpen = 0;
  460. return(false);
  461. } else {
  462. /*---------------------------------------------------------------------
  463. 0 = user has joined an existing game; save values & return
  464. ---------------------------------------------------------------------*/
  465. if (rc==0) {
  466. Write_MultiPlayer_Settings ();
  467. NetStealth = stealth;
  468. NetOpen = 0;
  469. return(true);
  470. } else {
  471. /*---------------------------------------------------------------------
  472. 1 = user requests New Network Game
  473. ---------------------------------------------------------------------*/
  474. if (rc==1) {
  475. /*..................................................................
  476. Pop up the New Network Game dialog; if user selects OK, return
  477. 'true'; otherwise, return to the Join Dialog.
  478. ..................................................................*/
  479. if (Net_New_Dialog()) {
  480. Write_MultiPlayer_Settings ();
  481. NetOpen = 0;
  482. NetStealth = stealth;
  483. NetOpen = 0;
  484. return(true);
  485. } else {
  486. continue;
  487. }
  488. }
  489. }
  490. }
  491. }
  492. }
  493. /***********************************************************************************************
  494. * Remote_Connect -- handles connecting this host to the server in an internet game *
  495. * *
  496. * INPUT: *
  497. * none. *
  498. * *
  499. * OUTPUT: *
  500. * true = connections established; false = not *
  501. * *
  502. * WARNINGS: *
  503. * none. *
  504. * *
  505. * HISTORY: *
  506. * 02/14/1995 BR : Created. *
  507. *=============================================================================================*/
  508. bool Server_Remote_Connect(void)
  509. {
  510. int stealth; // original state of NetStealth flag
  511. /*------------------------------------------------------------------------
  512. Init network timing parameters; these values should work for both a "real"
  513. network, and a simulated modem network (ie Kali)
  514. ------------------------------------------------------------------------*/
  515. Ipx.Set_Timing ( 30, // retry 2 times per second
  516. -1, // ignore max retries
  517. 600); // give up after 10 seconds
  518. /*------------------------------------------------------------------------
  519. Save the original value of the NetStealth flag, so we can turn stealth
  520. off for now (during this portion of the dialogs, we must show ourselves)
  521. ------------------------------------------------------------------------*/
  522. stealth = NetStealth;
  523. NetStealth = 0;
  524. /*------------------------------------------------------------------------
  525. The game is now "open" for joining. Close it as soon as we exit this
  526. routine.
  527. ------------------------------------------------------------------------*/
  528. NetOpen = 1;
  529. /*------------------------------------------------------------------------
  530. Read the default values from the INI file
  531. ------------------------------------------------------------------------*/
  532. Read_MultiPlayer_Settings ();
  533. if (!Net_Fake_New_Dialog()){
  534. Write_MultiPlayer_Settings ();
  535. return (false);
  536. }
  537. NetOpen = 0;
  538. NetStealth = stealth;
  539. Write_MultiPlayer_Settings ();
  540. return (true);
  541. }
  542. /***********************************************************************************************
  543. * Client_Remote_Connect -- handles connecting this client to the server in an internet game *
  544. * *
  545. * INPUT: *
  546. * none. *
  547. * *
  548. * OUTPUT: *
  549. * true = connections established; false = not *
  550. * *
  551. * WARNINGS: *
  552. * none. *
  553. * *
  554. * HISTORY: *
  555. * 02/14/1995 ST : Created. *
  556. *=============================================================================================*/
  557. bool Client_Remote_Connect(void)
  558. {
  559. int rc;
  560. int stealth; // original state of NetStealth flag
  561. /*------------------------------------------------------------------------
  562. Init network timing parameters; these values should work for both a "real"
  563. network, and a simulated modem network (ie Kali)
  564. ------------------------------------------------------------------------*/
  565. Ipx.Set_Timing ( 30, // retry 2 times per second
  566. -1, // ignore max retries
  567. 600); // give up after 10 seconds
  568. /*------------------------------------------------------------------------
  569. Save the original value of the NetStealth flag, so we can turn stealth
  570. off for now (during this portion of the dialogs, we must show ourselves)
  571. ------------------------------------------------------------------------*/
  572. stealth = NetStealth;
  573. NetStealth = 0;
  574. /*------------------------------------------------------------------------
  575. The game is now "open" for joining. Close it as soon as we exit this
  576. routine.
  577. ------------------------------------------------------------------------*/
  578. NetOpen = 1;
  579. /*------------------------------------------------------------------------
  580. Read the default values from the INI file
  581. ------------------------------------------------------------------------*/
  582. Read_MultiPlayer_Settings ();
  583. /*---------------------------------------------------------------------
  584. Pop up the network Join/New dialog
  585. ---------------------------------------------------------------------*/
  586. rc = Net_Fake_Join_Dialog();
  587. Write_MultiPlayer_Settings ();
  588. NetStealth = stealth;
  589. NetOpen = 0;
  590. if (rc == -1) {
  591. return(false);
  592. } else {
  593. return(true);
  594. }
  595. }
  596. /***********************************************************************************************
  597. * Net_Join_Dialog -- lets user join an existing game or start a new one *
  598. * *
  599. * This dialog displays an edit field for the player's name, and a list of all non-stealth- *
  600. * mode games. Clicking once on a game name displays a list of who's in that game. Clicking *
  601. * "New" takes the user to the Net_New dialog, where he waits for other users to join his *
  602. * game. All other input is done through this dialog. *
  603. * *
  604. * The dialog has several "states": *
  605. * *
  606. * 1) Initially, it waits for the user to fill in his/her name and then to select Join or New; *
  607. * if New is selected, this dialog is exited. *
  608. * *
  609. * 2) If Join is selected, the Join & New buttons are removed, but the Cancel button remains. *
  610. * The join request is transmitted to the game's owner, and the message "Waiting for *
  611. * Confirmation" is displayed, until a confirmation or denial is received from the game's *
  612. * owner. The user may click Cancel at this point to cancel the join request. *
  613. * (Once Join is selected, the name editing field is disabled, and becomes a display-only *
  614. * field. If cancel is selected, it reappears as an edit field.) The user can still click *
  615. * around & see who's in which games. *
  616. * *
  617. * 3) If the join request is denied, the dialog re-initializes to its pre-join state; the *
  618. * Join & New buttons reappear, & the Name field is available again. *
  619. * *
  620. * 4) If join confirmation is obtained, the message just changes to "Confirmed. Waiting for *
  621. * Entry Signal." or some such nonsense. The user can still click around & see who's *
  622. * in which games. *
  623. * *
  624. * Any game running in Stealth mode won't show up on this dialog. *
  625. * *
  626. * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ *
  627. * ³ Network Games ³ *
  628. * ³ ³ *
  629. * ³ Your Name: ____________ ³ *
  630. * ³ House: [GDI] [NOD] ³ *
  631. * ³ Desired Color: [ ][ ][ ][ ] ³ *
  632. * ³ ³ *
  633. * ³ Games Players ³ *
  634. * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ³ *
  635. * ³ ³(Bill's Game )³³ ³ Peter Parker GDI ³³ ³ *
  636. * ³ ³ Peter Parker's Game ÃÄ´ ³ Mary Jane GDI ÃÄ´ ³ *
  637. * ³ ³(Magnum PI's Game )³ ³ ³ JJ Jameson NOD ³ ³ ³ *
  638. * ³ ³ ÃÄ´ ³ ÃÄ´ ³ *
  639. * ³ ³ ³³ ³ ³³ ³ *
  640. * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ³ *
  641. * ³ Scenario: Big Long Description ³ *
  642. * ³ Starting Credits: xxxx ³ *
  643. * ³ Count: --- Level: --- ³ *
  644. * ³ Bases: ON Crates: ON ³ *
  645. * ³ Tiberium: ON AI Players: ON ³ *
  646. * ³ ³ *
  647. * ³ [Join] [Cancel] [New] ³ *
  648. * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ *
  649. * ³ ³ ³ ³ *
  650. * ³ ³ ³ ³ *
  651. * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ *
  652. * ³ [Send Message] ³ *
  653. * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ *
  654. * *
  655. * INPUT: *
  656. * none. *
  657. * *
  658. * OUTPUT: *
  659. * -1 = cancel, 0 = OK, 1 = New net game requested *
  660. * *
  661. * WARNINGS: *
  662. * none. *
  663. * *
  664. * HISTORY: *
  665. * 02/14/1995 BR : Created. *
  666. *=============================================================================================*/
  667. static int Net_Join_Dialog(void)
  668. {
  669. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  670. /*........................................................................
  671. Dialog & button dimensions
  672. ........................................................................*/
  673. /* ###Change collision detected! C:\PROJECTS\CODE\NETDLG.CPP... */
  674. int d_dialog_w = 287 *factor; // dialog width
  675. int d_dialog_h = 198*factor; // dialog height
  676. int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord
  677. int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord
  678. int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord
  679. int d_txt6_h = 6*factor+1; // ht of 6-pt text
  680. int d_margin1 = 5*factor; // large margin
  681. int d_margin2 = 2*factor; // small margin
  682. int d_name_w = 70*factor;
  683. int d_name_h = 9*factor;
  684. int d_name_x = d_dialog_cx - 10*factor;
  685. int d_name_y = d_dialog_y + d_margin1 + d_txt6_h + d_txt6_h;
  686. int d_gdi_w = 30*factor;
  687. int d_gdi_h = 9*factor;
  688. int d_gdi_x = d_dialog_cx - 10*factor;
  689. int d_gdi_y = d_name_y + d_name_h + d_margin2;
  690. int d_nod_w = 30*factor;
  691. int d_nod_h = 9*factor;
  692. int d_nod_x = d_gdi_x + d_gdi_w;
  693. int d_nod_y = d_name_y + d_name_h + d_margin2;
  694. int d_color_w = 10*factor;
  695. int d_color_h = 9*factor;
  696. int d_color_y = d_nod_y + d_nod_h + d_margin2;
  697. int d_gamelist_w = 160*factor;
  698. int d_gamelist_h = 27*factor;
  699. int d_gamelist_x = d_dialog_x + d_margin1;
  700. int d_gamelist_y = d_color_y + d_color_h + d_margin1 + d_txt6_h;
  701. int d_playerlist_w = 106*factor;
  702. int d_playerlist_h = 27*factor;
  703. int d_playerlist_x = d_dialog_x + d_dialog_w - d_margin1 - d_playerlist_w;
  704. int d_playerlist_y = d_color_y + d_color_h + d_margin1 + d_txt6_h;
  705. int d_msg1_y = d_gamelist_y + d_gamelist_h + d_margin1;
  706. int d_msg2_y = d_msg1_y + d_txt6_h;
  707. int d_msg3_y = d_msg2_y + d_txt6_h;
  708. int d_msg4_y = d_msg3_y + d_txt6_h;
  709. int d_msg5_y = d_msg4_y + d_txt6_h;
  710. int d_join_w = 40*factor;
  711. int d_join_h = 9*factor;
  712. int d_join_x = d_dialog_x + (d_dialog_w / 6) - (d_join_w / 2);
  713. int d_join_y = d_msg5_y + d_txt6_h + d_margin1;
  714. #if (GERMAN | FRENCH)
  715. int d_cancel_w = 50*factor;
  716. #else
  717. int d_cancel_w = 40*factor;
  718. #endif
  719. int d_cancel_h = 9*factor;
  720. int d_cancel_x = d_dialog_cx - d_cancel_w / 2;
  721. int d_cancel_y = d_msg5_y + d_txt6_h + d_margin1;
  722. int d_new_w = 40*factor;
  723. int d_new_h = 9*factor;
  724. int d_new_x = d_dialog_x + ((d_dialog_w * 5) / 6) - (d_new_w / 2);
  725. int d_new_y = d_msg5_y + d_txt6_h + d_margin1;
  726. int d_message_w = d_dialog_w - (d_margin1 * 2);
  727. int d_message_h = 34*factor;
  728. int d_message_x = d_dialog_x + d_margin1;
  729. int d_message_y = d_cancel_y + d_cancel_h + d_margin1;
  730. int d_send_w = 80*factor;
  731. int d_send_h = 9*factor;
  732. int d_send_x = d_dialog_cx - (d_send_w / 2);
  733. int d_send_y = d_message_y + d_message_h + d_margin2;
  734. /*........................................................................
  735. Button Enumerations
  736. ........................................................................*/
  737. enum {
  738. BUTTON_NAME = 100,
  739. BUTTON_GDI,
  740. BUTTON_NOD,
  741. BUTTON_GAMELIST,
  742. BUTTON_PLAYERLIST,
  743. BUTTON_JOIN,
  744. BUTTON_CANCEL,
  745. BUTTON_NEW,
  746. BUTTON_SEND,
  747. };
  748. /*........................................................................
  749. Redraw values: in order from "top" to "bottom" layer of the dialog
  750. ........................................................................*/
  751. typedef enum {
  752. REDRAW_NONE = 0,
  753. REDRAW_MESSAGE,
  754. REDRAW_COLORS,
  755. REDRAW_BUTTONS,
  756. REDRAW_BACKGROUND,
  757. REDRAW_ALL = REDRAW_BACKGROUND
  758. } RedrawType;
  759. /*........................................................................
  760. Dialog variables
  761. ........................................................................*/
  762. RedrawType display = REDRAW_ALL; // redraw level
  763. bool process = true; // process while true
  764. KeyNumType input;
  765. int cbox_x[] = { d_gdi_x,
  766. d_gdi_x + d_color_w,
  767. d_gdi_x + (d_color_w * 2),
  768. d_gdi_x + (d_color_w * 3),
  769. d_gdi_x + (d_color_w * 4),
  770. d_gdi_x + (d_color_w * 5)};
  771. JoinStateType joinstate = JOIN_NOTHING; // current "state" of this dialog
  772. char namebuf[MPLAYER_NAME_MAX] = {0}; // buffer for player's name
  773. int tabs[] = {77*factor}; // tabs for player list box
  774. int game_index = -1; // index of currently-selected game
  775. int join_index = -1; // index of game we're joining
  776. int rc = 0; // -1 = user cancelled, 1 = New
  777. JoinEventType event; // event from incoming packet
  778. int i,j; // loop counter
  779. char txt[80];
  780. char const *p;
  781. int parms_received; // 1 = game options received
  782. int found;
  783. unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's
  784. int min_index; // for sorting player ID's
  785. unsigned char min_id; // for sorting player ID's
  786. unsigned char id; // connection ID
  787. char * item;
  788. unsigned long starttime;
  789. NodeNameType *who;
  790. int message_length;
  791. int sent_so_far;
  792. unsigned short magic_number;
  793. unsigned short crc;
  794. void const *up_button;
  795. void const *down_button;
  796. if (InMainLoop){
  797. up_button = Hires_Retrieve("BTN-UP.SHP");
  798. down_button = Hires_Retrieve("BTN-DN.SHP");
  799. }else{
  800. up_button = Hires_Retrieve("BTN-UP2.SHP");
  801. down_button = Hires_Retrieve("BTN-DN2.SHP");
  802. }
  803. /*........................................................................
  804. Buttons
  805. ........................................................................*/
  806. GadgetClass *commands; // button list
  807. EditClass name_edt (BUTTON_NAME,
  808. namebuf, MPLAYER_NAME_MAX, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  809. d_name_x, d_name_y, d_name_w, d_name_h, EditClass::ALPHANUMERIC);
  810. TextButtonClass gdibtn(BUTTON_GDI, TXT_G_D_I,
  811. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  812. d_gdi_x, d_gdi_y, d_gdi_w, d_gdi_h);
  813. TextButtonClass nodbtn(BUTTON_NOD, TXT_N_O_D,
  814. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  815. d_nod_x, d_nod_y, d_nod_w, d_nod_h);
  816. ListClass gamelist(BUTTON_GAMELIST,
  817. d_gamelist_x, d_gamelist_y, d_gamelist_w, d_gamelist_h,
  818. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  819. up_button,
  820. down_button);
  821. ColorListClass playerlist(BUTTON_PLAYERLIST,
  822. d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h,
  823. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  824. up_button,
  825. down_button);
  826. TextButtonClass joinbtn(BUTTON_JOIN, TXT_JOIN,
  827. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  828. #ifdef FRENCH
  829. d_join_x, d_join_y);
  830. #else
  831. d_join_x, d_join_y, d_join_w, d_join_h);
  832. #endif
  833. TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL,
  834. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  835. //#if (GERMAN | FRENCH)
  836. // d_cancel_x, d_cancel_y);
  837. //#else
  838. d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h);
  839. //#endif
  840. TextButtonClass newbtn(BUTTON_NEW, TXT_NEW,
  841. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  842. d_new_x, d_new_y, d_new_w, d_new_h);
  843. TextButtonClass sendbtn(BUTTON_SEND, TXT_SEND_MESSAGE,
  844. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  845. //#if (GERMAN | FRENCH)
  846. // d_send_x, d_send_y);
  847. //#else
  848. d_send_x, d_send_y, d_send_w, d_send_h);
  849. //#endif
  850. playerlist.Set_Tabs(tabs);
  851. /*
  852. ----------------------------- Various Inits ------------------------------
  853. */
  854. MPlayerColorIdx = MPlayerPrefColor; // init my preferred color
  855. strcpy (namebuf, MPlayerName); // set my name
  856. name_edt.Set_Text(namebuf,MPLAYER_NAME_MAX);
  857. name_edt.Set_Color (MPlayerTColors[MPlayerColorIdx]);
  858. playerlist.Set_Selected_Style(ColorListClass::SELECT_NONE);
  859. if (MPlayerHouse==HOUSE_GOOD) {
  860. gdibtn.Turn_On();
  861. } else {
  862. nodbtn.Turn_On();
  863. }
  864. Fancy_Text_Print("", 0, 0, CC_GREEN, TBLACK,
  865. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  866. Messages.Init (d_message_x + 2, d_message_y + 2, 4,
  867. MAX_MESSAGE_LENGTH, d_txt6_h);
  868. /*
  869. --------------------------- Send network query ---------------------------
  870. */
  871. Send_Join_Queries (game_index, 1, 0);
  872. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  873. Blit_Hid_Page_To_Seen_Buff();
  874. Set_Palette(Palette);
  875. /*
  876. ---------------------------- Init Mono Output ----------------------------
  877. */
  878. #if(SHOW_MONO)
  879. Ipx.Configure_Debug(-1, sizeof (GlobalHeaderType),
  880. sizeof(NetCommandType), GlobalPacketNames, 11);
  881. Ipx.Mono_Debug_Print(-1,1);
  882. #endif
  883. while (Get_Mouse_State() > 0) Show_Mouse();
  884. /*
  885. ---------------------------- Processing loop -----------------------------
  886. */
  887. while (process) {
  888. /*
  889. ** If we have just received input focus again after running in the background then
  890. ** we need to redraw.
  891. */
  892. if (AllSurfaces.SurfacesRestored){
  893. AllSurfaces.SurfacesRestored=FALSE;
  894. display=REDRAW_ALL;
  895. }
  896. #if(SHOW_MONO)
  897. Ipx.Mono_Debug_Print(-1,0);
  898. #endif
  899. /*
  900. ...................... Refresh display if needed ......................
  901. */
  902. if (display) {
  903. Hide_Mouse();
  904. /*
  905. .................. Redraw backgound & dialog box ...................
  906. */
  907. if (display >= REDRAW_BACKGROUND) {
  908. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  909. Blit_Hid_Page_To_Seen_Buff();
  910. Set_Palette(Palette);
  911. Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
  912. /*...............................................................
  913. Dialog & Field labels
  914. ...............................................................*/
  915. Draw_Caption (TXT_JOIN_NETWORK_GAME, d_dialog_x, d_dialog_y, d_dialog_w);
  916. Fancy_Text_Print(TXT_YOUR_NAME,
  917. d_name_x - 5, d_name_y + 1, CC_GREEN, TBLACK,
  918. TPF_RIGHT | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  919. Fancy_Text_Print(TXT_SIDE_COLON,
  920. d_gdi_x - 5, d_gdi_y + 1, CC_GREEN, TBLACK,
  921. TPF_RIGHT | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  922. Fancy_Text_Print(TXT_COLOR_COLON,
  923. cbox_x[0] - 5, d_color_y + 1, CC_GREEN, TBLACK,
  924. TPF_RIGHT | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  925. Fancy_Text_Print(TXT_GAMES,
  926. d_gamelist_x + (d_gamelist_w / 2), d_gamelist_y - d_txt6_h,
  927. CC_GREEN, TBLACK,
  928. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  929. Fancy_Text_Print(TXT_PLAYERS,
  930. d_playerlist_x + (d_playerlist_w / 2), d_playerlist_y - d_txt6_h,
  931. CC_GREEN, TBLACK,
  932. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  933. /*...............................................................
  934. Join-state-specific labels:
  935. ...............................................................*/
  936. if (joinstate > JOIN_NOTHING) {
  937. Fancy_Text_Print(namebuf, d_name_x, d_name_y + 1, CC_GREEN,
  938. TBLACK, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  939. if (MPlayerHouse==HOUSE_GOOD) {
  940. Fancy_Text_Print(TXT_G_D_I, d_gdi_x, d_gdi_y + 1, CC_GREEN,
  941. TBLACK, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  942. } else {
  943. Fancy_Text_Print(TXT_N_O_D, d_gdi_x, d_gdi_y + 1, CC_GREEN,
  944. TBLACK, TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  945. }
  946. }
  947. /*
  948. .................... Rebuild the button list ....................
  949. */
  950. cancelbtn.Zap();
  951. gamelist.Zap();
  952. playerlist.Zap();
  953. gdibtn.Zap();
  954. nodbtn.Zap();
  955. name_edt.Zap();
  956. joinbtn.Zap();
  957. newbtn.Zap();
  958. sendbtn.Zap();
  959. commands = &cancelbtn;
  960. gamelist.Add_Tail(*commands);
  961. playerlist.Add_Tail(*commands);
  962. /*...............................................................
  963. Only add the name edit field, the House, Join & New buttons if
  964. we're doing nothing, or we've just been rejected.
  965. ...............................................................*/
  966. if (joinstate <= JOIN_NOTHING) {
  967. gdibtn.Add_Tail(*commands);
  968. nodbtn.Add_Tail(*commands);
  969. name_edt.Add_Tail(*commands);
  970. joinbtn.Add_Tail(*commands);
  971. newbtn.Add_Tail(*commands);
  972. }
  973. if (joinstate == JOIN_CONFIRMED)
  974. sendbtn.Add_Tail(*commands);
  975. }
  976. /*
  977. .......................... Redraw buttons ..........................
  978. */
  979. if (display >= REDRAW_BUTTONS) {
  980. commands->Draw_All();
  981. }
  982. /*..................................................................
  983. Draw the color boxes
  984. ..................................................................*/
  985. if (display >= REDRAW_COLORS) {
  986. for (i = 0; i < MAX_MPLAYER_COLORS; i++) {
  987. LogicPage->Fill_Rect (cbox_x[i] + 1, d_color_y + 1,
  988. cbox_x[i] + 1 + d_color_w - 2, d_color_y + 1 + d_color_h - 2,
  989. MPlayerGColors[i]);
  990. if (i == MPlayerColorIdx) {
  991. Draw_Box(cbox_x[i], d_color_y, d_color_w, d_color_h,
  992. BOXSTYLE_GREEN_DOWN, false);
  993. } else {
  994. Draw_Box(cbox_x[i], d_color_y, d_color_w, d_color_h,
  995. BOXSTYLE_GREEN_RAISED, false);
  996. }
  997. }
  998. }
  999. /*..................................................................
  1000. Draw the message:
  1001. - Erase an old message first
  1002. - If we're in a game, print the game options (if they've been
  1003. received)
  1004. - If we've been rejected from a game, print that message
  1005. ..................................................................*/
  1006. if (display >= REDRAW_MESSAGE) {
  1007. Draw_Box(d_message_x, d_message_y, d_message_w, d_message_h,
  1008. BOXSTYLE_GREEN_BORDER, true);
  1009. Messages.Draw();
  1010. LogicPage->Fill_Rect( d_dialog_x + 2,
  1011. d_msg1_y,
  1012. d_dialog_x + d_dialog_w - 4,
  1013. d_msg5_y + d_txt6_h,
  1014. BLACK);
  1015. if (joinstate==JOIN_CONFIRMED && parms_received) {
  1016. /*............................................................
  1017. Scenario title
  1018. ............................................................*/
  1019. p = Text_String(TXT_SCENARIO_COLON);
  1020. if (ScenarioIdx != -1) {
  1021. sprintf(txt,"%s %s",p, MPlayerScenarios[ScenarioIdx]);
  1022. Fancy_Text_Print (txt, d_dialog_cx,
  1023. d_msg1_y, CC_GREEN, TBLACK,
  1024. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW | TPF_CENTER);
  1025. } else {
  1026. sprintf(txt,"%s %s",p,Text_String(TXT_NOT_FOUND));
  1027. Fancy_Text_Print (txt, d_dialog_cx,
  1028. d_msg1_y, CC_NOD_COLOR, TBLACK,
  1029. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW | TPF_CENTER);
  1030. }
  1031. /*............................................................
  1032. # of credits
  1033. ............................................................*/
  1034. p = Text_String(TXT_START_CREDITS_COLON);
  1035. sprintf(txt, "%s %d", p, MPlayerCredits);
  1036. Fancy_Text_Print (txt, d_dialog_cx,
  1037. d_msg2_y, CC_GREEN, TBLACK,
  1038. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW | TPF_CENTER);
  1039. /*............................................................
  1040. Count & Level values
  1041. ............................................................*/
  1042. p = Text_String(TXT_COUNT);
  1043. sprintf(txt,"%s %d",p,MPlayerUnitCount);
  1044. Fancy_Text_Print (txt,
  1045. d_dialog_x + (d_dialog_w / 4) - String_Pixel_Width(p),
  1046. d_msg3_y, CC_GREEN, TBLACK,
  1047. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1048. p = Text_String(TXT_LEVEL);
  1049. if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) {
  1050. sprintf(txt, "%s %d", p, BuildLevel);
  1051. } else {
  1052. sprintf(txt, "%s **", p);
  1053. }
  1054. Fancy_Text_Print (txt,
  1055. d_dialog_x + d_dialog_w - (d_dialog_w / 4) - String_Pixel_Width(p),
  1056. d_msg3_y, CC_GREEN, TBLACK,
  1057. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1058. /*............................................................
  1059. Bases
  1060. ............................................................*/
  1061. p = Text_String(TXT_BASES_COLON);
  1062. if (MPlayerBases) {
  1063. sprintf(txt,"%s %s",p,Text_String(TXT_ON));
  1064. } else {
  1065. sprintf(txt,"%s %s",p,Text_String(TXT_OFF));
  1066. }
  1067. Fancy_Text_Print (txt,
  1068. d_dialog_x + (d_dialog_w / 4) - String_Pixel_Width(p),
  1069. d_msg4_y, CC_GREEN, TBLACK,
  1070. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1071. /*............................................................
  1072. Tiberium
  1073. ............................................................*/
  1074. p = Text_String(TXT_TIBERIUM_COLON);
  1075. if (MPlayerTiberium) {
  1076. sprintf(txt,"%s %s",p,Text_String(TXT_ON));
  1077. } else {
  1078. sprintf(txt,"%s %s",p,Text_String(TXT_OFF));
  1079. }
  1080. Fancy_Text_Print (txt,
  1081. d_dialog_x + (d_dialog_w / 4) - String_Pixel_Width(p),
  1082. d_msg5_y, CC_GREEN, TBLACK,
  1083. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1084. /*............................................................
  1085. Goody boxes
  1086. ............................................................*/
  1087. p = Text_String(TXT_CRATES_COLON);
  1088. if (MPlayerGoodies) {
  1089. sprintf(txt,"%s %s",p,Text_String(TXT_ON));
  1090. } else {
  1091. sprintf(txt,"%s %s",p,Text_String(TXT_OFF));
  1092. }
  1093. Fancy_Text_Print (txt,
  1094. d_dialog_x + d_dialog_w - (d_dialog_w / 4) - String_Pixel_Width(p),
  1095. d_msg4_y, CC_GREEN, TBLACK,
  1096. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1097. /*............................................................
  1098. Computer AI players
  1099. ............................................................*/
  1100. if (Special.IsCaptureTheFlag) {
  1101. p = Text_String(TXT_CAPTURE_THE_FLAG_COLON);
  1102. sprintf(txt,"%s %s",p,Text_String(TXT_ON));
  1103. } else {
  1104. p = Text_String(TXT_AI_PLAYERS_COLON);
  1105. if (MPlayerGhosts) {
  1106. sprintf(txt,"%s %s",p,Text_String(TXT_ON));
  1107. } else {
  1108. sprintf(txt,"%s %s",p,Text_String(TXT_OFF));
  1109. }
  1110. }
  1111. Fancy_Text_Print (txt,
  1112. d_dialog_x + d_dialog_w - (d_dialog_w / 4) - String_Pixel_Width(p),
  1113. d_msg5_y, CC_GREEN, TBLACK,
  1114. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1115. } else {
  1116. /*...............................................................
  1117. Rejection notice
  1118. ...............................................................*/
  1119. if (joinstate==JOIN_REJECTED) {
  1120. Fancy_Text_Print(TXT_REQUEST_DENIED,
  1121. d_dialog_cx, d_msg3_y, CC_GREEN, TBLACK,
  1122. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  1123. }
  1124. }
  1125. }
  1126. Show_Mouse();
  1127. display = REDRAW_NONE;
  1128. }
  1129. /*
  1130. ........................... Get user input ............................
  1131. */
  1132. input = commands->Input();
  1133. /*
  1134. ---------------------------- Process input ----------------------------
  1135. */
  1136. switch (input) {
  1137. /*------------------------------------------------------------------
  1138. User clicks on a color button:
  1139. - If we've joined a game, don't allow a new color selection
  1140. - otherwise, select that color
  1141. ------------------------------------------------------------------*/
  1142. case KN_LMOUSE:
  1143. if (joinstate > JOIN_NOTHING)
  1144. break;
  1145. if (_Kbd->MouseQX > cbox_x[0] &&
  1146. _Kbd->MouseQX < (cbox_x[MAX_MPLAYER_COLORS - 1] + d_color_w) &&
  1147. _Kbd->MouseQY > d_color_y &&
  1148. _Kbd->MouseQY < (d_color_y + d_color_h)) {
  1149. MPlayerPrefColor = (_Kbd->MouseQX - cbox_x[0]) / d_color_w;
  1150. MPlayerColorIdx = MPlayerPrefColor;
  1151. name_edt.Set_Color (MPlayerTColors[MPlayerColorIdx]);
  1152. name_edt.Flag_To_Redraw();
  1153. display = REDRAW_COLORS;
  1154. }
  1155. break;
  1156. /*------------------------------------------------------------------
  1157. User clicks on the game list:
  1158. - If we've joined a game, don't allow the selected item to change;
  1159. otherwise:
  1160. - Clear the player list
  1161. - Send an immediate player query
  1162. ------------------------------------------------------------------*/
  1163. case (BUTTON_GAMELIST | KN_BUTTON):
  1164. if (joinstate==JOIN_CONFIRMED) {
  1165. gamelist.Set_Selected_Index(game_index);
  1166. } else {
  1167. if (gamelist.Current_Index() != game_index) {
  1168. Clear_Player_List (&playerlist);
  1169. game_index = gamelist.Current_Index();
  1170. Send_Join_Queries (game_index, 0, 1);
  1171. }
  1172. }
  1173. break;
  1174. /*------------------------------------------------------------------
  1175. House Buttons: set the player's desired House
  1176. ------------------------------------------------------------------*/
  1177. case (BUTTON_GDI | KN_BUTTON):
  1178. MPlayerHouse = HOUSE_GOOD;
  1179. gdibtn.Turn_On();
  1180. nodbtn.Turn_Off();
  1181. break;
  1182. case (BUTTON_NOD | KN_BUTTON):
  1183. MPlayerHouse = HOUSE_BAD;
  1184. gdibtn.Turn_Off();
  1185. nodbtn.Turn_On();
  1186. break;
  1187. /*------------------------------------------------------------------
  1188. JOIN: send a join request packet & switch to waiting-for-confirmation
  1189. mode. (Request_To_Join fills in MPlayerName with my namebuf.)
  1190. ------------------------------------------------------------------*/
  1191. case (BUTTON_JOIN | KN_BUTTON):
  1192. name_edt.Clear_Focus();
  1193. name_edt.Flag_To_Redraw();
  1194. join_index = gamelist.Current_Index();
  1195. parms_received = 0;
  1196. if (Request_To_Join (namebuf, join_index, &playerlist, MPlayerHouse,
  1197. MPlayerColorIdx)) {
  1198. joinstate = JOIN_WAIT_CONFIRM;
  1199. } else {
  1200. display = REDRAW_ALL;
  1201. }
  1202. break;
  1203. /*------------------------------------------------------------------
  1204. CANCEL: send a SIGN_OFF
  1205. - If we're part of a game, stay in this dialog; otherwise, exit
  1206. ------------------------------------------------------------------*/
  1207. case (KN_ESC):
  1208. if (Messages.Get_Edit_Buf() != NULL) {
  1209. Messages.Input(input);
  1210. display = REDRAW_MESSAGE;
  1211. break;
  1212. }
  1213. case (BUTTON_CANCEL | KN_BUTTON):
  1214. memset (&GPacket, 0, sizeof(GlobalPacketType));
  1215. GPacket.Command = NET_SIGN_OFF;
  1216. strcpy(GPacket.Name,MPlayerName);
  1217. /*...............................................................
  1218. If we're joined to a game, make extra sure the other players in
  1219. that game know I'm exiting; send my SIGN_OFF as an ack-required
  1220. packet. Do not send this packet to myself (index 0).
  1221. ...............................................................*/
  1222. if (joinstate == JOIN_CONFIRMED) {
  1223. //
  1224. // Remove myself from the player list box
  1225. //
  1226. if (playerlist.Count()) { // added: BRR 6/14/96
  1227. item = (char *)(playerlist.Get_Item(0));
  1228. playerlist.Remove_Item(item);
  1229. delete [] item;
  1230. playerlist.Flag_To_Redraw();
  1231. }
  1232. //
  1233. // Remove myself from the Players list
  1234. //
  1235. if (Players.Count()) { // added: BRR 6/14/96
  1236. who = Players[0];
  1237. Players.Delete(0);
  1238. delete who;
  1239. }
  1240. for (i = 0; i < Players.Count(); i++) {
  1241. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  1242. &(Players[i]->Address));
  1243. Ipx.Service();
  1244. }
  1245. }
  1246. /*...............................................................
  1247. Now broadcast my SIGN_OFF so other players looking at this game
  1248. know I'm leaving.
  1249. ...............................................................*/
  1250. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  1251. 0, NULL);
  1252. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  1253. 0, NULL);
  1254. if (IsBridge) {
  1255. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  1256. &BridgeNet);
  1257. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  1258. &BridgeNet);
  1259. }
  1260. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  1261. if (joinstate != JOIN_CONFIRMED) {
  1262. process = false;
  1263. rc = -1;
  1264. } else {
  1265. MPlayerGameName[0] = 0;
  1266. joinstate = JOIN_NOTHING;
  1267. display = REDRAW_ALL;
  1268. }
  1269. break;
  1270. /*------------------------------------------------------------------
  1271. NEW: bail out with return code 1
  1272. ------------------------------------------------------------------*/
  1273. case (BUTTON_NEW | KN_BUTTON):
  1274. /*
  1275. .................. Force user to enter a name ...................
  1276. */
  1277. if (strlen(namebuf)==0) {
  1278. CCMessageBox().Process(TXT_NAME_ERROR);
  1279. display = REDRAW_ALL;
  1280. break;
  1281. }
  1282. /*
  1283. ..................... Ensure name is unique .....................
  1284. */
  1285. found = 0;
  1286. for (i = 0; i < Games.Count(); i++) {
  1287. if (!stricmp(Games[i]->Name, namebuf)) {
  1288. found = 1;
  1289. CCMessageBox().Process (TXT_GAMENAME_MUSTBE_UNIQUE);
  1290. display = REDRAW_ALL;
  1291. break;
  1292. }
  1293. }
  1294. if (found)
  1295. break;
  1296. /*
  1297. .................... Save player & game name ....................
  1298. */
  1299. strcpy(MPlayerName,namebuf);
  1300. strcpy(MPlayerGameName,namebuf);
  1301. name_edt.Clear_Focus();
  1302. name_edt.Flag_To_Redraw();
  1303. rc = 1;
  1304. process = false;
  1305. break;
  1306. /*------------------------------------------------------------------
  1307. Default: manage the inter-player messages
  1308. ------------------------------------------------------------------*/
  1309. default:
  1310. /*...............................................................
  1311. F4/SEND/'M' = edit a message
  1312. ...............................................................*/
  1313. if (Messages.Get_Edit_Buf()==NULL) {
  1314. if ( (input == KN_M && joinstate==JOIN_CONFIRMED) ||
  1315. input==(BUTTON_SEND | KN_BUTTON) || input == KN_F4) {
  1316. memset (txt, 0, 80);
  1317. strcpy(txt,Text_String(TXT_TO_ALL)); // "To All:"
  1318. Messages.Add_Edit (MPlayerTColors[MPlayerColorIdx],
  1319. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, d_message_w-70*factor);
  1320. if (joinstate <= JOIN_NOTHING) {
  1321. name_edt.Clear_Focus();
  1322. name_edt.Flag_To_Redraw();
  1323. }
  1324. display = REDRAW_MESSAGE;
  1325. break;
  1326. }
  1327. } else
  1328. /*...............................................................
  1329. If we're already editing a message and the user clicks on
  1330. 'Send', translate our input to a Return so Messages.Input() will
  1331. work properly.
  1332. ...............................................................*/
  1333. if (input==(BUTTON_SEND | KN_BUTTON)) {
  1334. input = KN_RETURN;
  1335. }
  1336. /*...............................................................
  1337. Manage the message system (get rid of old messages)
  1338. ...............................................................*/
  1339. if (Messages.Manage()) {
  1340. display = REDRAW_MESSAGE;
  1341. }
  1342. /*...............................................................
  1343. Service keyboard input for any message being edited.
  1344. ...............................................................*/
  1345. i = Messages.Input(input);
  1346. /*...............................................................
  1347. If 'Input' returned 1, it means refresh the message display.
  1348. ...............................................................*/
  1349. if (i==1) {
  1350. Messages.Draw();
  1351. } else {
  1352. /*...............................................................
  1353. If 'Input' returned 2, it means redraw the message display.
  1354. ...............................................................*/
  1355. if (i==2) {
  1356. display = REDRAW_MESSAGE;
  1357. } else {
  1358. /*...............................................................
  1359. If 'input' returned 3, it means send the current message.
  1360. ...............................................................*/
  1361. if (i==3) {
  1362. long actual_message_size;
  1363. char *the_string;
  1364. sent_so_far = 0;
  1365. magic_number = MESSAGE_HEAD_MAGIC_NUMBER;
  1366. message_length = strlen(Messages.Get_Edit_Buf());
  1367. crc = (unsigned short)
  1368. (Calculate_CRC(Messages.Get_Edit_Buf(),message_length) &0xffff);
  1369. while ( sent_so_far < message_length ){
  1370. GPacket.Command = NET_MESSAGE;
  1371. strcpy (GPacket.Name, namebuf);
  1372. memcpy (GPacket.Message.Buf, Messages.Get_Edit_Buf()+sent_so_far, COMPAT_MESSAGE_LENGTH-5);
  1373. /*
  1374. ** Steve I's stuff for splitting message on word boundries
  1375. */
  1376. actual_message_size = COMPAT_MESSAGE_LENGTH - 5;
  1377. /* Start at the end of the message and find a space with 10 chars. */
  1378. the_string = GPacket.Message.Buf;
  1379. while ( (COMPAT_MESSAGE_LENGTH -5) -actual_message_size < 10 &&
  1380. the_string[actual_message_size] != ' '){
  1381. --actual_message_size;
  1382. }
  1383. if ( the_string[actual_message_size] == ' ' ){
  1384. /* Now delete the extra characters after the space (they musnt print) */
  1385. for ( int i=0 ; i< (COMPAT_MESSAGE_LENGTH-5) - actual_message_size; i++ ){
  1386. the_string[i + actual_message_size] = 0; //0xff; ST - 12/18/2018 11:36AM
  1387. }
  1388. }else{
  1389. actual_message_size = COMPAT_MESSAGE_LENGTH - 5;
  1390. }
  1391. *(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-5) = 0;
  1392. *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4)) = magic_number;
  1393. *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2)) = crc;
  1394. GPacket.Message.ID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse);
  1395. GPacket.Message.NameCRC = Compute_Name_CRC(MPlayerGameName);
  1396. /*..................................................................
  1397. Send the message to every player in our player list. The local
  1398. system will also receive this message, since it's in the Player list.
  1399. ..................................................................*/
  1400. if (joinstate == JOIN_CONFIRMED) {
  1401. for (i = 1; i < Players.Count(); i++) {
  1402. Ipx.Send_Global_Message (&GPacket,
  1403. sizeof(GlobalPacketType), 1, &(Players[i]->Address));
  1404. Ipx.Service();
  1405. }
  1406. sprintf(txt,Text_String (TXT_FROM), MPlayerName, GPacket.Message.Buf);
  1407. Messages.Add_Message (txt,
  1408. MPlayerTColors[MPlayerColorIdx],
  1409. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 600, magic_number, crc);
  1410. }
  1411. else {
  1412. for (i = 0; i < Players.Count(); i++) {
  1413. Ipx.Send_Global_Message (&GPacket,
  1414. sizeof(GlobalPacketType), 1, &(Players[i]->Address));
  1415. Ipx.Service();
  1416. }
  1417. }
  1418. magic_number++;
  1419. sent_so_far += actual_message_size; //COMPAT_MESSAGE_LENGTH-5;
  1420. }
  1421. }
  1422. }
  1423. }
  1424. break;
  1425. }
  1426. /*---------------------------------------------------------------------
  1427. Resend our query packets
  1428. ---------------------------------------------------------------------*/
  1429. Send_Join_Queries(game_index, 0, 0);
  1430. /*---------------------------------------------------------------------
  1431. Process incoming packets
  1432. ---------------------------------------------------------------------*/
  1433. event = Get_Join_Responses(&joinstate, &gamelist, &playerlist,
  1434. join_index);
  1435. /*.....................................................................
  1436. If we've changed state, redraw everything; if we're starting the game,
  1437. break out of the loop. If we've just joined, send out a player query
  1438. so I'll get added to the list instantly.
  1439. .....................................................................*/
  1440. if (event == EV_STATE_CHANGE) {
  1441. display = REDRAW_ALL;
  1442. if (joinstate==JOIN_GAME_START) {
  1443. rc = 0;
  1444. process = false;
  1445. } else {
  1446. /*..................................................................
  1447. If we're newly-confirmed, immediately send out a player query
  1448. ..................................................................*/
  1449. if (joinstate==JOIN_CONFIRMED) {
  1450. Clear_Player_List(&playerlist);
  1451. item = new char [MPLAYER_NAME_MAX + 4];
  1452. if (MPlayerHouse==HOUSE_GOOD) {
  1453. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I));
  1454. } else {
  1455. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D));
  1456. }
  1457. playerlist.Add_Item (item, MPlayerTColors[MPlayerColorIdx]);
  1458. who = new NodeNameType;
  1459. strcpy(who->Name, MPlayerName);
  1460. who->Address = IPXAddressClass();
  1461. who->Player.House = MPlayerHouse;
  1462. who->Player.Color = MPlayerColorIdx;
  1463. Players.Add (who);
  1464. Send_Join_Queries (game_index, 0, 1);
  1465. } else {
  1466. /*..................................................................
  1467. If we've been rejected, clear any messages we may have been typing.
  1468. ..................................................................*/
  1469. if (joinstate==JOIN_REJECTED) {
  1470. //
  1471. // Remove myself from the player list box
  1472. //
  1473. if (playerlist.Count()) { // added: BRR 6/14/96
  1474. item = (char *)(playerlist.Get_Item(0));
  1475. if (item){
  1476. playerlist.Remove_Item(item);
  1477. delete [] item;
  1478. playerlist.Flag_To_Redraw();
  1479. }
  1480. }
  1481. //
  1482. // Remove myself from the Players list
  1483. //
  1484. if (Players.Count()){
  1485. who = Players[0];
  1486. Players.Delete(0);
  1487. delete who;
  1488. }
  1489. Messages.Init (d_message_x + 2, d_message_y + 2, 4,
  1490. MAX_MESSAGE_LENGTH, d_txt6_h);
  1491. }
  1492. }
  1493. }
  1494. } else
  1495. /*.....................................................................
  1496. If a new game is detected, and it's the first game on our list,
  1497. automatically send out a player query for that game.
  1498. .....................................................................*/
  1499. if (event == EV_NEW_GAME && gamelist.Count()==1) {
  1500. gamelist.Set_Selected_Index(0);
  1501. game_index = gamelist.Current_Index();
  1502. Send_Join_Queries (game_index, 0, 1);
  1503. } else
  1504. /*.....................................................................
  1505. If the game options have changed, print them.
  1506. .....................................................................*/
  1507. if (event == EV_GAME_OPTIONS) {
  1508. parms_received = 1;
  1509. display = REDRAW_MESSAGE;
  1510. } else
  1511. /*.....................................................................
  1512. Draw an incoming message
  1513. .....................................................................*/
  1514. if (event == EV_MESSAGE) {
  1515. display = REDRAW_MESSAGE;
  1516. } else
  1517. /*.....................................................................
  1518. A game before the one I've selected is gone, so we have a new index now.
  1519. 'game_index' must be kept set to the currently-selected list item, so
  1520. we send out queries for the currently-selected game. It's therefore
  1521. imperative that we detect any changes to the game list.
  1522. If we're joined in a game, we must decrement our game_index to keep
  1523. it aligned with the game we're joined to.
  1524. .....................................................................*/
  1525. if (event == EV_GAME_SIGNOFF) {
  1526. if (joinstate==JOIN_CONFIRMED) {
  1527. game_index--;
  1528. join_index--;
  1529. gamelist.Set_Selected_Index(join_index);
  1530. } else {
  1531. gamelist.Flag_To_Redraw();
  1532. Clear_Player_List(&playerlist);
  1533. game_index = gamelist.Current_Index();
  1534. Send_Join_Queries (game_index, 0, 1);
  1535. }
  1536. }
  1537. /*---------------------------------------------------------------------
  1538. Service the Ipx connections
  1539. ---------------------------------------------------------------------*/
  1540. Ipx.Service();
  1541. /*---------------------------------------------------------------------
  1542. Clean out the Game List; if an old entry is found:
  1543. - Remove it
  1544. - Clear the player list
  1545. - Send queries for the new selected game, if there is one
  1546. ---------------------------------------------------------------------*/
  1547. for (i = 0; i < Games.Count(); i++) {
  1548. if (TickCount.Time() - Games[i]->Game.LastTime > 400) {
  1549. Games.Delete(Games[i]);
  1550. item = (char *)(gamelist.Get_Item (i));
  1551. gamelist.Remove_Item (item);
  1552. delete [] item;
  1553. if (i <= game_index) {
  1554. gamelist.Flag_To_Redraw();
  1555. Clear_Player_List(&playerlist);
  1556. game_index = gamelist.Current_Index();
  1557. Send_Join_Queries (game_index, 0, 1);
  1558. }
  1559. }
  1560. }
  1561. /*---------------------------------------------------------------------
  1562. Service the sounds & score; GameActive must be false at this point,
  1563. so Call_Back() doesn't intercept global messages from me!
  1564. ---------------------------------------------------------------------*/
  1565. Call_Back();
  1566. }
  1567. /*------------------------------------------------------------------------
  1568. Establish connections with all other players.
  1569. ------------------------------------------------------------------------*/
  1570. if (rc == 0) {
  1571. /*.....................................................................
  1572. If the other guys are playing a scenario I don't have (sniff), I can't
  1573. play. Try to bail gracefully.
  1574. .....................................................................*/
  1575. if (ScenarioIdx==-1) {
  1576. CCMessageBox().Process (TXT_UNABLE_PLAY_WAAUGH);
  1577. //
  1578. // Remove myself from the player list box
  1579. //
  1580. if (playerlist.Count()) { // added: BRR 6/14/96
  1581. item = (char *)(playerlist.Get_Item(0));
  1582. playerlist.Remove_Item(item);
  1583. delete [] item;
  1584. playerlist.Flag_To_Redraw();
  1585. }
  1586. //
  1587. // Remove myself from the Players list
  1588. //
  1589. if (Players.Count()) { // added: BRR 6/14/96
  1590. who = Players[0];
  1591. Players.Delete(0);
  1592. delete who;
  1593. }
  1594. memset (&GPacket, 0, sizeof(GlobalPacketType));
  1595. GPacket.Command = NET_SIGN_OFF;
  1596. strcpy (GPacket.Name, MPlayerName);
  1597. for (i = 0; i < Players.Count(); i++) {
  1598. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  1599. &(Players[i]->Address));
  1600. Ipx.Service();
  1601. }
  1602. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  1603. 0, NULL);
  1604. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  1605. 0, NULL);
  1606. if (IsBridge) {
  1607. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  1608. &BridgeNet);
  1609. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  1610. &BridgeNet);
  1611. }
  1612. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  1613. rc = -1;
  1614. } else {
  1615. /*..................................................................
  1616. Set the number of players in this game, and my ID
  1617. ..................................................................*/
  1618. MPlayerCount = Players.Count();
  1619. MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse);
  1620. /*..................................................................
  1621. Get the scenario number
  1622. ..................................................................*/
  1623. Scenario = MPlayerFilenum[ScenarioIdx];
  1624. /*..................................................................
  1625. Form connections with all other players. Form the IPX Connection ID
  1626. from the player's Color and House. This will let us extract any
  1627. player's color & house at any time. Fill in 'tmp_id' while we're
  1628. doing this.
  1629. ..................................................................*/
  1630. for (i = 0; i < Players.Count(); i++) {
  1631. /*...............................................................
  1632. Only create the connection if it's not myself!
  1633. ...............................................................*/
  1634. if (strcmp (MPlayerName, Players[i]->Name)) {
  1635. id = Build_MPlayerID(Players[i]->Player.Color,
  1636. Players[i]->Player.House);
  1637. tmp_id[i] = id;
  1638. Ipx.Create_Connection((int)id, Players[i]->Name, &(Players[i]->Address) );
  1639. } else {
  1640. tmp_id[i] = MPlayerLocalID;
  1641. }
  1642. }
  1643. /*..................................................................
  1644. Store every player's ID in the MPlayerID[] array. This array will
  1645. determine the order of event execution, so the ID's must be stored
  1646. in the same order on all systems.
  1647. ..................................................................*/
  1648. for (i = 0; i < MPlayerCount; i++) {
  1649. min_index = 0;
  1650. min_id = 0xff;
  1651. for (j = 0; j < MPlayerCount; j++) {
  1652. if (tmp_id[j] < min_id) {
  1653. min_id = tmp_id[j];
  1654. min_index = j;
  1655. }
  1656. }
  1657. MPlayerID[i] = tmp_id[min_index];
  1658. tmp_id[min_index] = 0xff;
  1659. }
  1660. /*..................................................................
  1661. Fill in the array of player names, including my own.
  1662. ..................................................................*/
  1663. for (i = 0; i < MPlayerCount; i++) {
  1664. if (MPlayerID[i] == MPlayerLocalID) {
  1665. strcpy (MPlayerNames[i], MPlayerName);
  1666. } else {
  1667. strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i]));
  1668. }
  1669. }
  1670. }
  1671. /*---------------------------------------------------------------------
  1672. Wait a while, polling the IPX service routines, to give our ACK
  1673. a chance to get to the other system. If he doesn't get our ACK, he'll
  1674. be waiting the whole time we load MIX files.
  1675. ---------------------------------------------------------------------*/
  1676. i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)60);
  1677. starttime = TickCount.Time();
  1678. while (TickCount.Time() - starttime < (unsigned)i) {
  1679. Ipx.Service();
  1680. }
  1681. }
  1682. /*------------------------------------------------------------------------
  1683. Init network timing values, using previous response times as a measure
  1684. of what our retry delta & timeout should be.
  1685. ------------------------------------------------------------------------*/
  1686. Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1,
  1687. Ipx.Global_Response_Time() * 4);
  1688. /*------------------------------------------------------------------------
  1689. Clear all lists
  1690. ------------------------------------------------------------------------*/
  1691. Clear_Game_List(&gamelist);
  1692. Clear_Player_List(&playerlist);
  1693. /*------------------------------------------------------------------------
  1694. Restore screen
  1695. ------------------------------------------------------------------------*/
  1696. Hide_Mouse();
  1697. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  1698. Blit_Hid_Page_To_Seen_Buff();
  1699. Show_Mouse();
  1700. return(rc);
  1701. }
  1702. /***************************************************************************
  1703. * Clear_Game_List -- Clears the game-name listbox & 'Games' Vector *
  1704. * *
  1705. * Assumes each entry in 'Games' & the list box have been allocated *
  1706. * separately. *
  1707. * *
  1708. * INPUT: *
  1709. * gamelist ptr to list box *
  1710. * *
  1711. * OUTPUT: *
  1712. * none *
  1713. * *
  1714. * WARNINGS: *
  1715. * none *
  1716. * *
  1717. * HISTORY: *
  1718. *=========================================================================*/
  1719. static void Clear_Game_List (ListClass *gamelist)
  1720. {
  1721. char * item;
  1722. int i;
  1723. /*------------------------------------------------------------------------
  1724. Clear the list box
  1725. ------------------------------------------------------------------------*/
  1726. while (gamelist->Count()) {
  1727. item = (char *)(gamelist->Get_Item (0));
  1728. gamelist->Remove_Item(item);
  1729. delete [] item;
  1730. }
  1731. gamelist->Flag_To_Redraw();
  1732. /*------------------------------------------------------------------------
  1733. Clear the 'Games' Vector
  1734. ------------------------------------------------------------------------*/
  1735. for (i = 0; i < Games.Count(); i++)
  1736. delete Games[i];
  1737. Games.Clear();
  1738. } /* end of Clear_Game_List */
  1739. /***************************************************************************
  1740. * Clear_Player_List -- Clears the player-name listbox & Vector *
  1741. * *
  1742. * Assumes each entry in 'Players' & the list box have been allocated *
  1743. * separately. *
  1744. * *
  1745. * INPUT: *
  1746. * playerlist ptr to list box *
  1747. * *
  1748. * OUTPUT: *
  1749. * none *
  1750. * *
  1751. * WARNINGS: *
  1752. * none *
  1753. * *
  1754. * HISTORY: *
  1755. *=========================================================================*/
  1756. static void Clear_Player_List (ListClass *playerlist)
  1757. {
  1758. char * item;
  1759. int i;
  1760. /*------------------------------------------------------------------------
  1761. Clear the list box
  1762. ------------------------------------------------------------------------*/
  1763. while (playerlist->Count()) {
  1764. item = (char *)(playerlist->Get_Item(0));
  1765. playerlist->Remove_Item(item);
  1766. delete [] item;
  1767. }
  1768. playerlist->Flag_To_Redraw();
  1769. /*------------------------------------------------------------------------
  1770. Clear the 'Players' Vector
  1771. ------------------------------------------------------------------------*/
  1772. for (i = 0; i < Players.Count(); i++)
  1773. delete Players[i];
  1774. Players.Clear();
  1775. } /* end of Clear_Player_List */
  1776. /***************************************************************************
  1777. * Request_To_Join -- Sends a JOIN request packet to game owner *
  1778. * *
  1779. * Regardless of the return code, the Join Dialog will need to be redrawn *
  1780. * after calling this routine. *
  1781. * *
  1782. * INPUT: *
  1783. * playername player's name *
  1784. * join_index index of game we're joining *
  1785. * playerlist listbox containing other players' names *
  1786. * house requested house *
  1787. * color requested color *
  1788. * *
  1789. * OUTPUT: *
  1790. * 1 = Packet sent, 0 = wasn't *
  1791. * *
  1792. * WARNINGS: *
  1793. * none. *
  1794. * *
  1795. * HISTORY: *
  1796. *=========================================================================*/
  1797. static int Request_To_Join (char *playername, int join_index, ListClass *playerlist,
  1798. HousesType house, int color)
  1799. {
  1800. int i;
  1801. playerlist = playerlist; // shaddup, Mr stupid compiler!
  1802. /*
  1803. --------------------------- Validate join_index --------------------------
  1804. */
  1805. if ( (Games.Count()==0) || join_index > Games.Count() || join_index < 0) {
  1806. CCMessageBox().Process (TXT_NOTHING_TO_JOIN);
  1807. return(false);
  1808. }
  1809. /*
  1810. ----------------------- Force user to enter a name -----------------------
  1811. */
  1812. if (strlen(playername)==0) {
  1813. CCMessageBox().Process (TXT_NAME_ERROR);
  1814. return(false);
  1815. }
  1816. /*
  1817. ------------------------- The game must be open --------------------------
  1818. */
  1819. if (!Games[join_index]->Game.IsOpen) {
  1820. CCMessageBox().Process(TXT_GAME_IS_CLOSED);
  1821. return (false);
  1822. }
  1823. /*
  1824. ------------------------ Make sure name is unique ------------------------
  1825. */
  1826. for (i = 0; i < Players.Count(); i++) {
  1827. if (!stricmp(playername, Players[i]->Name)) {
  1828. CCMessageBox().Process (TXT_NAME_MUSTBE_UNIQUE);
  1829. return(false);
  1830. }
  1831. }
  1832. /*
  1833. ----------------------------- Check version #'s --------------------------
  1834. */
  1835. int v;
  1836. #ifdef PATCH
  1837. if (IsV107) {
  1838. v = 1;
  1839. } else {
  1840. v = 2;
  1841. }
  1842. #else
  1843. v = Version_Number();
  1844. #endif
  1845. if (Games[join_index]->Game.Version > v) {
  1846. CCMessageBox().Process (TXT_YOURGAME_OUTDATED);
  1847. return(false);
  1848. } else {
  1849. if (Games[join_index]->Game.Version < v) {
  1850. CCMessageBox().Process (TXT_DESTGAME_OUTDATED);
  1851. return(false);
  1852. }
  1853. }
  1854. /*
  1855. ----------------------------- Save game name -----------------------------
  1856. */
  1857. strcpy (MPlayerName,playername);
  1858. /*
  1859. ----------------------- Send packet to game's owner ----------------------
  1860. */
  1861. memset (&GPacket, 0, sizeof(GlobalPacketType));
  1862. GPacket.Command = NET_QUERY_JOIN;
  1863. strcpy (GPacket.Name, MPlayerName);
  1864. GPacket.PlayerInfo.House = house;
  1865. GPacket.PlayerInfo.Color = color;
  1866. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  1867. &(Games[join_index]->Address));
  1868. return(true);
  1869. }
  1870. /***********************************************************************************************
  1871. * Send_Join_Queries -- sends queries for the Join Dialog *
  1872. * *
  1873. * This routine [re]sends the queries related to the Join Dialog: *
  1874. * - NET_QUERY_GAME *
  1875. * - NET_QUERY_PLAYER for the game currently selected (if there is one) *
  1876. * *
  1877. * The queries are "staggered" in time so they aren't all sent at once; otherwise, we'd *
  1878. * be inundated with reply packets & we'd miss some (even though the replies will require *
  1879. * ACK's). *
  1880. * *
  1881. * INPUT: *
  1882. * curgame index of currently-selected game; -1 = none *
  1883. * gamenow if 1, will immediately send the game query *
  1884. * playernow if 1, will immediately send the player query for currently-selected game *
  1885. * *
  1886. * OUTPUT: *
  1887. * none. *
  1888. * *
  1889. * WARNINGS: *
  1890. * none. *
  1891. * *
  1892. * HISTORY: *
  1893. * 02/14/1995 BR : Created. *
  1894. * 04/15/1995 BRR : Created. *
  1895. *=============================================================================================*/
  1896. static void Send_Join_Queries(int curgame, int gamenow, int playernow)
  1897. {
  1898. static int lasttime1 = 0; // time since last Game query sent out
  1899. static int lasttime2 = 0; // time since last Player query sent out
  1900. /*------------------------------------------------------------------------
  1901. Send the game-name query if the time has expired, or we're told to do
  1902. it right now
  1903. ------------------------------------------------------------------------*/
  1904. if ( (TickCount.Time() - lasttime1 > 120) || gamenow) {
  1905. lasttime1 = TickCount.Time();
  1906. memset (&GPacket, 0, sizeof(GlobalPacketType));
  1907. GPacket.Command = NET_QUERY_GAME;
  1908. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, NULL);
  1909. /*.....................................................................
  1910. If the user specified a remote server address, broadcast over that
  1911. network, too.
  1912. .....................................................................*/
  1913. if (IsBridge)
  1914. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  1915. &BridgeNet);
  1916. }
  1917. /*------------------------------------------------------------------------
  1918. Send the player query for the game currently clicked on, if the time has
  1919. expired and there is a currently-selected game, or we're told to do it
  1920. right now
  1921. ------------------------------------------------------------------------*/
  1922. if ( (curgame != -1) && curgame < Games.Count() &&
  1923. ((TickCount.Time() - lasttime2 > 35) || playernow) ) {
  1924. lasttime2 = TickCount.Time();
  1925. memset (&GPacket, 0, sizeof(GlobalPacketType));
  1926. GPacket.Command = NET_QUERY_PLAYER;
  1927. strcpy (GPacket.Name, Games[curgame]->Name);
  1928. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0, NULL);
  1929. /*.....................................................................
  1930. If the user specified a remote server address, broadcast over that
  1931. network, too.
  1932. .....................................................................*/
  1933. if (IsBridge)
  1934. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  1935. &BridgeNet);
  1936. }
  1937. } /* end of Send_Join_Queries */
  1938. /***********************************************************************************************
  1939. * Get_Join_Responses -- sends queries for the Join Dialog *
  1940. * *
  1941. * This routine polls the Global Channel to see if there are any incoming packets; *
  1942. * if so, it processes them. This routine can change the state of the Join Dialog, or *
  1943. * the contents of the list boxes, based on what the packet is. *
  1944. * *
  1945. * The list boxes are passed in as pointers; they can't be made globals, because they *
  1946. * can't be constructed, because they require shape pointers to the arrow buttons, and *
  1947. * the mix files won't have been initialized when the global variables' constructors are *
  1948. * called. *
  1949. * *
  1950. * This routine sets the globals *
  1951. * MPlayerHouse (from NET_CONFIRM_JOIN) *
  1952. * MPlayerColorIdx (from NET_CONFIRM_JOIN) *
  1953. * MPlayerBases (from NET_GAME_OPTIONS) *
  1954. * MPlayerTiberium (from NET_GAME_OPTIONS) *
  1955. * MPlayerGoodies (from NET_GAME_OPTIONS) *
  1956. * MPlayerGhosts (from NET_GAME_OPTIONS) *
  1957. * ScenarioIdx (from NET_GAME_OPTIONS; -1 = scenario not found) *
  1958. * *
  1959. * INPUT: *
  1960. * joinstate current state of Join Dialog *
  1961. * gamelist list box containing game names *
  1962. * playerlist list box containing player names for the currently-selected game *
  1963. * join_index index of the game we've joined or are asking to join *
  1964. * *
  1965. * OUTPUT: *
  1966. * Event that occurred *
  1967. * *
  1968. * WARNINGS: *
  1969. * none. *
  1970. * *
  1971. * HISTORY: *
  1972. * 02/14/1995 BR : Created. *
  1973. * 04/15/1995 BRR : Created. *
  1974. *=============================================================================================*/
  1975. static JoinEventType Get_Join_Responses(JoinStateType *joinstate, ListClass *gamelist,
  1976. ColorListClass *playerlist, int join_index)
  1977. {
  1978. int rc;
  1979. char * item; // general-purpose string
  1980. NodeNameType *who; // node to add to Games or Players
  1981. int i;
  1982. int found;
  1983. JoinEventType retcode = EV_NONE;
  1984. char txt[80];
  1985. int color;
  1986. unsigned short magic_number;
  1987. unsigned short crc;
  1988. /*------------------------------------------------------------------------
  1989. If there is no incoming packet, just return
  1990. ------------------------------------------------------------------------*/
  1991. rc = Ipx.Get_Global_Message (&GPacket, &GPacketlen, &GAddress, &GProductID);
  1992. if (!rc || GProductID != IPXGlobalConnClass::COMMAND_AND_CONQUER)
  1993. return(EV_NONE);
  1994. /*------------------------------------------------------------------------
  1995. If we're joined in a game, handle the packet in a standard way; otherwise,
  1996. don't answer standard queries.
  1997. ------------------------------------------------------------------------*/
  1998. if ( (*joinstate)==JOIN_CONFIRMED &&
  1999. Process_Global_Packet(&GPacket,&GAddress)!=0)
  2000. return(EV_NONE);
  2001. /*------------------------------------------------------------------------
  2002. NET_ANSWER_GAME: Another system is answering our GAME query, so add that
  2003. system to our list box if it's new.
  2004. ------------------------------------------------------------------------*/
  2005. if (GPacket.Command==NET_ANSWER_GAME) {
  2006. /*.....................................................................
  2007. See if this name is unique
  2008. .....................................................................*/
  2009. retcode = EV_NONE;
  2010. found = 0;
  2011. for (i = 0; i < Games.Count(); i++) {
  2012. if (!strcmp(Games[i]->Name, GPacket.Name)) {
  2013. found = 1;
  2014. /*...............................................................
  2015. If name was found, update the node's time stamp & IsOpen flag.
  2016. ...............................................................*/
  2017. Games[i]->Game.LastTime = TickCount.Time();
  2018. if (Games[i]->Game.IsOpen != GPacket.GameInfo.IsOpen) {
  2019. item = (char *)gamelist->Get_Item(i);
  2020. if (GPacket.GameInfo.IsOpen) {
  2021. sprintf(item,Text_String(TXT_THATGUYS_GAME),GPacket.Name);
  2022. } else {
  2023. sprintf(item,Text_String(TXT_THATGUYS_GAME_BRACKET),GPacket.Name);
  2024. }
  2025. Games[i]->Game.IsOpen = GPacket.GameInfo.IsOpen;
  2026. gamelist->Flag_To_Redraw();
  2027. /*............................................................
  2028. If this game has gone from closed to open, copy the responder's
  2029. address into our Game slot, since the guy responding to this
  2030. must be game owner.
  2031. ............................................................*/
  2032. if (Games[i]->Game.IsOpen)
  2033. Games[i]->Address = GAddress;
  2034. }
  2035. break;
  2036. }
  2037. }
  2038. /*.....................................................................
  2039. name not found (or addresses are different); add it to 'Games'
  2040. .....................................................................*/
  2041. if (found==0) {
  2042. /*..................................................................
  2043. Create a new node structure, fill it in, add it to 'Games'
  2044. ..................................................................*/
  2045. who = new NodeNameType;
  2046. strcpy(who->Name, GPacket.Name);
  2047. who->Address = GAddress;
  2048. who->Game.Version = GPacket.GameInfo.Version;
  2049. who->Game.IsOpen = GPacket.GameInfo.IsOpen;
  2050. who->Game.LastTime = TickCount.Time();
  2051. Games.Add (who);
  2052. /*..................................................................
  2053. Create a string for "xxx's Game", leaving room for brackets around
  2054. the string if it's a closed game
  2055. ..................................................................*/
  2056. item = new char [MPLAYER_NAME_MAX + 9];
  2057. if (GPacket.GameInfo.IsOpen) {
  2058. sprintf(item,Text_String(TXT_THATGUYS_GAME),GPacket.Name);
  2059. } else {
  2060. sprintf(item,Text_String(TXT_THATGUYS_GAME_BRACKET),GPacket.Name);
  2061. }
  2062. gamelist->Add_Item(item);
  2063. retcode = EV_NEW_GAME;
  2064. }
  2065. }
  2066. /*------------------------------------------------------------------------
  2067. NET_ANSWER_PLAYER: Another system is answering our PLAYER query, so add it
  2068. to our player list box & the Player Vector if it's new
  2069. ------------------------------------------------------------------------*/
  2070. else if (GPacket.Command==NET_ANSWER_PLAYER) {
  2071. /*.....................................................................
  2072. See if this name is unique
  2073. .....................................................................*/
  2074. retcode = EV_NONE;
  2075. found = 0;
  2076. for (i = 0; i < Players.Count(); i++) {
  2077. /*..................................................................
  2078. If the address is already present, re-copy their name, color &
  2079. house into the existing entry, in case they've changed it without
  2080. our knowledge; set the 'found' flag so we won't create a new entry.
  2081. ..................................................................*/
  2082. if (Players[i]->Address==GAddress) {
  2083. strcpy(Players[i]->Name, GPacket.Name);
  2084. Players[i]->Player.House = GPacket.PlayerInfo.House;
  2085. Players[i]->Player.Color = GPacket.PlayerInfo.Color;
  2086. playerlist->Colors[i] = MPlayerTColors[GPacket.PlayerInfo.Color];
  2087. found = 1;
  2088. break;
  2089. }
  2090. }
  2091. /*.....................................................................
  2092. Don't add this player if he's not part of the game that's selected.
  2093. .....................................................................*/
  2094. i = gamelist->Current_Index();
  2095. if (Games.Count() && GPacket.PlayerInfo.NameCRC != Compute_Name_CRC(Games[i]->Name))
  2096. found = 1;
  2097. /*
  2098. ** Dont add this player if its really me! (hack, hack)
  2099. */
  2100. if (!strcmp(GPacket.Name, MPlayerName)){
  2101. found = 1;
  2102. }
  2103. /*.....................................................................
  2104. name not found (or address didn't match); add to player list box & Vector
  2105. .....................................................................*/
  2106. if (found==0) {
  2107. /*..................................................................
  2108. Create & add a node to the Vector
  2109. ..................................................................*/
  2110. who = new NodeNameType;
  2111. strcpy(who->Name, GPacket.Name);
  2112. who->Address = GAddress;
  2113. who->Player.House = GPacket.PlayerInfo.House;
  2114. who->Player.Color = GPacket.PlayerInfo.Color;
  2115. Players.Add (who);
  2116. /*..................................................................
  2117. Create & add a string to the list box
  2118. ..................................................................*/
  2119. item = new char [MPLAYER_NAME_MAX + 4];
  2120. if (GPacket.PlayerInfo.House==HOUSE_GOOD) {
  2121. sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_G_D_I));
  2122. } else {
  2123. sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_N_O_D));
  2124. }
  2125. playerlist->Add_Item(item, MPlayerTColors[who->Player.Color]);
  2126. retcode = EV_NEW_PLAYER;
  2127. }
  2128. }
  2129. /*------------------------------------------------------------------------
  2130. NET_CONFIRM_JOIN: The game owner has confirmed our JOIN query; mark us as
  2131. being confirmed, and start answering queries from other systems
  2132. ------------------------------------------------------------------------*/
  2133. else if (GPacket.Command==NET_CONFIRM_JOIN) {
  2134. if ( (*joinstate) != JOIN_CONFIRMED) {
  2135. strcpy (MPlayerGameName, GPacket.Name);
  2136. MPlayerHouse = GPacket.PlayerInfo.House;
  2137. MPlayerColorIdx = GPacket.PlayerInfo.Color;
  2138. (*joinstate) = JOIN_CONFIRMED;
  2139. retcode = EV_STATE_CHANGE;
  2140. }
  2141. }
  2142. /*------------------------------------------------------------------------
  2143. NET_REJECT_JOIN: The game owner has turned down our JOIN query; restore
  2144. the dialog state to its first pop-up state. Broadcast a sign-off to
  2145. tell all other systems that I'm no longer a part of any game; this way,
  2146. I'll be properly removed from their dialogs.
  2147. ------------------------------------------------------------------------*/
  2148. else if (GPacket.Command==NET_REJECT_JOIN) {
  2149. if ( (*joinstate) != JOIN_REJECTED) {
  2150. memset (&GPacket, 0, sizeof(GlobalPacketType));
  2151. GPacket.Command = NET_SIGN_OFF;
  2152. strcpy (GPacket.Name,MPlayerName);
  2153. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL);
  2154. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL);
  2155. if (IsBridge) {
  2156. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  2157. &BridgeNet);
  2158. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  2159. &BridgeNet);
  2160. }
  2161. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  2162. MPlayerGameName[0] = 0;
  2163. (*joinstate) = JOIN_REJECTED;
  2164. retcode = EV_STATE_CHANGE;
  2165. }
  2166. }
  2167. /*------------------------------------------------------------------------
  2168. NET_GAME_OPTIONS: The game owner has changed the game options & is sending
  2169. us the new values.
  2170. ------------------------------------------------------------------------*/
  2171. else if (GPacket.Command==NET_GAME_OPTIONS) {
  2172. if ( (*joinstate)==JOIN_CONFIRMED) {
  2173. MPlayerCredits = GPacket.ScenarioInfo.Credits;
  2174. MPlayerBases = GPacket.ScenarioInfo.IsBases;
  2175. MPlayerTiberium = GPacket.ScenarioInfo.IsTiberium;
  2176. MPlayerGoodies = GPacket.ScenarioInfo.IsGoodies;
  2177. MPlayerGhosts = GPacket.ScenarioInfo.IsGhosties;
  2178. BuildLevel = GPacket.ScenarioInfo.BuildLevel;
  2179. MPlayerUnitCount = GPacket.ScenarioInfo.UnitCount;
  2180. Seed = GPacket.ScenarioInfo.Seed;
  2181. Special = GPacket.ScenarioInfo.Special;
  2182. Options.GameSpeed = GPacket.ScenarioInfo.GameSpeed;
  2183. if (MPlayerTiberium) {
  2184. Special.IsTGrowth = 1;
  2185. Special.IsTSpread = 1;
  2186. } else {
  2187. Special.IsTGrowth = 0;
  2188. Special.IsTSpread = 0;
  2189. }
  2190. if (Winsock.Get_Connected()){
  2191. ScenarioIdx = GPacket.ScenarioInfo.Scenario;
  2192. }else{
  2193. ScenarioIdx = -1;
  2194. for (i = 0; i < MPlayerFilenum.Count(); i++) {
  2195. if (GPacket.ScenarioInfo.Scenario == MPlayerFilenum[i])
  2196. ScenarioIdx = i;
  2197. }
  2198. }
  2199. retcode = EV_GAME_OPTIONS;
  2200. }
  2201. }
  2202. /*------------------------------------------------------------------------
  2203. NET_SIGN_OFF: Another system is signing off: search for that system in
  2204. both the game list & player list, & remove it if found
  2205. ------------------------------------------------------------------------*/
  2206. else if (GPacket.Command==NET_SIGN_OFF) {
  2207. /*.....................................................................
  2208. Remove this name from the list of games
  2209. .....................................................................*/
  2210. for (i = 0; i < Games.Count(); i++) {
  2211. if (!strcmp(Games[i]->Name, GPacket.Name) &&
  2212. Games[i]->Address==GAddress) {
  2213. /*...............................................................
  2214. If the system signing off is the currently-selected list
  2215. item, clear the player list since that game is no longer
  2216. forming.
  2217. ...............................................................*/
  2218. if (i==gamelist->Current_Index()) {
  2219. Clear_Player_List (playerlist);
  2220. }
  2221. /*...............................................................
  2222. If the system signing off was the owner of our game, mark
  2223. ourselves as rejected
  2224. ...............................................................*/
  2225. if ( (*joinstate) > JOIN_NOTHING && i==join_index) {
  2226. (*joinstate) = JOIN_REJECTED;
  2227. retcode = EV_STATE_CHANGE;
  2228. }
  2229. /*
  2230. ....................... Set my return code ......................
  2231. */
  2232. if (retcode == EV_NONE) {
  2233. if (i <= gamelist->Current_Index()) {
  2234. retcode = EV_GAME_SIGNOFF;
  2235. } else {
  2236. retcode = EV_PLAYER_SIGNOFF;
  2237. }
  2238. }
  2239. /*
  2240. ................. Remove game name from game list ...............
  2241. */
  2242. Games.Delete(Games[i]);
  2243. item = (char *)(gamelist->Get_Item (i));
  2244. gamelist->Remove_Item (item);
  2245. delete [] item;
  2246. gamelist->Flag_To_Redraw();
  2247. }
  2248. }
  2249. /*.....................................................................
  2250. Remove this name from the list of players
  2251. .....................................................................*/
  2252. for (i = 0; i < Players.Count(); i++) {
  2253. /*
  2254. ..................... Name found; remove it .....................
  2255. */
  2256. if (Players[i]->Address==GAddress) {
  2257. item = (char *)(playerlist->Get_Item(i));
  2258. playerlist->Remove_Item(item);
  2259. delete [] item;
  2260. Players.Delete(Players[i]);
  2261. playerlist->Flag_To_Redraw();
  2262. if (retcode == EV_NONE)
  2263. retcode = EV_PLAYER_SIGNOFF;
  2264. }
  2265. }
  2266. }
  2267. /*------------------------------------------------------------------------
  2268. NET_GO: The game's owner is signalling us to start playing.
  2269. ------------------------------------------------------------------------*/
  2270. else if (GPacket.Command==NET_GO) {
  2271. if ( (*joinstate)==JOIN_CONFIRMED) {
  2272. MPlayerMaxAhead = GPacket.ResponseTime.OneWay;
  2273. (*joinstate) = JOIN_GAME_START;
  2274. retcode = EV_STATE_CHANGE;
  2275. CCDebugString ("C&C95 - Received the 'GO' packet\n");
  2276. }
  2277. }
  2278. /*------------------------------------------------------------------------
  2279. NET_MESSAGE: Someone is sending us a message
  2280. ------------------------------------------------------------------------*/
  2281. else if (GPacket.Command==NET_MESSAGE) {
  2282. sprintf(txt,Text_String (TXT_FROM), GPacket.Name, GPacket.Message.Buf);
  2283. magic_number = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4));
  2284. crc = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2));
  2285. color = MPlayerID_To_ColorIndex(GPacket.Message.ID);
  2286. Messages.Add_Message (txt, MPlayerTColors[color],
  2287. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 1200, magic_number, crc);
  2288. retcode = EV_MESSAGE;
  2289. }
  2290. /*------------------------------------------------------------------------
  2291. NET_PING: Someone is pinging me to get a response time measure (will only
  2292. happen after I've joined a game). Do nothing; the IPX Manager will handle
  2293. sending an ACK, and updating the response time measurements.
  2294. ------------------------------------------------------------------------*/
  2295. else if (GPacket.Command==NET_PING) {
  2296. retcode = EV_NONE;
  2297. }
  2298. /*------------------------------------------------------------------------
  2299. Default case: nothing happened. (This case will be hit every time I
  2300. receive my own NET_QUERY_GAME or NET_QUERY_PLAYER packets.)
  2301. ------------------------------------------------------------------------*/
  2302. else {
  2303. retcode = EV_NONE;
  2304. }
  2305. return(retcode);
  2306. }
  2307. /***********************************************************************************************
  2308. * Net_New_Dialog -- lets user start a new game *
  2309. * *
  2310. * This dialog shows a list of who's requesting to join this game, and lets *
  2311. * the game initiator selectively approve each user. *
  2312. * *
  2313. * ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ *
  2314. * ³ New Network Game ³ *
  2315. * ³ ³ *
  2316. * ³ Players Scenario ³ *
  2317. * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ³ *
  2318. * ³ ³ Boffo ³³ ³ Hell's Kitchen ³³ ³ *
  2319. * ³ ³ Bozo ÃÄ´ ³ Heaven's Gate ÃÄ´ ³ *
  2320. * ³ ³ Bonzo ³ ³ ³ ... ³ ³ ³ *
  2321. * ³ ³ ÃÄ´ ³ ÃÄ´ ³ *
  2322. * ³ ³ ³³ ³ ³³ ³ *
  2323. * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ³ *
  2324. * ³ [Reject] Count:--- ## ³ *
  2325. * ³ Level:--- ## ³ *
  2326. * ³ ³ *
  2327. * ³ Credits: _____ ³ *
  2328. * ³ [ Bases ] [ Crates ] ³ *
  2329. * ³ [ Tiberium ] [ AI Players ] ³ *
  2330. * ³ ³ *
  2331. * ³ [OK] [Cancel] ³ *
  2332. * ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ *
  2333. * ³ ³ ³ ³ *
  2334. * ³ ³ ³ ³ *
  2335. * ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ *
  2336. * ³ [Send Message] ³ *
  2337. * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ *
  2338. * *
  2339. * INPUT: *
  2340. * none. *
  2341. * *
  2342. * OUTPUT: *
  2343. * true = success, false = cancel *
  2344. * *
  2345. * WARNINGS: *
  2346. * MPlayerName & MPlayerGameName must contain this player's name. *
  2347. * *
  2348. * HISTORY: *
  2349. * 02/14/1995 BR : Created. *
  2350. *=============================================================================================*/
  2351. static int Net_New_Dialog(void)
  2352. {
  2353. /* ###Change collision detected! C:\PROJECTS\CODE\NETDLG.CPP... */
  2354. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  2355. /*........................................................................
  2356. Dialog & button dimensions
  2357. ........................................................................*/
  2358. //D_DIALOG_W = 281; // dialog width
  2359. int d_dialog_w = 287*factor; // dialog width
  2360. int d_dialog_h = 177*factor; // dialog height
  2361. int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord
  2362. int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord
  2363. int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord
  2364. int d_txt6_h = 6*factor+1; // ht of 6-pt text
  2365. int d_margin1 = 5*factor; // margin width/height
  2366. int d_margin2 = 2*factor; // margin width/height
  2367. //d_playerlist_w = 100;
  2368. int d_playerlist_w = 106*factor;
  2369. int d_playerlist_h = 27*factor;
  2370. int d_playerlist_x = d_dialog_x + d_margin1;
  2371. int d_playerlist_y = d_dialog_y + d_margin1 + (d_txt6_h * 3);
  2372. int d_scenariolist_w = 162*factor;
  2373. int d_scenariolist_h = 27*factor;
  2374. int d_scenariolist_x = d_dialog_x + d_dialog_w - d_margin1 - d_scenariolist_w;
  2375. int d_scenariolist_y = d_dialog_y + d_margin1 + (d_txt6_h * 3);
  2376. #if (GERMAN | FRENCH)
  2377. int d_reject_w = 55*factor;
  2378. #else
  2379. int d_reject_w = 45*factor;
  2380. #endif
  2381. int d_reject_h = 9*factor;
  2382. int d_reject_x = d_playerlist_x + (d_playerlist_w / 2) - (d_reject_w / 2);
  2383. int d_reject_y = d_playerlist_y + d_playerlist_h + d_margin2;
  2384. int d_count_w = 25*factor;
  2385. int d_count_h = d_txt6_h;
  2386. int d_count_x = d_scenariolist_x + (d_scenariolist_w / 2);
  2387. int d_count_y = d_scenariolist_y + d_scenariolist_h + d_margin2;
  2388. int d_level_w = 25*factor;
  2389. int d_level_h = d_txt6_h;
  2390. int d_level_x = d_scenariolist_x + (d_scenariolist_w / 2);
  2391. int d_level_y = d_count_y + d_count_h;
  2392. int d_credits_w = ((CREDITSBUF_MAX - 1) * 7*factor) + 4*factor;
  2393. //int d_credits_w = ((CREDITSBUF_MAX - 1) * 6*factor) + 3*factor;
  2394. int d_credits_h = 9*factor;
  2395. int d_credits_x = d_dialog_cx + 2*factor;
  2396. int d_credits_y = d_level_y + d_level_h + d_margin1;
  2397. #if (GERMAN | FRENCH)
  2398. int d_bases_w = 120*factor;//bga:100;
  2399. #else
  2400. int d_bases_w = 100*factor;
  2401. #endif
  2402. int d_bases_h = 9*factor;
  2403. int d_bases_x = d_dialog_cx - d_bases_w - d_margin2;
  2404. int d_bases_y = d_credits_y + d_credits_h + d_margin2;
  2405. #if (GERMAN | FRENCH)
  2406. int d_tiberium_w = 120*factor;
  2407. #else
  2408. int d_tiberium_w = 100*factor;
  2409. #endif
  2410. int d_tiberium_h = 9*factor;
  2411. int d_tiberium_x = d_dialog_cx - d_bases_w - d_margin2;
  2412. int d_tiberium_y = d_bases_y + d_bases_h + d_margin2;
  2413. #if (GERMAN | FRENCH)
  2414. int d_goodies_w = 120*factor;
  2415. #else
  2416. int d_goodies_w = 100*factor;
  2417. #endif
  2418. int d_goodies_h = 9*factor;
  2419. int d_goodies_x = d_dialog_cx + d_margin2;
  2420. int d_goodies_y = d_credits_y + d_credits_h + d_margin2;
  2421. #if (GERMAN | FRENCH)
  2422. int d_ghosts_w = 120*factor;
  2423. #else
  2424. int d_ghosts_w = 100*factor;
  2425. #endif
  2426. int d_ghosts_h = 9*factor;
  2427. int d_ghosts_x = d_dialog_cx + d_margin2;
  2428. int d_ghosts_y = d_goodies_y + d_goodies_h + d_margin2;
  2429. int d_ok_w = 45*factor;
  2430. int d_ok_h = 9*factor;
  2431. int d_ok_x = d_dialog_cx - d_margin2 - (d_bases_w / 2) - (d_ok_w / 2);
  2432. int d_ok_y = d_ghosts_y + d_ghosts_h + d_margin1;
  2433. #if (GERMAN | FRENCH)
  2434. int d_cancel_w = 50*factor;
  2435. #else
  2436. int d_cancel_w = 45*factor;
  2437. #endif
  2438. int d_cancel_h = 9*factor;
  2439. int d_cancel_x = d_dialog_cx + d_margin2 + (d_goodies_w / 2) - (d_cancel_w / 2);
  2440. int d_cancel_y = d_ghosts_y + d_ghosts_h + d_margin1;
  2441. int d_message_w = d_dialog_w - (d_margin1 * 2);
  2442. int d_message_h = 34*factor;
  2443. int d_message_x = d_dialog_x + d_margin1;
  2444. int d_message_y = d_cancel_y + d_cancel_h + d_margin1;
  2445. int d_send_w = 80*factor;
  2446. int d_send_h = 9*factor;
  2447. int d_send_x = d_dialog_cx - (d_send_w / 2);
  2448. int d_send_y = d_message_y + d_message_h + d_margin2;
  2449. /*........................................................................
  2450. Button Enumerations
  2451. ........................................................................*/
  2452. enum {
  2453. BUTTON_PLAYERLIST = 100,
  2454. BUTTON_SCENARIOLIST,
  2455. BUTTON_REJECT,
  2456. BUTTON_COUNT,
  2457. BUTTON_LEVEL,
  2458. BUTTON_CREDITS,
  2459. BUTTON_BASES,
  2460. BUTTON_TIBERIUM,
  2461. BUTTON_GOODIES,
  2462. BUTTON_GHOSTS,
  2463. BUTTON_OK,
  2464. BUTTON_CANCEL,
  2465. BUTTON_SEND,
  2466. };
  2467. /*........................................................................
  2468. Redraw values: in order from "top" to "bottom" layer of the dialog
  2469. ........................................................................*/
  2470. typedef enum {
  2471. REDRAW_NONE = 0,
  2472. REDRAW_UNIT_COUNT,
  2473. REDRAW_MESSAGE,
  2474. REDRAW_BUTTONS,
  2475. REDRAW_BACKGROUND,
  2476. REDRAW_ALL = REDRAW_BACKGROUND
  2477. } RedrawType;
  2478. /*........................................................................
  2479. Dialog variables
  2480. ........................................................................*/
  2481. RedrawType display = REDRAW_ALL; // redraw level
  2482. bool process = true; // process while true
  2483. KeyNumType input;
  2484. char credbuf[CREDITSBUF_MAX]; // for credit edit box
  2485. int old_cred; // old value in credits buffer
  2486. int transmit; // 1 = re-transmit new game options
  2487. long ok_timer = 0; // for timing OK button
  2488. int index; // index for rejecting a player
  2489. int rc;
  2490. int i,j;
  2491. char *item;
  2492. int tabs[] = {77*factor}; // tabs for player list box
  2493. long ping_timer = 0; // for sending Ping packets
  2494. unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's
  2495. int min_index; // for sorting player ID's
  2496. unsigned char min_id; // for sorting player ID's
  2497. unsigned char id; // connection ID
  2498. char txt[80];
  2499. JoinEventType whahoppa; // event generated by received packets
  2500. static int first_time = 1; // 1 = 1st time this dialog is run
  2501. int message_length;
  2502. int sent_so_far;
  2503. unsigned short magic_number;
  2504. unsigned short crc;
  2505. /*........................................................................
  2506. Buttons
  2507. ........................................................................*/
  2508. GadgetClass *commands; // button list
  2509. void const *up_button;
  2510. void const *down_button;
  2511. if (InMainLoop){
  2512. up_button = Hires_Retrieve("BTN-UP.SHP");
  2513. down_button = Hires_Retrieve("BTN-DN.SHP");
  2514. }else{
  2515. up_button = Hires_Retrieve("BTN-UP2.SHP");
  2516. down_button = Hires_Retrieve("BTN-DN2.SHP");
  2517. }
  2518. ColorListClass playerlist(BUTTON_PLAYERLIST,
  2519. d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h,
  2520. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2521. up_button,
  2522. down_button);
  2523. ListClass scenariolist(BUTTON_SCENARIOLIST,
  2524. d_scenariolist_x, d_scenariolist_y, d_scenariolist_w, d_scenariolist_h,
  2525. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2526. up_button,
  2527. down_button);
  2528. EditClass credit_edt (BUTTON_CREDITS,
  2529. credbuf, CREDITSBUF_MAX,
  2530. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2531. d_credits_x, d_credits_y, d_credits_w, d_credits_h, EditClass::ALPHANUMERIC);
  2532. TextButtonClass rejectbtn(BUTTON_REJECT, TXT_REJECT,
  2533. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2534. //#if (GERMAN | FRENCH)
  2535. // d_reject_x, d_reject_y);
  2536. //#else
  2537. d_reject_x, d_reject_y, d_reject_w, d_reject_h);
  2538. //#endif
  2539. GaugeClass countgauge (BUTTON_COUNT,
  2540. d_count_x, d_count_y, d_count_w, d_count_h);
  2541. GaugeClass levelgauge (BUTTON_LEVEL,
  2542. d_level_x, d_level_y, d_level_w, d_level_h);
  2543. TextButtonClass basesbtn(BUTTON_BASES, TXT_BASES_OFF,
  2544. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2545. d_bases_x, d_bases_y, d_bases_w, d_bases_h);
  2546. TextButtonClass tiberiumbtn(BUTTON_TIBERIUM, TXT_TIBERIUM_OFF,
  2547. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2548. d_tiberium_x, d_tiberium_y, d_tiberium_w, d_tiberium_h);
  2549. TextButtonClass goodiesbtn(BUTTON_GOODIES, TXT_CRATES_OFF,
  2550. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2551. d_goodies_x, d_goodies_y, d_goodies_w, d_goodies_h);
  2552. TextButtonClass ghostsbtn(BUTTON_GHOSTS, TXT_AI_PLAYERS_OFF,
  2553. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2554. d_ghosts_x, d_ghosts_y, d_ghosts_w, d_ghosts_h);
  2555. TextButtonClass okbtn(BUTTON_OK, TXT_OK,
  2556. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2557. d_ok_x, d_ok_y, d_ok_w, d_ok_h);
  2558. TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL,
  2559. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2560. //#if (GERMAN | FRENCH)
  2561. // d_cancel_x, d_cancel_y);
  2562. //#else
  2563. d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h);
  2564. //#endif
  2565. TextButtonClass sendbtn(BUTTON_SEND, TXT_SEND_MESSAGE,
  2566. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  2567. //#if (GERMAN | FRENCH)
  2568. // d_send_x, d_send_y);
  2569. //#else
  2570. d_send_x, d_send_y, d_send_w, d_send_h);
  2571. //#endif
  2572. /*
  2573. ------------------------- Build the button list --------------------------
  2574. */
  2575. commands = &playerlist;
  2576. scenariolist.Add_Tail(*commands);
  2577. credit_edt.Add_Tail(*commands);
  2578. rejectbtn.Add_Tail(*commands);
  2579. countgauge.Add_Tail(*commands);
  2580. levelgauge.Add_Tail(*commands);
  2581. basesbtn.Add_Tail(*commands);
  2582. tiberiumbtn.Add_Tail(*commands);
  2583. goodiesbtn.Add_Tail(*commands);
  2584. ghostsbtn.Add_Tail(*commands);
  2585. okbtn.Add_Tail(*commands);
  2586. cancelbtn.Add_Tail(*commands);
  2587. sendbtn.Add_Tail(*commands);
  2588. playerlist.Set_Tabs(tabs);
  2589. /*
  2590. ----------------------------- Various Inits ------------------------------
  2591. */
  2592. /*........................................................................
  2593. Init dialog values, only the first time through
  2594. ........................................................................*/
  2595. if (first_time) {
  2596. MPlayerCredits = 3000; // init credits & credit buffer
  2597. MPlayerBases = 1; // init scenario parameters
  2598. MPlayerTiberium = 0;
  2599. MPlayerGoodies = 0;
  2600. MPlayerGhosts = 0;
  2601. Special.IsCaptureTheFlag = 0;
  2602. MPlayerUnitCount = (MPlayerCountMax[MPlayerBases] + MPlayerCountMin[MPlayerBases]) / 2;
  2603. first_time = 0;
  2604. }
  2605. /*........................................................................
  2606. Init button states
  2607. ........................................................................*/
  2608. if (MPlayerBases) {
  2609. basesbtn.Turn_On();
  2610. basesbtn.Set_Text(TXT_BASES_ON);
  2611. }
  2612. if (MPlayerTiberium) {
  2613. tiberiumbtn.Turn_On();
  2614. tiberiumbtn.Set_Text(TXT_TIBERIUM_ON);
  2615. }
  2616. if (MPlayerGoodies) {
  2617. goodiesbtn.Turn_On();
  2618. goodiesbtn.Set_Text(TXT_CRATES_ON);
  2619. }
  2620. if (MPlayerGhosts) {
  2621. ghostsbtn.Turn_On();
  2622. ghostsbtn.Set_Text(TXT_AI_PLAYERS_ON);
  2623. }
  2624. if (Special.IsCaptureTheFlag) {
  2625. MPlayerGhosts = 0;
  2626. ghostsbtn.Turn_On();
  2627. ghostsbtn.Set_Text(TXT_CAPTURE_THE_FLAG);
  2628. }
  2629. sprintf(credbuf, "%d", MPlayerCredits);
  2630. credit_edt.Set_Text(credbuf, CREDITSBUF_MAX);
  2631. old_cred = MPlayerCredits;
  2632. levelgauge.Set_Maximum(MPLAYER_BUILD_LEVEL_MAX - 1);
  2633. levelgauge.Set_Value(BuildLevel - 1);
  2634. countgauge.Set_Maximum(MPlayerCountMax[MPlayerBases] - MPlayerCountMin[MPlayerBases]);
  2635. countgauge.Set_Value(MPlayerUnitCount - MPlayerCountMin[MPlayerBases]);
  2636. /*........................................................................
  2637. Init other scenario parameters
  2638. ........................................................................*/
  2639. Special.IsTGrowth = MPlayerTiberium;
  2640. Special.IsTSpread = MPlayerTiberium;
  2641. transmit = 0;
  2642. /*........................................................................
  2643. Init scenario description list box
  2644. ........................................................................*/
  2645. for (i = 0; i < MPlayerScenarios.Count(); i++) {
  2646. scenariolist.Add_Item (strupr(MPlayerScenarios[i]));
  2647. }
  2648. ScenarioIdx = 0; // 1st scenario is selected
  2649. /*........................................................................
  2650. Init player color-used flags
  2651. ........................................................................*/
  2652. for (i = 0; i < MAX_MPLAYER_COLORS; i++) {
  2653. ColorUsed[i] = 0; // init all colors to available
  2654. }
  2655. ColorUsed[MPlayerColorIdx] = 1; // set my color to used
  2656. playerlist.Set_Selected_Style(ColorListClass::SELECT_BAR, CC_GREEN_SHADOW);
  2657. /*........................................................................
  2658. Init random-number generator, & create a seed to be used for all random
  2659. numbers from here on out
  2660. ........................................................................*/
  2661. //ST - 12/18/2018 11:37AM
  2662. //randomize();
  2663. //Seed = rand();
  2664. /*........................................................................
  2665. Init the message display system
  2666. ........................................................................*/
  2667. Messages.Init (d_message_x + 2*factor, d_message_y + 2*factor, 4, MAX_MESSAGE_LENGTH,
  2668. d_txt6_h);
  2669. /*------------------------------------------------------------------------
  2670. Add myself to the list. Note that since I'm not in the Players Vector,
  2671. the Vector & listbox are now 1 out of sync.
  2672. ------------------------------------------------------------------------*/
  2673. item = new char [MPLAYER_NAME_MAX + 4];
  2674. if (MPlayerHouse==HOUSE_GOOD) {
  2675. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I));
  2676. } else {
  2677. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D));
  2678. }
  2679. playerlist.Add_Item(item, MPlayerTColors[MPlayerColorIdx]);
  2680. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  2681. Blit_Hid_Page_To_Seen_Buff();
  2682. Set_Palette(Palette);
  2683. while (Get_Mouse_State() > 0) Show_Mouse();
  2684. /*
  2685. ---------------------------- Processing loop -----------------------------
  2686. */
  2687. while (process) {
  2688. /*
  2689. ** If we have just received input focus again after running in the background then
  2690. ** we need to redraw.
  2691. */
  2692. if (AllSurfaces.SurfacesRestored){
  2693. AllSurfaces.SurfacesRestored=FALSE;
  2694. display=REDRAW_ALL;
  2695. }
  2696. #if(SHOW_MONO)
  2697. Ipx.Mono_Debug_Print(-1,0);
  2698. #endif
  2699. /*
  2700. ...................... Refresh display if needed ......................
  2701. */
  2702. if (display == REDRAW_UNIT_COUNT){
  2703. /*
  2704. ** Wipe the background behind the unit count then reprint it
  2705. */
  2706. LogicPage->Fill_Rect(d_count_x + d_count_w + 2*factor,
  2707. d_count_y,
  2708. d_count_x + d_count_w + 2*factor + 20,
  2709. d_count_y + 12,
  2710. 0 );
  2711. sprintf(txt,"%d",MPlayerUnitCount);
  2712. Fancy_Text_Print (txt, d_count_x + d_count_w + 2*factor, d_count_y,
  2713. CC_GREEN, TBLACK,
  2714. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  2715. display = REDRAW_NONE;
  2716. }
  2717. if (display) {
  2718. Hide_Mouse();
  2719. /*
  2720. .................. Redraw backgound & dialog box ...................
  2721. */
  2722. if (display >= REDRAW_BACKGROUND) {
  2723. /*
  2724. ** Reload and draw the title page
  2725. */
  2726. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  2727. Blit_Hid_Page_To_Seen_Buff();
  2728. Set_Palette(Palette);
  2729. Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
  2730. /*...............................................................
  2731. Dialog & Field labels
  2732. ...............................................................*/
  2733. Draw_Caption (TXT_NETGAME_SETUP, d_dialog_x, d_dialog_y, d_dialog_w);
  2734. Fancy_Text_Print(TXT_PLAYERS,
  2735. d_playerlist_x + (d_playerlist_w / 2), d_playerlist_y - d_txt6_h,
  2736. CC_GREEN, TBLACK,
  2737. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_CENTER);
  2738. Fancy_Text_Print(TXT_SCENARIOS,
  2739. d_scenariolist_x + (d_scenariolist_w / 2),
  2740. d_scenariolist_y - d_txt6_h,
  2741. CC_GREEN, TBLACK,
  2742. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_CENTER);
  2743. Fancy_Text_Print (TXT_COUNT, d_count_x - 2*factor, d_count_y,
  2744. CC_GREEN, TBLACK,
  2745. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_RIGHT);
  2746. sprintf(txt,"%d",MPlayerUnitCount);
  2747. Fancy_Text_Print (txt, d_count_x + d_count_w + 2*factor, d_count_y,
  2748. CC_GREEN, TBLACK,
  2749. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  2750. Fancy_Text_Print (TXT_LEVEL, d_level_x - 2*factor, d_level_y,
  2751. CC_GREEN, TBLACK,
  2752. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_RIGHT);
  2753. if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) {
  2754. sprintf(txt,"%d",BuildLevel);
  2755. } else {
  2756. sprintf(txt, "**");
  2757. }
  2758. Fancy_Text_Print (txt, d_level_x + d_level_w + 2*factor, d_level_y,
  2759. CC_GREEN, TBLACK,
  2760. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  2761. Fancy_Text_Print (TXT_START_CREDITS_COLON, d_credits_x - 5*factor,
  2762. d_credits_y + 1*factor, CC_GREEN, TBLACK,
  2763. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_RIGHT);
  2764. }
  2765. /*
  2766. .......................... Redraw buttons ..........................
  2767. */
  2768. if (display >= REDRAW_BUTTONS) {
  2769. commands->Draw_All();
  2770. }
  2771. /*..................................................................
  2772. Draw the messages:
  2773. - Erase an old message first
  2774. - If we're in a game, print the game options (if they've been
  2775. received)
  2776. - If we've been rejected from a game, print that message
  2777. ..................................................................*/
  2778. if (display >= REDRAW_MESSAGE) {
  2779. Draw_Box(d_message_x, d_message_y, d_message_w, d_message_h,
  2780. BOXSTYLE_GREEN_BORDER, true);
  2781. Messages.Draw();
  2782. }
  2783. Show_Mouse();
  2784. display = REDRAW_NONE;
  2785. }
  2786. /*
  2787. ........................... Get user input ............................
  2788. */
  2789. input = commands->Input();
  2790. /*
  2791. ---------------------------- Process input ----------------------------
  2792. */
  2793. switch (input) {
  2794. /*------------------------------------------------------------------
  2795. New Scenario selected.
  2796. ------------------------------------------------------------------*/
  2797. case (BUTTON_SCENARIOLIST | KN_BUTTON):
  2798. if (scenariolist.Current_Index() != ScenarioIdx) {
  2799. ScenarioIdx = scenariolist.Current_Index();
  2800. MPlayerCredits = atoi(credbuf);
  2801. transmit = 1;
  2802. }
  2803. break;
  2804. /*------------------------------------------------------------------
  2805. Reject the currently-selected player (don't allow rejecting myself,
  2806. who will be the first entry in the list)
  2807. ------------------------------------------------------------------*/
  2808. case (BUTTON_REJECT | KN_BUTTON):
  2809. index = playerlist.Current_Index();
  2810. if (index == 0) {
  2811. CCMessageBox().Process (TXT_CANT_REJECT_SELF, TXT_OOPS);
  2812. display = REDRAW_ALL;
  2813. break;
  2814. } else {
  2815. if (index < 0 || index >= playerlist.Count()) {
  2816. CCMessageBox().Process (TXT_SELECT_PLAYER_REJECT,TXT_OOPS);
  2817. display = REDRAW_ALL;
  2818. break;
  2819. }
  2820. }
  2821. memset (&GPacket, 0, sizeof(GlobalPacketType));
  2822. GPacket.Command = NET_REJECT_JOIN;
  2823. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 1,
  2824. &(Players[index - 1]->Address));
  2825. break;
  2826. /*------------------------------------------------------------------
  2827. User adjusts max # units
  2828. ------------------------------------------------------------------*/
  2829. case (BUTTON_COUNT | KN_BUTTON):
  2830. MPlayerUnitCount = countgauge.Get_Value() + MPlayerCountMin[MPlayerBases];
  2831. Hide_Mouse();
  2832. LogicPage->Fill_Rect (d_count_x + d_count_w + 2*factor, d_count_y,
  2833. d_count_x + d_count_w + 14*factor, d_count_y + 6*factor, BLACK);
  2834. sprintf(txt,"%d",MPlayerUnitCount);
  2835. Fancy_Text_Print (txt, d_count_x + d_count_w + 2*factor, d_count_y,
  2836. CC_GREEN, TBLACK,
  2837. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  2838. Show_Mouse();
  2839. transmit = 1;
  2840. break;
  2841. /*------------------------------------------------------------------
  2842. User adjusts build level
  2843. ------------------------------------------------------------------*/
  2844. case (BUTTON_LEVEL | KN_BUTTON):
  2845. BuildLevel = levelgauge.Get_Value() + 1;
  2846. if (BuildLevel > MPLAYER_BUILD_LEVEL_MAX) // if it's pegged, max it out
  2847. BuildLevel = MPLAYER_BUILD_LEVEL_MAX;
  2848. Hide_Mouse();
  2849. LogicPage->Fill_Rect (d_level_x + d_level_w + 2*factor, d_level_y,
  2850. d_level_x + d_level_w + 14*factor, d_level_y + 6*factor, BLACK);
  2851. if (BuildLevel <= MPLAYER_BUILD_LEVEL_MAX) {
  2852. sprintf(txt,"%d",BuildLevel);
  2853. } else {
  2854. sprintf(txt, "**");
  2855. }
  2856. Fancy_Text_Print (txt, d_level_x + d_level_w + 2*factor, d_level_y,
  2857. CC_GREEN, TBLACK,
  2858. TPF_NOSHADOW | TPF_6PT_GRAD | TPF_USE_GRAD_PAL);
  2859. Show_Mouse();
  2860. transmit = 1;
  2861. break;
  2862. /*------------------------------------------------------------------
  2863. User edits the credits value; retransmit new game options
  2864. ------------------------------------------------------------------*/
  2865. case (BUTTON_CREDITS | KN_BUTTON):
  2866. MPlayerCredits = atoi(credbuf);
  2867. transmit = 1;
  2868. break;
  2869. /*------------------------------------------------------------------
  2870. Toggle bases:
  2871. - Clear scenario list & rebuild it with new names
  2872. - toggle bases button, change its text
  2873. - adjust the MPlayerUnitCount to reflect the new allowed range,
  2874. using the current gauge setting
  2875. - Change the unit count gauge limit & value
  2876. ------------------------------------------------------------------*/
  2877. case (BUTTON_BASES | KN_BUTTON):
  2878. if (MPlayerBases) {
  2879. MPlayerBases = 0;
  2880. basesbtn.Turn_Off();
  2881. basesbtn.Set_Text(TXT_BASES_OFF);
  2882. MPlayerUnitCount = Fixed_To_Cardinal (MPlayerCountMax[0]-MPlayerCountMin[0],
  2883. Cardinal_To_Fixed(MPlayerCountMax[1]-MPlayerCountMin[1],
  2884. MPlayerUnitCount-MPlayerCountMin[1])) + MPlayerCountMin[0];
  2885. } else {
  2886. MPlayerBases = 1;
  2887. basesbtn.Turn_On();
  2888. basesbtn.Set_Text(TXT_BASES_ON);
  2889. MPlayerUnitCount = Fixed_To_Cardinal (MPlayerCountMax[1]-MPlayerCountMin[1],
  2890. Cardinal_To_Fixed(MPlayerCountMax[0]-MPlayerCountMin[0],
  2891. MPlayerUnitCount-MPlayerCountMin[0])) + MPlayerCountMin[1];
  2892. }
  2893. MPlayerCredits = atoi(credbuf);
  2894. countgauge.Set_Maximum(MPlayerCountMax[MPlayerBases] - MPlayerCountMin[MPlayerBases]);
  2895. countgauge.Set_Value(MPlayerUnitCount - MPlayerCountMin[MPlayerBases]);
  2896. transmit = 1;
  2897. countgauge.Flag_To_Redraw();
  2898. display = REDRAW_UNIT_COUNT;
  2899. break;
  2900. /*------------------------------------------------------------------
  2901. Toggle tiberium
  2902. ------------------------------------------------------------------*/
  2903. case (BUTTON_TIBERIUM | KN_BUTTON):
  2904. if (MPlayerTiberium) {
  2905. MPlayerTiberium = 0;
  2906. Special.IsTGrowth = 0;
  2907. Special.IsTSpread = 0;
  2908. tiberiumbtn.Turn_Off();
  2909. tiberiumbtn.Set_Text(TXT_TIBERIUM_OFF);
  2910. } else {
  2911. MPlayerTiberium = 1;
  2912. Special.IsTGrowth = 1;
  2913. Special.IsTSpread = 1;
  2914. tiberiumbtn.Turn_On();
  2915. tiberiumbtn.Set_Text(TXT_TIBERIUM_ON);
  2916. }
  2917. MPlayerCredits = atoi(credbuf);
  2918. transmit = 1;
  2919. break;
  2920. /*------------------------------------------------------------------
  2921. Toggle goodies
  2922. ------------------------------------------------------------------*/
  2923. case (BUTTON_GOODIES | KN_BUTTON):
  2924. if (MPlayerGoodies) {
  2925. MPlayerGoodies = 0;
  2926. goodiesbtn.Turn_Off();
  2927. goodiesbtn.Set_Text(TXT_CRATES_OFF);
  2928. } else {
  2929. MPlayerGoodies = 1;
  2930. goodiesbtn.Turn_On();
  2931. goodiesbtn.Set_Text(TXT_CRATES_ON);
  2932. }
  2933. MPlayerCredits = atoi(credbuf);
  2934. transmit = 1;
  2935. break;
  2936. /*------------------------------------------------------------------
  2937. Toggle ghosts/capture-the-flag
  2938. ------------------------------------------------------------------*/
  2939. case (BUTTON_GHOSTS | KN_BUTTON):
  2940. if (!MPlayerGhosts && !Special.IsCaptureTheFlag) { // ghosts OFF => ghosts ON
  2941. MPlayerGhosts = 1;
  2942. Special.IsCaptureTheFlag = 0;
  2943. ghostsbtn.Turn_On();
  2944. ghostsbtn.Set_Text(TXT_AI_PLAYERS_ON);
  2945. } else {
  2946. if (MPlayerGhosts) { // ghosts ON => capture-flag
  2947. MPlayerGhosts = 0;
  2948. Special.IsCaptureTheFlag = 1;
  2949. ghostsbtn.Turn_On();
  2950. ghostsbtn.Set_Text(TXT_CAPTURE_THE_FLAG);
  2951. } else {
  2952. if (Special.IsCaptureTheFlag) { // capture-flag => AI OFF
  2953. MPlayerGhosts = 0;
  2954. Special.IsCaptureTheFlag = 0;
  2955. ghostsbtn.Turn_Off();
  2956. ghostsbtn.Set_Text(TXT_AI_PLAYERS_OFF);
  2957. }
  2958. }
  2959. }
  2960. MPlayerCredits = atoi(credbuf);
  2961. transmit = 1;
  2962. break;
  2963. /*------------------------------------------------------------------
  2964. OK: exit loop with TRUE status
  2965. ------------------------------------------------------------------*/
  2966. case (BUTTON_OK | KN_BUTTON):
  2967. /*...............................................................
  2968. If a new player has joined in the last second, don't allow
  2969. an OK; force a wait longer than 1 second (to give all players
  2970. a chance to know about this new guy)
  2971. ...............................................................*/
  2972. i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)60);
  2973. while (TickCount.Time() - ok_timer < i)
  2974. Ipx.Service();
  2975. /*...............................................................
  2976. If there are at least 2 players, go ahead & play; error otherwise
  2977. ...............................................................*/
  2978. if (MPlayerSolo || Players.Count() > 0) {
  2979. rc = TRUE;
  2980. process = FALSE;
  2981. } else {
  2982. CCMessageBox().Process (TXT_ONLY_ONE,TXT_OOPS,NULL);
  2983. display = REDRAW_ALL;
  2984. }
  2985. break;
  2986. /*------------------------------------------------------------------
  2987. CANCEL: send a SIGN_OFF, bail out with error code
  2988. ------------------------------------------------------------------*/
  2989. case (KN_ESC):
  2990. if (Messages.Get_Edit_Buf() != NULL) {
  2991. Messages.Input(input);
  2992. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  2993. break;
  2994. }
  2995. case (BUTTON_CANCEL | KN_BUTTON):
  2996. memset (&GPacket, 0, sizeof(GlobalPacketType));
  2997. GPacket.Command = NET_SIGN_OFF;
  2998. strcpy (GPacket.Name, MPlayerName);
  2999. /*...............................................................
  3000. Broadcast my sign-off over my network
  3001. ...............................................................*/
  3002. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3003. 0, NULL);
  3004. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3005. 0, NULL);
  3006. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  3007. /*...............................................................
  3008. Broadcast my sign-off over a bridged network if there is one
  3009. ...............................................................*/
  3010. if (IsBridge) {
  3011. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  3012. &BridgeNet);
  3013. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  3014. &BridgeNet);
  3015. }
  3016. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  3017. /*...............................................................
  3018. And now, just be absolutely sure, send my sign-off to each
  3019. player in my game. (If there's a bridge between us, the other
  3020. player will have specified my address, so he can cross the
  3021. bridge; but I may not have specified a bridge address, so the
  3022. only way I have of crossing the bridge is to send a packet
  3023. directly to him.)
  3024. ...............................................................*/
  3025. for (i = 0; i < Players.Count(); i++) {
  3026. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  3027. &(Players[i]->Address));
  3028. Ipx.Service();
  3029. }
  3030. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  3031. MPlayerGameName[0] = 0;
  3032. process = false;
  3033. rc = false;
  3034. break;
  3035. /*------------------------------------------------------------------
  3036. Default: manage the inter-player messages
  3037. ------------------------------------------------------------------*/
  3038. default:
  3039. /*...............................................................
  3040. F4/SEND/'M' = send a message
  3041. ...............................................................*/
  3042. if (Messages.Get_Edit_Buf()==NULL) {
  3043. if (input == KN_M || input==(BUTTON_SEND | KN_BUTTON) ||
  3044. input == KN_F4) {
  3045. memset (txt, 0, 80);
  3046. strcpy(txt,Text_String(TXT_TO_ALL)); // "To All:"
  3047. Messages.Add_Edit (MPlayerTColors[MPlayerColorIdx],
  3048. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, txt, d_message_w-70*factor);
  3049. credit_edt.Clear_Focus();
  3050. credit_edt.Flag_To_Redraw();
  3051. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  3052. break;
  3053. }
  3054. } else {
  3055. /*...............................................................
  3056. If we're already editing a message and the user clicks on
  3057. 'Send', translate our input to a Return so Messages.Input() will
  3058. work properly.
  3059. ...............................................................*/
  3060. if (input==(BUTTON_SEND | KN_BUTTON)) {
  3061. input = KN_RETURN;
  3062. }
  3063. }
  3064. /*...............................................................
  3065. Manage the message system (get rid of old messages)
  3066. ...............................................................*/
  3067. if (Messages.Manage()) {
  3068. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  3069. }
  3070. /*...............................................................
  3071. Re-draw the messages & service keyboard input for any message
  3072. being edited.
  3073. ...............................................................*/
  3074. i = Messages.Input(input);
  3075. /*...............................................................
  3076. If 'Input' returned 1, it means refresh the message display.
  3077. ...............................................................*/
  3078. if (i==1) {
  3079. Messages.Draw();
  3080. }
  3081. /*...............................................................
  3082. If 'Input' returned 2, it means redraw the message display.
  3083. ...............................................................*/
  3084. else if (i==2) {
  3085. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  3086. }
  3087. /*...............................................................
  3088. If 'input' returned 3, it means send the current message.
  3089. ...............................................................*/
  3090. else if (i==3) {
  3091. long actual_message_size;
  3092. char *the_string;
  3093. sent_so_far = 0;
  3094. magic_number = MESSAGE_HEAD_MAGIC_NUMBER;
  3095. message_length = strlen(Messages.Get_Edit_Buf());
  3096. crc = (unsigned short)
  3097. (Calculate_CRC(Messages.Get_Edit_Buf(), message_length) &0xffff);
  3098. while ( sent_so_far < message_length ){
  3099. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3100. GPacket.Command = NET_MESSAGE;
  3101. strcpy (GPacket.Name, MPlayerName);
  3102. memcpy (GPacket.Message.Buf, Messages.Get_Edit_Buf()+sent_so_far, COMPAT_MESSAGE_LENGTH-5);
  3103. /*
  3104. ** Steve I's stuff for splitting message on word boundries
  3105. */
  3106. actual_message_size = COMPAT_MESSAGE_LENGTH - 5;
  3107. /* Start at the end of the message and find a space with 10 chars. */
  3108. the_string = GPacket.Message.Buf;
  3109. while ( (COMPAT_MESSAGE_LENGTH -5) -actual_message_size < 10 &&
  3110. the_string[actual_message_size] != ' '){
  3111. --actual_message_size;
  3112. }
  3113. if ( the_string[actual_message_size] == ' ' ){
  3114. /* Now delete the extra characters after the space (they musnt print) */
  3115. for ( int i=0 ; i< (COMPAT_MESSAGE_LENGTH-5) - actual_message_size; i++ ){
  3116. the_string[i + actual_message_size] = 0; //0xff; ST - 12/18/2018 11:37AM
  3117. }
  3118. }else{
  3119. actual_message_size = COMPAT_MESSAGE_LENGTH - 5;
  3120. }
  3121. *(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-5) = 0;
  3122. *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4)) = magic_number;
  3123. *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2)) = crc;
  3124. GPacket.Message.ID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse);
  3125. GPacket.Message.NameCRC = Compute_Name_CRC(MPlayerGameName);
  3126. /*..................................................................
  3127. Send the message to every player in our player list.
  3128. ..................................................................*/
  3129. for (i = 0; i < Players.Count(); i++) {
  3130. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  3131. &(Players[i]->Address));
  3132. Ipx.Service();
  3133. }
  3134. /*..................................................................
  3135. Add the message to our own list, since we're not in the player list
  3136. on this dialog.
  3137. ..................................................................*/
  3138. sprintf(txt,Text_String (TXT_FROM), MPlayerName, GPacket.Message.Buf);
  3139. Messages.Add_Message (txt, MPlayerTColors[MPlayerColorIdx],
  3140. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 1200, magic_number, crc);
  3141. magic_number++;
  3142. sent_so_far += actual_message_size; //COMPAT_MESSAGE_LENGTH-5;
  3143. }
  3144. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  3145. }
  3146. }
  3147. /*---------------------------------------------------------------------
  3148. Detect editing of the credits buffer, transmit new values to players
  3149. ---------------------------------------------------------------------*/
  3150. if (atoi(credbuf) != old_cred) {
  3151. old_cred = Bound(atoi(credbuf), 0, 9999);
  3152. MPlayerCredits = old_cred;
  3153. transmit = 1;
  3154. sprintf(credbuf, "%d", MPlayerCredits);
  3155. credit_edt.Set_Text(credbuf, CREDITSBUF_MAX);
  3156. }
  3157. /*---------------------------------------------------------------------
  3158. Process incoming packets
  3159. ---------------------------------------------------------------------*/
  3160. whahoppa = Get_NewGame_Responses(&playerlist);
  3161. if (whahoppa == EV_NEW_PLAYER) {
  3162. ok_timer = TickCount.Time();
  3163. transmit = 1;
  3164. } else {
  3165. if (whahoppa == EV_MESSAGE) {
  3166. if (display < REDRAW_MESSAGE) display = REDRAW_MESSAGE;
  3167. }
  3168. }
  3169. /*---------------------------------------------------------------------
  3170. If our Transmit flag is set, we need to send out a game option packet
  3171. ---------------------------------------------------------------------*/
  3172. if (transmit) {
  3173. for (i = 0; i < Players.Count(); i++) {
  3174. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3175. GPacket.Command = NET_GAME_OPTIONS;
  3176. GPacket.ScenarioInfo.Scenario = MPlayerFilenum[ScenarioIdx];
  3177. GPacket.ScenarioInfo.Credits = MPlayerCredits;
  3178. GPacket.ScenarioInfo.IsBases = MPlayerBases;
  3179. GPacket.ScenarioInfo.IsTiberium = MPlayerTiberium;
  3180. GPacket.ScenarioInfo.IsGoodies = MPlayerGoodies;
  3181. GPacket.ScenarioInfo.IsGhosties = MPlayerGhosts;
  3182. GPacket.ScenarioInfo.BuildLevel = BuildLevel;
  3183. GPacket.ScenarioInfo.UnitCount = MPlayerUnitCount;
  3184. GPacket.ScenarioInfo.Seed = Seed;
  3185. GPacket.ScenarioInfo.Special = Special;
  3186. GPacket.ScenarioInfo.GameSpeed = Options.GameSpeed;
  3187. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3188. 1, &(Players[i]->Address) );
  3189. }
  3190. transmit = 0;
  3191. }
  3192. /*---------------------------------------------------------------------
  3193. Ping every player in my game, to force the Global Channel to measure
  3194. the connection response time.
  3195. ---------------------------------------------------------------------*/
  3196. if (TickCount.Time() - ping_timer > 15) {
  3197. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3198. GPacket.Command = NET_PING;
  3199. for (i = 0; i < Players.Count(); i++) {
  3200. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3201. 1, &(Players[i]->Address) );
  3202. }
  3203. ping_timer = TickCount.Time();
  3204. }
  3205. /*---------------------------------------------------------------------
  3206. Service the Ipx connections
  3207. ---------------------------------------------------------------------*/
  3208. Ipx.Service();
  3209. /*---------------------------------------------------------------------
  3210. Service the sounds & score; GameActive must be false at this point,
  3211. so Call_Back() doesn't intercept global messages from me!
  3212. ---------------------------------------------------------------------*/
  3213. Call_Back();
  3214. } /* end of while */
  3215. /*------------------------------------------------------------------------
  3216. Establish connections with all other players.
  3217. ------------------------------------------------------------------------*/
  3218. if (rc) {
  3219. /*.....................................................................
  3220. Set the number of players in this game, and my ID
  3221. .....................................................................*/
  3222. MPlayerCount = Players.Count() + 1;
  3223. MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse);
  3224. /*.....................................................................
  3225. Get the scenario filename
  3226. .....................................................................*/
  3227. Scenario = MPlayerFilenum[ScenarioIdx];
  3228. /*.....................................................................
  3229. Compute frame delay value for packet transmissions:
  3230. - Divide global channel's response time by 8 (2 to convert to 1-way
  3231. value, 4 more to convert from ticks to frames)
  3232. .....................................................................*/
  3233. MPlayerMaxAhead = MAX( (Ipx.Global_Response_Time() / 8), (unsigned long)2);
  3234. /*.....................................................................
  3235. Send all players the NET_GO packet. Wait until all ACK's have been
  3236. received.
  3237. .....................................................................*/
  3238. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3239. GPacket.Command = NET_GO;
  3240. GPacket.ResponseTime.OneWay = MPlayerMaxAhead;
  3241. for (i = 0; i < Players.Count(); i++) {
  3242. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3243. 1, &(Players[i]->Address) );
  3244. /*..................................................................
  3245. Wait for all the ACK's to come in.
  3246. ..................................................................*/
  3247. while (Ipx.Global_Num_Send() > 0)
  3248. Ipx.Service();
  3249. }
  3250. /*.....................................................................
  3251. Form connections with all other players. Form the IPX Connection ID
  3252. from the player's Color (high byte) and House (low byte). This
  3253. will let us extract any player's color & house at any time.
  3254. Fill in 'tmp_id' while we're doing this.
  3255. .....................................................................*/
  3256. for (i = 0; i < Players.Count(); i++) {
  3257. id = Build_MPlayerID (Players[i]->Player.Color,
  3258. Players[i]->Player.House);
  3259. tmp_id[i] = id;
  3260. Ipx.Create_Connection(id, Players[i]->Name, &(Players[i]->Address) );
  3261. }
  3262. tmp_id[i] = MPlayerLocalID;
  3263. /*.....................................................................
  3264. Store every player's ID in the MPlayerID[] array. This array will
  3265. determine the order of event execution, so the ID's must be stored
  3266. in the same order on all systems.
  3267. .....................................................................*/
  3268. for (i = 0; i < MPlayerCount; i++) {
  3269. min_index = 0;
  3270. min_id = 0xff;
  3271. for (j = 0; j < MPlayerCount; j++) {
  3272. if (tmp_id[j] < min_id) {
  3273. min_id = tmp_id[j];
  3274. min_index = j;
  3275. }
  3276. }
  3277. MPlayerID[i] = tmp_id[min_index];
  3278. tmp_id[min_index] = 0xff;
  3279. }
  3280. /*.....................................................................
  3281. Fill in the array of player names, including my own.
  3282. .....................................................................*/
  3283. for (i = 0; i < MPlayerCount; i++) {
  3284. if (MPlayerID[i] == MPlayerLocalID) {
  3285. strcpy (MPlayerNames[i], MPlayerName);
  3286. } else {
  3287. strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i]));
  3288. }
  3289. }
  3290. }
  3291. /*------------------------------------------------------------------------
  3292. Init network timing values, using previous response times as a measure
  3293. of what our retry delta & timeout should be.
  3294. ------------------------------------------------------------------------*/
  3295. Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1,
  3296. Ipx.Global_Response_Time() * 4);
  3297. /*------------------------------------------------------------------------
  3298. Clear all lists
  3299. ------------------------------------------------------------------------*/
  3300. while (scenariolist.Count()) {
  3301. scenariolist.Remove_Item(scenariolist.Get_Item(0));
  3302. }
  3303. Clear_Player_List(&playerlist);
  3304. /*------------------------------------------------------------------------
  3305. Restore screen
  3306. ------------------------------------------------------------------------*/
  3307. Hide_Mouse();
  3308. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  3309. Blit_Hid_Page_To_Seen_Buff();
  3310. Show_Mouse();
  3311. return(rc);
  3312. }
  3313. /***************************************************************************
  3314. * Get_NewGame_Responses -- processes packets for New Game dialog *
  3315. * *
  3316. * This routine can modify the contents of the given list box, as well *
  3317. * as the contents of the Players Vector global. *
  3318. * *
  3319. * INPUT: *
  3320. * playerlist list of players in this game *
  3321. * *
  3322. * OUTPUT: *
  3323. * EV_NONE = nothing happened *
  3324. * EV_NEW_PLAYER = a new player has joined; false otherwise *
  3325. * EV_MESSAGE = a message was received *
  3326. * *
  3327. * WARNINGS: *
  3328. * none. *
  3329. * *
  3330. * HISTORY: *
  3331. * 04/18/1995 BRR : Created. *
  3332. *=========================================================================*/
  3333. static JoinEventType Get_NewGame_Responses(ColorListClass *playerlist)
  3334. {
  3335. int rc;
  3336. char * item; // general-purpose string
  3337. NodeNameType *who; // node to add to Players Vector
  3338. int i;
  3339. int found;
  3340. JoinEventType retval = EV_NONE;
  3341. int resend;
  3342. char txt[80];
  3343. int color;
  3344. unsigned short magic_number;
  3345. unsigned short crc;
  3346. /*------------------------------------------------------------------------
  3347. If there is no incoming packet, just return
  3348. ------------------------------------------------------------------------*/
  3349. rc = Ipx.Get_Global_Message (&GPacket, &GPacketlen, &GAddress, &GProductID);
  3350. if (!rc || GProductID != IPXGlobalConnClass::COMMAND_AND_CONQUER) {
  3351. return(EV_NONE);
  3352. }
  3353. /*------------------------------------------------------------------------
  3354. Try to handle the packet in a standard way
  3355. ------------------------------------------------------------------------*/
  3356. if (Process_Global_Packet(&GPacket,&GAddress) != 0) {
  3357. return(EV_NONE);
  3358. } else
  3359. /*------------------------------------------------------------------------
  3360. NET_QUERY_JOIN:
  3361. ------------------------------------------------------------------------*/
  3362. if (GPacket.Command==NET_QUERY_JOIN) {
  3363. /*.....................................................................
  3364. See if this name is unique:
  3365. - If the name matches, but the address is different, reject this player
  3366. - If the name & address match, this packet must be a re-send of a
  3367. prevous request; in this case, do nothing. The other player must have
  3368. received my CONFIRM_JOIN packet (since it was sent with an ACK
  3369. required), so we can ignore this resend.
  3370. .....................................................................*/
  3371. found = 0;
  3372. resend = 0;
  3373. for (i = 0; i < Players.Count(); i++) {
  3374. if (!strcmp(Players[i]->Name,GPacket.Name)) {
  3375. if (Players[i]->Address != GAddress) {
  3376. found = 1;
  3377. }
  3378. else {
  3379. resend = 1;
  3380. }
  3381. break;
  3382. }
  3383. }
  3384. if (!strcmp (MPlayerName, GPacket.Name)) {
  3385. found = 1;
  3386. }
  3387. /*.....................................................................
  3388. Reject if name is a duplicate, or if there are too many players:
  3389. .....................................................................*/
  3390. if (found || (Players.Count() >= (MPlayerMax - 1) && !resend) ) {
  3391. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3392. GPacket.Command = NET_REJECT_JOIN;
  3393. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3394. 1, &GAddress);
  3395. }
  3396. /*.....................................................................
  3397. If this packet is NOT a resend, accept the player. Grant him the
  3398. requested color if possible.
  3399. .....................................................................*/
  3400. else if (!resend) {
  3401. /*..................................................................
  3402. Add node to the Vector list
  3403. ..................................................................*/
  3404. who = new NodeNameType;
  3405. strcpy(who->Name, GPacket.Name);
  3406. who->Address = GAddress;
  3407. who->Player.House = GPacket.PlayerInfo.House;
  3408. Players.Add (who);
  3409. /*..................................................................
  3410. Set player's color; if requested color isn't used, give it to him;
  3411. otherwise, give him the 1st available color. Mark the color we
  3412. give him as used.
  3413. ..................................................................*/
  3414. if (ColorUsed[GPacket.PlayerInfo.Color] == 0) {
  3415. who->Player.Color = GPacket.PlayerInfo.Color;
  3416. } else {
  3417. for (i = 0; i < MAX_MPLAYER_COLORS; i++) {
  3418. if (ColorUsed[i]==0) {
  3419. who->Player.Color = i;
  3420. break;
  3421. }
  3422. }
  3423. }
  3424. ColorUsed[who->Player.Color] = 1;
  3425. /*..................................................................
  3426. Add player name to the list box
  3427. ..................................................................*/
  3428. item = new char [MPLAYER_NAME_MAX + 4];
  3429. if (GPacket.PlayerInfo.House==HOUSE_GOOD) {
  3430. sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_G_D_I));
  3431. } else {
  3432. sprintf(item,"%s\t%s",GPacket.Name,Text_String(TXT_N_O_D));
  3433. }
  3434. playerlist->Add_Item (item, MPlayerTColors[who->Player.Color]);
  3435. /*..................................................................
  3436. Send a confirmation packet
  3437. ..................................................................*/
  3438. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3439. GPacket.Command = NET_CONFIRM_JOIN;
  3440. strcpy(GPacket.Name,MPlayerName);
  3441. GPacket.PlayerInfo.House = who->Player.House;
  3442. GPacket.PlayerInfo.Color = who->Player.Color;
  3443. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3444. 1, &GAddress);
  3445. retval = EV_NEW_PLAYER;
  3446. }
  3447. }
  3448. /*------------------------------------------------------------------------
  3449. NET_SIGN_OFF: Another system is signing off: search for that system in
  3450. the player list, & remove it if found
  3451. ------------------------------------------------------------------------*/
  3452. else if (GPacket.Command==NET_SIGN_OFF) {
  3453. for (i = 0; i < Players.Count(); i++) {
  3454. /*
  3455. ....................... Name found; remove it ......................
  3456. */
  3457. if (!strcmp (Players[i]->Name, GPacket.Name) &&
  3458. Players[i]->Address==GAddress) {
  3459. /*...............................................................
  3460. Remove from the list box
  3461. ...............................................................*/
  3462. item = (char *)(playerlist->Get_Item(i + 1));
  3463. playerlist->Remove_Item(item);
  3464. playerlist->Flag_To_Redraw();
  3465. delete [] item;
  3466. /*...............................................................
  3467. Mark his color as available
  3468. ...............................................................*/
  3469. ColorUsed[Players[i]->Player.Color] = 0;
  3470. /*...............................................................
  3471. Delete from the Vector list
  3472. ...............................................................*/
  3473. Players.Delete(Players[i]);
  3474. break;
  3475. }
  3476. }
  3477. }
  3478. /*------------------------------------------------------------------------
  3479. NET_MESSAGE: Someone is sending us a message
  3480. ------------------------------------------------------------------------*/
  3481. else if (GPacket.Command==NET_MESSAGE) {
  3482. sprintf(txt,Text_String (TXT_FROM), GPacket.Name, GPacket.Message.Buf);
  3483. magic_number = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-4));
  3484. crc = *((unsigned short*)(GPacket.Message.Buf + COMPAT_MESSAGE_LENGTH-2));
  3485. color = MPlayerID_To_ColorIndex(GPacket.Message.ID);
  3486. Messages.Add_Message (txt, MPlayerTColors[color],
  3487. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_FULLSHADOW, 1200, magic_number, crc);
  3488. retval = EV_MESSAGE;
  3489. }
  3490. return(retval);
  3491. }
  3492. /***************************************************************************
  3493. * Compute_Name_CRC -- computes CRC from char string *
  3494. * *
  3495. * INPUT: *
  3496. * name string to create CRC for *
  3497. * *
  3498. * OUTPUT: *
  3499. * CRC *
  3500. * *
  3501. * WARNINGS: *
  3502. * none. *
  3503. * *
  3504. * HISTORY: *
  3505. * 06/29/1995 BRR : Created. *
  3506. *=========================================================================*/
  3507. unsigned long Compute_Name_CRC(char *name)
  3508. {
  3509. char buf[80];
  3510. unsigned long crc = 0L;
  3511. int i;
  3512. strcpy (buf, name);
  3513. strupr (buf);
  3514. for (i = 0; i < (int)strlen(buf); i++) {
  3515. Add_CRC (&crc, (unsigned long)buf[i]);
  3516. }
  3517. return (crc);
  3518. }
  3519. /***************************************************************************
  3520. * Net_Reconnect_Dialog -- Draws/updates the network reconnect dialog *
  3521. * *
  3522. * INPUT: *
  3523. * reconn 1 = reconnect, 0 = waiting for first-time connection *
  3524. * fresh 1 = draw from scratch, 0 = only update time counter *
  3525. * oldest_index IPX connection index of oldest connection *
  3526. * (only used for reconnection) *
  3527. * timeval value to print in the countdown field *
  3528. * *
  3529. * OUTPUT: *
  3530. * none. *
  3531. * *
  3532. * WARNINGS: *
  3533. * none. *
  3534. * *
  3535. * HISTORY: *
  3536. * 07/08/1995 BRR : Created. *
  3537. *=========================================================================*/
  3538. void Net_Reconnect_Dialog(int reconn, int fresh, int oldest_index,
  3539. unsigned long timeval)
  3540. {
  3541. static int x,y,w,h;
  3542. int id;
  3543. char buf1[40] = {0};
  3544. char buf2[40] = {0};
  3545. char const *buf3 = "";
  3546. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  3547. int d_txt6_h = 6*factor+1;
  3548. int d_margin = 5*factor;
  3549. /*------------------------------------------------------------------------
  3550. Draw the dialog from scratch
  3551. ------------------------------------------------------------------------*/
  3552. if (fresh) {
  3553. Fancy_Text_Print ("", 0, 0, CC_GREEN, TBLACK,
  3554. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  3555. if (reconn) {
  3556. id = Ipx.Connection_ID(oldest_index);
  3557. sprintf(buf1,Text_String(TXT_RECONNECTING_TO),
  3558. Ipx.Connection_Name(id));
  3559. } else {
  3560. sprintf(buf1,Text_String(TXT_WAITING_FOR_CONNECTIONS));
  3561. }
  3562. sprintf(buf2,Text_String(TXT_TIME_ALLOWED), timeval + 1);
  3563. buf3 = Text_String(TXT_PRESS_ESC);
  3564. w = MAX(String_Pixel_Width(buf1),String_Pixel_Width(buf2));
  3565. w = MAX(String_Pixel_Width(buf3), (unsigned)w);
  3566. w += (d_margin * 4);
  3567. h = (d_txt6_h * 3) + (d_margin * 6);
  3568. x = 160*factor - (w / 2);
  3569. y = 100*factor - (h / 2);
  3570. Hide_Mouse();
  3571. Set_Logic_Page(SeenBuff);
  3572. Dialog_Box(x, y, w, h);
  3573. Fancy_Text_Print (buf1, 160*factor, y + (d_margin * 2), CC_GREEN, BLACK,
  3574. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  3575. Fancy_Text_Print (buf2, 160*factor, y + (d_margin * 2) + d_txt6_h + d_margin,
  3576. CC_GREEN, BLACK,
  3577. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  3578. Fancy_Text_Print (buf3, 160*factor, y + (d_margin * 2) + (d_txt6_h + d_margin) * 2,
  3579. CC_GREEN, BLACK,
  3580. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  3581. Show_Mouse();
  3582. } else {
  3583. /*------------------------------------------------------------------------
  3584. Just update the timeout value on the dialog
  3585. ------------------------------------------------------------------------*/
  3586. Hide_Mouse();
  3587. Set_Logic_Page(SeenBuff);
  3588. sprintf(buf2,Text_String(TXT_TIME_ALLOWED), timeval + 1);
  3589. int pixwidth = String_Pixel_Width (buf2);
  3590. LogicPage->Fill_Rect (160*factor - (pixwidth/2) - 12, y+(d_margin*2) + d_txt6_h + d_margin,
  3591. 160*factor + (pixwidth/2) + 12, y+(d_margin*2) + d_txt6_h*2 + d_margin,
  3592. TBLACK);
  3593. Fancy_Text_Print (buf2, 160*factor, y + (d_margin * 2) + d_txt6_h + d_margin,
  3594. CC_GREEN, BLACK,
  3595. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  3596. Show_Mouse();
  3597. }
  3598. }
  3599. /***********************************************************************************************
  3600. * Wait_For_Focus -- Wait for game to be in focus before proceeding *
  3601. * *
  3602. * *
  3603. * *
  3604. * INPUT: Nothing *
  3605. * *
  3606. * OUTPUT: Nothing *
  3607. * *
  3608. * WARNINGS: None *
  3609. * *
  3610. * HISTORY: *
  3611. * 1/6/97 3:23PM ST : Created *
  3612. *=============================================================================================*/
  3613. void Wait_For_Focus (void)
  3614. {
  3615. CountDownTimerClass focus_timer;
  3616. focus_timer.Set(5*60);
  3617. ShowWindow ( MainWindow, SW_SHOWMAXIMIZED );
  3618. /*
  3619. ** Process the message loop until we are in focus.
  3620. */
  3621. if (!GameInFocus){
  3622. CCDebugString ("C&C95 - Waiting for game to come into focus.");
  3623. do {
  3624. CCDebugString (".");
  3625. Keyboard::Check();
  3626. if (!focus_timer.Time()){
  3627. CCDebugString ("C&C95 - Calling SetForgroundWindow.\n");
  3628. SetForegroundWindow ( MainWindow );
  3629. CCDebugString ("C&C95 - Calling ShowWindow.\n");
  3630. ShowWindow ( MainWindow, SW_SHOWMAXIMIZED );
  3631. focus_timer.Set(5*60);
  3632. }
  3633. }while (!GameInFocus);
  3634. CCDebugString ("\n");
  3635. AllSurfaces.SurfacesRestored=FALSE;
  3636. }
  3637. }
  3638. extern bool Spawn_WChat(bool can_launch);
  3639. /***********************************************************************************************
  3640. * Net_Fake_New_Dialog -- Just like Net_New_Dialog but without the Dialog. For internet play *
  3641. * *
  3642. * This 'dialog' does all the non-dialog game set up stuff that is done in the normal *
  3643. * network game set up dialog. The only visible button is 'cancel' *
  3644. * *
  3645. * INPUT: Nothing *
  3646. * *
  3647. * OUTPUT: true if successfully connected *
  3648. * *
  3649. * WARNINGS: None *
  3650. * *
  3651. * HISTORY: *
  3652. * 5/24/96 10:34AM ST : Created *
  3653. *=============================================================================================*/
  3654. static int Net_Fake_New_Dialog(void)
  3655. {
  3656. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  3657. int d_dialog_w = 120*factor; // dialog width
  3658. int d_dialog_h = 80*factor; // dialog height
  3659. int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord
  3660. int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord
  3661. int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord
  3662. //d_playerlist_w = 100;
  3663. int d_playerlist_w = 106*factor;
  3664. int d_playerlist_h = 27*factor;
  3665. //int d_playerlist_x = 10 * factor; //off screen
  3666. int d_playerlist_x = 500*factor; //10 * factor; //off screen
  3667. int d_playerlist_y = d_dialog_y + 20;
  3668. #if (GERMAN | FRENCH)
  3669. int d_cancel_w = 50*factor;
  3670. #else
  3671. int d_cancel_w = 45*factor;
  3672. #endif
  3673. int d_cancel_h = 9*factor;
  3674. int d_cancel_x = d_dialog_cx - (d_cancel_w / 2);
  3675. int d_cancel_y = d_dialog_y + d_dialog_h - 20*factor;
  3676. #if (GERMAN | FRENCH)
  3677. int width=160*factor;
  3678. int height=80*factor;
  3679. #else
  3680. int width=120*factor;
  3681. int height=80*factor;
  3682. #endif //GERMAN | FRENCH
  3683. bool player_joined = false;
  3684. CountDownTimerClass join_timer;
  3685. Fancy_Text_Print(TXT_NONE,0,0,TBLACK,TBLACK,TPF_6PT_GRAD | TPF_NOSHADOW);
  3686. Format_Window_String((char*)Text_String(TXT_CONNECTING), SeenBuff.Get_Height(), width, height);
  3687. #if (GERMAN | FRENCH)
  3688. d_dialog_w = width + 25*factor;
  3689. d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord
  3690. d_cancel_x = d_dialog_cx - (d_cancel_w / 2);
  3691. #endif
  3692. /*........................................................................
  3693. Button Enumerations
  3694. ........................................................................*/
  3695. enum {
  3696. BUTTON_CANCEL = 100,
  3697. BUTTON_PLAYERLIST,
  3698. };
  3699. /*........................................................................
  3700. Redraw values: in order from "top" to "bottom" layer of the dialog
  3701. ........................................................................*/
  3702. typedef enum {
  3703. REDRAW_NONE = 0,
  3704. REDRAW_MESSAGE,
  3705. REDRAW_BUTTONS,
  3706. REDRAW_BACKGROUND,
  3707. REDRAW_ALL = REDRAW_BACKGROUND
  3708. } RedrawType;
  3709. /*........................................................................
  3710. Dialog variables
  3711. ........................................................................*/
  3712. RedrawType display = REDRAW_ALL; // redraw level
  3713. bool process = true; // process while true
  3714. KeyNumType input;
  3715. char credbuf[CREDITSBUF_MAX]; // for credit edit box
  3716. int old_cred; // old value in credits buffer
  3717. int transmit; // 1 = re-transmit new game options
  3718. long ok_timer = 0; // for timing OK button
  3719. int rc;
  3720. int i,j;
  3721. char *item;
  3722. int tabs[] = {77*factor}; // tabs for player list box
  3723. long ping_timer = 0; // for sending Ping packets
  3724. unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's
  3725. int min_index; // for sorting player ID's
  3726. unsigned char min_id; // for sorting player ID's
  3727. unsigned char id; // connection ID
  3728. JoinEventType whahoppa; // event generated by received packets
  3729. void const *up_button;
  3730. void const *down_button;
  3731. if (InMainLoop){
  3732. up_button = Hires_Retrieve("BTN-UP.SHP");
  3733. down_button = Hires_Retrieve("BTN-DN.SHP");
  3734. }else{
  3735. up_button = Hires_Retrieve("BTN-UP2.SHP");
  3736. down_button = Hires_Retrieve("BTN-DN2.SHP");
  3737. }
  3738. /*........................................................................
  3739. Buttons
  3740. ........................................................................*/
  3741. GadgetClass *commands; // button list
  3742. ColorListClass playerlist(BUTTON_PLAYERLIST,
  3743. d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h,
  3744. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  3745. up_button,
  3746. down_button);
  3747. TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL,
  3748. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  3749. //#if (GERMAN | FRENCH)
  3750. // d_cancel_x, d_cancel_y);
  3751. //#else
  3752. d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h);
  3753. //#endif
  3754. CCDebugString ("C&C95 - In new game dialog - initialising lists.\n");
  3755. /*
  3756. ------------------------- Build the button list --------------------------
  3757. */
  3758. commands = &playerlist;
  3759. cancelbtn.Add_Tail(*commands);
  3760. playerlist.Set_Tabs(tabs);
  3761. /*
  3762. ----------------------------- Various Inits ------------------------------
  3763. */
  3764. sprintf(credbuf, "%d", MPlayerCredits);
  3765. old_cred = MPlayerCredits;
  3766. /*........................................................................
  3767. Init other scenario parameters
  3768. ........................................................................*/
  3769. Special.IsTGrowth = MPlayerTiberium;
  3770. Special.IsTSpread = MPlayerTiberium;
  3771. transmit = 0;
  3772. /*........................................................................
  3773. Init player color-used flags
  3774. ........................................................................*/
  3775. for (i = 0; i < MAX_MPLAYER_COLORS; i++) {
  3776. ColorUsed[i] = 0; // init all colors to available
  3777. }
  3778. ColorUsed[MPlayerColorIdx] = 1; // set my color to used
  3779. playerlist.Set_Selected_Style(ColorListClass::SELECT_BAR, CC_GREEN_SHADOW);
  3780. /*........................................................................
  3781. Init random-number generator, & create a seed to be used for all random
  3782. numbers from here on out
  3783. ........................................................................*/
  3784. //ST - 12/18/2018 11:37AM
  3785. //randomize();
  3786. //Seed = rand();
  3787. /*------------------------------------------------------------------------
  3788. Add myself to the list. Note that since I'm not in the Players Vector,
  3789. the Vector & listbox are now 1 out of sync.
  3790. ------------------------------------------------------------------------*/
  3791. item = new char [MPLAYER_NAME_MAX + 4];
  3792. if (MPlayerHouse==HOUSE_GOOD) {
  3793. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I));
  3794. } else {
  3795. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D));
  3796. }
  3797. playerlist.Add_Item(item, MPlayerTColors[MPlayerColorIdx]);
  3798. Wait_For_Focus();
  3799. CCDebugString ("C&C95 - About to uncompress title page.\n");
  3800. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  3801. Blit_Hid_Page_To_Seen_Buff();
  3802. CCDebugString ("C&C95 - About to set the palette.\n");
  3803. Set_Palette(Palette);
  3804. CCDebugString ("C&C95 - Palette was set OK.\n");
  3805. if (LogicPage != &SeenBuff && LogicPage!= &HidPage){
  3806. CCDebugString ("C&C95 - Logic page invalid");
  3807. Set_Logic_Page (SeenBuff);
  3808. }
  3809. char a_buffer [128];
  3810. sprintf (a_buffer, "Number of players:%d", Players.Count());
  3811. CCDebugString (a_buffer);
  3812. #ifdef VIRTUAL_SUBNET_SERVER
  3813. /*
  3814. ** Send a bogus packet to wake up the VSS
  3815. */
  3816. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3817. GPacket.Command = (NetCommandType)50; //Invalid command
  3818. strcpy (GPacket.Name, MPlayerName);
  3819. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType), 0, NULL);
  3820. #endif //VIRTUAL_SUBNET_SERVER
  3821. CCDebugString ("C&C95 - About to reveal mouse\n");
  3822. while (Get_Mouse_State() > 0) Show_Mouse();
  3823. /*
  3824. ---------------------------- Processing loop -----------------------------
  3825. */
  3826. CCDebugString ("C&C95 - Entering join dialogue loop\n");
  3827. while (process) {
  3828. /*
  3829. ** If we have just received input focus again after running in the background then
  3830. ** we need to redraw.
  3831. */
  3832. if (AllSurfaces.SurfacesRestored){
  3833. AllSurfaces.SurfacesRestored=FALSE;
  3834. display=REDRAW_ALL;
  3835. }
  3836. /*
  3837. ...................... Refresh display if needed ......................
  3838. */
  3839. if (display) {
  3840. Hide_Mouse();
  3841. /*
  3842. .................. Redraw backgound & dialog box ...................
  3843. */
  3844. if (display >= REDRAW_BACKGROUND) {
  3845. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  3846. Blit_Hid_Page_To_Seen_Buff();
  3847. Set_Palette(Palette);
  3848. Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
  3849. /*...............................................................
  3850. Dialog & Field labels
  3851. ...............................................................*/
  3852. Draw_Caption (TXT_NONE, d_dialog_x, d_dialog_y, d_dialog_w);
  3853. Fancy_Text_Print(TXT_CONNECTING, d_dialog_cx-width/2, d_dialog_y + 25*factor, CC_GREEN, TBLACK,
  3854. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  3855. }
  3856. /*
  3857. .......................... Redraw buttons ..........................
  3858. */
  3859. if (display >= REDRAW_BUTTONS) {
  3860. commands->Draw_All();
  3861. }
  3862. Show_Mouse();
  3863. display = REDRAW_NONE;
  3864. }
  3865. /*
  3866. ........................... Get user input ............................
  3867. */
  3868. input = commands->Input();
  3869. /*
  3870. ---------------------------- Process input ----------------------------
  3871. */
  3872. switch (input) {
  3873. /*------------------------------------------------------------------
  3874. CANCEL: send a SIGN_OFF, bail out with error code
  3875. ------------------------------------------------------------------*/
  3876. case (KN_ESC):
  3877. case (BUTTON_CANCEL | KN_BUTTON):
  3878. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3879. GPacket.Command = NET_SIGN_OFF;
  3880. strcpy (GPacket.Name, MPlayerName);
  3881. /*...............................................................
  3882. Broadcast my sign-off over my network
  3883. ...............................................................*/
  3884. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3885. 0, NULL);
  3886. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3887. 0, NULL);
  3888. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  3889. /*...............................................................
  3890. Broadcast my sign-off over a bridged network if there is one
  3891. ...............................................................*/
  3892. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  3893. /*...............................................................
  3894. And now, just be absolutely sure, send my sign-off to each
  3895. player in my game. (If there's a bridge between us, the other
  3896. player will have specified my address, so he can cross the
  3897. bridge; but I may not have specified a bridge address, so the
  3898. only way I have of crossing the bridge is to send a packet
  3899. directly to him.)
  3900. ...............................................................*/
  3901. for (i = 0; i < Players.Count(); i++) {
  3902. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  3903. &(Players[i]->Address));
  3904. Ipx.Service();
  3905. }
  3906. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  3907. MPlayerGameName[0] = 0;
  3908. process = false;
  3909. rc = false;
  3910. Send_Data_To_DDE_Server ("Hello", strlen("Hello"), DDEServerClass::DDE_CONNECTION_FAILED);
  3911. GameStatisticsPacketSent = false;
  3912. Spawn_WChat(false);
  3913. break;
  3914. /*------------------------------------------------------------------
  3915. default: exit loop with TRUE status
  3916. ------------------------------------------------------------------*/
  3917. default:
  3918. #ifdef VIRTUAL_SUBNET_SERVER
  3919. if (Players.Count() == InternetMaxPlayers-1){
  3920. #else //VIRTUAL_SUBNET_SERVER
  3921. if (Players.Count() > 0){
  3922. #endif // VIRTUAL_SUBNET_SERVER
  3923. //char ddkks[128];
  3924. //sprintf (ddkks, "C&C95 - Players.Count() = %d\n", Players.Count());
  3925. //CCDebugString (ddkks);
  3926. /*
  3927. ** Wait for several secs after receiving request to join before sending
  3928. ** start game packet
  3929. */
  3930. if (!player_joined){
  3931. player_joined = true;
  3932. join_timer.Set (3*60, true);
  3933. break;
  3934. }else{
  3935. if (join_timer.Time()) break;
  3936. }
  3937. CCDebugString ("C&C95 - Join timer expired\n");
  3938. /*...............................................................
  3939. If a new player has joined in the last second, don't allow
  3940. an OK; force a wait longer than 2 seconds (to give all players
  3941. a chance to know about this new guy)
  3942. ...............................................................*/
  3943. i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)120);
  3944. while (TickCount.Time() - ok_timer < i)
  3945. Ipx.Service();
  3946. /*...............................................................
  3947. If there are at least 2 players, go ahead & play; error otherwise
  3948. ...............................................................*/
  3949. if (MPlayerSolo || Players.Count() > 0) {
  3950. rc = TRUE;
  3951. process = FALSE;
  3952. } else {
  3953. CCMessageBox().Process (TXT_ONLY_ONE,TXT_OOPS,NULL);
  3954. display = REDRAW_ALL;
  3955. }
  3956. }
  3957. break;
  3958. }
  3959. /*---------------------------------------------------------------------
  3960. Process incoming packets
  3961. ---------------------------------------------------------------------*/
  3962. whahoppa = Get_NewGame_Responses(&playerlist);
  3963. if (whahoppa == EV_NEW_PLAYER) {
  3964. ok_timer = TickCount.Time();
  3965. transmit = 1;
  3966. } else {
  3967. if (whahoppa == EV_MESSAGE) {
  3968. display = REDRAW_MESSAGE;
  3969. }
  3970. }
  3971. /*---------------------------------------------------------------------
  3972. If our Transmit flag is set, we need to send out a game option packet
  3973. ---------------------------------------------------------------------*/
  3974. if (transmit) {
  3975. for (i = 0; i < Players.Count(); i++) {
  3976. memset (&GPacket, 0, sizeof(GlobalPacketType));
  3977. GPacket.Command = NET_GAME_OPTIONS;
  3978. GPacket.ScenarioInfo.Scenario = ScenarioIdx; //MPlayerFilenum[ScenarioIdx];
  3979. GPacket.ScenarioInfo.Credits = MPlayerCredits;
  3980. GPacket.ScenarioInfo.IsBases = MPlayerBases;
  3981. GPacket.ScenarioInfo.IsTiberium = MPlayerTiberium;
  3982. GPacket.ScenarioInfo.IsGoodies = MPlayerGoodies;
  3983. GPacket.ScenarioInfo.IsGhosties = MPlayerGhosts;
  3984. GPacket.ScenarioInfo.BuildLevel = BuildLevel;
  3985. GPacket.ScenarioInfo.UnitCount = MPlayerUnitCount;
  3986. GPacket.ScenarioInfo.Seed = Seed;
  3987. GPacket.ScenarioInfo.Special = Special;
  3988. GPacket.ScenarioInfo.GameSpeed = Options.GameSpeed;
  3989. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  3990. 1, &(Players[i]->Address) );
  3991. }
  3992. transmit = 0;
  3993. }
  3994. /*---------------------------------------------------------------------
  3995. Ping every player in my game, to force the Global Channel to measure
  3996. the connection response time.
  3997. ---------------------------------------------------------------------*/
  3998. if (TickCount.Time() - ping_timer > 15) {
  3999. memset (&GPacket, 0, sizeof(GlobalPacketType));
  4000. GPacket.Command = NET_PING;
  4001. for (i = 0; i < Players.Count(); i++) {
  4002. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  4003. 1, &(Players[i]->Address) );
  4004. }
  4005. ping_timer = TickCount.Time();
  4006. }
  4007. /*---------------------------------------------------------------------
  4008. Service the Ipx connections
  4009. ---------------------------------------------------------------------*/
  4010. Ipx.Service();
  4011. /*---------------------------------------------------------------------
  4012. Service the sounds & score; GameActive must be false at this point,
  4013. so Call_Back() doesn't intercept global messages from me!
  4014. ---------------------------------------------------------------------*/
  4015. Call_Back();
  4016. } /* end of while */
  4017. CCDebugString ("C&C95 - Exited process loop\n");
  4018. /*------------------------------------------------------------------------
  4019. Establish connections with all other players.
  4020. ------------------------------------------------------------------------*/
  4021. if (rc) {
  4022. /*.....................................................................
  4023. Set the number of players in this game, and my ID
  4024. .....................................................................*/
  4025. MPlayerCount = Players.Count() + 1;
  4026. MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse);
  4027. /*.....................................................................
  4028. Get the scenario filename
  4029. .....................................................................*/
  4030. Scenario = ScenarioIdx; //PlayerFilenum[ScenarioIdx]; We are passed actual number now from wchat not index from
  4031. //Scenario = MPlayerFilenum[ScenarioIdx];
  4032. /*.....................................................................
  4033. Compute frame delay value for packet transmissions:
  4034. - Divide global channel's response time by 8 (2 to convert to 1-way
  4035. value, 4 more to convert from ticks to frames)
  4036. .....................................................................*/
  4037. MPlayerMaxAhead = MAX( (Ipx.Global_Response_Time() / 8), (unsigned long)2);
  4038. /*.....................................................................
  4039. Send all players the NET_GO packet. Wait until all ACK's have been
  4040. received.
  4041. .....................................................................*/
  4042. CCDebugString ("C&C95 - Sending the 'GO' packet\n");
  4043. memset (&GPacket, 0, sizeof(GlobalPacketType));
  4044. GPacket.Command = NET_GO;
  4045. GPacket.ResponseTime.OneWay = MPlayerMaxAhead;
  4046. for (i = 0; i < Players.Count(); i++) {
  4047. char flopbuf [128];
  4048. sprintf (flopbuf, "Sending 'GO' packet to address %d\n", *((unsigned short*)&(Players[i]->Address)));
  4049. CCDebugString (flopbuf);
  4050. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  4051. 1, &(Players[i]->Address) );
  4052. /*..................................................................
  4053. Wait for all the ACK's to come in.
  4054. ..................................................................*/
  4055. while (Ipx.Global_Num_Send() > 0)
  4056. Ipx.Service();
  4057. }
  4058. /*.....................................................................
  4059. Form connections with all other players. Form the IPX Connection ID
  4060. from the player's Color (high byte) and House (low byte). This
  4061. will let us extract any player's color & house at any time.
  4062. Fill in 'tmp_id' while we're doing this.
  4063. .....................................................................*/
  4064. for (i = 0; i < Players.Count(); i++) {
  4065. id = Build_MPlayerID (Players[i]->Player.Color,
  4066. Players[i]->Player.House);
  4067. tmp_id[i] = id;
  4068. Ipx.Create_Connection(id, Players[i]->Name, &(Players[i]->Address) );
  4069. }
  4070. #ifdef VIRTUAL_SUBNET_SERVER
  4071. CCDebugString ("C&C95 - Creating connection to the VSS\n");
  4072. /*
  4073. ** Create an additional connection to the VSS
  4074. */
  4075. if (UseVirtualSubnetServer){
  4076. IPXAddressClass vss_global_address;
  4077. NetNodeType vss_node;
  4078. NetNumType vss_net;
  4079. memset (vss_net, 1, sizeof (vss_net));
  4080. memset (vss_node, 0, sizeof (vss_node));
  4081. vss_global_address.Set_Address(vss_net, vss_node);
  4082. Ipx.Create_Connection( VSS_ID, "VSS", &vss_global_address);
  4083. }
  4084. #endif //VIRTUAL_SUBNET_SERVER
  4085. tmp_id[i] = MPlayerLocalID;
  4086. /*.....................................................................
  4087. Store every player's ID in the MPlayerID[] array. This array will
  4088. determine the order of event execution, so the ID's must be stored
  4089. in the same order on all systems.
  4090. .....................................................................*/
  4091. for (i = 0; i < MPlayerCount; i++) {
  4092. min_index = 0;
  4093. min_id = 0xff;
  4094. for (j = 0; j < MPlayerCount; j++) {
  4095. if (tmp_id[j] < min_id) {
  4096. min_id = tmp_id[j];
  4097. min_index = j;
  4098. }
  4099. }
  4100. MPlayerID[i] = tmp_id[min_index];
  4101. tmp_id[min_index] = 0xff;
  4102. }
  4103. /*.....................................................................
  4104. Fill in the array of player names, including my own.
  4105. .....................................................................*/
  4106. for (i = 0; i < MPlayerCount; i++) {
  4107. if (MPlayerID[i] == MPlayerLocalID) {
  4108. strcpy (MPlayerNames[i], MPlayerName);
  4109. } else {
  4110. strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i]));
  4111. }
  4112. }
  4113. }
  4114. /*------------------------------------------------------------------------
  4115. Init network timing values, using previous response times as a measure
  4116. of what our retry delta & timeout should be.
  4117. ------------------------------------------------------------------------*/
  4118. Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1,
  4119. Ipx.Global_Response_Time() * 4);
  4120. /*------------------------------------------------------------------------
  4121. Clear all lists
  4122. ------------------------------------------------------------------------*/
  4123. Clear_Player_List(&playerlist);
  4124. /*------------------------------------------------------------------------
  4125. Restore screen
  4126. ------------------------------------------------------------------------*/
  4127. Hide_Mouse();
  4128. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  4129. Blit_Hid_Page_To_Seen_Buff();
  4130. Show_Mouse();
  4131. if (rc){
  4132. Wait_For_Focus();
  4133. }
  4134. return(rc);
  4135. }
  4136. /***********************************************************************************************
  4137. * Net_Fake_Join_Dialog -- Like Net_Join_Dialog but with no dialogs. For Internet Play. *
  4138. * *
  4139. * This 'dialog' does all the non-dialog game set up stuff that is done in the normal *
  4140. * network game set up dialog. The only visible button is 'cancel' *
  4141. * *
  4142. * *
  4143. * INPUT: Nothing *
  4144. * *
  4145. * OUTPUT: 0 = good, -1 = bad *
  4146. * *
  4147. * WARNINGS: None *
  4148. * *
  4149. * HISTORY: *
  4150. * 5/24/96 11:07AM ST : Created *
  4151. *=============================================================================================*/
  4152. static int Net_Fake_Join_Dialog(void)
  4153. {
  4154. int factor = (SeenBuff.Get_Width() == 320) ? 1 : 2;
  4155. /*........................................................................
  4156. Dialog & button dimensions
  4157. ........................................................................*/
  4158. /* ###Change collision detected! C:\PROJECTS\CODE\NETDLG.CPP... */
  4159. int d_dialog_w = 120 *factor; // dialog width
  4160. int d_dialog_h = 80*factor; // dialog height
  4161. int d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord
  4162. int d_dialog_y = ((200*factor - d_dialog_h) / 2); // centered y-coord
  4163. int d_dialog_cx = d_dialog_x + (d_dialog_w / 2); // center x-coord
  4164. int d_margin1=10;
  4165. int d_txt6_h=15;
  4166. int d_gamelist_w = 160*factor;
  4167. int d_gamelist_h = 27*factor;
  4168. int d_gamelist_x = 500*factor; //230*factor; //Off screen
  4169. //int d_gamelist_x = 230*factor; //Off screen
  4170. int d_gamelist_y = d_dialog_y + 20;
  4171. int d_playerlist_w = 106*factor;
  4172. int d_playerlist_h = 27*factor;
  4173. //int d_playerlist_x = 10 * factor; //Off screen
  4174. int d_playerlist_x = 500*factor; //10 * factor; //Off screen
  4175. int d_playerlist_y = d_gamelist_y + 20;
  4176. #if (GERMAN | FRENCH)
  4177. int d_cancel_w = 50*factor;
  4178. #else
  4179. int d_cancel_w = 45*factor;
  4180. #endif
  4181. int d_cancel_h = 9*factor;
  4182. int d_cancel_x = d_dialog_cx - d_cancel_w / 2;
  4183. int d_cancel_y = d_dialog_y + d_dialog_h - 20*factor;
  4184. bool ready_to_go = false;
  4185. #if (GERMAN | FRENCH)
  4186. int width=160*factor;
  4187. int height=80*factor;
  4188. #else
  4189. int width=120*factor;
  4190. int height=80*factor;
  4191. #endif //GERMAN | FRENCH
  4192. Fancy_Text_Print(TXT_NONE,0,0,TBLACK,TBLACK,TPF_6PT_GRAD | TPF_NOSHADOW);
  4193. Format_Window_String((char*)Text_String(TXT_CONNECTING), SeenBuff.Get_Height(), width, height);
  4194. #if (GERMAN | FRENCH)
  4195. d_dialog_w = width + 25*factor;
  4196. d_dialog_x = ((320*factor - d_dialog_w) / 2); // dialog x-coord
  4197. d_cancel_x = d_dialog_cx - (d_cancel_w / 2);
  4198. #endif
  4199. /*........................................................................
  4200. Button Enumerations
  4201. ........................................................................*/
  4202. enum {
  4203. BUTTON_CANCEL = 100,
  4204. BUTTON_GAMELIST,
  4205. BUTTON_PLAYERLIST,
  4206. };
  4207. /*........................................................................
  4208. Redraw values: in order from "top" to "bottom" layer of the dialog
  4209. ........................................................................*/
  4210. typedef enum {
  4211. REDRAW_NONE = 0,
  4212. REDRAW_MESSAGE,
  4213. REDRAW_COLORS,
  4214. REDRAW_BUTTONS,
  4215. REDRAW_BACKGROUND,
  4216. REDRAW_ALL = REDRAW_BACKGROUND
  4217. } RedrawType;
  4218. /*........................................................................
  4219. Dialog variables
  4220. ........................................................................*/
  4221. RedrawType display = REDRAW_ALL; // redraw level
  4222. bool process = true; // process while true
  4223. KeyNumType input;
  4224. JoinStateType joinstate = JOIN_NOTHING; // current "state" of this dialog
  4225. char namebuf[MPLAYER_NAME_MAX] = {0}; // buffer for player's name
  4226. int game_index = -1; // index of currently-selected game
  4227. int join_index = -1; // index of game we're joining
  4228. int rc = 0; // -1 = user cancelled, 1 = New
  4229. JoinEventType event; // event from incoming packet
  4230. int i,j; // loop counter
  4231. int parms_received; // 1 = game options received
  4232. unsigned char tmp_id[MAX_PLAYERS]; // temp storage for sorting player ID's
  4233. int min_index; // for sorting player ID's
  4234. unsigned char min_id; // for sorting player ID's
  4235. unsigned char id; // connection ID
  4236. char * item;
  4237. unsigned long starttime;
  4238. NodeNameType *who;
  4239. void const *up_button;
  4240. void const *down_button;
  4241. if (InMainLoop){
  4242. up_button = Hires_Retrieve("BTN-UP.SHP");
  4243. down_button = Hires_Retrieve("BTN-DN.SHP");
  4244. }else{
  4245. up_button = Hires_Retrieve("BTN-UP2.SHP");
  4246. down_button = Hires_Retrieve("BTN-DN2.SHP");
  4247. }
  4248. /*........................................................................
  4249. Buttons
  4250. ........................................................................*/
  4251. GadgetClass *commands; // button list
  4252. ColorListClass playerlist(BUTTON_PLAYERLIST,
  4253. d_playerlist_x, d_playerlist_y, d_playerlist_w, d_playerlist_h,
  4254. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  4255. up_button,
  4256. down_button);
  4257. ListClass gamelist(BUTTON_GAMELIST,
  4258. d_gamelist_x, d_gamelist_y, d_gamelist_w, d_gamelist_h,
  4259. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  4260. up_button,
  4261. down_button);
  4262. TextButtonClass cancelbtn(BUTTON_CANCEL, TXT_CANCEL,
  4263. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW,
  4264. //#if (GERMAN | FRENCH)
  4265. // d_cancel_x, d_cancel_y);
  4266. //#else
  4267. d_cancel_x, d_cancel_y, d_cancel_w, d_cancel_h);
  4268. //#endif
  4269. /*
  4270. ----------------------------- Various Inits ------------------------------
  4271. */
  4272. //MPlayerColorIdx = MPlayerPrefColor; // init my preferred color
  4273. playerlist.Set_Selected_Style(ColorListClass::SELECT_NONE);
  4274. Fancy_Text_Print("", 0, 0, CC_GREEN, TBLACK,
  4275. TPF_CENTER | TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  4276. /*
  4277. --------------------------- Send network query ---------------------------
  4278. */
  4279. CCDebugString ("C&C95 - About to call Send_Join_Queries.\n");
  4280. Send_Join_Queries (game_index, 1, 0);
  4281. Wait_For_Focus();
  4282. CCDebugString ("C&C95 - About to uncompress title page.\n");
  4283. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  4284. Blit_Hid_Page_To_Seen_Buff();
  4285. CCDebugString ("C&C95 - About to set the palette.\n");
  4286. Set_Palette(Palette);
  4287. CCDebugString ("C&C95 - Palette was set OK.\n");
  4288. if (LogicPage != &SeenBuff && LogicPage!= &HidPage){
  4289. CCDebugString ("C&C95 - Logic page invalid\n");
  4290. Set_Logic_Page (SeenBuff);
  4291. }
  4292. char a_buffer [128];
  4293. sprintf (a_buffer, "C&C95 - Number of players:%d\n", Players.Count());
  4294. CCDebugString (a_buffer);
  4295. /*
  4296. ---------------------------- Init Mono Output ----------------------------
  4297. */
  4298. CCDebugString ("C&C95 - About to reveal mouse\n");
  4299. while (Get_Mouse_State() > 0) Show_Mouse();
  4300. /*
  4301. ---------------------------- Processing loop -----------------------------
  4302. */
  4303. CCDebugString ("C&C95 - Entering join dialogue loop\n");
  4304. while (process) {
  4305. /*
  4306. ** If we have just received input focus again after running in the background then
  4307. ** we need to redraw.
  4308. */
  4309. if (AllSurfaces.SurfacesRestored){
  4310. AllSurfaces.SurfacesRestored=FALSE;
  4311. display=REDRAW_ALL;
  4312. }
  4313. /*
  4314. ...................... Refresh display if needed ......................
  4315. */
  4316. if (display) {
  4317. Hide_Mouse();
  4318. /*
  4319. .................. Redraw backgound & dialog box ...................
  4320. */
  4321. if (display >= REDRAW_BACKGROUND) {
  4322. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  4323. Blit_Hid_Page_To_Seen_Buff();
  4324. Set_Palette(Palette);
  4325. Dialog_Box(d_dialog_x, d_dialog_y, d_dialog_w, d_dialog_h);
  4326. /*...............................................................
  4327. Dialog & Field labels
  4328. ...............................................................*/
  4329. Draw_Caption (TXT_NONE, d_dialog_x, d_dialog_y, d_dialog_w);
  4330. Fancy_Text_Print(TXT_CONNECTING, d_dialog_cx-width/2, d_dialog_y + 25*factor, CC_GREEN, TBLACK,
  4331. TPF_6PT_GRAD | TPF_USE_GRAD_PAL | TPF_NOSHADOW);
  4332. /*
  4333. .................... Rebuild the button list ....................
  4334. */
  4335. cancelbtn.Zap();
  4336. gamelist.Zap();
  4337. playerlist.Zap();
  4338. commands = &cancelbtn;
  4339. gamelist.Add_Tail(*commands);
  4340. playerlist.Add_Tail(*commands);
  4341. }
  4342. /*
  4343. .......................... Redraw buttons ..........................
  4344. */
  4345. if (display >= REDRAW_BUTTONS) {
  4346. commands->Draw_All();
  4347. }
  4348. Show_Mouse();
  4349. display = REDRAW_NONE;
  4350. }
  4351. /*
  4352. ........................... Get user input ............................
  4353. */
  4354. input = commands->Input();
  4355. /*
  4356. ---------------------------- Process input ----------------------------
  4357. */
  4358. switch (input) {
  4359. /*------------------------------------------------------------------
  4360. CANCEL: send a SIGN_OFF
  4361. - If we're part of a game, stay in this dialog; otherwise, exit
  4362. ------------------------------------------------------------------*/
  4363. case (KN_ESC):
  4364. case (BUTTON_CANCEL | KN_BUTTON):
  4365. memset (&GPacket, 0, sizeof(GlobalPacketType));
  4366. GPacket.Command = NET_SIGN_OFF;
  4367. strcpy(GPacket.Name,MPlayerName);
  4368. /*...............................................................
  4369. If we're joined to a game, make extra sure the other players in
  4370. that game know I'm exiting; send my SIGN_OFF as an ack-required
  4371. packet. Do not send this packet to myself (index 0).
  4372. ...............................................................*/
  4373. if (joinstate == JOIN_CONFIRMED) {
  4374. //
  4375. // Remove myself from the player list box
  4376. //
  4377. item = (char *)(playerlist.Get_Item(0));
  4378. playerlist.Remove_Item(item);
  4379. delete [] item;
  4380. playerlist.Flag_To_Redraw();
  4381. //
  4382. // Remove myself from the Players list
  4383. //
  4384. who = Players[0];
  4385. Players.Delete(0);
  4386. delete who;
  4387. for (i = 0; i < Players.Count(); i++) {
  4388. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  4389. &(Players[i]->Address));
  4390. Ipx.Service();
  4391. }
  4392. }
  4393. /*...............................................................
  4394. Now broadcast my SIGN_OFF so other players looking at this game
  4395. know I'm leaving.
  4396. ...............................................................*/
  4397. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  4398. 0, NULL);
  4399. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  4400. 0, NULL);
  4401. if (IsBridge) {
  4402. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  4403. &BridgeNet);
  4404. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  4405. &BridgeNet);
  4406. }
  4407. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  4408. Send_Data_To_DDE_Server ("Hello", strlen("Hello"), DDEServerClass::DDE_CONNECTION_FAILED);
  4409. GameStatisticsPacketSent = false;
  4410. Spawn_WChat(false);
  4411. process = false;
  4412. rc = -1;
  4413. #if (0)
  4414. if (joinstate != JOIN_CONFIRMED) {
  4415. process = false;
  4416. rc = -1;
  4417. } else {
  4418. MPlayerGameName[0] = 0;
  4419. joinstate = JOIN_NOTHING;
  4420. display = REDRAW_ALL;
  4421. }
  4422. #endif //(0)
  4423. break;
  4424. /*------------------------------------------------------------------
  4425. JOIN: send a join request packet & switch to waiting-for-confirmation
  4426. mode. (Request_To_Join fills in MPlayerName with my namebuf.)
  4427. ------------------------------------------------------------------*/
  4428. default:
  4429. if (joinstate == JOIN_NOTHING && Games.Count()!=0){
  4430. gamelist.Set_Selected_Index(0);
  4431. join_index = gamelist.Current_Index();
  4432. parms_received = 0;
  4433. if (Request_To_Join (MPlayerName, join_index, &playerlist, MPlayerHouse,
  4434. MPlayerColorIdx)) {
  4435. joinstate = JOIN_WAIT_CONFIRM;
  4436. } else {
  4437. display = REDRAW_ALL;
  4438. }
  4439. }
  4440. break;
  4441. }
  4442. /*---------------------------------------------------------------------
  4443. Resend our query packets
  4444. ---------------------------------------------------------------------*/
  4445. Send_Join_Queries(game_index, 0, 0);
  4446. /*---------------------------------------------------------------------
  4447. Process incoming packets
  4448. ---------------------------------------------------------------------*/
  4449. event = Get_Join_Responses(&joinstate, &gamelist, &playerlist,
  4450. join_index);
  4451. /*.....................................................................
  4452. If we've changed state, redraw everything; if we're starting the game,
  4453. break out of the loop. If we've just joined, send out a player query
  4454. so I'll get added to the list instantly.
  4455. .....................................................................*/
  4456. if (event == EV_STATE_CHANGE) {
  4457. display = REDRAW_ALL;
  4458. if (joinstate==JOIN_GAME_START) {
  4459. CCDebugString ("C&C95 - Received 'GO' packet\n");
  4460. ready_to_go = true;
  4461. } else {
  4462. /*..................................................................
  4463. If we're newly-confirmed, immediately send out a player query
  4464. ..................................................................*/
  4465. if (joinstate==JOIN_CONFIRMED) {
  4466. Clear_Player_List(&playerlist);
  4467. item = new char [MPLAYER_NAME_MAX + 4];
  4468. if (MPlayerHouse==HOUSE_GOOD) {
  4469. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_G_D_I));
  4470. } else {
  4471. sprintf(item,"%s\t%s",MPlayerName,Text_String(TXT_N_O_D));
  4472. }
  4473. playerlist.Add_Item (item, MPlayerTColors[MPlayerColorIdx]);
  4474. who = new NodeNameType;
  4475. strcpy(who->Name, MPlayerName);
  4476. who->Address = IPXAddressClass();
  4477. who->Player.House = MPlayerHouse;
  4478. who->Player.Color = MPlayerColorIdx;
  4479. Players.Add (who);
  4480. Send_Join_Queries (game_index, 0, 1);
  4481. } else {
  4482. /*..................................................................
  4483. If we've been rejected, clear any messages we may have been typing.
  4484. ..................................................................*/
  4485. if (joinstate==JOIN_REJECTED) {
  4486. //
  4487. // Remove myself from the player list box
  4488. //
  4489. item = (char *)(playerlist.Get_Item(0));
  4490. if (item){
  4491. playerlist.Remove_Item(item);
  4492. delete [] item;
  4493. playerlist.Flag_To_Redraw();
  4494. }
  4495. //
  4496. // Remove myself from the Players list
  4497. //
  4498. if (Players.Count()){
  4499. who = Players[0];
  4500. Players.Delete(0);
  4501. delete who;
  4502. }
  4503. }
  4504. }
  4505. }
  4506. } else
  4507. /*.....................................................................
  4508. If a new game is detected, and it's the first game on our list,
  4509. automatically send out a player query for that game.
  4510. .....................................................................*/
  4511. if (event == EV_NEW_GAME && gamelist.Count()==1) {
  4512. gamelist.Set_Selected_Index(0);
  4513. game_index = gamelist.Current_Index();
  4514. Send_Join_Queries (game_index, 0, 1);
  4515. } else
  4516. /*.....................................................................
  4517. If the game options have changed, print them.
  4518. .....................................................................*/
  4519. if (event == EV_GAME_OPTIONS) {
  4520. parms_received = 1;
  4521. display = REDRAW_MESSAGE;
  4522. } else
  4523. /*.....................................................................
  4524. Draw an incoming message
  4525. .....................................................................*/
  4526. if (event == EV_MESSAGE) {
  4527. display = REDRAW_MESSAGE;
  4528. } else
  4529. /*.....................................................................
  4530. A game before the one I've selected is gone, so we have a new index now.
  4531. 'game_index' must be kept set to the currently-selected list item, so
  4532. we send out queries for the currently-selected game. It's therefore
  4533. imperative that we detect any changes to the game list.
  4534. If we're joined in a game, we must decrement our game_index to keep
  4535. it aligned with the game we're joined to.
  4536. .....................................................................*/
  4537. if (event == EV_GAME_SIGNOFF) {
  4538. if (joinstate==JOIN_CONFIRMED) {
  4539. game_index--;
  4540. join_index--;
  4541. gamelist.Set_Selected_Index(join_index);
  4542. } else {
  4543. gamelist.Flag_To_Redraw();
  4544. Clear_Player_List(&playerlist);
  4545. game_index = gamelist.Current_Index();
  4546. Send_Join_Queries (game_index, 0, 1);
  4547. }
  4548. }
  4549. /*---------------------------------------------------------------------
  4550. Service the Ipx connections
  4551. ---------------------------------------------------------------------*/
  4552. Ipx.Service();
  4553. /*---------------------------------------------------------------------
  4554. Clean out the Game List; if an old entry is found:
  4555. - Remove it
  4556. - Clear the player list
  4557. - Send queries for the new selected game, if there is one
  4558. ---------------------------------------------------------------------*/
  4559. for (i = 0; i < Games.Count(); i++) {
  4560. if (TickCount.Time() - Games[i]->Game.LastTime > 400) {
  4561. Games.Delete(Games[i]);
  4562. item = (char *)(gamelist.Get_Item (i));
  4563. gamelist.Remove_Item (item);
  4564. delete [] item;
  4565. if (i <= game_index) {
  4566. gamelist.Flag_To_Redraw();
  4567. Clear_Player_List(&playerlist);
  4568. game_index = gamelist.Current_Index();
  4569. Send_Join_Queries (game_index, 0, 1);
  4570. }
  4571. }
  4572. }
  4573. /*
  4574. ** If we were flagged to start the game and we recognise both players then quit the loop
  4575. */
  4576. //char ddkks[128];
  4577. //sprintf (ddkks, "C&C95 - Players.Count() = %d\n", Players.Count());
  4578. //CCDebugString (ddkks);
  4579. if (ready_to_go){ // && Players.Count() == InternetMaxPlayers){
  4580. rc = 0;
  4581. process = false;
  4582. }
  4583. /*---------------------------------------------------------------------
  4584. Service the sounds & score; GameActive must be false at this point,
  4585. so Call_Back() doesn't intercept global messages from me!
  4586. ---------------------------------------------------------------------*/
  4587. Call_Back();
  4588. }
  4589. /*------------------------------------------------------------------------
  4590. Establish connections with all other players.
  4591. ------------------------------------------------------------------------*/
  4592. if (rc == 0) {
  4593. /*.....................................................................
  4594. If the other guys are playing a scenario I don't have (sniff), I can't
  4595. play. Try to bail gracefully.
  4596. .....................................................................*/
  4597. if (ScenarioIdx==-1) {
  4598. CCMessageBox().Process (TXT_UNABLE_PLAY_WAAUGH);
  4599. //
  4600. // Remove myself from the player list box
  4601. //
  4602. item = (char *)(playerlist.Get_Item(0));
  4603. playerlist.Remove_Item(item);
  4604. delete [] item;
  4605. playerlist.Flag_To_Redraw();
  4606. //
  4607. // Remove myself from the Players list
  4608. //
  4609. who = Players[0];
  4610. Players.Delete(0);
  4611. delete who;
  4612. memset (&GPacket, 0, sizeof(GlobalPacketType));
  4613. GPacket.Command = NET_SIGN_OFF;
  4614. strcpy (GPacket.Name, MPlayerName);
  4615. for (i = 0; i < Players.Count(); i++) {
  4616. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 1,
  4617. &(Players[i]->Address));
  4618. Ipx.Service();
  4619. }
  4620. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  4621. 0, NULL);
  4622. Ipx.Send_Global_Message (&GPacket, sizeof (GlobalPacketType),
  4623. 0, NULL);
  4624. if (IsBridge) {
  4625. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  4626. &BridgeNet);
  4627. Ipx.Send_Global_Message (&GPacket, sizeof(GlobalPacketType), 0,
  4628. &BridgeNet);
  4629. }
  4630. while (Ipx.Global_Num_Send() > 0 && Ipx.Service() != 0) ;
  4631. rc = -1;
  4632. } else {
  4633. /*..................................................................
  4634. Set the number of players in this game, and my ID
  4635. ..................................................................*/
  4636. MPlayerCount = Players.Count();
  4637. MPlayerLocalID = Build_MPlayerID (MPlayerColorIdx, MPlayerHouse);
  4638. /*..................................................................
  4639. Get the scenario number
  4640. ..................................................................*/
  4641. Scenario = ScenarioIdx; //PlayerFilenum[ScenarioIdx]; We are passed actual number now from wchat not index from
  4642. /*..................................................................
  4643. Form connections with all other players. Form the IPX Connection ID
  4644. from the player's Color and House. This will let us extract any
  4645. player's color & house at any time. Fill in 'tmp_id' while we're
  4646. doing this.
  4647. ..................................................................*/
  4648. for (i = 0; i < Players.Count(); i++) {
  4649. /*...............................................................
  4650. Only create the connection if it's not myself!
  4651. ...............................................................*/
  4652. if (strcmp (MPlayerName, Players[i]->Name)) {
  4653. id = Build_MPlayerID(Players[i]->Player.Color,
  4654. Players[i]->Player.House);
  4655. tmp_id[i] = id;
  4656. Ipx.Create_Connection((int)id, Players[i]->Name, &(Players[i]->Address) );
  4657. } else {
  4658. tmp_id[i] = MPlayerLocalID;
  4659. }
  4660. }
  4661. #ifdef VIRTUAL_SUBNET_SERVER
  4662. /*
  4663. ** Create an additional connection to the VSS
  4664. */
  4665. if (UseVirtualSubnetServer){
  4666. IPXAddressClass vss_global_address;
  4667. NetNodeType vss_node;
  4668. NetNumType vss_net;
  4669. memset (vss_net, 1, sizeof (vss_net));
  4670. memset (vss_node, 0, sizeof (vss_node));
  4671. vss_global_address.Set_Address(vss_net, vss_node);
  4672. Ipx.Create_Connection( VSS_ID, "VSS", &vss_global_address);
  4673. }
  4674. #endif //VIRTUAL_SUBNET_SERVER
  4675. /*..................................................................
  4676. Store every player's ID in the MPlayerID[] array. This array will
  4677. determine the order of event execution, so the ID's must be stored
  4678. in the same order on all systems.
  4679. ..................................................................*/
  4680. for (i = 0; i < MPlayerCount; i++) {
  4681. min_index = 0;
  4682. min_id = 0xff;
  4683. for (j = 0; j < MPlayerCount; j++) {
  4684. if (tmp_id[j] < min_id) {
  4685. min_id = tmp_id[j];
  4686. min_index = j;
  4687. }
  4688. }
  4689. MPlayerID[i] = tmp_id[min_index];
  4690. tmp_id[min_index] = 0xff;
  4691. }
  4692. /*..................................................................
  4693. Fill in the array of player names, including my own.
  4694. ..................................................................*/
  4695. for (i = 0; i < MPlayerCount; i++) {
  4696. if (MPlayerID[i] == MPlayerLocalID) {
  4697. strcpy (MPlayerNames[i], MPlayerName);
  4698. } else {
  4699. strcpy (MPlayerNames[i], Ipx.Connection_Name(MPlayerID[i]));
  4700. }
  4701. }
  4702. }
  4703. /*---------------------------------------------------------------------
  4704. Wait a while, polling the IPX service routines, to give our ACK
  4705. a chance to get to the other system. If he doesn't get our ACK, he'll
  4706. be waiting the whole time we load MIX files.
  4707. ---------------------------------------------------------------------*/
  4708. i = MAX(Ipx.Global_Response_Time() * 2, (unsigned long)120);
  4709. starttime = TickCount.Time();
  4710. while (TickCount.Time() - starttime < (unsigned)i) {
  4711. Ipx.Service();
  4712. }
  4713. }
  4714. /*------------------------------------------------------------------------
  4715. Init network timing values, using previous response times as a measure
  4716. of what our retry delta & timeout should be.
  4717. ------------------------------------------------------------------------*/
  4718. Ipx.Set_Timing (Ipx.Global_Response_Time() + 2, -1,
  4719. Ipx.Global_Response_Time() * 4);
  4720. /*------------------------------------------------------------------------
  4721. Clear all lists
  4722. ------------------------------------------------------------------------*/
  4723. Clear_Game_List(&gamelist);
  4724. Clear_Player_List(&playerlist);
  4725. /*------------------------------------------------------------------------
  4726. Restore screen
  4727. ------------------------------------------------------------------------*/
  4728. Hide_Mouse();
  4729. Load_Title_Screen("HTITLE.PCX", &HidPage, Palette);
  4730. Blit_Hid_Page_To_Seen_Buff();
  4731. Show_Mouse();
  4732. if (rc != -1){
  4733. Wait_For_Focus();
  4734. }
  4735. return(rc);
  4736. }
  4737. #endif