1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666 |
- ////////////////////////////////////////////////////////////////////////////////
- //
- // 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
- //
- // game.cpp
- // Project: Postal
- //
- // This module deals with the high-level aspects of setting up and running the
- // game.
- //
- // History:
- // 11/19/96 MJR Started.
- // 01/15/96 MJR Added GamePath()
- //
- // 01/28/97 JMI Added calls to MenuTrans API (a PalTran).
- //
- // 01/30/97 MJR Fixed bug in CorrectifyPath() that accidentally truncated
- // the passed-in string.
- //
- // 01/31/97 JMI Now uses FullPath() to get full path for filespecs.
- //
- // 01/31/97 JMI Added g_resmgrGame for specific to actual game data.
- //
- // 01/31/97 JMI Number of title loops done on start up is now gotten from
- // INI file.
- //
- // 02/02/97 JMI Now calls StartTitle() and EndTitle() after launching an
- // edit session, a user game, or a demo game.
- //
- // 02/02/97 JMI Now, before exiting, makes sure all samples are done
- // playing.
- //
- // 02/03/97 JMI Changed DoMenu() called to new DoMenuInput() and
- // DoMenuOutput() calls.
- //
- // 02/03/97 JMI Now sets the base path for g_resmgrGame, Shell, & Menus.
- //
- // 02/04/97 JMI Added functions to get and set the gamma level.
- //
- // 02/04/97 JMI Changed LoadDib() call to Load() (which now supports
- // loading of DIBs).
- //
- // 02/13/97 JMI Removed game level alpha XRay stuff (now setup in CHood).
- //
- // 02/18/97 JMI Now opens SampleMaster's SAK file.
- //
- // 03/06/97 JMI Made PalTranOn() and PalTranOff() extern instead of inline.
- //
- // 03/17/97 JMI Made PalTranOff() abortable via a keypress. Put in the
- // shape of the code for aborting via a key in PalTranOn() but
- // there is currently no interface to MenuTrans to allow this
- // type of abort (or jump).
- //
- // 03/28/97 JMI Un#if 0'd the SavePrefs() call.
- //
- // 03/28/97 JMI Now stores and resets the current dir.
- //
- // 04/11/97 JMI Added Game_Menu_Demo() externally callable function to
- // start the demo.
- //
- // 04/14/97 JMI Now specifies which image for StartTitle() to start with.
- //
- // 04/14/97 JMI Missed a spot in the previous change.
- //
- // 04/16/97 MJR Added simple test of file paths. Also changed it so that
- // preferences are always saved, even if the game encounters
- // an error beforehand.
- //
- // Fixed the simple test of file paths to actual use the
- // file path!!!
- //
- // 04/17/97 MJR Put the test for the CD path back in.
- //
- // 04/22/97 JMI No longer uses chdir().
- //
- // 04/22/97 JMI Now sets g_GameSettings.m_sServer and
- // g_GameSettings.m_sClient to 0 before running the demo.
- //
- // 04/24/97 JMI Currently, aborting the PalTranOff() is a bad idea, so
- // we don't allow it (until we support EndMenuTrans(TRUE) ).
- //
- // 05/06/97 JMI Now uses a Gamma multiplier to define a line instead of
- // the exponent defining the curve.
- //
- // 05/07/97 JMI Now uses a Gamma exponent and uses the 'Gamma Val' as a
- // constant multiplier:
- // MappedColorVal = (colorVal ^ GAMMA_EXPONENT) * GammaVal
- //
- // 05/21/97 JMI Added a resource manager for resources that are not SAKed.
- //
- // 05/23/97 JMI Added a CloseSaks() which closes and purges the SAKs.
- // This solves the problem with the ASSERTions about the logic
- // vars (the RResmgr's were declared at file scope as were the
- // CLogTabVars so it was just a matter of order of destruction
- // that dictated whether the ASSERTions occurred).
- //
- // 06/03/97 JMI Commented out error message for read-only prefs file.
- //
- // 06/03/97 JMI Now uses g_GameSettings members for demo timeouts instead
- // of the DEMO_TIMEOUT macro.
- //
- // 06/04/97 JMI Added conditionally compiled message instead of editor
- // when editor is requested from the menu.
- // Also, now StartTitle() calls within GameLoop() request the
- // last title page.
- //
- // 06/04/97 JMI Added AbortAllSamples() call when exitting.
- //
- // 06/04/97 JMI Added MUST_BE_ON_CD, EDITOR_DISABLED, and CHECK_FOR_COOKIE
- // conditional compilation macros and added a check for a
- // specific U32 in the COOKIE file.
- //
- // 06/12/97 MJR Reworked the callbacks so that the game-specific code now
- // resides in this module rather than the menu module.
- // Reworked the entire core loop so it passes all the
- // required parameters to Play() instead of using globals.
- // Moved all the demo and network setup stuff out of play.cpp
- // and into here.
- //
- // 06/15/97 MJR More changes in terms of how Play() is called and what
- // this module does to get ready for calling it.
- // Also changed calls to rspDoSystem() into calls to Update().
- //
- // Added required calls to DeleteInputDemoData().
- //
- // 06/15/97 MJR Made use of new-and-improved input demo interface.
- // (But demo mode is still not working right...had to check
- // it in though to go along with changes in other files).
- //
- // 06/16/97 MJR Fixed stupid error that caused demo record not to work.
- //
- // 06/16/97 JMI Now passes destination buffer in StartMenu() call.
- //
- // 06/16/97 JMI Added g_fontSmall.
- //
- // MJR Added make-a-demo-movie stuff for debugging demo mode
- // problems.
- //
- // JMI Now, based on INI setting g_GameSettings.m_sTrickySystemQuit,
- // we en/disable system quit status flags.
- //
- // JMI Changed "res/fonts/SmallSmash.fnt" to "res/fonts/SmSmash.fnt"
- //
- // 06/17/97 MJR Modified CorrectifyBasePath() so it will change any
- // relative paths into absolute paths. This, in turn, fixed
- // a problem whereby the loading of demo files failed because
- // it assumed the name of the demo file would begin with the
- // HD path. This assumption normally worked, but failed when
- // the HD path was a relative path.
- //
- // 06/18/97 MJR Added SeedRandom() and GetRandom().
- //
- // MJR Fixed bug in CorrectifyBasePath(). Now handles empty
- // paths (it ignores them).
- //
- // 06/24/97 JMI Added SynchLog() debug mechanism. See function comment for
- // functionality details. See macros in game.h for usage via
- // macro(s).
- //
- // 06/24/97 JMI Undefined CHECK_FOR_COOKIE.
- //
- // JMI Changed usage of strcmp to rspStricmp in GetRandom() and
- // SynchLog().
- //
- // 06/30/97 MJR Changed client and server objects to use new/delete instead
- // of having them live on the stack. They are very large,
- // and caused local (stack) data to exceed 32k on the mac.
- //
- // 07/03/97 JMI Converted calls to rspOpen/SaveBox() to new parm
- // conventions.
- //
- // 07/03/97 JMI Added Game_ControlsMenu() and actions for editting input
- // settings for keys and mouse.
- //
- // 07/05/97 MJR Changed to RSP_BLACK_INDEX instead of 0.
- //
- // 07/06/97 JMI Changed ACTION_EDIT_MOUSE_SETTINGS and
- // ACTION_EDIT_KEY_SETTINGS to ACTION_EDIT_INPUT_SETTINGS.
- // Also, now only one function is called no matter which type
- // of input settings are to be editted, EditInputSettings().
- //
- // 07/11/97 BRH Finished up the expiration date checking for the
- // Registry. Still need to add something for the Mac
- // version.
- //
- // 07/11/97 BRH Fixed typos causing the latest date not to be written to
- // the registry.
- //
- // 07/13/97 JMI Now sets the appropriate base path or opens the approriate
- // SAK dependent on the current audio mode.
- //
- // 07/13/97 JMI Added Game_StartChallengeGame() and an action for the
- // various challenge game types.
- //
- // 07/14/97 BRH Changed calls to Play() to pass the challenge mode flag.
- // Fixed value in Get Registry in case of an error on
- // decrypt.
- //
- // 07/16/97 BRH Made changes to the Mac expiration date code to normalize
- // the time to 1970 like the rest of the machines so that
- // the dates can be stored in 1 format.
- //
- // 07/16/97 JMI Now uses real time when pausing on the titel screens (in-
- // stead of 'Load Loops').
- //
- // 07/17/97 BRH Finished debugging the Mac Prefs file expiration date code.
- //
- // MJR Fixed sample rate problem on the mac.
- //
- // BRH Put in the real expiration date and a comment for the
- // real release date, and updated the current release date
- // to today so that we can still test it.
- //
- // 07/18/97 BRH Added game load and save functions so that the player's
- // game can be saved and loaded. Also added a global
- // stockpile object used to transfer loaded/saved info to/from
- // the CDude's stockpile.
- //
- // 07/19/97 MJR Fixed bug where demo mode would start if user cancelled out
- // of a dialog after spending a long time there.
- // Also changed so demo mode will not start if app is in BG.
- //
- // 07/23/97 BRH Changed calls to Title functions to use the new array of
- // title screen durations.
- //
- // 07/23/97 BRH Changed expiration date display for PC back to asctime(gmtime())
- // since ctime didn't work correctly.
- //
- // 07/26/97 JMI Added g_fontPostal to replace g_fontSmall. Got rid of
- // g_fontSmall.
- //
- // 07/28/97 JMI Now displays a different message for non-marketing
- // releases.
- //
- // 08/01/97 BRH Cycles through 3 demos rather than just 1. Also added
- // open dialog for playing demos so that the user can choose
- // which demo to play.
- //
- // 08/02/97 JMI Now initializes the default RGuiItem font to g_fontBig in-
- // stead of relying on everybody who uses it to invidually set
- // it.
- //
- // 08/05/97 JMI Added Game_AudioOptionsChoice().
- //
- // 08/06/97 MJR Added socket startup/shutdown.
- //
- // 08/08/97 MJR Background and foreground callbacks are now installed here
- // so they are in effect for the entire app.
- //
- // 08/08/97 JMI Now passes parameter to start musak in title to
- // StartTitle().
- //
- // 08/12/97 JMI m_szDemoFile was FullPath()'ed twice so the demo wouldn't
- // load. Fixed.
- //
- // 08/12/97 JMI Added SubPathOpenBox() (see proto for details) and
- // FullPathCustom().
- //
- // 08/13/97 MJR We now pass difficulty level to Play().
- //
- // 08/13/97 JMI No longer remembers the previous demo file you recorded as
- // a patch to either improper usage or problem in
- // SubPathOpenBox().
- //
- // 08/14/97 JMI Added prealm parameter to Game_Save/LoadPlayersGame() so
- // they can query/modify realm settings/flags.
- // Also, changed questionable access on m_action in
- // Game_SavePlayersGame() and Game_LoadPlayersGame() which
- // were casting &m_action to a (short*) even though ACTION is
- // a 32 bit value. May not have worked on the Mac although it
- // would for values less than 32767 and greater than 0 on the
- // little endian PC.
- // Also, added an ACTION_LOAD_GAME so that could be part of
- // the main loop with the intent of making the loaded
- // difficulty a local variable but this turned out to be error
- // prone with keeping this value up to date with the proper
- // value (either the INI difficulty or the loaded difficulty)
- // and it was annoying to determine which one to use on each
- // Play() call so I made a function that returns the
- // appropriate value (but only once...ick). If you feel like
- // it try it the other way, but be aware that on any iteration
- // g_GameSettings.m_sDifficulty may change via a menu.
- // Also, had to add a flag so one action can lead to another.
- // The main loop used to reset the action after every action
- // making it impossible for one action to lead to another.
- //
- // 08/15/97 JRD Added a function to control brightness/contrast in place
- // of gamma. This was because the gamma function could not
- // recreate a "normal palette."
- //
- // 08/15/97 JRD Attempted to hook both brightness and contrast changes to
- // the old gamma slider with a crude algorithm.
- //
- // 08/18/97 JMI Now allows ALT-F4 to drop you out of the title sequence.
- //
- // 08/18/97 JMI In both debug and release modes, we were setting the do
- // system mode to sleep. But we'd only restore it in release
- // mode which basically left us in sleep mode in debug mode.
- // Now restores it to TOLERATEOS in debug mode.
- //
- // 08/19/97 BRH Uses the game settings m_sNumAvailableDemos to control the
- // demo loop rather than the set macro NUM_DEMO_FILES
- //
- // MJR Added support for new MP flags.
- //
- // 08/20/97 JMI Modified Game_LoadPlayersGame() to receive the ptr to the
- // action to fill with the Player's saved action so the
- // function would not have to use the global m_action.
- // Also, Moved Game_LoadPlayersGame() proto into game.cpp b/c
- // it now takes an ACTION* but ACTION is defined in game.cpp
- // and since no one currently calls this function externally,
- // what the hell.
- //
- // 08/21/97 BRH Changed the game sak to be loaded from the GAME_PATH_GAME
- // directory, getting it ready for the installation process.
- // Also changed the demos to HD path to make it easier for
- // people to load their own demos. Changed the sound res
- // manager path to the GAME_PATH_SOUND for installation.
- //
- // 08/21/97 JMI Changed call to Update() to UpdateSystem() and occurrences
- // of rspUpdateDisplay() to UpdateDisplay().
- //
- // 08/22/97 JMI Changed occurrences of UpdateDisplay() back to
- // rspUpdateDisplay(). Now that we are using the lock
- // functions correctly, we don't need them.
- // Also, removed rspLockBuffer() and rspUnlockBuffer() that
- // were used to encapsulate the entire app in a lock.
- //
- // 08/22/97 BRH Changed the cookie position for use with a new smaller
- // res.sak file since we now have Direct X and more sound,
- // we needed more space on the CD.
- //
- // 08/23/97 JMI Now gets callbacks from the initialization and killing of
- // the main menu and stops any playing title/main-menu musak
- // when the main menu is killed.
- //
- // 08/24/97 JMI Added a timeout to the abortion of playing samples just in
- // case there's a bug or a sound driver problem (no need to
- // to taunt infinite loopage).
- //
- // 08/25/97 JMI Now sets the sound quality based on the current mode.
- // Also, now, if there's no sak dir and no sak for the current
- // audio mode, complains.
- //
- // 08/26/97 BRH Merged in changes from a branched game.cpp which has the
- // special cases for the ending demo level of the game.
- // Added a function GameEndingSequence which is called
- // when the global flag that indicates the player has won is
- // set. It plays the demo file and then calls the
- // Title_EndingSequence.
- //
- // 08/26/97 JMI Now any menu can be restore in the GameCore() loop instead
- // of just the main menu by setting pmenuStart to point at the
- // menu to be next started.
- //
- // 08/30/97 BRH Fixed the base path for the logic table resource manager
- // to load from the CD rather than the HD path.
- //
- // 09/02/97 JMI Added a new option to the demo actions which plays one of
- // the factory preset demos.
- // Also, in the case that there were no factory preset demos
- // and the auto play demo kicked in, it would ASSERT that
- // the filename was "".
- //
- // 09/02/97 JMI Now more deluxe control for regarding the starting of the
- // next menu after an action in GameCore().
- //
- // 09/03/97 BRH Changed the g_resmgrRes logic table manager to load
- // from the HD path rather than the CD path, so that it
- // is easier to modify, add or change logics, especially
- // if we have to patch them in the future.
- //
- // 09/04/97 JMI Now Game_ControlsMenu() only sets a new action if one is
- // not already set. This keeps the controls menu from setting
- // the action when it is launched from Play.cpp instead of
- // here.
- //
- // 09/05/97 PPL In CorrectifyBasePath, made sure we allocate the buffer for the
- // full path instead of letting getcwd allocate it for us. It's
- // not that we won't let it -- it's just that the Mac implementation
- // will not do it automatically as the PC implementation would.
- //
- // 09/05/97 PPL Per Bill's directions, we will use the path from the CD for
- // the challenge level.
- //
- // 09/05/97 MJR A few changes to use the new network stuff.
- //
- // 09/06/97 MJR Now inits and kills the network problem GUI.
- //
- // 09/10/97 BRH Had to change the res.sak in order to fit the MPlayer
- // and Heat setups on the CD, so I also had to change the
- // cookie.
- //
- // 09/10/97 MJR Now properly converts paths from system to rspix format
- // on the start single player and start challenge level
- // dialogs. This bug only showed up on the Mac.
- //
- // 09/11/97 BRH Added different cookie and file position for
- // COMP_USA_VERSION only.
- //
- // 09/11/97 JMI Removed old code for PLAY_SPECIFIC_LEVEL_ONLY macro which
- // no longer exists.
- //
- // 09/12/97 MJR Now more code doesn't compile when the editor is disabled,
- // in an attempt to make it harder to hack.
- //
- // 09/18/97 JMI Added expiration message for
- // EXPIRATION_MSG_POSTAL_LAUNCH_WEEKEND compile condition.
- //
- // JMI Changed 'will expire on' to 'expires' so it sounds better
- // both past/future/etc tense wise and the 'on' didn't work
- // well with the format "Mon Sep 22 23:59:00" which contains
- // no 'at'.
- //
- // 09/24/97 BRH For LOCALE != US version, took out the school yard demo
- // from the ending sequence.
- //
- // 09/29/97 JMI Now will try to load any samples SAK in the case that there
- // is no audio mode, the specified mode's samples SAK is not
- // present, and there's no 'NoSak' dir specification.
- // If absolutely no samples SAK is found, a message is
- // displayed that does not mention whether or not your
- // hardware supports the specified mode.
- //
- // 10/01/97 BRH Changed res.sak location so it would fit on the disk.
- //
- // 10/08/97 JMI Made the synchronization logs opened and closed via one
- // set of two functions to make it easier to use them in
- // different scenarios.
- // Also, the logs should now only use the filename (excluding
- // the path) to make it possible for Mac vs. PC logs to be
- // compared.
- //
- // 10/10/97 JMI Updated Game_ControlsMenu() to handle joystick option
- // when ALLOW_JOYSTICK is defined.
- //
- // 10/14/97 JMI Made SynchLog()'s expr parameter a double instead of an int
- // for more accuracy.
- //
- // 10/15/97 JMI Changed the %g used to fprintf() SynchLog() expr values
- // to %0.8f b/c the Mac and PC formats differed slightly. The
- // Mac one often contains as many as four zeroes after the
- // last significant decimal, sometimes less, and most of the
- // time none. The PC never seems to put trailing zeroes.
- //
- // 10/16/97 JMI Now mac demo basename is mdefault.dmo (instead of
- // default.dmo) since the game plays slightly differently on
- // the Mac than on the PC.
- //
- // 10/22/97 JMI In the call to Play() for recording demos, FullPathHD() was
- // being called on the passed in path but now that
- // CRealm::Open() tries all the deluxe path stuff we don't
- // need that (and cannot use it b/c Open() does a conversion
- // to system path format as does FullPathHD() ).
- //
- // 11/20/97 JMI Added cooperative flag to Play() calls.
- //
- // 12/01/97 BRH Added flags for Add On levels to play calls, and
- // added ACTION_PLAY_ADDON as one of the options.
- //
- // 12/04/97 BRH Added Single player menu option to play add on levels
- // or original levels.
- //
- // 01/05/98 JMI Now uses RMix::GetMode() to get sound quality. Also, now
- // uses the source bits per sample (instead of the device
- // setting) to determine which sample resources to use.
- // Note that the quality is still set based on the device bits
- // per sample though so that the volumes could be tuned
- // accordingly in SampleMaster's ms_asQualityCategoryAdjustors.
- //
- // 01/21/98 JMI Now the foreground and background callbacks use a value,
- // INVALID_CURSOR_SHOW_LEVEL, to flag whether or not they're
- // in the background so they know which callbacks to ignore
- // and which one's to use. I think that before (under DirectX)
- // we were getting more than one Backcall per Forecall and/or
- // vice-versa.
- //
- // 03/05/98 BRH Now attempts to identify the PostalSD disc when the game
- // starts to clear up any confusion about which CD must be
- // in the drive to play the Add on Pack. The Add on Pack
- // requires the original PostalCD in the drive, and it reads
- // the original res.sak file from that disc. The PostalSD
- // disc also has a res.sak file on it, but its not the one
- // we want, and if someone tried to play the game with the
- // PostalSD disc in the drive rather than the PostalCD, then
- // the copy protection would flag it as invalid. So an
- // additional check is now made and if the PostalSD disc
- // is in the drive, it will display a message to tell them
- // to put the PostalCD in the drive.
- //
- // 06/04/98 BRH Removed the demo timeout check from the SPAWN build since
- // the spawn version doesn't have any demo files available
- // it shouldn't try to run them when the user is idle. It
- // was attempting to do so, and when it can't find a demo
- // file, a message box pops up which would cause much
- // confusion to the user.
- //
- // 07/08/98 JMI Removed extra Close() in checking for add on CD. Also,
- // moved close that was in incorrect spot in check for add on
- // CD. These were only annoying in Debug mode when it is
- // flagged.
- //
- // 09/27/99 JMI Changed to allow ending sequence only in any locale
- // satisfying the CompilerOptions macro VIOLENT_LOCALE.
- //
- // 10/07/99 JMI Conditional remove Add On start menu option when in
- // SUPER_POSTAL target.
- //
- // 10/11/99 JMI Changed the audio sak name to be RATEjBITS instead of
- // RATE_BITS to differentiate it from Orig & SD Postal sound
- // saks.
- //
- // 02/04/00 MJR Added dialog box to prompt for original CD if
- // PROMPT_FOR_ORIGINAL_CD is defined.
- //
- // MJR Changed so that it now checks the HD first and the VD
- // second when trying to load the shell sak. This
- // was done to fix problems with the Japan Add On.
- //
- // 03/30/00 MJR Changed to new macro for controlling the test for the
- // original Postal CD to differentiate it from the test for
- // a CD-ROM drive.
- //
- // Added AUDIO_SAK_SEPARATOR_CHAR to make it easy to control
- // the separater character in audio sak filenames.
- //
- // 04/01/00 MJR Fixed bug with AUDIO_SAK_SEPARATOR_CHAR.
- // Changed so in debug mode, it continues even if not on CD.
- //
- // 04/03/00 MJR Modified MUST_BE_ON_CD code so that the test is bypassed if
- // the CD path is to our development server. This allows
- // for easier testing.
- //
- // 06/24/01 MJR Got rid of CompUSA cookie variation. Also cleaned up a
- // few other macros.
- //
- ////////////////////////////////////////////////////////////////////////////////
- #define DWORD U32
- #include "RSPiX.h"
- #include <time.h>
- #ifdef WIN32
- #include <direct.h>
- #else
- #include <unistd.h>
- #endif
- #include "WishPiX/Menu/menu.h"
- #include "WishPiX/Prefs/prefs.h"
- #include "WishPiX/ResourceManager/resmgr.h"
- #include "main.h"
- #include "menus.h"
- #include "game.h"
- #include "localize.h"
- #include "play.h"
- #include "title.h"
- #include "credits.h"
- #include "scene.h"
- #include "update.h"
- #include "gameedit.h"
- #include "MenuTrans.h"
- #include "SampleMaster.h"
- #include "net.h"
- #include "NetDlg.h"
- #include "input.h"
- #include "InputSettingsDlg.h"
- #include "encrypt.h"
- #include "credits.h"
- #include "CompileOptions.h"
- ////////////////////////////////////////////////////////////////////////////////
- // Macros/types/etc.
- ////////////////////////////////////////////////////////////////////////////////
- // Total units required for loading during title sequence (estimated)
- #define TITLE_LOAD_UNITS 5000
- // TEMPORARY! Determines how long the fake title sequence load will take.
- // Remove this when there's real stuff being loaded.
- #define TEMP_TITLE_LOOPS 500
- #define TEMP_TITLE_TIME_PER_LOOP 10 // 100 looks normal, 10 goes extremely quickly
- // Font stuff
- #define BIG_FONT_FILE "res/fonts/system1.fnt"
- #define POSTAL_FONT_FILE "res/fonts/smash.fnt"
- #define FONT_HEIGHT 12 // "Best" for ComicB.
- #define FONT_FORE_INDEX 255 // White or black.
- #define FONT_BACK_INDEX 0 // Transparent.
- #define NORMAL_PAL_TRAN_TIME 750
- #define TEMP_ALPHA_EFFECT "2dEffects/alpha00.bmp"
- #define SHELL_SAK_FILENAME "res/shell/shell.sak"
- #define GAME_SAK_FILENAME "res/game/game.sak"
- #define SAMPLES_SAK_SUBDIR "res/game/"
- #define CUTSCENE_SAK_FILENAME_FRMT "res/cutscene/cutscene%02d.sak"
- // Since the game plays slightly differently on the PC than on the Mac,
- // we'll have two different sets of demos.
- #define DEFAULT_DEMO_PREFIX "res/demos/default"
- #define DEFAULT_DEMO_SUFFIX ".dmo"
- #define DEMO_OPEN_TITLE "Choose a Demo File to Play Back"
- #define DEMO_LEVEL_DIR "res/demos/."
- #define ENDING_DEMO_NAME "res/levels/single/index.rdx" // Fake name for school.dmo
- #define DEMO_DIR "res/demos/."
- #define DEMO_EXT ".dmo"
- #define LEVEL_DIR "res/levels/."
- #if WITH_STEAMWORKS
- extern bool EnableSteamCloud;
- #define SAVEGAME_DIR (EnableSteamCloud ? "steamcloud" : "savegame")
- #else
- #define SAVEGAME_DIR ("savegame")
- #endif
- #define CHECK_FOR_ASSETS_FILENAME "res/res.sak"
- #define CHECK_FOR_POSTALSD_FILENAME "res/hoods/ezmart.sak"
- #define COOKIE_VALUE 0x9504cc39 //0xb5cf76dd
- #define COOKIE_FILE_POSITION 289546856 //323290320
- #define COOKIE_XOR_MASK 0x6afb39e5 //0x66666666
- // Exponent used to define gamma curve.
- #define GAMMA_EXPONENT 1.50
- // The directories for each type of challenge levels.
- #define TIMED_CHALLENGE_LEVEL_DIR "res/levels/gauntlet/timed/."
- #define CHECKPOINT_CHALLENGE_LEVEL_DIR "res/levels/gauntlet/checkpt/."
- #define GOAL_CHALLENGE_LEVEL_DIR "res/levels/gauntlet/goal/."
- #define FLAG_CHALLENGE_LEVEL_DIR "res/levels/gauntlet/capflag/."
- // The titles for the open dialog for each type of challenge levels.
- #ifdef MOBILE
- #define TIMED_CHALLENGE_OPEN_TITLE "Timed Challenge"
- #define CHECKPOINT_CHALLENGE_OPEN_TITLE "Checkpoint Challenge"
- #define GOAL_CHALLENGE_OPEN_TITLE "Goal Challenge"
- #define FLAG_CHALLENGE_OPEN_TITLE "Capture the Flag Challenge"
- #else
- #define TIMED_CHALLENGE_OPEN_TITLE "Choose Timed Challenge"
- #define CHECKPOINT_CHALLENGE_OPEN_TITLE "Choose Checkpoint Challenge"
- #define GOAL_CHALLENGE_OPEN_TITLE "Choose Goal Challenge"
- #define FLAG_CHALLENGE_OPEN_TITLE "Choose Capture the Flag Challenge"
- #endif
- #define INVALID_DIFFICULTY -7
- #define TIME_OUT_FOR_ABORT_SOUNDS 3000 // In ms.
- // Determines the number of elements in the passed array at compile time.
- #define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0]) )
- // We use this value to flag the fact that we haven't hidden the cursor.
- #define INVALID_CURSOR_SHOW_LEVEL ( (short)0x8000)
- // Various action types
- typedef enum
- {
- ACTION_NOTHING,
- ACTION_PLAY_SINGLE,
- ACTION_PLAY_BROWSE,
- ACTION_PLAY_HOST,
- ACTION_PLAY_CONNECT,
- ACTION_PLAY_CHALLENGE,
- ACTION_EDITOR,
- ACTION_DEMO_PLAYBACK,
- ACTION_DEMO_RECORD,
- ACTION_EDIT_INPUT_SETTINGS,
- ACTION_POSTAL_ORGAN,
- ACTION_LOAD_GAME,
- ACTION_PLAY_ADDON
- #ifdef MOBILE
- ,ACTION_CONTINUE_GAME
- #endif
- } ACTION;
- ////////////////////////////////////////////////////////////////////////////////
- // Variables/data
- ////////////////////////////////////////////////////////////////////////////////
- // Global game settings
- CGameSettings g_GameSettings;
- // Cookie flag
- long g_lCookieMonster;
- // Global screen buffer
- RImage* g_pimScreenBuf;
- // Global big font
- RFont g_fontBig;
- // Global Postal font.
- RFont g_fontPostal;
- // Resource manager for game resources. These are resources used by the actual
- // game, like things that a CThing loads that is not level specific. For example,
- // CBall loads, of course, foot.bmp, which would be loaded through this ResMgr.
- // Note: This resmgr should not be used for things like info on ordering, menu
- // resources, g_fontBig, or anything not specific to the real game.
- // Note: Realm specifc data, such as alpha effects, etc., should be loaded
- // through prealm->m_resmgr.
- RResMgr g_resmgrGame;
- // Resource manager for shell resources. Do not use this to load things like
- // the main dudes' sprites.
- RResMgr g_resmgrShell;
- // Resource manager for non-SAK resources.
- RResMgr g_resmgrRes;
- // Time and Date values
- long g_lRegTime;
- long g_lRegValue;
- long g_lExpTime;
- long g_lExpValue;
- long g_lReleaseTime;
- // Stockpile used to transfer loaded/saved data to/from the CDude's stockpile
- CStockPile g_stockpile;
- bool g_bTransferStockpile;
- short g_sRealmNumToSave;
- // Flag for special end of game demo sequence which is set in Play() when
- // it has been determined that the player has won.
- bool g_bLastLevelDemo = false;
- // The secret cookie value used to determine if the humongous file exists
- static U32 ms_u32Cookie = COOKIE_VALUE;
- // These variables are generally controlled via the menu system
- static ACTION m_action;
- static long m_lDemoBaseTime;
- static long m_lDemoTimeOut;
- static char m_szRealmFile[RSP_MAX_PATH+1];
- static char m_szDemoFile[RSP_MAX_PATH+1];
- static short m_sRealmNum;
- static bool m_bJustOneRealm;
- // Cursor show level before we went to the background
- static short ms_sForegroundCursorShowLevel = INVALID_CURSOR_SHOW_LEVEL;
- // Used by random number stuff
- static long m_lRandom = 1;
- static RFile* m_pfileRandom = 0;
- // Used by if-logging schtuff.
- static long ms_lSynchLogSeq = 0;
- static RFile ms_fileSynchLog;
- // true to create synchronization logs, false to compare to them.
- static bool m_bWriteLogs = false;
- static short ms_sLoadedDifficulty = INVALID_DIFFICULTY;
- static SampleMaster::SoundInstance ms_siMusak = 0;
- ////////////////////////////////////////////////////////////////////////////////
- // Function prototypes
- ////////////////////////////////////////////////////////////////////////////////
- static short GameCore(void); // Returns 0 on success.
- static void ResetDemoTimer(void);
- static short OpenSaks(void); // Returns 0 on success.
- static void CloseSaks(void);
- static short LoadAssets(void);
- static short UnloadAssets(void);
- static void GameSetRegistry(void);
- static void GameGetRegistry(void);
- static void GameEndingSequence(void);
- static short GetRealmToRecord(
- char* pszRealmFile,
- short sMaxFileLen);
- static short GetDemoFile(
- char* pszDemoFile,
- short sMaxFileLen);
- // Callback gets called when OS is about to switch app into the background
- static void BackgroundCall(void);
- // Callback gets called when OS is about to switch app into the foreground
- static void ForegroundCall(void);
- // Returns difficulty for games.
- // Note that this function is only valid once after a difficulty adjustment
- // and then it goes back to the default (g_GameSettings value).
- static short GetGameDifficulty(void); // Returns cached game difficulty.
- // Opens the synchronization log with the specified access flags if in a
- // TRACENASSERT mode and synchronization logging is enabled.
- // Also, opens the random log, if it is enabled via
- // g_GameSettings.m_szDebugMovie or something.
- static void OpenSynchLogs( // Returns nothing.
- bool bWriteLogs); // In: true to create log, false to compare.
- // Closes the synchronization logs, if open.
- static void CloseSynchLogs(void); // Returns nothing.
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Load a previously saved game
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern short Game_LoadPlayersGame( // Returns SUCCESS if loaded saved game file
- char* pszSaveName, // In: Name of the saved game file to open
- short* psDifficulty, // Out: Saved game realm difficulty.
- ACTION* paction); // Out: Saved game action.
- bool StatsAreAllowed = false;
- int Stat_BulletsFired = 0;
- int Stat_BulletsHit = 0;
- int Stat_BulletsMissed = 0;
- int Stat_Deaths = 0;
- int Stat_Suicides = 0;
- int Stat_Executions = 0;
- int Stat_HitsTaken = 0;
- int Stat_DamageTaken = 0;
- int Stat_Burns = 0;
- int Stat_TimeRunning = 0;
- int Stat_KilledHostiles = 0;
- int Stat_KilledCivilians = 0;
- int Stat_TotalKilled = 0;
- int Stat_LevelsPlayed = 0;
- ULONG Flag_Achievements = 0;
- #if 1 //PLATFORM_UNIX
- #include <sys/stat.h>
- static void EnumExistingSaveGames(Menu *menu)
- {
- char gamename[RSP_MAX_PATH];
- int i = 0;
- int Max = (sizeof(menu->ami) / sizeof(menu->ami[0])) - 1;
- if (Max > MAX_SAVE_SLOTS)
- Max = MAX_SAVE_SLOTS;
- #if MOBILE
- snprintf(gamename, sizeof (gamename), "%s/auto.gme", SAVEGAME_DIR);
- const char *fname = FindCorrectFile(gamename, "w");
- struct stat statbuf;
- const char *str = "unused";
- char timebuf[32];
- menu->ami[0].sEnabled = (stat(fname, &statbuf) != -1);
- if (menu->ami[0].sEnabled)
- {
- struct tm *tm;
- if ((tm = localtime((const time_t*)&statbuf.st_mtime)) == NULL)
- str = "unknown";
- else
- {
- strftime(timebuf, sizeof (timebuf), "%m/%d/%y %H:%M", tm);
- str = timebuf;
- }
- }
- snprintf(gamename, sizeof (gamename), "Auto - [%s]", str);
- menu->ami[0].pszText = strdup(gamename);
- for (i = 0; i < Max; i++)
- {
- snprintf(gamename, sizeof (gamename), "%s/%d.gme", SAVEGAME_DIR, i);
- const char *fname = FindCorrectFile(gamename, "w");
- struct stat statbuf;
- const char *str = "unused";
- char timebuf[32];
- menu->ami[i+1].sEnabled = (stat(fname, &statbuf) != -1);
- if (menu->ami[i+1].sEnabled)
- {
- struct tm *tm;
- if ((tm = localtime((const time_t*)&statbuf.st_mtime)) == NULL)
- str = "unknown";
- else
- {
- strftime(timebuf, sizeof (timebuf), "%m/%d/%y %H:%M", tm);
- str = timebuf;
- }
- }
- snprintf(gamename, sizeof (gamename), "%d - [%s]", i, str);
- menu->ami[i+1].pszText = strdup(gamename);
- }
- #else
- for (i = 0; i < Max; i++)
- {
- snprintf(gamename, sizeof (gamename), "%s/%d.gme", SAVEGAME_DIR, i);
- const char *fname = FindCorrectFile(gamename, "w");
- struct stat statbuf;
- const char *str = "unused";
- char timebuf[32];
- menu->ami[i].sEnabled = (stat(fname, &statbuf) != -1);
- if (menu->ami[i].sEnabled)
- {
- struct tm *tm;
- if ((tm = localtime(&statbuf.st_mtime)) == NULL)
- str = "unknown";
- else
- {
- strftime(timebuf, sizeof (timebuf), "%m/%d/%y %H:%M", tm);
- str = timebuf;
- }
- }
- snprintf(gamename, sizeof (gamename), "%s/%d.gme [%s]", SAVEGAME_DIR, i, str);
- menu->ami[i].pszText = strdup(gamename);
- }
- #endif
- }
- #endif
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Do the high-level startup stuff, run the game, and then cleanup afterwards.
- //
- // It is assumed that the system/RSPiX environment are setup properly before
- // this function is called.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void TheGame(void)
- {
- short sResult = 0;
- // Set up callbacks for when OS sends us to foreground or background.
- rspSetBackgroundCallback(BackgroundCall);
- rspSetForegroundCallback(ForegroundCall);
- ms_u32Cookie = ~ms_u32Cookie;
- g_lRegValue = 0;
- g_lExpValue = 0;
- g_lRegTime = 0;
- #ifdef CHECK_EXPIRATION_DATE
- g_lExpTime = EXPIRATION_DATE;
- #else
- g_lExpTime = SAFE_DATE;
- #endif
- g_lReleaseTime = RELEASE_DATE;
- // To make it more confusing for someone debugging through the code,
- // the flag for the cookie check will be this large number SAFE_DATE.
- // Once the game determines elsewhere that the cookie is correct, it will
- // in some way modify the flag so that it is not SAFE_DATE, then later
- // the check will be for anything other than SAFE_DATE
- #ifdef CHECK_FOR_COOKIE
- g_lCookieMonster = SAFE_DATE;
- #else
- g_lCookieMonster = SAFE_DATE - RELEASE_DATE;
- #endif
- g_bTransferStockpile = false;
- // Get pointer to screen buffer and lock it. Our Update()
- // unlocks and re-locks these each time it is called.
- rspNameBuffers(&g_pimScreenBuf);
- // Lock the RSPiX composite buffer so we can rect it.
- rspLockBuffer();
- // Clear screen buffer
- rspRect(RSP_BLACK_INDEX, g_pimScreenBuf,
- 0, 0, g_pimScreenBuf->m_sWidth, g_pimScreenBuf->m_sHeight);
- // Unlock now that we're done with the composite buffer.
- rspUnlockBuffer();
- // Update display
- rspUpdateDisplay();
- // Read all settings from preference file
- sResult = CSettings::LoadPrefs(g_pszPrefFileName);
- RFile file;
- if (sResult == 0)
- {
- #ifdef PROMPT_FOR_ORIGINAL_CD
- rspMsgBox(RSP_MB_ICN_INFO | RSP_MB_BUT_OK, g_pszAppName, g_pszPromptForOriginalCD);
- #endif
- #ifdef REQUIRE_POSTAL_CD
- // Check to make sure the correct CD is in the drive. The Postal Add On Requires
- // that the original PostalCD is in the drive.
- short sCorrectCD = -2;
- while (sCorrectCD == -2)
- {
- // We are looking for a disc that has a res.sak, but doesn't have ezmart.sak
- // to insure that they have the original PostalCD in the drive
- if (file.Open(FullPathCD(CHECK_FOR_ASSETS_FILENAME), "r", RFile::LittleEndian) == 0)
- {
- file.Close();
- sCorrectCD++;
- if (file.Open(FullPathCD(CHECK_FOR_POSTALSD_FILENAME), "r", RFile::LittleEndian) != 0)
- {
- sCorrectCD++;
- }
- else
- {
- file.Close();
- }
- }
- if (sCorrectCD != 0)
- {
- TRACE("Game(): Wrong CD in the drive - this is not the original PostalCD\n");
- if (rspMsgBox(RSP_MB_ICN_INFO | RSP_MB_BUT_RETRYCANCEL, g_pszCriticalErrorTitle, g_pszWrongCD, "Wrong CD") == 3)
- sCorrectCD = -2;
- else
- sCorrectCD = -3;
- }
- }
- // If we have the correct CD in the drive, then we can proceed
- sResult = sCorrectCD;
- #endif // REQUIRE_POSTAL_CD
-
- // Try loading special file that exists solely for the purpose of checking for
- // valid paths in the prefs file. We do this for each of the paths.
- if (sResult == 0)
- {
- if (file.Open(FullPathHD(CHECK_FOR_ASSETS_FILENAME), "r", RFile::LittleEndian) == 0)
- file.Close();
- else
- {
- sResult = -1;
- TRACE("Game(): Can't find assets based on HD path specified in prefs!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszCantFindAssets, "HD");
- }
- }
- if (sResult == 0)
- {
- if (file.Open(FullPathVD(CHECK_FOR_ASSETS_FILENAME), "r", RFile::LittleEndian) == 0)
- file.Close();
- else
- {
- sResult = -1;
- TRACE("Game(): Can't find assets based on VD path specified in prefs!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszCantFindAssets, "VD");
- }
- }
- if (sResult == 0)
- {
- if (file.Open(FullPathSound(CHECK_FOR_ASSETS_FILENAME), "r", RFile::LittleEndian) == 0)
- file.Close();
- else
- {
- sResult = -1;
- TRACE("Game(): Can't find assets based on Sound path specified in prefs!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszCantFindAssets, "Sound");
- }
- }
- if (sResult == 0)
- {
- if (file.Open(FullPathGame(CHECK_FOR_ASSETS_FILENAME), "r", RFile::LittleEndian) == 0)
- file.Close();
- else
- {
- sResult = -1;
- TRACE("Game(): Can't find assets based on Game path specified in prefs!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszCantFindAssets, "Game");
- }
- }
- if (sResult == 0)
- {
- if (file.Open(FullPathHoods(CHECK_FOR_ASSETS_FILENAME), "r", RFile::LittleEndian) == 0)
- file.Close();
- else
- {
- sResult = -1;
- TRACE("Game(): Can't find assets based on Hoods path specified in prefs!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszCantFindAssets, "Hoods");
- }
- }
- // Check for special file, COOKIE, and size.
- if (sResult == 0)
- {
- ms_u32Cookie ^= COOKIE_XOR_MASK;
- if (file.Open(FullPathCD(CHECK_FOR_ASSETS_FILENAME), "rb", RFile::LittleEndian) == 0)
- {
- #if defined(CHECK_FOR_COOKIE)
- if (file.Seek(COOKIE_FILE_POSITION, SEEK_SET) == 0)
- {
- U32 u32Cookie = 0;
- if (file.Read(&u32Cookie) == 1)
- {
- if (u32Cookie == ms_u32Cookie)
- {
- // Okay, you can play.
- // This can be any number, the check will verify that the
- // g_lCookieMonster is not SAFE_DATE.
- g_lCookieMonster += 15;
- }
- else
- {
- //sResult = -4;
- TRACE("Game(): Cookie value is incorrect.\n");
- }
- }
- else
- {
- //sResult = -3;
- TRACE("Game(): Failed to read cookie.\n");
- }
- }
- else
- {
- //sResult = -2;
- TRACE("Game(): Cookie file is incorrect size!\n");
- }
- #endif // defined(CHECK_FOR_COOKIE)
- file.Close();
- }
- else
- {
- sResult = -1;
- TRACE("Game(): Can't find assets based on CD path specified in prefs!\n");
- }
- // If any problems . . .
- if (sResult != 0)
- {
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszCantFindAssets, "CD");
- }
- }
- // Check for CDROM drive.
- if (sResult == 0)
- {
- #if defined(MUST_BE_ON_CD)
- // Check for the special case where the path is the one we use for
- // development. If someone out there happens to use this as their
- // own path, then they will defeat this test for CD-ROM. Oh well.
- char* pszDevelopmentPath = "\\\\narnia\\projects\\";
- if (strnicmp(FullPathCD("."), pszDevelopmentPath, strlen(pszDevelopmentPath)) != 0)
- {
- #if defined(WIN32)
- if (GetDriveType(FullPathCD(".") ) != DRIVE_CDROM)
- #else
- #error MUST_BE_ON_CD feature is currently implemented only for Win32
- #endif
- {
- // Only set the error flag if we're in release mode
- #ifndef _DEBUG
- sResult = -1;
- #endif
- TRACE("Game(): CD path is not a CDROM!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszNotOnCDROM);
- }
- }
- #endif
- }
- if (sResult == 0)
- {
- // Set the gamma level to value indicated by settings.
- SetGammaLevel(g_GameSettings.m_sGammaVal);
- // If trickier quit specified . . .
- if (g_GameSettings.m_sTrickySystemQuit != FALSE)
- {
- // Add shift key as a requirement for the quit status keys.
- rspSetQuitStatusFlags(RSP_GKF_SHIFT);
- }
- // Open SAKs or setup equivalent paths.
- sResult = OpenSaks();
- if (sResult == 0)
- {
- // Start title, passing the "total units" for its progress meter
- sResult = StartTitle(1, true, &ms_siMusak);
- if (sResult == 0)
- {
- // Load assets that we want to keep around at all times
- sResult = LoadAssets();
-
- // End title (regardless of previous result)
- EndTitle();
- if (sResult == 0)
- {
- // Set the font most GUIs will use (the menu system uses its own RPrint).
- // Note that the size does not matter, we just want to set the font ptr.
- RGuiItem::ms_print.SetFont(15, &g_fontBig);
- // Do the core game stuff
- sResult = GameCore();
- // If there weren't any errors, wrap things up
- if (!sResult)
- {
- // Do ending credits
- if (rspGetQuitStatus() > 1)
- {
- rspSetQuitStatus(0);
- Credits();
- }
- }
- }
- else
- {
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszGeneralError);
- }
- // Unload assets loaded earlier
- UnloadAssets();
- }
- else
- {
- TRACE("Game(): Error returned by StartTitle()!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszTitleError);
- }
- }
- else
- {
- TRACE("Game(): Error returned by OpenSaks().\n");
- }
- #if 0
- // Make sure we're not paused . . .
- if (RMix::IsPaused() )
- {
- RMix::Resume();
- }
- #endif
- // Abort all samples.
- AbortAllSamples();
- // We should never need a timeout but I don't want to risk a Muppets
- // scenario where a shitty sound driver causes us to think a sound is always
- // playing.
- // Wait for all samples to finish.
- long lTimeOutTime = rspGetMilliseconds() + TIME_OUT_FOR_ABORT_SOUNDS;
- // Wait for them to stop.
- while (IsSamplePlaying() == true && rspGetMilliseconds() < lTimeOutTime)
- {
- // Always do periodic updates.
- // Crucial to sound completing.
- UpdateSystem();
- }
- // Close SAKs and/or create SAKs??
- CloseSaks();
- }
- // Save all settings to preference file
- sResult = CSettings::SavePrefs(g_pszPrefFileName);
- if (sResult > 0)
- {
- TRACE("Game(): Read-only prefs file!\n");
- // rspMsgBox(RSP_MB_ICN_INFO | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszPrefReadOnly);
- }
- else if (sResult < 0)
- {
- TRACE("Game(): Error writing prefs file!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszPrefWriteError);
- }
- }
- else
- {
- TRACE("Game(): Error returned by ReadGamePrefs()!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszCriticalErrorTitle, g_pszPrefReadError);
- }
- // Remove the callbacks
- rspSetBackgroundCallback(NULL);
- rspSetForegroundCallback(NULL);
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Do the core game stuff (display menu, play a game, run the demo, etc.)
- //
- ////////////////////////////////////////////////////////////////////////////////
- static short GameCore(void) // Returns 0 on success.
- {
- short sResult = 0;
- USHORT usDemoCount = 0;
- bool bMPath = false,
- bMPathServer = false;
- #ifdef CHECK_EXPIRATION_DATE
- #ifdef WIN32
- char acTime[100];
- strcpy(acTime, asctime(gmtime(&g_lExpTime)));
- #define NEXT_LINE "\n\n"
- #else
- char acTime[100];
- unsigned long lTime = g_lExpTime + (((365 * 70UL) + 17) * 24 * 60 * 60); // time_fudge 1900->1970
- strcpy(acTime, ctime(&lTime));
- char* pCR = strchr(acTime, '\n');
- if (pCR != NULL)
- *pCR = 0;
- #define NEXT_LINE "\r\r"
- #endif // WIN32
- rspMsgBox(
- RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
- #if defined(EXPIRATION_MSG_POSTAL_LAUNCH_WEEKEND)
- // Title
- "Postal Launch Weekend Edition",
- #elif defined(EXPIRATION_MSG_MARKETING_RELEASE)
- // Title
- "Postal Beta Contest",
- // Message Body
- "This is a large, single-player, single-level BETA test version -- that means we're "
- "still working on it and it's not final. But we want your comments to help us make it "
- "even cooler, so we're holding a BETA TEST CONTEST!"
- NEXT_LINE
- "We're giving away tons o' free stuff, including FREE GAMES, T-SHIRTS, and even a hot "
- "NEW DELL 266MHZ COMPUTER!"
- NEXT_LINE
- "If you haven't already registered, visit http://www.gopostal.com to find out more about Postal "
- "and how you can register for the BETA TEST CONTEST!"
- NEXT_LINE
- #else
- // Title
- "Limited-Time Version",
- #endif
- // Message Body
- "This limited-time version will expire on %s"
- NEXT_LINE
- "After the expiration date, you will still be able to get into the game, "
- "but you will notice that everyone bursts into flames and dies. This is "
- "NOT a bug -- it simply indicates that your version has expired.",
- // Time String
- acTime);
- #endif // CHECK_EXPIRATION_DATE
- #ifndef _WIN32
- UnlockAchievement(ACHIEVEMENT_PLAY_ON_NON_WINDOWS_PLATFORM);
- #endif
- // Clear end of game flag - play will set the flag if the player wins the game
- g_bLastLevelDemo = false;
- // Clear any events that might be in the queue
- rspClearAllInputEvents();
- ClearXInputState();
- // Get the registry value
- GameGetRegistry();
- // Init demo mode times
- m_lDemoBaseTime = rspGetMilliseconds();
- m_lDemoTimeOut = g_GameSettings.m_lInitialDemoTimeOut;
- // Clear flags that are updated by the menu system callbacks (in this module)
- m_action = ACTION_NOTHING;
- m_sRealmNum = 0;
- m_szRealmFile[0] = 0;
- m_bJustOneRealm = false;
- // Flag indicates whether or not menu is active
- bool bMenuActive = false;
- ACTION actionNext = ACTION_NOTHING; // Initialized for safety.
- Menu* pmenuStart = NULL; // Next menu to start if not NULL.
- bool bPalTran = true; // true to PalTranOn() before next
- // menu.
- bool bTitleImage = true; // true to display title image before
- // next menu.
- bool bTitleMusak = true; // true to play title musak during
- // next menu. Requires title image.
- //////////////////////////////////////
- //////////////////////////////////////
- // Keep looping until user quits or error occurs. Maybe even play
- // a game or two along the way. If there's no user input for a
- // certain amount of time, automatically run the self-playing demo.
- RInputEvent ie;
- memset(&ie, '\0', sizeof (ie)); // fix valgrind complaining... --ryan.
- while (sResult == 0)
- {
- // Clear the end of game flag each time just to be safe, it only needs
- // to be set within the last iteration
- g_bLastLevelDemo = false;
- // As always...
- UpdateSystem();
- // Get next input event
- ie.type = RInputEvent::None;
- rspGetNextInputEvent(&ie);
- // If there's any key or button input, or the app is in BG mode (per the OS),
- // reset the demo timer
- if ((ie.type != RInputEvent::None) || rspIsBackground())
- ResetDemoTimer();
- // Does user want to exit app? Do this BEFORE checking whether menu is active
- // so we won't bother activating the menu only to find out we're going to exit.
- if (rspGetQuitStatus())
- break;
- // If menu isn't active, get it going
- if (!bMenuActive)
- {
- // If paltran requested . . .
- if (bPalTran)
- PalTranOn();
- sResult = StartMenu(pmenuStart ? pmenuStart : &menuMain, &g_resmgrShell, g_pimScreenBuf);
- if (sResult == 0)
- {
- bMenuActive = true;
- // Restore defaults.
- pmenuStart = NULL;
- bPalTran = true;
- bTitleImage = true;
- bTitleMusak = true;
- }
- else
- {
- TRACE("GameLoop(): Error returned by StartMenu()!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, "Cannot initialize menu system, most likely due to a memory or drive error.\n");
- break;
- }
- }
- // Let menu system do its thing
- DoMenuInput(&ie, g_InputSettings.m_sUseJoy);
- DoMenuOutput(g_pimScreenBuf);
- // Update the screen
- rspUpdateDisplay();
- // If this is not the spawn version, then check to see if the user has been
- // idle long enough to run a demo. The spawn version doesn't have any
- // demos available, so we shouldn't try to run them.
- #ifndef SPAWN
- // If there's no user action and the demo timer expired, simulate the
- // appropriate action to start the self-running demo.
- #if 0 // Just disable demos entirely, we've changed things too much for the old demos to be compatible anymore. - Rick
- if ((m_action == ACTION_NOTHING) &&
- ((rspGetMilliseconds() - m_lDemoBaseTime) >= m_lDemoTimeOut) &&
- g_GameSettings.m_sNumAvailableDemos > 0)
- m_action = ACTION_DEMO_PLAYBACK;
- #endif
- #endif // SPAWN
- // Reset next action.
- actionNext = ACTION_NOTHING;
- // Any action to handle?
- if (m_action != ACTION_NOTHING)
- {
- // Handle the action
- switch(m_action)
- {
- //------------------------------------------------------------------------------
- // Play single player game
- //------------------------------------------------------------------------------
- case ACTION_PLAY_SINGLE:
- // If this is the spawn version, then they are not allowed to play single
- // player, so we will take out some of the single player code so its not
- // easy to hack back in.
- #ifndef SPAWN
- // End menu
- StopMenu();
- PalTranOff();
- bMenuActive = false;
- // Clear the game winning flag - play will set it before it returns
- // if the player has won the game
- g_bLastLevelDemo = false;
- Play(
- NULL, // No client (not network game)
- NULL, // No server (not network game)
- INPUT_MODE_LIVE, // Input mode
- m_sRealmNum, // Realm number OR -1 to use realm file
- m_szRealmFile, // Realm file
- m_bJustOneRealm, // Whether to play just one realm or not
- false, // Not challenge mode
- false, // Not new single player Add on levels
- GetGameDifficulty(), // Difficulty level
- false, // Rejunenate (MP only)
- 0, // Time limit (MP only)
- 0, // Kill limit (MP only)
- 0, // Use cooperative levels (MP only)
- 0, // Use cooperative mode (MP only)
- 0, // Frame time (MP only)
- NULL); // Demo mode file
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- // If the player won the game, show them the last level demo
- // and then the ending cutscenes.
- if (g_bLastLevelDemo)
- GameEndingSequence();
- // clear the end of game flag just to be safe
- g_bLastLevelDemo = false;
- #endif
- break;
-
- //------------------------------------------------------------------------------
- // Join a multiplayer game
- //------------------------------------------------------------------------------
- case ACTION_PLAY_BROWSE:
- case ACTION_PLAY_CONNECT:
- // If multiplayer is disabled, leave out this code to make it harder to hack back in
- #ifndef MULTIPLAYER_DISABLED
- {
- // Set flag as to whether we're browsing or connecting
- bool bBrowse = (m_action == ACTION_PLAY_BROWSE) ? true : false;
- // Startup sockets with selected protocol
- if (RSocket::Startup((RSocket::ProtoType)g_GameSettings.m_usProtocol, false) == 0)
- {
- InitNetProbGUI();
- // Set next menu to start on to the current menu.
- pmenuStart = GetCurrentMenu();
- // End the menu but don't PalTranOff unless we actually join a game.
- StopMenu();
- bMenuActive = false;
- bPalTran = false;
- bTitleImage = false;
- bTitleMusak = false;
- // Use the net game dialog to join a multiplayer game
- CNetClient* pnetclient = new CNetClient;
- NetMsg msg;
- if (DoNetGameDialog(pnetclient, bBrowse, NULL, &msg) == 0)
- {
- // If the game was actually started...
- if (msg.msg.nothing.ucType == NetMsg::START_GAME)
- {
- PalTranOff();
- // Go back to the main menu when done and do
- // all the deluxe stuff.
- pmenuStart = NULL;
- bPalTran = true;
- bTitleImage = true;
- bTitleMusak = true;
- ASSERT(pnetclient->GetNumPlayers() >= 1);
- // Create synchronization logs, if enabled.
- OpenSynchLogs(true);
- Play(
- pnetclient, // Client
- NULL, // No server (not hosting game)
- INPUT_MODE_LIVE, // Input mode
- msg.msg.startGame.sRealmNum, // Realm number OR -1 to use realm file
- msg.msg.startGame.acRealmFile, // Realm file
- msg.msg.startGame.sRealmNum >= 0 ? false : true, // Whether to play just one realm or not
- false, // Not challenge mode
- false, // Not new single player Add On leves
- msg.msg.startGame.sDifficulty, // Difficulty
- msg.msg.startGame.sRejuvenate, // Rejunenate (MP only)
- msg.msg.startGame.sTimeLimit, // Time limit (MP only)
- msg.msg.startGame.sKillLimit, // Kill limit (MP only)
- msg.msg.startGame.sCoopLevels, // Cooperative or Deathmatch levels (MP only)
- msg.msg.startGame.sCoopMode, // Cooperative or Deathmatch mode (MP only)
- msg.msg.startGame.sFrameTime, // Frame time (MP only)
- NULL); // Demo mode file
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- // Close synchronization logs, if opened.
- CloseSynchLogs();
- }
- }
- delete pnetclient;
- KillNetProbGUI();
- RSocket::Shutdown();
- }
- else
- {
- TRACE("GameCore(): Couldn't init protocol!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, "The selected network protocol has failed to initialize. Please contact your system administrator or network vendor.\n");
- }
- }
- #endif //MULTIPLAYER_DISABLED
- break;
- //------------------------------------------------------------------------------
- // Host a multiplayer game
- //------------------------------------------------------------------------------
- case ACTION_PLAY_HOST:
- // If multiplayer is disabled, leave out this code to make it harder to hack back in
- #ifndef MULTIPLAYER_DISABLED
- {
- // Startup sockets with selected protocol
- if (RSocket::Startup((RSocket::ProtoType)g_GameSettings.m_usProtocol, false) == 0)
- {
- InitNetProbGUI();
- // Set next menu to start on to the current menu.
- pmenuStart = GetCurrentMenu();
- // End the menu but don't PalTranOff unless we actually join a game.
- StopMenu();
- bMenuActive = false;
- bPalTran = false;
- bTitleImage = false;
- bTitleMusak = false;
- // Use the net game dialog to host a multiplayer game
- CNetClient* pnetclient = new CNetClient;
- CNetServer* pnetserver = new CNetServer;
- NetMsg msg;
- if (DoNetGameDialog(pnetclient, false, pnetserver, &msg) == 0)
- {
- // If the game was actually started...
- if (msg.msg.nothing.ucType == NetMsg::START_GAME)
- {
- PalTranOff();
- // Go back to the main menu when done and do
- // all the deluxe stuff.
- pmenuStart = NULL;
- bPalTran = true;
- bTitleImage = true;
- bTitleMusak = true;
- ASSERT(pnetclient->GetNumPlayers() >= 1);
- // Create synchronization logs, if enabled.
- OpenSynchLogs(true);
- Play(
- pnetclient, // Client
- pnetserver, // Server, too
- INPUT_MODE_LIVE, // Input mode
- msg.msg.startGame.sRealmNum, // Realm number OR -1 to use realm file
- msg.msg.startGame.acRealmFile, // Realm file
- msg.msg.startGame.sRealmNum >= 0 ? false : true, // Whether to play just one realm or not
- false, // Not challenge mode
- false, // Not new single player Add on levels
- msg.msg.startGame.sDifficulty, // Difficulty
- msg.msg.startGame.sRejuvenate, // Rejunenate (MP only)
- msg.msg.startGame.sTimeLimit, // Time limit (MP only)
- msg.msg.startGame.sKillLimit, // Kill limit (MP only)
- msg.msg.startGame.sCoopLevels, // Cooperative or Deathmatch levels (MP only)
- msg.msg.startGame.sCoopMode, // Cooperative or Deathmatch mode (MP only)
- msg.msg.startGame.sFrameTime, // Frame time (MP only)
- NULL); // Demo mode file
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- // Close synchronization logs, if opened.
- CloseSynchLogs();
- }
- }
- delete pnetserver;
- delete pnetclient;
- KillNetProbGUI();
- RSocket::Shutdown();
- }
- else
- {
- TRACE("GameCore(): Couldn't init protocol!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, "The selected network protocol has failed to initialize. Please contact your system administrator or network vendor.\n");
- }
- }
- #endif //MULTIPLAYER_DISABLED
- break;
- //------------------------------------------------------------------------------
- // Play challenge game
- //------------------------------------------------------------------------------
- case ACTION_PLAY_CHALLENGE:
- // Remember menu to go back to.
- pmenuStart = GetCurrentMenu();
- // End the menu.
- StopMenu();
- bMenuActive = false;
- // Turn off paltran but remember to restore.
- PalTranOff();
- bPalTran = true;
- // Remember to show title, but no musak.
- bTitleImage = true;
- bTitleMusak = false;
- // Note that m_sRealmNum, m_szRealmFile, and m_bJustOneRealm are
- // set via the callback, Game_StartChallengeGame().
- // ***ADD FLAG(S) TO THIS CALL INDICATING THIS IS A CHALLENGE GAME***
- Play(
- NULL, // No client (not network game)
- NULL, // No server (not network game)
- INPUT_MODE_LIVE, // Input mode
- m_sRealmNum, // Realm number OR -1 to use realm file
- m_szRealmFile, // Realm file
- m_bJustOneRealm, // Whether to play just one realm or not
- true, // Play challenge levels
- false, // Not new single player Add On levels
- GetGameDifficulty(), // Difficulty level
- false, // Rejunenate (MP only)
- 0, // Time limit (MP only)
- 0, // Kill limit (MP only)
- 0, // Cooperative (MP only)
- 0, // Use cooperative mode (MP only)
- 0, // Frame time (MP only)
- NULL); // Demo mode file
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- break;
- //------------------------------------------------------------------------------
- // Play Add On levels
- //------------------------------------------------------------------------------
- case ACTION_PLAY_ADDON:
- #ifndef SPAWN
- // Remember menu to go back to.
- pmenuStart = GetCurrentMenu();
- // End the menu.
- StopMenu();
- bMenuActive = false;
- // Turn off paltran but remember to restore.
- PalTranOff();
- bPalTran = true;
- // Remember to show title, but no musak.
- bTitleImage = true;
- bTitleMusak = false;
- // Note that m_sRealmNum, m_szRealmFile, and m_bJustOneRealm are
- // set via the callback, Game_StartChallengeGame().
- // ***ADD FLAG(S) TO THIS CALL INDICATING THIS IS A CHALLENGE GAME***
- Play(
- NULL, // No client (not network game)
- NULL, // No server (not network game)
- INPUT_MODE_LIVE, // Input mode
- m_sRealmNum, // Realm number OR -1 to use realm file
- m_szRealmFile, // Realm file
- m_bJustOneRealm, // Whether to play just one realm or not
- false, // Don't play challenge levels
- true, // Play new single player Add on levels
- GetGameDifficulty(), // Difficulty level
- false, // Rejunenate (MP only)
- 0, // Time limit (MP only)
- 0, // Kill limit (MP only)
- 0, // Cooperative (MP only)
- 0, // Use cooperative mode (MP only)
- 0, // Frame time (MP only)
- NULL); // Demo mode file
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- #endif // SPAWN
- break;
-
- //------------------------------------------------------------------------------
- // Playback demo
- //------------------------------------------------------------------------------
- case ACTION_DEMO_PLAYBACK:
- {
- // Prepare all settings for demo mode
- CSettings::PreDemo();
- // If demo debug movie file is specified in prefs, open it now. The RFile*
- // is does double-duty as a flag, where non-zero means movie mode is enabled.
- RFile* pfileDemoDebugMovie = 0;
- #if 0
- if (strlen(g_GameSettings.m_szDemoDebugMovie) > 0)
- {
- pfileDemoDebugMovie = new RFile;
- if (pfileDemoDebugMovie->Open(g_GameSettings.m_szDemoDebugMovie, "rb", RFile::LittleEndian) != 0)
- {
- delete pfileDemoDebugMovie;
- pfileDemoDebugMovie = 0;
- }
- }
- #else
- // Compare to synchronization logs, if enabled.
- OpenSynchLogs(false);
- #endif
- if (InputDemoInit() == 0)
- {
- // If no specific filename has been set for the demo, then load one of
- // the default demos.
- if (m_szDemoFile[0] == '\0')
- {
- // If there are default demos . . .
- if(g_GameSettings.m_sNumAvailableDemos > 0)
- {
- sprintf(m_szDemoFile, "%s%d%s", FullPathHD(DEFAULT_DEMO_PREFIX), usDemoCount % MAX((short) 1, g_GameSettings.m_sNumAvailableDemos), DEFAULT_DEMO_SUFFIX);
- }
- }
-
- // If there is now a demo filename . . .
- if (m_szDemoFile[0] != '\0')
- {
- RFile fileDemo;
- usDemoCount++;
- if (fileDemo.Open(m_szDemoFile, "rb", RFile::LittleEndian) == 0)
- {
- // Read name of realm file
- char szRealmFile[RSP_MAX_PATH];
- fileDemo.Read(szRealmFile);
- // Read whether it's a full path.
- short sRealmFileIsFullPath;
- fileDemo.Read(&sRealmFileIsFullPath);
- if (!fileDemo.Error())
- {
- // Load input demo data (must be BEFORE setting playback mode)
- if (InputDemoLoad(&fileDemo) == 0)
- {
- // End menu (now that we know there were no errors)
- StopMenu();
- PalTranOff();
- bMenuActive = false;
- Play(
- NULL, // No client (not network game)
- NULL, // No server (not network game)
- INPUT_MODE_PLAYBACK, // Input mode
- -1, // Always use specific realm file
- szRealmFile, // Realm file to be played
- false, // Don't play just one realm
- false, // Not challenge mode
- false, // Not new single player Add On levels
- GetGameDifficulty(), // Difficulty level
- false, // Rejunenate (MP only)
- 0, // Time limit (MP only)
- 0, // Kill limit (MP only)
- 0, // Cooperative (MP only)
- 0, // Use cooperative mode (MP only)
- 0, // Frame time (MP only)
- pfileDemoDebugMovie); // Demo mode file
- }
- else
- {
- TRACE("GameCore(): Couldn't load demo data!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileReadError_s, (char*) m_szDemoFile);
- }
- }
- else
- {
- TRACE("GameCore(): Couldn't load realm name!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileReadError_s, (char*) m_szDemoFile);
- }
- fileDemo.Close();
- }
- else
- {
- TRACE("GameCore(): Couldn't open demo file: '%s'\n", m_szDemoFile);
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileOpenError_s, (char*) m_szDemoFile);
- }
- }
- else
- {
- TRACE("GameCore(): No demo filename.\n");
- }
- // Reset demo file name for next time.
- m_szDemoFile[0] = 0;
- InputDemoKill();
- }
- #if 0
- if (pfileDemoDebugMovie)
- {
- // File may have been closed by Play() if an error occurred
- if (pfileDemoDebugMovie->IsOpen())
- pfileDemoDebugMovie->Close();
- delete pfileDemoDebugMovie;
- pfileDemoDebugMovie = 0;
- }
- #else
- CloseSynchLogs();
- #endif
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- // Restore settings to what they were before demo mode
- CSettings::PostDemo();
- }
- break;
- //------------------------------------------------------------------------------
- // Record demo
- //------------------------------------------------------------------------------
- case ACTION_DEMO_RECORD:
- {
- // Prepare all settings for demo mode
- CSettings::PreDemo();
- // If demo debug movie file is specified in prefs, open it now. The RFile*
- // is does double-duty as a flag, where non-zero means movie mode is enabled.
- RFile* pfileDemoDebugMovie = 0;
- #if 0
- if (strlen(g_GameSettings.m_szDemoDebugMovie) > 0)
- {
- pfileDemoDebugMovie = new RFile;
- if (pfileDemoDebugMovie->Open(g_GameSettings.m_szDemoDebugMovie, "wb", RFile::LittleEndian) != 0)
- {
- delete pfileDemoDebugMovie;
- pfileDemoDebugMovie = 0;
- }
- }
- #else
- // Create synchronization logs, if enabled.
- OpenSynchLogs(true);
- #endif
- if (InputDemoInit() == 0)
- {
- // Get name of realm to play
- char szRealmFile[RSP_MAX_PATH];
- short sGetRealmResult = GetRealmToRecord(szRealmFile, sizeof(szRealmFile));
- switch (sGetRealmResult)
- {
- case 0: // Success.
- break;
- case 1: // Not a relative path. Got a full path.
- break;
- default: // Error.
- break;
- }
- if (sGetRealmResult >= 0)
- {
- // Get name of demo file to save to
- char szDemoFile[RSP_MAX_PATH];
- if (GetDemoFile(szDemoFile, sizeof(szDemoFile)) == 0)
- {
- // Open demo file
- RFile fileDemo;
- if (fileDemo.Open(szDemoFile, "wb", RFile::LittleEndian) == 0)
- {
- // Write name of realm file
- fileDemo.Write(szRealmFile);
- // Write whether it's a full path.
- fileDemo.Write(sGetRealmResult);
- // End menu (now that we know there were no errors)
- StopMenu();
- PalTranOff();
- bMenuActive = false;
- Play(
- NULL, // No client (not network game)
- NULL, // No server (not network game)
- INPUT_MODE_RECORD, // Input mode
- -1, // Always use specific realm file
- szRealmFile, // Realm file to be played
- false, // Don't play just one realm
- false, // Not challenge mode
- false, // Not new single player Add on levels
- GetGameDifficulty(), // Difficulty level
- false, // Rejunenate (MP only)
- 0, // Time limit (MP only)
- 0, // Kill limit (MP only)
- 0, // Cooperative (MP only)
- 0, // Use cooperative mode (MP only)
- 0, // Frame time (MP only)
- pfileDemoDebugMovie); // Demo mode file
- #ifdef MOBILE
- AndroidSetScreenMode(TOUCH_SCREEN_MENU);
- #endif
- // Save input data to file
- if (InputDemoSave(&fileDemo) != 0)
- {
- TRACE("GameCore(): Couldn't save demo data!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileWriteError_s, szDemoFile);
- }
- }
- fileDemo.Close();
- }
- else
- {
- TRACE("GameCore(): Couldn't open demo file: '%s'\n", szDemoFile);
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileOpenError_s, szDemoFile);
- }
- }
- InputDemoKill();
- }
- #if 0
- if (pfileDemoDebugMovie)
- {
- // File may have been closed by Play() if an error occurred
- if (pfileDemoDebugMovie->IsOpen())
- pfileDemoDebugMovie->Close();
- delete pfileDemoDebugMovie;
- pfileDemoDebugMovie = 0;
- }
- #else
- CloseSynchLogs();
- #endif
- // Restore settings to what they were before demo mode
- CSettings::PostDemo();
- }
- break;
- //------------------------------------------------------------------------------
- // Go to the editor
- //------------------------------------------------------------------------------
- #if !defined(EDITOR_DISABLED)
- case ACTION_EDITOR:
- // End menu
- StopMenu();
- PalTranOff();
- bMenuActive = false;
- // Run the game editor
- GameEdit();
- break;
- #endif
- //------------------------------------------------------------------------------
- // Edit key, mouse, or joystick settings.
- //------------------------------------------------------------------------------
- case ACTION_EDIT_INPUT_SETTINGS:
- // Leave the menu on.
- // Run the input settings editor.
- EditInputSettings();
- break;
- //------------------------------------------------------------------------------
- // Postal organ.
- //------------------------------------------------------------------------------
- case ACTION_POSTAL_ORGAN:
- // Launch Postal Organ.
- PlayWithMyOrgan();
- break;
- //------------------------------------------------------------------------------
- // Load previously saved user game.
- //------------------------------------------------------------------------------
- case ACTION_LOAD_GAME:
- {
- // Static so dialog will "remember" the previously-used name
- static char szFileSaved[RSP_MAX_PATH] = "";
- // If not yet used, start out in appropirate directory
- if (szFileSaved[0] == '\0')
- strcpy(szFileSaved, FullPathHD(SAVEGAME_DIR));
- // Display option dialog to let user choose a realm file
- #if 1 //PLATFORM_UNIX
- char tmp[RSP_MAX_PATH];
- if (PickFile("Choose Game Slot", EnumExistingSaveGames, szFileSaved, sizeof(szFileSaved)) == 0)
- {
- #ifdef MOBILE
- //Android we have the format "1 - date"
- //Auot save is "Auto - date"
- //Need to create the filename
- char number = szFileSaved[0];
- if (number == 'A') //Check for auto save now
- snprintf(szFileSaved, sizeof (szFileSaved), "%s/auto.gme", SAVEGAME_DIR);
- else
- snprintf(szFileSaved, sizeof (szFileSaved), "%s/%c.gme", SAVEGAME_DIR,number);
- TRACE("Load file: %s",szFileSaved);
- #else
- char *ptr = strrchr(szFileSaved, '[');
- if (ptr) *(ptr-1) = '\0';
- #endif
- // This function will open the saved game file and set the correct game mode
- // and settings. Note that this modifies the m_action (that's how we get
- // out this state...this confused me for a while but it seems like a good
- // way to choose the appropriate original action).
- Game_LoadPlayersGame(szFileSaved, &ms_sLoadedDifficulty, &actionNext);
- m_bJustOneRealm = false;
- }
- #else
- if (rspOpenBox(g_pszLoadGameTitle, szFileSaved, szFileSaved, sizeof(szFileSaved), ".gme") == 0)
- {
- // This function will open the saved game file and set the correct game mode
- // and settings. Note that this modifies the m_action (that's how we get
- // out this state...this confused me for a while but it seems like a good
- // way to choose the appropriate original action).
- Game_LoadPlayersGame(szFileSaved, &ms_sLoadedDifficulty, &actionNext);
- m_bJustOneRealm = false;
- }
- #endif
- break;
- }
- #ifdef MOBILE
- case ACTION_CONTINUE_GAME:
- {
- static char szFileSaved[RSP_MAX_PATH] = "";
- snprintf(szFileSaved, sizeof (szFileSaved), "%s/auto.gme", SAVEGAME_DIR);
- Game_LoadPlayersGame(szFileSaved, &ms_sLoadedDifficulty, &actionNext);
- m_bJustOneRealm = false;
- }
- break;
- #endif
- //------------------------------------------------------------------------------
- // Oooops
- //------------------------------------------------------------------------------
- default:
- TRACE("GameCore(): Unrecognized action: %ld!\n", (long)m_action);
- break;
- }
- // If this action lead to another action . . .
- if (actionNext != ACTION_NOTHING)
- {
- // Set current action to the next action
- m_action = actionNext;
- }
- else
- {
- // Reset action
- m_action = ACTION_NOTHING;
- }
- // If menu was taken away, restore the screen behind it
- if (!bMenuActive)
- {
- // If title requested . . .
- if (bTitleImage)
- {
- // Only use musak, if specified.
- StartTitle(0, bTitleMusak, &ms_siMusak);
- EndTitle();
- }
- }
- // Reset demo timer
- ResetDemoTimer();
- }
- }
- // Set the registry value before exiting
- GameSetRegistry();
- // If the menu is active, end it
- if (bMenuActive)
- {
- StopMenu();
- PalTranOff();
- bMenuActive = false;
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Reset temo timer
- //
- ////////////////////////////////////////////////////////////////////////////////
- static void ResetDemoTimer(void)
- {
- // Reset base time
- m_lDemoBaseTime = rspGetMilliseconds();
-
- // Change timeout to use persistant timeout
- m_lDemoTimeOut = g_GameSettings.m_lPersistentDemoTimeOut;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Get realm to be recorded
- //
- ////////////////////////////////////////////////////////////////////////////////
- static short GetRealmToRecord( // Returns 0 on success, negative on error, 1 if
- // not subpathable (i.e., returned path is full path).
- char* pszRealmFile,
- short sMaxFileLen)
- {
- short sResult = 0;
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- // If not yet used, start out in appropriate directory
- // if (szFile[0] == '\0')
- strcpy(szFile, FullPathHD(LEVEL_DIR));
- // Display open dialog to let user choose a file
- sResult = SubPathOpenBox(FullPathHD(""), "Choose Realm To Record", szFile, szFile, sizeof(szFile), "rlm");
- if (sResult >= 0)
- {
- // Convert path to RSPiX path.
- char* pszFullPath = rspPathFromSystem(szFile);
- // Check if result will fit into specified buffer
- if (strlen(pszFullPath) < sMaxFileLen)
- {
- strcpy(pszRealmFile, pszFullPath);
- }
- else
- {
- sResult = -1;
- TRACE("GetRealmToRecord(): File name too long to return in specified buffer!\n");
- }
-
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Get a subpath relative to the specified game path.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern short SubPathOpenBox( // Returns 0 on success, negative on error, 1 if
- // not subpathable (i.e., returned path is full path).
- char* pszFullPath, // In: Full path to be relative to (system format).
- char* pszBoxTitle, // In: Title of box.
- char* pszDefFileName, // In: Default filename (system format).
- char* pszChosenFileName, // Out: User's choice (system format).
- short sStrSize, // In: Amount of memory pointed to by pszChosenFileName.
- char* pszFilter /*= NULL*/) // In: If not NULL, '.' delimited extension based filename
- // filter specification. Ex: ".cpp.h.exe.lib" or "cpp.h.exe.lib"
- // Note: Cannot use '.' in filter. Preceding '.' ignored.
- {
- short sResult;
- char szBasePath[RSP_MAX_PATH];
- long lBasePathLen = strlen(pszFullPath);
- if (lBasePathLen < sizeof(szBasePath) )
- {
- strcpy(szBasePath, pszFullPath);
- // Get index to last character
- short sLastIndex = lBasePathLen;
- if (sLastIndex > 0)
- sLastIndex--;
- #ifdef WIN32
- // If base path doesn't end with a slash, add one
- if (szBasePath[sLastIndex] != RSP_SYSTEM_PATH_SEPARATOR)
- {
- if ((sLastIndex + 2) < RSP_MAX_PATH)
- {
- szBasePath[sLastIndex+1] = RSP_SYSTEM_PATH_SEPARATOR;
- szBasePath[sLastIndex+2] = 0;
- }
- else
- {
- sResult = -1;
- TRACE("SubPathOpenBox(): Path would've exceed max length with separator tacked on!\n");
- }
- }
- #else
- // If base path ends with a colon, get rid of it
- if (szBasePath[sLastIndex] == RSP_SYSTEM_PATH_SEPARATOR)
- szBasePath[sLastIndex] = 0;
- #endif
- char szChosenFileName[RSP_MAX_PATH];
- // Display open dialog to let user choose a file
- sResult = rspOpenBox(pszBoxTitle, pszDefFileName, szChosenFileName, sizeof(szChosenFileName), pszFilter);
- if (sResult == 0)
- {
- // Attempt to remove path from the specified name
- long lFullPathLen = strlen(szBasePath);
- if (rspStrnicmp(szChosenFileName, szBasePath, lFullPathLen) == 0)
- {
- // Copy sub path to destination.
- strcpy(pszChosenFileName, szChosenFileName + lFullPathLen);
- }
- else
- {
- // Not subpathable.
- sResult = 1;
- // Return fullpath.
- // Copy full path to destination.
- strcpy(pszChosenFileName, szChosenFileName);
- }
- }
- }
- else
- {
- sResult = -2;
- TRACE("SubPathOpenBox(): pszFullPath string too long.\n");
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Get name of demo file
- //
- ////////////////////////////////////////////////////////////////////////////////
- static short GetDemoFile(
- char* pszDemoFile,
- short sMaxFileLen)
- {
- short sResult = 0;
-
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- // If not yet used, start out in appropriate directory
- if (szFile[0] == '\0')
- strcpy(szFile, FullPathVD(DEMO_DIR));
- // Display save dialog to let user choose a file
- sResult = rspSaveBox(g_pszSaveDemoTitle, szFile, szFile, sizeof(szFile), DEMO_EXT);
- if (sResult == 0)
- {
- // Check if result will fit into specified buffer
- if (strlen(szFile) < sMaxFileLen)
- {
- strcpy(pszDemoFile, szFile);
- }
- else
- {
- sResult = -1;
- TRACE("GetDemoFile(): File name too long to return in specified buffer!\n");
- }
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Macro to get the sound SAK and (for the event there is no SAK) dir path.
- ////////////////////////////////////////////////////////////////////////////////
- inline void GetSoundPaths( // Returns nothing.
- long lSamplesPerSec, // In: The sample rate in samples per second.
- long lBitsPerSample, // In: The number of bits per sample.
- char* pszSakPath, // Out: The subpath and name of the sound SAK.
- // Should be able to store at least RSP_MAX_PATH
- // characters here.
- char* pszNoSakDir) // Out: The full path of the sound dir to use when
- // there is no sak.
- // Should be able to store at least RSP_MAX_PATH
- // characters here.
- {
- // Make the SAK and base path name.
- char szAudioResDescriptor[256];
- sprintf(
- szAudioResDescriptor,
- "%ld%c%ld",
- lSamplesPerSec,
- AUDIO_SAK_SEPARATOR_CHAR,
- lBitsPerSample);
- // Create the samples SAK sub path.
- strcpy(pszSakPath, SAMPLES_SAK_SUBDIR);
- strcat(pszSakPath, szAudioResDescriptor);
- strcat(pszSakPath, ".sak");
- // Create the samples NO SAK sub path.
- char szSamplesNoSakSubPath[RSP_MAX_PATH];
- strcpy(szSamplesNoSakSubPath, "sound/");
- strcat(szSamplesNoSakSubPath, szAudioResDescriptor);
- // Note that g_GameSettings.m_szNoSakDir is already system
- // specific and already contains the appropriate ending
- // path delimiter, if any, appropriate to the current
- // platform.
- strcpy(pszNoSakDir, g_GameSettings.m_szNoSakDir);
- strcat(pszNoSakDir, rspPathToSystem(szSamplesNoSakSubPath) );
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Open SAKs or set equivalent base paths.
- //
- ////////////////////////////////////////////////////////////////////////////////
- static short OpenSaks(void)
- {
- short sResult = 0; // Assume success.
- // Set base paths.
- g_resmgrShell.SetBasePath(g_GameSettings.m_szNoSakDir);
- g_resmgrGame.SetBasePath(g_GameSettings.m_szNoSakDir);
- g_resmgrRes.SetBasePath(FullPath(GAME_PATH_HD, "") );
- // Attempt to load the Game SAK . . .
- if (g_resmgrGame.OpenSak(FullPath(GAME_PATH_GAME, GAME_SAK_FILENAME) ) == 0)
- {
- }
- // Attempt to load the Shell SAK . . .
- if ((g_resmgrShell.OpenSak(FullPath(GAME_PATH_HD, SHELL_SAK_FILENAME) ) == 0) ||
- (g_resmgrShell.OpenSak(FullPath(GAME_PATH_VD, SHELL_SAK_FILENAME) ) == 0))
- {
- }
- ////////////////////////////////////////////////////////////////////////////
- // The Samples res directory and SAK filename are based on the current
- // audio mode.
- ////////////////////////////////////////////////////////////////////////////
- // Get the current audio mode, if any.
- short sInSoundMode;
- long lSamplesPerSec;
- long lDevBitsPerSample;
- long lSrcBitsPerSample;
- long lMixBitsPerSample;
- if (RMix::GetMode( // Returns 0 on success;
- // nonzero if no mode.
- &lSamplesPerSec, // Sample rate in samples per second
- // returned here, if not NULL.
- &lDevBitsPerSample, // Bits per sample of device,
- // returned here, if not NULL.
- NULL, // Number of channels (1 == mono,
- // 2 == stereo) returned here,
- // if not NULL.
- NULL, // Amount of time in ms to lead the
- // current play cursor returned here,
- // if not NULL. This could also be
- // described as the maximum amount of
- // time in ms that can occur between
- // calls to rspDoSound.
- NULL, // Maximum buffer time. This is the amt
- // that *plBufferTime can be increased to.
- // This is indicative of how much space
- // was/will-be allocated for the sound
- // output device on rspLockSoundOut.
- &lMixBitsPerSample, // Bits per sample at which samples are
- // mixed, if not NULL.
- &lSrcBitsPerSample) // Bits per sample at which samples must
- // be to be mixed (0 if no requirement),
- // if not NULL.
- == 0)
- {
- // Sample quality values set by rspGetSoundOutMode().
- // If no pref on src bits . . .
- if (lSrcBitsPerSample == 0)
- {
- // Set it to the mix quality. This is a just in case as currently
- // these are always the same as set in main.cpp.
- lSrcBitsPerSample = lMixBitsPerSample;
- }
- // Note that there is a real sound mode.
- sInSoundMode = TRUE;
- }
- else
- {
- // In the case that there is no audio mode we still need to access one set of
- // samples so we assume Vanilla settings b/c these use less memory.
- lSamplesPerSec = MAIN_VANILLA_AUDIO_RATE;
- lDevBitsPerSample = lMixBitsPerSample = lSrcBitsPerSample = MAIN_VANILLA_AUDIO_BITS;
-
- // Note that there is no real sound mode.
- sInSoundMode = FALSE;
- }
- // Actual sample rates can (and do) vary from system to system. We need
- // to "round" the actual rate so it matches one of the specific rates that
- // we're looking for. The variance we allow for is +/- one percent.
- if ((lSamplesPerSec >= (11025 - 110)) && (lSamplesPerSec <= (11025 + 110)))
- lSamplesPerSec = 11025;
- else if ((lSamplesPerSec >= (22050 - 220)) && (lSamplesPerSec <= (22050 + 220)))
- lSamplesPerSec = 22050;
- else if ((lSamplesPerSec >= (44100 - 441)) && (lSamplesPerSec <= (44100 + 441)))
- lSamplesPerSec = 44100;
- else
- {
- TRACE("OpenSaks(): Unsupported sample rate: %ld!\n", (long)lSamplesPerSec);
- ASSERT(0);
- }
- char szSamplesSakSubPath[RSP_MAX_PATH];
- char szSamplesNoSakFullPath[RSP_MAX_PATH];
- GetSoundPaths(lSamplesPerSec, lSrcBitsPerSample, szSamplesSakSubPath, szSamplesNoSakFullPath);
- // Attempt to load the Sample SAK . . .
- if (g_resmgrSamples.OpenSak(FullPath(GAME_PATH_SOUND, szSamplesSakSubPath) ) == 0)
- {
- // Wahoo. No worries.
- }
- // Otherwise, if there's a dir for files when there's no SAK . . .
- else if (g_GameSettings.m_szNoSakDir[0] != '\0')
- {
- g_resmgrSamples.SetBasePath(szSamplesNoSakFullPath);
- }
- // Otherwise, . . .
- else
- {
- // If there's a sound mode that was successfully set up . . .
- if (sInSoundMode)
- {
- char szSoundQuality[256];
- sprintf(szSoundQuality, "%.3f kHz, %hd Bit",
- (float)lSamplesPerSec/(float)1000,
- (short)lSrcBitsPerSample,
- (MAIN_AUDIO_CHANNELS == 1) ? "Mono" : "Stereo");
- rspMsgBox(
- RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
- g_pszAppName,
- g_pszCannotOpenSoundFiles_s_s,
- szSoundQuality,
- szSoundQuality);
- // Failure.
- sResult = 1;
- }
- else
- {
- // We've one last chance. Try 'em all. Technically, we've already
- // tried 22050, 8 (the 'Vanilla mode') if we got here, but let's try
- // them all to make sure.
- struct
- {
- long lSamplesPerSec;
- long lBitsPerSample;
- } amodes[] =
- {
- // Put the smaller ones first b/c they use less memory.
- { 22050, 8 },
- { 11025, 16 },
- { 22050, 16 },
- };
- short sModeIndex;
- bool bSakFound = false;
- for (sModeIndex = 0; sModeIndex < NUM_ELEMENTS(amodes) && bSakFound == false; sModeIndex++)
- {
- // Get the appropriate sample SAK name.
- GetSoundPaths(amodes[sModeIndex].lSamplesPerSec, amodes[sModeIndex].lBitsPerSample, szSamplesSakSubPath, szSamplesNoSakFullPath);
-
- // Attempt to load the Sample SAK . . .
- if (g_resmgrSamples.OpenSak(FullPath(GAME_PATH_SOUND, szSamplesSakSubPath) ) == 0)
- {
- // Set values to determine SampleMaster quality.
- // This is probably not necessary when using no sound but let's be safe.
- lSamplesPerSec = amodes[sModeIndex].lSamplesPerSec;
- lSrcBitsPerSample = amodes[sModeIndex].lBitsPerSample;
- // Got one.
- bSakFound = true;
- }
- }
- // If no SAK found . . .
- if (bSakFound == false)
- {
- rspMsgBox(
- RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
- g_pszAppName,
- g_pszNoSoundFiles);
- // Failure.
- sResult = 1;
- }
- }
- }
- // Set the appropriate quality.
- g_GameSettings.m_eCurSoundQuality = (SampleMaster::SoundQuality)( ( (lSamplesPerSec / 11025) - 1) * 2 + ( (lDevBitsPerSample / 8) - 1) );
- // Set volumes based on quality's category adjustor.
- short i;
- for (i = 0; i < SampleMaster::MAX_NUM_SOUND_CATEGORIES; i++)
- {
- SetCategoryVolume((SampleMaster::SoundCategory)i, g_GameSettings.m_asCategoryVolumes[i] );
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Close SAKs and/or Purge() them.
- //
- ////////////////////////////////////////////////////////////////////////////////
- static void CloseSaks(void)
- {
- g_resmgrShell.Purge();
- g_resmgrShell.CloseSak();
-
- g_resmgrGame.Purge();
- g_resmgrGame.CloseSak();
-
- g_resmgrSamples.Purge();
- g_resmgrSamples.CloseSak();
- g_resmgrRes.Purge();
- g_resmgrRes.CloseSak();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Load game data that we want around the entire game.
- //
- // I'm not entirely against just keeping all the game data global since that's
- // the way it's always been done. On the other hand, I kind of like the idea
- // of using a similar mechanism for loading game data as I did for doing the
- // game settings. It allows various modules to automatically be included in
- // the loading process, and keeps the data local to the module. Back on the
- // first hand, we'll probably be grouping data into large, wad-type files, so
- // somehow it seems less compelling to try to keep the data separated within
- // the app.
- //
- ////////////////////////////////////////////////////////////////////////////////
- static short LoadAssets(void)
- {
- // Load font.
- if (g_fontBig.Load(FullPath(GAME_PATH_VD, BIG_FONT_FILE)) != 0)
- {
- TRACE("GameLoadAssets(): Error loading font: %s !\n", FullPath(GAME_PATH_VD, BIG_FONT_FILE));
- return -1;
- }
- // Load font, the smaller.
- if (g_fontPostal.Load(FullPath(GAME_PATH_VD, POSTAL_FONT_FILE) ) != 0)
- {
- TRACE("GameLoadAssets(): Error loading font: %s !\n", FullPath(GAME_PATH_VD, POSTAL_FONT_FILE));
- return -1;
- }
- short i;
- long lTotalTime = 0;
- for (i = 0; i < TitleGetNumTitles(); i++)
- lTotalTime += g_GameSettings.m_alTitleDurations[i];
- // Fake lots of loading with a simple timing loop
- long lTime;
- long lLastTime = rspGetMilliseconds();
- long lEndTime = lLastTime + lTotalTime;
- do
- {
- lTime = rspGetMilliseconds();
- UpdateSystem();
- DoTitle(lTime - lLastTime);
- lLastTime = lTime;
- } while (lTime < lEndTime && rspGetQuitStatus() == FALSE);
- // If we get this far, return success
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Unload game data that was loaded by GameLoadAssets().
- //
- ////////////////////////////////////////////////////////////////////////////////
- static short UnloadAssets(void)
- {
- return 0;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Start Single Player Game" menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_StartSinglePlayerGame(
- short sMenuItem)
- {
- // we reset these as we go along.
- const bool usedCheats = ((Flag_Achievements & FLAG_USED_CHEATS) != 0);
- Flag_Achievements = FLAG_USED_M16 | FLAG_KILLED_EVERYTHING | FLAG_KILLED_ONLY_HOSTILES | FLAG_HIGHEST_DIFFICULTY;
- if (usedCheats)
- Flag_Achievements |= FLAG_USED_CHEATS;
- playthroughMS = 0;
- // If its a spawn version, then don't allow them to play single player
- // games, and to make it harder, we will take out some of the code for
- // single player games so its harder to hack back in.
- #ifndef SPAWN
- switch (sMenuItem)
- {
- // "ORIGINAL LEVELS"
- case 0:
- m_action = ACTION_PLAY_SINGLE;
- m_sRealmNum = 0;
- m_szRealmFile[0] = 0;
- m_bJustOneRealm = false;
- break;
- #if defined(START_MENU_ADDON_ITEM)
- #define START_MENU_ID_OFFSET 0
- // "ADD-ON LEVELS"
- case 1:
- m_action = ACTION_PLAY_ADDON;
- m_sRealmNum = 0;
- m_szRealmFile[0] = 0;
- m_bJustOneRealm = false;
- break;
- #else
- #define START_MENU_ID_OFFSET -1
- #endif
- #ifdef MOBILE
- case 2 + START_MENU_ID_OFFSET:
- m_action = ACTION_CONTINUE_GAME;
- break;
- case 3 + START_MENU_ID_OFFSET:
- #else
- // "LOAD" game
- case 2 + START_MENU_ID_OFFSET:
- #endif
- #ifndef LOADLEVEL_REMOVED
- {
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- // If not yet used, start out in appropriate directory
- if (szFile[0] == '\0')
- strcpy(szFile, FullPathHD(LEVEL_DIR));
- if (rspOpenBox("Load Realm", szFile, szFile, sizeof(szFile), ".rlm") == 0)
- {
- // Convert path from system format to rspix format so it matches the
- // way we normally call Play(), which is with a rspix path.
- rspPathFromSystem(szFile, m_szRealmFile);
- m_action = ACTION_PLAY_SINGLE;
- m_sRealmNum = -1;
- m_bJustOneRealm = true;
- }
- break;
- }
- // For the final version, the LOAD above will actually be this, but
- // it is still useful for testing the way it is now, so I'll add this
- // as a separate option - Load Saved Game
- case 3 + START_MENU_ID_OFFSET:
- #endif
- m_action = ACTION_LOAD_GAME;
- break;
- #if (TARGET == POSTAL_2015)
- case 3 + START_MENU_ID_OFFSET:
- Game_StartChallengeGame(0);
- break;
- #endif
- }
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- #endif // SPAWN
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Start MultiPlayer Game" menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern bool Game_StartMultiPlayerGame(
- short sMenuItem)
- {
- bool bAccept = true;
- #if defined(MULTIPLAYER_DISABLED)
- rspMsgBox(RSP_MB_ICN_INFO | RSP_MB_BUT_OK, APP_NAME, g_pszMultiplayerDisabled);
- bAccept = false;
- #else
- // Do nothing if multiplayer is available
- #endif
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- return bAccept;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Join MultiPlayer Game" menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_JoinMultiPlayerGame(
- short sMenuItem)
- {
- switch (sMenuItem)
- {
- // "BROWSE"
- case 0:
- m_action = ACTION_PLAY_BROWSE;
- break;
- // "CONNECT"
- case 1:
- m_action = ACTION_PLAY_CONNECT;
- break;
- }
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Host MultiPlayer Game" menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_HostMultiPlayerGame(
- short sMenuItem)
- {
- switch (sMenuItem)
- {
- // "HOST"
- case 0:
- m_action = ACTION_PLAY_HOST;
- break;
- }
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Start Demo Game" menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_StartDemoGame(
- short sMenuItem)
- {
- char* pszDemoFile = NULL;
- char szLevelDir[RSP_MAX_PATH] = "";
- char szTitle[256] = "";
- switch (sMenuItem)
- {
- // Browse for and Playback demo
- case 0:
- {
- // Get the filename of the demo to load.
- static char szFile[RSP_MAX_PATH] = "";
- sprintf(szLevelDir, "%s", DEMO_LEVEL_DIR);
- pszDemoFile = szFile;
- // If not yet used, start out in appropriate directory
- if (pszDemoFile[0] == '\0')
- strcpy(pszDemoFile, FullPathHD(szLevelDir) );
- // Display open dialog to let user choose a realm file
- sprintf(szTitle, "%s", DEMO_OPEN_TITLE);
- if (rspOpenBox(szTitle, pszDemoFile, m_szDemoFile, sizeof(m_szDemoFile), ".dmo") == 0)
- {
- m_action = ACTION_DEMO_PLAYBACK;
- }
- }
- break;
- // Play auto demo.
- case 1:
- // Clear demo filename. This signifies that we should play one of
- // the auto demos.
- m_szDemoFile[0] = '\0';
- m_action = ACTION_DEMO_PLAYBACK;
- break;
- // Record demo
- case 2:
- m_action = ACTION_DEMO_RECORD;
- break;
- }
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Buy" option on the Main Menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_Buy(void)
- {
- rspMsgBox(RSP_MB_ICN_INFO | RSP_MB_BUT_OK, APP_NAME, g_pszBuy);
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Editor" option on the Main Menu
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_StartEditor(void)
- {
- #if defined(EDITOR_DISABLED)
- rspMsgBox(RSP_MB_ICN_INFO | RSP_MB_BUT_OK, APP_NAME, g_pszEditorDisabled);
- #else
- m_action = ACTION_EDITOR;
- #endif
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Controls" menu.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_ControlsMenu(
- short sMenuItem)
- {
- // Only do this if we're not currently in an action . . .
- if (m_action == ACTION_NOTHING)
- {
- switch (sMenuItem)
- {
- // Edit keyboard settings.
- case 0:
- m_action = ACTION_EDIT_INPUT_SETTINGS;
- break;
- // Edit mouse settings.
- case 1:
- m_action = ACTION_EDIT_INPUT_SETTINGS;
- break;
- // Edit joystick settings.
- case 2:
- #if defined(ALLOW_JOYSTICK)
- m_action = ACTION_EDIT_INPUT_SETTINGS;
- #endif // defined(ALLOW_JOYSTICK)
- break;
- }
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for "Audio Options" menu.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_AudioOptionsChoice( // Returns nothing.
- short sMenuItem) // In: Chosen item.
- {
- switch (sMenuItem)
- {
- case 1:
- m_action = ACTION_POSTAL_ORGAN;
- break;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the "Start Challenge" menu.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_StartChallengeGame( // Returns nothing.
- short sMenuItem) // In: Chosen menu item.
- {
- char* pszRealmFile = NULL;
- char szLevelDir[RSP_MAX_PATH] = "";
- char szTitle[256] = "";
- switch (sMenuItem)
- {
- // Run the Gauntlet.
- case 0:
- m_action = ACTION_PLAY_CHALLENGE;
- m_sRealmNum = 0;
- m_szRealmFile[0] = 0;
- m_bJustOneRealm = false;
- break;
- // Timed Challenge.
- case 1:
- {
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- pszRealmFile = szFile;
- strcpy(szLevelDir, TIMED_CHALLENGE_LEVEL_DIR);
- strcpy(szTitle, TIMED_CHALLENGE_OPEN_TITLE);
- break;
- }
- // Goal Challenge.
- case 2:
- {
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- pszRealmFile = szFile;
- strcpy(szLevelDir, GOAL_CHALLENGE_LEVEL_DIR);
- strcpy(szTitle, GOAL_CHALLENGE_OPEN_TITLE);
- break;
- }
- // Flag Challenge.
- case 3:
- {
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- pszRealmFile = szFile;
- strcpy(szLevelDir, FLAG_CHALLENGE_LEVEL_DIR);
- strcpy(szTitle, FLAG_CHALLENGE_OPEN_TITLE);
- break;
- }
- // Checkpoint Challenge.
- case 4:
- {
- // Static so dialog will "remember" the previously-used name
- static char szFile[RSP_MAX_PATH] = "";
- pszRealmFile = szFile;
- strcpy(szLevelDir, CHECKPOINT_CHALLENGE_LEVEL_DIR);
- strcpy(szTitle, CHECKPOINT_CHALLENGE_OPEN_TITLE);
- break;
- }
- }
- if (pszRealmFile)
- {
- // If not yet used, start out in appropriate directory
- if (pszRealmFile[0] == '\0')
- //strcpy(pszRealmFile, FullPathHD(szLevelDir) );
- strcpy(pszRealmFile, FullPathCD(szLevelDir) );
- // Display open dialog to let user choose a realm file
- if (rspOpenBox(szTitle, pszRealmFile, m_szRealmFile, sizeof(m_szRealmFile), ".rlm") == 0)
- {
- // Convert path from system format to rspix format so it matches the
- // way we normally call Play(), which is with a rspix path.
- // MASSIVE BUG IN rspPathFromSystem() on the Mac -- it doesn't allow
- // the src and dst to be the same, even though the doc says it can!!!!
- // Workaround is to use temporary buffer.
- char szTmp[RSP_MAX_PATH];
- strcpy(szTmp, m_szRealmFile);
- rspPathFromSystem(szTmp, m_szRealmFile);
- m_action = ACTION_PLAY_CHALLENGE;
- m_sRealmNum = -1;
- m_bJustOneRealm = false;
- }
- }
- // The main game loop resets the demo timer whenever it notices any user input.
- // However, when the user is in a dialog or message box, the OS handles all the
- // user input, and the main game loop won't know anything about what's going on
- // in there. If the user spends a long time in there, the demo timer will
- // expire. We don't want that to happen, so we manually reset the demo timer
- // here in recognition of the fact that some kind of user input obviously occurred.
- ResetDemoTimer();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Callback for the Main Menu init/kill.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void Game_InitMainMenu( // Returns nothing.
- short sInit) // In: TRUE, if initializing; FALSE, if killing.
- {
- // If initializing the menu . . .
- if (sInit)
- {
- }
- // Otherwise, killing the menu.
- else
- {
- // Abort the title/main-menu musak.
- AbortSample(ms_siMusak);
- // No need to reset ms_siMusak.
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Game_SavePlayersGame - Save the realm, game type, difficulty, and stockpile
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern short Game_SavePlayersGame(
- char* pszSaveName, // In: Name of the save file
- short sDifficulty) // In: Current realm difficulty.
- {
- RFile rf;
- short sResult = rf.Open(pszSaveName, "wb", RFile::LittleEndian);
- ULONG ulFileVersion = CRealm::FileVersion;
- if (sResult == SUCCESS)
- {
- rf.Write(ulFileVersion);
- rf.Write(sDifficulty);
- rf.Write((short)m_action);
- rf.Write(g_sRealmNumToSave);
- g_stockpile.Save(&rf);
- // new in version 48.
- rf.Write(Flag_Achievements);
- // new in version 49.
- rf.Write(playthroughMS);
- rf.Close();
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Game_LoadPlayersGame - Load a previously saved game, restore the settings
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern short Game_LoadPlayersGame(
- char* pszSaveName, // In: Name of the saved game file to open
- short* psDifficulty, // Out: Saved game realm difficulty.
- ACTION* paction) // Out: Saved game action.
- {
- RFile rf;
- short sResult = rf.Open(pszSaveName, "rb", RFile::LittleEndian);
- ULONG ulFileVersion;
- if (sResult == SUCCESS)
- {
- rf.Read(&ulFileVersion);
- rf.Read(psDifficulty);
- // Store as 16 bit value (in case Read() fails (we want to keep original
- // functionality which read directly into m_action) ).
- short sAction = (short)*paction;
- // Read as 16 bit.
- rf.Read(&sAction);
- // Store as action.
- *paction = (ACTION)sAction;
- rf.Read(&m_sRealmNum);
- g_stockpile.Load(&rf, ulFileVersion);
- // new in version 48.
- const bool usedCheats = ((Flag_Achievements & FLAG_USED_CHEATS) != 0);
- Flag_Achievements = 0;
- if (ulFileVersion >= 48)
- rf.Read(&Flag_Achievements);
- if (usedCheats)
- Flag_Achievements |= FLAG_USED_CHEATS;
- #if 0
- printf("achievements:\n");
- #define printflag(x) printf("%s: %s\n", #x, (Flag_Achievements & x) ? "true" : "false");
- printflag(FLAG_USED_M16);
- printflag(FLAG_USED_SHOTGUN);
- printflag(FLAG_USED_DBL_SHOTGUN);
- printflag(FLAG_USED_GRENADE);
- printflag(FLAG_USED_ROCKET);
- printflag(FLAG_USED_MOLOTOV);
- printflag(FLAG_USED_NAPALM);
- printflag(FLAG_USED_FLAMETHROWER);
- printflag(FLAG_USED_PROXIMITY_MINE);
- printflag(FLAG_USED_TIMED_MINE);
- printflag(FLAG_USED_REMOTE_MINE);
- printflag(FLAG_USED_BETTY_MINE);
- printflag(FLAG_USED_HEATSEEKER);
- printflag(FLAG_USED_SPRAY_CANNON);
- printflag(FLAG_USED_DEATHWAD);
- printflag(FLAG_USED_CHEATS);
- printflag(FLAG_KILLED_EVERYTHING);
- printflag(FLAG_KILLED_ONLY_HOSTILES);
- #undef printflag
- #endif
- // new in version 49.
- playthroughMS = -1; // disable the achievement for old save games.
- if (ulFileVersion >= 49)
- rf.Read(&playthroughMS);
- rf.Close();
- g_bTransferStockpile = true;
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // GameEndingSequence - Start a demo of the last level
- //
- ////////////////////////////////////////////////////////////////////////////////
- void GameEndingSequence(void)
- {
- // Prepare all settings for demo mode
- CSettings::PreDemo();
- #if VIOLENT_LOCALE
- // If demo debug movie file is specified in prefs, open it now. The RFile*
- // is does double-duty as a flag, where non-zero means movie mode is enabled.
- RFile* pfileDemoDebugMovie = 0;
- m_pfileRandom = 0;
- if (strlen(g_GameSettings.m_szDemoDebugMovie) > 0)
- {
- m_pfileRandom = new RFile;
- if (m_pfileRandom->Open(g_GameSettings.m_szDemoDebugMovie, "rb", RFile::LittleEndian) != 0)
- {
- delete m_pfileRandom;
- m_pfileRandom = 0;
- }
- }
- if (InputDemoInit() == 0)
- {
- // This is the special end of game demo, so set up the demo name
- sprintf(m_szDemoFile, "%s", FullPathCD(ENDING_DEMO_NAME));
- RFile fileDemo;
- if (fileDemo.Open(m_szDemoFile, "rb", RFile::LittleEndian) == 0)
- {
- // Read name of realm file
- char szRealmFile[RSP_MAX_PATH];
- fileDemo.Read(szRealmFile);
- // Read whether it's a full path.
- short sRealmFileIsFullPath;
- fileDemo.Read(&sRealmFileIsFullPath);
- if (!fileDemo.Error())
- {
- // Load input demo data (must be BEFORE setting playback mode)
- if (InputDemoLoad(&fileDemo) == 0)
- {
- // End menu (now that we know there were no errors)
- // StopMenu();
- // PalTranOff();
- // bMenuActive = false;
- Play(
- NULL, // No client (not network game)
- NULL, // No server (not network game)
- INPUT_MODE_PLAYBACK, // Input mode
- -1, // Always use specific realm file
- szRealmFile, // Realm file to be played
- false, // Don't play just one realm
- false, // Not challenge mode
- false, // Not new single player Add On levels
- GetGameDifficulty(), // Difficulty level
- false, // Rejunenate (MP only)
- 0, // Time limit (MP only)
- 0, // Kill limit (MP only)
- 0, // Cooperative (MP only)
- 0, // Use cooperative mode (MP only)
- 0, // Frame time (MP only)
- pfileDemoDebugMovie); // Demo mode file
- }
- else
- {
- TRACE("GameCore(): Couldn't load demo data!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileReadError_s, (char*) m_szDemoFile);
- }
- }
- else
- {
- TRACE("GameCore(): Couldn't load realm name!\n");
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileReadError_s, (char*) m_szDemoFile);
- }
- fileDemo.Close();
- }
- else
- {
- TRACE("GameCore(): Couldn't open demo file: '%s'\n", m_szDemoFile);
- rspMsgBox(RSP_MB_ICN_STOP | RSP_MB_BUT_OK, g_pszAppName, g_pszFileOpenError_s, (char*) m_szDemoFile);
- }
- // Reset demo file name for next time.
- m_szDemoFile[0] = 0;
- InputDemoKill();
- }
- if (m_pfileRandom)
- {
- // File may have been closed by Play() if an error occurred
- if (m_pfileRandom->IsOpen())
- m_pfileRandom->Close();
- delete m_pfileRandom;
- m_pfileRandom = 0;
- }
- #endif // VIOLENT_LOCALE
- // Restore settings to what they were before demo mode
- CSettings::PostDemo();
- SetInputMode(INPUT_MODE_LIVE); // take it out of demo mode so achievements can unlock.
- // Do the ending title sequence.
- Title_GameEndSequence();
- // Do special credits:
- Credits(&g_smidFinalSceneCredits);
- UnlockAchievement(ACHIEVEMENT_COMPLETE_GAME);
- if (playthroughMS < MAX_PLAYTHROUGH_ACHIEVEMENT_MS)
- UnlockAchievement(ACHIEVEMENT_COMPLETE_GAME_IN_X_MINUTES);
- if ((Flag_Achievements & FLAG_MASK_WEAPONS) == FLAG_USED_M16)
- UnlockAchievement(ACHIEVEMENT_USE_ONLY_M16);
- if (Flag_Achievements & FLAG_KILLED_EVERYTHING)
- UnlockAchievement(ACHIEVEMENT_KILL_EVERYTHING);
- if (Flag_Achievements & FLAG_KILLED_ONLY_HOSTILES)
- UnlockAchievement(ACHIEVEMENT_KILL_ONLY_HOSTILES);
- if (Flag_Achievements & FLAG_HIGHEST_DIFFICULTY)
- UnlockAchievement(ACHIEVEMENT_COMPLETE_GAME_ON_HARDEST);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Returns a ptr to just the portion of the file path that specifies the file
- // name (excluding the path).
- ////////////////////////////////////////////////////////////////////////////////
- static char* GetFileNameFromPath( // Returns file name.
- char* pszFullPath) // In: File's full path.
- {
- // Scan back for the separator or the beginning.
- char* pszIndex = pszFullPath + (strlen(pszFullPath) - 1);
- while (pszIndex >= pszFullPath && *pszIndex != RSP_SYSTEM_PATH_SEPARATOR)
- {
- pszIndex--;
- }
- return (pszIndex + 1);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Opens the synchronization log with the specified access flags if in a
- // TRACENASSERT mode and synchronization logging is enabled.
- // Also, opens the random log, if it is enabled via
- // g_GameSettings.m_szDebugMovie or something.
- ////////////////////////////////////////////////////////////////////////////////
- static void OpenSynchLogs( // Returns nothing.
- bool bWriteLogs) // In: true to create log, false to compare.
- {
- m_pfileRandom = 0;
- if (strlen(g_GameSettings.m_szDemoDebugMovie) > 0)
- {
- m_pfileRandom = new RFile;
- if (m_pfileRandom->Open(
- g_GameSettings.m_szDemoDebugMovie,
- bWriteLogs ? "wb" : "rb",
- RFile::LittleEndian) != 0)
- {
- delete m_pfileRandom;
- m_pfileRandom = 0;
- }
- }
- #if defined(_DEBUG) || defined(TRACENASSERT)
- ms_lSynchLogSeq = 0;
- if (g_GameSettings.m_szSynchLogFile[0] != '\0')
- {
- if (ms_fileSynchLog.Open(
- g_GameSettings.m_szSynchLogFile,
- bWriteLogs ? "wb" : "rb",
- RFile::LittleEndian) == 0)
- {
- // Success.
- }
- else
- {
- TRACE("OpenSynchLogs(): Failed to open 'if' log file \"%s\".\n",
- g_GameSettings.m_szSynchLogFile);
- }
- }
- #endif // defined(_DEBUG) || defined(TRACENASSERT)
- m_bWriteLogs = bWriteLogs;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Closes the synchronization logs, if open.
- ////////////////////////////////////////////////////////////////////////////////
- static void CloseSynchLogs(void) // Returns nothing.
- {
- if (m_pfileRandom)
- {
- // File may have been closed by Play() if an error occurred
- if (m_pfileRandom->IsOpen())
- m_pfileRandom->Close();
- delete m_pfileRandom;
- m_pfileRandom = 0;
- }
- #if defined(_DEBUG) || defined(TRACENASSERT)
- if (ms_fileSynchLog.IsOpen() )
- {
- ms_fileSynchLog.Close();
- }
- #endif // defined(_DEBUG) || defined(TRACENASSERT)
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Synchronization logger -- Call this function to log an expression and a user
- // value in the synch log. When active (if g_GameSettings.m_szSynchLog is
- // a valid path and filename), if recording a demo, these calls are logged to
- // a file including the calling file and line number. When active, if playing
- // back a demo, these calls are compared to those stored in the log and, if
- // a discrepancy occurs, a modal dialog box will pop up with the pertinent info
- // followed by an ASSERT(0) for easy debugging.
- ////////////////////////////////////////////////////////////////////////////////
- extern int SynchLog( // Result of expr.
- double expr, // In: Expression to evaluate.
- char* pszFile, // In: Calling file.
- long lLine, // In: Calling line.
- char* pszExpr, // In: Original C++ source expression.
- U32 u32User) // In: A user value that is intended to be consistent.
- {
- #if defined(_DEBUG) || defined(TRACENASSERT)
- if (ms_fileSynchLog.IsOpen() )
- {
- if (m_bWriteLogs)
- {
- fprintf(
- ms_fileSynchLog.m_fs,
- "[Seq: %ld] %s : %ld <$%s$> == %0.8f; User == %lu\n",
- ms_lSynchLogSeq++,
- GetFileNameFromPath(pszFile),
- lLine,
- pszExpr,
- expr,
- u32User);
- }
- else
- {
- char szFileIn[RSP_MAX_PATH];
- char szExprIn[1024];
- long lLineIn;
- long lSeqIn;
- double exprIn;
- U32 u32UserIn;
- if (fscanf(
- ms_fileSynchLog.m_fs,
- "[Seq: %ld] %s : %ld <$%1024[^$]$> == %g; User == %lu\n",
- &lSeqIn,
- szFileIn,
- &lLineIn,
- szExprIn,
- &exprIn,
- &u32UserIn) == 6)
- {
- // Verify . . .
- if ( (rspStricmp(szFileIn, GetFileNameFromPath(pszFile) ) != 0)
- || (lLineIn != lLine)
- || (exprIn != expr)
- || (u32UserIn != u32User) )
- {
- char szOut[2048];
- sprintf(
- szOut,
- "'If' sequence (%ld) mismatch!\n\n"
- " Was <<%s>> at %s(%ld) which got %g; User == %lu\n\n"
- " Now <<%s>> at %s(%ld) which got %g; User == %lu",
- ms_lSynchLogSeq,
- szExprIn,
- szFileIn,
- lLineIn,
- exprIn,
- u32UserIn,
- pszExpr,
- GetFileNameFromPath(pszFile),
- lLine,
- expr,
- u32User);
- TRACE("%s\n\n", szOut);
- rspMsgBox(
- RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
- "Postal",
- szOut);
- // Make this easy to debug
- ASSERT(0);
- }
- ms_lSynchLogSeq++;
- }
- else
- {
- TRACE("Synch(): Error reading log file.\n");
- }
- }
- }
- #else
- rspMsgBox(
- RSP_MB_ICN_STOP | RSP_MB_BUT_OK,
- "Postal",
- "Synchronization logging is disabled for release mode for safety.\n");
- #endif // defined(_DEBUG) || defined(TRACENASSERT)
- return expr;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // GameGetRegistry
- ////////////////////////////////////////////////////////////////////////////////
- static void GameGetRegistry(void)
- {
- #ifdef CHECK_EXPIRATION_DATE
- char szTime[40];
- char szTimeEncrypt[40];
- time_t lTime;
- DWORD dwTimeLength;
- DWORD dwSize = 255;
- char szData[256];
- char szName[256];
- short sEncryptedKeyLength = 36;
- unsigned char szKey[40];
- // This is the encoded path name of the registry key where the value is stored
- szKey[0] = 0x07;
- szKey[1] = 0x29;
- szKey[2] = 0xbd;
- szKey[3] = 0x3a;
- szKey[4] = 0xba;
- szKey[5] = 0x22;
- szKey[6] = 0xbe;
- szKey[7] = 0x36;
- szKey[8] = 0xf5;
- szKey[9] = 0x22;
- szKey[10] = 0xfb;
- szKey[11] = 0x24;
- szKey[12] = 0xd0;
- szKey[13] = 0x3a;
- szKey[14] = 0xd4;
- szKey[15] = 0x71;
- szKey[16] = 0xcb;
- szKey[17] = 0x3e;
- szKey[18] = 0xd5;
- szKey[19] = 0x2a;
- szKey[20] = 0xec;
- szKey[21] = 0x29;
- szKey[22] = 0x89;
- szKey[23] = 0x30;
- szKey[24] = 0x8f;
- szKey[25] = 0x78;
- szKey[26] = 0x83;
- szKey[27] = 0x66;
- szKey[28] = 0xb4;
- szKey[29] = 0x40;
- szKey[30] = 0x86;
- szKey[31] = 0x66;
- szKey[32] = 0x8f;
- szKey[33] = 0x71;
- szKey[34] = 0x9b;
- szKey[35] = 0xfe;
- szKey[36] = 0x00;
- #ifdef WIN32
- DWORD dwDisposition;
- DWORD dwType;
- DWORD dwNameSize = 255;
- HKEY hkResult;
- long lError;
- short sEncryptedValueLength = 9;
- unsigned char szIn[10];
- // This is the encoded name of the registry value itendifier
- szIn[0] = 0x07;
- szIn[1] = 0x29;
- szIn[2] = 0xa8;
- szIn[3] = 0x0f;
- szIn[4] = 0xa7;
- szIn[5] = 0x0c;
- szIn[6] = 0xa8;
- szIn[7] = 0x0e;
- szIn[8] = 0xfd;
- szIn[9] = 0x00;
- // Get the current time and convert it to a string so it can be encoded
- time( &lTime );
- sprintf(szTime, "%ld", lTime);
- // Decrypte the registry key path so the key can be opened
- Decrypt((char*) szKey, szName, sEncryptedKeyLength);
- szName[sEncryptedKeyLength-2] = 0;
- lError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szName, 0,
- "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
- &hkResult, &dwDisposition);
- // Destroy the source and result.
- memset(szName, 0xeb, sEncryptedKeyLength);
- if (lError == ERROR_SUCCESS && lTime > g_lReleaseTime)
- {
- if (dwDisposition == REG_CREATED_NEW_KEY)
- // Write the initial value
- {
- // Make sure current value is after release value
- dwTimeLength = Encrypt(szTime, szTimeEncrypt, strlen(szTime));
- Decrypt((char*) szIn, szName, sEncryptedValueLength);
- szName[sEncryptedValueLength-2] = 0;
- RegSetValueEx(hkResult, szName, 0, REG_BINARY, (unsigned char *) szTimeEncrypt, dwTimeLength);
- memset(szName, 0xeb, sEncryptedValueLength);
- g_lRegTime = lTime;
- }
- else
- {
- lError = RegEnumValue(hkResult, 0, szName, &dwNameSize, 0, &dwType, (unsigned char *) szData, &dwSize);
- if (lError != ERROR_SUCCESS)
- g_lRegTime = EXPIRATION_DATE;
- else
- {
- if (Decrypt(szData, szTime, dwSize) == 0)
- {
- szTime[dwSize] = 0;
- g_lRegTime = atol(szTime);
- }
- else
- {
- g_lRegTime = EXPIRATION_DATE;
- }
- }
- }
- RegCloseKey(hkResult);
- }
- else
- // If there was an error opening the registry key, then it will trace the error
- // message here.
- {
- LPVOID lpMsgBuf;
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
- // Display the string.
- TRACE((char*) lpMsgBuf);
- // Free the buffer.
- LocalFree( lpMsgBuf );
- // This failed either because it couldn't write, or because
- // the date has been set back before the release date, so
- // force this to fail
- g_lRegTime = EXPIRATION_DATE;
- }
- #else // WIN32
- // Do mac version here.
- char szPath[512];
- time( &lTime );
- lTime -= ((365 * 70UL) + 17) * 24 * 60 * 60; // time_fudge 1900->1970
- // Open a prefs file and read the value, or write the value
- // if it is the first time.
- RFile rfPref;
- // If the file does not exist, then write the current date to the file
- // as long as it is after the release date.
- macGetSpecialPath(MacPreferencesFolderType, true, szPath, 254);
- Decrypt((char*) szKey, szName, sEncryptedKeyLength);
- sEncryptedKeyLength = MAX(0, sEncryptedKeyLength - 2);
- szName[sEncryptedKeyLength] = 0;
- strcat(szPath, szName+19);
- if (rfPref.Open(szPath, "rb", RFile::LittleEndian) != SUCCESS)
- {
- if (rfPref.Open(szPath, "wb", RFile::LittleEndian) != SUCCESS)
- {
- // If the file cannot be created, then hose the program
- g_lRegTime = EXPIRATION_DATE;
- }
- else
- {
- // If the date is set back before the release of the beta, then hose the
- // program
- g_lRegTime = lTime;
- if (lTime < g_lReleaseTime)
- g_lRegTime = lTime = EXPIRATION_DATE;
- dwTimeLength = Encrypt((char*) &lTime, szTimeEncrypt, 4);
- rfPref.Write(&dwTimeLength);
- rfPref.Write(szTime, dwTimeLength);
- rfPref.Close();
- }
- }
- // If the prefs file is here, then open it and read the last date
- else
- {
- rfPref.Read(&dwSize);
- rfPref.Read(szData, dwSize);
- rfPref.Close();
-
- if (Decrypt(szData, (char*) &lTime, dwSize) == 0)
- {
- g_lRegTime = lTime;
- }
- else
- {
- g_lRegTime = EXPIRATION_DATE;
- }
- }
-
- #endif // WIN32
- if (g_lRegTime < RELEASE_DATE)
- g_lRegTime = EXPIRATION_DATE;
- #else // CHECK_EXPIRATION_DATE
- g_lRegTime = 0;
- #endif // CHECK_EXPIRATION_DATE
- }
- ////////////////////////////////////////////////////////////////////////////////
- // GameSetRegistry
- ////////////////////////////////////////////////////////////////////////////////
- static void GameSetRegistry(void)
- {
- #ifdef CHECK_EXPIRATION_DATE
- char szTimeEncrypt[40];
- time_t lTime;
- DWORD dwTimeLength;
- char szName[256];
- short sEncryptedKeyLength = 36;
- unsigned char szKey[40];
- szKey[0] = 0x00;
- szKey[1] = 0x3e;
- szKey[2] = 0xde;
- szKey[3] = 0x28;
- szKey[4] = 0xda;
- szKey[5] = 0x46;
- szKey[6] = 0xdd;
- szKey[7] = 0x57;
- szKey[8] = 0xc2;
- szKey[9] = 0x34;
- szKey[10] = 0xc4;
- szKey[11] = 0x32;
- szKey[12] = 0xe8;
- szKey[13] = 0x3f;
- szKey[14] = 0xf8;
- szKey[15] = 0x2c;
- szKey[16] = 0xe8;
- szKey[17] = 0x3e;
- szKey[18] = 0xe8;
- szKey[19] = 0x2a;
- szKey[20] = 0xdc;
- szKey[21] = 0x03;
- szKey[22] = 0xff;
- szKey[23] = 0x14;
- szKey[24] = 0xfb;
- szKey[25] = 0x18;
- szKey[26] = 0xfe;
- szKey[27] = 0x1f;
- szKey[28] = 0xc9;
- szKey[29] = 0x35;
- szKey[30] = 0xe0;
- szKey[31] = 0x02;
- szKey[32] = 0xea;
- szKey[33] = 0x09;
- szKey[34] = 0xf1;
- szKey[35] = 0xf5;
- szKey[36] = 0x00;
- #ifdef WIN32
- char szTime[40];
- DWORD dwDisposition;
- DWORD dwSize = 255;
- DWORD dwNameSize = 255;
- HKEY hkResult;
- long lError;
- short sEncryptedValueLength = 9;
- unsigned char szIn[10];
- szIn[0] = 0x07;
- szIn[1] = 0x29;
- szIn[2] = 0xa8;
- szIn[3] = 0x0f;
- szIn[4] = 0xa7;
- szIn[5] = 0x0c;
- szIn[6] = 0xa8;
- szIn[7] = 0x0e;
- szIn[8] = 0xfd;
- szIn[9] = 0x00;
- time( &lTime );
- lTime = MAX(lTime, g_lRegTime);
- sprintf(szTime, "%ld", lTime);
- Decrypt((char*) szKey, szName, sEncryptedKeyLength);
- szName[sEncryptedKeyLength-2] = 0;
- lError = RegCreateKeyEx(HKEY_LOCAL_MACHINE, szName, 0,
- "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
- &hkResult, &dwDisposition);
- memset(szName, 0xea, sEncryptedKeyLength);
- if (lError == ERROR_SUCCESS)
- {
- // Make sure current value is after release value
- dwTimeLength = Encrypt(szTime, szTimeEncrypt, strlen(szTime));
- Decrypt((char*) szIn, szName, sEncryptedValueLength);
- szName[sEncryptedValueLength-2] = 0;
- RegSetValueEx(hkResult, szName, 0, REG_BINARY, (unsigned char *) szTimeEncrypt, dwTimeLength);
- memset(szIn, 0xee, sEncryptedValueLength);
- RegCloseKey(hkResult);
- }
- else
- {
- LPVOID lpMsgBuf;
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
- // Display the string.
- TRACE((char*) lpMsgBuf);
- // Free the buffer.
- LocalFree( lpMsgBuf );
- }
- #else // WIN32
- // Do the Mac version here
- char szPath[512];
- RFile rfPref;
- time( &lTime );
- lTime -= ((365 * 70UL) + 17) * 24 * 60 * 60; // time_fudge 1900->1970
- // Make sure the time is after the last registered time.
- lTime = MAX(lTime, (time_t) g_lRegTime);
- dwTimeLength = Encrypt((char*) &lTime, szTimeEncrypt, 4);
- macGetSpecialPath(MacPreferencesFolderType, true, szPath, 254);
- Decrypt((char*) szKey, szName, sEncryptedKeyLength);
- sEncryptedKeyLength = MAX(0, sEncryptedKeyLength - 2);
- szName[sEncryptedKeyLength] = 0;
- strcat(szPath, szName+19);
-
- if (rfPref.Open(szPath, "wb", RFile::LittleEndian) == SUCCESS)
- {
- rfPref.Write(&dwTimeLength);
- rfPref.Write(szTimeEncrypt, dwTimeLength);
- rfPref.Close();
- }
- // Open the prefs file and write the value here.
- #endif // WIN32
- #endif // CHECK_EXPIRATION_DATE
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Seed the random number generator
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void SeedRand(
- long lSeed)
- {
- m_lRandom = lSeed;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Get a random number
- //
- ////////////////////////////////////////////////////////////////////////////////
- #if defined(_DEBUG) || defined(TRACENASSERT)
- extern long GetRandomDebug(char* FILE_MACRO, long LINE_MACRO)
- {
- // Get next random number
- long lNewVal = (((m_lRandom = m_lRandom * 214013L + 2531011L) >> 16) & 0x7fff);
- if (m_pfileRandom)
- {
- if (m_bWriteLogs)
- {
- fprintf(
- m_pfileRandom->m_fs,
- "%s : %ld rand = %ld\n",
- GetFileNameFromPath(FILE_MACRO),
- LINE_MACRO,
- lNewVal);
- // m_pfileRandom->Write(lNewVal);
- // m_pfileRandom->Write(LINE_MACRO);
- // m_pfileRandom->Write(FILE_MACRO);
- }
- else
- {
- long lSavedVal;
- long lSavedLine;
- char szSavedFile[1024];
- fscanf(
- m_pfileRandom->m_fs,
- "%s : %ld rand = %ld\n",
- szSavedFile,
- &lSavedLine,
- &lSavedVal);
- // m_pfileRandom->Read(&lSavedVal);
- // m_pfileRandom->Read(&lSavedLine);
- // m_pfileRandom->Read(szSavedFile);
- if ((lSavedVal != lNewVal) || (lSavedLine != LINE_MACRO) || (rspStricmp(szSavedFile, GetFileNameFromPath(FILE_MACRO) ) != 0))
- {
- rspMsgBox(
- RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
- "Postal",
- "Random number sequence mismatch!\n\n"
- " Was %s(%ld) which got %ld\n\n"
- " Now %s(%ld) which got %ld",
- szSavedFile,
- (long)lSavedLine,
- (long)lSavedVal,
- GetFileNameFromPath(FILE_MACRO),
- LINE_MACRO,
- (long)lNewVal);
- // Make this easy to debug
- ASSERT(0);
- }
- }
- }
- return lNewVal;
- }
- #else
- extern long GetRandom(void)
- {
- // Get next random number
- return (((m_lRandom = m_lRandom * 214013L + 2531011L) >> 16) & 0x7fff);
- }
- #endif // defined(_DEBUG) || defined(TRACENASSERT).
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Define a rand() to take the place of the stdlib version. We don't want
- // anyone calling that version!
- //
- ////////////////////////////////////////////////////////////////////////////////
- // It seems that this only works in debug mode. In release, the linker
- // generates a fatal "multiple definitions of rand()" error. For now, only
- // do this in debug mode.
- #ifdef _DEBUG
- #ifndef PLATFORM_UNIX
- extern int rand(void)
- {
- rspMsgBox(
- RSP_MB_ICN_INFO | RSP_MB_BUT_OK,
- "Postal",
- "The stdlib version of rand() was called. It is forbidden within this application.");
- return 0;
- }
- #endif
- #endif
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Do palette transition so menu can be displayed on top of existing background.
- // NOTE: There must be a matching PalTranOff() for each PalTranOn()!!!
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void PalTranOn(
- long lTime /* = -1 */) // In: How long transition should take (or -1 for default)
- {
- if (lTime == -1)
- lTime = NORMAL_PAL_TRAN_TIME;
- StartMenuTrans(lTime);
- // Do until done or keypress.
- while (DoPreMenuTrans() == false)
- UpdateSystem();
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Undo the palette transition to restore the original background colors.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void PalTranOff(void)
- {
- // Do until done
- while (DoPostMenuTrans() == false)
- UpdateSystem();
- // Let paltran finish/clean up.
- EndMenuTrans(true);
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Set gamma/brighten-effect value. Note that there is no value that results
- // in identity. See Brightness / contrast below:
- // RIGHT NOW THIS FUNCTION IS BEING USED TO CALL BRIGHTNESS CONTRAST:
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void SetGammaLevel( // Returns nothing.
- short sBase) // New brighten value.
- {
- // For the time being, use this to control the other function:
- // Pick a contrast based on the chosen brightness.
- double dBrightness = double(sBase)/128.0 - 1.0;
- // Allow a larger range:
- dBrightness *= 2.0;
- // This was no clip
- //double dContrast = MIN(1.0 - dBrightness, dBrightness + 1.0);
- // Let's link contrast with brightness and clip:
- double dContrast = (dBrightness + 1.0); // needs to be a value of 1 to be neutral
- // With this scheme, contrast can never be more than +1.0 or less than 0.0
- SetBrightnessContrast(dBrightness,dContrast);
- // Update settings.
- g_GameSettings.m_sGammaVal = sBase;
- return; // don't set gamma for now
- U8 au8RedMap[256];
- U8 au8GreenMap[256];
- U8 au8BlueMap[256];
- short i;
- short sClipVal;
- for ( i = 0;
- i < 256;
- i++)
- {
- sClipVal = MAX((short)0, MIN(short(pow((double)i / 100.0, GAMMA_EXPONENT) * sBase), (short)255));
- au8RedMap[i] = (U8)sClipVal;
- au8GreenMap[i] = (U8)sClipVal;
- au8BlueMap[i] = (U8)sClipVal;
- }
- // Update map.
- rspSetPaletteMaps(
- 0,
- 256,
- au8RedMap,
- au8GreenMap,
- au8BlueMap,
- sizeof(U8));
- // Update hardware through new map.
- rspUpdatePalette();
- // Update settings.
- g_GameSettings.m_sGammaVal = sBase;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Set Brightness and Contrast. Zero (neutral) values yield and identity
- // curve. Valid input is from -1 to 1.
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern void SetBrightnessContrast(
- double dBrightness, // -1.0 = dim, 0.0 = normal, 1.0 = bright
- double dContrast // -1.0 = low contrast, 0.0 = normal, 1.0 = high
- )
- {
- U8 au8RedMap[256];
- U8 au8GreenMap[256];
- U8 au8BlueMap[256];
- // I will scale the ranges to within reasonable limits:
- ASSERT( (dBrightness >= -1.0) || (dBrightness <= 1.0));
- //ASSERT( (dContrast >= -1.0) || (dContrast <= 1.0));
- //dContrast = dContrast + 1.0; // this IS the tangent value (0-2)
- short i;
- double dScale = 1.0/128.0;
- for (i=0;i < 256; i++)
- {
- double dX = dScale * i - 1.0;
- short sLev = short(128.0 + 128.0 * (
- ( ( ( ((1.0 - dContrast) * dX) - dBrightness) * dX) + dContrast) * dX
- + dBrightness));
- if (sLev < 0) sLev = 0;
- if (sLev > 255) sLev = 255;
- au8RedMap[i] = (U8)sLev;
- au8GreenMap[i] = (U8)sLev;
- au8BlueMap[i] = (U8)sLev;
- }
- // Update map.
- rspSetPaletteMaps(
- 0,
- 256,
- au8RedMap,
- au8GreenMap,
- au8BlueMap,
- sizeof(U8));
- // Update hardware through new map.
- rspUpdatePalette();
- //----------------------------------
- // set postal levels?
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Get gamma/brighten-effect value from palette map (not from settings).
- //
- ////////////////////////////////////////////////////////////////////////////////
- extern short GetGammaLevel(void) // Returns current brighten value.
- {
- return g_GameSettings.m_sGammaVal;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Create a full path out of a partial path.
- //
- // The partial path must be in "RSPiX neutral" format, which is pretty much
- // like a partial Windows path, except with slashes instead of backslashes.
- //
- // BEWARE: The return value is a pointer to a static string, which means its
- // contents are changed every time this function is called! If you're just
- // going to use the string and then be done with it, this should work fine, but
- // if you need the string to stick around a while, you should probably do a
- // strcpy() into your own string buffer.
- //
- // There are several variations - pick the one you like best.
- //
- ////////////////////////////////////////////////////////////////////////////////
- // This string is much larger than it needs to be in case the string
- // size changes as a result of the conversion to system format, in which
- // case our tests would miss it until it's too late. A massive overrun
- // will still cause a problem, but that would never happen :)
- static char m_acFullPath[RSP_MAX_PATH + RSP_MAX_PATH];
- extern char* FullPath( // Returns full path in system format
- short sPathType, // In: PATH_CD, PATH_HD, or PATH_VD
- char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with the specified base path (copy the string from the game settings)
- if (sPathType == GAME_PATH_CD)
- return FullPathCD(pszPartialPath);
- else if (sPathType == GAME_PATH_HD)
- return FullPathHD(pszPartialPath);
- else if (sPathType == GAME_PATH_VD)
- return FullPathVD(pszPartialPath);
- else if (sPathType == GAME_PATH_SOUND)
- return FullPathSound(pszPartialPath);
- else if (sPathType == GAME_PATH_GAME)
- return FullPathGame(pszPartialPath);
- else if (sPathType == GAME_PATH_HOODS)
- return FullPathHoods(pszPartialPath);
- else
- {
- TRACE("FullPath(): Unknown path type: %d -- I predict an ASSERT() will occur soon...\n", (short)sPathType);
- ASSERT(1);
- // In case they want to ignore the assert, just return a pointer to an empty string
- m_acFullPath[0] = 0;
- return m_acFullPath;
- }
- }
- extern char* FullPathCD( // Returns full path in system format
- char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with proper base path
- ASSERT(strlen(g_GameSettings.m_pszCDPath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, g_GameSettings.m_pszCDPath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- extern char* FullPathHD( // Returns full path in system format
- const char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with proper base path
- ASSERT(strlen(g_GameSettings.m_pszHDPath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, g_GameSettings.m_pszHDPath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- extern char* FullPathVD( // Returns full path in system format
- char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with proper base path
- ASSERT(strlen(g_GameSettings.m_pszVDPath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, g_GameSettings.m_pszVDPath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- extern char* FullPathSound( // Returns full path in system format
- char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with proper base path
- ASSERT(strlen(g_GameSettings.m_pszSoundPath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, g_GameSettings.m_pszSoundPath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- extern char* FullPathGame( // Returns full path in system format
- char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with proper base path
- ASSERT(strlen(g_GameSettings.m_pszGamePath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, g_GameSettings.m_pszGamePath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- extern char* FullPathHoods( // Returns full path in system format
- char* pszPartialPath) // In: Partial path in RSPiX format
- {
- // Start with proper base path
- ASSERT(strlen(g_GameSettings.m_pszHoodsPath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, g_GameSettings.m_pszHoodsPath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- extern char* FullPathCustom( // Returns full path in system format
- char* pszFullPath, // In: Full path in in RSPiX format.
- char* pszPartialPath) // In: Partial path in RSPiX format.
- {
- char* pszFullSystemPath = rspPathToSystem(pszFullPath);
- // Start with proper base path
- ASSERT(strlen(pszFullSystemPath) < RSP_MAX_PATH);
- strcpy(m_acFullPath, pszFullSystemPath);
- // Make sure partial path isn't too long. It is possible that the conversion
- // to the system format will change its length slightly, but it shouldn't be
- // enough to make a real difference to this test.
- ASSERT(strlen(pszPartialPath) < RSP_MAX_PATH);
- // Check if the combination of the partial and base path will be too long.
- ASSERT((strlen(pszPartialPath) + strlen(m_acFullPath)) < RSP_MAX_PATH);
- // Convert specified partial path from rspix to system format, putting the
- // result immediately following the base path
- rspPathToSystem(pszPartialPath, m_acFullPath + strlen(m_acFullPath));
- // Make sure result isn't too long (our buffer can handle it, but it's still a problem)
- ASSERT(strlen(m_acFullPath) < RSP_MAX_PATH);
- // Return pointer to full path
- return m_acFullPath;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Correctify the specified base path.
- //
- // First, it ensures that the path is absolute (not relative). Then, it ensures
- // the path ends properly, either with or without the system-specific separator
- // character, depending on which system we're running on.
- //
- ////////////////////////////////////////////////////////////////////////////////
- short CorrectifyBasePath( // Returns 0 if successfull, non-zero otherwise
- char* pszBasePath, // I/O: Base path to be corrected
- short sMaxPathLen) // In: Maximum length of base path
- {
- short sResult = 0;
- // Make sure they aren't passing an empty string, which should be be left alone
- if (strlen(pszBasePath) > 0)
- {
- // Make sure they aren't passing a string that's already too large!
- if ((strlen(pszBasePath) + 1) <= sMaxPathLen)
- {
- //------------------------------------------------------------------------------
- // Convert path from relative to absolute. We do this by setting the current
- // directory to the specified path and then asking for the current directory,
- // which is always returned as an absolute path. If the path is already
- // absolute to begin with, it *should* be unchanged as a result.
- //------------------------------------------------------------------------------
- // Get original directory (let it allocate buffer of at LEAST specified size, more if needed)
-
- // 09/05/97, PPL
- // Apparently, the getcwd function works completely (well, maybe not completely) different
- // on the MAC. We need to go ahead and allocate our own buffer and free it later because
- // if a NULL is passed in, a NULL is returned. This should not have any adverse effects
- // on the PC version.
- //char* pszOrigDir = getcwd(NULL, RSP_MAX_PATH);
- char* pszOrigDir = (char*)malloc(RSP_MAX_PATH);
- if (pszOrigDir != NULL)
- {
- // Let's go ahead and get the current working directory here, once we're sure that
- // the string to store it has been properly allocated.
- pszOrigDir = getcwd(pszOrigDir, RSP_MAX_PATH);
- // Change to specified directory, which may be relative or absolute
- if (chdir(pszBasePath) == 0)
- {
- // Get directory, which is always returned as absolute
- if (getcwd(pszBasePath, sMaxPathLen) == NULL)
- {
- sResult = -1;
- TRACE("CorrectifyBasePath(): Couldn't get current directory (was set to '%s')!\n", pszBasePath);
- }
- }
- else
- {
- sResult = -1;
- TRACE("CorrectifyBasePath(): Couldn't change to specified directory: '%s'!\n", pszBasePath);
- }
- // Restore original directory
- if (chdir(pszOrigDir) != 0)
- {
- sResult = -1;
- TRACE("CorrectifyBasePath(): Couldn't restore original directory: '%s'!\n", pszOrigDir);
- }
- // Free buffer that was allocated by getcwd()
- free(pszOrigDir);
- pszOrigDir = 0;
- }
- //------------------------------------------------------------------------------
- // Ensure that path ends properly, either with or without the system-specific
- // separator character, depending on which system we're on.
- //------------------------------------------------------------------------------
- if (sResult == 0)
- {
- // Get index to last character
- short sLastIndex = strlen(pszBasePath);
- if (sLastIndex > 0)
- sLastIndex--;
- #if 1 //def WIN32
- // If base path doesn't end with a slash, add one
- if (pszBasePath[sLastIndex] != RSP_SYSTEM_PATH_SEPARATOR)
- {
- if ((sLastIndex + 2) < RSP_MAX_PATH)
- {
- pszBasePath[sLastIndex+1] = RSP_SYSTEM_PATH_SEPARATOR;
- pszBasePath[sLastIndex+2] = 0;
- }
- else
- {
- sResult = -1;
- TRACE("CorrectifyBasePath(): Path would've exceed max length with separator tacked on!\n");
- }
- }
- #else
- // If base path ends with a colon, get rid of it
- if (pszBasePath[sLastIndex] == RSP_SYSTEM_PATH_SEPARATOR)
- pszBasePath[sLastIndex] = 0;
- #endif
- }
- }
- else
- {
- sResult = -1;
- TRACE("CorrectifyBasePath(): Specified path is already longer than the specified maximum length!\n");
- }
- }
- return sResult;
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Notification that we are about to be in the background.
- //
- ////////////////////////////////////////////////////////////////////////////////
- static void BackgroundCall(void)
- {
- // TRACE("Background\n");
- // Return CPU to OS.
- rspSetDoSystemMode(RSP_DOSYSTEM_SLEEP);
- // If cursor show level not already stored . . .
- if (ms_sForegroundCursorShowLevel == INVALID_CURSOR_SHOW_LEVEL)
- {
- // Store current cursor show level and then make cursor visible
- ms_sForegroundCursorShowLevel = rspGetMouseCursorShowLevel();
- rspSetMouseCursorShowLevel(1);
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Notification that we are about to be in the foreground.
- //
- ////////////////////////////////////////////////////////////////////////////////
- static void ForegroundCall(void)
- {
- // TRACE("Foreground\n");
- #if defined(_DEBUG)
- // Wake CPU.
- rspSetDoSystemMode(RSP_DOSYSTEM_TOLERATEOS);
- #else
- // Return CPU to us.
- rspSetDoSystemMode(RSP_DOSYSTEM_HOGCPU);
- #endif
- // If cursor show level stored . . .
- if (ms_sForegroundCursorShowLevel != INVALID_CURSOR_SHOW_LEVEL)
- {
- // Restore previous cursor show level
- rspSetMouseCursorShowLevel(ms_sForegroundCursorShowLevel);
- ms_sForegroundCursorShowLevel = 0;
- // Reset the input.
- ClearLocalInput();
- // Flag that we're no longer storing the show level.
- ms_sForegroundCursorShowLevel = INVALID_CURSOR_SHOW_LEVEL;
- }
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Returns difficulty for games.
- // Note that this function is only valid once after a difficulty adjustment
- // and then it goes back to the default (g_GameSettings value).
- ////////////////////////////////////////////////////////////////////////////////
- static short GetGameDifficulty(void) // Returns cached game difficulty.
- {
- short sDifficulty = g_GameSettings.m_sDifficulty;
- // If there is a cached difficulty . . .
- if (ms_sLoadedDifficulty != INVALID_DIFFICULTY)
- {
- // Return cached difficulty.
- sDifficulty = ms_sLoadedDifficulty;
- // Clear cache.
- ms_sLoadedDifficulty = INVALID_DIFFICULTY;
- }
- return sDifficulty;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // EOF
- ////////////////////////////////////////////////////////////////////////////////
|