GameLogic.cpp 137 KB

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