GameLogic.cpp 154 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: GameLogic.cpp ////////////////////////////////////////////////////////////////////////////
  24. // GameLogic class implementation
  25. // Author: Michael S. Booth, October 2000
  26. ///////////////////////////////////////////////////////////////////////////////////////////////////
  27. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  28. #include "Common/AudioAffect.h"
  29. #include "Common/AudioHandleSpecialValues.h"
  30. #include "Common/BuildAssistant.h"
  31. #include "Common/CopyProtection.h"
  32. #include "Common/CRCDebug.h"
  33. #include "Common/GameAudio.h"
  34. #include "Common/GameEngine.h"
  35. #include "Common/GameLOD.h"
  36. #include "Common/GameState.h"
  37. #include "Common/INI.h"
  38. #include "Common/LatchRestore.h"
  39. #include "Common/MapObject.h"
  40. #include "Common/MultiplayerSettings.h"
  41. #include "Common/PerfTimer.h"
  42. #include "Common/Player.h"
  43. #include "Common/PlayerList.h"
  44. #include "Common/PlayerTemplate.h"
  45. #include "Common/Radar.h"
  46. #include "Common/RandomValue.h"
  47. #include "Common/Recorder.h"
  48. #include "Common/StatsCollector.h"
  49. #include "Common/ThingFactory.h"
  50. #include "Common/Team.h"
  51. #include "Common/ThingTemplate.h"
  52. #include "GameClient/Water.h"
  53. #include "GameClient/Snow.h"
  54. #include "Common/WellKnownKeys.h"
  55. #include "Common/Xfer.h"
  56. #include "Common/XferCRC.h"
  57. #include "Common/XferDeepCRC.h"
  58. #include "Common/GameSpyMiscPreferences.h"
  59. #include "GameClient/ControlBar.h"
  60. #include "GameClient/Drawable.h"
  61. #include "GameClient/GameClient.h"
  62. #include "GameClient/GameText.h"
  63. #include "GameClient/GUICallbacks.h"
  64. #include "GameClient/InGameUI.h"
  65. #include "GameClient/LoadScreen.h"
  66. #include "GameClient/MapUtil.h"
  67. #include "GameClient/Mouse.h"
  68. #include "GameClient/ParticleSys.h"
  69. #include "GameClient/TerrainVisual.h"
  70. #include "GameClient/View.h"
  71. #include "GameClient/ControlBar.h"
  72. #include "GameClient/CampaignManager.h"
  73. #include "GameClient/GameWindowTransitions.h"
  74. #include "GameLogic/AI.h"
  75. #include "GameLogic/AIPathfind.h"
  76. #include "GameLogic/CaveSystem.h"
  77. #include "GameLogic/CrateSystem.h"
  78. #include "GameLogic/FPUControl.h"
  79. #include "GameLogic/GameLogic.h"
  80. #include "GameLogic/Locomotor.h"
  81. #include "GameLogic/Object.h"
  82. #include "GameLogic/Module/AIUpdate.h"
  83. #include "GameLogic/Module/BodyModule.h"
  84. #include "GameLogic/Module/CreateModule.h"
  85. #include "GameLogic/Module/DestroyModule.h"
  86. #include "GameLogic/Module/OpenContain.h"
  87. #include "GameLogic/PartitionManager.h"
  88. #include "GameLogic/PolygonTrigger.h"
  89. #include "GameLogic/ScriptActions.h"
  90. #include "GameLogic/ScriptConditions.h"
  91. #include "GameLogic/ScriptEngine.h"
  92. #include "GameLogic/SidesList.h"
  93. #include "GameLogic/VictoryConditions.h"
  94. #include "GameLogic/Weapon.h"
  95. #include "GameLogic/GhostObject.h"
  96. #include "Common/DataChunk.h"
  97. #include "GameLogic/Scripts.h"
  98. #include "GameNetwork/GameSpy/BuddyThread.h"
  99. #include "GameNetwork/GameSpy/PeerDefs.h"
  100. #include "GameNetwork/GameSpy/ThreadUtils.h"
  101. #include "GameNetwork/LANAPICallbacks.h"
  102. #include "GameNetwork/NetworkInterface.h"
  103. #include "GameNetwork/GameSpy/PersistentStorageThread.h"
  104. #include <rts/profile.h>
  105. DECLARE_PERF_TIMER(SleepyMaintenance)
  106. #include "Common/UnitTimings.h" //Contains the DO_UNIT_TIMINGS define jba.
  107. // If defined, the game times various units.
  108. #ifdef DO_UNIT_TIMINGS
  109. #pragma MESSAGE("*** WARNING *** DOING DO_UNIT_TIMINGS!!!!")
  110. Bool g_UT_gotUnit = false;
  111. const ThingTemplate *g_UT_curThing = NULL;
  112. Bool g_UT_startTiming = false;
  113. FILE *g_UT_timingLog=NULL;
  114. FILE *g_UT_commaLog=NULL;
  115. // Note - this is only for gathering timing data! DO NOT DO THIS IN REGULAR CODE!!! JBA
  116. #define BRUTAL_TIMING_HACK
  117. #include "../../gameenginedevice/include/W3DDevice/GameClient/Module/W3DModelDraw.h"
  118. extern void externalAddTree(Coord3D location, Real scale, Real angle, AsciiString name);
  119. #endif
  120. #ifdef _INTERNAL
  121. // for occasional debugging...
  122. //#pragma optimize("", off)
  123. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  124. #endif
  125. // I'm making this larger now that we know how big our maps are going to be.
  126. enum { OBJ_HASH_SIZE = 8192 };
  127. /// The GameLogic singleton instance
  128. GameLogic *TheGameLogic = NULL;
  129. static void findAndSelectCommandCenter(Object *obj, void* alreadyFound);
  130. // ------------------------------------------------------------------------------------------------
  131. /** This enum is for loading screen bar progress */
  132. // ------------------------------------------------------------------------------------------------
  133. enum
  134. {
  135. LOAD_PROGRESS_START =0,
  136. LOAD_PROGRESS_POST_PARTICLE_INI_LOAD = LOAD_PROGRESS_START + 1,
  137. LOAD_PROGRESS_POST_LOAD_MAP = LOAD_PROGRESS_POST_PARTICLE_INI_LOAD + 1,
  138. LOAD_PROGRESS_SIDE_POPULATION = LOAD_PROGRESS_POST_LOAD_MAP + 1, // Increment the next one by at least MAX_SLOTS
  139. LOAD_PROGRESS_POST_SIDE_LIST_INIT = LOAD_PROGRESS_SIDE_POPULATION + 1 + MAX_SLOTS,
  140. LOAD_PROGRESS_POST_PLAYER_LIST_RESET = LOAD_PROGRESS_POST_SIDE_LIST_INIT + 1,
  141. LOAD_PROGRESS_POST_SCRIPT_ENGINE_NEW_MAP = LOAD_PROGRESS_POST_PLAYER_LIST_RESET + 1,
  142. LOAD_PROGRESS_POST_VICTORY_CONDITION_SETUP = LOAD_PROGRESS_POST_SCRIPT_ENGINE_NEW_MAP + 2,
  143. LOAD_PROGRESS_POST_VICTORY_CONDITION_SET_VICTORY_CONDITION = LOAD_PROGRESS_POST_VICTORY_CONDITION_SETUP + 1,
  144. LOAD_PROGRESS_POST_GHOST_OBJECT_MANAGER_RESET = LOAD_PROGRESS_POST_VICTORY_CONDITION_SET_VICTORY_CONDITION + 1,
  145. LOAD_PROGRESS_POST_TERRAIN_LOGIC_NEW_MAP = LOAD_PROGRESS_POST_GHOST_OBJECT_MANAGER_RESET + 1,
  146. LOAD_PROGRESS_POST_BRIDGE_LOAD = LOAD_PROGRESS_POST_TERRAIN_LOGIC_NEW_MAP + 1,
  147. LOAD_PROGRESS_POST_PATHFINDER_NEW_MAP = LOAD_PROGRESS_POST_BRIDGE_LOAD + 1,
  148. LOAD_PROGRESS_LOOP_ALL_THE_FREAKN_OBJECTS = LOAD_PROGRESS_POST_BRIDGE_LOAD + 1,
  149. LOAD_PROGRESS_MAX_ALL_THE_FREAKN_OBJECTS = 80,// THE END OF THE BIG ASS PROGRESS PAUSE
  150. LOAD_PROGRESS_LOOP_INITIAL_NETWORK_BUILDINGS = LOAD_PROGRESS_MAX_ALL_THE_FREAKN_OBJECTS + 1, // Increment the next one by at least MAX_SLOTS
  151. LOAD_PROGRESS_POST_INITIAL_NETWORK_BUILDINGS = LOAD_PROGRESS_LOOP_INITIAL_NETWORK_BUILDINGS + MAX_SLOTS + 1,
  152. LOAD_PROGRESS_POST_PRELOAD_ASSETS = LOAD_PROGRESS_POST_INITIAL_NETWORK_BUILDINGS + 1,
  153. LOAD_PROGRESS_POST_STARTING_CAMERA = LOAD_PROGRESS_POST_PRELOAD_ASSETS + 1,
  154. LOAD_PROGRESS_POST_STARTING_CAMERA_2 = LOAD_PROGRESS_POST_STARTING_CAMERA + 1,
  155. LOAD_PROGRESS_END = 100,
  156. };
  157. // ------------------------------------------------------------------------------------------------
  158. // ------------------------------------------------------------------------------------------------
  159. static Waypoint * findNamedWaypoint(AsciiString name)
  160. {
  161. for (Waypoint *way = TheTerrainLogic->getFirstWaypoint(); way; way = way->getNext())
  162. {
  163. if (way->getName() == name)
  164. {
  165. return way;
  166. }
  167. }
  168. return NULL;
  169. }
  170. // ------------------------------------------------------------------------------------------------
  171. // ------------------------------------------------------------------------------------------------
  172. void setFPMode( void )
  173. {
  174. // Set floating point round mode to CHOP, which only comes
  175. // into play when precision is exceeded. This is necessary
  176. // for the fast float to int routines used elsewhere in the
  177. // system.
  178. //
  179. // Also set floating point precision to low. It could be
  180. // anything as long as it is consistent, really, but this
  181. // is in the (vain?) hope of any slight speed boost.
  182. //
  183. _fpreset();
  184. UnsignedInt curVal = _statusfp();
  185. UnsignedInt newVal = curVal;
  186. newVal = (newVal & ~_MCW_RC) | (_RC_NEAR & _MCW_RC);
  187. //newVal = (newVal & ~_MCW_RC) | (_RC_CHOP & _MCW_RC);
  188. newVal = (newVal & ~_MCW_PC) | (_PC_24 & _MCW_PC);
  189. _controlfp(newVal, _MCW_PC | _MCW_RC);
  190. }
  191. // ------------------------------------------------------------------------------------------------
  192. /** GameLogic class constructor */
  193. // ------------------------------------------------------------------------------------------------
  194. GameLogic::GameLogic( void )
  195. {
  196. //Added By Sadullah Nader
  197. //Initializations missing and necessary
  198. m_background = NULL;
  199. m_CRC = 0;
  200. m_isInUpdate = FALSE;
  201. m_rankPointsToAddAtGameStart = 0;
  202. for(Int i = 0; i < MAX_SLOTS; i++)
  203. {
  204. m_progressComplete[i] = FALSE;
  205. m_progressCompleteTimeout[i] = 0;
  206. }
  207. m_shouldValidateCRCs = FALSE;
  208. m_startNewGame = FALSE;
  209. //
  210. m_frame = 0;
  211. m_frameObjectsChangedTriggerAreas = 0;
  212. m_width = 0;
  213. m_height = 0;
  214. m_objList = NULL;
  215. m_curUpdateModule = NULL;
  216. m_nextObjID = INVALID_ID;
  217. m_startNewGame = FALSE;
  218. m_gameMode = GAME_NONE;
  219. m_rankLevelLimit = 1000;
  220. m_gamePaused = FALSE;
  221. m_inputEnabledMemory = TRUE;
  222. m_mouseVisibleMemory = TRUE;
  223. m_loadScreen = NULL;
  224. m_forceGameStartByTimeOut = FALSE;
  225. #ifdef DUMP_PERF_STATS
  226. m_overallFailedPathfinds = 0;
  227. #endif
  228. m_loadingMap = FALSE;
  229. m_loadingSave = FALSE;
  230. m_clearingGameData = FALSE;
  231. }
  232. // ------------------------------------------------------------------------------------------------
  233. /** Utility function to set class variables to default values. */
  234. // ------------------------------------------------------------------------------------------------
  235. void GameLogic::setDefaults( Bool loadingSaveGame )
  236. {
  237. m_frame = 0;
  238. m_width = DEFAULT_WORLD_WIDTH;
  239. m_height = DEFAULT_WORLD_HEIGHT;
  240. m_objList = NULL;
  241. #ifdef ALLOW_NONSLEEPY_UPDATES
  242. m_normalUpdates.clear();
  243. #endif
  244. for (std::vector<UpdateModulePtr>::iterator it = m_sleepyUpdates.begin(); it != m_sleepyUpdates.end(); ++it)
  245. {
  246. (*it)->friend_setIndexInLogic(-1);
  247. }
  248. m_sleepyUpdates.clear();
  249. m_curUpdateModule = NULL;
  250. //
  251. // only reset the next object ID allocater counter when we're not loading a save game.
  252. // for save games, we read this value out of the save game file and it is important
  253. // that we preserve it as we load and execute the game
  254. //
  255. if( loadingSaveGame == FALSE )
  256. m_nextObjID = (ObjectID)1;
  257. }
  258. //-------------------------------------------------------------------------------------------------
  259. //-------------------------------------------------------------------------------------------------
  260. Bool GameLogic::isInSinglePlayerGame( void )
  261. {
  262. return (m_gameMode == GAME_SINGLE_PLAYER ||
  263. (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_PLAYBACK && TheRecorder->getGameMode() == GAME_SINGLE_PLAYER));
  264. }
  265. //-------------------------------------------------------------------------------------------------
  266. /** Destroy all objects immediately */
  267. //-------------------------------------------------------------------------------------------------
  268. void GameLogic::destroyAllObjectsImmediate()
  269. {
  270. // destroy all remaining objects
  271. Object *obj;
  272. Object *nextObj;
  273. for( obj = m_objList; obj; obj = nextObj )
  274. {
  275. nextObj = obj->getNextObject();
  276. destroyObject( obj );
  277. }
  278. // process the destroy list immediately
  279. processDestroyList();
  280. DEBUG_ASSERTCRASH( m_objList == NULL, ("destroyAllObjectsImmediate: Object list not cleared\n") );
  281. } // end destroyAllObjectsImmediate
  282. //-------------------------------------------------------------------------------------------------
  283. /**GameLogic class destructor, the destruction order should mirror the
  284. * initialization order */
  285. // ------------------------------------------------------------------------------------------------
  286. GameLogic::~GameLogic()
  287. {
  288. // clear any object TOC we might have
  289. m_objectTOC.clear();
  290. if (m_background)
  291. {
  292. m_background->destroyWindows();
  293. m_background->deleteInstance();
  294. m_background = NULL;
  295. }
  296. // destroy all remaining objects
  297. destroyAllObjectsImmediate();
  298. // delete the logical terrain
  299. delete TheTerrainLogic;
  300. TheTerrainLogic = NULL;
  301. delete TheGhostObjectManager;
  302. TheGhostObjectManager=NULL;
  303. // delete the partition manager
  304. delete ThePartitionManager;
  305. ThePartitionManager = NULL;
  306. delete TheScriptActions;
  307. TheScriptActions = NULL;
  308. delete TheScriptConditions;
  309. TheScriptConditions = NULL;
  310. // delete the Script Engine
  311. delete TheScriptEngine;
  312. TheScriptEngine = NULL;
  313. // Null out TheGameLogic
  314. TheGameLogic = NULL;
  315. }
  316. // ------------------------------------------------------------------------------------------------
  317. /** (re)initialize the instance. */
  318. // ------------------------------------------------------------------------------------------------
  319. void GameLogic::init( void )
  320. {
  321. setFPMode();
  322. /// @todo Clear object and destroy lists
  323. setDefaults( FALSE );
  324. // create the partition manager
  325. ThePartitionManager = NEW PartitionManager;
  326. ThePartitionManager->init();
  327. ThePartitionManager->setName("ThePartitionManager");
  328. // Create system for holding deleted objects that are
  329. // still in the partition manager because player has a fogged
  330. // view of them.
  331. TheGhostObjectManager = createGhostObjectManager();
  332. // create the terrain logic
  333. TheTerrainLogic = createTerrainLogic();
  334. TheTerrainLogic->init();
  335. TheTerrainLogic->setName("TheTerrainLogic");
  336. // Create script engine system.
  337. TheScriptActions = NEW ScriptActions; // Basically, a subsystem of TheScriptEngine.
  338. TheScriptConditions = NEW ScriptConditions; // Basically, a subsystem of TheScriptEngine.
  339. TheScriptEngine = NEW ScriptEngine;
  340. TheScriptEngine->init();
  341. TheScriptEngine->setName("TheScriptEngine");
  342. // create a team for the player
  343. //DEBUG_ASSERTCRASH(ThePlayerList, ("null ThePlayerList"));
  344. //ThePlayerList->setLocalPlayer(0);
  345. m_CRC = 0;
  346. m_gamePaused = FALSE;
  347. m_inputEnabledMemory = TRUE;
  348. m_mouseVisibleMemory = TRUE;
  349. for(Int i = 0; i < MAX_SLOTS; ++i)
  350. {
  351. m_progressComplete[i] = FALSE;
  352. m_progressCompleteTimeout[i] = 0;
  353. }
  354. m_forceGameStartByTimeOut = FALSE;
  355. m_isScoringEnabled = TRUE;
  356. m_showBehindBuildingMarkers = TRUE;
  357. m_drawIconUI = TRUE;
  358. m_showDynamicLOD = TRUE;
  359. m_scriptHulkMaxLifetimeOverride = -1;
  360. m_isInUpdate = FALSE;
  361. m_rankPointsToAddAtGameStart = 0;
  362. }
  363. //-------------------------------------------------------------------------------------------------
  364. /** Reset the game logic systems */
  365. //-------------------------------------------------------------------------------------------------
  366. void GameLogic::reset( void )
  367. {
  368. m_thingTemplateBuildableOverrides.clear();
  369. m_controlBarOverrides.clear();
  370. // set the hash to be rather large. We need to optimize this value later.
  371. // m_objHash.clear();
  372. // m_objHash.resize(OBJ_HASH_SIZE);
  373. m_objVector.clear();
  374. m_objVector.resize(OBJ_HASH_SIZE, NULL);
  375. m_gamePaused = FALSE;
  376. m_inputEnabledMemory = TRUE;
  377. m_mouseVisibleMemory = TRUE;
  378. setFPMode();
  379. // destroy all objects
  380. destroyAllObjectsImmediate();
  381. m_nextObjID = (ObjectID)1;
  382. m_frameObjectsChangedTriggerAreas = 0;
  383. TheGhostObjectManager->reset();
  384. ThePartitionManager->reset();
  385. TheTerrainLogic->reset();
  386. TheAI->reset();
  387. TheScriptEngine->reset();
  388. m_CRC = 0;
  389. for(Int i = 0; i < MAX_SLOTS; ++i)
  390. {
  391. m_progressComplete[i] = FALSE;
  392. m_progressCompleteTimeout[i] = 0;
  393. }
  394. m_forceGameStartByTimeOut = FALSE;
  395. if(TheStatsCollector)
  396. {
  397. delete TheStatsCollector;
  398. TheStatsCollector = NULL;
  399. }
  400. // clear any table of contents we have
  401. m_objectTOC.clear();
  402. setDefaults( FALSE );
  403. m_isScoringEnabled = TRUE;
  404. m_showBehindBuildingMarkers = TRUE;
  405. m_drawIconUI = TRUE;
  406. m_showDynamicLOD = TRUE;
  407. m_scriptHulkMaxLifetimeOverride = -1;
  408. // Clean up any water transparency overrides that were generated for this map.
  409. WaterTransparencySetting *wt = (WaterTransparencySetting*) TheWaterTransparency.getNonOverloadedPointer();
  410. TheWaterTransparency = (WaterTransparencySetting*) wt->deleteOverrides();
  411. // Clean up any weather overrides that were generated for this map.
  412. WeatherSetting *ws = (WeatherSetting*) TheWeatherSetting.getNonOverloadedPointer();
  413. TheWeatherSetting = (WeatherSetting*) ws->deleteOverrides();
  414. m_rankPointsToAddAtGameStart = 0;
  415. } // end reset
  416. static Object * placeObjectAtPosition(Int slotNum, AsciiString objectTemplateName, Coord3D& pos, Player *pPlayer,
  417. const PlayerTemplate *pTemplate)
  418. {
  419. const ThingTemplate* btt = TheThingFactory->findTemplate(objectTemplateName);
  420. DEBUG_ASSERTCRASH(btt, ("TheThingFactory didn't find a template in placeObjectAtPosition()") );
  421. Object *obj = TheThingFactory->newObject( btt, pPlayer->getDefaultTeam() );
  422. DEBUG_ASSERTCRASH(obj, ("TheThingFactory didn't give me a valid Object for player %d's (%ls) starting building\n",
  423. slotNum, pTemplate->getDisplayName().str()));
  424. if (obj)
  425. {
  426. obj->setOrientation(obj->getTemplate()->getPlacementViewAngle());
  427. obj->setPosition( &pos );
  428. //DEBUG_LOG(("Placed a starting building for %s at waypoint %s\n", playerName.str(), waypointName.str()));
  429. CRCDEBUG_LOG(("Placed an object for %ls at pos (%g,%g,%g)\n", pPlayer->getPlayerDisplayName().str(),
  430. pos.x, pos.y, pos.z));
  431. DUMPCOORD3D(&pos);
  432. Team *team = pPlayer->getDefaultTeam();
  433. // Now onCreates were called at the constructor. This magically created
  434. // thing needs to be considered as Built for Game specific stuff.
  435. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  436. {
  437. CreateModuleInterface* create = (*m)->getCreate();
  438. if (!create)
  439. continue;
  440. create->onBuildComplete();
  441. }
  442. // Since the team now has members, activate it.
  443. // srj sez: team should not be null, but could be for ill-formed user maps. so don't crash.
  444. if (team)
  445. team->setActive();
  446. TheAI->pathfinder()->addObjectToPathfindMap(obj);
  447. if (obj->getAIUpdateInterface() && !obj->isKindOf(KINDOF_IMMOBILE)) {
  448. CRCDEBUG_LOG(("Not immobile - adjusting dest\n"));
  449. if (TheAI->pathfinder()->adjustDestination(obj, obj->getAIUpdateInterface()->getLocomotorSet(), &pos)) {
  450. DUMPCOORD3D(&pos);
  451. TheAI->pathfinder()->updateGoal(obj, &pos, LAYER_GROUND); // Units always start on the ground for now. jba.
  452. obj->setPosition( &pos );
  453. }
  454. }
  455. }
  456. return obj;
  457. }
  458. static void placeNetworkBuildingsForPlayer(Int slotNum, const GameSlot *pSlot, Player *pPlayer, const PlayerTemplate *pTemplate)
  459. {
  460. Int startPos = pSlot->getStartPos();
  461. AsciiString waypointName;
  462. waypointName.format("Player_%d_Start", startPos+1); // start pos waypoints are 1-based
  463. AsciiString rallyWaypointName;
  464. rallyWaypointName.format("Player_%d_Rally", startPos+1); // start pos waypoints are 1-based
  465. Waypoint *waypoint = findNamedWaypoint(waypointName);
  466. Waypoint *rallyWaypoint = findNamedWaypoint(rallyWaypointName);
  467. DEBUG_ASSERTCRASH(waypoint, ("Player %d has no starting waypoint (Player_%d_Start)\n", slotNum, startPos));
  468. if (!waypoint)
  469. return;
  470. Coord3D pos = *waypoint->getLocation();
  471. pos.z = TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  472. AsciiString buildingTemplateName = pTemplate->getStartingBuilding();
  473. DEBUG_ASSERTCRASH(!buildingTemplateName.isEmpty(), ("no starting building type for player %d (playertemplate %ls)\n",
  474. slotNum, pTemplate->getDisplayName().str()));
  475. if (buildingTemplateName.isEmpty())
  476. return;
  477. DEBUG_LOG(("Placing starting building at waypoint %s\n", waypointName.str()));
  478. Object *conYard = placeObjectAtPosition(slotNum, buildingTemplateName, pos, pPlayer, pTemplate);
  479. if (!conYard)
  480. return;
  481. pPlayer->onStructureCreated(NULL, conYard);
  482. pPlayer->onStructureConstructionComplete(NULL, conYard, FALSE);
  483. //pos.x -= conYard->getGeometryInfo().getBoundingSphereRadius()/2;
  484. pos.y -= conYard->getGeometryInfo().getBoundingSphereRadius()/2;
  485. pos.z = TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  486. if (rallyWaypoint)
  487. {
  488. pos = *rallyWaypoint->getLocation();
  489. pos.z = TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  490. }
  491. for (Int i=0; i<MAX_MP_STARTING_UNITS; ++i)
  492. {
  493. AsciiString objName = pTemplate->getStartingUnit(i);
  494. if (objName.isNotEmpty())
  495. {
  496. Coord3D objPos = pos;
  497. FindPositionOptions options;
  498. options.minRadius = conYard->getGeometryInfo().getBoundingSphereRadius() * 0.7f;
  499. options.maxRadius = conYard->getGeometryInfo().getBoundingSphereRadius() * 1.3f;
  500. DEBUG_LOG(("Placing starting object %d (%s)\n", i, objName.str()));
  501. ThePartitionManager->update();
  502. Bool foundPos = ThePartitionManager->findPositionAround(&pos, &options, &objPos);
  503. if (foundPos)
  504. {
  505. Object *unit = placeObjectAtPosition(slotNum, objName, objPos, pPlayer, pTemplate);
  506. if (unit) {
  507. pPlayer->onUnitCreated(NULL, unit);
  508. }
  509. }
  510. else
  511. {
  512. DEBUG_LOG(("Could not find position\n"));
  513. }
  514. }
  515. }
  516. }
  517. // ------------------------------------------------------------------------------------------------
  518. // ------------------------------------------------------------------------------------------------
  519. LoadScreen *GameLogic::getLoadScreen( Bool loadingSaveGame )
  520. {
  521. switch (m_gameMode)
  522. {
  523. case GAME_SHELL:
  524. return NEW ShellGameLoadScreen;
  525. break;
  526. case GAME_SINGLE_PLAYER:
  527. {
  528. Campaign* currentCampaign = TheCampaignManager->getCurrentCampaign();
  529. if( currentCampaign && loadingSaveGame == FALSE )
  530. {
  531. if ( currentCampaign->m_isChallengeCampaign)
  532. {
  533. return NEW ChallengeLoadScreen;
  534. }
  535. return NEW SinglePlayerLoadScreen;
  536. }
  537. else
  538. return NEW ShellGameLoadScreen;
  539. break;
  540. }
  541. case GAME_SKIRMISH:
  542. return NEW MultiPlayerLoadScreen;
  543. break;
  544. case GAME_LAN:
  545. return NEW MultiPlayerLoadScreen;
  546. break;
  547. case GAME_REPLAY:
  548. return NEW ShellGameLoadScreen;
  549. break;
  550. case GAME_INTERNET:
  551. return NEW GameSpyLoadScreen;
  552. break;
  553. case GAME_NONE:
  554. default:
  555. return NULL;
  556. }
  557. }
  558. // ------------------------------------------------------------------------------------------------
  559. // ------------------------------------------------------------------------------------------------
  560. void handleNameChange( MapObject *mapObj )
  561. {
  562. if( !mapObj->getName().compare( "AmericaTankLeopard" ) )
  563. {
  564. mapObj->setName( "AmericaTankCrusader" );
  565. const ThingTemplate *thingTemplate = TheThingFactory->findTemplate( mapObj->getName() );
  566. mapObj->setThingTemplate( thingTemplate );
  567. }
  568. if( !mapObj->getName().compare( "AmericaVehicleHumVee" ) )
  569. {
  570. mapObj->setName( "AmericaVehicleHumvee" );
  571. const ThingTemplate *thingTemplate = TheThingFactory->findTemplate( mapObj->getName() );
  572. mapObj->setThingTemplate( thingTemplate );
  573. }
  574. }
  575. // ------------------------------------------------------------------------------------------------
  576. // ------------------------------------------------------------------------------------------------
  577. static void checkForDuplicateColors( GameInfo *game )
  578. {
  579. if(!game)
  580. return;
  581. Int i;
  582. // In QuickMatch, people can possibly set preferred color and house.
  583. // Here, we check for collisions in the color choice. If there is a
  584. // collision, the first player will get the color, and the other(s)
  585. // will map to random.
  586. for (i=MAX_SLOTS-1; i>=0; --i)
  587. {
  588. GameSlot *slot = game->getSlot(i);
  589. if (!slot || !slot->isOccupied())
  590. continue;
  591. Int colorIdx = slot->getColor();
  592. if (colorIdx < 0 || colorIdx >= TheMultiplayerSettings->getNumColors())
  593. continue; // don't need to fix up random ones
  594. slot->setColor(-1);
  595. if (!game->isColorTaken(colorIdx))
  596. {
  597. // we were the only one using the color. it is safe to keep using it.
  598. slot->setColor(colorIdx);
  599. }
  600. else if (colorIdx >= 0)
  601. {
  602. DEBUG_LOG(("Clearing color %d for player %d\n", colorIdx, i));
  603. }
  604. }
  605. }
  606. // ------------------------------------------------------------------------------------------------
  607. // ------------------------------------------------------------------------------------------------
  608. static void populateRandomSideAndColor( GameInfo *game )
  609. {
  610. if(!game)
  611. return;
  612. Int i;
  613. #define MORE_RANDOM
  614. #ifdef MORE_RANDOM
  615. std::vector<Int> startSlots;
  616. for (i = 0; i < ThePlayerTemplateStore->getPlayerTemplateCount(); ++i)
  617. {
  618. const PlayerTemplate* ptTest = ThePlayerTemplateStore->getNthPlayerTemplate(i);
  619. if (!ptTest || ptTest->getStartingBuilding().isEmpty())
  620. continue;
  621. if ( game->oldFactionsOnly() && !ptTest->isOldFaction() )
  622. continue;
  623. // Prevent from selecting the disabled Generals.
  624. // This is also enforced at GUI setup (GUIUtil.cpp).
  625. // @todo: unlock these when something rad happens
  626. Bool disallowLockedGenerals = TRUE;
  627. const GeneralPersona *general = TheChallengeGenerals->getGeneralByTemplateName(ptTest->getName());
  628. Bool startsLocked = general ? !general->isStartingEnabled() : FALSE;
  629. if (disallowLockedGenerals && startsLocked)
  630. continue;
  631. startSlots.push_back(i);
  632. }
  633. #endif
  634. for (i=0; i<MAX_SLOTS; ++i)
  635. {
  636. GameSlot *slot = game->getSlot(i);
  637. if (!slot || !slot->isOccupied())
  638. continue;
  639. // clean up random factions
  640. Int playerTemplateIdx = slot->getPlayerTemplate();
  641. DEBUG_LOG(("Player %d has playerTemplate index %d\n", i, playerTemplateIdx));
  642. while (playerTemplateIdx != PLAYERTEMPLATE_OBSERVER && (playerTemplateIdx < 0 || playerTemplateIdx >= ThePlayerTemplateStore->getPlayerTemplateCount()))
  643. {
  644. DEBUG_ASSERTCRASH(playerTemplateIdx == PLAYERTEMPLATE_RANDOM, ("Non-random bad playerTemplate %d in slot %d\n", playerTemplateIdx, i));
  645. #ifdef MORE_RANDOM
  646. // our RNG is basically shit -- horribly nonrandom at the start of the sequence.
  647. // get a few values at random to get rid of the dreck.
  648. // there's no mathematical basis for this, but empirically, it helps a lot.
  649. UnsignedInt silly = GetGameLogicRandomSeed() % 7;
  650. for (Int poo = 0; poo < silly; ++poo)
  651. {
  652. GameLogicRandomValue(0, 1); // ignore result
  653. }
  654. Int idxIdx = GameLogicRandomValue(0, 1000) % startSlots.size();
  655. playerTemplateIdx = startSlots[idxIdx];
  656. #else
  657. playerTemplateIdx = GameLogicRandomValue(0, ThePlayerTemplateStore->getPlayerTemplateCount()-1);
  658. #endif
  659. const PlayerTemplate* pt = ThePlayerTemplateStore->getNthPlayerTemplate(playerTemplateIdx);
  660. if (!pt || pt->getStartingBuilding().isEmpty())
  661. {
  662. #ifdef MORE_RANDOM
  663. DEBUG_CRASH(("should not be possible"));
  664. #endif
  665. playerTemplateIdx = -1; // only pick playable factions
  666. }
  667. else
  668. {
  669. DEBUG_LOG(("Setting playerTemplateIdx %d to %d\n", i, playerTemplateIdx));
  670. slot->setPlayerTemplate(playerTemplateIdx);
  671. }
  672. }
  673. Int colorIdx = slot->getColor();
  674. if (colorIdx < 0 || colorIdx >= TheMultiplayerSettings->getNumColors())
  675. {
  676. DEBUG_ASSERTCRASH(colorIdx == -1, ("Non-random bad color %d in slot %d\n", colorIdx, i));
  677. while (colorIdx == -1)
  678. {
  679. colorIdx = GameLogicRandomValue(0, TheMultiplayerSettings->getNumColors()-1);
  680. if (game->isColorTaken(colorIdx))
  681. colorIdx = -1;
  682. }
  683. DEBUG_LOG(("Setting color %d to %d\n", i, colorIdx));
  684. slot->setColor(colorIdx);
  685. }
  686. }
  687. }
  688. // ------------------------------------------------------------------------------------------------
  689. // ------------------------------------------------------------------------------------------------
  690. static void populateRandomStartPosition( GameInfo *game )
  691. {
  692. if(!game)
  693. return;
  694. Int i;
  695. Int numPlayers = MAX_SLOTS;
  696. const MapMetaData *md = TheMapCache->findMap( game->getMap() );
  697. DEBUG_ASSERTCRASH( md , ("Could not find map %s in the mapcache", game->getMap().str()));
  698. if (md)
  699. numPlayers = md->m_numPlayers;
  700. // generate a map of start spot distances
  701. Real startSpotDistance[MAX_SLOTS][MAX_SLOTS];
  702. for (i=0; i<MAX_SLOTS; ++i)
  703. {
  704. for (Int j=0; j<MAX_SLOTS; ++j)
  705. {
  706. if (i != j && (i<numPlayers && j<numPlayers))
  707. {
  708. AsciiString w1, w2;
  709. w1.format("Player_%d_Start", i+1);
  710. w2.format("Player_%d_Start", j+1);
  711. WaypointMap::const_iterator c1 = md->m_waypoints.find(w1);
  712. WaypointMap::const_iterator c2 = md->m_waypoints.find(w2);
  713. if (c1 == md->m_waypoints.end() || c2 == md->m_waypoints.end())
  714. {
  715. // couldn't find a waypoint. must be kinda far away.
  716. startSpotDistance[i][j] = 1000000.0f;
  717. }
  718. else
  719. {
  720. Coord3D p1 = c1->second;
  721. Coord3D p2 = c2->second;
  722. startSpotDistance[i][j] = sqrt( sqr(p1.x-p2.x) + sqr(p1.y-p2.y) );
  723. }
  724. }
  725. else
  726. {
  727. startSpotDistance[i][j] = 0.0f; // not gonna need this
  728. }
  729. }
  730. }
  731. // see if a start spot has been chosen at all yet
  732. Bool hasStartSpotBeenPicked = FALSE;
  733. Bool taken[MAX_SLOTS];
  734. for (i=0; i<MAX_SLOTS; ++i)
  735. {
  736. taken[i] = (i<numPlayers)?FALSE:TRUE;
  737. }
  738. for (i=0; i<MAX_SLOTS; ++i)
  739. {
  740. GameSlot *slot = game->getSlot(i);
  741. if (!slot || !slot->isOccupied() || slot->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER)
  742. continue;
  743. Int posIdx = slot->getStartPos();
  744. if (posIdx >= 0 || posIdx >= numPlayers)
  745. {
  746. hasStartSpotBeenPicked = TRUE;
  747. taken[posIdx] = TRUE;
  748. }
  749. }
  750. #if 0 //GS The old way puts everyone as far apart as possible.
  751. // now pick non-observer spots
  752. for (i=0; i<MAX_SLOTS; ++i)
  753. {
  754. GameSlot *slot = game->getSlot(i);
  755. if (!slot || !slot->isOccupied() || slot->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER)
  756. continue;
  757. // clean up random start spots
  758. Int posIdx = slot->getStartPos();
  759. if (posIdx < 0 || posIdx >= numPlayers)
  760. {
  761. DEBUG_ASSERTCRASH(posIdx == -1, ("Non-random bad start position %d in slot %d\n", posIdx, i));
  762. if (hasStartSpotBeenPicked)
  763. {
  764. // pick the farthest spot away
  765. Real farthestDistance = 0.0f;
  766. Int farthestIndex = -1;
  767. for (posIdx = 0; posIdx < numPlayers; ++posIdx)
  768. {
  769. if (!taken[posIdx])
  770. {
  771. if (farthestIndex < 0)
  772. {
  773. farthestIndex = posIdx; // take this one as best if none else
  774. for (Int n=0; n<numPlayers; ++n)
  775. {
  776. if (taken[n] && n != posIdx)
  777. farthestDistance += startSpotDistance[posIdx][n];
  778. }
  779. }
  780. else
  781. {
  782. Real dist = 0.0f;
  783. for (Int n=0; n<numPlayers; ++n)
  784. {
  785. if (taken[n] && n != posIdx)
  786. dist += startSpotDistance[posIdx][n];
  787. }
  788. if (dist > farthestDistance)
  789. {
  790. farthestDistance = dist;
  791. farthestIndex = posIdx;
  792. }
  793. }
  794. }
  795. }
  796. DEBUG_ASSERTCRASH(farthestIndex >= 0, ("Couldn't find a farthest spot!\n"));
  797. slot->setStartPos(farthestIndex);
  798. taken[farthestIndex] = TRUE;
  799. }
  800. else
  801. {
  802. // We're the first real spot. Pick randomly.
  803. // This while loop shouldn't be neccessary, since we're first. Why not, though?
  804. while (posIdx == -1)
  805. {
  806. posIdx = GameLogicRandomValue(0, numPlayers-1);
  807. if (game->isStartPositionTaken(posIdx))
  808. posIdx = -1;
  809. }
  810. DEBUG_LOG(("Setting start position %d to %d (random choice)\n", i, posIdx));
  811. slot->setStartPos(posIdx);
  812. taken[posIdx] = TRUE;
  813. hasStartSpotBeenPicked = TRUE;
  814. }
  815. }
  816. }
  817. #else //GS The new way puts teammates next to each other.
  818. Int teamPosIdx[MAX_SLOTS];
  819. for (i=0; i<MAX_SLOTS; ++i)
  820. teamPosIdx[i] = -1; //team has no starting position yet
  821. // now pick non-observer spots
  822. for (i=0; i<MAX_SLOTS; ++i)
  823. {
  824. GameSlot *slot = game->getSlot(i);
  825. if (!slot || !slot->isOccupied() || slot->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER)
  826. continue; //slot not used
  827. Int posIdx = slot->getStartPos();
  828. if (posIdx >= 0 && posIdx < numPlayers)
  829. continue; //position already assigned
  830. DEBUG_ASSERTCRASH(posIdx == -1, ("Non-random bad start position %d in slot %d\n", posIdx, i));
  831. //choose a starting position
  832. Int team = slot->getTeamNumber();
  833. if( !hasStartSpotBeenPicked )
  834. { // We're the first real spot. Pick randomly.
  835. while (posIdx == -1)
  836. { // This while loop shouldn't be neccessary, since we're first. Why not, though?
  837. posIdx = GameLogicRandomValue(0, numPlayers-1);
  838. if (game->isStartPositionTaken(posIdx))
  839. posIdx = -1;
  840. }
  841. DEBUG_LOG(("Setting start position %d to %d (random choice)\n", i, posIdx));
  842. hasStartSpotBeenPicked = TRUE;
  843. slot->setStartPos(posIdx);
  844. taken[posIdx] = TRUE;
  845. if( team > -1 )
  846. teamPosIdx[team] = posIdx; //remember where this team is
  847. } else
  848. { //pick teams far apart, team members close together
  849. if( team < 0 || teamPosIdx[ team ] == -1 ) //if team None or team not yet placed
  850. { //pick position furthest from all other teams
  851. Real farthestDistance = 0.0f;
  852. Int farthestIndex = -1;
  853. for (posIdx = 0; posIdx < numPlayers; ++posIdx)
  854. {
  855. if (taken[posIdx])
  856. continue; //skip occupied positions
  857. if (farthestIndex < 0)
  858. { //take this one as best if none else
  859. farthestIndex = posIdx;
  860. for (Int n=0; n<numPlayers; ++n)
  861. {
  862. if (taken[n] && n != posIdx)
  863. farthestDistance += startSpotDistance[posIdx][n];
  864. }
  865. }
  866. else
  867. { //find empty position furthest from all taken positions
  868. Real dist = 0.0f;
  869. for (Int n=0; n<numPlayers; ++n)
  870. {
  871. if (taken[n] && n != posIdx)
  872. dist += startSpotDistance[posIdx][n];
  873. }
  874. if (dist > farthestDistance)
  875. {
  876. farthestDistance = dist;
  877. farthestIndex = posIdx;
  878. }
  879. }
  880. } //for posInx
  881. DEBUG_ASSERTCRASH(farthestIndex >= 0, ("Couldn't find a farthest spot!\n"));
  882. slot->setStartPos(farthestIndex);
  883. taken[farthestIndex] = TRUE;
  884. if( team > -1 )
  885. teamPosIdx[team] = farthestIndex; //remember where this team is
  886. } //pick farthest
  887. else //team already has a starting position
  888. { //pick position closest to team
  889. Real closestDist = FLT_MAX;
  890. Int closestIdx = 0;
  891. for( Int n=0; n < numPlayers; ++n )
  892. {
  893. Real dist = startSpotDistance[ teamPosIdx[team] ][n];
  894. if( !taken[n] && dist < closestDist )
  895. { //found a better match
  896. closestDist = dist;
  897. closestIdx = n;
  898. }
  899. } //for n
  900. DEBUG_ASSERTCRASH( closestDist < FLT_MAX, ("Couldn't find a closest starting positon!\n"));
  901. slot->setStartPos(closestIdx);
  902. taken[closestIdx] = TRUE;
  903. }
  904. }
  905. } //for i
  906. #endif 0
  907. // now go back & assign observer spots
  908. Int numPlayersInGame = 0;
  909. for (i=0; i<MAX_SLOTS; ++i)
  910. {
  911. const GameSlot *slot = game->getConstSlot(i);
  912. if (slot->isOccupied() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  913. ++numPlayersInGame;
  914. }
  915. for (i=0; i<MAX_SLOTS; ++i)
  916. {
  917. GameSlot *slot = game->getSlot(i);
  918. if (!slot || !slot->isOccupied())
  919. continue;
  920. if (slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  921. continue;
  922. // clean up random start spots
  923. Int posIdx = -1;
  924. if (numPlayersInGame == 0)
  925. posIdx = 0;
  926. while (posIdx == -1)
  927. {
  928. posIdx = GameLogicRandomValue(0, numPlayers-1);
  929. if (!game->isStartPositionTaken(posIdx))
  930. posIdx = -1;
  931. }
  932. DEBUG_LOG(("Setting observer start position %d to %d\n", i, posIdx));
  933. slot->setStartPos(posIdx);
  934. }
  935. }
  936. // ------------------------------------------------------------------------------------------------
  937. /** Update the load screen progress */
  938. // ------------------------------------------------------------------------------------------------
  939. void GameLogic::updateLoadProgress( Int progress )
  940. {
  941. if( m_loadScreen )
  942. m_loadScreen->update( progress );
  943. } // end updateLoadProgress
  944. // ------------------------------------------------------------------------------------------------
  945. /** Delete the load screen */
  946. // ------------------------------------------------------------------------------------------------
  947. void GameLogic::deleteLoadScreen( void )
  948. {
  949. if( m_loadScreen )
  950. {
  951. delete m_loadScreen;
  952. m_loadScreen = NULL;
  953. } // end if
  954. } // end deleteLoadScreen
  955. // ------------------------------------------------------------------------------------------------
  956. /** Entry point for starting a new game, the engine is already in clean state at this
  957. * point and ready to load up with all the data */
  958. // ------------------------------------------------------------------------------------------------
  959. void GameLogic::startNewGame( Bool loadingSaveGame )
  960. {
  961. #ifdef DUMP_PERF_STATS
  962. __int64 startTime64;
  963. __int64 endTime64,freq64;
  964. GetPrecisionTimerTicksPerSec(&freq64);
  965. GetPrecisionTimer(&startTime64);
  966. #endif
  967. setLoadingMap( TRUE );
  968. if( loadingSaveGame == FALSE )
  969. {
  970. // record pristine map name when we're loading from the map (not a save game)
  971. TheGameState->setPristineMapName( TheGlobalData->m_mapName );
  972. //
  973. // sanity, the pristine map should never start with "Save", otherwise that would be
  974. // a map from the save directory
  975. //
  976. if (TheGameState->isInSaveDirectory(TheGlobalData->m_mapName))
  977. {
  978. DEBUG_CRASH(( "FATAL SAVE/LOAD ERROR! - Setting a pristine map name that refers to a map in the save directory. The pristine map should always refer to the ORIGINAL map in the Maps directory, if the pristine map string is corrupt then map.ini files will not load correctly.\n" ));
  979. } // end if
  980. if( m_startNewGame == FALSE )
  981. {
  982. /// @todo: Here is where we would look at the game mode & play an intro movie or something.
  983. // Failing that, we just set the flag so the actual game can start from a uniform
  984. // entry point (startNewGame() called from update()).
  985. if( m_gameMode == GAME_SINGLE_PLAYER )
  986. {
  987. if(m_background)
  988. {
  989. m_background->destroyWindows();
  990. m_background->deleteInstance();
  991. m_background = NULL;
  992. }
  993. m_loadScreen = getLoadScreen( loadingSaveGame );
  994. if(m_loadScreen)
  995. {
  996. TheWritableGlobalData->m_loadScreenRender = TRUE; ///< mark it so only a few select things are rendered during load
  997. m_loadScreen->init(NULL);
  998. }
  999. }
  1000. m_startNewGame = TRUE;
  1001. return;
  1002. }
  1003. } // end if
  1004. m_rankLevelLimit = 1000; // this is reset every game.
  1005. setDefaults( loadingSaveGame );
  1006. TheWritableGlobalData->m_loadScreenRender = TRUE; ///< mark it so only a few select things are rendered during load
  1007. TheWritableGlobalData->m_TiVOFastMode = FALSE; //always disable the TIVO fast-forward mode at the start of a new game.
  1008. m_showBehindBuildingMarkers = TRUE;
  1009. m_drawIconUI = TRUE;
  1010. m_showDynamicLOD = TRUE;
  1011. m_scriptHulkMaxLifetimeOverride = -1;
  1012. Campaign* currentCampaign = TheCampaignManager->getCurrentCampaign();
  1013. Bool isChallengeCampaign = m_gameMode == GAME_SINGLE_PLAYER && currentCampaign && currentCampaign->m_isChallengeCampaign;
  1014. // Fill in the game color and Factions before we do the Load Screen
  1015. GameInfo *game = NULL;
  1016. TheGameInfo = NULL;
  1017. Int localSlot = 0;
  1018. if (TheNetwork)
  1019. {
  1020. if (TheLAN)
  1021. {
  1022. DEBUG_LOG(("Starting network game\n"));
  1023. TheGameInfo = game = TheLAN->GetMyGame();
  1024. }
  1025. else
  1026. {
  1027. DEBUG_LOG(("Starting gamespy game\n"));
  1028. TheGameInfo = game = TheGameSpyGame; /// @todo: MDC add back in after demo
  1029. }
  1030. }
  1031. else
  1032. {
  1033. if (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_PLAYBACK)
  1034. {
  1035. TheGameInfo = game = TheRecorder->getGameInfo();
  1036. }
  1037. else if(m_gameMode == GAME_SKIRMISH)
  1038. {
  1039. TheGameInfo = game = TheSkirmishGameInfo;
  1040. }
  1041. else if(isChallengeCampaign)
  1042. {
  1043. TheGameInfo = game = TheChallengeGameInfo;
  1044. }
  1045. }
  1046. // On a NEW game, we need to copy the superweapon restrictions from the game info to here
  1047. // (because TheGameInfo is not always saved and doesn't carry over to replays). On a save
  1048. // game, we save the superweapon restrictions in GameLogic::xfer()
  1049. if ( !loadingSaveGame )
  1050. {
  1051. if ( TheGameInfo )
  1052. {
  1053. m_superweaponRestriction = TheGameInfo->getSuperweaponRestriction();
  1054. }
  1055. else
  1056. {
  1057. // ??? Apparently this is legit? Oh well, use defaults
  1058. m_superweaponRestriction = 0;
  1059. }
  1060. }
  1061. checkForDuplicateColors( game );
  1062. Bool isSkirmishOrSkirmishReplay = FALSE;
  1063. if (game)
  1064. {
  1065. for (Int i=0; i<MAX_SLOTS; ++i)
  1066. {
  1067. GameSlot *slot = game->getSlot(i);
  1068. if (!loadingSaveGame) {
  1069. slot->saveOffOriginalInfo();
  1070. }
  1071. if (slot->isAI())
  1072. {
  1073. isSkirmishOrSkirmishReplay = TRUE;
  1074. continue;
  1075. }
  1076. }
  1077. } else {
  1078. if (m_gameMode == GAME_SINGLE_PLAYER) {
  1079. if (TheSkirmishGameInfo) {
  1080. delete TheSkirmishGameInfo;
  1081. TheSkirmishGameInfo = NULL;
  1082. }
  1083. }
  1084. }
  1085. populateRandomSideAndColor( game );
  1086. populateRandomStartPosition( game );
  1087. //****************************//
  1088. // Start the LoadScreen Now! //
  1089. //****************************//
  1090. // Get the m_loadScreen for this kind of game
  1091. if(!m_loadScreen)
  1092. {
  1093. m_loadScreen = getLoadScreen( loadingSaveGame );
  1094. if(m_loadScreen)
  1095. {
  1096. TheMouse->setVisibility(FALSE);
  1097. m_loadScreen->init(game);
  1098. //
  1099. updateLoadProgress( LOAD_PROGRESS_START );
  1100. }
  1101. }
  1102. if(m_background)
  1103. {
  1104. m_background->destroyWindows();
  1105. m_background->deleteInstance();
  1106. m_background = NULL;
  1107. }
  1108. setFPMode();
  1109. if(TheCampaignManager)
  1110. TheCampaignManager->SetVictorious(FALSE);
  1111. m_startNewGame = FALSE;
  1112. // update the loadscreen
  1113. if(m_loadScreen)
  1114. updateLoadProgress(LOAD_PROGRESS_POST_PARTICLE_INI_LOAD);
  1115. // reset the frame counter
  1116. m_frame = 0;
  1117. // before loading the map, load the map.ini file in the same directory.
  1118. loadMapINI( TheGlobalData->m_mapName );
  1119. // load a map
  1120. TheTerrainLogic->loadMap( TheGlobalData->m_mapName, false );
  1121. // anytime the world's size changes, must reset the partition mgr
  1122. //ThePartitionManager->init();
  1123. // update the loadscreen
  1124. updateLoadProgress(LOAD_PROGRESS_POST_LOAD_MAP);
  1125. #ifdef DUMP_PERF_STATS
  1126. GetPrecisionTimer(&endTime64);
  1127. char Buf[256];
  1128. sprintf(Buf,"After terrainlogic->loadmap=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  1129. //DEBUG_LOG(("Placed a starting building for %s at waypoint %s\n", playerName.str(), waypointName.str()));
  1130. DEBUG_LOG(("%s", Buf));
  1131. #endif
  1132. Int progressCount = LOAD_PROGRESS_SIDE_POPULATION;
  1133. if (game)
  1134. {
  1135. if (TheGameEngine->isMultiplayerSession() || isSkirmishOrSkirmishReplay)
  1136. {
  1137. // Saves off any player, and resets the sides to 0 players so we can add the skirmish players.
  1138. TheSidesList->prepareForMP_or_Skirmish();
  1139. }
  1140. //DEBUG_LOG(("Starting LAN game with %d players\n", game->getNumPlayers()));
  1141. Dict d;
  1142. for (int i=0; i<MAX_SLOTS; ++i)
  1143. {
  1144. // Add a Side to TheSidesList
  1145. GameSlot *slot = game->getSlot(i);
  1146. if (!slot || !slot->isHuman())
  1147. {
  1148. m_progressComplete[i] = TRUE;
  1149. lastHeardFrom(i);
  1150. }
  1151. if (!slot || !slot->isOccupied())
  1152. continue;
  1153. d.clear();
  1154. AsciiString playerName;
  1155. playerName.format("player%d", i);
  1156. d.setAsciiString(TheKey_playerName, playerName);
  1157. d.setBool(TheKey_playerIsHuman, slot->isHuman());
  1158. d.setUnicodeString(TheKey_playerDisplayName, slot->getName());
  1159. const PlayerTemplate* pt;
  1160. if (slot->getPlayerTemplate() >= 0)
  1161. pt = ThePlayerTemplateStore->getNthPlayerTemplate(slot->getPlayerTemplate());
  1162. else
  1163. pt = ThePlayerTemplateStore->findPlayerTemplate( TheNameKeyGenerator->nameToKey("FactionObserver") );
  1164. if (pt)
  1165. {
  1166. d.setAsciiString(TheKey_playerFaction, KEYNAME(pt->getNameKey()));
  1167. }
  1168. if (game->isPlayerPreorder(i))
  1169. {
  1170. d.setBool(TheKey_playerIsPreorder, TRUE);
  1171. }
  1172. AsciiString enemiesString, alliesString;
  1173. Int team = slot->getTeamNumber();
  1174. DEBUG_LOG(("Looking for allies of player %d, team %d\n", i, team));
  1175. for(int j=0; j < MAX_SLOTS; ++j)
  1176. {
  1177. GameSlot *teamSlot = game->getSlot(j);
  1178. // for check to see if we're trying to add ourselves
  1179. if(i == j || !teamSlot->isOccupied())
  1180. continue;
  1181. DEBUG_LOG(("Player %d is team %d\n", j, teamSlot->getTeamNumber()));
  1182. AsciiString teamPlayerName;
  1183. teamPlayerName.format("player%d", j);
  1184. // if our team is None, or our team is not equal to their team,
  1185. // then their our enemy
  1186. Bool isEnemy = FALSE;
  1187. if(team == -1 || teamSlot->getTeamNumber() != team ) isEnemy = TRUE;
  1188. DEBUG_LOG(("Player %d is %s\n", j, (isEnemy)?"enemy":"ally"));
  1189. if (isEnemy)
  1190. {
  1191. if(!enemiesString.isEmpty())
  1192. enemiesString.concat(" ");
  1193. enemiesString.concat(teamPlayerName);
  1194. }
  1195. else
  1196. {
  1197. // he's on our team, add him!
  1198. if(!alliesString.isEmpty())
  1199. alliesString.concat(" ");
  1200. alliesString.concat(teamPlayerName);
  1201. }
  1202. }
  1203. d.setAsciiString(TheKey_playerAllies, alliesString);
  1204. d.setAsciiString(TheKey_playerEnemies, enemiesString);
  1205. DEBUG_LOG(("Player %d's teams are: allies=%s, enemies=%s\n", i,alliesString.str(),enemiesString.str()));
  1206. /*
  1207. Int colorIdx = slot->getColor();
  1208. if (colorIdx < 0 || colorIdx >= TheMultiplayerSettings->getNumColors())
  1209. {
  1210. DEBUG_ASSERTCRASH(colorIdx == -1, ("Non-random bad color %d in slot %d\n", colorIdx, i));
  1211. while (colorIdx == -1)
  1212. {
  1213. colorIdx = GameLogicRandomValue(0, TheMultiplayerSettings->getNumColors()-1);
  1214. if (game->isColorTaken(colorIdx))
  1215. colorIdx = -1;
  1216. }
  1217. DEBUG_LOG(("Setting color %d to %d\n", i, colorIdx));
  1218. slot->setColor(colorIdx);
  1219. }
  1220. */
  1221. d.setInt(TheKey_playerColor, TheMultiplayerSettings->getColor(slot->getColor())->getColor());
  1222. d.setInt(TheKey_playerNightColor, TheMultiplayerSettings->getColor(slot->getColor())->getNightColor());
  1223. d.setInt(TheKey_multiplayerStartIndex, slot->getStartPos());
  1224. // d.setBool(TheKey_multiplayerIsLocal, slot->isLocalPlayer());
  1225. // d.setBool(TheKey_multiplayerIsLocal, slot->getIP() == game->getLocalIP());
  1226. d.setBool(TheKey_multiplayerIsLocal, slot->isHuman() && (slot->getName().compare(game->getSlot(game->getLocalSlotNum())->getName().str()) == 0));
  1227. /*
  1228. if (slot->getIP() == game->getLocalIP())
  1229. {
  1230. localSlot = i;
  1231. DEBUG_LOG(("GameLogic::StartNewGame - local slot is %d\n", localSlot));
  1232. }
  1233. */
  1234. if (isSkirmishOrSkirmishReplay)
  1235. {
  1236. d.setBool(TheKey_playerIsSkirmish, true);
  1237. switch (slot->getState()) {
  1238. case SLOT_EASY_AI : d.setInt(TheKey_skirmishDifficulty, DIFFICULTY_EASY); break;
  1239. case SLOT_MED_AI : d.setInt(TheKey_skirmishDifficulty, DIFFICULTY_NORMAL); break;
  1240. case SLOT_BRUTAL_AI : d.setInt(TheKey_skirmishDifficulty, DIFFICULTY_HARD); break;
  1241. default: break; // no setting.
  1242. }
  1243. }
  1244. AsciiString slotNameAscii;
  1245. slotNameAscii.translate(slot->getName());
  1246. if (slot->isHuman() && game->getSlotNum(slotNameAscii) == game->getLocalSlotNum()) {
  1247. localSlot = i;
  1248. }
  1249. TheSidesList->addSide(&d);
  1250. AsciiString playerTeamName;
  1251. playerTeamName.set("team");
  1252. playerTeamName.concat(playerName);
  1253. d.clear();
  1254. d.setAsciiString(TheKey_teamName, playerTeamName);
  1255. d.setAsciiString(TheKey_teamOwner, playerName);
  1256. d.setBool(TheKey_teamIsSingleton, true);
  1257. TheSidesList->addTeam(&d);
  1258. DEBUG_LOG(("Added side %d\n", i));
  1259. updateLoadProgress(progressCount + i);
  1260. }
  1261. }
  1262. //if(m_gameMode != GAME_REPLAY)
  1263. //{
  1264. // Always add in an observer Player
  1265. Dict d;
  1266. d.setAsciiString(TheKey_playerName, "ReplayObserver");
  1267. d.setBool(TheKey_playerIsHuman, TRUE);
  1268. d.setUnicodeString(TheKey_playerDisplayName, UnicodeString(L"Observer"));
  1269. const PlayerTemplate* pt;
  1270. pt = ThePlayerTemplateStore->findPlayerTemplate( TheNameKeyGenerator->nameToKey("FactionObserver") );
  1271. if (pt)
  1272. {
  1273. d.setAsciiString(TheKey_playerFaction, KEYNAME(pt->getNameKey()));
  1274. }
  1275. d.setAsciiString(TheKey_playerAllies, AsciiString::TheEmptyString);
  1276. d.setAsciiString(TheKey_playerEnemies, AsciiString::TheEmptyString);
  1277. d.setInt(TheKey_playerColor, TheMultiplayerSettings->getColor(0)->getColor());
  1278. d.setInt(TheKey_playerNightColor, TheMultiplayerSettings->getColor(0)->getNightColor());
  1279. d.setInt(TheKey_multiplayerStartIndex, 0);
  1280. d.setBool(TheKey_multiplayerIsLocal, FALSE);
  1281. TheSidesList->addSide(&d);
  1282. d.clear();
  1283. d.setAsciiString(TheKey_teamName, "teamReplayObserver");
  1284. d.setAsciiString(TheKey_teamOwner, "ReplayObserver");
  1285. d.setBool(TheKey_teamIsSingleton, true);
  1286. TheSidesList->addTeam(&d);
  1287. //}
  1288. TheSidesList->validateSides();
  1289. // update the loadscreen
  1290. updateLoadProgress(LOAD_PROGRESS_POST_SIDE_LIST_INIT);
  1291. // update the player list to match the new map.
  1292. TheTeamFactory->reset();
  1293. ThePlayerList->newGame();
  1294. // update the loadscreen
  1295. updateLoadProgress(LOAD_PROGRESS_POST_PLAYER_LIST_RESET);
  1296. // Tell the script engine that a newe set of scripts is loaded.
  1297. TheScriptEngine->newMap();
  1298. // update the loadscreen
  1299. updateLoadProgress(LOAD_PROGRESS_POST_SCRIPT_ENGINE_NEW_MAP);
  1300. if (TheGameEngine->isMultiplayerSession() || isSkirmishOrSkirmishReplay)
  1301. {
  1302. // if there are no other teams (happens for debugging) don't end the game immediately
  1303. Int numTeams = 0; // this can be higher than expected, but is accurate for determining 0, 1, 2+
  1304. Int lastTeam = -1;
  1305. if (game)
  1306. {
  1307. for (int i=0; i<MAX_SLOTS; ++i)
  1308. {
  1309. const GameSlot *slot = game->getConstSlot(i);
  1310. if (slot->isOccupied() && slot->getPlayerTemplate() != PLAYERTEMPLATE_OBSERVER)
  1311. {
  1312. if (slot->getTeamNumber() == -1 || slot->getTeamNumber() != lastTeam)
  1313. {
  1314. ++numTeams;
  1315. lastTeam = slot->getTeamNumber();
  1316. }
  1317. }
  1318. }
  1319. }
  1320. if (numTeams > 1)
  1321. {
  1322. // add in the multiplayer victory/defeat scripts
  1323. AsciiString path = "Data\\Scripts\\MultiplayerScripts.scb";
  1324. CachedFileInputStream theInputStream;
  1325. if (theInputStream.open(path))
  1326. {
  1327. ChunkInputStream *pStrm = &theInputStream;
  1328. DataChunkInput file( pStrm );
  1329. file.registerParser( AsciiString("PlayerScriptsList"), AsciiString::TheEmptyString, ScriptList::ParseScriptsDataChunk );
  1330. if (!file.parse(NULL)) {
  1331. DEBUG_LOG(("ERROR - Unable to read in multiplayer scripts.\n"));
  1332. return;
  1333. }
  1334. ScriptList *scripts[MAX_PLAYER_COUNT];
  1335. Int count = ScriptList::getReadScripts(scripts);
  1336. if (count)
  1337. {
  1338. ScriptList *pSL = TheSidesList->getSideInfo(0)->getScriptList();
  1339. Script *next = scripts[0]->getScript();
  1340. while (next)
  1341. {
  1342. Script *dupe = next->duplicate();
  1343. pSL->addScript(dupe, 0);
  1344. next = next->getNext();
  1345. }
  1346. }
  1347. for (Int i=0; i<count; ++i)
  1348. {
  1349. scripts[i]->deleteInstance();
  1350. }
  1351. }
  1352. }
  1353. /*
  1354. // add multiplayer single-player defeat script
  1355. if (numTeams > 1)
  1356. {
  1357. AsciiString name;
  1358. name.format("MultiplayerPlayerDefeat"); // name is for the ui in the editor
  1359. Script *pNewScript = newInstance(Script);
  1360. pNewScript->setName(name);
  1361. Condition *pFalse1 = newInstance(Condition)(Condition::MULTIPLAYER_PLAYER_DEFEAT);
  1362. OrCondition *pOr = newInstance(OrCondition);
  1363. pOr->setFirstAndCondition(pFalse1);
  1364. pNewScript->setOrCondition(pOr);
  1365. ScriptAction *action = newInstance(ScriptAction)(ScriptAction::LOCALDEFEAT);
  1366. pNewScript->setAction(action);
  1367. ScriptList *pSL = TheSidesList->getSideInfo(0)->getScriptList();
  1368. pSL->addScript(pNewScript, 0); // adds this as the player's first script (index 0)
  1369. }
  1370. // add multiplayer victory scripts
  1371. if (numTeams > 1)
  1372. {
  1373. AsciiString name;
  1374. name.format("MultiplayerVictory"); // name is for the ui in the editor
  1375. Script *pNewScript = newInstance( Script );
  1376. pNewScript->setName(name);
  1377. Condition *pFalse1 = newInstance(Condition)(Condition::MULTIPLAYER_ALLIED_VICTORY);
  1378. OrCondition *pOr = newInstance(OrCondition);
  1379. pOr->setFirstAndCondition(pFalse1);
  1380. pNewScript->setOrCondition(pOr);
  1381. ScriptAction *action = newInstance(ScriptAction)(ScriptAction::VICTORY);
  1382. pNewScript->setAction(action);
  1383. ScriptList *pSL = TheSidesList->getSideInfo(0)->getScriptList();
  1384. pSL->addScript(pNewScript, 0); // adds this as the player's first script (index 0)
  1385. }
  1386. // add multiplayer defeat scripts
  1387. if (numTeams > 1)
  1388. {
  1389. AsciiString name;
  1390. name.format("MultiplayerDefeat"); // name is for the ui in the editor
  1391. Script *pNewScript = newInstance(Script);
  1392. pNewScript->setName(name);
  1393. Condition *pFalse1 = newInstance(Condition)(Condition::MULTIPLAYER_ALLIED_DEFEAT);
  1394. OrCondition *pOr = newInstance(OrCondition);
  1395. pOr->setFirstAndCondition(pFalse1);
  1396. pNewScript->setOrCondition(pOr);
  1397. ScriptAction *action = newInstance(ScriptAction)(ScriptAction::DEFEAT);
  1398. pNewScript->setAction(action);
  1399. ScriptList *pSL = TheSidesList->getSideInfo(0)->getScriptList();
  1400. pSL->addScript(pNewScript, 0); // adds this as the player's first script (index 0)
  1401. }
  1402. */
  1403. }
  1404. // update the loadscreen
  1405. updateLoadProgress(LOAD_PROGRESS_POST_VICTORY_CONDITION_SETUP);
  1406. // set the radar as on a new map
  1407. TheRadar->newMap( TheTerrainLogic );
  1408. TheInGameUI->setClientQuiet( FALSE ); // okay to start beeping and stuff
  1409. // Tell the multiplayer victory condition singleton that the players are created
  1410. TheVictoryConditions->cachePlayerPtrs();
  1411. TheVictoryConditions->setVictoryConditions(VICTORY_NOBUILDINGS);
  1412. // update the loadscreen
  1413. updateLoadProgress(LOAD_PROGRESS_POST_VICTORY_CONDITION_SET_VICTORY_CONDITION);
  1414. // set the world extents to that of the map
  1415. Region3D extent;
  1416. TheTerrainLogic->getExtent( &extent );
  1417. TheGameLogic->setWidth( extent.hi.x - extent.lo.x );
  1418. TheGameLogic->setHeight( extent.hi.y - extent.lo.y );
  1419. // anytime the world's size changes, must reset the partition mgr
  1420. ThePartitionManager->init();
  1421. ThePartitionManager->refreshShroudForLocalPlayer();// Can't do this until after init, and doesn't seem right to do in init
  1422. TheGhostObjectManager->setLocalPlayerIndex(ThePlayerList->getLocalPlayer()->getPlayerIndex());
  1423. TheGhostObjectManager->reset();
  1424. // update the loadscreen
  1425. updateLoadProgress(LOAD_PROGRESS_POST_GHOST_OBJECT_MANAGER_RESET);
  1426. // update the terrain logic now that all is loaded
  1427. TheTerrainLogic->newMap( loadingSaveGame );
  1428. // update the loadscreen
  1429. updateLoadProgress(LOAD_PROGRESS_POST_TERRAIN_LOGIC_NEW_MAP);
  1430. #ifdef DUMP_PERF_STATS
  1431. GetPrecisionTimer(&endTime64);
  1432. sprintf(Buf,"After terrainlogic->newmap=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  1433. DEBUG_LOG(("%s", Buf));
  1434. #endif
  1435. // Special case, load any bridge map objects.
  1436. const ThingTemplate *thingTemplate;
  1437. MapObject *pMapObj;
  1438. for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext())
  1439. {
  1440. if (pMapObj->getFlag(FLAG_BRIDGE_FLAGS) || pMapObj->getFlag(FLAG_ROAD_FLAGS))
  1441. continue; // these roads & bridges are special cased in the terrain side.
  1442. // get thing template based from map object name
  1443. thingTemplate = pMapObj->getThingTemplate();
  1444. if( thingTemplate == NULL )
  1445. continue;
  1446. Bool isBridgeLikeObject = false;
  1447. if (thingTemplate->isBridge())
  1448. isBridgeLikeObject = true;
  1449. if (thingTemplate->isKindOf(KINDOF_WALK_ON_TOP_OF_WALL))
  1450. isBridgeLikeObject = true;
  1451. if (!isBridgeLikeObject)
  1452. continue;
  1453. Team *team = ThePlayerList->getNeutralPlayer()->getDefaultTeam();
  1454. // create new object in the world
  1455. Object *obj = TheThingFactory->newObject( thingTemplate, team ); //, OBJECT_STATUS_LOADING_FROM_MAP );
  1456. if( obj )
  1457. {
  1458. Coord3D pos = *pMapObj->getLocation();
  1459. pos.z += TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  1460. Real angle = normalizeAngle(pMapObj->getAngle());
  1461. obj->setOrientation(angle);
  1462. obj->setPosition( &pos );
  1463. if (thingTemplate->isBridge()) {
  1464. TheTerrainLogic->addLandmarkBridgeToLogic(obj);
  1465. }
  1466. if (thingTemplate->isKindOf(KINDOF_WALK_ON_TOP_OF_WALL)) {
  1467. TheAI->pathfinder()->addWallPiece(obj);
  1468. }
  1469. // Do this after positioning the object, because we may place objects in response to keys
  1470. // in the map object properties.
  1471. // update this object instance with properties from the map object
  1472. obj->updateObjValuesFromMapProperties( pMapObj->getProperties() );
  1473. } // end if
  1474. } // for, loading bridge map objects
  1475. // update the loadscreen
  1476. updateLoadProgress(LOAD_PROGRESS_POST_BRIDGE_LOAD);
  1477. // refresh the radar to reflect loaded bridges
  1478. TheRadar->refreshTerrain( TheTerrainLogic );
  1479. // tell the AI about it
  1480. // Note that it is important that the pathfinder be called before the map objects are loaded.
  1481. TheAI->pathfinder()->newMap( );
  1482. // update the loadscreen
  1483. updateLoadProgress(LOAD_PROGRESS_POST_PATHFINDER_NEW_MAP);
  1484. // reveal the map for the permanent observer
  1485. ThePartitionManager->revealMapForPlayerPermanently( ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey("ReplayObserver"))->getPlayerIndex() );
  1486. DEBUG_LOG(("Reveal shroud for %ls whose index is %d\n", ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey("ReplayObserver"))->getPlayerDisplayName().str(),ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey("ReplayObserver"))->getPlayerIndex()));
  1487. if (game)
  1488. {
  1489. for (int i=0; i<MAX_SLOTS; ++i)
  1490. {
  1491. GameSlot *slot = game->getSlot(i);
  1492. if (!slot || !slot->isOccupied())
  1493. continue;
  1494. AsciiString playerName;
  1495. playerName.format("player%d", i);
  1496. Player *player = ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(playerName));
  1497. if (slot->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER)
  1498. {
  1499. DEBUG_LOG(("Clearing shroud for observer %s in playerList slot %d\n", playerName.str(), player->getPlayerIndex()));
  1500. ThePartitionManager->revealMapForPlayerPermanently( player->getPlayerIndex() );
  1501. }
  1502. else
  1503. {
  1504. // remove shroud for the player in MP games
  1505. if (!TheMultiplayerSettings->isShroudInMultiplayer())
  1506. ThePartitionManager->revealMapForPlayer( player->getPlayerIndex() );
  1507. }
  1508. }
  1509. }
  1510. #ifdef DUMP_PERF_STATS
  1511. GetPrecisionTimer(&endTime64);
  1512. sprintf(Buf,"Before loading objects=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  1513. DEBUG_LOG(("%s", Buf));
  1514. #endif
  1515. Bool useTrees = TheGlobalData->m_useTrees;
  1516. // If forceFluffToProp == true, removable objects get created on client only. [7/14/2003]
  1517. // If static lod is HIGH, we don't do force fluff to client side only (create logic side props, more expensive. jba)
  1518. Bool forceFluffToProp = TheGameLODManager->getStaticLODLevel() != STATIC_GAME_LOD_HIGH;
  1519. if (TheGameLODManager->getStaticLODLevel() == STATIC_GAME_LOD_CUSTOM &&
  1520. TheGlobalData->m_useShadowVolumes) {
  1521. // Custom LOD, and volumetric shadows turned on - very high detail. So use logic props too. jba. [7/14/2003]
  1522. forceFluffToProp = false;
  1523. }
  1524. if (TheRecorder && TheRecorder->isMultiplayer()) {
  1525. useTrees = TRUE; // Always use trees in multiplayer, cause we want it to sync properly. jba.
  1526. forceFluffToProp = TRUE; // Always do client side fluff - faster, and syncs properly. jba.
  1527. }
  1528. progressCount = LOAD_PROGRESS_LOOP_ALL_THE_FREAKN_OBJECTS;
  1529. Int timer = timeGetTime();
  1530. if( loadingSaveGame ) {
  1531. // Loading a loadingSaveGame, need to add the trees to the client. jba. [8/11/2003]
  1532. for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext())
  1533. {
  1534. // get thing template based from map object name
  1535. thingTemplate = pMapObj->getThingTemplate();
  1536. if( thingTemplate == NULL )
  1537. continue;
  1538. // don't create trees and shrubs if this is one and we have that option off
  1539. if( thingTemplate->isKindOf( KINDOF_SHRUBBERY ) && !useTrees )
  1540. continue;
  1541. Coord3D pos = *pMapObj->getLocation();
  1542. pos.z += TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  1543. Real angle = normalizeAngle(pMapObj->getAngle());
  1544. if (thingTemplate->isKindOf(KINDOF_OPTIMIZED_TREE)) {
  1545. // Opt trees and props just get drawables to tell the client about it, then deleted. jba [6/5/2003]
  1546. // This way there is no logic object to slow down partition manager and core logic stuff.
  1547. Drawable *draw = TheThingFactory->newDrawable(thingTemplate, DRAWABLE_STATUS_NONE);
  1548. if (draw) {
  1549. draw->setOrientation(angle);
  1550. draw->setPosition( &pos );
  1551. TheGameClient->destroyDrawable(draw);
  1552. }
  1553. }
  1554. }
  1555. }
  1556. else
  1557. {
  1558. for (pMapObj = MapObject::getFirstMapObject(); pMapObj; pMapObj = pMapObj->getNext())
  1559. {
  1560. if (pMapObj->getFlag(FLAG_BRIDGE_FLAGS) || pMapObj->getFlag(FLAG_ROAD_FLAGS)) {
  1561. continue; // roads & bridges are special cased in the terrain side.
  1562. }
  1563. //Kris: Added this function so that we can rename objects and preserve them. If the patch
  1564. // entry is missing for a particular unit, it doesn't get added to the world.
  1565. handleNameChange( pMapObj );
  1566. // get thing template based from map object name
  1567. thingTemplate = pMapObj->getThingTemplate();
  1568. //
  1569. // if no template continue, some map objects don't have thing templates like
  1570. // lights (handled in the device). Objects that are test objects have a
  1571. // test string (designated with *** and the define TEST_STRING) and will
  1572. // have temporary templates created 'on the fly' during a
  1573. // ThingFactory->findTemplate() call when loading from the map file
  1574. //
  1575. if( thingTemplate == NULL )
  1576. continue;
  1577. Bool isBridgeLikeObject = false;
  1578. if (thingTemplate->isBridge()) isBridgeLikeObject = true;
  1579. if (thingTemplate->isKindOf(KINDOF_WALK_ON_TOP_OF_WALL)) isBridgeLikeObject = true;
  1580. if (isBridgeLikeObject)
  1581. continue; // bridges have to be added earlier.
  1582. // don't create trees and shrubs if this is one and we have that option off
  1583. if( thingTemplate->isKindOf( KINDOF_SHRUBBERY ) && !useTrees )
  1584. continue;
  1585. Coord3D pos = *pMapObj->getLocation();
  1586. pos.z += TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  1587. Real angle = normalizeAngle(pMapObj->getAngle());
  1588. if (thingTemplate->isKindOf(KINDOF_OPTIMIZED_TREE)) {
  1589. // Opt trees and props just get drawables to tell the client about it, then deleted. jba [6/5/2003]
  1590. // This way there is no logic object to slow down partition manager and core logic stuff.
  1591. Drawable *draw = TheThingFactory->newDrawable(thingTemplate, DRAWABLE_STATUS_NONE);
  1592. if (draw) {
  1593. draw->setOrientation(angle);
  1594. draw->setPosition( &pos );
  1595. TheGameClient->destroyDrawable(draw);
  1596. }
  1597. continue;
  1598. }
  1599. #if 1
  1600. Bool isProp = thingTemplate->isKindOf(KINDOF_PROP);
  1601. Bool isFluff = false;
  1602. if (thingTemplate->isKindOf(KINDOF_CLEARED_BY_BUILD)) {
  1603. if (thingTemplate->getFenceWidth() == 0.0f) {
  1604. // Objects that are cleared by building, but aren't fences, are fluff. jba. [7/14/2003]
  1605. isFluff = true;
  1606. }
  1607. }
  1608. if (isProp || (isFluff && forceFluffToProp)) {
  1609. TheTerrainVisual->addProp(thingTemplate, &pos, angle);
  1610. continue;
  1611. }
  1612. #endif
  1613. // Get the team information
  1614. DEBUG_ASSERTCRASH(pMapObj->getProperties()->getType(TheKey_originalOwner) == Dict::DICT_ASCIISTRING, ("unit %s has no original owner specified (obsolete map file)\n",pMapObj->getName().str()));
  1615. AsciiString originalOwner = pMapObj->getProperties()->getAsciiString(TheKey_originalOwner);
  1616. Team *team = ThePlayerList->validateTeam(originalOwner);
  1617. // create new object in the world
  1618. Object *obj = TheThingFactory->newObject( thingTemplate, team ); //, OBJECT_STATUS_LOADING_FROM_MAP );
  1619. if( obj )
  1620. {
  1621. if(pMapObj->getFlag(FLAG_DRAWS_IN_MIRROR) || obj->isKindOf(KINDOF_CAN_CAST_REFLECTIONS))
  1622. {
  1623. Drawable* draw = obj->getDrawable();
  1624. if(draw)
  1625. draw->setDrawableStatus( DRAWABLE_STATUS_DRAWS_IN_MIRROR );
  1626. }
  1627. obj->setOrientation(angle);
  1628. obj->setPosition( &pos );
  1629. // Do this after positioning the object, because we may place objects in response to keys
  1630. // in the map object properties.
  1631. // update this object instance with properties from the map object
  1632. obj->updateObjValuesFromMapProperties( pMapObj->getProperties() );
  1633. PathfindLayerEnum layer = TheTerrainLogic->getLayerForDestination(&pos);
  1634. obj->setLayer(layer);
  1635. // Now onCreates were called at the constructor. This magically created
  1636. // thing needs to be considered as Built for Game specific stuff.
  1637. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  1638. {
  1639. CreateModuleInterface* create = (*m)->getCreate();
  1640. if (!create)
  1641. continue;
  1642. create->onBuildComplete();
  1643. }
  1644. // Since the team now has members, activate it.
  1645. team->setActive();
  1646. TheAI->pathfinder()->addObjectToPathfindMap( obj );
  1647. } // end if
  1648. if(timeGetTime() > timer + 500)
  1649. {
  1650. if(progressCount < LOAD_PROGRESS_MAX_ALL_THE_FREAKN_OBJECTS)
  1651. progressCount ++;
  1652. updateLoadProgress(progressCount);
  1653. timer = timeGetTime();
  1654. }
  1655. } // for, loading map objects
  1656. } // end if, not loading save game
  1657. #ifdef DUMP_PERF_STATS
  1658. GetPrecisionTimer(&endTime64);
  1659. sprintf(Buf,"After loading objects=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  1660. DEBUG_LOG(("%s", Buf));
  1661. #endif
  1662. progressCount = LOAD_PROGRESS_LOOP_INITIAL_NETWORK_BUILDINGS;
  1663. // place initial network buildings/units
  1664. if (game && !loadingSaveGame)
  1665. {
  1666. for (int i=0; i<MAX_SLOTS; ++i)
  1667. {
  1668. GameSlot *slot = game->getSlot(i);
  1669. if (!slot || !slot->isOccupied())
  1670. continue;
  1671. AsciiString playerName;
  1672. playerName.format("player%d", i);
  1673. Player *player = ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(playerName));
  1674. if (slot->getPlayerTemplate() == PLAYERTEMPLATE_OBSERVER)
  1675. {
  1676. slot->setPlayerTemplate(0);
  1677. const PlayerTemplate *pt = ThePlayerTemplateStore->findPlayerTemplate( TheNameKeyGenerator->nameToKey("FactionObserver") );
  1678. if (pt)
  1679. {
  1680. for (Int j=0; j<ThePlayerTemplateStore->getPlayerTemplateCount(); ++j)
  1681. {
  1682. if (pt == ThePlayerTemplateStore->getNthPlayerTemplate(j))
  1683. {
  1684. slot->setPlayerTemplate(j);
  1685. break;
  1686. }
  1687. }
  1688. }
  1689. DEBUG_LOG(("Setting observer's playerTemplate to %d in slot %d\n", slot->getPlayerTemplate(), i));
  1690. }
  1691. else
  1692. {
  1693. const PlayerTemplate* pt = NULL;
  1694. pt = ThePlayerTemplateStore->getNthPlayerTemplate(slot->getPlayerTemplate());
  1695. // Prevent from loading the disabled Generals, in case your game peer hacked their GUI.
  1696. // The game will start, but the cheater will be instantly defeated because he has no troops.
  1697. // This is also enforced at GUI setup (GUIUtil.cpp and UserPreferences.cpp).
  1698. // @todo: unlock these when something rad happens
  1699. Bool disallowLockedGenerals = TRUE;
  1700. const GeneralPersona *general = TheChallengeGenerals->getGeneralByTemplateName(pt->getName());
  1701. Bool startsLocked = general ? !general->isStartingEnabled() : FALSE;
  1702. if (disallowLockedGenerals && startsLocked)
  1703. continue;
  1704. // prevent from loading disallowed templates, in case your peer hacked their GUI.
  1705. // So that the global flag for restricting factions to "OLD" is applied only in the appropriate context!
  1706. // Trouble was that skirmish games would get no command centers upon start, if this was set true in a GameSpyMenu
  1707. if ( isInInternetGame() )
  1708. {
  1709. if ( game->oldFactionsOnly() && !pt->isOldFaction() )
  1710. continue;
  1711. }
  1712. placeNetworkBuildingsForPlayer(i, slot, player, pt);
  1713. }
  1714. updateLoadProgress(progressCount++);
  1715. }
  1716. }
  1717. // update the loadscreen
  1718. updateLoadProgress(LOAD_PROGRESS_POST_INITIAL_NETWORK_BUILDINGS);
  1719. //
  1720. // tell the client to pre-load some assets that we will use such as faction things we
  1721. // will build and various damage states for all the structures on the map so that we
  1722. // don't have big pauses when building those objects or switching to those states
  1723. //
  1724. if( TheGlobalData->m_preloadAssets )
  1725. {
  1726. if (TheGlobalData->m_preloadEverything)
  1727. {
  1728. for (Int td = TIME_OF_DAY_FIRST; td < TIME_OF_DAY_COUNT; ++td)
  1729. TheGameClient->preloadAssets((TimeOfDay)td);
  1730. }
  1731. else
  1732. {
  1733. TheGameClient->preloadAssets( TheGlobalData->m_timeOfDay );
  1734. }
  1735. }
  1736. //put this here somewhat randomly.
  1737. TheControlBar->hideCommunicator( FALSE );
  1738. // update the loadscreen
  1739. updateLoadProgress(LOAD_PROGRESS_POST_PRELOAD_ASSETS);
  1740. TheTacticalView->setAngleAndPitchToDefault();
  1741. TheTacticalView->setZoomToDefault();
  1742. if( TheRecorder )
  1743. TheRecorder->initControls();
  1744. // Note - WorldBuilderDoc.cpp also uses initial camera position, so if changed, update both. jba
  1745. // Note - We construct the multiplayer start spot name manually here, so change this if you
  1746. // change TheKey_Player_1_Start etc. mdc
  1747. AsciiString startingCamName = TheNameKeyGenerator->keyToName(TheKey_InitialCameraPosition);
  1748. if (game)
  1749. {
  1750. GameSlot *slot = game->getSlot(localSlot);
  1751. DEBUG_ASSERTCRASH(slot, ("Starting a LAN game without ourselves!"));
  1752. if (slot->isHuman())
  1753. {
  1754. Int startPos = slot->getStartPos();
  1755. startingCamName.format("Player_%d_Start", startPos+1); // start pos waypoints are 1-based
  1756. DEBUG_LOG(("Using %s as the multiplayer initial camera position\n", startingCamName.str()));
  1757. }
  1758. }
  1759. // update the loadscreen
  1760. updateLoadProgress(LOAD_PROGRESS_POST_STARTING_CAMERA);
  1761. Waypoint *way = findNamedWaypoint(startingCamName);
  1762. if (way)
  1763. {
  1764. Coord3D pos = *way->getLocation();
  1765. TheTacticalView->lookAt( &pos );
  1766. }
  1767. else
  1768. {
  1769. // Just look somewhere. lookAt does some terrain specific setup, so it is good
  1770. // to call it. jba
  1771. Coord3D pos;
  1772. pos.x = 50;
  1773. pos.y = 50;
  1774. pos.z = 0;
  1775. TheTacticalView->lookAt( &pos );
  1776. DEBUG_LOG(("Failed to find initial camera position waypoint %s\n", startingCamName.str()));
  1777. }
  1778. // Set up the camera height based on the map height & globalData.
  1779. TheTacticalView->initHeightForMap();
  1780. TheTacticalView->setAngleAndPitchToDefault();
  1781. TheTacticalView->setZoomToDefault();
  1782. // update the loadscreen
  1783. updateLoadProgress(LOAD_PROGRESS_POST_STARTING_CAMERA_2);
  1784. // update partition info - We need to do the initial update so that it can be queried
  1785. // during the first frame. jba.
  1786. ThePartitionManager->update();
  1787. #ifdef DUMP_PERF_STATS
  1788. GetPrecisionTimer(&endTime64);
  1789. sprintf(Buf,"After partition manager update=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  1790. DEBUG_LOG(("%s", Buf));
  1791. #endif
  1792. // final step, run newMap for all players
  1793. if( loadingSaveGame == FALSE )
  1794. ThePlayerList->newMap();
  1795. if ( isChallengeCampaign )
  1796. {
  1797. // Establish local player relationships with other teams as
  1798. // they're set up for "ThePlayer" in challenge mode map.
  1799. // Some designers have used "ThePlayer" as an empty player for Generals'
  1800. // Challenge maps which they reference in script and by which they set
  1801. // player relationships. The skirmish local player will receive these
  1802. // relationships. If there is no "ThePlayer", we have to assume that
  1803. // all players on the map are the local player's enemy, except neutral
  1804. // and civilian players.
  1805. Player *localPlayer = ThePlayerList->getLocalPlayer();
  1806. DEBUG_ASSERTCRASH(localPlayer, ("Local player has not been established for Challenge map."));
  1807. Player *placeholderThePlayer = ThePlayerList->findPlayerWithNameKey(NAMEKEY("ThePlayer"));
  1808. DEBUG_ASSERTCRASH(placeholderThePlayer, ("Challenge maps without player \"ThePlayer\" assume that the local player is mutual enemies with all other players except the neutral and civilian players."));
  1809. if (placeholderThePlayer)
  1810. {
  1811. PlayerMaskType thePlayerEnemysMask = ThePlayerList->getPlayersWithRelationship(placeholderThePlayer->getPlayerIndex(), ALLOW_ENEMIES);
  1812. while( thePlayerEnemysMask )
  1813. {
  1814. // set local player enemy relationships based on "ThePlayer" enemy relationships
  1815. Player *thePlayerEnemy = ThePlayerList->getEachPlayerFromMask(thePlayerEnemysMask);
  1816. thePlayerEnemy->setPlayerRelationship(localPlayer, ENEMIES);
  1817. localPlayer->setPlayerRelationship(thePlayerEnemy, ENEMIES);
  1818. }
  1819. }
  1820. else
  1821. {
  1822. // This map has no "ThePlayer" by which to model the local player's
  1823. // relationships, so make assumptions.
  1824. for (Int i = 0; i < ThePlayerList->getPlayerCount(); i++)
  1825. {
  1826. Relationship rel = NEUTRAL;
  1827. Player *thatPlayer = ThePlayerList->getNthPlayer(i);
  1828. if (thatPlayer == localPlayer)
  1829. {
  1830. rel = ALLIES;
  1831. }
  1832. else if (thatPlayer != ThePlayerList->getNeutralPlayer()
  1833. && thatPlayer != ThePlayerList->findPlayerWithNameKey(NAMEKEY("PlyrCivilian")))
  1834. {
  1835. rel = ENEMIES;
  1836. }
  1837. thatPlayer->setPlayerRelationship(localPlayer, rel);
  1838. localPlayer->setPlayerRelationship(thatPlayer, rel);
  1839. }
  1840. }
  1841. }
  1842. // reset all the skill points in a single player game
  1843. if(loadingSaveGame == FALSE && isInSinglePlayerGame())
  1844. {
  1845. for (Int i=0; i<MAX_PLAYER_COUNT; ++i)
  1846. {
  1847. Player *pPlayer = ThePlayerList->getNthPlayer(i);
  1848. if (pPlayer && pPlayer->getPlayerType() != PLAYER_HUMAN)
  1849. pPlayer = NULL;
  1850. if (pPlayer)
  1851. {
  1852. pPlayer->addSkillPoints(m_rankPointsToAddAtGameStart);
  1853. DEBUG_LOG(("GameLogic::startNewGame() - adding m_rankPointsToAddAtGameStart==%d to player %d(%ls)\n",
  1854. m_rankPointsToAddAtGameStart, i, pPlayer->getPlayerDisplayName().str()));
  1855. }
  1856. }
  1857. }
  1858. updateLoadProgress(LOAD_PROGRESS_END);
  1859. if(isInMultiplayerGame() && TheNetwork)
  1860. {
  1861. TheNetwork->loadProgressComplete();
  1862. TheNetwork->liteupdate();
  1863. }
  1864. while(!isProgressComplete())
  1865. {
  1866. updateLoadProgress(101); // keep greater then 100
  1867. testTimeOut();
  1868. Sleep(100);
  1869. }
  1870. // if we're in a load game, don't fade yet
  1871. if( loadingSaveGame == FALSE )
  1872. {
  1873. TheTransitionHandler->setGroup("FadeWholeScreen");
  1874. while(!TheTransitionHandler->isFinished())
  1875. {
  1876. TheWindowManager->update();
  1877. if(!TheTransitionHandler->isFinished())
  1878. {
  1879. TheDisplay->draw();
  1880. setFPMode();
  1881. Sleep(33);
  1882. }
  1883. }
  1884. }
  1885. if(m_loadScreen)
  1886. {
  1887. TheMouse->setVisibility(TRUE);
  1888. /*
  1889. //
  1890. // delete load screen only when not loading a save game, for save games we still
  1891. // have more work to do and the load screen will be deleted elsewhere after
  1892. // we're all done with the load game progress
  1893. //
  1894. if( loadingSaveGame == FALSE )
  1895. */
  1896. deleteLoadScreen();
  1897. }
  1898. #ifdef DUMP_PERF_STATS
  1899. GetPrecisionTimer(&endTime64);
  1900. sprintf(Buf,"After delete load screen=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  1901. DEBUG_LOG(("%s", Buf));
  1902. #endif
  1903. if(m_gameMode == GAME_SHELL)
  1904. {
  1905. if(TheShell->getScreenCount() == 0)
  1906. TheShell->push( AsciiString("Menus/MainMenu.wnd") );
  1907. else if (TheShell->top())
  1908. {
  1909. TheShell->top()->hide(FALSE);
  1910. TheShell->top()->bringForward();
  1911. }
  1912. HideControlBar();
  1913. }
  1914. else
  1915. {
  1916. // TheShell->hideShell();
  1917. if(TheStatsCollector)
  1918. {
  1919. TheStatsCollector->reset();
  1920. }
  1921. else if( TheGlobalData->m_playStats > 0)
  1922. {
  1923. TheStatsCollector = NEW StatsCollector;
  1924. TheStatsCollector->reset();
  1925. }
  1926. /// ShowControlBar(FALSE);
  1927. // explicitly set the Control bar to Observer Mode
  1928. if(m_gameMode == GAME_REPLAY )
  1929. {
  1930. ThePlayerList->setLocalPlayer(ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey("ReplayObserver")));
  1931. TheRadar->forceOn(TRUE);
  1932. ThePartitionManager->refreshShroudForLocalPlayer();
  1933. TheControlBar->setControlBarSchemeByPlayer( ThePlayerList->getLocalPlayer());
  1934. DEBUG_LOG(("Start of a replay game %ls, %d\n",ThePlayerList->getLocalPlayer()->getPlayerDisplayName().str(), ThePlayerList->getLocalPlayer()->getPlayerIndex()));
  1935. }
  1936. else
  1937. TheControlBar->setControlBarSchemeByPlayer(ThePlayerList->getLocalPlayer());
  1938. // ShowControlBar();
  1939. }
  1940. TheTacticalView->setOkToAdjustHeight(TRUE);
  1941. // If defined, the game times various units.
  1942. #ifdef DO_UNIT_TIMINGS
  1943. g_UT_curThing = TheThingFactory->firstTemplate();
  1944. g_UT_startTiming = true;
  1945. g_UT_gotUnit = false;
  1946. g_UT_timingLog = fopen("TimingLog.txt", "w");
  1947. g_UT_commaLog = fopen("TimingCDL.txt", "w");
  1948. fputs("Full,100*ms,NoPart-NoSpawn,,No Spawn,100*ms,Logic,100*ms,Thing,Model,Kind,Side,DrawCalls All,DrawCalls NoPart-NoSpawn,DrawCalls NoSpawn\n", g_UT_commaLog);
  1949. // Turn off shadows
  1950. TheWritableGlobalData->m_useShadowVolumes = false;
  1951. TheWritableGlobalData->m_debugIgnoreAsserts = TRUE;
  1952. // Just look somewhere. lookAt does some terrain specific setup, so it is good
  1953. // to call it. jba
  1954. Coord3D thePos;
  1955. thePos.x = 50;
  1956. thePos.y = 50;
  1957. thePos.z = 0;
  1958. TheTacticalView->lookAt( &thePos );
  1959. #endif
  1960. // @todo remove this hack
  1961. // TheGlobalData->m_inGame = TRUE;
  1962. // If we are now starting a multiplayer or skirmish game, let us set the local players selectionto be the command center
  1963. // We'll ask the Recorder, so we survive replays
  1964. if( TheRecorder->isMultiplayer() )
  1965. {
  1966. // Iterate through each player's objects, and ask if the object
  1967. //is a command center, and if so, select it for that player
  1968. for (Int i = 0; i < MAX_PLAYER_COUNT; ++i)
  1969. {
  1970. Player *player = ThePlayerList->getNthPlayer(i);
  1971. if (player && player->isPlayerActive())
  1972. {
  1973. // we need to iterate their objects, and select the first Command Center we find
  1974. Bool alreadyFound = FALSE;
  1975. player->iterateObjects(findAndSelectCommandCenter, &alreadyFound);
  1976. }
  1977. }
  1978. }
  1979. TheControlBar->initSpecialPowershortcutBar(ThePlayerList->getLocalPlayer());
  1980. if(m_gameMode == GAME_SHELL)
  1981. {
  1982. HideControlBar();
  1983. }
  1984. else
  1985. {
  1986. ShowControlBar(FALSE);
  1987. }
  1988. #ifdef DO_UNIT_TIMINGS
  1989. // Turn off the UI
  1990. HideControlBar();
  1991. #endif
  1992. TheWritableGlobalData->m_loadScreenRender = FALSE; ///< mark to resume rendering as normal
  1993. // if we're in a gamespy game, mark us as playing
  1994. if (TheGameSpyBuddyMessageQueue && TheGameSpyGame && isInInternetGame())
  1995. {
  1996. BuddyRequest req;
  1997. req.buddyRequestType = BuddyRequest::BUDDYREQUEST_SETSTATUS;
  1998. req.arg.status.status = GP_PLAYING;
  1999. strcpy(req.arg.status.statusString, "Playing");
  2000. sprintf(req.arg.status.locationString, "%s", WideCharStringToMultiByte(TheGameSpyGame->getGameName().str()).c_str());
  2001. TheGameSpyBuddyMessageQueue->addRequest(req);
  2002. }
  2003. if( loadingSaveGame == FALSE )
  2004. {
  2005. // Drawables need to do some work on level start; give them a chance to do it
  2006. Drawable * drawable = TheGameClient->getDrawableList();
  2007. while ( drawable != NULL )
  2008. {
  2009. drawable->onLevelStart();
  2010. drawable = drawable->getNextDrawable();
  2011. }
  2012. }
  2013. //Added By Sadullah Nader
  2014. //Added to fix the quit menu
  2015. //ReAllows quit menu to work during loading scene
  2016. //setGameLoading(FALSE);
  2017. setLoadingMap( FALSE );
  2018. #ifdef DUMP_PERF_STATS
  2019. GetPrecisionTimer(&endTime64);
  2020. sprintf(Buf,"Total startnewgame=%f\n",((double)(endTime64-startTime64)/(double)(freq64)*1000.0));
  2021. DEBUG_LOG(("%s", Buf));
  2022. #endif
  2023. //Assume that getting this far means we've successfully entered an online game.
  2024. //Add an additional disconnection to player stats in case he doesn't complete this game. -MW
  2025. if (TheGameSpyInfo)
  2026. TheGameSpyInfo->updateAdditionalGameSpyDisconnections(1);
  2027. if ( isInReplayGame() && TheInGameUI && TheGameText )
  2028. {
  2029. TheInGameUI->message( TheGameText->fetch( "GUI:FastForwardInstructions" ) );
  2030. }
  2031. } // end startNewGame
  2032. //-----------------------------------------------------------------------------------------
  2033. static void findAndSelectCommandCenter(Object *obj, void* alreadyFound)
  2034. {
  2035. if (!((*(Bool*)alreadyFound)) && obj && obj->isKindOf(KINDOF_COMMANDCENTER) )
  2036. {
  2037. ((*(Bool*)alreadyFound)) = TRUE;
  2038. TheGameLogic->selectObject(obj, TRUE, obj->getControllingPlayer()->getPlayerMask(), obj->isLocallyControlled());
  2039. }
  2040. }
  2041. //-----------------------------------------------------------------------------------------
  2042. //-----------------------------------------------------------------------------------------
  2043. // ------------------------------------------------------------------------------------------------
  2044. // ------------------------------------------------------------------------------------------------
  2045. void GameLogic::loadMapINI( AsciiString mapName )
  2046. {
  2047. if (!TheMapCache) {
  2048. // Need the map cache to get the map and user map directories.
  2049. return;
  2050. }
  2051. char filename[_MAX_PATH];
  2052. char fullFledgeFilename[_MAX_PATH];
  2053. memset(filename, 0, _MAX_PATH);
  2054. strcpy(filename, mapName.str());
  2055. //
  2056. // if map name begins with a "SAVE_DIRECTORY\", then the map refers to a map
  2057. // that has been extracted from a save game file ... in that case we need to get
  2058. // the pristine map name string in order to manipulate and load the right map.ini
  2059. // for that map from it's original location
  2060. //
  2061. if (TheGameState->isInSaveDirectory(filename))
  2062. strcpy( filename, TheGameState->getSaveGameInfo()->pristineMapName.str() );
  2063. // sanity
  2064. int length = strlen(filename);
  2065. if (length < 4) {
  2066. return;
  2067. }
  2068. // back up over the ".map" extension and to the first directory separator
  2069. char *extension = filename + length - 4;
  2070. while ((extension > filename) && (*extension != '\\') && (*extension != '/')) {
  2071. --extension;
  2072. }
  2073. *extension = 0;
  2074. sprintf(fullFledgeFilename, "%s\\map.ini", filename);
  2075. if (TheFileSystem->doesFileExist(fullFledgeFilename)) {
  2076. DEBUG_LOG(("Loading map.ini\n"));
  2077. INI ini;
  2078. ini.load( AsciiString(fullFledgeFilename), INI_LOAD_CREATE_OVERRIDES, NULL );
  2079. }
  2080. sprintf(fullFledgeFilename, "%s\\solo.ini", filename);
  2081. if (TheFileSystem->doesFileExist(fullFledgeFilename)) {
  2082. DEBUG_LOG(("Loading solo.ini\n"));
  2083. INI ini;
  2084. ini.load( AsciiString(fullFledgeFilename), INI_LOAD_CREATE_OVERRIDES, NULL );
  2085. }
  2086. // No error here. There could've just *not* been a map.ini file.
  2087. // now look for a string file
  2088. sprintf(fullFledgeFilename, "%s\\map.str", filename);
  2089. if (TheFileSystem->doesFileExist(fullFledgeFilename)) {
  2090. TheGameText->initMapStringFile(fullFledgeFilename);
  2091. }
  2092. // we want to do this before doing the actual map load!
  2093. if (TheDisplay)
  2094. {
  2095. const char* ASSET_USAGE_FILE_NAME = "AssetUsage.txt";
  2096. sprintf(fullFledgeFilename, "%s\\%s", filename, ASSET_USAGE_FILE_NAME);
  2097. // note: call this EVEN IF THE FILE IN QUESTION DOES NOT EXIST.
  2098. TheDisplay->doSmartAssetPurgeAndPreload(fullFledgeFilename);
  2099. }
  2100. }
  2101. // ------------------------------------------------------------------------------------------------
  2102. /** Process the destroy list, destroying all pending objects.
  2103. * The destroy list exists to ensure that all objects have a chance to
  2104. * see each other at each simulation frame - the object list is the
  2105. * same at the start of the update as it is at the end of the update. */
  2106. // ------------------------------------------------------------------------------------------------
  2107. //DECLARE_PERF_TIMER(processDestroyList)
  2108. void GameLogic::processDestroyList( void )
  2109. {
  2110. //USE_PERF_TIMER(processDestroyList)
  2111. for( ObjectPointerListIterator iterator = m_objectsToDestroy.begin(); iterator != m_objectsToDestroy.end(); iterator++ )
  2112. {
  2113. Object* currentObject = (*iterator);
  2114. #ifdef ALLOW_NONSLEEPY_UPDATES
  2115. for (std::list<UpdateModulePtr>::iterator it = m_normalUpdates.begin(); it != m_normalUpdates.end(); /* nothing */)
  2116. {
  2117. if ((*it)->friend_getObject() == currentObject)
  2118. {
  2119. it = m_normalUpdates.erase(it);
  2120. }
  2121. else
  2122. {
  2123. ++it;
  2124. }
  2125. }
  2126. #endif
  2127. /*
  2128. this looks odd, but is necessary; since erasing a single entry can shuffle others in the list
  2129. (in order to maintain its heap-ness), we must do two passes: one to find the updates for this
  2130. object, another to actually erase 'em.
  2131. (in case you're wondering: yes, this is still more efficient than just deleting them
  2132. and rebalancing the entire heap afterwards, at least for real-world maps, since an individual
  2133. rebalance is O(log N) and a full rebalance is O(N)... so unless you are deleting the majority
  2134. of the objects in the world every frame, we come out well ahead this way.)
  2135. */
  2136. const Int MAX_SUO = 256;
  2137. UpdateModulePtr sleepyUpdatesForThisObject[MAX_SUO];
  2138. Int numSUO = 0;
  2139. for (std::vector<UpdateModulePtr>::iterator it2 = m_sleepyUpdates.begin(); it2 != m_sleepyUpdates.end(); ++it2)
  2140. {
  2141. UpdateModulePtr u = *it2;
  2142. if (u->friend_getObject() == currentObject && numSUO < MAX_SUO)
  2143. {
  2144. sleepyUpdatesForThisObject[numSUO++] = u;
  2145. }
  2146. }
  2147. for (--numSUO; numSUO >= 0; --numSUO)
  2148. {
  2149. // have to re-get idx each time since each call to erase might change others.
  2150. Int idx = sleepyUpdatesForThisObject[numSUO]->friend_getIndexInLogic();
  2151. DEBUG_ASSERTCRASH(m_sleepyUpdates[idx] == sleepyUpdatesForThisObject[numSUO], ("Hmm, expected update mismatch here"));
  2152. eraseSleepyUpdate(idx);
  2153. DEBUG_ASSERTCRASH(sleepyUpdatesForThisObject[numSUO]->friend_getIndexInLogic() == -1, ("Hmm, expected index to be -1 here"));
  2154. }
  2155. currentObject->removeFromList(&m_objList);//remove from object list
  2156. // remove object from lookup table
  2157. removeObjectFromLookupTable( currentObject );
  2158. currentObject->friend_deleteInstance();//actual delete
  2159. }
  2160. m_objectsToDestroy.clear();//list full of bad pointers now, clear it. If anyone's deletion resulted
  2161. //in the request for a new deletion (sub-object), the new object was added to the end of this list.
  2162. }
  2163. //-------------------------------------------------------------------------------------------------
  2164. /** Process the command list passed to the logic from the network */
  2165. //-------------------------------------------------------------------------------------------------
  2166. void GameLogic::processCommandList( CommandList *list )
  2167. {
  2168. m_cachedCRCs.clear();
  2169. m_shouldValidateCRCs = FALSE;
  2170. GameMessage* msg;
  2171. for( msg = list->getFirstMessage(); msg; msg = msg->next() )
  2172. {
  2173. #ifdef _DEBUG
  2174. DEBUG_ASSERTCRASH(msg != NULL && msg != (GameMessage*)0xdeadbeef, ("bad msg"));
  2175. #endif
  2176. logicMessageDispatcher( msg, NULL );
  2177. }
  2178. if (m_shouldValidateCRCs && !TheNetwork->sawCRCMismatch())
  2179. {
  2180. Bool sawCRCMismatch = FALSE;
  2181. Int numPlayers = 0;
  2182. DEBUG_ASSERTCRASH(TheNetwork, ("No Network!"));
  2183. if (TheNetwork)
  2184. {
  2185. for (Int i=0; i<MAX_SLOTS; ++i)
  2186. {
  2187. if (TheNetwork->isPlayerConnected(i))
  2188. ++numPlayers;
  2189. }
  2190. if (m_cachedCRCs.size() < numPlayers)
  2191. {
  2192. DEBUG_CRASH(("Not enough CRCs!"));
  2193. sawCRCMismatch = TRUE;
  2194. }
  2195. else
  2196. {
  2197. //DEBUG_LOG(("Comparing %d CRCs on frame %d\n", m_cachedCRCs.size(), m_frame));
  2198. std::map<Int, UnsignedInt>::const_iterator crcIt = m_cachedCRCs.begin();
  2199. Int validatorCRC = crcIt->second;
  2200. //DEBUG_LOG(("Validator CRC from player %d is %8.8X\n", crcIt->first, validatorCRC));
  2201. while (++crcIt != m_cachedCRCs.end())
  2202. {
  2203. Int validatedCRC = crcIt->second;
  2204. //DEBUG_LOG(("CRC to validate is from player %d: %8.8X\n", crcIt->first, validatedCRC));
  2205. if (validatorCRC != validatedCRC)
  2206. {
  2207. DEBUG_CRASH(("CRC mismatch!"));
  2208. sawCRCMismatch = TRUE;
  2209. }
  2210. }
  2211. }
  2212. }
  2213. if (sawCRCMismatch)
  2214. {
  2215. #ifdef DEBUG_LOGGING
  2216. DEBUG_LOG(("CRC Mismatch - saw %d CRCs from %d players\n", m_cachedCRCs.size(), numPlayers));
  2217. for (std::map<Int, UnsignedInt>::const_iterator crcIt = m_cachedCRCs.begin(); crcIt != m_cachedCRCs.end(); ++crcIt)
  2218. {
  2219. Player *player = ThePlayerList->getNthPlayer(crcIt->first);
  2220. DEBUG_LOG(("CRC from player %d (%ls) = %X\n", crcIt->first,
  2221. player?player->getPlayerDisplayName().str():L"<NONE>", crcIt->second));
  2222. }
  2223. #endif DEBUG_LOGGING
  2224. TheNetwork->setSawCRCMismatch();
  2225. }
  2226. }
  2227. } // end processCommandList
  2228. // ------------------------------------------------------------------------------------------------
  2229. // ------------------------------------------------------------------------------------------------
  2230. Bool GameLogic::isIntroMoviePlaying()
  2231. {
  2232. /// @todo remove this hack
  2233. return m_startNewGame && TheDisplay->isMoviePlaying();
  2234. }
  2235. // ------------------------------------------------------------------------------------------------
  2236. // ------------------------------------------------------------------------------------------------
  2237. void GameLogic::selectObject(Object *obj, Bool createNewSelection, PlayerMaskType playerMask, Bool affectClient)
  2238. {
  2239. if (!obj)
  2240. {
  2241. return;
  2242. }
  2243. if (!obj->isMassSelectable() && !createNewSelection)
  2244. {
  2245. DEBUG_LOG(("GameLogic::selectObject() - Object attempted to be added to selection, but isn't mass-selectable.\n"));
  2246. return;
  2247. }
  2248. while( playerMask )
  2249. {
  2250. Player *player = ThePlayerList->getEachPlayerFromMask(playerMask);
  2251. if( !player )
  2252. {
  2253. return;
  2254. }
  2255. AIGroup *group = NULL;
  2256. CRCGEN_LOG(( "Creating AIGroup in GameLogic::selectObject()\n" ));
  2257. group = TheAI->createGroup();
  2258. group->add(obj);
  2259. // add all selected agents to the AI group
  2260. if (createNewSelection)
  2261. {
  2262. player->setCurrentlySelectedAIGroup(group);
  2263. }
  2264. else
  2265. {
  2266. player->addAIGroupToCurrentSelection(group);
  2267. }
  2268. TheAI->destroyGroup(group);
  2269. if( affectClient )
  2270. {
  2271. Drawable *draw = obj->getDrawable();
  2272. if( draw )
  2273. {
  2274. TheInGameUI->selectDrawable(draw);
  2275. }
  2276. }
  2277. }
  2278. }
  2279. // ------------------------------------------------------------------------------------------------
  2280. // ------------------------------------------------------------------------------------------------
  2281. void GameLogic::deselectObject(Object *obj, PlayerMaskType playerMask, Bool affectClient)
  2282. {
  2283. if (!obj) {
  2284. return;
  2285. }
  2286. while (playerMask) {
  2287. Player *player = ThePlayerList->getEachPlayerFromMask(playerMask);
  2288. if (!player) {
  2289. return;
  2290. }
  2291. AIGroup *group = NULL;
  2292. CRCGEN_LOG(( "Removing a unit from a selected group in GameLogic::deselectObject()\n" ));
  2293. group = TheAI->createGroup();
  2294. player->getCurrentSelectionAsAIGroup(group);
  2295. Bool deleted = FALSE;
  2296. Bool actuallyRemoved = FALSE;
  2297. if (group) {
  2298. deleted = group->remove(obj);
  2299. actuallyRemoved = TRUE;
  2300. }
  2301. if (actuallyRemoved) {
  2302. // Set this to be the currently selected group.
  2303. if (!deleted) {
  2304. player->setCurrentlySelectedAIGroup(group);
  2305. // Then, cleanup the group.
  2306. TheAI->destroyGroup(group);
  2307. } else {
  2308. // NULL will clear the group.
  2309. player->setCurrentlySelectedAIGroup(NULL);
  2310. }
  2311. if (affectClient) {
  2312. Drawable *draw = obj->getDrawable();
  2313. if (draw) {
  2314. TheInGameUI->deselectDrawable(draw);
  2315. }
  2316. }
  2317. }
  2318. }
  2319. }
  2320. // ------------------------------------------------------------------------------------------------
  2321. inline void GameLogic::validateSleepyUpdate() const
  2322. {
  2323. // pretty slow, so do only for DEBUG for now. turn on if you suspect wonkiness.
  2324. #ifdef _DEBUG
  2325. #define SLEEPY_DEBUG
  2326. #endif
  2327. #ifdef SLEEPY_DEBUG
  2328. int sz = m_sleepyUpdates.size();
  2329. if (sz == 0)
  2330. return;
  2331. int i;
  2332. //DEBUG_LOG(("\n\n"));
  2333. //for (i = 0; i < sz; ++i)
  2334. //{
  2335. // DEBUG_LOG(("u %04d: %08lx %08lx\n",i,m_sleepyUpdates[i],m_sleepyUpdates[i]->friend_getNextCallFrame()));
  2336. //}
  2337. for (i = 0; i < sz; ++i)
  2338. {
  2339. DEBUG_ASSERTCRASH(m_sleepyUpdates[i]->friend_getIndexInLogic() == i, ("index mismatch: expected %d, got %d\n",i,m_sleepyUpdates[i]->friend_getIndexInLogic()));
  2340. UnsignedInt pri = m_sleepyUpdates[i]->friend_getPriority();
  2341. if (i > 0)
  2342. {
  2343. Int i0 = (i+1)/2-1;
  2344. UnsignedInt pri0 = m_sleepyUpdates[i0]->friend_getPriority();
  2345. DEBUG_ASSERTCRASH(pri >= pri0, ("sleepyUpdates are munged (0)"));
  2346. }
  2347. Int i1 = 2*(i+1)-1;
  2348. Int i2 = 2*(i+1);
  2349. if (i1 < sz)
  2350. {
  2351. UnsignedInt pri1 = m_sleepyUpdates[i1]->friend_getPriority();
  2352. DEBUG_ASSERTCRASH(pri <= pri1, ("sleepyUpdates are munged (1)"));
  2353. }
  2354. if (i2 < sz)
  2355. {
  2356. UnsignedInt pri2 = m_sleepyUpdates[i2]->friend_getPriority();
  2357. DEBUG_ASSERTCRASH(pri <= pri2, ("sleepyUpdates are munged (2)"));
  2358. }
  2359. }
  2360. #endif
  2361. }
  2362. // ------------------------------------------------------------------------------------------------
  2363. void GameLogic::eraseSleepyUpdate(Int i)
  2364. {
  2365. USE_PERF_TIMER(SleepyMaintenance)
  2366. DEBUG_ASSERTCRASH(i >= 0 && i < m_sleepyUpdates.size(), ("bad sleepy idx"));
  2367. // swap with the final item, toss the final item, then rebalance
  2368. m_sleepyUpdates[i]->friend_setIndexInLogic(-1);
  2369. Int final = m_sleepyUpdates.size() - 1;
  2370. if (i < final)
  2371. {
  2372. m_sleepyUpdates[i] = m_sleepyUpdates[final];
  2373. m_sleepyUpdates[i]->friend_setIndexInLogic(i);
  2374. m_sleepyUpdates.pop_back();
  2375. rebalanceSleepyUpdate(i);
  2376. }
  2377. else
  2378. {
  2379. m_sleepyUpdates.pop_back();
  2380. }
  2381. }
  2382. // ------------------------------------------------------------------------------------------------
  2383. inline Bool isLowerPriority(const UpdateModulePtr a, const UpdateModulePtr b)
  2384. {
  2385. // return true iff a is lower pri than b.
  2386. // remember: lower ordinal value means higher priority.
  2387. // therefore, higher ordinal value means lower priority.
  2388. DEBUG_ASSERTCRASH(a && b, ("these may no longer be null"));
  2389. UnsignedInt f1 = a->friend_getPriority();
  2390. UnsignedInt f2 = b->friend_getPriority();
  2391. return f1 > f2;
  2392. }
  2393. // ------------------------------------------------------------------------------------------------
  2394. Int GameLogic::rebalanceParentSleepyUpdate(Int i)
  2395. {
  2396. USE_PERF_TIMER(SleepyMaintenance)
  2397. DEBUG_ASSERTCRASH(i >= 0 && i < m_sleepyUpdates.size(), ("bad sleepy idx"));
  2398. Int parent = ((i+1)>>1)-1;
  2399. while (parent >= 0 && isLowerPriority(m_sleepyUpdates[parent], m_sleepyUpdates[i]))
  2400. {
  2401. UpdateModulePtr a = m_sleepyUpdates[parent];
  2402. UpdateModulePtr b = m_sleepyUpdates[i];
  2403. m_sleepyUpdates[i] = a;
  2404. m_sleepyUpdates[parent] = b;
  2405. a->friend_setIndexInLogic(i);
  2406. b->friend_setIndexInLogic(parent);
  2407. i = parent;
  2408. parent = ((parent+1)>>1)-1;
  2409. }
  2410. return i;
  2411. }
  2412. // ------------------------------------------------------------------------------------------------
  2413. Int GameLogic::rebalanceChildSleepyUpdate(Int i)
  2414. {
  2415. USE_PERF_TIMER(SleepyMaintenance)
  2416. DEBUG_ASSERTCRASH(i >= 0 && i < m_sleepyUpdates.size(), ("bad sleepy idx"));
  2417. // this function gets the brunt of the work (we frequently
  2418. // balance down, not up), so this one is hand-unrolled for
  2419. // max efficiency. I have left the pristine non-unrolled
  2420. // version present for clarity. (Yes, this is worth doing.) (srj)
  2421. #if 1
  2422. UpdateModulePtr* pI = &m_sleepyUpdates[i];
  2423. // our children are i*2 and i*2+1
  2424. Int child = ((i+1)<<1)-1;
  2425. UpdateModulePtr* pChild = &m_sleepyUpdates[child];
  2426. UpdateModulePtr* pSZ = &m_sleepyUpdates[m_sleepyUpdates.size()]; // yes, this is off the end.
  2427. while (pChild < pSZ)
  2428. {
  2429. // choose the higher-priority of the two children; we must be higher-pri than that.
  2430. if (pChild < pSZ-1 && isLowerPriority(*pChild, *(pChild+1)))
  2431. {
  2432. ++pChild;
  2433. ++child;
  2434. }
  2435. // if we're higher-pri than our children, we're done.
  2436. if (!isLowerPriority(*pI, *pChild))
  2437. {
  2438. break;
  2439. }
  2440. // doh. swap with the highest-pri child we have.
  2441. UpdateModulePtr a = *pChild;
  2442. UpdateModulePtr b = *pI;
  2443. *pI = a;
  2444. *pChild = b;
  2445. a->friend_setIndexInLogic(i);
  2446. b->friend_setIndexInLogic(child);
  2447. i = child;
  2448. pI = pChild;
  2449. child = ((i+1)<<1)-1;
  2450. pChild = &m_sleepyUpdates[child];
  2451. }
  2452. #else
  2453. // our children are i*2 and i*2+1
  2454. Int sz = m_sleepyUpdates.size();
  2455. Int child = ((i+1)<<1)-1;
  2456. while (child < sz)
  2457. {
  2458. // choose the higher-priority of the two children; we must be higher-pri than that.
  2459. if (child < sz-1 && isLowerPriority(m_sleepyUpdates[child], m_sleepyUpdates[child+1]))
  2460. ++child;
  2461. // if we're higher-pri than our children, we're done.
  2462. if (!isLowerPriority(m_sleepyUpdates[i], m_sleepyUpdates[child]))
  2463. {
  2464. break;
  2465. }
  2466. // doh. swap with the highest-pri child we have.
  2467. UpdateModulePtr a = m_sleepyUpdates[child];
  2468. UpdateModulePtr b = m_sleepyUpdates[i];
  2469. m_sleepyUpdates[i] = a;
  2470. m_sleepyUpdates[child] = b;
  2471. a->friend_setIndexInLogic(i);
  2472. b->friend_setIndexInLogic(child);
  2473. i = child;
  2474. child = ((i+1)<<1)-1;
  2475. }
  2476. #endif
  2477. return i;
  2478. }
  2479. // ------------------------------------------------------------------------------------------------
  2480. void GameLogic::rebalanceSleepyUpdate(Int i)
  2481. {
  2482. USE_PERF_TIMER(SleepyMaintenance)
  2483. i = rebalanceParentSleepyUpdate(i);
  2484. i = rebalanceChildSleepyUpdate(i);
  2485. }
  2486. // ------------------------------------------------------------------------------------------------
  2487. void GameLogic::remakeSleepyUpdate()
  2488. {
  2489. USE_PERF_TIMER(SleepyMaintenance)
  2490. Int parent = m_sleepyUpdates.size() / 2;
  2491. while (true)
  2492. {
  2493. rebalanceChildSleepyUpdate(parent);
  2494. if (parent == 0)
  2495. break;
  2496. --parent;
  2497. }
  2498. validateSleepyUpdate();
  2499. }
  2500. // ------------------------------------------------------------------------------------------------
  2501. void GameLogic::pushSleepyUpdate(UpdateModulePtr u)
  2502. {
  2503. USE_PERF_TIMER(SleepyMaintenance)
  2504. DEBUG_ASSERTCRASH(u != NULL, ("You may not pass null for sleepy update info"));
  2505. m_sleepyUpdates.push_back(u);
  2506. u->friend_setIndexInLogic(m_sleepyUpdates.size() - 1);
  2507. rebalanceParentSleepyUpdate(m_sleepyUpdates.size()-1);
  2508. }
  2509. // ------------------------------------------------------------------------------------------------
  2510. UpdateModulePtr GameLogic::peekSleepyUpdate() const
  2511. {
  2512. USE_PERF_TIMER(SleepyMaintenance)
  2513. UpdateModulePtr u = m_sleepyUpdates.front();
  2514. DEBUG_ASSERTCRASH(u->friend_getIndexInLogic() == 0, ("index mismatch: expected %d, got %d\n",0,u->friend_getIndexInLogic()));
  2515. return u;
  2516. }
  2517. // ------------------------------------------------------------------------------------------------
  2518. void GameLogic::popSleepyUpdate()
  2519. {
  2520. USE_PERF_TIMER(SleepyMaintenance)
  2521. Int sz = m_sleepyUpdates.size();
  2522. if (sz == 0)
  2523. {
  2524. DEBUG_CRASH(("should not happen"));
  2525. return;
  2526. }
  2527. m_sleepyUpdates[0]->friend_setIndexInLogic(-1);
  2528. if (sz > 1)
  2529. {
  2530. m_sleepyUpdates[0] = m_sleepyUpdates[sz-1];
  2531. m_sleepyUpdates[0]->friend_setIndexInLogic(0);
  2532. m_sleepyUpdates.pop_back();
  2533. rebalanceChildSleepyUpdate(0);
  2534. }
  2535. else
  2536. {
  2537. m_sleepyUpdates.pop_back();
  2538. }
  2539. }
  2540. // ------------------------------------------------------------------------------------------------
  2541. // this should be called only by UpdateModule, thanks.
  2542. // ------------------------------------------------------------------------------------------------
  2543. //DECLARE_PERF_TIMER(friend_awakenUpdateModule)
  2544. void GameLogic::friend_awakenUpdateModule(Object* obj, UpdateModulePtr u, UnsignedInt whenToWakeUp)
  2545. {
  2546. //USE_PERF_TIMER(friend_awakenUpdateModule)
  2547. UnsignedInt now = TheGameLogic->getFrame();
  2548. DEBUG_ASSERTCRASH(whenToWakeUp >= now, ("setWakeFrame frame is in the past... are you sure this is what you want?"));
  2549. if (u == m_curUpdateModule)
  2550. {
  2551. DEBUG_CRASH(("You should not call setWakeFrame() from inside your update(), because it will be ignored, in favor of the return code from update.\n"));
  2552. return;
  2553. }
  2554. if (whenToWakeUp == u->friend_getNextCallFrame())
  2555. return; // my, that was easy
  2556. if ((now > 0) && (u->friend_getNextCallFrame() == now) && (whenToWakeUp == now + 1))
  2557. {
  2558. // subtle but important case: if we already awake, and someone calls
  2559. // setWakeFrame(self, UPDATE_SLEEP_NONE), we don't want to reset our wake frame,
  2560. // since that would prevent us from getting called THIS frame. since UPDATE_SLEEP_NONE
  2561. // really means "wake up as soon as possible", we don't want to change our status
  2562. // if we are already awake. (srj)
  2563. return;
  2564. }
  2565. Int idx = u->friend_getIndexInLogic();
  2566. if (obj->isInList(&m_objList))
  2567. {
  2568. if (idx < 0 || idx >= m_sleepyUpdates.size())
  2569. {
  2570. RELEASE_CRASH("fatal error! sleepy update module illegal index.\n");
  2571. return;
  2572. }
  2573. if (m_sleepyUpdates[idx] != u)
  2574. {
  2575. RELEASE_CRASH("fatal error! sleepy update module index mismatch.\n");
  2576. return;
  2577. }
  2578. // update the value.
  2579. u->friend_setNextCallFrame(whenToWakeUp);
  2580. // rebalance.
  2581. rebalanceSleepyUpdate(idx);
  2582. // validate. (harmless except in debug mode)
  2583. validateSleepyUpdate();
  2584. return;
  2585. }
  2586. else
  2587. {
  2588. if (idx != -1)
  2589. {
  2590. RELEASE_CRASH("fatal error! sleepy update module index mismatch.\n");
  2591. return;
  2592. }
  2593. // this can happen if stuff happens during object initialization. fortunately,
  2594. // it's easy to deal with:
  2595. u->friend_setNextCallFrame(whenToWakeUp);
  2596. return;
  2597. }
  2598. }
  2599. // ------------------------------------------------------------------------------------------------
  2600. #ifdef DO_UNIT_TIMINGS
  2601. void drawGraph( const char* style, Real scale, double value )
  2602. {
  2603. for ( Int t = 0; t < value*scale; ++t)
  2604. {
  2605. DEBUG_LOG((style));
  2606. if ( t%200 == 199 )
  2607. DEBUG_LOG(("...\n"));
  2608. }
  2609. DEBUG_LOG(("\n"));
  2610. }
  2611. enum {TIME_FRAMES=20};
  2612. enum {SETTLE_FRAMES=10};
  2613. static void unitTimings(void)
  2614. {
  2615. static Int settleFrames = 0;
  2616. static Int timeFrames = 0;
  2617. enum { INFANTRY, VEHICLE, STRUCTURE, OTHER, END};
  2618. static Int unitTypes = INFANTRY;
  2619. AsciiString sides[16];
  2620. const Int UNIT_X = 10;
  2621. const Int UNIT_Y = 10;
  2622. const Int TOTAL_UNITS = UNIT_X*UNIT_Y;
  2623. const Int UNIT_SPACING = 30;
  2624. const Int UNIT_BORDER = 30;
  2625. Int sideCount = 0;
  2626. #define no_SINGLE_UNIT "AmericaInfantryRanger"
  2627. #define DO_FACTION
  2628. #ifdef DO_FACTION
  2629. sides[sideCount++] = "America";
  2630. sides[sideCount++] = "China";
  2631. sides[sideCount++] = "GLA";
  2632. //The MissionDisk new 'sides'
  2633. sides[sideCount++] = "AmericaSuperWeaponGeneral";
  2634. sides[sideCount++] = "AmericaLaserGeneral";
  2635. sides[sideCount++] = "AmericaAirForceGeneral";
  2636. sides[sideCount++] = "ChinaTankGeneral";
  2637. sides[sideCount++] = "ChinaInfantryGeneral";
  2638. sides[sideCount++] = "ChinaNukeGeneral";
  2639. sides[sideCount++] = "GLAToxinGeneral";
  2640. sides[sideCount++] = "GLADemolitionGeneral";
  2641. sides[sideCount++] = "GLAStealthGeneral";
  2642. // sides[sideCount++] = "*"; // wildcard for unspecified side
  2643. #endif
  2644. #define DO_CIVILIAN
  2645. #ifdef DO_CIVILIAN
  2646. sides[sideCount++] = "Civilian";
  2647. #endif
  2648. #define DO_SINGLE_KIND
  2649. #ifdef DO_SINGLE_KIND
  2650. static KindOfType goalKind = KINDOF_STRUCTURE;
  2651. //static KindOfType goalKind = KINDOF_INFANTRY;
  2652. //static KindOfType goalKind = KINDOF_VEHICLE;
  2653. #endif
  2654. sides[sideCount] = "";
  2655. static bool veryFirstTime = true;
  2656. static Int side = 0;
  2657. static __int64 startTime64;
  2658. static __int64 endTime64,freq64;
  2659. static int drawCallTotal;
  2660. static enum { LOGIC, NO_PARTICLES, NO_SPAWN, ALL} mode;
  2661. static double timeAll, timeAllNoAnim, timeNoPart, timeNoSpawn, timeLogic, timeLogicNoAnim;
  2662. static float drawCallAll,drawCallNoPart,drawCallNoSpawn,drawCallLogic;
  2663. if (settleFrames>0) {
  2664. settleFrames--;
  2665. if (settleFrames>0) return;
  2666. QueryPerformanceCounter((LARGE_INTEGER *)&startTime64);
  2667. QueryPerformanceFrequency((LARGE_INTEGER *)&freq64);
  2668. timeFrames = TIME_FRAMES;
  2669. // reset the draw counter
  2670. drawCallTotal = 0;
  2671. return;
  2672. }
  2673. if (timeFrames>0) {
  2674. drawCallTotal += TheDisplay->getLastFrameDrawCalls();
  2675. timeFrames--;
  2676. if (timeFrames>0) return;
  2677. QueryPerformanceCounter((LARGE_INTEGER *)&endTime64);
  2678. double timeToUpdate = ((double)(endTime64-startTime64) / (double)(freq64));
  2679. // Real timeToUpdateMicrosec = timeToUpdate*1E6/(TIME_FRAMES * TOTAL_UNITS);
  2680. timeToUpdate *= 100.0f/TIME_FRAMES;
  2681. if (mode == LOGIC) {
  2682. timeLogic = timeToUpdate;
  2683. drawCallLogic = (float)drawCallTotal / (float)(TIME_FRAMES * TOTAL_UNITS); // 100 units for TIME_FRAMES
  2684. mode = ALL;
  2685. settleFrames = SETTLE_FRAMES;
  2686. //g_timing_no_anim = true;
  2687. Coord3D thePos;
  2688. thePos.x = 50;
  2689. thePos.y = 50;
  2690. thePos.z = 0;
  2691. TheTacticalView->lookAt( &thePos );
  2692. return;
  2693. }
  2694. if (mode == ALL) {
  2695. timeAll = timeToUpdate;
  2696. drawCallAll = (float)drawCallTotal / (float)(TIME_FRAMES * TOTAL_UNITS); // 100 units for TIME_FRAMES
  2697. mode = NO_PARTICLES;
  2698. settleFrames = SETTLE_FRAMES;
  2699. if (TheParticleSystemManager->getParticleCount()>1) {
  2700. TheParticleSystemManager->reset();
  2701. DEBUG_LOG(("Starting noParticles - \n"));
  2702. }
  2703. return;
  2704. }
  2705. if (mode == NO_PARTICLES) {
  2706. timeNoPart = timeToUpdate;
  2707. drawCallNoPart = (float)drawCallTotal / (float)(TIME_FRAMES * TOTAL_UNITS); // 100 units for TIME_FRAMES
  2708. mode = NO_SPAWN;
  2709. Object *obj = TheGameLogic->getFirstObject();
  2710. Bool gotSpawn;
  2711. while (obj) {
  2712. if (obj->getTemplate() != g_UT_curThing) {
  2713. TheGameLogic->destroyObject(obj);
  2714. gotSpawn = true;
  2715. }
  2716. obj = obj->getNextObject();
  2717. }
  2718. if (gotSpawn) {
  2719. DEBUG_LOG(("Starting noSpawn - \n"));
  2720. settleFrames = SETTLE_FRAMES;
  2721. return;
  2722. }
  2723. }
  2724. if (mode==NO_SPAWN) {
  2725. timeNoSpawn = timeToUpdate;
  2726. drawCallNoSpawn = (float)drawCallTotal / (float)(TIME_FRAMES * TOTAL_UNITS); // 100 units for TIME_FRAMES
  2727. }
  2728. if (g_UT_curThing==NULL) return;
  2729. char remark[2048];
  2730. Real graphScale = 20.0f;
  2731. AsciiString thingName = g_UT_curThing->getName();
  2732. if (veryFirstTime) {
  2733. thingName = "No Object";
  2734. }
  2735. sprintf(remark, "All %f: (%d ms) for %d %s's\n", timeAll, (Int)(timeAll*1000/TIME_FRAMES), TOTAL_UNITS, thingName.str() );
  2736. DEBUG_LOG((remark));
  2737. drawGraph( "@", graphScale, timeAll );
  2738. sprintf(remark, "Without Particles %f\n", timeNoPart);
  2739. DEBUG_LOG((remark));
  2740. drawGraph( "@", graphScale, timeNoPart );
  2741. sprintf(remark, "Without Spawn %f \n", timeNoSpawn );
  2742. DEBUG_LOG((remark));
  2743. drawGraph( "@", graphScale, timeNoSpawn );
  2744. sprintf(remark, "Logic %f \n", timeLogic);
  2745. DEBUG_LOG((remark));
  2746. drawGraph( "@", graphScale, timeLogic );
  2747. sprintf(remark, "DrawCalls for %s \n", thingName.str() ) ;
  2748. DEBUG_LOG((remark));
  2749. sprintf(remark, "All %f\n", drawCallAll );
  2750. DEBUG_LOG((remark));
  2751. drawGraph( "#", graphScale, drawCallAll );
  2752. sprintf(remark, "Without Particles %f\n", drawCallNoPart );
  2753. DEBUG_LOG((remark));
  2754. drawGraph( "#", graphScale, drawCallNoPart );
  2755. sprintf(remark, "Without Spawn %f \n", drawCallNoSpawn );
  2756. DEBUG_LOG((remark));
  2757. drawGraph( "#", graphScale, drawCallNoSpawn );
  2758. sprintf(remark, "Draw Call Logic %f \n", drawCallLogic );
  2759. DEBUG_LOG((remark));
  2760. drawGraph( "#", graphScale, drawCallLogic );
  2761. if (g_UT_timingLog) {
  2762. fputs(remark, g_UT_timingLog);
  2763. }
  2764. if (g_UT_commaLog) {
  2765. AsciiString type;
  2766. if (unitTypes == INFANTRY) {
  2767. type="Infantry";
  2768. } else if (unitTypes == VEHICLE) {
  2769. type="Vehicle";
  2770. } else if (unitTypes == STRUCTURE) {
  2771. type="Structure";
  2772. } else {
  2773. type="Other";
  2774. }
  2775. AsciiString modelName;
  2776. ModelConditionFlags state;
  2777. state.clear();
  2778. const ModuleInfo& mi = g_UT_curThing->getDrawModuleInfo();
  2779. if (mi.getCount() > 0)
  2780. {
  2781. const ModuleData* mdd = mi.getNthData(0);
  2782. const W3DModelDrawModuleData* md = mdd ? mdd->getAsW3DModelDrawModuleData() : NULL;
  2783. if (md)
  2784. {
  2785. modelName = md->getBestModelNameForWB(state);
  2786. }
  2787. }
  2788. if (veryFirstTime) {
  2789. modelName = "**NO MODEL**";
  2790. veryFirstTime = false;
  2791. }
  2792. sprintf(remark, "%f,%d,%f,%d,%f,%d,%f,%d,%s,%s,%s,%s,%f,%f,%f\n", timeAll,
  2793. (Int)(timeAll*1000/TIME_FRAMES),timeNoPart,
  2794. (Int)(timeNoPart*1000/TIME_FRAMES),timeNoSpawn,
  2795. (Int)(timeNoSpawn*1000/TIME_FRAMES),timeLogic,
  2796. (Int)(timeLogic*1000/TIME_FRAMES), thingName.str(), modelName.str(), type.str(),
  2797. sides[side].str(),
  2798. drawCallAll,drawCallNoPart,drawCallNoSpawn);
  2799. fputs(remark, g_UT_commaLog);
  2800. }
  2801. TheParticleSystemManager->reset();
  2802. g_UT_gotUnit = false;
  2803. }
  2804. #ifdef SINGLE_UNIT
  2805. if (g_UT_curThing && g_UT_startTiming) {
  2806. if (g_UT_curThing->getName()==SINGLE_UNIT) {
  2807. if (g_UT_timingLog) {
  2808. fclose(g_UT_timingLog);
  2809. g_UT_timingLog = NULL;
  2810. }
  2811. if (g_UT_commaLog) {
  2812. fclose(g_UT_commaLog);
  2813. g_UT_commaLog = NULL;
  2814. }
  2815. return;
  2816. }
  2817. while (g_UT_curThing->friend_getNextTemplate()
  2818. && g_UT_curThing->friend_getNextTemplate()->getName()!=SINGLE_UNIT)
  2819. g_UT_curThing = g_UT_curThing->friend_getNextTemplate();
  2820. }
  2821. #endif
  2822. Object *obj = TheGameLogic->getFirstObject();
  2823. while (obj) {
  2824. TheGameLogic->destroyObject(obj);
  2825. obj = obj->getNextObject();
  2826. }
  2827. if (g_UT_startTiming && g_UT_curThing && !g_UT_gotUnit) {
  2828. TheWritableGlobalData->m_framesPerSecondLimit = 10000;
  2829. TheWritableGlobalData->m_useFpsLimit = false;
  2830. while (!g_UT_gotUnit) {
  2831. if (veryFirstTime) {
  2832. g_UT_gotUnit = true;
  2833. break;
  2834. }
  2835. g_UT_curThing = g_UT_curThing->friend_getNextTemplate();
  2836. if (g_UT_curThing == NULL) {
  2837. unitTypes++;
  2838. if (unitTypes==END) {
  2839. side++;
  2840. unitTypes = INFANTRY;
  2841. if (sides[side].isEmpty() ) // end of sides list
  2842. {
  2843. g_UT_startTiming = false;
  2844. if (g_UT_timingLog)
  2845. {
  2846. fclose(g_UT_timingLog);
  2847. g_UT_timingLog = NULL;
  2848. }
  2849. if (g_UT_commaLog)
  2850. {
  2851. fclose(g_UT_commaLog);
  2852. g_UT_commaLog = NULL;
  2853. }
  2854. break;
  2855. }
  2856. }
  2857. g_UT_curThing = TheThingFactory->firstTemplate();
  2858. }
  2859. const ThingTemplate* btt = g_UT_curThing;
  2860. #ifndef SINGLE_UNIT
  2861. Bool unspecified = FALSE;
  2862. if (btt->getDefaultOwningSide() != sides[side])
  2863. {
  2864. if (sides[side] == "*")
  2865. {
  2866. if ( btt->getDefaultOwningSide() == ("") )// wildcard for unspecified side
  2867. unspecified = TRUE;
  2868. else
  2869. continue;
  2870. }
  2871. else
  2872. continue;
  2873. }
  2874. if (unitTypes == INFANTRY) {
  2875. if (!btt->isKindOf(KINDOF_INFANTRY)) continue;
  2876. } else if (unitTypes == VEHICLE) {
  2877. if (!btt->isKindOf(KINDOF_VEHICLE)) continue;
  2878. } else if (unitTypes == STRUCTURE) {
  2879. if (!btt->isKindOf(KINDOF_STRUCTURE)) continue;
  2880. } else {
  2881. if (btt->isKindOf(KINDOF_INFANTRY)) continue;
  2882. if (btt->isKindOf(KINDOF_VEHICLE)) continue;
  2883. if (btt->isKindOf(KINDOF_STRUCTURE)) continue;
  2884. }
  2885. #endif
  2886. #ifdef DO_SINGLE_KIND
  2887. if (!btt->isKindOf(goalKind)) continue;
  2888. #endif
  2889. static char *illegalTemplateNames[] =
  2890. {
  2891. "EMPPulseBomb",
  2892. "GLAAngryMobRockProjectileObject",
  2893. "ClusterMinesBomb",
  2894. "BlackNapalmFirestormSmall",
  2895. "CabooseFullOfTerrorists",
  2896. "GLAAngryMobMolotovCocktailProjectileObject",
  2897. "Firestorm",
  2898. "Avalanche",
  2899. "InfernoTankShell",
  2900. "ChinaArtilleryBarrageShell",
  2901. "ChinaTankOverlordBattleBunker",
  2902. "ChinaTankOverlordPropagandaTower",
  2903. "ChinaTankOverlordGattlingCannon",
  2904. "CINE",
  2905. "GLAInfantryAngryMobNexus",
  2906. "AircraftCarrier",
  2907. "GermanMuseum",
  2908. "Cin_",
  2909. "Amb_",
  2910. "Ambient",
  2911. "GC_",
  2912. "SpecialEffectsTrainCrashObject",
  2913. NULL
  2914. };
  2915. Bool skip = FALSE;
  2916. for ( Int test = 0; test < sizeof( illegalTemplateNames ) ; ++test )
  2917. {
  2918. if ( illegalTemplateNames[test] == NULL )
  2919. break;
  2920. if (btt->getName().startsWith(illegalTemplateNames[test]))
  2921. {
  2922. skip = TRUE;
  2923. break;
  2924. }
  2925. if (btt->getName().endsWith(illegalTemplateNames[test]))
  2926. {
  2927. skip = TRUE;
  2928. break;
  2929. }
  2930. if (btt->getName() == illegalTemplateNames[test] )
  2931. {
  2932. skip = TRUE;
  2933. break;
  2934. }
  2935. }
  2936. if ( skip )
  2937. continue;
  2938. // if (btt->getName() endsWith("EMPPulseBomb")) continue; // 100 overloads system.
  2939. // if (btt->getName() endsWith("GLAAngryMobRockProjectileObject")) continue; // 100 overloads system.
  2940. // if (btt->getName() endsWith("ClusterMinesBomb")) continue; // 100 overloads system.
  2941. // if (btt->getName() endsWith("BlackNapalmFirestormSmall")) continue; // 100 overloads system.
  2942. // if (btt->getName() endsWith("CabooseFullOfTerrorists")) continue; // 100 overloads system.
  2943. // if (btt->getName() endsWith("GLAAngryMobMolotovCocktailProjectileObject")) continue; // 100 overloads system.
  2944. // if (btt->getName().startsWith("Firestorm")) continue; // 100 crashes
  2945. // if (btt->getName().startsWith("Avalanche")) continue; // 100 crashes
  2946. // if (btt->getName().startsWith("InfernoTankShell")) continue; // 100 crashes
  2947. //
  2948. // if (btt->getName() endsWith("ChinaArtilleryBarrageShell") continue; // 100 takes really, freaking long. Doesn't crash jba.
  2949. // if (btt->getName() endsWith("ChinaTankOverlordBattleBunker") continue; // 100 seems to hang gth.
  2950. // if (btt->getName() endsWith("ChinaTankOverlordPropagandaTower") continue; // 100 seems to hang gth.
  2951. // if (btt->getName() endsWith("ChinaTankOverlordGattlingCannon") continue; // 100 seems to hang gth.
  2952. // if (btt->getName().startsWith("CINE")) continue;
  2953. // if (btt->getName() endsWith("GLAInfantryAngryMobNexus") continue;
  2954. //
  2955. // //missiondisk perps
  2956. //
  2957. // if (btt->getName() == "AmericaAircraftCarrier") continue;
  2958. #ifdef SINGLE_UNIT
  2959. if (btt->getName()!=SINGLE_UNIT) {
  2960. DEBUG_LOG(("Skipping %s\n", btt->getName().str()));
  2961. continue;
  2962. }
  2963. #endif
  2964. DEBUG_LOG(("\n===Doing thing %s ===\n", btt->getName().str()));
  2965. #define dont_DO_ATTACK
  2966. #ifdef DO_ATTACK
  2967. Coord3D attackedPos;
  2968. attackedPos.x = UNIT_SPACING * 4.5 + UNIT_BORDER;
  2969. attackedPos.y = UNIT_SPACING * 4.5 + UNIT_BORDER;
  2970. attackedPos.z = TheTerrainLogic->getGroundHeight( attackedPos.x, attackedPos.y );
  2971. #endif
  2972. Int i, j;
  2973. for (i=0; i<10; i++) {
  2974. for (j=0; j<10; j++) {
  2975. Coord3D pos;
  2976. pos.x = UNIT_SPACING*i+UNIT_BORDER;
  2977. pos.y = UNIT_SPACING*j+UNIT_BORDER;
  2978. pos.z = TheTerrainLogic->getGroundHeight( pos.x, pos.y );
  2979. Team *team = ThePlayerList->getNthPlayer(1)->getDefaultTeam();
  2980. Object *obj = TheThingFactory->newObject( btt, team );
  2981. if (obj==NULL) break;
  2982. #define dont_DO_TREE 1
  2983. #ifdef DO_TREE
  2984. TheGameLogic->destroyObject(obj);
  2985. externalAddTree(pos, 1.0f, 0.0f, "TreeOakFall1");
  2986. g_UT_gotUnit = true;
  2987. #else
  2988. if (obj)
  2989. {
  2990. g_UT_gotUnit = true;
  2991. obj->setOrientation(0);
  2992. obj->setPosition( &pos );
  2993. // Now onCreates were called at the constructor. This magically created
  2994. // thing needs to be considered as Built for Game specific stuff.
  2995. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  2996. {
  2997. CreateModuleInterface* create = (*m)->getCreate();
  2998. if (!create)
  2999. continue;
  3000. create->onBuildComplete();
  3001. }
  3002. // Since the team now has members, activate it.
  3003. team->setActive();
  3004. TheAI->pathfinder()->addObjectToPathfindMap(obj);
  3005. #ifdef DO_ATTACK
  3006. AIUpdateInterface *myAI = obj->getAI();
  3007. if(myAI)
  3008. {
  3009. myAI->aiAttackPosition(&attackedPos, 9999, CMD_FROM_AI);
  3010. }
  3011. #endif
  3012. }
  3013. #endif
  3014. }
  3015. }
  3016. }
  3017. if (g_UT_gotUnit) {
  3018. settleFrames = TIME_FRAMES/2;
  3019. Coord3D thePos;
  3020. thePos.x = 5000;
  3021. thePos.y = 50;
  3022. thePos.z = 0;
  3023. TheTacticalView->lookAt( &thePos );
  3024. mode = LOGIC;
  3025. return;
  3026. }
  3027. }
  3028. }
  3029. #endif
  3030. DECLARE_PERF_TIMER(GameLogic_update)
  3031. DECLARE_PERF_TIMER(GameLogic_update_normal)
  3032. DECLARE_PERF_TIMER(GameLogic_update_sleepy)
  3033. #ifdef DUMP_PERF_STATS
  3034. extern __int64 Total_Get_Texture_Time;
  3035. extern __int64 Total_Get_HAnim_Time;
  3036. extern __int64 Total_Create_Render_Obj_Time;
  3037. extern __int64 Total_Load_3D_Assets;
  3038. #endif
  3039. // ------------------------------------------------------------------------------------------------
  3040. /** Update all objects in the world by invoking their update() methods. */
  3041. // ------------------------------------------------------------------------------------------------
  3042. void GameLogic::update( void )
  3043. {
  3044. USE_PERF_TIMER(GameLogic_update)
  3045. LatchRestore<Bool> inUpdateLatch(m_isInUpdate, TRUE);
  3046. #ifdef DO_UNIT_TIMINGS
  3047. unitTimings();
  3048. #endif
  3049. setFPMode();
  3050. /// @todo remove this hack
  3051. if ( m_startNewGame && !TheDisplay->isMoviePlaying())
  3052. {
  3053. #ifdef DUMP_PERF_STATS
  3054. Total_Get_Texture_Time=0;
  3055. Total_Get_HAnim_Time=0;
  3056. Total_Create_Render_Obj_Time=0;
  3057. Total_Load_3D_Assets=0;
  3058. #endif
  3059. #ifdef _PROFILE
  3060. Profile::StartRange("map_load");
  3061. #endif
  3062. startNewGame( FALSE );
  3063. #ifdef _PROFILE
  3064. Profile::StopRange("map_load");
  3065. #endif
  3066. m_startNewGame = FALSE;
  3067. #ifdef DUMP_PERF_STATS
  3068. char Buf[1024];
  3069. __int64 freq64;
  3070. GetPrecisionTimerTicksPerSec(&freq64);
  3071. sprintf(Buf,"Texture=%f, Anim=%f, CreateRobj=%f, Load3DAssets=%f\n",
  3072. ((double)Total_Get_Texture_Time/(double)(freq64)*1000.0),
  3073. ((double)Total_Get_HAnim_Time/(double)(freq64)*1000.0),
  3074. ((double)Total_Create_Render_Obj_Time/(double)(freq64)*1000.0),
  3075. ((double)Total_Load_3D_Assets/(double)(freq64)*1000.0));
  3076. DEBUG_LOG(("%s", Buf));
  3077. #endif
  3078. }
  3079. // send the current time to the GameClient
  3080. DEBUG_ASSERTCRASH(TheGameLogic == this, ("hmm, TheGameLogic is not right"));
  3081. UnsignedInt now = TheGameLogic->getFrame();
  3082. TheGameClient->setFrame(now);
  3083. // update (execute) scripts
  3084. {
  3085. TheScriptEngine->UPDATE();
  3086. }
  3087. Bool freezeTime = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
  3088. freezeTime = freezeTime || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
  3089. if (freezeTime)
  3090. {
  3091. if (TheCommandList->containsMessageOfType(GameMessage::MSG_CLEAR_GAME_DATA))
  3092. {
  3093. TheScriptEngine->forceUnfreezeTime();
  3094. }
  3095. else
  3096. {
  3097. /// @todo - make sure this never happens during a network game. jba.
  3098. return;
  3099. }
  3100. }
  3101. // Note - TerrainLogic update needs to happen after ScriptEngine update, but before object updates. jba.
  3102. // This way changes in bridges are noted in the script engine before being cleared in TerrainLogic->update
  3103. {
  3104. TheTerrainLogic->UPDATE();
  3105. }
  3106. // force CRC calculation, so we can keep a cache of the last N CRCs. We do this right where the recorder
  3107. // would be getting the CRC anyway, so replays can get the CRCs from the exact instant in time as the original.
  3108. Bool isMPGameOrReplay = (TheRecorder && TheRecorder->isMultiplayer() && getGameMode() != GAME_SHELL && getGameMode() != GAME_NONE);
  3109. Bool isSoloGameOrReplay = (TheRecorder && !TheRecorder->isMultiplayer() && getGameMode() != GAME_SHELL && getGameMode() != GAME_NONE);
  3110. Bool generateForMP = (isMPGameOrReplay && (m_frame % TheGameInfo->getCRCInterval()) == 0);
  3111. #if defined(_DEBUG) || defined(_INTERNAL)
  3112. Bool generateForSolo = isSoloGameOrReplay && ((m_frame && (m_frame%100 == 0)) ||
  3113. (getFrame() > TheCRCFirstFrameToLog && getFrame() < TheCRCLastFrameToLog && ((m_frame % REPLAY_CRC_INTERVAL) == 0)));
  3114. #else
  3115. Bool generateForSolo = isSoloGameOrReplay && ((m_frame % REPLAY_CRC_INTERVAL) == 0);
  3116. #endif // defined(_DEBUG) || defined(_INTERNAL)
  3117. if (generateForSolo || generateForMP)
  3118. {
  3119. m_CRC = getCRC( CRC_RECALC );
  3120. if (isMPGameOrReplay)
  3121. {
  3122. GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_LOGIC_CRC );
  3123. msg->appendIntegerArgument( m_CRC );
  3124. msg->appendBooleanArgument( (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_PLAYBACK) ); // playback CRC
  3125. //DEBUG_LOG(("Appended CRC of %8.8X on frame %d\n", m_CRC, m_frame));
  3126. }
  3127. else
  3128. {
  3129. GameMessage *msg = TheMessageStream->appendMessage( GameMessage::MSG_LOGIC_CRC );
  3130. msg->appendIntegerArgument( m_CRC );
  3131. msg->appendBooleanArgument( (TheRecorder && TheRecorder->getMode() == RECORDERMODETYPE_PLAYBACK) ); // playback CRC
  3132. //DEBUG_LOG(("Appended Playback CRC of %8.8X on frame %d\n", m_CRC, m_frame));
  3133. }
  3134. }
  3135. // collect stats
  3136. if(TheStatsCollector)
  3137. {
  3138. TheStatsCollector->update();
  3139. }
  3140. // Update the Recorder
  3141. {
  3142. TheRecorder->UPDATE();
  3143. }
  3144. // process client commands
  3145. {
  3146. processCommandList( TheCommandList );
  3147. }
  3148. #ifdef ALLOW_NONSLEEPY_UPDATES
  3149. {
  3150. for (std::list<UpdateModulePtr>::const_iterator it = m_normalUpdates.begin(); it != m_normalUpdates.end(); ++it)
  3151. {
  3152. UpdateModulePtr u = *it;
  3153. DisabledMaskType dis = u->friend_getObject()->getDisabledFlags();
  3154. if (!dis.any() || dis.anyIntersectionWith(u->getDisabledTypesToProcess()))
  3155. {
  3156. USE_PERF_TIMER(GameLogic_update_normal)
  3157. m_curUpdateModule = u;
  3158. #ifdef DEBUG_LOGGING
  3159. UpdateSleepTime sleep = u->update();
  3160. DEBUG_ASSERTCRASH(sleep == UPDATE_SLEEP_NONE, ("you must return SLEEPNONE from all nonsleepy modules"));
  3161. #else
  3162. u->update();
  3163. #endif
  3164. m_curUpdateModule = NULL;
  3165. }
  3166. }
  3167. }
  3168. #endif
  3169. {
  3170. while (!m_sleepyUpdates.empty())
  3171. {
  3172. UpdateModulePtr u = peekSleepyUpdate();
  3173. if (!u)
  3174. {
  3175. DEBUG_CRASH(("Null update. should not happen."));
  3176. continue;
  3177. }
  3178. // we're done, everyone else is sleeping.
  3179. // break from the loop BEFORE we pop this item off.
  3180. if (u->friend_getNextCallFrame() > now)
  3181. {
  3182. break;
  3183. }
  3184. UpdateSleepTime sleepLen = UPDATE_SLEEP_NONE; // default, if it is disabled.
  3185. DisabledMaskType dis = u->friend_getObject()->getDisabledFlags();
  3186. if (!dis.any() || dis.anyIntersectionWith(u->getDisabledTypesToProcess()))
  3187. {
  3188. USE_PERF_TIMER(GameLogic_update_sleepy)
  3189. //DEBUG_LOG(("calling update %08lx (%d %d)... ",update,update->friend_getNextCallFrame(),update->friend_getNextCallPhase()));
  3190. m_curUpdateModule = u;
  3191. sleepLen = u->update();
  3192. DEBUG_ASSERTCRASH(sleepLen > 0, ("you may not return 0 from update"));
  3193. if (sleepLen < 1)
  3194. sleepLen = UPDATE_SLEEP_NONE;
  3195. m_curUpdateModule = NULL;
  3196. }
  3197. // else defer it till next frame and re-push it
  3198. u->friend_setNextCallFrame(now + sleepLen);
  3199. rebalanceSleepyUpdate(0);
  3200. }
  3201. }
  3202. validateSleepyUpdate();
  3203. // update the Artificial Intelligence system
  3204. {
  3205. TheAI->UPDATE();
  3206. }
  3207. // production updates
  3208. {
  3209. TheBuildAssistant->UPDATE();
  3210. }
  3211. // update partition info
  3212. {
  3213. ThePartitionManager->UPDATE();
  3214. }
  3215. //
  3216. // End of frame clean-up
  3217. //
  3218. // destroy all pending objects
  3219. processDestroyList();
  3220. // reset the command list, destroying all messages
  3221. TheCommandList->reset();
  3222. TheWeaponStore->UPDATE();
  3223. TheLocomotorStore->UPDATE();
  3224. TheVictoryConditions->UPDATE();
  3225. #ifdef DO_COPY_PROTECTION
  3226. if (!isInShellGame() && isInGame())
  3227. {
  3228. if ((m_frame == 1024) && !CopyProtect::validate())
  3229. {
  3230. DEBUG_LOG(("Copy protection failed - bailing"));
  3231. GameMessage *msg = TheMessageStream->appendMessage(GameMessage::MSG_SELF_DESTRUCT);
  3232. msg->appendBooleanArgument(FALSE);
  3233. }
  3234. }
  3235. #endif
  3236. {
  3237. //Handle disabled statii (and re-enable objects once frame matches)
  3238. for( Object *obj = m_objList; obj; obj = obj->getNextObject() )
  3239. {
  3240. if( obj->isDisabled() )
  3241. {
  3242. obj->checkDisabledStatus();
  3243. }
  3244. }
  3245. }
  3246. // increment world time
  3247. if (!m_startNewGame)
  3248. {
  3249. m_frame++;
  3250. }
  3251. }
  3252. // ------------------------------------------------------------------------------------------------
  3253. /** Return the first object in the world list */
  3254. // ------------------------------------------------------------------------------------------------
  3255. Object *GameLogic::getFirstObject( void )
  3256. {
  3257. return m_objList;
  3258. }
  3259. // ------------------------------------------------------------------------------------------------
  3260. /** Return a new unique object id. */
  3261. // ------------------------------------------------------------------------------------------------
  3262. ObjectID GameLogic::allocateObjectID( void )
  3263. {
  3264. /// @todo Find unused value in current object set
  3265. ObjectID ret = m_nextObjID;
  3266. m_nextObjID = (ObjectID)((UnsignedInt)m_nextObjID + 1);
  3267. return ret;
  3268. }
  3269. // ------------------------------------------------------------------------------------------------
  3270. /** Add object ID to the lookup table */
  3271. // ------------------------------------------------------------------------------------------------
  3272. void GameLogic::addObjectToLookupTable( Object *obj )
  3273. {
  3274. // sanity
  3275. if( obj == NULL )
  3276. return;
  3277. // add to lookup
  3278. // m_objHash[ obj->getID() ] = obj;
  3279. ObjectID newID = obj->getID();
  3280. while( newID >= m_objVector.size() ) // Fail case is hella rare, so faster to double up on size() call
  3281. m_objVector.resize(m_objVector.size() * 2, NULL);
  3282. m_objVector[ newID ] = obj;
  3283. } // end addObjectToLookupTable
  3284. // ------------------------------------------------------------------------------------------------
  3285. /** Remove object from the ID lookup table */
  3286. // ------------------------------------------------------------------------------------------------
  3287. void GameLogic::removeObjectFromLookupTable( Object *obj )
  3288. {
  3289. // sanity
  3290. if( obj == NULL )
  3291. return;
  3292. // remove from lookup table
  3293. // m_objHash.erase( obj->getID() );
  3294. m_objVector[ obj->getID() ] = NULL;
  3295. } // end removeObjectFromLookupTable
  3296. // ------------------------------------------------------------------------------------------------
  3297. /** Given an object, register it with the GameLogic and give it a unique ID. */
  3298. // ------------------------------------------------------------------------------------------------
  3299. void GameLogic::registerObject( Object *obj )
  3300. {
  3301. // add the object to the global list
  3302. obj->prependToList(&m_objList);
  3303. // add object to lookup table
  3304. addObjectToLookupTable( obj );
  3305. UnsignedInt now = TheGameLogic->getFrame();
  3306. if (now == 0)
  3307. now = 1;
  3308. for (BehaviorModule** b = obj->getBehaviorModules(); *b; ++b)
  3309. {
  3310. #ifdef DIRECT_UPDATEMODULE_ACCESS
  3311. // evil, but necessary at this point. (srj)
  3312. UpdateModulePtr u = (UpdateModulePtr)((*b)->getUpdate());
  3313. #else
  3314. UpdateModulePtr u = (*b)->getUpdate();
  3315. #endif
  3316. if (!u)
  3317. continue;
  3318. UnsignedInt when = u->friend_getNextCallFrame();
  3319. #ifdef ALLOW_NONSLEEPY_UPDATES
  3320. if (when == 0)
  3321. {
  3322. // zero is the magic value for "never sleeps"
  3323. m_normalUpdates.push_back(u);
  3324. }
  3325. else
  3326. #else
  3327. // note that 'when' can be zero here for any update module
  3328. // that didn't bother to call setWakeFrame() in its ctor.
  3329. // this is legal.
  3330. if (when == 0)
  3331. u->friend_setNextCallFrame(now);
  3332. #endif
  3333. {
  3334. DEBUG_ASSERTCRASH(u->friend_getNextCallFrame() >= now, ("you may not specify a zero initial sleep time for sleepy modules (%d %d)",u->friend_getNextCallFrame(),now));
  3335. pushSleepyUpdate(u);
  3336. }
  3337. }
  3338. }
  3339. // ------------------------------------------------------------------------------------------------
  3340. /** create an object based on the thing template, the reason that this is
  3341. * here and not in the ThingFactory is so that we can mirror what the
  3342. * creation process is on the client side because clients have specific
  3343. * device dependent drawables (such as a W3DDrawable derived from Drawable).
  3344. * here we will allocate an object of the correct type based on thing
  3345. * template properties
  3346. *
  3347. * if we want to have the thing manager actually contain the pools of
  3348. * object and drawable storage it seems OK to have it be friends with the
  3349. * GameLogic/Client for those purposes, or we could put the allocation pools
  3350. * in the GameLogic and GameClient themselves */
  3351. // ------------------------------------------------------------------------------------------------
  3352. Object *GameLogic::friend_createObject( const ThingTemplate *thing, const ObjectStatusMaskType &statusBits, Team *team )
  3353. {
  3354. Object *obj;
  3355. obj = newInstance(Object)( thing, statusBits, team );
  3356. return obj;
  3357. }
  3358. // ------------------------------------------------------------------------------------------------
  3359. /** Mark the object as destroyed, and place on list for deletion at the end of the next update.
  3360. * This is the only interface to destroy objects - objects cannot be directly deleted. */
  3361. // ------------------------------------------------------------------------------------------------
  3362. void GameLogic::destroyObject( Object *obj )
  3363. {
  3364. DEBUG_ASSERTCRASH(obj != NULL, ("destroying null object"));
  3365. // if already flagged for destruction, ignore
  3366. if (!obj || obj->isDestroyed())
  3367. return;
  3368. // run the object onDestroy event if provied
  3369. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  3370. {
  3371. DestroyModuleInterface* destroy = (*m)->getDestroy();
  3372. if (destroy)
  3373. destroy->onDestroy();
  3374. }
  3375. // mark object as destroyed
  3376. obj->setStatus( MAKE_OBJECT_STATUS_MASK( OBJECT_STATUS_DESTROYED ) );
  3377. // We desperately need to stop here, or else the destructor of the statemachine will try to do
  3378. // stopping logic, which uses virtual functions and deleted modules, which will crash us.
  3379. AIUpdateInterface *ai = obj->getAIUpdateInterface();
  3380. if( ai )
  3381. {
  3382. ai->setLocomotorGoalNone();
  3383. ai->destroyPath();
  3384. }
  3385. // add to end of destruction list, in case something is being destroyed and trying to destroy subobjects
  3386. m_objectsToDestroy.push_back(obj);
  3387. // run any on destroy logic internal to the object
  3388. obj->onDestroy();
  3389. // remove wall pieces from the pathfinder
  3390. if( obj->isKindOf( KINDOF_WALK_ON_TOP_OF_WALL ) )
  3391. TheAI->pathfinder()->removeWallPiece( obj );
  3392. //Clean up special power shortcut bars
  3393. if( obj->hasAnySpecialPower() )
  3394. {
  3395. if( ThePlayerList->getLocalPlayer() == obj->getControllingPlayer() )
  3396. {
  3397. TheControlBar->markUIDirty();
  3398. }
  3399. }
  3400. } // end destroyObject
  3401. // ------------------------------------------------------------------------------------------------
  3402. // ------------------------------------------------------------------------------------------------
  3403. Bool inCRCGen = FALSE;
  3404. UnsignedInt GameLogic::getCRC( Int mode, AsciiString deepCRCFileName )
  3405. {
  3406. if (mode != CRC_RECALC)
  3407. return m_CRC;
  3408. setFPMode();
  3409. LatchRestore<Bool> latch(inCRCGen, !isInGameLogicUpdate());
  3410. XferCRC *xferCRC;
  3411. AsciiString marker;
  3412. if (deepCRCFileName.isNotEmpty())
  3413. {
  3414. xferCRC = NEW XferDeepCRC;
  3415. xferCRC->open(deepCRCFileName.str());
  3416. }
  3417. else
  3418. {
  3419. AsciiString crcName;
  3420. #ifdef DEBUG_CRC
  3421. if (isInGameLogicUpdate() && g_keepCRCSaves && m_frame < 5)
  3422. {
  3423. xferCRC = NEW XferDeepCRC;
  3424. crcName.format("logicFrame%d.crc", (m_frame%5));
  3425. }
  3426. else
  3427. #endif DEBUG_CRC
  3428. {
  3429. xferCRC = NEW XferCRC;
  3430. crcName = "lightCRC";
  3431. }
  3432. xferCRC->open(crcName);
  3433. }
  3434. // calculate CRCs
  3435. Object *obj;
  3436. DEBUG_ASSERTCRASH(this == TheGameLogic, ("Not in GameLogic"));
  3437. if (isInGameLogicUpdate())
  3438. {
  3439. CRCGEN_LOG(("CRC at start of frame %d is 0x%8.8X\n", m_frame, xferCRC->getCRC()));
  3440. }
  3441. marker = "MARKER:Objects";
  3442. xferCRC->xferAsciiString(&marker);
  3443. for( obj = m_objList; obj; obj=obj->getNextObject() )
  3444. {
  3445. xferCRC->xferSnapshot( obj );
  3446. }
  3447. UnsignedInt seed = GetGameLogicRandomSeedCRC();
  3448. if (isInGameLogicUpdate())
  3449. {
  3450. CRCGEN_LOG(("CRC after objects for frame %d is 0x%8.8X\n", m_frame, xferCRC->getCRC()));
  3451. }
  3452. if (isInGameLogicUpdate())
  3453. {
  3454. CRCGEN_LOG(("RandomSeed: %d\n", seed));
  3455. }
  3456. if (xferCRC->getXferMode() == XFER_CRC)
  3457. {
  3458. xferCRC->xferUnsignedInt( &seed );
  3459. }
  3460. marker = "MARKER:ThePartitionManager";
  3461. xferCRC->xferAsciiString(&marker);
  3462. xferCRC->xferSnapshot( ThePartitionManager );
  3463. if (isInGameLogicUpdate())
  3464. {
  3465. CRCGEN_LOG(("CRC after partition manager for frame %d is 0x%8.8X\n", m_frame, xferCRC->getCRC()));
  3466. }
  3467. #ifdef DEBUG_CRC
  3468. if ((g_crcModuleDataFromClient && !isInGameLogicUpdate()) ||
  3469. (g_crcModuleDataFromLogic && isInGameLogicUpdate()))
  3470. {
  3471. marker = "MARKER:TheModuleFactory";
  3472. xferCRC->xferAsciiString(&marker);
  3473. xferCRC->xferSnapshot( TheModuleFactory );
  3474. if (isInGameLogicUpdate())
  3475. {
  3476. CRCGEN_LOG(("CRC after module factory for frame %d is 0x%8.8X\n", m_frame, xferCRC->getCRC()));
  3477. }
  3478. }
  3479. #endif DEBUG_CRC
  3480. marker = "MARKER:ThePlayerList";
  3481. xferCRC->xferAsciiString(&marker);
  3482. xferCRC->xferSnapshot( ThePlayerList );
  3483. if (isInGameLogicUpdate())
  3484. {
  3485. CRCGEN_LOG(("CRC after PlayerList for frame %d is 0x%8.8X\n", m_frame, xferCRC->getCRC()));
  3486. }
  3487. marker = "MARKER:TheAI";
  3488. xferCRC->xferAsciiString(&marker);
  3489. xferCRC->xferSnapshot( TheAI );
  3490. if (isInGameLogicUpdate())
  3491. {
  3492. CRCGEN_LOG(("CRC after AI for frame %d is 0x%8.8X\n", m_frame, xferCRC->getCRC()));
  3493. }
  3494. if (xferCRC->getXferMode() == XFER_SAVE)
  3495. {
  3496. marker = "MARKER:GameSave";
  3497. xferCRC->xferAsciiString(&marker);
  3498. TheGameState->friend_xferSaveDataForCRC(xferCRC, SNAPSHOT_DEEPCRC_LOGICONLY);
  3499. }
  3500. xferCRC->close();
  3501. UnsignedInt theCRC = xferCRC->getCRC();
  3502. delete xferCRC;
  3503. xferCRC = NULL;
  3504. if (isInGameLogicUpdate())
  3505. {
  3506. CRCGEN_LOG(("CRC for frame %d is 0x%8.8X\n", m_frame, theCRC));
  3507. }
  3508. return theCRC;
  3509. }
  3510. // ------------------------------------------------------------------------------------------------
  3511. /** A new GameLogic object has been constructed, therefore create
  3512. * a corresponding drawable and bind them together. */
  3513. // ------------------------------------------------------------------------------------------------
  3514. void GameLogic::sendObjectCreated( Object *obj )
  3515. {
  3516. Drawable *draw = TheThingFactory->newDrawable(obj->getTemplate());
  3517. /// @todo COLIN ... shouldn't we have a check here for existing drawable!!!!!
  3518. // bind drawable to object and object to drawable
  3519. bindObjectAndDrawable(obj, draw);
  3520. }
  3521. // ------------------------------------------------------------------------------------------------
  3522. void GameLogic::bindObjectAndDrawable(Object* obj, Drawable* draw)
  3523. {
  3524. draw->friend_bindToObject( obj );
  3525. obj->friend_bindToDrawable( draw );
  3526. }
  3527. // ------------------------------------------------------------------------------------------------
  3528. /** Send notification of object destruction. */
  3529. // ------------------------------------------------------------------------------------------------
  3530. void GameLogic::sendObjectDestroyed( Object *obj )
  3531. {
  3532. // Because this implementation is a bridge between the Logic and Interface,
  3533. // we must take extra care to handle such cases as when the system it
  3534. // shutting down.
  3535. if(TheGameClient == NULL)
  3536. return;
  3537. // destroy the drawable
  3538. Drawable *draw = obj->getDrawable();
  3539. if(draw)
  3540. {
  3541. TheGameClient->destroyDrawable( draw );
  3542. }
  3543. // erase the binding of the drawable to this object
  3544. obj->friend_bindToDrawable( NULL );
  3545. }
  3546. // ------------------------------------------------------------------------------------------------
  3547. /** Return if the game is paused or not */
  3548. // ------------------------------------------------------------------------------------------------
  3549. Bool GameLogic::isGamePaused( void )
  3550. {
  3551. return m_gamePaused;
  3552. }
  3553. // ------------------------------------------------------------------------------------------------
  3554. // ------------------------------------------------------------------------------------------------
  3555. void GameLogic::setGamePaused( Bool paused, Bool pauseMusic )
  3556. {
  3557. // We need to ignore an unpause called when we are unpaused or else:
  3558. // Mouse is hidden for some reason (script or something)
  3559. // GamePaused
  3560. // Remember that we were hidden
  3561. // Show mouse
  3562. // GameUnpaused
  3563. // Set mouse the way it was
  3564. // Time passes, mouse is unhidden
  3565. // GameUnpaused
  3566. // Set mouse the way it "was" <--- Was counting on right answer being set in Pause.
  3567. if( paused == m_gamePaused )
  3568. return;
  3569. m_gamePaused = paused;
  3570. AudioAffect audToAffect = (AudioAffect)(pauseMusic ? AudioAffect_All : (AudioAffect_All & ~AudioAffect_Music));
  3571. if(paused)
  3572. {
  3573. // remember the state of the mouse/input so we can return to the same state once we "unpause"
  3574. m_inputEnabledMemory = TheInGameUI->getInputEnabled();
  3575. m_mouseVisibleMemory = TheMouse->getVisibility();
  3576. // Make sure the mouse is visible and the cursor is an arrow
  3577. TheMouse->setVisibility(TRUE);
  3578. TheMouse->setCursor( Mouse::ARROW );
  3579. // if Input is enabled, disable it
  3580. if(m_inputEnabledMemory)
  3581. {
  3582. TheInGameUI->setInputEnabled(FALSE);
  3583. }
  3584. TheAudio->pauseAudio(audToAffect);
  3585. #if 0 // Kris added this code some time ago. I'm not sure why -- the pauseAudio should stop the
  3586. // ambients by itself. Everything seems to work fine without it and it's messing up my
  3587. // custom ambient code. Hopefully he can explain it to me, but until he gets back, I'm
  3588. // disabling it. -Ian
  3589. //Stop all ambient sounds!
  3590. Drawable *drawable = TheGameClient->getDrawableList();
  3591. while( drawable )
  3592. {
  3593. drawable->stopAmbientSound();
  3594. drawable = drawable->getNextDrawable();
  3595. }
  3596. #endif
  3597. }
  3598. else
  3599. {
  3600. // set the mouse/input states to what they were before we paused.
  3601. TheMouse->setVisibility(m_mouseVisibleMemory);
  3602. if(m_inputEnabledMemory)
  3603. TheInGameUI->setInputEnabled(TRUE);
  3604. TheAudio->resumeAudio(audToAffect);
  3605. #if 0
  3606. //Start all ambient sounds!
  3607. Drawable *drawable = TheGameClient->getDrawableList();
  3608. while( drawable )
  3609. {
  3610. drawable->startAmbientSound();
  3611. TheAudio->stopAllAmbientsBy( drawable );
  3612. drawable = drawable->getNextDrawable();
  3613. }
  3614. #endif
  3615. }
  3616. }
  3617. // ------------------------------------------------------------------------------------------------
  3618. // ------------------------------------------------------------------------------------------------
  3619. void GameLogic::processProgress(Int playerId, Int percentage)
  3620. {
  3621. if(m_loadScreen)
  3622. m_loadScreen->processProgress(playerId, percentage);
  3623. lastHeardFrom(playerId);
  3624. }
  3625. // ------------------------------------------------------------------------------------------------
  3626. /** Whenever we get a progress complete packet for a Net Game,
  3627. * Set a flag that that player is ready */
  3628. // ------------------------------------------------------------------------------------------------
  3629. void GameLogic::processProgressComplete(Int playerId)
  3630. {
  3631. if(playerId < 0 || playerId >= MAX_SLOTS)
  3632. {
  3633. DEBUG_ASSERTCRASH(FALSE,("GameLogic::processProgressComplete, Invalid playerid was passed in %d\n", playerId));
  3634. return;
  3635. }
  3636. if(m_progressComplete[playerId] == TRUE)
  3637. {
  3638. DEBUG_LOG(("GameLogic::processProgressComplete, playerId %d is marked TRUE already yet we're trying to mark him as true again\n", playerId));
  3639. return;
  3640. }
  3641. DEBUG_LOG(("Progress Complete for Player %d\n", playerId));
  3642. m_progressComplete[playerId] = TRUE;
  3643. lastHeardFrom(playerId);
  3644. }
  3645. // ------------------------------------------------------------------------------------------------
  3646. /// @TODO: Add check to account for timeouts
  3647. // ------------------------------------------------------------------------------------------------
  3648. Bool GameLogic::isProgressComplete( void )
  3649. {
  3650. //If we're not in a network game, always return true
  3651. if(!isInMultiplayerGame() || !TheNetwork || m_forceGameStartByTimeOut)
  3652. return TRUE;
  3653. // Only loop on the Number of players we got in here
  3654. for(Int i =0; i < MAX_SLOTS; ++i)
  3655. {
  3656. if(!m_progressComplete[i])
  3657. return FALSE;
  3658. }
  3659. return TRUE;
  3660. }
  3661. // ------------------------------------------------------------------------------------------------
  3662. // ------------------------------------------------------------------------------------------------
  3663. void GameLogic::lastHeardFrom( Int playerId )
  3664. {
  3665. if( playerId < 0 || playerId >= MAX_SLOTS)
  3666. return;
  3667. m_progressCompleteTimeout[playerId] = timeGetTime();
  3668. }
  3669. // ------------------------------------------------------------------------------------------------
  3670. // ------------------------------------------------------------------------------------------------
  3671. void GameLogic::testTimeOut( void )
  3672. {
  3673. // if everyone is loaded, lets just load the game like normal.
  3674. if(isProgressComplete())
  3675. return;
  3676. Int curTime = timeGetTime();
  3677. // Loop and test everyone in our game.
  3678. for(Int i =0; i < MAX_SLOTS; ++i)
  3679. {
  3680. // If they've completed their progress, ignore them
  3681. if(m_progressComplete[i])
  3682. continue;
  3683. if( m_progressCompleteTimeout[i] + PROGRESS_COMPLETE_TIMEOUT > curTime )
  3684. return;
  3685. }
  3686. // if we made it this far, that means everyone has timed out.
  3687. m_forceGameStartByTimeOut = TRUE;
  3688. }
  3689. // ------------------------------------------------------------------------------------------------
  3690. // ------------------------------------------------------------------------------------------------
  3691. void GameLogic::timeOutGameStart( void )
  3692. {
  3693. DEBUG_LOG(("We got the Force TimeOut Start Message\n"));
  3694. m_forceGameStartByTimeOut = TRUE;
  3695. }
  3696. // ------------------------------------------------------------------------------------------------
  3697. // ------------------------------------------------------------------------------------------------
  3698. void GameLogic::initTimeOutValues( void )
  3699. {
  3700. if (!TheNetwork)
  3701. return;
  3702. for(Int i = 0; i < TheNetwork->getNumPlayers(); ++i)
  3703. {
  3704. m_progressCompleteTimeout[i] = timeGetTime();
  3705. }
  3706. }
  3707. // ------------------------------------------------------------------------------------------------
  3708. /** returns the total number of objects in the world */
  3709. // ------------------------------------------------------------------------------------------------
  3710. UnsignedInt GameLogic::getObjectCount( void )
  3711. {
  3712. UnsignedInt totalObjects = 0;
  3713. Object *obj;
  3714. for( obj = getFirstObject(); obj; obj = obj->getNextObject() )
  3715. {
  3716. ++totalObjects;
  3717. }
  3718. return totalObjects;
  3719. }
  3720. // ------------------------------------------------------------------------------------------------
  3721. // ------------------------------------------------------------------------------------------------
  3722. GhostObjectManager *GameLogic::createGhostObjectManager(void)
  3723. {
  3724. return NEW GhostObjectManager;
  3725. }
  3726. // ------------------------------------------------------------------------------------------------
  3727. // ------------------------------------------------------------------------------------------------
  3728. TerrainLogic *GameLogic::createTerrainLogic( void )
  3729. {
  3730. return NEW TerrainLogic;
  3731. }
  3732. // ------------------------------------------------------------------------------------------------
  3733. void GameLogic::setBuildableStatusOverride(const ThingTemplate* tt, BuildableStatus bs)
  3734. {
  3735. if (tt)
  3736. {
  3737. m_thingTemplateBuildableOverrides[tt->getName()] = bs;
  3738. }
  3739. }
  3740. // ------------------------------------------------------------------------------------------------
  3741. Bool GameLogic::findBuildableStatusOverride(const ThingTemplate* tt, BuildableStatus& bs) const
  3742. {
  3743. if (tt)
  3744. {
  3745. BuildableMap::const_iterator it = m_thingTemplateBuildableOverrides.find(tt->getName());
  3746. if (it != m_thingTemplateBuildableOverrides.end())
  3747. {
  3748. bs = it->second;
  3749. return true;
  3750. }
  3751. }
  3752. return false;
  3753. }
  3754. // ------------------------------------------------------------------------------------------------
  3755. void GameLogic::setControlBarOverride(const AsciiString& commandSetName, Int slot, ConstCommandButtonPtr commandButton)
  3756. {
  3757. char buf[256];
  3758. buf[0] = '0' + slot;
  3759. strcpy(&buf[1], commandSetName.str());
  3760. m_controlBarOverrides[buf] = commandButton;
  3761. }
  3762. // ------------------------------------------------------------------------------------------------
  3763. Bool GameLogic::findControlBarOverride(const AsciiString& commandSetName, Int slot, ConstCommandButtonPtr& commandButton) const
  3764. {
  3765. char buf[256];
  3766. buf[0] = '0' + slot;
  3767. strcpy(&buf[1], commandSetName.str());
  3768. ControlBarOverrideMap::const_iterator it = m_controlBarOverrides.find(buf);
  3769. if (it != m_controlBarOverrides.end())
  3770. {
  3771. commandButton = it->second; // could be null.
  3772. return true;
  3773. }
  3774. // leave commandButton unmodified.
  3775. return false;
  3776. }
  3777. #ifdef DUMP_PERF_STATS
  3778. // ------------------------------------------------------------------------------------------------
  3779. void GameLogic::getAIMetricsStatistics( UnsignedInt *numAI, UnsignedInt *numMoving, UnsignedInt *numAttacking, UnsignedInt *numWaitingForPath, UnsignedInt *overallFailedPathfinds )
  3780. {
  3781. Object *obj;
  3782. *numAI = 0;
  3783. *numMoving = 0;
  3784. *numAttacking = 0;
  3785. *numWaitingForPath = 0;
  3786. for( obj = getFirstObject(); obj; obj = obj->getNextObject() )
  3787. {
  3788. AIUpdateInterface *ai = obj->getAI();
  3789. if( ai )
  3790. {
  3791. (*numAI)++;
  3792. if( ai->isMoving() )
  3793. {
  3794. (*numMoving)++;
  3795. }
  3796. if( ai->isWaitingForPath() )
  3797. {
  3798. (*numWaitingForPath)++;
  3799. }
  3800. if( ai->isAttacking() )
  3801. {
  3802. (*numAttacking)++;
  3803. }
  3804. }
  3805. }
  3806. *overallFailedPathfinds = m_overallFailedPathfinds;
  3807. }
  3808. #endif
  3809. // ------------------------------------------------------------------------------------------------
  3810. /** Light CRC */
  3811. // ------------------------------------------------------------------------------------------------
  3812. void GameLogic::crc( Xfer *xfer )
  3813. {
  3814. } // end crc
  3815. // ------------------------------------------------------------------------------------------------
  3816. /** Given a string name, find the object TOC entry (if any) associated with it */
  3817. // ------------------------------------------------------------------------------------------------
  3818. GameLogic::ObjectTOCEntry *GameLogic::findTOCEntryByName( AsciiString name )
  3819. {
  3820. for( ObjectTOCListIterator it = m_objectTOC.begin(); it != m_objectTOC.end(); ++it )
  3821. if( (*it).name == name )
  3822. return &(*it);
  3823. return NULL;
  3824. } // end findTOCEntryByname
  3825. // ------------------------------------------------------------------------------------------------
  3826. /** Given a object TOC identifier, find the object TOC if any */
  3827. // ------------------------------------------------------------------------------------------------
  3828. GameLogic::ObjectTOCEntry *GameLogic::findTOCEntryById( UnsignedShort id )
  3829. {
  3830. for( ObjectTOCListIterator it = m_objectTOC.begin(); it != m_objectTOC.end(); ++it )
  3831. if( (*it).id == id )
  3832. return &(*it);
  3833. return NULL;
  3834. } // end findTOCEntryById
  3835. // ------------------------------------------------------------------------------------------------
  3836. /** Add an object TOC entry */
  3837. // ------------------------------------------------------------------------------------------------
  3838. void GameLogic::addTOCEntry( AsciiString name, UnsignedShort id )
  3839. {
  3840. ObjectTOCEntry tocEntry;
  3841. tocEntry.name = name;
  3842. tocEntry.id = id;
  3843. m_objectTOC.push_back( tocEntry );
  3844. } // end addTOCEntry
  3845. // ------------------------------------------------------------------------------------------------
  3846. /** Xfer object table of contents */
  3847. // ------------------------------------------------------------------------------------------------
  3848. void GameLogic::xferObjectTOC( Xfer *xfer )
  3849. {
  3850. // version
  3851. const XferVersion currentVersion = 1;
  3852. XferVersion version = currentVersion;
  3853. xfer->xferVersion( &version, currentVersion );
  3854. // clear our current table of contents
  3855. m_objectTOC.clear();
  3856. // xfer the table
  3857. UnsignedInt tocCount = 0;
  3858. if( xfer->getXferMode() == XFER_SAVE )
  3859. {
  3860. AsciiString templateName;
  3861. // generate a new TOC based on the objects that are in the map
  3862. for( Object *obj = getFirstObject(); obj; obj = obj->getNextObject() )
  3863. {
  3864. // get the name we're working with
  3865. templateName = obj->getTemplate()->getName();
  3866. // if is this object name already in the TOC, skip it
  3867. if( findTOCEntryByName( templateName ) != NULL )
  3868. continue;
  3869. // add this entry to the TOC
  3870. addTOCEntry( obj->getTemplate()->getName(), ++tocCount );
  3871. } // end for obj
  3872. // xfer entries in the TOC
  3873. xfer->xferUnsignedInt( &tocCount );
  3874. // xfer each TOC entry
  3875. ObjectTOCListIterator it;
  3876. ObjectTOCEntry *tocEntry;
  3877. for( it = m_objectTOC.begin(); it != m_objectTOC.end(); ++it )
  3878. {
  3879. // get this toc entry
  3880. tocEntry = &(*it);
  3881. // xfer the name
  3882. xfer->xferAsciiString( &tocEntry->name );
  3883. // xfer the paired id
  3884. xfer->xferUnsignedShort( &tocEntry->id );
  3885. } // end for
  3886. } // end if
  3887. else
  3888. {
  3889. AsciiString templateName;
  3890. UnsignedShort id;
  3891. // how many entries are we going to read
  3892. xfer->xferUnsignedInt( &tocCount );
  3893. // read all the entries
  3894. for( UnsignedInt i = 0; i < tocCount; ++i )
  3895. {
  3896. // read the name
  3897. xfer->xferAsciiString( &templateName );
  3898. // read the id
  3899. xfer->xferUnsignedShort( &id );
  3900. // add this to the TOC
  3901. addTOCEntry( templateName, id );
  3902. } // end for i
  3903. } // end else
  3904. } // end xferObjectTOC
  3905. // ------------------------------------------------------------------------------------------------
  3906. // ------------------------------------------------------------------------------------------------
  3907. void GameLogic::prepareLogicForObjectLoad( void )
  3908. {
  3909. //
  3910. // this is a band-aid :(
  3911. // when loading from a map file, objects were created for the bridges, towers, walls etc.
  3912. // since we're going to load that data from the save game file we will destroy any of
  3913. // those bridge objects and tower objects so that we can create them from the save data
  3914. //
  3915. Object *obj, *next;
  3916. for( obj = getFirstObject(); obj; obj = next )
  3917. {
  3918. // get next
  3919. next = obj->getNextObject();
  3920. // is this a bridge object?
  3921. if( obj->isKindOf( KINDOF_BRIDGE ) )
  3922. {
  3923. Bridge *bridge = TheTerrainLogic->findBridgeAt( obj->getPosition() );
  3924. // sanity
  3925. DEBUG_ASSERTCRASH( bridge, ("GameLogic::prepareLogicForObjectLoad - Unable to find bridge\n" ));
  3926. // get the old object that is in the bridge info
  3927. const BridgeInfo *bridgeInfo = bridge->peekBridgeInfo();
  3928. Object *oldObject = findObjectByID( bridgeInfo->bridgeObjectID );
  3929. DEBUG_ASSERTCRASH( oldObject, ("GameLogic::prepareLogicForObjectLoad - Unable to find old bridge object\n") );
  3930. DEBUG_ASSERTCRASH( oldObject == obj, ("GameLogic::prepareLogicForObjectLoad - obj != oldObject\n") );
  3931. //
  3932. // destroy the 4 towers that are attached to this old object (they will be loaded from
  3933. // the save game file
  3934. //
  3935. Object *oldTower;
  3936. for( Int i = 0; i < BRIDGE_MAX_TOWERS; ++i )
  3937. {
  3938. oldTower = findObjectByID( bridgeInfo->towerObjectID[ i ] );
  3939. if (oldTower) {
  3940. destroyObject( oldTower );
  3941. }
  3942. } // end for, i
  3943. // destroy the old bridge object
  3944. destroyObject( oldObject );
  3945. } // end if, bridge
  3946. else if( obj->isKindOf( KINDOF_WALK_ON_TOP_OF_WALL ) )
  3947. {
  3948. // destroy walk on top of wall things too
  3949. destroyObject( obj );
  3950. } // end else if
  3951. } // end for, obj
  3952. // process the destruction of these objects immediately before we proceed with the load process
  3953. processDestroyList();
  3954. // there should be no objects anywhere
  3955. DEBUG_ASSERTCRASH( getFirstObject() == NULL,
  3956. ("GameLogic::prepareLogicForObjectLoad - There are still objects loaded in the engine, but it should be empty (Top is '%s')\n",
  3957. getFirstObject()->getTemplate()->getName().str()) );
  3958. } // end prepareLogicForObjectLoad
  3959. // ------------------------------------------------------------------------------------------------
  3960. /** Load/Save game logic to xfer
  3961. * Version Info:
  3962. * 1: Initial version
  3963. * 2: Added m_isScoringEnabled flag (BGC)
  3964. * 3: Added polygon triggers (CBD)
  3965. * 4: Added block markers around object data, no version checking is done and therefore
  3966. * this version breaks compatibility with previous versions. (CBD)
  3967. * 5: Added xfering the BuildAssistant's sell list.
  3968. * 9: Added m_rankPointsToAddAtGameStart, or else on a load game, your RestartGame button will forget your exp
  3969. * 10: xfer m_superweaponRestriction
  3970. */
  3971. // ------------------------------------------------------------------------------------------------
  3972. void GameLogic::xfer( Xfer *xfer )
  3973. {
  3974. // version
  3975. const XferVersion currentVersion = 10;
  3976. XferVersion version = currentVersion;
  3977. xfer->xferVersion( &version, currentVersion );
  3978. // logic frame number
  3979. xfer->xferUnsignedInt( &m_frame );
  3980. //
  3981. // note that we do not do the id counter here, we did it in the game state block because
  3982. // it's important to do that part very early in the load process
  3983. //
  3984. // !!!DON'T DO THIS!!! ----> xfer->xferObjectID( &m_nextObjectID ); <---- !!!DON'T DO THIS!!!
  3985. //
  3986. // xfer a table of contents that contain thing template and indentifier pairs. this
  3987. // table of contents is good for this save file only as unique numbers are only
  3988. // generated and stored for the actual things that are on this map
  3989. //
  3990. xferObjectTOC( xfer );
  3991. // when loading, we need to clean up bridges and get them ready for a load
  3992. if( xfer->getXferMode() == XFER_LOAD )
  3993. prepareLogicForObjectLoad();
  3994. // object count
  3995. UnsignedInt objectCount = getObjectCount();
  3996. xfer->xferUnsignedInt( &objectCount );
  3997. // object data
  3998. Object *obj;
  3999. ObjectTOCEntry *tocEntry;
  4000. if( xfer->getXferMode() == XFER_SAVE )
  4001. {
  4002. for( obj = getFirstObject(); obj; obj = obj->getNextObject() )
  4003. {
  4004. // get the object TOC entry for this template
  4005. tocEntry = findTOCEntryByName( obj->getTemplate()->getName() );
  4006. if( tocEntry == NULL )
  4007. {
  4008. DEBUG_CRASH(( "GameLogic::xfer - Object TOC entry not found for '%s'\n", obj->getTemplate()->getName().str() ));
  4009. throw SC_INVALID_DATA;
  4010. } // end if
  4011. // transfer TOC id entry
  4012. xfer->xferUnsignedShort( &tocEntry->id );
  4013. // begin a block of data
  4014. xfer->beginBlock();
  4015. // write object data
  4016. xfer->xferSnapshot( obj );
  4017. // end a block of data
  4018. xfer->endBlock();
  4019. } // end for
  4020. } // end if, save
  4021. else
  4022. {
  4023. Team *defaultTeam = ThePlayerList->getNeutralPlayer()->getDefaultTeam();
  4024. const ThingTemplate *thingTemplate;
  4025. // read all objects
  4026. Int objectDataSize;
  4027. UnsignedShort tocID;
  4028. ObjectTOCEntry *tocEntry;
  4029. for( UnsignedInt i = 0; i < objectCount; ++i )
  4030. {
  4031. // read toc entry identifier
  4032. xfer->xferUnsignedShort( &tocID );
  4033. // find Object TOC entry with this identifier
  4034. tocEntry = findTOCEntryById( tocID );
  4035. if( tocEntry == NULL )
  4036. {
  4037. DEBUG_CRASH(( "GameLogic::xfer - No TOC entry match for id '%d'\n", tocID ));
  4038. throw SC_INVALID_DATA;
  4039. } // end if
  4040. // a block of data has begun
  4041. objectDataSize = xfer->beginBlock();
  4042. // find matching thing template
  4043. thingTemplate = TheThingFactory->findTemplate( tocEntry->name );
  4044. if( thingTemplate == NULL )
  4045. {
  4046. DEBUG_CRASH(( "GameLogic::xfer - Unrecognized thing template name '%s', skipping. ENGINEERS - Are you *sure* it's OK to be ignoring this object from the save file??? Think hard about it!\n",
  4047. tocEntry->name.str() ));
  4048. xfer->skip( objectDataSize );
  4049. continue;
  4050. } // end if
  4051. // create new object
  4052. obj = TheThingFactory->newObject( thingTemplate, defaultTeam );
  4053. // xfer the rest of the object data
  4054. xfer->xferSnapshot( obj );
  4055. // end of block of data (not necessary in a load, but looks symettrically nice)
  4056. xfer->endBlock();
  4057. // special case for wall pieces, need to add them to the pathfinder
  4058. if( obj->isKindOf( KINDOF_WALK_ON_TOP_OF_WALL ) )
  4059. TheAI->pathfinder()->addWallPiece( obj );
  4060. } // end for, i
  4061. } // end else
  4062. // campaign info
  4063. xfer->xferSnapshot( TheCampaignManager );
  4064. // cave system info
  4065. xfer->xferSnapshot( TheCaveSystem );
  4066. // is scoring enabled
  4067. if( version >= 2 )
  4068. xfer->xferBool(&m_isScoringEnabled);
  4069. // polygon triggers
  4070. if( version >= 3 )
  4071. {
  4072. PolygonTrigger *poly;
  4073. // count the number of polygon triggers we have
  4074. UnsignedInt triggerCount = 0;
  4075. for( poly = PolygonTrigger::getFirstPolygonTrigger(); poly; poly = poly->getNext() )
  4076. triggerCount++;
  4077. // sanity count
  4078. UnsignedInt sanityTriggerCount = triggerCount;
  4079. // xfer count
  4080. xfer->xferUnsignedInt( &triggerCount );
  4081. //
  4082. // since the save game loaded should have exactly the same number of polygon triggers
  4083. // in it that we did from loading the map this is just a sanity check here
  4084. //
  4085. if( sanityTriggerCount != triggerCount )
  4086. {
  4087. DEBUG_CRASH(( "GameLogic::xfer - Polygon trigger count mismatch. Save file has a count of '%d', but map had '%d' triggers\n",
  4088. sanityTriggerCount, triggerCount ));
  4089. throw SC_INVALID_DATA;
  4090. } // end if
  4091. // xfer each of the polygon triggers
  4092. if( xfer->getXferMode() == XFER_SAVE )
  4093. {
  4094. Int triggerID;
  4095. for( poly = PolygonTrigger::getFirstPolygonTrigger(); poly; poly = poly->getNext() )
  4096. {
  4097. // write polygon ID
  4098. triggerID = poly->getID();
  4099. xfer->xferInt( &triggerID );
  4100. // xfer polygon data
  4101. xfer->xferSnapshot( poly );
  4102. } // end for, poly
  4103. } // end if, save
  4104. else
  4105. {
  4106. Int triggerID;
  4107. // loop through all triggers
  4108. for( UnsignedInt i = 0; i < triggerCount; ++i )
  4109. {
  4110. // read ID
  4111. xfer->xferInt( &triggerID );
  4112. // find this polygon trigger
  4113. poly = PolygonTrigger::getPolygonTriggerByID( triggerID );
  4114. // sanity
  4115. if( poly == NULL )
  4116. {
  4117. DEBUG_CRASH(( "GameLogic::xfer - Unable to find polygon trigger with id '%d'\n",
  4118. triggerID ));
  4119. throw SC_INVALID_DATA;
  4120. } // end if
  4121. // xfer polygon data
  4122. xfer->xferSnapshot( poly );
  4123. } // end for, i
  4124. //
  4125. // force a recalculation of the pathfinding cause some of these polygon triggers
  4126. // are water which can move during run-time, and therefore affecting the area
  4127. // that objects can move on. Also, map objects need recalculation. jba.
  4128. //
  4129. TheAI->pathfinder()->newMap();
  4130. } // end else, load
  4131. } // end if, version >= 3
  4132. // note that version=4 is the same as version=3
  4133. if (version >= 5)
  4134. {
  4135. xfer->xferInt(&m_rankLevelLimit);
  4136. }
  4137. if (version>=6) {
  4138. // We need the list of buildings in process of being sold.
  4139. TheBuildAssistant->xferTheSellList(xfer);
  4140. }
  4141. if (version >= 7)
  4142. {
  4143. if( xfer->getXferMode() == XFER_SAVE )
  4144. {
  4145. for (BuildableMap::const_iterator it = m_thingTemplateBuildableOverrides.begin(); it != m_thingTemplateBuildableOverrides.end(); ++it )
  4146. {
  4147. AsciiString name = it->first;
  4148. BuildableStatus bs = it->second;
  4149. xfer->xferAsciiString(&name);
  4150. xfer->xferUser(&bs, sizeof(bs));
  4151. }
  4152. AsciiString empty;
  4153. xfer->xferAsciiString(&empty);
  4154. }
  4155. else if (xfer->getXferMode() == XFER_LOAD)
  4156. {
  4157. if (m_thingTemplateBuildableOverrides.empty() == false)
  4158. {
  4159. DEBUG_CRASH(( "GameLogic::xfer - m_thingTemplateBuildableOverrides should be empty, but is not\n"));
  4160. throw SC_INVALID_DATA;
  4161. }
  4162. for (;;)
  4163. {
  4164. AsciiString name;
  4165. xfer->xferAsciiString(&name);
  4166. if (name.isEmpty())
  4167. break;
  4168. BuildableStatus bs;
  4169. xfer->xferUser(&bs, sizeof(bs));
  4170. m_thingTemplateBuildableOverrides[name] = bs;
  4171. }
  4172. }
  4173. }
  4174. if (version >= 8)
  4175. {
  4176. xfer->xferBool(&m_showBehindBuildingMarkers);
  4177. xfer->xferBool(&m_drawIconUI);
  4178. xfer->xferBool(&m_showDynamicLOD);
  4179. xfer->xferInt(&m_scriptHulkMaxLifetimeOverride);
  4180. if( xfer->getXferMode() == XFER_SAVE )
  4181. {
  4182. for (ControlBarOverrideMap::const_iterator it = m_controlBarOverrides.begin(); it != m_controlBarOverrides.end(); ++it )
  4183. {
  4184. AsciiString name = it->first;
  4185. AsciiString value = it->second ? it->second->getName() : AsciiString::TheEmptyString;
  4186. xfer->xferAsciiString(&name);
  4187. xfer->xferAsciiString(&value);
  4188. }
  4189. AsciiString empty;
  4190. xfer->xferAsciiString(&empty);
  4191. }
  4192. else if (xfer->getXferMode() == XFER_LOAD)
  4193. {
  4194. if (m_controlBarOverrides.empty() == false)
  4195. {
  4196. DEBUG_CRASH(( "GameLogic::xfer - m_controlBarOverrides should be empty, but is not\n"));
  4197. throw SC_INVALID_DATA;
  4198. }
  4199. for (;;)
  4200. {
  4201. AsciiString name;
  4202. xfer->xferAsciiString(&name);
  4203. if (name.isEmpty())
  4204. break;
  4205. AsciiString value;
  4206. xfer->xferAsciiString(&value);
  4207. ConstCommandButtonPtr button = NULL;
  4208. if (value.isNotEmpty())
  4209. {
  4210. button = TheControlBar->findCommandButton(value);
  4211. DEBUG_ASSERTCRASH(button != NULL, ("Could not find button %s\n",value.str()));
  4212. }
  4213. m_controlBarOverrides[name] = button;
  4214. }
  4215. }
  4216. }
  4217. if (version >= 9)
  4218. {
  4219. xfer->xferInt(&m_rankPointsToAddAtGameStart);
  4220. }
  4221. if ( version >= 10 )
  4222. {
  4223. xfer->xferUnsignedShort( &m_superweaponRestriction );
  4224. }
  4225. else if ( xfer->getXferMode() == XFER_LOAD )
  4226. {
  4227. m_superweaponRestriction = 0;
  4228. }
  4229. } // end xfer
  4230. // ------------------------------------------------------------------------------------------------
  4231. /** Load post process entry point */
  4232. // ------------------------------------------------------------------------------------------------
  4233. void GameLogic::loadPostProcess( void )
  4234. {
  4235. //
  4236. // the act of loading objects can (theoretically) as a side effect create other objects,
  4237. // our m_nextObjID that we maintain to give objects unique ID is also continually
  4238. // climbing higher and higher due to us allocating objects during load (even though
  4239. // those objects have their ids overwritten with data from the file. To prevent the
  4240. // m_nextObjID from getting un-necessarily high we will set it to the next available
  4241. // id from the objects that are now in the world and actually in use
  4242. //
  4243. m_nextObjID = INVALID_ID;
  4244. Object *obj;
  4245. for( obj = getFirstObject(); obj; obj = obj->getNextObject() )
  4246. if( obj->getID() >= m_nextObjID )
  4247. m_nextObjID = (ObjectID)((UnsignedInt)obj->getID() + 1);
  4248. // blow away the sleepy update and normal update module lists
  4249. for (std::vector<UpdateModulePtr>::iterator it = m_sleepyUpdates.begin(); it != m_sleepyUpdates.end(); ++it)
  4250. {
  4251. (*it)->friend_setIndexInLogic(-1);
  4252. }
  4253. m_sleepyUpdates.clear();
  4254. #ifdef ALLOW_NONSLEEPY_UPDATES
  4255. m_normalUpdates.clear();
  4256. #else
  4257. UnsignedInt now = TheGameLogic->getFrame();
  4258. if (now == 0)
  4259. now = 1;
  4260. #endif
  4261. // go through all objects, examine each update module and put it on the appropriate update list
  4262. for( obj = getFirstObject(); obj; obj = obj->getNextObject() )
  4263. {
  4264. // get the update list of modules for this object
  4265. for( BehaviorModule** b = obj->getBehaviorModules(); *b; ++b )
  4266. {
  4267. #ifdef DIRECT_UPDATEMODULE_ACCESS
  4268. // evil, but necessary at this point. (srj)
  4269. UpdateModulePtr u = (UpdateModulePtr)((*b)->getUpdate());
  4270. #else
  4271. UpdateModulePtr u = (*b)->getUpdate();
  4272. #endif
  4273. if (!u)
  4274. continue;
  4275. DEBUG_ASSERTCRASH(u->friend_getIndexInLogic() == -1, ("Hmm, expected index to be -1 here"));
  4276. // check each update module
  4277. UnsignedInt when = u->friend_getNextCallFrame();
  4278. #ifdef ALLOW_NONSLEEPY_UPDATES
  4279. if( when == 0 )
  4280. {
  4281. // zero if the magic value for "never sleeps"
  4282. m_normalUpdates.push_back(u);
  4283. }
  4284. else
  4285. #else
  4286. // note that 'when' will only be zero for legacy save files.
  4287. if (when == 0)
  4288. u->friend_setNextCallFrame(now);
  4289. #endif
  4290. {
  4291. m_sleepyUpdates.push_back(u);
  4292. u->friend_setIndexInLogic(m_sleepyUpdates.size() - 1);
  4293. }
  4294. } // end for, u
  4295. } // end for, obj
  4296. // re-sort the priority queue all at once now that all modules are on it
  4297. remakeSleepyUpdate();
  4298. } // end loadPostProcess