12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Copyright 2016 RWS Inc, All Rights Reserved
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of version 2 of the GNU General Public License as published by
- // the Free Software Foundation
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License along
- // with this program; if not, write to the Free Software Foundation, Inc.,
- // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- //
- // NetDlg.CPP
- // Project: Nostril (aka Postal)
- //
- // History:
- // 04/08/97 JMI Started.
- //
- // 05/20/97 JMI Now ms_pguiOK and ms_pguiCancel use SAFE_REF() so the
- // current GUI can, optionally, not have one or both GUI
- // items.
- //
- // 05/25/97 JMI Integrated newest TCP/IP CNetServer/Client interface.
- // Still need to detect when the game is starting.
- // GUI could still use a little cleaning up.
- //
- // 05/26/97 JMI Removed case for NetMsg::DuplicateName in reason
- // for JoinDeny message (it no longer exists).
- //
- // 05/26/97 JMI Added sending and receiving of START_REALM.
- // Removed psNumPlayers and psMyPlayerNum parameters.
- //
- // 05/27/97 JMI Added sending and receiving of LOAD_REALM before
- // START_REALM.
- // Fixed bug in OnLoginMsg() which was telling the client
- // the wrong net ID.
- // Upgraded to utilize new functions RSocket::SetPort() and
- // CNet::OpenPeerData().
- //
- // 05/27/97 JMI OnJoinedMsg() now only adds the players' names to the
- // listbox of players.
- //
- // 05/28/97 JMI Integrated new dialog.
- //
- // 05/28/97 JMI Changed so the LOAD_REALM message motivates the leaving
- // of the dialog interface (was START_REALM that did it
- // before).
- //
- // 06/11/97 JMI Removed unnecessary code in OnLoadRealmMsg().
- // Now uses Play_GetNextLevel to get realm names.
- //
- // 06/11/97 JMI Now centers client/server dialogs on screen.
- //
- // 06/13/97 MJR Restructed lots of stuff to consolidate client and
- // server code into a single function.
- // Implimented new version of START_GAME message.
- // Added code to get/release resources for new deluxe
- // dialog box.
- //
- // 06/15/97 JMI Now deactivates client items in listbox as they are
- // added.
- // Also, now, instead of simply squashing the dialog to
- // exclude server controls in client mode, we simply hide
- // the server controls and center the remaining controls
- // in the dialog without altering its size.
- //
- // 06/16/97 JMI Now uses g_fontSmall for dialogs.
- //
- // MJR Added use of watchdog timer for network blocking callbacks.
- //
- // JMI Changed use of g_fontSmall to g_fontBig.
- //
- // 06/17/97 JMI Now only allows the server to process a DLG_OK.
- //
- // 06/30/97 MJR Switched over to new GuiItem.h-supplied macros.
- //
- // 07/14/97 BRH Changed call to Play_GetRealmInfo to include the
- // new challenge mode parameter.
- //
- // 08/02/97 JMI Added an icon to watchdog timer for network blocking
- // callbacks and made it generally callable.
- //
- // 08/04/97 BRH Added protocol parameter to net calls.
- //
- // 08/11/97 JMI Changed a little of the structure of SetUpDlg() to allow
- // for more than just two types of dialogs.
- // Also, changed UpdateDialog() to use an RProcessGui which
- // simplifies that down to nearly nothing. #if 0'd out old
- // stuff for now.
- // Checking in so Mike can compile so we can check his stuff
- // in so I can check this out again.
- //
- // MJR Modified to use new browsing functions and moved all
- // the find-the-host code into a separate function.
- //
- // JMI Now adds the items from the browse list to the dialog
- // (and drops them too (theoretically) ).
- //
- // 08/12/97 JMI Dropped hosts were not setting the repaginate flag in
- // UpdateListBox(). Fixed.
- // DoNetGameDialog() now loops nearly all logic while
- // browsing and no errors.
- //
- // 08/13/97 JMI Cleaned up some more stuff.
- // MJR Fixed bugs that kept us in a browsing loop.
- //
- // 08/14/97 JMI Added global difficulty parameter to Play_GetRealmInfo().
- // I imagine it's not actually used for multiplayer levels
- // until we have options to play cooperative.
- //
- // 08/19/97 JMI Added some unfinished usage of the multiplayer options
- // updating. Needs to be updated to the correct spot,
- // either the game settings or the message. Probably the
- // game settings which then get copied to the message.
- //
- // 08/19/97 JMI Now uses the g_GameSettings for the multiplayer options.
- // Tinkered with chat messages that I thought weren't
- // working but then realized they were being ignored b/c
- // the UpdateDialog() function was being called by the
- // net blocking callback so hopefully I didn't ruin anything
- // in that process... .
- // Genericized SetupDlg() to use UploadLinks().
- //
- // 08/19/97 JMI Added a flag to UpdateDialog() indicating that it should
- // not clear any GUIs. This is useful for when
- // UpdateDialog() is called via callback (so we don't loose
- // any of the pressages processed via the callback).
- //
- // 08/20/97 JMI Up/DownloadLinkInteger() are now hardwired to assume
- // 'signed' type for String links b/c bool had a warning
- // for the trickery I was using to determine if the type
- // was signed.
- //
- // 08/20/97 JMI Now chat history is a listbox.
- // Clicking the 'Send Chat' button moves focus back to the
- // edit field for better feedback.
- // Limits chats to 20.
- // Now updates client's view of host's multiplay options.
- // Now the server can select a player (for disconnection)
- // from the players list.
- // Implemented host option to disconnect a player.
- // Newest player is EnsureVisible()d in player list now.
- // Newest chat is EnsureVisible()d in chat list now.
- // Now sets number of connected players on two GUIs so
- // there can be a 3D effect.
- // Sends and responds to SETUP_GAME message.
- // Sets options in START_GAME message from dialog settings
- // now.
- // Updates settings even if dialog aborted for consistency.
- //
- // 08/21/97 JMI Temporarily hardwired 'Rejuvenate' to ON and disallowed
- // user modifications of the checkbox.
- //
- // 08/21/97 JMI Changed call to Update() to UpdateSystem() and occurrences
- // of rspUpdateDisplay() to UpdateDisplay().
- //
- // 08/23/97 MJR Lots of changes in how errors are handled and other such
- // stuff.
- //
- // 08/23/97 JMI Now list box items appear with a barely perceptible
- // shadow that makes them alot easier to read.
- // Player colors now displayed as color descriptions.
- //
- // 08/25/97 JMI Now the chat text edit field limits the text to the
- // message's capacity for text.
- // Also, got rid of some '***'s.
- //
- // 08/25/97 JMI Now removes areas on chat items in chat box to make
- // for the border lines we hide to get more space.
- //
- // 08/27/97 JMI Changed NetProbIcons functions to NetProbGui functions.
- // Also, instead of a DrawNetProbGui() there's a
- // GetNetProbGui() so you can draw it, move it, change the
- // text, etc.
- //
- // 09/01/97 MJR Nearing the end of a huge overhaul of networking.
- //
- // 09/02/97 MJR It appears to work well after much testing, tuning, and
- // debugging.
- //
- // 09/03/97 MJR Fixed a problem that made browsing for yourself fail
- // once in a while (the timeout timer was too short).
- //
- // 09/06/97 JMI Now sets the Client's Game Options text field to use
- // the text shadow. Also, selects the first item in the
- // level browser box in the Server's dialog.
- // Also, combined the status field and the chat box into
- // one 'Net Console'.
- //
- // 09/06/97 JMI Now filters out the high word of ie.lKey when checking
- // for enter. This filters out the the key flags (i.e.,
- // shift, control, alt, system).
- //
- // 09/07/97 JMI Now BrowseForHosts() updates the display before
- // displaying the browse dialog.
- //
- // 09/08/97 MJR Fixed bug where net prob gui was showing up
- // immediately instead of after the watchdog expired.
- // Also cleaned up the erasing of the net prob gui.
- //
- // 09/09/97 JMI Now initializes ms_pguiRetry to NULL in DlgBeGone().
- //
- // 09/09/97 MJR Now detects protocol-not-supported and dispalys a
- // specific msg box describing the problem.
- //
- // 09/11/97 MJR Now client checks to see whether the level that was
- // specified in the SETUP_GAME message is available, and
- // automatically sends a chat message that complains if it
- // isn't, in the hope that the host player will change it.
- //
- // Now the host will send the realm name if only a single
- // realm is available, which tells everyone to only play
- // that realm.
- //
- // Changed the dropped message, which was incorrectly using
- // the error message as the player's name.
- //
- // 09/11/97 JMI Now only adds the SPECIFIC_MP_REALM_TEXT choice to the
- // host's level browser if ENABLE_PLAY_SPECIFIC_REALMS_ONLY
- // is defined. Otherwise, it chooses the first item in the
- // listbox.
- //
- // 09/12/97 MJR Reversed the #if for which method to use for filling
- // hood listbox.
- //
- // Added hardwired realm stuff to SetupGame() when we're
- // in the specific realm mode.
- //
- // 09/18/97 JMI There were some /"s instead of \"s. If someone had
- // their syntax coloring on useful colors, they would've
- // seen this blaringly obvious color collage. :)
- //
- // 09/24/97 JMI Fixed OnSetupGameMsg() to handle checking to see if the
- // local machine has the required realm using the title
- // that is passed in the SetupGame msg (was originally
- // intended to use filenames but got hosed).
- //
- // 09/26/97 JMI Now '-' is blocked at the UpdateDialog() level and never
- // reaches the GUIs so that the time limit and kill limit
- // edit fields cannot have a negative number enter in them
- // (of course you could enter the letter 'a' which looks
- // wrong too but I know one cares about that (you'd have to
- // be STUPID to do that but even smart people enter negative
- // numbers for time and kill limits) ).
- // Also, this keeps players from using '-' in their chat
- // strings.
- //
- // 11/20/97 JMI Added cooperative flags and associated checkboxes. Now
- // displays info on client side regarding cooperative mode
- // and carries all the necessary flagage around between
- // messages regarding cooperative mode as well. Also, now
- // the level browse listbox can show either deathmatch or
- // cooperative levels (controlled by the user's cooperative
- // checkbox setting).
- // Also, the user can choose operate checkbox deciding
- // whether to allow cooperative play mode (which is missiles
- // and bullets pass through fellow players).
- //
- // 11/25/97 JMI Added platform conflict message and more informative
- // version conflict messages (also added version conflict
- // message for server -- previous the error did not propagate
- // to this level).
- //
- // 11/25/97 JMI Changed the server dialog .GUI to be loaded from the HD
- // instead of from the VD so we can guarantee the new asset
- // gets loaded (since they'll use their old Postal disc, we
- // cannot load the .GUI from the CD).
- //
- //////////////////////////////////////////////////////////////////////////////
- //
- // Deals with networking dialogs. There is an interface for the server,
- // client, and browser dialogs that deal heavily with user input, and GUI
- // output. The client/server messages are now handled by the black-box-like
- // lower level.
- //
- //////////////////////////////////////////////////////////////////////////////
- #include "RSPiX.h"
- #include "CompileOptions.h"
- #include "GameSettings.h"
- #include "game.h"
- #include "play.h"
- #include "update.h"
- #include "NetDlg.h"
- #include "netbrowse.h"
- //////////////////////////////////////////////////////////////////////////////
- // Module specific macros.
- //////////////////////////////////////////////////////////////////////////////
- // Common.
- #define GUI_ID_OK 1001
- #define GUI_ID_CANCEL 1002
- // Common Client/Server dialog.
- #define GUI_ID_PLAYERS_LISTBOX 1010
- #define GUI_ID_CHAT_TEXT 1013
- #define GUI_ID_CHAT_SEND 1015
- #define GUI_ID_NET_CONSOLE 1016
- #define GUI_ID_PLAYERS_STATIC1 7000
- #define GUI_ID_PLAYERS_STATIC2 7001
- // Client dialog.
- #define GUI_ID_OPTIONS_STATIC 2000
- #define GUI_ID_RETRY 9000
- // Server dialog.
- #define GUI_ID_DISCONNECT_PLAYER 6000
- //#define GUI_ID_RESPAWN_PLAYERS 3000
- #define GUI_ID_ENABLE_TIME_LIMIT 4000
- #define GUI_ID_EDIT_TIME_LIMIT 4001
- #define GUI_ID_ENABLE_KILL_LIMIT 5000
- #define GUI_ID_EDIT_KILL_LIMIT 5001
- #define GUI_ID_LEVEL_LISTBOX 1020
- #define GUI_ID_SHOW_COOP_LEVELS 8000
- #define GUI_ID_ENABLE_COOP_MODE 9000
- // Browser dialog.
- #define GUI_ID_HOST_LISTBOX 1010
- #define SERVER_GUI "res/shell/Server.gui"
- #define CLIENT_GUI "res/shell/Client.gui"
- #define BROWSER_GUI "res/shell/Browser.gui"
- #define GUI_DIR "menu/"
- // Note that this is evaluated at compile time, so even
- // if the ptr is NULL, it will work.
- #define MAX_STATUS_STR GUI_MAX_STR
- // Maximum number of chat strings in the box.
- #define MAX_CHAT_STRINGS 20
- // Time between game setup net sends.
- #define OPTIONS_SEND_FREQUENCY 2000
- // Amount of time that must elapse after the first "Cancel" before an
- // addition "Cancel" wil be recognized.
- #define CANCEL_DELAY_TIME 1500
- // If status hasn't been updated for this long, then we will display the default message
- #define STATUS_MAX_DISPLAY_TIME 2000
- // NOTE: If we add anymore icons, we might as well just spend the extra few
- // minutes making a separate file for them.
- // Net problems icon file.
- #define NET_PROB_GUI_FILE "menu/netprob.gui"
- // Initial location for net problems icon on screen.
- #define NET_PROB_GUI_X 10
- #define NET_PROB_GUI_Y 40
- #define NET_PROB_TEXT_SHADOW_COLOR_INDEX 4
- #define TERMINATING_GUI_ID 0x80000000
- // Note that the following color indices are from the 'Artie Zone' of colors
- // in the menu palette and, therefore, should not change.
- #define LIST_ITEM_TEXT_SHADOW_COLOR_INDEX 220
- // This has been remapped to a Win32 color to make it stand out more
- #define NET_STATUS_MSG_COLOR_INDEX 247
- //////////////////////////////////////////////////////////////////////////////
- // THIS ENTIRE SECTION OF STRINGS SHOULD BE MOVED TO LOCALIZE.CPP!!!
- //////////////////////////////////////////////////////////////////////////////
- // Client-specific messages displayed in client dialog's status area
- char* g_pszClientStat_NameTooLongForChat = "Name too long, can't chat";
- char* g_pszClientStat_YouWereDropped = "Connection was lost";
- char* g_pszClientStat_SomeoneDropped_s = "\"%s\" is no longer connected";
- char* g_pszClientStat_ServerAborted = "Game aborted";
- char* g_pszClientStat_ServerStarted = "Starting game";
- char* g_pszClientStat_Opened = "Opened connection";
- char* g_pszClientStat_Connected = "Connected";
- char* g_pszClientStat_JoinDenyTooMany = "Can't join -- too many players";
- char* g_pszClientStat_JoinDenyLowBandwidth = "Can't join -- your bandwidth is too low";
- char* g_pszClientStat_JoinDenyCantDropIn = "Can't join -- game has already started";
- char* g_pszClientStat_JoinDenyUnknown = "Can't join -- don't know why";
- char* g_pszClientStat_JoinAccepted = "Joined";
- char* g_pszClientStat_LoginAccepted_hd = "Logged in (ID = %hd)";
- char* g_pszClientStat_Startup = "Trying to connect...";
- char* g_pszClientStat_Default = "Ready";
- char* g_pszClientStat_Error_s = "Network error (%s) -- aborting";
- char* g_pszClientStat_Retrying = "Retry...";
- // Server-specific messages displayed in server dialog's status area
- char* g_pszServerStat_InvalidDropReq_hd = "Ignored invalid drop request (ID = %hd)";
- char* g_pszServerStat_AcceptedClient = "\"%s\" has joined";
- char* g_pszServerStat_CantAcceptJoinReq = "Can't grant join request (too many players)";
- char* g_pszServerStat_InvalidChangeReq_hd = "Ignored invalid change request (ID = %hd)";
- char* g_pszServerStat_LoginAccepted_hd = "Login accepted (id = %hd)";
- char* g_pszServerStat_LoginDeniedVersion_ld = "Login denied (obsolete client version %ld)";
- char* g_pszServerStat_LoginDeniedMagic = "Login denied (invalid signature)";
- char* g_pszServerStat_Startup = "Setting up connection...";
- char* g_pszServerStat_Default = "Ready";
- char* g_pszServerStat_CantDropSelf = "You can't drop yourself";
- char* g_pszServerStat_PlayerErr = "Player was dropped (bad connection)";
- // General messages displayed in client or server dialog's status area
- char* g_pszNetStat_Aborting = "Aborting...";
- char* g_pszNetStat_Starting = "Starting game...";
- char* g_pszNetStat_AttemptToDrop_s = "Attempting to drop \"%s\"";
- char* g_pszNetStat_UnhandledMsg = "Ignoring extraneous message";
- char* g_pszNetStat_NoError = "No errors";
- char* g_pszNetStat_ReceiveError = "Network error (can't receive data)";
- char* g_pszNetStat_InQFullError = "Network error (input buffer is full)";
- char* g_pszNetStat_OutQFullError = "Network error (output buffer is full)";
- char* g_pszNetStat_SendError = "Network error (can't send data)";
- char* g_pszNetStat_InQReadError = "Network error (can't read data)";
- char* g_pszNetStat_OutQWriteError = "Network error (couldn't write data)";
- char* g_pszNetStat_ConnectionError = "Network error (bad connection)";
- char* g_pszNetStat_TimeoutError = "Network error (time-out)";
- char* g_pszNetStat_ListenError = "Network error (can't listen)";
- char* g_pszNetStat_ConnectError = "Network error (can't connect)";
- char* g_pszNetStat_ConnectTimeoutError = "Network error (connection attempt timed-out)";
- char* g_pszNetStat_ClientVersionMismatchError_lu_lu = "Version mismatch--dropping (Host ver is %lu -- Our ver is %lu)";
- char* g_pszNetStat_ServerVersionMismatchError_lu_lu = "Version mismatch--dropping client (Client ver is %lu -- Our ver is %lu)";
- char* g_pszNetStat_CantOpenPeerSocketError = "Network error (couldn't connect to other players)";
- char* g_pszNetStat_LoginDeniedError = "Login failed";
- char* g_pszNetStat_JoinDeniedError = "Host refused join request";
- char* g_pszNetStat_UnknownError = "Network error (general failure)";
- char* g_pszNetStat_ProgramError = "Network error (generic failure)";
- #if defined(WIN32)
- char* g_pszNetStat_ClientPlatformMismatchError = "Cannot login to host because it is a Mac";
- char* g_pszNetStat_ServerPlatformMismatchError = "Cannot allow client to connect because it is a Mac";
- #else
- char* g_pszNetStat_ClientPlatformMismatchError = "Cannot login to host because it is a PC";
- char* g_pszNetStat_ServerPlatformMismatchError = "Cannot allow client to connect because it is a PC";
- #endif
- // This is what we say when the user has chosen a protocol that is not supported.
- // There are two variations: one for if the user only has one choice (because we
- // only support that one) and the other for if the user can try another choice.
- char* g_pszNetOnlyProtocolUnsupported_s =
- "Your system does not support \"%s\", which is the required network protocol.\n"
- "\n"
- "This protocol must be added to your system before multiplayer mode can be used.";
- char* g_pszNetProtocolUnsupported_s =
- "Your system does not support \"%s\", which is the currently selected network protocol.\n"
- "\n"
- "Either add this protocol to your system or choose a different protocol from the "
- "multiplayer options menu.";
- // Text which is used to dynamically update one of the text fields on the client or server dialog
- char* g_pszNetDlg_ConnectedPlayers_d = "Connected Players: %d";
- // Text which is used for the net problems GUI.
- // WARNING: This is an EXTERN and is used by other modules!
- char* g_pszNetProb_General =
- "Network not responding.\nYou can wait or\npress " NET_PROB_GUI_ABORT_KEY_TEXT" to abort";
- // Text to prefix net status messages, if any.
- char* g_pszNetStatusMsgPrefix = "> ";
- //////////////////////////////////////////////////////////////////////////////
- // Module specific typedefs.
- //////////////////////////////////////////////////////////////////////////////
- // Dialog actions
- typedef enum
- {
- DLG_NOTHING,
- DLG_OK,
- DLG_CANCEL,
- DLG_CHAT,
- DLG_DISCONNECT_PLAYER,
- DLG_OPTIONS_UPDATED,
- DLG_RETRY
- } DLG_ACTION;
- // Dialog types.
- typedef enum
- {
- DLG_SERVER,
- DLG_CLIENT,
- DLG_BROWSER
- } DLG_TYPE;
- // GUI/Var Link
- typedef struct
- {
- typedef enum
- {
- Long,
- ULong,
- Short,
- UShort,
- Char,
- UChar,
- String,
- Bool,
- Gui
- } Type;
- long lId; // ID of GUI to link to.
- Type type;
- #if 1
- union
- {
- void* pvLink;
- long* pl;
- ULONG* pul;
- short* ps;
- USHORT* pus;
- char* pc;
- UCHAR* puc;
- char* psz;
- bool* pb;
- RGuiItem** ppgui;
- };
- #else
- void* pvLink;
- #endif
- } GuiLink;
- //////////////////////////////////////////////////////////////////////////////
- // Module specific (static) variables / Instantiate class statics.
- //////////////////////////////////////////////////////////////////////////////
- // Common.
- static RGuiItem* ms_pguiRoot = NULL; // Root of GUI tree for network interface.
- static RGuiItem* ms_pguiOk = NULL; // GUI that, once 'clicked', indicates acceptance.
- static RGuiItem* ms_pguiCancel = NULL; // GUI that, once 'clicked', indicates rejection.
- // Client/Server common.
- static RListBox* ms_plbPlayers = NULL; // Listbox used by both types of net dialogs.
- static RListBox* ms_plbNetConsole = NULL; // List of net console (chat and status) strings.
- static RGuiItem* ms_pguiChatText = NULL; // Chat text.
- static RGuiItem* ms_pguiChatSend = NULL; // Chat send button.
- // Server.
- static RListBox* ms_plbLevelBrowse = NULL; // Level browse listbox.
- static RGuiItem* ms_pguiDisconnectPlayer = NULL; // Disconnect a player button.
- static RMultiBtn* ms_pmbCoopLevels = NULL; // Coop levels checkbox.
- static RMultiBtn* ms_pmbCoopMode = NULL; // Coop mode checkbox.
- // Client.
- static RGuiItem* ms_pguiOptions = NULL; // Options shown on client dialog.
- static RGuiItem* ms_pguiRetry = NULL; // Retry button on client dialog shown when needed.
- // Browser.
- static RListBox* ms_plbHostBrowse = NULL; // Browse for host listbox.
- // Other static vars.
- static long ms_lWatchdogTime = 0; // Watchdog timer
- static bool ms_bNetBlockingAbort = false; // Net blocking abort flag
- static long ms_lNumConsoleEntries = 0; // Track number of chat items.
- static bool ms_bGotSetupMsg = false;
- static short ms_sSetupRealmNum = 0;
- static char ms_szSetupRealmFile[Net::MaxRealmNameSize];
- static long ms_lSetupLastChatComplaint = 0;
- static long ms_lNextOptionsUpdateTime; // Next time to send an options update.
- static RTxt* ms_ptxtNetProb = NULL; // Net problem GUI.
- static bool m_bNetWatchdogExpired = false; // Whether net blocking expired
- static bool ms_bCoopLevels = false; // true, to use cooperative levels.
- // This is used by UpdateDialog() to perform GUI processing.
- static RProcessGui ms_pgDoGui;
- // Linkable vars.
- static bool ms_bTimeLimit = false; // Enable Time Limit if true.
- static bool ms_bKillLimit = false; // Enable Kill Limit if true.
- static bool ms_bCoopMode = false; // true, for cooperative mode (false for deathmatch).
- static GuiLink ms_aglServerLinkage[] =
- {
- { GUI_ID_DISCONNECT_PLAYER, GuiLink::Gui, &ms_pguiDisconnectPlayer, },
- // { GUI_ID_RESPAWN_PLAYERS, GuiLink::Short, &g_GameSettings.m_sHostRejuvenate, },
- { GUI_ID_ENABLE_TIME_LIMIT, GuiLink::Bool, &ms_bTimeLimit, },
- { GUI_ID_EDIT_TIME_LIMIT, GuiLink::Short, &g_GameSettings.m_sHostTimeLimit, },
- { GUI_ID_ENABLE_KILL_LIMIT, GuiLink::Bool, &ms_bKillLimit, },
- { GUI_ID_EDIT_KILL_LIMIT, GuiLink::Short, &g_GameSettings.m_sHostKillLimit, },
- { GUI_ID_LEVEL_LISTBOX, GuiLink::Gui, &ms_plbLevelBrowse, },
- { GUI_ID_SHOW_COOP_LEVELS, GuiLink::Gui, &ms_pmbCoopLevels, },
- { GUI_ID_ENABLE_COOP_MODE, GuiLink::Gui, &ms_pmbCoopMode, },
- { GUI_ID_ENABLE_COOP_MODE, GuiLink::Bool, &ms_bCoopMode, },
- { static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
- };
- static GuiLink ms_aglClientLinkage[] =
- {
- { GUI_ID_OPTIONS_STATIC, GuiLink::Gui, &ms_pguiOptions, },
- { GUI_ID_RETRY, GuiLink::Gui, &ms_pguiRetry, },
-
- { static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
- };
- static GuiLink ms_aglClientServerLinkage[] =
- {
- { GUI_ID_PLAYERS_LISTBOX, GuiLink::Gui, &ms_plbPlayers, },
- { GUI_ID_CHAT_TEXT, GuiLink::Gui, &ms_pguiChatText, },
- { GUI_ID_CHAT_SEND, GuiLink::Gui, &ms_pguiChatSend, },
- { GUI_ID_NET_CONSOLE, GuiLink::Gui, &ms_plbNetConsole, },
- { GUI_ID_OK, GuiLink::Gui, &ms_pguiOk, },
- { GUI_ID_CANCEL, GuiLink::Gui, &ms_pguiCancel, },
-
- { static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
- };
- static GuiLink ms_aglBrowserLinkage[] =
- {
- { GUI_ID_HOST_LISTBOX, GuiLink::Gui, &ms_plbHostBrowse, },
- { GUI_ID_OK, GuiLink::Gui, &ms_pguiOk, },
- { GUI_ID_CANCEL, GuiLink::Gui, &ms_pguiCancel, },
-
- { static_cast<long>(TERMINATING_GUI_ID), }, // Terminator.
- };
- //////////////////////////////////////////////////////////////////////////////
- // Module specific (static) protos.
- //////////////////////////////////////////////////////////////////////////////
- static void AddConsoleMsg( // Returns nothing.
- bool bChat, // In: true for a chat message, or false for others (like net status).
- const char* pszFrmt, // In: sprintf style formatting.
- ...); // In: Optional arguments based on context of pszFrmt.
- // Get dialog resource
- short DlgGetRes( // Returns 0 if successfull, non-zero otherwise
- RGuiItem* pgui); // I/O: Pointer to gui item
- // Release dialog resource
- void DlgReleaseRes( // Returns 0 if successfull, non-zero otherwise
- RGuiItem* pgui); // I/O: Pointer to gui item
- // Net blocking callback
- static short NetBlockingCallback(void); // Returns 0 to continue normally, 1 to abort
- static short BrowseForHost(
- CNetServer* pserver, // I/O: Server interface or NULL if none
- RSocket::Address* paddress); // Out: Address returned here (if successfull)
- static short FindSpecificSystem(
- RSocket::Address* paddress); // Out: Address returned here (if successfull)
- static short BrowseForSelf(
- CNetServer* pserver, // I/O: Server interface
- RSocket::Address* paddress); // Out: Address returned here (if successfull)
- //////////////////////////////////////////////////////////////////////////////
- // Helper for UploadLinks() to handle all integer vars.
- //////////////////////////////////////////////////////////////////////////////
- template <class Int> // Templated input type (can be unsigned).
- void UploadLinkInteger( // Returns nothing.
- RGuiItem* pgui, // In: GUI to upload to.
- Int i) // In: Input val to upload to GUI.
- {
- ASSERT(pgui);
- switch (pgui->m_type)
- {
- case RGuiItem::MultiBtn:
- {
- RMultiBtn* pmb = (RMultiBtn*)pgui;
- if (i)
- {
- pmb->m_sState = 1;
- }
- else
- {
- pmb->m_sState = 2;
- }
- break;
- }
- case RGuiItem::PushBtn:
- {
- RPushBtn* ppushbtn = (RPushBtn*)pgui;
- if (i)
- {
- ppushbtn->m_state = RPushBtn::On;
- }
- else
- {
- ppushbtn->m_state = RPushBtn::Off;
- }
- break;
- }
- default:
- #if 0
- // Determine if signed (this is wierd but may work) . . .
- if ((Int)-1 < 0)
- {
- // Signed.
- pgui->SetText("%ld", (long)i);
- }
- else
- {
- // Unsigned.
- pgui->SetText("%lu", (ULONG)i);
- }
- #else
- // Hardwire to signed b/c bool was displaying a warning regarding the
- // above comparison to determine the [un]signed nature of the templated
- // type.
- pgui->SetText("%ld", (long)i);
- #endif
- break;
- }
- pgui->Compose();
- }
- //////////////////////////////////////////////////////////////////////////////
- // Helper for DownloadLinks() to handle all integer vars.
- //////////////////////////////////////////////////////////////////////////////
- template <class Int> // Templated output type (can be unsigned).
- void DownloadLinkInteger( // Returns nothing.
- RGuiItem* pgui, // In: GUI to download from.
- Int* pi) // Out: Input val to download into from GUI.
- {
- ASSERT(pgui);
- switch (pgui->m_type)
- {
- case RGuiItem::MultiBtn:
- {
- RMultiBtn* pmb = (RMultiBtn*)pgui;
- *pi = (pmb->m_sState == 1) ? 1 : 0;
- break;
- }
- case RGuiItem::PushBtn:
- {
- RPushBtn* ppushbtn = (RPushBtn*)pgui;
- *pi = (ppushbtn->m_state == RPushBtn::On) ? 1 : 0;
- break;
- }
- default:
- #if 0
- // Determine if signed (this is wierd but may work) . . .
- if ((Int)-1 < 0)
- {
- // Signed.
- *pi = pgui->GetVal();
- }
- else
- {
- // Unsigned.
- *pi = strtoul(pgui->m_szText, NULL, 0);
- }
- #else
- // Hardwire to signed b/c bool was displaying a warning regarding the
- // above comparison to determine the [un]signed nature of the templated
- // type.
- *pi = pgui->GetVal();
- #endif
- break;
- }
- pgui->Compose();
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Upload variables to their GUI links.
- //
- //////////////////////////////////////////////////////////////////////////////
- static void UploadLinks( // Returns nothing.
- GuiLink* pagl, // In: Links to upload.
- RGuiItem* pguiRoot) // In: GUI to upload to.
- {
- ASSERT(pguiRoot);
- while (pagl->lId != TERMINATING_GUI_ID)
- {
- // Get item.
- RGuiItem* pgui = pguiRoot->GetItemFromId(pagl->lId);
- if (pgui)
- {
- switch (pagl->type)
- {
- case GuiLink::Long:
- UploadLinkInteger(pgui, *pagl->pl);
- break;
- case GuiLink::ULong:
- UploadLinkInteger(pgui, *pagl->pul);
- break;
-
- case GuiLink::Short:
- UploadLinkInteger(pgui, *pagl->ps);
- break;
-
- case GuiLink::UShort:
- UploadLinkInteger(pgui, *pagl->pus);
- break;
- case GuiLink::Char:
- UploadLinkInteger(pgui, *pagl->pc);
- break;
-
- case GuiLink::UChar:
- UploadLinkInteger(pgui, *pagl->puc);
- break;
- case GuiLink::Bool:
- UploadLinkInteger(pgui, *pagl->pb);
- break;
-
- case GuiLink::String:
- pgui->SetText("%s", pagl->psz );
- break;
- // This may seem backward but it's more convenient.
- case GuiLink::Gui:
- *pagl->ppgui = pgui;
- break;
- default:
- TRACE("UploadLinks(): Type %d not supported.\n",
- pagl->type);
- break;
- }
- }
- else
- {
- TRACE("UploadLinks(): GUI ID %d does not exist.\n", pagl->lId);
- }
- // Next.
- pagl++;
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Download variables to their GUI links.
- //
- //////////////////////////////////////////////////////////////////////////////
- static void DownloadLinks( // Returns nothing.
- GuiLink* pagl, // In: Links to upload.
- RGuiItem* pguiRoot) // In: GUI to upload to.
- {
- ASSERT(pguiRoot);
- while (pagl->lId != TERMINATING_GUI_ID)
- {
- // Get item.
- RGuiItem* pgui = pguiRoot->GetItemFromId(pagl->lId);
- if (pgui)
- {
- switch (pagl->type)
- {
- case GuiLink::Long:
- DownloadLinkInteger(pgui, pagl->pl);
- break;
-
- case GuiLink::ULong:
- DownloadLinkInteger(pgui, pagl->pul);
- break;
-
- case GuiLink::Short:
- DownloadLinkInteger(pgui, pagl->ps);
- break;
-
- case GuiLink::UShort:
- DownloadLinkInteger(pgui, pagl->pus);
- break;
-
- case GuiLink::Char:
- DownloadLinkInteger(pgui, pagl->pc);
- break;
-
- case GuiLink::UChar:
- DownloadLinkInteger(pgui, pagl->puc);
- break;
-
- case GuiLink::Bool:
- DownloadLinkInteger(pgui, pagl->pb);
- break;
-
- case GuiLink::String:
- strcpy( pagl->psz, pgui->m_szText );
- break;
-
- case GuiLink::Gui:
- break;
- default:
- TRACE("DownloadLinks(): Type %d not yet supported.\n",
- pagl->type);
- break;
- }
- }
- else
- {
- TRACE("DownloadLinks(): GUI ID %d does not exist.\n", pagl->lId);
- }
- // Next.
- pagl++;
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Macro to activate certain parms to make our list item GUI's look nice and
- // readable.
- //
- //////////////////////////////////////////////////////////////////////////////
- inline void MakeMoreReadable( // Returns nothing.
- RGuiItem* pgui) // In: GUI to shadowify using global values.
- {
- ASSERT(pgui);
- if (pgui)
- {
- pgui->m_sTextEffects = RGuiItem::Shadow;
- pgui->m_u32TextShadowColor = LIST_ITEM_TEXT_SHADOW_COLOR_INDEX;
- pgui->m_sShowFocus = FALSE;
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // [Re]compose Options GUI with word wrap preserving original word wrap status.
- //
- //////////////////////////////////////////////////////////////////////////////
- inline void ComposeOptions(void)
- {
- // Most likely someone has already checked this before calling this but
- // it doesn't hurt to be safe.
- if (ms_pguiOptions)
- {
- // Store old word wrap status so we can restore it when done.
- short sWordWrapWas = (ms_pguiOptions->m_pprint->m_eModes & RPrint::WORD_WRAP) ? TRUE : FALSE;
- // Enable word wrap (not accessible from GUI editor currently).
- ms_pguiOptions->m_pprint->SetWordWrap(TRUE);
- ms_pguiOptions->Compose();
- // Reset word wrap.
- ms_pguiOptions->m_pprint->SetWordWrap(sWordWrapWas);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Clean/Reset Client dialog to defaults.
- //
- //////////////////////////////////////////////////////////////////////////////
- static void CleanClientDlg(
- CNetClient* pnet,
- bool bRetryButton)
- {
- if (ms_pguiOptions)
- {
- // Set no-connection text for options GUI.
- ms_pguiOptions->SetText("Not currently connected to a host.");
- // Repaginate now!
- ComposeOptions();
- }
- if (ms_plbPlayers)
- {
- // Empty players listbox.
- ms_plbPlayers->RemoveAll();
- }
- int iNumPlayers = (pnet) ? pnet->GetNumPlayers() : 0;
-
- // This cheese updates the number of players displayed. I cannot remember why we did not simply
- // make this one text shadowed GUI.
- RGuiItem* pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC1);
- RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, iNumPlayers));
- RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose());
- pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC2);
- RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, iNumPlayers));
- RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose());
-
- if (ms_pguiRetry)
- {
- // Show as specified by caller.
- ms_pguiRetry->SetVisible(bRetryButton ? TRUE : FALSE);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Show the selectable network levels in the hood to play listbox.
- //
- //////////////////////////////////////////////////////////////////////////////
- static short ShowLevels(void) // Returns 0 on success.
- {
- short sRes = 0; // Assume success.
- if (ms_plbLevelBrowse != NULL)
- {
- // Must be listbox.
- ASSERT(ms_plbLevelBrowse->m_type == RGuiItem::ListBox);
- // Get rid of existing entries.
- ms_plbLevelBrowse->RemoveAll();
- #if !defined(ENABLE_PLAY_SPECIFIC_REALMS_ONLY)
- // Add all the available realms.
- char szRealm[RSP_MAX_PATH+1];
- char szTitle[512];
- short i = 0;
- while (sRes == 0)
- {
- // Get realm name from realm prefs file
- sRes = Play_GetRealmInfo(true, ms_bCoopLevels, false, false, i, g_GameSettings.m_sDifficulty, szRealm, sizeof(szRealm), szTitle, sizeof(szTitle));
- if (sRes == 1)
- {
- // That's it.
- sRes = 0;
- break;
- }
- else if (sRes == 0)
- {
- // Add to listbox.
- RGuiItem* pguiLevel = ms_plbLevelBrowse->AddString(szTitle);
- if (pguiLevel != NULL)
- {
- // Activate shadow parameters.
- MakeMoreReadable(pguiLevel);
- pguiLevel->Compose();
- pguiLevel->m_lId = i;
- }
- else
- {
- TRACE("ShowLevels(): Failed to add string to listbox.\n");
- sRes = -1;
- }
- }
- i++;
- }
- #else
- // Add the one and only level option.
- RGuiItem* pguiLevel = ms_plbLevelBrowse->AddString(SPECIFIC_MP_REALM_TEXT);
- if (pguiLevel != NULL)
- {
- // Activate shadow parameters.
- MakeMoreReadable(pguiLevel);
- pguiLevel->Compose();
- pguiLevel->m_lId = SPECIFIC_MP_REALM_NUM;
- }
- else
- {
- TRACE("ShowLevels(): Failed to add string to listbox.\n");
- sRes = -1;
- }
- #endif // ENABLE_PLAY_SPECIFIC_REALMS_ONLY
- // Select the first item in the listbox.
- ms_plbLevelBrowse->SetSel(ms_plbLevelBrowse->GetFirst() );
- // Update listbox.
- ms_plbLevelBrowse->AdjustContents();
- }
- return sRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Be done with the current dialog and related settings.
- //
- //////////////////////////////////////////////////////////////////////////////
- static void DlgBeGone(void)
- {
- // Clean up processor.
- ms_pgDoGui.Unprepare();
- if (ms_pguiRoot != NULL)
- {
- delete ms_pguiRoot;
- }
- ms_pguiRoot = NULL;
- ms_pguiOk = NULL;
- ms_pguiCancel = NULL;
- ms_plbPlayers = NULL;
- ms_plbNetConsole = NULL;
- ms_pguiChatText = NULL;
- ms_pguiChatSend = NULL;
- ms_plbLevelBrowse = NULL;
- ms_pguiOptions = NULL;
- ms_pguiDisconnectPlayer = NULL;
- ms_pmbCoopLevels = NULL;
- ms_pmbCoopMode = NULL;
- ms_plbHostBrowse = NULL;
- ms_pguiRetry = NULL;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Setup the specified dialog and related settings.
- //
- //////////////////////////////////////////////////////////////////////////////
- static short SetupDlg( // Returns 0 on success.
- char* pszGuiFile, // In: Full path to GUI file.
- DLG_TYPE type) // In: Type of dialog.
- {
- short sRes = 0; // Assume success.
- // Make sure everything is clean.
- DlgBeGone();
- // Anh...reset these here.
- ms_lNumConsoleEntries = 0;
- ms_lNextOptionsUpdateTime = 0;
- // Create a dialog. We have to take this approach instea of the nicer
- // LoadInstantiate() method because we need to install callbacks for
- // getting and releasing resources, which we can only do if we already
- // have the gui item (the dialog in this case). With LoadInstantiate(),
- // the dialog doesn't exist until after the call, and by then the resource
- // has already been loaded (or failed to load in this case because the
- // gui stuff can't possibly know the correct path for loading it).
- ms_pguiRoot = new RDlg;
- if (ms_pguiRoot != NULL)
- {
- // Setup callbacks for getting and releasing resources
- ms_pguiRoot->m_fnGetRes = DlgGetRes;
- ms_pguiRoot->m_fnReleaseRes = DlgReleaseRes;
- // Set font. The size in this call matters not b/c each GUI item
- // has a size it uses when printing.
- ms_pguiRoot->m_pprint->SetFont(15, &g_fontPostal);
- // Load the gui description file
- sRes = ms_pguiRoot->Load(pszGuiFile);
- if (sRes == 0)
- {
- // Set focus to first child control or none if there's none.
- ms_pguiRoot->SetFocus(ms_pguiRoot->m_listguiChildren.GetHead());
- // The special case stuff.
- switch (type)
- {
- case DLG_CLIENT:
- {
- // Upload client stuff.
- UploadLinks(ms_aglClientLinkage, ms_pguiRoot);
- // Upload stuff common to client/server.
- UploadLinks(ms_aglClientServerLinkage, ms_pguiRoot);
- // If exists . . .
- if (ms_plbPlayers != NULL)
- {
- // Must be listbox.
- ASSERT(ms_plbPlayers->m_type == RGuiItem::ListBox);
- // Get rid of existing entries.
- ms_plbPlayers->RemoveAll();
- }
- // If exists . . .
- if (ms_pguiChatText != NULL)
- {
- // Must be edit.
- ASSERT(ms_pguiChatText->m_type == RGuiItem::Edit);
- // Limit text.
- ( (REdit*)ms_pguiChatText)->m_sMaxText = Net::MaxChatSize - 1;
- }
- // Make the options GUI more readable.
- if (ms_pguiOptions)
- {
- MakeMoreReadable(ms_pguiOptions);
- }
- // Set title text.
- ms_pguiRoot->SetText(
- "%s [%s]",
- ms_pguiRoot->m_szText,
- g_GameSettings.m_szPlayerName);
- ms_pguiRoot->Compose();
- // Start with a clean slate.
- CleanClientDlg(0, false);
- break;
- }
- case DLG_SERVER:
- {
- // Upload server stuff.
- UploadLinks(ms_aglServerLinkage, ms_pguiRoot);
- // Upload stuff common to client/server.
- UploadLinks(ms_aglClientServerLinkage, ms_pguiRoot);
- // If exists . . .
- if (ms_plbPlayers != NULL)
- {
- // Must be listbox.
- ASSERT(ms_plbPlayers->m_type == RGuiItem::ListBox);
- // Get rid of existing entries.
- ms_plbPlayers->RemoveAll();
- }
- // If exists . . .
- if (ms_pguiChatText != NULL)
- {
- // Must be edit.
- ASSERT(ms_pguiChatText->m_type == RGuiItem::Edit);
- // Limit text.
- ( (REdit*)ms_pguiChatText)->m_sMaxText = Net::MaxChatSize - 1;
- }
- // If exists . . .
- if (ms_pmbCoopLevels)
- {
- // Must be multibtn.
- ASSERT(ms_pmbCoopLevels->m_type == RGuiItem::MultiBtn);
- // Set state to last choice.
- ms_pmbCoopLevels->m_sState = (ms_bCoopLevels == false) ? 1 : 2;
- // Recompose with new state.
- ms_pmbCoopLevels->Compose();
- }
- // If exists . . .
- if (ms_pmbCoopMode)
- {
- // Must be multibtn.
- ASSERT(ms_pmbCoopMode->m_type == RGuiItem::MultiBtn);
- // Set state to last choice.
- ms_pmbCoopMode->m_sState = (ms_bCoopMode == false) ? 2 : 1;
- // Recompose with new state.
- ms_pmbCoopMode->Compose();
- }
- // Fill level browser listbox.
- ShowLevels();
- // Set title text.
- ms_pguiRoot->SetText(
- "%s [%s]",
- ms_pguiRoot->m_szText,
- g_GameSettings.m_szPlayerName);
- ms_pguiRoot->Compose();
- break;
- }
- case DLG_BROWSER:
- {
- // Upload browser linkage.
- UploadLinks(ms_aglBrowserLinkage, ms_pguiRoot);
- // If exists . . .
- if (ms_plbHostBrowse)
- {
- // Must be listbox.
- ASSERT(ms_plbHostBrowse->m_type == RGuiItem::ListBox);
- // Get rid of existing entries.
- ms_plbHostBrowse->RemoveAll();
- }
- break;
- }
- }
- // Center.
- ms_pguiRoot->Move(
- g_pimScreenBuf->m_sWidth / 2 - ms_pguiRoot->m_im.m_sWidth / 2,
- g_pimScreenBuf->m_sHeight / 2 - ms_pguiRoot->m_im.m_sHeight / 2);
- // Make visible.
- ms_pguiRoot->SetVisible(TRUE);
- // Prepare GUI processor.
- ms_pgDoGui.m_sFlags = RProcessGui::NoCleanScreen;
- ms_pgDoGui.Prepare(ms_pguiRoot, ms_pguiOk, ms_pguiCancel);
- }
- else
- {
- TRACE("SetupDlg(): Failed to load .gui file!\n");
- }
- }
- else
- {
- TRACE("SetupDlg(): Failed to allocate RDlg!\n");
- sRes = -1;
- }
- // If any errors . . .
- if (sRes != 0)
- {
- DlgBeGone();
- }
- return sRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Get dialog resource
- //
- //////////////////////////////////////////////////////////////////////////////
- short DlgGetRes( // Returns 0 if successfull, non-zero otherwise
- RGuiItem* pgui) // I/O: Pointer to gui item
- {
- short sResult = 0;
- // Release resources first (just in case)
- DlgReleaseRes(pgui);
- // Allocate and load new resources. We get the name of the file (which
- // is ASSUMED to have NO PATH!!) from the gui itself, then tack on the
- // path we need and get the resource from the resource manager.
- char szFile[RSP_MAX_PATH * 2];
- sprintf(szFile, "%s%s", GUI_DIR, pgui->m_szBkdResName);
- if (rspGetResource(&g_resmgrShell, szFile, &pgui->m_pimBkdRes) == 0)
- {
- // Set palette
- ASSERT(pgui->m_pimBkdRes->m_pPalette != NULL);
- ASSERT(pgui->m_pimBkdRes->m_pPalette->m_type == RPal::PDIB);
- rspSetPaletteEntries(
- 0,
- 230,
- pgui->m_pimBkdRes->m_pPalette->Red(0),
- pgui->m_pimBkdRes->m_pPalette->Green(0),
- pgui->m_pimBkdRes->m_pPalette->Blue(0),
- pgui->m_pimBkdRes->m_pPalette->m_sPalEntrySize);
- // Update hardware palette.
- rspUpdatePalette();
- }
- else
- {
- sResult = -1;
- TRACE("DlgGetRes(): Failed to open file '%s'\n", FullPathVD(szFile));
- }
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Release dialog resource
- //
- //////////////////////////////////////////////////////////////////////////////
- void DlgReleaseRes( // Returns 0 if successfull, non-zero otherwise
- RGuiItem* pgui) // I/O: Pointer to gui item
- {
- rspReleaseResource(&g_resmgrShell, &pgui->m_pimBkdRes);
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Process GUI tree through one iteration.
- //
- //////////////////////////////////////////////////////////////////////////////
- static DLG_ACTION UpdateDialog( // Returns dialog action
- RGuiItem* pguiRoot, // In: GUI to process via user input.
- bool bReset) // In: If false, does not reset any
- // GUIs before returning their action.
- // Note that this means that the next
- // time through, we'll probably return
- // the same action.
- {
- // Get next input event.
- RInputEvent ie;
- // Make sure we start with no event.
- ie.type = RInputEvent::None;
- rspGetNextInputEvent(&ie);
- // Block minus sign right here (note that this will keep players
- // from being able to use '-' in chat strings).
- if (ie.type == RInputEvent::Key)
- {
- switch (ie.lKey & 0x0000FFFF)
- {
- case '-':
- ie.type = RInputEvent::None;
- break;
- }
- }
- // When we lose the focus, this might need to be updated.
- // Should we do it everytime?
- rspNameBuffers(&g_pimScreenBuf);
- // Process GUI through an iteration.
- long lPressedId = ms_pgDoGui.DoModeless(pguiRoot, &ie, g_pimScreenBuf);
- // If OK chosen or enter pressed . . .
- if (lPressedId == GUI_ID_OK || (ie.type == RInputEvent::Key && (ie.lKey & 0x0000FFFF) == '\r') )
- {
- // If there's a focus . . .
- if (RGuiItem::ms_pguiFocus)
- {
- // If in chatbox . . .
- if (RGuiItem::ms_pguiFocus == ms_pguiChatText)
- {
- // Send chat.
- RSP_SAFE_GUI_REF_VOID(ms_pguiChatSend, SetClicked(TRUE) );
- }
- else if (RGuiItem::ms_pguiFocus == ms_pguiRetry)
- {
- RSP_SAFE_GUI_REF_VOID(ms_pguiRetry, SetClicked(TRUE) );
- }
- else
- {
- // OK.
- RSP_SAFE_GUI_REF_VOID(ms_pguiOk, SetClicked(TRUE) );
- }
- }
- else
- {
- // OK.
- RSP_SAFE_GUI_REF_VOID(ms_pguiOk, SetClicked(TRUE) );
- }
- }
- // Return proper action based on what the user clicked on
- DLG_ACTION action = DLG_NOTHING;
- if (RSP_SAFE_GUI_REF(ms_pguiOk, IsClicked()))
- {
- if (bReset)
- {
- RSP_SAFE_GUI_REF_VOID(ms_pguiOk, SetClicked(FALSE));
- }
-
- action = DLG_OK;
- }
- if (RSP_SAFE_GUI_REF(ms_pguiCancel, IsClicked()))
- {
- if (bReset)
- {
- RSP_SAFE_GUI_REF_VOID(ms_pguiCancel, SetClicked(FALSE));
- }
- action = DLG_CANCEL;
- }
- if (RSP_SAFE_GUI_REF(ms_pguiRetry, IsClicked() ) )
- {
- if (bReset)
- {
- RSP_SAFE_GUI_REF_VOID(ms_pguiRetry, SetClicked(FALSE) );
- }
- action = DLG_RETRY;
- }
- if (RSP_SAFE_GUI_REF(ms_pguiChatSend, IsClicked()))
- {
- if (bReset)
- {
- if (ms_pguiChatSend)
- {
- ms_pguiChatSend->SetClicked(FALSE);
- // If focus is on the chat send . . .
- if (RGuiItem::ms_pguiFocus == ms_pguiChatSend && ms_pguiChatText)
- {
- // Switch back to the edit...makes sense on the user interface, I think.
- RGuiItem::SetFocus(ms_pguiChatText);
- }
- }
- }
- action = DLG_CHAT;
- }
- if (RSP_SAFE_GUI_REF(ms_pguiDisconnectPlayer, IsClicked() ) )
- {
- if (bReset)
- {
- RSP_SAFE_GUI_REF_VOID(ms_pguiDisconnectPlayer, SetClicked(FALSE) );
- }
- action = DLG_DISCONNECT_PLAYER;
- }
- // If no other action . . .
- if (action == DLG_NOTHING)
- {
- // Temporarily timed based. ***
- long lCurTime = rspGetMilliseconds();
- if (lCurTime > ms_lNextOptionsUpdateTime)
- {
- if (bReset)
- {
- ms_lNextOptionsUpdateTime = lCurTime + OPTIONS_SEND_FREQUENCY;
- }
- action = DLG_OPTIONS_UPDATED;
- }
- }
- if (ms_pmbCoopLevels)
- {
- // If not pressed . . .
- if (ms_pmbCoopLevels->m_sState > 0)
- {
- bool bCoopLevels = (ms_pmbCoopLevels->m_sState == 2) ? true : false;
- // If status has changed . . .
- if (bCoopLevels != ms_bCoopLevels)
- {
- // Set new value.
- ms_bCoopLevels = bCoopLevels;
- // Repaginate.
- ShowLevels();
- // If showing deathmatch levels . . .
- if (bCoopLevels == false && ms_pmbCoopMode)
- {
- // Since cooperative mode in deathmatch levels makes little
- // sense, let's automagically switch to deathmatch mode for
- // convenience sake.
- ms_pmbCoopMode->m_sState = 2;
- ms_pmbCoopMode->Compose();
- }
- }
- }
- }
- return action;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Update hosts listbox for browser.
- //
- //////////////////////////////////////////////////////////////////////////////
- static short UpdateListBox( // Returns 0 on success.
- RListBox* plb, // In: Browser listbox.
- CNetBrowse::Hosts* phostslistPersist, // In: Hosts.
- CNetBrowse::Hosts* phostslistAdded, // In: Hosts to add to listbox.
- CNetBrowse::Hosts* phostslistDropped) // In: Hosts to drop from listbox.
- {
- short sResult = 0; // Assume success.
- if (plb)
- {
- CNetBrowse::Hosts::Pointer i;
- bool bRepaginate = false;
-
- // Look for unGUIed entries . . .
- for (i = phostslistPersist->GetHead(); i; i = phostslistPersist->GetNext(i))
- {
- CNetBrowse::CHost* phost = &(phostslistPersist->GetData(i) );
- // If not yet GUIed . . .
- if ( !(phost->m_u32User) )
- {
- RGuiItem* pgui = plb->AddString(phost->m_acName);
- if (pgui)
- {
- // Activate shadow parameters.
- MakeMoreReadable(pgui);
- pgui->Compose();
- // Point GUI at entry.
- pgui->m_ulUserData = (ULONG)phost;
- // Successfully added entry.
- phost->m_u32User = (U32)pgui;
- // Note that we updated the dialog and will need to re-adjust
- // fields and recompose.
- bRepaginate = true;
- }
- else
- {
- TRACE("UpdateListBox(): Failed to add a host to the listbox.\n");
- // sResult = -1; // Error?
- }
- }
- }
- // For whatever it's worth, let's do dropped first so it'll be a little
- // faster. On second thought, let's not. It just seems a bit scary. Like,
- // if a host gets added and then dropped on the same iteration, it will not
- // be in the listbox and I was using that conidition to hopefully flag bugs.
- // Note that we use the m_u32User field of the host structure to store a pointer
- // to the corresponding GUI item. Since we know these host items get copied
- // from the added list to the main list and then, possibly, to the dropped list
- // this value will remain with the host all the way to the dropped list.
- while (phostslistDropped->GetHead())
- {
- // Get pointer to first host in list
- U32 u32User = phostslistDropped->GetHeadData().m_u32User;
- // We should have already been using this.
- ASSERT(u32User);
- if (u32User)
- {
- // Remove the corresponding GUI list entry from the listbox.
- plb->RemoveItem((RGuiItem*)(u32User));
- // Note that we updated the dialog and will need to re-adjust
- // fields and recompose.
- bRepaginate = true;
- }
- // Remove first host in list
- phostslistDropped->RemoveHead();
- }
- if (bRepaginate)
- {
- plb->AdjustContents();
- }
- // If there is a selection . . .
- if (plb->GetSel() )
- {
- // Currently, we view this as a choice. Let's simply set the OK button
- // so it'll be easy to switch back and forth between these two methods.
- RSP_SAFE_GUI_REF_VOID(ms_pguiOk, SetClicked(TRUE) );
- }
- // Empty the added list, which we don't use, but we don't want it to keep
- // growing either, and it's our responsibility to empty it.
- while (phostslistAdded->GetHead())
- phostslistAdded->RemoveHead();
- }
- else
- {
- TRACE("UpdateListBox(): No listbox to update.\n");
- sResult = -1;
- }
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Add a console message.
- //
- //////////////////////////////////////////////////////////////////////////////
- static void AddConsoleMsg( // Returns nothing.
- bool bChat, // In: true for a chat message, or false for others (like net status).
- const char* pszFrmt, // In: sprintf style formatting.
- ...) // In: Optional arguments based on context of pszFrmt.
- {
- if (ms_plbNetConsole != NULL)
- {
- char szOutput[MAX_STATUS_STR];
- va_list varp;
- va_start(varp, pszFrmt);
- vsprintf(szOutput, pszFrmt, varp);
- va_end(varp);
- U32 u32TextColor = ms_plbNetConsole->m_u32TextColor;
- char szMsg[MAX_STATUS_STR];
- // If it's a chat message . . .
- if (bChat)
- {
- // Verbatim is good (already includes name and such).
- strcpy(szMsg, szOutput);
- }
- else
- {
- // Otherwise, add optional prefix.
- sprintf(szMsg, "%s%s", g_pszNetStatusMsgPrefix, szOutput);
- // And use alternate color.
- u32TextColor = NET_STATUS_MSG_COLOR_INDEX;
- }
- bool bRepaginate = false; // true to repaginate the listbox.
- // If this one will put us over . . .
- if (ms_lNumConsoleEntries >= MAX_CHAT_STRINGS)
- {
- // Get the oldest chat.
- RGuiItem* pguiOldestConsoleMsg = ms_plbNetConsole->GetFirst();
- if (pguiOldestConsoleMsg)
- {
- // Remove it.
- ms_plbNetConsole->RemoveItem(pguiOldestConsoleMsg);
- // Repaginate.
- bRepaginate = true;
- }
- }
- RGuiItem* pguiConsoleMsg = ms_plbNetConsole->AddString(szMsg);
- if (pguiConsoleMsg)
- {
- // Another chat.
- ms_lNumConsoleEntries++;
- // Store the old border thickness so we know how much we can reduce
- // these.
- short sOrigTotalBorderThickness = pguiConsoleMsg->GetTopLeftBorderThickness() + pguiConsoleMsg->GetBottomRightBorderThickness();
- // No lines.
- pguiConsoleMsg->m_sBorderThickness = 0;
- // Adjust color.
- pguiConsoleMsg->m_u32TextColor = u32TextColor;
- // Activate shadow parameters.
- MakeMoreReadable(pguiConsoleMsg);
- // Recreate without space for border lines . . .
- if (pguiConsoleMsg->Create(
- pguiConsoleMsg->m_sX,
- pguiConsoleMsg->m_sY,
- // We want to keep these as small as possible so we can fit as many as possible.
- // Subtract the border thickness since we don't use it but add 1 for text shadow effect.
- pguiConsoleMsg->m_im.m_sWidth - sOrigTotalBorderThickness + 1,
- pguiConsoleMsg->m_im.m_sHeight - sOrigTotalBorderThickness + 1,
- pguiConsoleMsg->m_im.m_sDepth) == 0)
- {
- // We cannot click on these.
- pguiConsoleMsg->m_sActive = FALSE;
- pguiConsoleMsg->SetActive(FALSE);
- // Repaginate now, now.
- ms_plbNetConsole->AdjustContents();
- // Ensure the new item is visible.
- ms_plbNetConsole->EnsureVisible(pguiConsoleMsg);
- }
- else
- {
- // This is useless then.
- delete pguiConsoleMsg;
- pguiConsoleMsg = NULL;
- }
- }
- else
- {
- // If we need to repaginate anyways . . .
- if (bRepaginate)
- {
- // Repaginate now even though we failed to add a new string.
- ms_plbNetConsole->AdjustContents();
- }
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Get descriptive text associated with specified error message
- //
- //////////////////////////////////////////////////////////////////////////////
- extern const char* NetErrorText( // Returns pointer to text
- NetMsg* pmsg) // In: Error message
- {
- static char szStaticErrorText[512];
- char* pText = "";
- if (pmsg->msg.nothing.ucType == NetMsg::ERR)
- {
- switch (pmsg->msg.err.error)
- {
- case NetMsg::NoError:
- pText = g_pszNetStat_NoError;
- break;
- case NetMsg::ReceiveError:
- pText = g_pszNetStat_ReceiveError;
- break;
- case NetMsg::InQFullError:
- pText = g_pszNetStat_InQFullError;
- break;
- case NetMsg::OutQFullError:
- pText = g_pszNetStat_OutQFullError;
- break;
- case NetMsg::SendError:
- pText = g_pszNetStat_SendError;
- break;
- case NetMsg::InQReadError:
- pText = g_pszNetStat_InQReadError;
- break;
- case NetMsg::OutQWriteError:
- pText = g_pszNetStat_OutQWriteError;
- break;
- case NetMsg::ConnectionError:
- pText = g_pszNetStat_ConnectionError;
- break;
- case NetMsg::TimeoutError:
- pText = g_pszNetStat_TimeoutError;
- break;
- case NetMsg::ListenError:
- pText = g_pszNetStat_ListenError;
- break;
- case NetMsg::CantConnectError:
- pText = g_pszNetStat_ConnectError;
- break;
- case NetMsg::ConnectTimeoutError:
- pText = g_pszNetStat_ConnectTimeoutError;
- break;
- case NetMsg::ServerVersionMismatchError:
- pText = szStaticErrorText;
- sprintf(pText, g_pszNetStat_ServerVersionMismatchError_lu_lu, pmsg->msg.err.ulParam, CNetMsgr::CurVersionNum & ~CNetMsgr::MacVersionBit);
- break;
- case NetMsg::ClientVersionMismatchError:
- pText = szStaticErrorText;
- sprintf(pText, g_pszNetStat_ClientVersionMismatchError_lu_lu, pmsg->msg.err.ulParam, CNetMsgr::CurVersionNum & ~CNetMsgr::MacVersionBit);
- break;
- case NetMsg::LoginDeniedError:
- pText = g_pszNetStat_LoginDeniedError;
- break;
- case NetMsg::JoinDeniedError:
- pText = g_pszNetStat_JoinDeniedError;
- break;
- case NetMsg::CantOpenPeerSocketError:
- pText = g_pszNetStat_CantOpenPeerSocketError;
- break;
- case NetMsg::ServerPlatformMismatchError:
- pText = g_pszNetStat_ServerPlatformMismatchError;
- break;
- case NetMsg::ClientPlatformMismatchError:
- pText = g_pszNetStat_ClientPlatformMismatchError;
- break;
- default:
- pText = g_pszNetStat_UnknownError;
- break;
- }
- }
- return pText;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Get the realm filename from the realm title, using the INI.
- //
- //////////////////////////////////////////////////////////////////////////////
- static short GetRealmFileFromRealmTitle( // Returns 0, if found; non-zero
- // otherwise.
- bool bCoopLevel, // In: true, if a coop level; false, if deathmatch level.
- char* pszRealmTitle, // In: Realm title.
- char* pszRealmFileName, // Out: Realm filename.
- short sMaxLen) // In: Max space available at
- // pszRealmFileName.
- {
- short sResult = 0; // Assume success.
- RPrefs prefsRealm;
- // Try opening the realms.ini file on the HD path first, if that fails go to the CD
- sResult = prefsRealm.Open(FullPathHD(g_GameSettings.m_pszRealmPrefsFile), "rt");
- if (sResult != 0)
- sResult = prefsRealm.Open(FullPathCD(g_GameSettings.m_pszRealmPrefsFile), "rt");
- if (sResult == 0)
- {
- // Try each realm section until we find the title we're looking for
- // or we find an empty entry.
- // Multiplayer sections are named "RealmNet1, "RealmNet2", etc.
- // Multiplayer realm entry is always "Realm".
- // The title is always "Title".
- short sRealmNum = 1;
- char szRealmTitle[512];
- char szSection[512];
- bool bFound = false;
- do
- {
- // Form section name.
- sprintf(
- szSection,
- "Realm%sNet%d",
- bCoopLevel ? "Coop" : "",
- sRealmNum++);
- // Safety; renitialize.
- szRealmTitle[0] = '\0';
- // Get the title for this net realm.
- prefsRealm.GetVal(szSection, "Title", "", szRealmTitle);
- // If this is the title of the realm we're looking for . . .
- if (rspStricmp(szRealmTitle, pszRealmTitle) == 0)
- {
- // Found it; get filename.
- // Note that there's no real way to use the sMaxLen.
- prefsRealm.GetVal(szSection, "Realm", "", pszRealmFileName);
- // Done.
- bFound = true;
- }
- } while (szRealmTitle[0] != '\0' && bFound == false);
- // If we didn't find it . . .
- if (bFound == false)
- {
- // Let the caller know.
- sResult = 1;
- }
- }
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Client has been dropped
- //
- //////////////////////////////////////////////////////////////////////////////
- static void OnDroppedMsg(
- CNetClient* pnet, // In: Network interface.
- NetMsg* pmsg) // In: Dropped msg from client to remove.
- {
- ASSERT(pmsg->msg.nothing.ucType == NetMsg::DROPPED);
- // Print message while player's info is still in our database
- if (pmsg->msg.dropped.id == Net::InvalidID)
- AddConsoleMsg(false, "%s", g_pszClientStat_YouWereDropped);
- else
- AddConsoleMsg(false, g_pszClientStat_SomeoneDropped_s, pnet->GetPlayerName(pmsg->msg.dropped.id));
- // Update number of players displayed.
- RGuiItem* pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC1);
- RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, pnet->GetNumPlayers()));
- RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose());
- pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC2);
- RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, pnet->GetNumPlayers()));
- RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose());
- // Get client's GUI . . .
- RGuiItem* pguiClient = ms_plbPlayers->GetItemFromId( long(pmsg->msg.dropped.id));
- if (pguiClient != NULL)
- {
- // Remove the item.
- ms_plbPlayers->RemoveItem(pguiClient);
- ms_plbPlayers->AdjustContents();
- }
- else
- {
- TRACE("RemoveClient(): We didn't even know of this client!!\n");
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Player has joined
- //
- //////////////////////////////////////////////////////////////////////////////
- static short OnJoinedMsg( // Returns 0 on success.
- CNetClient* pnet, // In: Network interface.
- NetMsg* pmsg, // In: Joined msg from client to add.
- bool bServer) // In: true if in server mode; false if client.
- {
- short sRes = 0; // Assume success.
- ASSERT(pmsg->msg.nothing.ucType == NetMsg::JOINED);
-
- UCHAR ucColorIndex = pmsg->msg.joined.ucColor;
- if (ucColorIndex >= CGameSettings::ms_sNumPlayerColorDescriptions)
- ucColorIndex = 0;
- // Add info to listbox.
- char szPlayer[256];
- sprintf(szPlayer, "%s (%s)", pmsg->msg.joined.acName, CGameSettings::ms_apszPlayerColorDescriptions[ucColorIndex]);
- // Update number of players displayed.
- RGuiItem* pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC1);
- RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, pnet->GetNumPlayers()));
- RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose() );
- pguiConnected = ms_pguiRoot->GetItemFromId(GUI_ID_PLAYERS_STATIC2);
- RSP_SAFE_GUI_REF_VOID(pguiConnected, SetText(g_pszNetDlg_ConnectedPlayers_d, pnet->GetNumPlayers()));
- RSP_SAFE_GUI_REF_VOID(pguiConnected, Compose() );
- RGuiItem* pguiClient = ms_plbPlayers->AddString(szPlayer);
- if (pguiClient != NULL)
- {
- // Let's be able to identify this client by its net ID.
- pguiClient->m_lId = (long)pmsg->msg.joined.id;
- // Don't allow the user to select these in client mode . . .
- if (bServer == false)
- {
- pguiClient->m_sActive = FALSE;
- pguiClient->SetActive(FALSE);
- }
- // Activate shadow parameters.
- MakeMoreReadable(pguiClient);
- pguiClient->Compose();
- ms_plbPlayers->AdjustContents();
- ms_plbPlayers->EnsureVisible(pguiClient);
- }
- else
- {
- TRACE("OnJoinedMsg(): ms_plbPlayers->AddString() failed.\n");
- sRes = -1;
- }
- return sRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Player has changed info
- //
- //////////////////////////////////////////////////////////////////////////////
- static short OnChangedMsg( // Returns 0 on success.
- CNetClient* pnet, // In: Network interface.
- NetMsg* pmsg) // In: Changed msg
- {
- short sRes = 0; // Assume success.
- ASSERT(pmsg->msg.nothing.ucType == NetMsg::CHANGED);
- TRACE("OnChangedMsg(): Changes are not yet refelected in the gui's!\n");
- return sRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Incoming chat message
- //
- //////////////////////////////////////////////////////////////////////////////
- static void OnChatMsg(
- CNetClient* pnet, // In: Network interface.
- NetMsg* pmsg) // In: Chat msg.
- {
- ASSERT(pmsg->msg.nothing.ucType == NetMsg::CHAT);
- AddConsoleMsg(true, "%s", pmsg->msg.chat.acText);
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Handles SetupGame message.
- //
- //////////////////////////////////////////////////////////////////////////////
- static void OnSetupGameMsg(
- CNetClient* pnet, // In: Network interface.
- NetMsg* pmsg) // In: Message.
- {
- // Paginate into user displayable single string.
- if (ms_pguiOptions)
- {
- // Check whether this message contains the same realm info as the last such
- // message, if there was one. In other words, is there new realm info?
- bool bNewRealm = false;
- if (ms_bGotSetupMsg)
- {
- if ((pmsg->msg.setupGame.sRealmNum != ms_sSetupRealmNum) ||
- (rspStricmp(pmsg->msg.setupGame.acRealmFile, ms_szSetupRealmFile) != 0))
- {
- bNewRealm = true;
- }
- }
- else
- {
- bNewRealm = true;
- }
- // If it's new, save it for next time
- if (bNewRealm)
- {
- ms_sSetupRealmNum = pmsg->msg.setupGame.sRealmNum;
- strcpy(ms_szSetupRealmFile, pmsg->msg.setupGame.acRealmFile);
- ms_bGotSetupMsg = true;
- }
- // Determine whether the selected realm is available
- bool bAvailable = false;
- #ifdef ENABLE_PLAY_SPECIFIC_REALMS_ONLY
- // If there's only specific realms available, we simply check for
- // the hardwired values.
- if (pmsg->msg.setupGame.sRealmNum > -1)
- {
- if (pmsg->msg.setupGame.sRealmNum == SPECIFIC_MP_REALM_NUM)
- bAvailable = true;
- }
- else
- {
- if (rspStricmp(pmsg->msg.setupGame.acRealmFile, SPECIFIC_MP_REALM_TEXT) == 0)
- bAvailable = true;
- }
- #else
- // If it's a full version of the game, we still need to see if the specified
- // file is available because the host may be trying to use an add-on realm
- // that wasn't on the original CD.
- if (pmsg->msg.setupGame.sRealmNum > -1)
- {
- // Convert realm number to file name
- char szFile[RSP_MAX_PATH];
- if (Play_GetRealmInfo(
- true, // Multiplayer
- pmsg->msg.setupGame.sCoopLevels ? true : false, // Cooperative or Deathmatch levels
- false, // Not gauntlet
- false, // Not new single player Add On levels
- pmsg->msg.setupGame.sRealmNum,
- pmsg->msg.setupGame.sDifficulty,
- szFile,
- sizeof(szFile)) == 0)
- {
- // Check if file is available
- if (CRealm::DoesFileExist(szFile))
- bAvailable = true;
- }
- }
- else
- {
- // acRealmFile, due to a bizzarre twist of events, is never a filename
- // but, rather, the title of the realm. The only way we can get a filename
- // from this title is to scan the NetRealm's in the INI.
- char szRealmFileName[RSP_MAX_PATH];
- if (GetRealmFileFromRealmTitle(
- pmsg->msg.setupGame.sCoopLevels ? true : false, // Cooperative or Deathmatch levels
- pmsg->msg.setupGame.acRealmFile,
- szRealmFileName,
- sizeof(szRealmFileName) ) == 0)
- {
- // Check if file is available
- if (CRealm::DoesFileExist(szRealmFileName))
- bAvailable = true;
- }
- }
- #endif
- // If level is available, display info about it. Otherwise, say it isn't available!
- if (bAvailable)
- {
- char szCoop[256] = "";
- if (pmsg->msg.setupGame.sCoopLevels != 0)
- {
- strcpy(szCoop, "Cooperative ");
- }
- char szRealm[256];
- if (pmsg->msg.setupGame.sRealmNum > -1)
- {
- // Use number.
- sprintf(szRealm, "Level %hd", pmsg->msg.setupGame.sRealmNum);
- }
- else
- {
- // Use string.
- sprintf(szRealm, "\"%s\"", pmsg->msg.setupGame.acRealmFile);
- }
- char szPlayMode[256];
- if (pmsg->msg.setupGame.sCoopMode)
- {
- strcpy(szPlayMode, "Cooperative");
- }
- else
- {
- strcpy(szPlayMode, "Deathmatch");
- }
- char szTimeLimit[256];
- if (pmsg->msg.setupGame.sTimeLimit > 0)
- {
- sprintf(szTimeLimit, "a time limit of %hd", pmsg->msg.setupGame.sTimeLimit);
- }
- else
- {
- sprintf(szTimeLimit, "no time limit");
- }
- char szKillLimit[256];
- if (pmsg->msg.setupGame.sKillLimit > 0)
- {
- sprintf(szKillLimit, "a kill limit of %hd", pmsg->msg.setupGame.sKillLimit);
- }
- else
- {
- sprintf(szKillLimit, "no kill limit");
- }
- ms_pguiOptions->SetText(
- "Host has selected %s%s in %s mode on difficulty %hd with %s and %s.",
- szCoop,
- szRealm,
- szPlayMode,
- pmsg->msg.setupGame.sDifficulty,
- szTimeLimit,
- szKillLimit);
- }
- else
- {
- // Tell the local user that the selected level is not available
- ms_pguiOptions->SetText("Host has selected a level you don't have!");
- // Send a text message to all players (we'd like to send it to just the host,
- // but we don't support that, and maybe it's nice that the other players see
- // it, too). The message complains that the selected level is not available.
- // Note that we only send this when the realm info has changed, so as to avoid
- // sending an endless stream of the same messages over and over.
- if (bNewRealm)
- {
- char szTmp[1024];
- #ifdef ENABLE_PLAY_SPECIFIC_REALMS_ONLY
- sprintf(szTmp, "%s\"%s\" only has the \""SPECIFIC_MP_REALM_TEXT"\" hood -- please pick it!",
- g_pszNetStatusMsgPrefix,
- pnet->GetPlayerName(pnet->GetID()));
- pnet->SendText(szTmp);
- #else
- sprintf(szTmp, "%s\"%s\" does not have the selected hood -- please pick another one!",
- g_pszNetStatusMsgPrefix,
- pnet->GetPlayerName(pnet->GetID()));
- pnet->SendText(szTmp);
- #endif
- }
- }
- // Compose options GUI with word wrap preserving original word wrap status.
- ComposeOptions();
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Explain the fact that the procol the user chose is not supported
- //
- //////////////////////////////////////////////////////////////////////////////
- void ProtoNotSupported(void)
- {
- // Check if there's only one protocol or more than one
- if (RSocket::FirstProtocol + 1 == RSocket::NumProtocols)
- {
- // Only one protocol
- rspMsgBox(
- RSP_MB_BUT_OK | RSP_MB_ICN_INFO,
- g_pszAppName,
- g_pszNetOnlyProtocolUnsupported_s,
- RSocket::GetProtoName());
- }
- else
- {
- // More than one protocol
- rspMsgBox(
- RSP_MB_BUT_OK | RSP_MB_ICN_INFO,
- g_pszAppName,
- g_pszNetProtocolUnsupported_s,
- RSocket::GetProtoName());
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Do network game dialog
- //
- //////////////////////////////////////////////////////////////////////////////
- extern short DoNetGameDialog( // Returns 0 if successfull, non-zero otherwise.
- CNetClient* pclient, // I/O: Client interface
- bool bBrowse, // In: Whether to browse (true) or connect (false)
- CNetServer* pserver, // I/O: Server interface or NULL if not server
- NetMsg* pmsgOut) // Out: NetMsg::NOTHING or NetMsg::START_GAME
- {
- ASSERT(pclient != NULL);
- short sResult = 0; // Assume success.
- // Under Win95 with DirectX, certain problems have come up due to a
- // combination of our hogging the CPU and DirectX adding to that hogging,
- // and us taking over the screen via DirectX, all of which is a problem
- // when the dialup-networking dialog tries to display itself. In an
- // attempt to alleviate some of this, we go to a lower-level of CPU hogging
- // during the network dialogs, and restore the level afterwards.
- rspSetDoSystemMode(RSP_DOSYSTEM_TOLERATEOS);
- // Init globals
- ms_pguiRoot = NULL;
- ms_pguiOk = NULL;
- ms_pguiCancel = NULL;
- ms_plbPlayers = NULL;
- ms_plbNetConsole = NULL;
- ms_pguiChatText = NULL;
- ms_pguiChatSend = NULL;
- ms_plbLevelBrowse = NULL;
- ms_pmbCoopLevels = NULL;
- ms_pmbCoopMode = NULL;
- ms_pguiRetry = NULL;
- ms_lWatchdogTime = 0;
- ms_bNetBlockingAbort = false;
- // We haven't received a setup msg yet
- ms_bGotSetupMsg = false;
- ClearNetProb();
- // Make sure vars with built in flagging get reflected properly.
- // No time limit is flagged as 0 or negative
- if (g_GameSettings.m_sHostTimeLimit > 0)
- {
- ms_bTimeLimit = true;
- }
- else
- {
- ms_bTimeLimit = false;
- g_GameSettings.m_sHostTimeLimit = -g_GameSettings.m_sHostTimeLimit;
- }
-
- // No kill limit is flagged as 0 or negative
- if (g_GameSettings.m_sHostKillLimit > 0)
- {
- ms_bKillLimit = true;
- }
- else
- {
- ms_bKillLimit = false;
- g_GameSettings.m_sHostKillLimit = -g_GameSettings.m_sHostKillLimit;
- }
- // Save current mouse cursor level and then force it to be visible
- short sCursorLevel = rspGetMouseCursorShowLevel();
- rspSetMouseCursorShowLevel(1);
- // Clear any events that might be in the queue
- rspClearAllInputEvents();
- // *************************** TEMP
- // bBrowse = true;
- // *************************** TEMP
- // If we're browsing, this loop continues until the user aborts or starts.
- // If we're not browsing, this loop only goes through once.
- bool bAbort = false;
- bool bStart = false;
- do {
- // Call this periodically to let it know we're not locked up
- NetBlockingWatchdog();
- // Default to returning a NetMsg::NOTHING
- pmsgOut->msg.nothing.ucType = NetMsg::NOTHING;
- // If there's a server, start it up
- if (pserver)
- sResult = pserver->Startup(g_GameSettings.m_usServerPort, g_GameSettings.m_szHostName, &NetBlockingCallback);
- if (sResult == 0)
- {
- // Host address
- RSocket::Address addressHost;
- // If we're browsing, do it before the client dialog since it uses a dialog of its own
- if (bBrowse)
- sResult = BrowseForHost(pserver, &addressHost);
- if (sResult == 0)
- {
- // Setup dialog in client or server mode, as appropriate
- sResult = SetupDlg(pserver ? FullPathHD(SERVER_GUI) : FullPathVD(CLIENT_GUI), pserver ? DLG_SERVER : DLG_CLIENT);
- if (sResult == 0)
- {
- // Display "startup" messages
- if (pserver)
- AddConsoleMsg(false, "%s", g_pszServerStat_Startup);
- else
- AddConsoleMsg(false, g_pszClientStat_Startup);
- // Update the dialog so it shows up on the screen. We ignore the
- // return since we aren't ready to deal with it here. This seems
- // okay since the dialog has just shown up, so nobody (except Jeff)
- // could possibly hit a key or mouse button on the first frame.
- UpdateDialog(ms_pguiRoot, true);
- // If we didn't browse for a host, we still need to find one
- if (!bBrowse)
- {
- if (pserver)
- {
- // Try to find the local server
- sResult = BrowseForSelf(pserver, &addressHost);
- }
- else
- {
- // The local client tries to find a remote server
- sResult = FindSpecificSystem(&addressHost);
- }
- }
- if (sResult == 0)
- {
- // This loop is used for when the user hits the "RETRY" button on the client dialog
- bool bRetry = false;
- do {
- // Clear retry flag each time so we don't accidentally get caught in a loop
- bRetry = false;
- // Startup client
- pclient->Startup(&NetBlockingCallback);
- // Start the (asynchronous) process of joining the specified host. We
- // specifically check for the "protocol not supported" error and handle
- // that as a special case, because users are likely to screw that up.
- // Any other errors will be discovered via our normal GetMsg() loop.
- sResult = pclient->StartJoinProcess(
- &addressHost,
- g_GameSettings.m_szPlayerName,
- g_GameSettings.m_sPlayerColorIndex,
- 0,
- g_GameSettings.m_sNetBandwidth);
- if (sResult != RSocket::errNotSupported)
- {
- //------------------------------------------------------------------------------
- // This may appear to be a rather bizarre loop, and maybe it is, but it seemed
- // like a really good idea at the time...
- //
- // It handles three primary tasks. First, if this machine is a server, it does
- // all the server stuff. Then, it does the client stuff (remember that a server
- // is always a client, but a client is not necessarily a server). Finally, it
- // does the dialog and user-input stuff, which again is slightly different
- // depending on whether it's a client or a server.
- //
- // The alternative approach was to have separate functions to handle the client
- // and server ends. It was originally that way, but there was so much
- // similarity between the two that it seemed better to merge them, thereby
- // avoiding having to maintain two very similar sets of code.
- //
- // A key point about this loop is that you should NEVER use a 'break' to get
- // out of the loop. In fact, you should rarely exit the loop in any kind of
- // direct manner. Instead, you should always try to wait until the client
- // and server (if any) have been allowed to "gracefully" finish whatever it
- // is they need to get done.
- //
- // Note that if the user clicks the "ABORT" button in the dialog, we don't
- // immediately end the loop, either. We simply set the flags and hope the
- // loop will end itself soon enough. If, after a certain amount of time, the
- // loop hasn't ended, the user can click "ABORT" again to end, and this time
- // we end immediately. At some point, this should perhaps be replaced by a
- // timer which automatically ends the loop after a certain amount of time.
- //------------------------------------------------------------------------------
- bool bEndClientCleanly = false;
- bool bEndServerCleanly = false;
- bool bServerDone = pserver ? false : true;
- bool bClientDone = false;
- bool bUserAbortNow = false;
- long lCancelDelay;
- DLG_ACTION action;
- NetMsg msg;
- while (!(bClientDone && bServerDone && (bAbort || bStart || bRetry)) && !bUserAbortNow)
- {
- // Always and forever
- UpdateSystem();
- // Call this periodically to let it know we're not locked up
- NetBlockingWatchdog();
- //------------------------------------------------------------------------------
- // Do dialog and any other user-input stuff
- //------------------------------------------------------------------------------
- // Update GUI
- action = UpdateDialog(ms_pguiRoot, true);
- // If user wants to quit, simulate a cancel. Note that this is NOT an event
- // but a flag, so once it starts, we'll continue to get CANCEL actions each
- // time we get to this point. This is exactly what we want, since this type
- // of quit indicates that the user doesn't want to wait around to quit.
- if (rspGetQuitStatus() || NetBlockingWasAborted())
- action = DLG_CANCEL;
- // Handle action
- switch (action)
- {
- // Nothing to do
- case DLG_NOTHING:
- break;
- // OK was pressed. This only exists on server dialog! Note that we don't
- // allow OK to be used if either it or Cancel were already used.
- case DLG_OK:
- // Must be server. . .
- if (pserver)
- {
- // Make sure neither OK nor Cancel were pressed, and that we have at least 1 client
- if (!bStart && !bAbort && pserver->GetNumberOfClients())
- {
- // Download GUI vals.
- DownloadLinks(ms_aglServerLinkage, ms_pguiRoot);
- // Feedback
- PlaySample(g_smidMenuItemSelect, SampleMaster::UserFeedBack);
- AddConsoleMsg(false, "%s", g_pszNetStat_Starting);
- // Get pointer to game selection GUI
- RGuiItem* pguiSel = RSP_SAFE_GUI_REF(ms_plbLevelBrowse, GetSel());
- // Start game using specified settings
- pserver->StartGame(
- pclient->GetID(),
- #ifdef ENABLE_PLAY_SPECIFIC_REALMS_ONLY
- -1,
- SPECIFIC_MP_REALM_FILE,
- #else
- RSP_SAFE_GUI_REF(pguiSel, m_lId),
- "",
- #endif
- g_GameSettings.m_sDifficulty,
- g_GameSettings.m_sHostRejuvenate,
- ms_bTimeLimit ? g_GameSettings.m_sHostTimeLimit : -g_GameSettings.m_sHostTimeLimit,
- ms_bKillLimit ? g_GameSettings.m_sHostKillLimit : -g_GameSettings.m_sHostKillLimit,
- ms_bCoopLevels ? 1 : 0,
- ms_bCoopMode ? 1 : 0,
- g_GameSettings.m_sNetTimePerFrame,
- g_GameSettings.m_sNetMaxFrameLag);
- // End server cleanly (client will end when it gets start message)
- bEndServerCleanly = true;
- }
- }
- break;
- // Cancel was pressed. Note that in server mode, we allow cancel to be
- // pressed even after OK was pressed. We merely send another message
- // to the clients saying to abort the game that was already started.
- case DLG_CANCEL:
- // If cancel was already pressed, we ignore additional cancel's until
- // the timer has expired, at which point they can hit cancel again.
- // The idea is to give the cancel process time to finish cleanly.
- if (bAbort)
- {
- if ((rspGetMilliseconds() - lCancelDelay) > CANCEL_DELAY_TIME)
- {
- // Feedback sound
- PlaySample(g_smidMenuItemSelect, SampleMaster::UserFeedBack);
- // User has aborted, exit immediately
- bUserAbortNow = true;
- }
- }
- else
- {
- // Pressed cancel, so set flag and init delay timer
- bAbort = true;
- lCancelDelay = rspGetMilliseconds();
- // Feedback
- AddConsoleMsg(false, "%s", g_pszNetStat_Aborting);
- PlaySample(g_smidMenuItemSelect, SampleMaster::UserFeedBack);
- if (pserver)
- {
- // Download GUI vals anyways for consistency.
- DownloadLinks(ms_aglServerLinkage, ms_pguiRoot);
- // Tell players to abort game
- pserver->AbortGame(NetMsg::UserAbortedGame);
- }
- else
- {
- // Drop out of game
- pclient->Drop();
- // Start with a clean slate (no RETRY button because user selected ABORT)
- CleanClientDlg(pclient, false);
- }
- // End server and client cleanly
- bEndServerCleanly = true;
- bEndClientCleanly = true;
- }
- break;
- // Chat was pressed. We don't allow this if OK or Cancel were pressed.
- case DLG_CHAT:
- // Make sure neither Ok nor Cancel were pressed
- if (!bStart && !bAbort)
- {
- // Make sure text field exists
- if (ms_pguiChatText != NULL)
- {
- // See if there's any text
- if (ms_pguiChatText->m_szText[0] != '\0')
- {
- // Sent chat
- pclient->SendChat(ms_pguiChatText->m_szText);
- // Clear text
- ms_pguiChatText->SetText("");
- ms_pguiChatText->Compose();
- }
- }
- }
- break;
- // Disconnect player was pressed. We don't allow this if OK or Cancel were pressed.
- case DLG_DISCONNECT_PLAYER:
- // Make sure neither Ok nor Cancel were pressed
- if (!bStart && !bAbort)
- {
- // If there's a selection . . .
- RGuiItem* pguiPlayerSel = ms_plbPlayers->GetSel();
- if (pguiPlayerSel)
- {
- Net::ID id = (UCHAR)pguiPlayerSel->m_lId;
- // Don't be a moron -- don't drop yourself
- if (id == pclient->GetID())
- {
- // Tell user he can't drop himself
- AddConsoleMsg(false, "%s", g_pszServerStat_CantDropSelf);
- }
- else
- {
- // Drop player (must get his name BEFORE he is dropped!)
- AddConsoleMsg(false, g_pszNetStat_AttemptToDrop_s, pserver->GetPlayerName(id));
- pserver->DropClient(id);
- }
- }
- }
- break;
- // Send an options update. We don't allow this if OK or Cancel were pressed.
- case DLG_OPTIONS_UPDATED:
- if (pserver && !bStart && !bAbort)
- {
- // Get current settings into their variables.
- DownloadLinks(ms_aglServerLinkage, ms_pguiRoot);
- // Get pointer to game selection GUI
- RGuiItem* pguiSel = RSP_SAFE_GUI_REF(ms_plbLevelBrowse, GetSel());
- // Setup game
- pserver->SetupGame(
- #ifdef ENABLE_PLAY_SPECIFIC_REALMS_ONLY
- -1,
- SPECIFIC_MP_REALM_TEXT,
- #else
- pguiSel ? -1 : 0,
- pguiSel ? pguiSel->m_szText : "",
- #endif
- g_GameSettings.m_sDifficulty,
- g_GameSettings.m_sHostRejuvenate,
- ms_bTimeLimit ? g_GameSettings.m_sHostTimeLimit : -g_GameSettings.m_sHostTimeLimit,
- ms_bKillLimit ? g_GameSettings.m_sHostKillLimit : -g_GameSettings.m_sHostKillLimit,
- ms_bCoopLevels ? 1 : 0,
- ms_bCoopMode ? 1 : 0);
- }
- break;
- case DLG_RETRY:
- if (!bStart && !bAbort)
- {
- // Clean the slate (without RETRY since they just hit it and may not need it again)
- CleanClientDlg(pclient, false);
- // Feedback
- PlaySample(g_smidMenuItemSelect, SampleMaster::UserFeedBack);
- AddConsoleMsg(false, "%s", g_pszClientStat_Retrying);
- AddConsoleMsg(false, g_pszClientStat_Startup);
- // End server and client cleanly
- bEndServerCleanly = true;
- bEndClientCleanly = true;
- // Set retry flag
- bRetry = true;
- }
- break;
- default:
- TRACE("DoNetGameDialog(): Unknown dialog action!\n");
- break;
- }
- //------------------------------------------------------------------------------
- // Do server stuff.
- //
- // Note that bServerDone should rarely be set to true directly. Instead, set
- // bEndServerCleanly to true, which will try to end the server cleanly, and will
- // eventually result in bServerDone being set to true.
- //
- // It's okay to ignore incoming messages when trying to end because they will
- // still be received and buffered, they just won't be processed here. Instead,
- // they'll be processed in the game loop. Of course, if the game never actually
- // gets started they won't ever be processed, but then it doesn't matter.
- //------------------------------------------------------------------------------
- if (pserver && !bServerDone)
- {
- pserver->Update();
- // Check if we're trying to end
- if (bEndServerCleanly)
- {
- // If there isn't anything more to send, then we're done
- if (!pserver->IsMoreToSend())
- bServerDone = true;
- }
- else
- {
- // Process messages
- pserver->GetMsg(&msg);
- switch(msg.msg.nothing.ucType)
- {
- case NetMsg::ERR:
- if (msg.ucSenderID == Net::InvalidID)
- {
- // A server occurred occurred
- AddConsoleMsg(false, NetErrorText(&msg));
- // Play a sound of badness
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- switch (msg.msg.nothing.ucType)
- {
- // These messages are NOT so horrible and don't
- // require us to clean up and be done.
- // They are merely notifications.
- case NetMsg::ServerVersionMismatchError:
- case NetMsg::ServerPlatformMismatchError:
- break;
-
- // These messages are so horrible and don't
- // require us to clean up and be done.
- default:
- // End server and client cleanly
- bEndServerCleanly = true;
- bEndClientCleanly = true;
- break;
- }
- }
- else if (msg.ucSenderID == pclient->GetID())
- {
- // The error occurred on the local client. We registered the
- // local client with the server, so it will have aborted the game.
- AddConsoleMsg(false, NetErrorText(&msg));
- // Play a sound of badness
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- // End server and client cleanly
- bEndServerCleanly = true;
- bEndClientCleanly = true;
- }
- else
- {
- // The error occurred on a remote client, so the server will
- // have dropped that client.
- AddConsoleMsg(false, g_pszServerStat_PlayerErr);
- }
- break;
- default:
- break;
- }
- }
- }
- //------------------------------------------------------------------------------
- // Do client stuff
- //
- // Note that bClientDone should rarely be set to true directly. Instead, set
- // bEndClientCleanly to true, which will try to end the client cleanly, and will
- // eventually result in bClientDone being set to true.
- //------------------------------------------------------------------------------
- if (!bClientDone)
- {
- pclient->Update();
- // Check if we're trying to end
- if (bEndClientCleanly)
- {
- // If there isn't anything more to send, then we're done
- if (!pclient->IsMoreToSend())
- bClientDone = true;
- }
- else
- {
- // Assume no problems
- short sProblem = 0;
- // Process messages from server
- pclient->GetMsg(&msg);
- switch(msg.msg.nothing.ucType)
- {
- case NetMsg::NOTHING:
- break;
- case NetMsg::ERR:
- AddConsoleMsg(false, NetErrorText(&msg));
- // Attempt to drop nicely
- pclient->Drop();
- // End server and client cleanly
- bEndServerCleanly = true;
- bEndClientCleanly = true;
- // Play a sound of badness and clean the slate (and show RETRY button)
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- CleanClientDlg(pclient, true);
- break;
- case NetMsg::STAT:
- switch (msg.msg.stat.status)
- {
- case NetMsg::Opened:
- AddConsoleMsg(false, "%s", g_pszClientStat_Opened);
- break;
- case NetMsg::Connected:
- AddConsoleMsg(false, "%s", g_pszClientStat_Connected);
- break;
- case NetMsg::LoginAccepted:
- // If we are the server's local client, register ourself so
- // that it realizes that if there's an error on our connection,
- // it will abort the whole game.
- if (pserver)
- pserver->SetLocalClientID(pclient->GetID());
- AddConsoleMsg(false, g_pszClientStat_LoginAccepted_hd, (short)pclient->GetID());
- break;
- case NetMsg::JoinAccepted:
- AddConsoleMsg(false, "%s", g_pszClientStat_JoinAccepted);
- break;
- default:
- break;
- }
- break;
- case NetMsg::JOINED:
- if (OnJoinedMsg(pclient, &msg, pserver ? true : false) != 0)
- {
- // A program error occurred, so tell them something vague
- AddConsoleMsg(false, g_pszNetStat_ProgramError);
- // Attempt to drop nicely
- pclient->Drop();
- // End server and client cleanly
- bEndServerCleanly = true;
- bEndClientCleanly = true;
- // Play a sound of badness and clean the slate (and show RETRY button)
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- CleanClientDlg(pclient, true);
- }
- break;
-
- case NetMsg::DROPPED:
- OnDroppedMsg(pclient, &msg);
- // If we were dropped, end immediately
- if (msg.msg.dropped.id == Net::InvalidID)
- {
- // Play a sound of badness and clean the slate (and show RETRY button)
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- CleanClientDlg(pclient, true);
- bClientDone = true;
- }
- break;
- case NetMsg::CHAT:
- OnChatMsg(pclient, &msg);
- break;
- case NetMsg::SETUP_GAME:
- OnSetupGameMsg(pclient, &msg);
- break;
- case NetMsg::START_GAME:
- // Return this message to caller
- *pmsgOut = msg;
- // Game has been started
- bStart = true;
- // End immediately (no need to wait)
- bClientDone = true;
- break;
- case NetMsg::ABORT_GAME:
- AddConsoleMsg(false, "%s", g_pszClientStat_ServerAborted);
- // Play a sound of badness and clean the slate (and show RETRY button)
- PlaySample(g_smidEmptyWeapon, SampleMaster::UserFeedBack);
- CleanClientDlg(pclient, true);
- // End immediately (no need to wait)
- bClientDone = true;
- break;
- default:
- AddConsoleMsg(false, "%s", g_pszNetStat_UnhandledMsg);
- break;
- }
- }
- }
- } // while()
- }
- else
- {
- // Display msg box that says the protocol is not supported
- ProtoNotSupported();
- }
- // If we're not starting, shutdown client
- if (!bStart)
- pclient->Shutdown();
- } while (bRetry && !sResult);
- }
- // Get rid of dialog
- DlgBeGone();
- // Call this periodically to let it know we're not locked up
- NetBlockingWatchdog();
- }
- else
- {
- TRACE("DoNetGameDialog(): Failed to setup dialog.\n");
- }
- }
- // If not starting, shutdown server
- if (!bStart && pserver)
- pserver->Shutdown();
- }
- else
- {
- // Handle the "protocol not supported" error as a special case because users
- // are likely to screw that up.
- if (sResult == RSocket::errNotSupported)
- {
- // Display msg box that says the protocol is not supported
- ProtoNotSupported();
- }
- }
- } while (!sResult && (bBrowse && !bAbort && !bStart));
- // Call this one last time on the way out
- NetBlockingWatchdog();
- // Make sure vars with built in flagging get reflected properly.
- if (ms_bTimeLimit == false)
- {
- // Flag no time limit as a negative or zero.
- g_GameSettings.m_sHostTimeLimit = -g_GameSettings.m_sHostTimeLimit;
- }
-
- if (ms_bKillLimit == false)
- {
- // Flag no kill limit as a negative or zero.
- g_GameSettings.m_sHostKillLimit = -g_GameSettings.m_sHostKillLimit;
- }
- // Clear any events that might be in the queue
- rspClearAllInputEvents();
- // Restore mouse cursor show level
- rspSetMouseCursorShowLevel(sCursorLevel);
- // Go back to normal CPU mode
- #if defined(_DEBUG)
- // Wake CPU.
- rspSetDoSystemMode(RSP_DOSYSTEM_TOLERATEOS);
- #else
- // Return CPU to us.
- rspSetDoSystemMode(RSP_DOSYSTEM_HOGCPU);
- #endif
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Browse for a host.
- //
- // This is normally only used in client-only mode, but it is easier to test
- // and debug if we can also use it in client-server mode. That's why this
- // takes a pserver pointer.
- //
- //////////////////////////////////////////////////////////////////////////////
- static short BrowseForHost(
- CNetServer* pserver, // I/O: Server interface or NULL if none
- RSocket::Address* paddress) // Out: Address returned here (if successfull)
- {
- short sResult = 0;
- // Start with empty list of hosts
- CNetBrowse::Hosts hostsAll;
- CNetBrowse::Hosts hostsAdded;
- CNetBrowse::Hosts hostsDropped;
- NetBlockingWatchdog();
- // Create browser and start it up
- CNetBrowse browse;
- sResult = browse.Startup(g_GameSettings.m_usServerPort, &NetBlockingCallback);
- if (sResult == 0)
- {
- sResult = SetupDlg(FullPathVD(BROWSER_GUI), DLG_BROWSER);
- if (sResult == 0)
- {
- // Since we don't let RProcessGUI draw cleaned up the screen, we should.
- rspUpdateDisplay();
- DLG_ACTION action = DLG_NOTHING;
- // Loop until error, user abort, or user choice . . .
- while ((sResult == 0) && action != DLG_OK && action != DLG_CANCEL)
- {
- // Do default processing.
- UpdateSystem();
- // Update watchdog timer for net blocking.
- NetBlockingWatchdog();
- // Update server interface, if available.
- if (pserver)
- pserver->Update();
- // Check for new or lost host games.
- browse.Update(&hostsAll, &hostsAdded, &hostsDropped);
- // Update listbox via added and dropped hosts lists.
- sResult = UpdateListBox(ms_plbHostBrowse, &hostsAll, &hostsAdded, &hostsDropped);
- if (sResult == 0)
- {
- // Update the dialog (user input and GUI output).
- action = UpdateDialog(ms_pguiRoot, true);
- }
- // If quitting . . .
- if (rspGetQuitStatus() != FALSE)
- sResult = 1;
- }
- // If no error . . .
- if (sResult == 0)
- {
- switch (action)
- {
- case DLG_OK:
- {
- // Play feedback sound
- PlaySample(g_smidMenuItemSelect, SampleMaster::UserFeedBack);
- // Get selection . . .
- RGuiItem* pguiSel = ms_plbHostBrowse->GetSel();
- // If there's no selection . . .
- if (pguiSel == NULL)
- {
- // Take the first.
- pguiSel = ms_plbHostBrowse->GetFirst();
- }
- // If tehre's a selection . . .
- if (pguiSel)
- {
- // Get corresponding host.
- CNetBrowse::CHost* phost = (CNetBrowse::CHost*)(pguiSel->m_ulUserData);
- ASSERT(phost);
- // Get host address.
- *paddress = phost->m_address;
- // Success.
- }
- else
- {
- TRACE("BrowseForHost(): No host selected.\n");
- sResult = -1;
- }
- break;
- }
- case DLG_CANCEL:
- // Play feedback sound
- PlaySample(g_smidMenuItemSelect, SampleMaster::UserFeedBack);
- // Cancelled.
- sResult = 1;
- break;
- default:
- TRACE("BrowseForHost(): Unknown action.\n");
- sResult = 1;
- break;
- }
- }
- // Done with dialog.
- DlgBeGone();
- }
- // Stop browsing
- NetBlockingWatchdog();
- browse.Shutdown();
- }
- else
- {
- // Handle the "protocol not supported" error as a special case because users
- // are likely to screw that up.
- if (sResult == RSocket::errNotSupported)
- {
- // Display msg box that says the protocol is not supported
- ProtoNotSupported();
- }
- }
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Try to connect to specified host
- //
- //////////////////////////////////////////////////////////////////////////////
- static short FindSpecificSystem(
- RSocket::Address* paddress) // Out: Address returned here (if successfull)
- {
- short sResult = 0;
- // Lookup the specified host (by name or dotted address) and port
- sResult = CNetBrowse::LookupHost(
- g_GameSettings.m_szServerName,
- g_GameSettings.m_usServerPort,
- paddress);
- if (sResult == 0)
- {
- // Success!
- }
- else
- {
- rspMsgBox(
- RSP_MB_BUT_OK | RSP_MB_ICN_INFO,
- g_pszAppName,
- "The specified computer ('%s') could not be found. Please verify that the specified name or address is correct.",
- g_GameSettings.m_szServerName);
- }
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Try to find the local server. This is necessary because there isn't any
- // foolproof method by which to simply lookup the local computer's address.
- // Instead, we browse for ourselves, just like any other client would.
- //
- //////////////////////////////////////////////////////////////////////////////
- static short BrowseForSelf(
- CNetServer* pserver, // I/O: Server interface
- RSocket::Address* paddress) // Out: Address returned here (if successfull)
- {
- ASSERT(pserver);
- short sResult = 0;
- // Start with empty list of hosts
- CNetBrowse::Hosts hostsAll;
- CNetBrowse::Hosts hostsAdded;
- CNetBrowse::Hosts hostsDropped;
- NetBlockingWatchdog();
- // Create browser and start it up
- bool bFoundSelf = false;
- CNetBrowse browse;
- sResult = browse.Startup(g_GameSettings.m_usServerPort, &NetBlockingCallback);
- if (sResult == 0)
- {
- // Wait for our own broadcast
- long lTime = rspGetMilliseconds() + Net::BroadcastDropTime;
- while (!bFoundSelf && (rspGetMilliseconds() < lTime))
- {
- UpdateSystem();
- NetBlockingWatchdog();
- pserver->Update();
- browse.Update(&hostsAll, &hostsAdded, &hostsDropped);
- // Try to find ourself in the list
- for (CNetBrowse::Hosts::Pointer p = hostsAll.GetHead(); p; p = hostsAll.GetNext(p))
- {
- CNetBrowse::CHost* phost;
- phost = &hostsAll.GetData(p);
- if ((strcmp(phost->m_acName, pserver->GetHostName()) == 0) && (phost->m_lMagic == pserver->GetHostMagic()))
- {
- // Return this host's address
- *paddress = phost->m_address;
- bFoundSelf = true;
- break;
- }
- }
- }
- // If we didn't find ourself, set the error flag
- if (!bFoundSelf)
- {
- sResult = -1;
- TRACE("BrowseForSelf(): Couldn't find myself!\n");
- }
- // Stop browsing
- NetBlockingWatchdog();
- browse.Shutdown();
- }
- // If this failed, put up a msgbox
- if (sResult != 0)
- {
- rspMsgBox(
- RSP_MB_BUT_OK | RSP_MB_ICN_INFO,
- g_pszAppName,
- "This computer's network address could not be determined. If this is a multi-homed host, you may need to disable all but one address.");
- }
- return sResult;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Net blocking watchdog. Call this periodically to let the watchdog know
- // that the program hasn't locked up.
- //
- //////////////////////////////////////////////////////////////////////////////
- extern void NetBlockingWatchdog(void)
- {
- // Reset timer to current time
- ms_lWatchdogTime = rspGetMilliseconds();
-
- // If net blocking had expired, then clear it so the net prob gui goes
- // away (since we got here, we're obviously not blocking anymore)
- if (m_bNetWatchdogExpired)
- {
- // Clear flag
- m_bNetWatchdogExpired = false;
- // Erase net prob gui
- RGuiItem* ptxt = GetNetProbGUI();
- if (ptxt)
- {
- // This will PROBABLY work, but it does assume that something else
- // was drawn to the buffer after the last time we drew the net gui.
- // If nothing was drawn to the buffer, the gui will still be there!
- rspUpdateDisplay(ptxt->m_sX, ptxt->m_sY, ptxt->m_im.m_sWidth, ptxt->m_im.m_sHeight);
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Check if a blocked network operation was aborted.
- //
- //////////////////////////////////////////////////////////////////////////////
- extern bool NetBlockingWasAborted(void)
- {
- return ms_bNetBlockingAbort;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Net blocking callback
- //
- //////////////////////////////////////////////////////////////////////////////
- static short NetBlockingCallback(void) // Returns 0 to continue normally, 1 to abort
- {
- // We only need to grab this ptr once (it is guaranteed not to move).
- // Once we have this pointer to the Key status array, we can use it to
- // check on a key's status. The important thing would be NOT to clear
- // any key's status so we don't affect the input module (input.cpp) or
- // the play loop (play.cpp:PlayRealm()).
- static U8* pau8KeyStatus = rspGetKeyStatusArray();
- // Assume we won't abort
- short sAbort = 0;
- // It's always a good idea to do this
- UpdateSystem();
- // System-specific quit always aborts immediately
- if (rspGetQuitStatus())
- sAbort = 1;
- // If the watchdog hasn't already expired, then check it. If it has
- // already expired, then we need to see if the user hit the abort key.
- if (!m_bNetWatchdogExpired)
- {
- // If the watchdog function hasn't been called in a too-long time, then we
- // assume the network stuff is blocking (although it could be that someone
- // forgot to call the watchdog function) and we display the net problem gui.
- if ((rspGetMilliseconds() - ms_lWatchdogTime) > g_GameSettings.m_lNetMaxBlockingTime)
- {
- // Set flag to indicate that there is a problem. This servers two
- // purposes: (1) it let's us know that the net prob gui is being
- // displayed and we should check for the abort key, and (2) it let's
- // other parts of the program determine whether or not to draw the
- // net prob gui on top of whatever else is being drawn to the screen.
- m_bNetWatchdogExpired = true;
- }
- }
- // If watchdog is expired, draw the net prob gui and check for an abort key press
- if (m_bNetWatchdogExpired)
- {
- // Display net problem gui
- RGuiItem* ptxt = GetNetProbGUI();
- if (ptxt)
- {
- // Set to display general error and abort instructions
- ptxt->SetText("%s", g_pszNetProb_General);
- ptxt->Compose();
-
- // Center it so it gets erased by whatever menu or dialog is being displayed
- ptxt->Move(
- (g_pimScreenBuf->m_sWidth / 2) - (ptxt->m_im.m_sWidth / 2),
- (g_pimScreenBuf->m_sHeight / 2) - (ptxt->m_im.m_sHeight / 2));
- // Create temporary image of what's currently in the buffer
- bool bGotImage = false;
- RImage image;
- if (image.CreateImage(ptxt->m_im.m_sWidth, ptxt->m_im.m_sHeight, ptxt->m_im.m_type) == 0)
- {
- rspLockBuffer();
- rspBlit(g_pimScreenBuf, &image, ptxt->m_sX, ptxt->m_sY, 0, 0, image.m_sWidth, image.m_sHeight);
- bGotImage = true;
- rspUnlockBuffer();
- }
- // Note that the GUI locks the buffer, if appropriate.
- ptxt->Draw(g_pimScreenBuf);
- rspUpdateDisplay(ptxt->m_sX, ptxt->m_sY, ptxt->m_im.m_sWidth, ptxt->m_im.m_sHeight);
- if (bGotImage)
- {
- rspLockBuffer();
- rspBlit(&image, g_pimScreenBuf, 0, 0, ptxt->m_sX, ptxt->m_sY, image.m_sWidth, image.m_sHeight);
- rspUnlockBuffer();
- }
- }
- // Check for the abort key
- if (pau8KeyStatus[NET_PROB_GUI_ABORT_SK_KEY])
- sAbort = 1;
- }
- // If aborting, set our own flag, too
- if (sAbort)
- {
- // Set flag
- ms_bNetBlockingAbort = true;
- }
- return sAbort;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Initialize the net problems GUI.
- // Note that this is nearly instantaneous (no file access) if it has already
- // been called. That is, calling this twice in a row is fine. Just make
- // sure you call KillNetProbGUI() when done (although, even that is not
- // essential).
- //
- //////////////////////////////////////////////////////////////////////////////
- extern short InitNetProbGUI(void)
- {
- short sRes = 0; // Assume success.
- KillNetProbGUI();
- sRes = rspGetResource(&g_resmgrShell, NET_PROB_GUI_FILE, &ms_ptxtNetProb);
- if (sRes == 0)
- {
- // Set some intial stuff.
- ms_ptxtNetProb->m_sTextEffects = RGuiItem::Shadow;
- ms_ptxtNetProb->m_u32TextShadowColor = NET_PROB_TEXT_SHADOW_COLOR_INDEX;
- ms_ptxtNetProb->m_sX = NET_PROB_GUI_X;
- ms_ptxtNetProb->m_sY = NET_PROB_GUI_Y;
- // Set generic initial text.
- ms_ptxtNetProb->SetText("%s", g_pszNetProb_General);
- ms_ptxtNetProb->Compose();
- }
- else
- {
- TRACE("InitNetProbGUI(): Error loading Net Prob GUI \"%s\".\n",
- NET_PROB_GUI_FILE);
- }
- return sRes;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Kill the net problems GUI.
- //
- //////////////////////////////////////////////////////////////////////////////
- extern void KillNetProbGUI(void)
- {
- if (ms_ptxtNetProb)
- {
- rspReleaseResource(&g_resmgrShell, &ms_ptxtNetProb);
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Get the net prob GUI which is used to notify the user of network problems.
- // You can move it, draw it, change its text, or whatever. It's just up to
- // you to avoid having a problem with other things updating its settings while
- // you are.
- // Note that this is automagically drawn to the screen via the blocking
- // callback.
- //
- //////////////////////////////////////////////////////////////////////////////
- extern RTxt* GetNetProbGUI(void)
- {
- return ms_ptxtNetProb;
- }
- //////////////////////////////////////////////////////////////////////////////
- //
- // Determine whether there is a net problem. Set via blocking callback.
- // Cleared by you when you call ClearNetProb().
- //
- //////////////////////////////////////////////////////////////////////////////
- extern bool IsNetProb(void) // Returns true, if net problem; false otherwise.
- {
- return m_bNetWatchdogExpired;
- }
- extern void ClearNetProb(void)
- {
- m_bNetWatchdogExpired = false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // EOF
- ///////////////////////////////////////////////////////////////////////////////
|