Mission.cpp 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412
  1. //============================================================================================
  2. // Spirenkov Maxim, 2003
  3. //============================================================================================
  4. // Mission
  5. //============================================================================================
  6. #include "Mission.h"
  7. #include "MissionLoader.h"
  8. #include "Objects\MissionTime.h"
  9. #include "..\..\common_h\corecmds.h"
  10. #include "..\..\common_h\InputSrvCmds.h"
  11. #include "..\..\common_h\LocStrings.h"
  12. #ifdef LOAD_DEBUG
  13. #include "CAPROFAPI.h"
  14. #pragma comment(lib, "CAProfAPI32.lib")
  15. #endif
  16. //============================================================================================
  17. CREATE_CLASS(Mission)
  18. //============================================================================================
  19. #ifndef _XBOX
  20. #define MISSION_DEBUGFILENAME "logic_debug.txt"
  21. #else
  22. #define MISSION_DEBUGFILENAME "DEVKIT:\\logic_debug.txt"
  23. #endif
  24. #define MISSION_PARTICLES "missions"
  25. #define LOGICTRACE_SPACE " "
  26. //Текущая миссия при исполнении
  27. //Mission * Mission::current = null;
  28. //Миссия, для которой исполняются команды консоли
  29. #ifndef NO_CONSOLE
  30. Mission * Mission::controlMission = null;
  31. IConsole * Mission::console = null;
  32. bool Mission::enableConsoleLogicDebug = false;
  33. char Mission::debugObjects[64][128];
  34. long Mission::debugObjectsCounts = 0;
  35. char Mission::debugObjectCurrent[256];
  36. #endif
  37. const char * Mission::loadingHint = "";
  38. float Mission::loadingProgress = 0.0f;
  39. float Mission::loadingProgressScale = 1.0f;
  40. //Пути
  41. const char * Mission::missionsPath = "Resource\\Missions\\";
  42. const char * Mission::missionPath = "data\\";
  43. const char * Mission::cutLine = "---------------------------------------------------------------------------------\n";
  44. #ifndef STOP_LOGICTRACE
  45. Mission * Mission::traceFirstInList = null;
  46. #endif
  47. //============================================================================================
  48. void _cdecl Mission::ParticlesUpdater::UpdateParticles(float dltTime, long level)
  49. {
  50. Particles().Execute(dltTime);
  51. }
  52. void _cdecl Mission::ParticlesUpdater::DrawParticles(float dltTime, long level)
  53. {
  54. Particles().DrawAllParticles();
  55. }
  56. void _cdecl Mission::PhysicsUpdater::StartFrame(float dltTime, long level)
  57. {
  58. Physics().UpdateBeginFrame(dltTime);
  59. }
  60. void _cdecl Mission::PhysicsUpdater::EndFrame(float dltTime, long level)
  61. {
  62. Physics().UpdateEndFrame(dltTime);
  63. }
  64. void _cdecl Mission::AnimationUpdater::UpdateAnimation(float dltTime, long level)
  65. {
  66. srv->Update(scene, dltTime);
  67. }
  68. void _cdecl Mission::PostEffectsUpdater::PreparePostEffects(float dltTime, long level)
  69. {
  70. }
  71. void _cdecl Mission::PostEffectsUpdater::DrawPostEffects(float dltTime, long level)
  72. {
  73. Render().PostProcess();
  74. }
  75. //============================================================================================
  76. Mission::Mission() : regObjectTypes(_FL_),
  77. group(_FL_),
  78. timeModifiers(_FL_),
  79. objectsFindList(_FL_),
  80. textures(_FL_, 128),
  81. models(_FL_, 128),
  82. animations(_FL_, 128),
  83. boundPlanes(_FL_, 32)
  84. #ifndef STOP_PROFILES
  85. ,creationTable(_FL_)
  86. #endif
  87. {
  88. #ifndef STOP_LOGICTRACE
  89. traceNextInList = null;
  90. traceDltTime = 0.0f;
  91. traceTimeScale = 0.0f;
  92. traceFPS = 0.0f;
  93. #endif
  94. bEditModeAdditionalDraw = true;
  95. loader = null;
  96. for(long i = 0; i < ARRSIZE(entryGroups); i++) entryGroups[i] = null;
  97. player = null;
  98. particlesUpdater = null;
  99. physicsUpdater = null;
  100. animationUpdater = null;
  101. postEffectsUpdater = null;
  102. dataBuffer = null;
  103. validateCacheCounter = 0;
  104. uIdCodeCounter = 1;
  105. //static const char * objectsListName = "Mission.objectsList";
  106. objectsList.SetId(GroupId(0, 'O','b','j'));
  107. //static const char * executeListName = "Mission.executeList";
  108. executeList.SetId(GroupId(0, 'E','x','e'));
  109. executeIterator = executeList.CreateIterator(_FL_);
  110. profileLevel = 0;
  111. isSleep = false;
  112. isMissionPause = false;
  113. isProcessMissionPause = true;
  114. missionPauseCount = 0;
  115. swingAngs = 0.0f;
  116. enableDebug = false;
  117. largeshot = null;
  118. largeshotPrjScale = null;
  119. largeshotPrjX = null;
  120. largeshotPrjY = null;
  121. framesCounter = 0;
  122. #ifndef MIS_STOP_EDIT_FUNCS
  123. isEditMode = true;
  124. #else
  125. isEditMode = false;
  126. #endif
  127. for(long i = 0; i < ARRSIZE(regObjectTypesEntry); i++) regObjectTypesEntry[i] = -1;
  128. mirrorPath = null;
  129. //TestFrames();
  130. }
  131. Mission::~Mission()
  132. {
  133. #ifndef NO_CONSOLE
  134. if(controlMission == this)
  135. {
  136. controlMission = null;
  137. console = null;
  138. }
  139. #endif
  140. //Разлочиваем доступ к файлам
  141. if(&Files()) Files().LockFileAccess(false);
  142. //Удаляем кэшированые ресурсы
  143. for(long i = 0; i < textures; i++)
  144. {
  145. textures[i]->Release();
  146. }
  147. textures.Empty();
  148. for(long i = 0; i < animations; i++)
  149. {
  150. animations[i]->Release();
  151. }
  152. animations.Empty();
  153. for(long i = 0; i < models; i++)
  154. {
  155. models[i]->Release();
  156. }
  157. models.Empty();
  158. //Удалим подземную ограничивающую плоскость
  159. for(long i = 0; i < boundPlanes; i++)
  160. {
  161. if(boundPlanes[i])
  162. {
  163. boundPlanes[i]->Release();
  164. boundPlanes[i] = null;
  165. }
  166. }
  167. if(particlesUpdater) delete particlesUpdater;
  168. particlesUpdater = null;
  169. if(physicsUpdater) delete physicsUpdater;
  170. physicsUpdater = null;
  171. if(animationUpdater) delete animationUpdater;
  172. animationUpdater = null;
  173. if(postEffectsUpdater) delete postEffectsUpdater;
  174. postEffectsUpdater = null;
  175. player = null;
  176. //Если загрузчик ещё остался, удалим его
  177. if(loader) delete loader; loader = null;
  178. //Удалим все объекты
  179. objectsList.DeleteList();
  180. //Удалим списки
  181. for(long i = 0; i < group; i++) delete group[i];
  182. //Удалим системные итераторы
  183. RELEASE(executeIterator);
  184. //Удалим звуковые банки
  185. ISoundService * ssrv = (ISoundService *)api->GetService("SoundService");
  186. Assert(ssrv);
  187. ssrv->ReleaseSoundBank(name.c_str());
  188. ILocStrings * locStrings = (ILocStrings *)api->GetService("LocStrings");
  189. Assert(locStrings);
  190. // locStrings->ReleaseLocSoundBank(name.c_str());
  191. //Отключаем пак миссии
  192. if(mirrorPath)
  193. {
  194. mirrorPath->Release();
  195. mirrorPath = null;
  196. }
  197. //Удаляем звуковую сцену
  198. if(&Sound()) Sound().Release();
  199. //Удаляем партикловый менеджер
  200. if(&Particles()) Particles().Release();
  201. //Удаляем физическую сцену
  202. if(&Physics()) Physics().Release();
  203. //Удаляем сцену ввода
  204. if(&Controls()) Controls().Release();
  205. //Удалим имена зарегестрённых объектов
  206. for(long i = 0; i < regObjectTypes; i++)
  207. {
  208. delete regObjectTypes[i].type;
  209. }
  210. regObjectTypes.Empty();
  211. //Удаляем анимационную сцену
  212. if(&Animation()) Animation().Release();
  213. //Мисионные данные
  214. if(dataBuffer)
  215. {
  216. dataBuffer->Release();
  217. dataBuffer = null;
  218. }
  219. RELEASE(largeshot);
  220. RELEASE(largeshotPrjScale);
  221. RELEASE(largeshotPrjX);
  222. RELEASE(largeshotPrjY);
  223. }
  224. //============================================================================================
  225. bool Mission::EditMode_IsAdditionalDraw ()
  226. {
  227. return bEditModeAdditionalDraw;
  228. }
  229. void Mission::EditMode_AdditionalDraw (bool value)
  230. {
  231. bEditModeAdditionalDraw = value;
  232. }
  233. //============================================================================================
  234. //Управление миссией
  235. //============================================================================================
  236. //Заргузить миссию
  237. bool Mission::CreateMission(const char * missionName, float percentsPerMission, float & percentsCounter)
  238. {
  239. AssertCoreThread
  240. #ifdef LOAD_DEBUG
  241. CAProfResume();
  242. #endif
  243. loadingProgressScale = percentsPerMission*0.01f;
  244. LogicDebug("--------------------------------------------\nLoad mission: %s\n--------------------------------------------\n", missionName);
  245. name = missionName;
  246. api->SetWatchDog();
  247. Sound().ModifyOvnerName(missionName);
  248. string path = missionsPath;
  249. path += name;
  250. path += "\\";
  251. path += name;
  252. api->Trace("\n===========================================================================\nCreate mission: %s\n===========================================================================\n", missionName);
  253. loadingHint = "Load level description...";
  254. loadingProgress = percentsCounter;
  255. LoadingProgress(0.0f);
  256. isEditMode = false;
  257. if(!missionName || !missionName[0])
  258. {
  259. api->Trace("CreateMission -> invalidate mission name");
  260. percentsCounter = loadingProgress;
  261. return false;
  262. }
  263. if(enableDebug)
  264. {
  265. LogicDebug("===========================================================================\nInit mission: \"%s\"\n===========================================================================\n", missionName);
  266. }
  267. #ifndef _XBOX
  268. const char * basePacksPath = "resource\\";
  269. #else
  270. const char * basePacksPath = "";
  271. #endif
  272. //Подключаем путь миссии
  273. path = missionsPath;
  274. path += name;
  275. mirrorPath = Files().CreateMirrorPath(path, "Resource\\", _FL_);
  276. //Загружаем пак с данными объектов
  277. string packName = basePacksPath;
  278. packName += "d_";
  279. packName += missionName;
  280. packName += ".pkx";
  281. IPackFile * misPack = Files().LoadPack(packName.c_str(), _FL_);
  282. //Путь до файла описывающего миссию
  283. path = "Resource\\";
  284. path += missionPath;
  285. path += name;
  286. path.AddExtention(".mis");
  287. //Загружаем файл описания миссии
  288. dataBuffer = Files().LoadData(path, _FL_);
  289. if(!dataBuffer)
  290. {
  291. api->Trace("CreateMission -> file %s not loaded", path.GetBuffer());
  292. percentsCounter = loadingProgress;
  293. RELEASE(misPack);
  294. return false;
  295. }
  296. //Загружаем паки
  297. dword loadTime = 0;
  298. dword creationTime = 0;
  299. //Текстуры
  300. api->SetWatchDog();
  301. dword startTime = GetTickCount();
  302. LoadingProgress(1.0f);
  303. loadingHint = "Load textures...";
  304. packName = basePacksPath;
  305. packName += "t_";
  306. packName += missionName;
  307. packName += ".pkx";
  308. dword loadTimeForTextures = loadTime;
  309. dword creationTimeForTextures = creationTime;
  310. PrecachePack(packName.c_str(), &Mission::PrecacheCreator_Textures, 14.0f, 25.0f, loadTime, creationTime);
  311. loadTimeForTextures = loadTime - loadTimeForTextures;
  312. creationTimeForTextures = creationTime - creationTimeForTextures;
  313. //Анимации
  314. api->SetWatchDog();
  315. loadingHint = "Load animations...";
  316. packName = basePacksPath;
  317. packName += "a_";
  318. packName += missionName;
  319. packName += ".pkx";
  320. dword loadTimeForAnimations = loadTime;
  321. dword creationTimeForAnimations = creationTime;
  322. PrecachePack(packName.c_str(), &Mission::PrecacheCreator_Animation, 5.0f, 5.0f, loadTime, creationTime);
  323. loadTimeForAnimations = loadTime - loadTimeForAnimations;
  324. creationTimeForAnimations = creationTime - creationTimeForAnimations;
  325. //Модельки
  326. api->SetWatchDog();
  327. loadingHint = "Load models...";
  328. packName = basePacksPath;
  329. packName += "m_";
  330. packName += missionName;
  331. packName += ".pkx";
  332. dword loadTimeForModels = loadTime;
  333. dword creationTimeForModels = creationTime;
  334. PrecachePack(packName.c_str(), &Mission::PrecacheCreator_Models, 10.0f, 20.0f, loadTime, creationTime);
  335. loadTimeForModels = loadTime - loadTimeForModels;
  336. creationTimeForModels = creationTime - creationTimeForModels;
  337. dword precacheTime = GetTickCount() - startTime;
  338. //Звуковые банки
  339. api->SetWatchDog();
  340. dword loadTimeForSounds = GetTickCount();
  341. ISoundService * ssrv = (ISoundService *)api->GetService("SoundService");
  342. Assert(ssrv);
  343. ssrv->LoadSoundBank(name.c_str());
  344. api->SetWatchDog();
  345. ILocStrings * locStrings = (ILocStrings *)api->GetService("LocStrings");
  346. Assert(locStrings);
  347. // locStrings->LoadLocSoundBank(name.c_str());
  348. loadTimeForSounds = GetTickCount() - loadTimeForSounds;
  349. loadTime += loadTimeForSounds;
  350. //Пишем отчёт о загрузке
  351. #ifndef STOP_PROFILES
  352. api->Trace("Packs load time = %.2f seconds, resource creation time = %.2f seconds, total precache time = %.2f seconds", loadTime*0.001f, creationTime*0.001f, precacheTime*0.001f);
  353. if(profileLevel > 0)
  354. {
  355. api->Trace(" Textures load time = %.2f seconds, textures creation time = %.2f seconds", loadTimeForTextures*0.001f, creationTimeForTextures*0.001f);
  356. api->Trace(" Animations load time = %.2f seconds, animations creation time = %.2f seconds", loadTimeForAnimations*0.001f, creationTimeForAnimations*0.001f);
  357. api->Trace(" Models load time = %.2f seconds, models creation time = %.2f seconds", loadTimeForModels*0.001f, creationTimeForModels*0.001f);
  358. api->Trace(" Load time for mission sound banks %.2f seconds", loadTimeForSounds*0.001f);
  359. }
  360. #endif
  361. //Создаём миссионные объекты
  362. api->SetWatchDog();
  363. startTime = GetTickCount();
  364. Assert(loader == null);
  365. loader = NEW MissionLoader(*this, dataBuffer->Buffer(), dataBuffer->Size());
  366. loadingHint = "Creating game objects...";
  367. LoadingProgress(2.0f);
  368. if(!loader->StartProcess(18.0f))
  369. {
  370. api->Trace("CreateMission -> loader create process if failed");
  371. percentsCounter = loadingProgress;
  372. RELEASE(misPack);
  373. return false;
  374. }
  375. //Доинициализация объектов
  376. api->SetWatchDog();
  377. MGIterator * it = objectsList.CreateIterator(_FL_);
  378. Assert(it);
  379. for(; !it->IsDone(); it->Next())
  380. {
  381. it->Get()->PostCreate();
  382. }
  383. it->Release();
  384. //
  385. LoadingProgress(100.0f);
  386. api->Trace("Objects creation time = %.2f seconds", (GetTickCount() - startTime)*0.001f);
  387. #ifndef STOP_PROFILES
  388. if(profileLevel >= 1)
  389. {
  390. CreationProfile();
  391. }
  392. #endif
  393. api->Trace("Mission \"%s\" loaded successful...", missionName);
  394. api->ExecuteCoreCommand(CoreCommand_MemStat(cmemstat_onlytotal));
  395. //Пока грузим синхронно
  396. api->SetWatchDog();
  397. if(enableDebug)
  398. {
  399. LogicDebug("===========================================================================\nStart mission...\n===========================================================================\n", null);
  400. }
  401. loadingHint = "";
  402. #ifdef LOAD_DEBUG
  403. CAProfPause();
  404. #endif
  405. percentsCounter = loadingProgress;
  406. RELEASE(misPack);
  407. return true;
  408. }
  409. void Mission::PrecachePack(const char * packPath, PrecacheCreator creator, float filePerc, float dataPerc, dword & loadTime, dword & creationTime)
  410. {
  411. dword startTime = GetTickCount();
  412. IPackFile * pack = Files().LoadPack(packPath, _FL_);
  413. loadTime += GetTickCount() - startTime;
  414. LoadingProgress(filePerc);
  415. float step = dataPerc;
  416. if(pack)
  417. {
  418. if(pack->Count())
  419. {
  420. step = step/pack->Count();
  421. }else{
  422. LoadingProgress(step);
  423. }
  424. startTime = GetTickCount();
  425. textures.Reserve(pack->Count());
  426. for(dword i = 0; i < pack->Count(); i++)
  427. {
  428. const char * name = pack->LocalPath(i);
  429. (this->*creator)(name);
  430. LoadingProgress(step);
  431. }
  432. creationTime += GetTickCount() - startTime;
  433. pack->Release();
  434. pack = null;
  435. }else{
  436. LoadingProgress(step);
  437. }
  438. }
  439. void Mission::PrecacheCreator_Textures(const char * name)
  440. {
  441. IBaseTexture * texture = Render().CreateTexture(_FL_, name);
  442. if(texture)
  443. {
  444. textures.Add(texture);
  445. }
  446. }
  447. void Mission::PrecacheCreator_Animation(const char * name)
  448. {
  449. IAnimation * animation = Animation().Create(name, _FL_);
  450. if(animation)
  451. {
  452. animations.Add(animation);
  453. }
  454. }
  455. void Mission::PrecacheCreator_Models(const char * name)
  456. {
  457. IGMXScene * model = Geometry().CreateScene(name, &Animation(), &Particles(), &Sound(), _FL_);
  458. if(model)
  459. {
  460. models.Add(model);
  461. }
  462. }
  463. void Mission::LoadingProgress(float delta)
  464. {
  465. loadingProgress += delta;
  466. if(loadingProgress > 100.0f)
  467. {
  468. loadingProgress = 100.0f;
  469. }
  470. Render().SetLoadingScreenPercents(loadingProgress, 100.0f, loadingHint);
  471. }
  472. //Удалить миссию
  473. void Mission::DeleteMission()
  474. {
  475. delete this;
  476. }
  477. //Получить имя загруженой миссии
  478. const char * Mission::GetMissionName()
  479. {
  480. return name;
  481. }
  482. //Закончен ли процесс загрузки
  483. bool Mission::IsLoadDone()
  484. {
  485. if(loader)
  486. {
  487. if(loader->IsDone())
  488. {
  489. delete loader;
  490. loader = null;
  491. return true;
  492. }
  493. return false;
  494. }
  495. return true;
  496. }
  497. //Добавить в список модификатор времени
  498. void Mission::AddTimeModifier(float * modifier)
  499. {
  500. for(long i = 0; i < timeModifiers; i++)
  501. {
  502. if(timeModifiers[i] == modifier)
  503. {
  504. return;
  505. }
  506. }
  507. timeModifiers.Add(modifier);
  508. }
  509. //Добавить из списока модификатор времени
  510. void Mission::RemoveTimeModifier(float * modifier)
  511. {
  512. for(long i = 0; i < timeModifiers; i++)
  513. {
  514. if(timeModifiers[i] == modifier)
  515. {
  516. timeModifiers.DelIndex(i);
  517. return;
  518. }
  519. }
  520. }
  521. //Пауза миссии
  522. void Mission::MissionPause(bool isPause)
  523. {
  524. if(isPause)
  525. {
  526. if(missionPauseCount == 0)
  527. {
  528. //Встать на паузу
  529. LogicDebug("%s\nPause mission: %s\n%s", cutLine, name.c_str(), cutLine);
  530. MGIterator & it = GroupIterator(DEACTIVATE_EVENT_GROUP, _FL_);
  531. for(; !it.IsDone(); it.Next())
  532. {
  533. it.ExecuteEvent();
  534. }
  535. it.Release();
  536. if(services.sound)
  537. {
  538. services.sound->Pause();
  539. }
  540. if(services.ctrl)
  541. {
  542. services.ctrl->Activate(false);
  543. }
  544. }
  545. missionPauseCount++;
  546. }else{
  547. if(missionPauseCount > 0)
  548. {
  549. missionPauseCount--;
  550. Assert(missionPauseCount >= 0);
  551. if(missionPauseCount == 0)
  552. {
  553. //Возобновить работу
  554. LogicDebug("%s\nResume mission: %s\n%s", cutLine, name.c_str(), cutLine);
  555. MGIterator & it = GroupIterator(ACTIVATE_EVENT_GROUP, _FL_);
  556. for(; !it.IsDone(); it.Next())
  557. {
  558. it.ExecuteEvent();
  559. }
  560. it.Release();
  561. if(services.sound)
  562. {
  563. services.sound->Resume();
  564. }
  565. if(services.ctrl)
  566. {
  567. services.ctrl->Activate(true);
  568. }
  569. }
  570. }
  571. }
  572. }
  573. //============================================================================================
  574. //Функции для редактора миссий
  575. //============================================================================================
  576. #ifndef NO_TOOLS
  577. //Подключить пак для редактора если нет, то создать
  578. void Mission::EditorSetPack(const char * missionName)
  579. {
  580. Assert(isEditMode);
  581. if(!missionName || !missionName[0]) return;
  582. if(name.Len() > 0) return;
  583. //Сохраним имя миссии
  584. name = missionName;
  585. Sound().ModifyOvnerName(missionName);
  586. //Путь до пака миссии
  587. string path = missionsPath;
  588. path += name;
  589. path += "\\";
  590. //Создадим путь
  591. Files().CreateFolder(path);
  592. //Подключим заркальный путь
  593. path = missionsPath;
  594. path += name;
  595. if(mirrorPath)
  596. {
  597. mirrorPath->Release();
  598. mirrorPath = null;
  599. }
  600. mirrorPath = Files().CreateMirrorPath(path, "Resource\\", _FL_);
  601. }
  602. //Получить путь до пак-файла миссии
  603. void Mission::EditorGetPackPath(string & path)
  604. {
  605. Assert(isEditMode);
  606. path.Empty();
  607. if(name.Len() == 0) return;
  608. path = missionsPath;
  609. path += name;
  610. if(name.Len() > 0) path += "\\";
  611. path.CheckPath();
  612. }
  613. //Получить путь до файла миссии .mis, чтобы сохранить его
  614. void Mission::EditorGetMisPath(string & path)
  615. {
  616. Assert(isEditMode);
  617. path.Empty();
  618. if(name.Len() == 0) return;
  619. path = missionsPath;
  620. path += name;
  621. if(name.Len() > 0) path += "\\";
  622. path += missionPath;
  623. path += "\\";
  624. path += name;
  625. path += ".mis";
  626. path.CheckPath();
  627. }
  628. //Усыпить/разбудить миссию
  629. void Mission::EditorSetSleep(bool isSleep)
  630. {
  631. Assert(isEditMode);
  632. if(this->isSleep == isSleep) return;
  633. this->isSleep = isSleep;
  634. MGIterator * it = objectsList.CreateIterator(_FL_);
  635. Assert(it);
  636. for(; !it->IsDone(); it->Next())
  637. {
  638. it->Get()->EditMode_Sleep(isSleep);
  639. }
  640. it->Release();
  641. MissionPause(isSleep);
  642. }
  643. //Обновить объект
  644. void Mission::EditorUpdateObject(MissionObject * mo, MOPWriter & writer)
  645. {
  646. Assert(isEditMode);
  647. if(!mo) return;
  648. void * data = null;
  649. dword readerDataSize = writer.GetData(data);
  650. void * readerData = NEW byte[readerDataSize];
  651. memcpy(readerData, data, readerDataSize);
  652. MOPReader reader(readerData, readerDataSize);
  653. bool isDifferentName = (string::NotEqual(reader.GetObjectID(), mo->GetObjectID().c_str()));
  654. if(isDifferentName)
  655. {
  656. RemoveMissionObjectFromFFTable(mo);
  657. }
  658. sysSetObjectReaderDataBeforeCreate(mo, readerData, readerDataSize, readerData);
  659. sysSetObjectIDBeforeCreate(mo, reader.GetObjectID());
  660. if(isDifferentName)
  661. {
  662. AddMissionObjectToFFTable(mo);
  663. }
  664. sysEditMode_Update(mo, reader);
  665. }
  666. //Нарисовать миссию
  667. void Mission::EditorDraw(float dltTime)
  668. {
  669. isProcessMissionPause = false;
  670. FrameUpdate(dltTime);
  671. }
  672. #endif
  673. //============================================================================================
  674. //Управление объектами миссии
  675. //============================================================================================
  676. //Динамическое создание миссионного объекта
  677. MissionObject * Mission::sysCreateObject(const char * type, const ConstString & id, bool alone)
  678. {
  679. if(id.IsEmpty()) return null;
  680. if(alone)
  681. {
  682. MissionObject * mo = FindObject(id);
  683. if(mo)
  684. {
  685. return mo;
  686. }
  687. }
  688. MOPWriter writer('0.00', id.c_str());
  689. MOPReader reader = writer.Reader();
  690. dword readerDataSize = 0;
  691. void * readerData = reader.ReplaseData(readerDataSize);
  692. const char * rid = reader.GetObjectID();
  693. MissionObject * mo = sysCreateObject(type, reader);
  694. //Регистрации
  695. RemoveMissionObjectFromFFTable(mo);
  696. sysSetObjectReaderDataBeforeCreate(mo, readerData, readerDataSize, readerData);
  697. sysSetObjectIDBeforeCreate(mo, rid);
  698. AddMissionObjectToFFTable(mo);
  699. return mo;
  700. }
  701. //Динамическое создание миссионного объекта
  702. MissionObject * Mission::sysCreateObject(const char * type, MOPReader & rd)
  703. {
  704. if(!type || !type[0]) return null;
  705. //Создаём объект
  706. MissionObject * mo = (MissionObject *)api->CreateObject(type);
  707. if(!mo) return null;
  708. SetObjectUId(mo);
  709. type = CreateObject_AddType(type);
  710. //В режиме редактора дублируем имя
  711. #ifndef MIS_STOP_EDIT_FUNCS
  712. if(isEditMode)
  713. {
  714. dword readerDataSize;
  715. void * readerData = rd.ReplaseData(readerDataSize);
  716. sysSetObjectReaderDataBeforeCreate(mo, readerData, readerDataSize, readerData);
  717. }
  718. #endif
  719. const char * objectID = rd.GetObjectID();
  720. //Проставляем указатель на себя
  721. sysSetThisPointerToObject(mo);
  722. //Устанавливаем идентификатор
  723. sysSetObjectIDBeforeCreate(mo, objectID);
  724. sysSetObjectTypeBeforeCreate(mo, type);
  725. //Ставим текущий режим
  726. sysSetObjectEMBeforeCreate(mo, isEditMode);
  727. //Заносим в таблицу поиска
  728. AddMissionObjectToFFTable(mo);
  729. //Инициализируем
  730. bool isOk = true;
  731. if(!isEditMode)
  732. {
  733. #ifndef STOP_PROFILES
  734. if(profileLevel < 2)
  735. {
  736. if(!mo->Create(rd)) isOk = false;
  737. }else{
  738. ProfileTimer timer;
  739. if(!mo->Create(rd)) isOk = false;
  740. timer.Stop();
  741. ProfileCreation & cr = creationTable[creationTable.Add()];
  742. cr.time = timer.GetTime64();
  743. cr.type = type;
  744. cr.id = objectID;
  745. }
  746. #else
  747. if(!mo->Create(rd)) isOk = false;
  748. #endif
  749. }else{
  750. #ifndef MIS_STOP_EDIT_FUNCS
  751. if(!sysEditMode_Create(mo, rd)) isOk = false;
  752. #endif
  753. }
  754. if(!isOk)
  755. {
  756. sysDelUpdate(mo, null);
  757. sysUnregistryAll(mo);
  758. delete mo;
  759. return null;
  760. }
  761. MissionObjectsList::Func func;
  762. func.funcEvent = null;
  763. objectsList.Add(mo, 0, func);
  764. #ifndef MIS_STOP_EDIT_FUNCS
  765. if(isEditMode)
  766. {
  767. mo->EditMode_Sleep(isSleep);
  768. }
  769. #endif
  770. return mo;
  771. }
  772. const char * Mission::CreateObject_AddType(const char * type)
  773. {
  774. dword typeHash = string::Hash(type);
  775. long index = typeHash & (ARRSIZE(regObjectTypesEntry) - 1);
  776. for(long i = regObjectTypesEntry[index]; i >= 0; i = regObjectTypes[i].next)
  777. {
  778. TypeElement & rte = regObjectTypes[i];
  779. if(rte.hash == typeHash)
  780. {
  781. if(strcmp(rte.type, type) == 0)
  782. {
  783. return rte.type;
  784. }
  785. }
  786. }
  787. TypeElement te;
  788. te.hash = typeHash;
  789. te.next = regObjectTypesEntry[index];
  790. long len = strlen(type) + 1;
  791. te.type = NEW char[len];
  792. memcpy(te.type, type, len);
  793. regObjectTypesEntry[index] = (long)regObjectTypes.Add(te);
  794. return te.type;
  795. }
  796. //Перезапуск всех объектов миссии
  797. void Mission::RestartAllObjects()
  798. {
  799. LogicDebug("\n%sGlobal mission restart (mission:\"%s\")\n%s", cutLine, name.c_str(), cutLine);
  800. //Рестартим все объекты
  801. MGIterator * it = objectsList.CreateIterator(_FL_);
  802. Assert(it);
  803. for(; !it->IsDone(); it->Next())
  804. {
  805. MissionObject * mo = it->Get();
  806. Assert(mo);
  807. mo->Restart();
  808. }
  809. it->Release();
  810. //Проматываем итератор на конец списка
  811. while(!executeIterator->IsDone())
  812. {
  813. executeIterator->Next();
  814. }
  815. LogicDebug("\n%s\n\n", cutLine);
  816. }
  817. //Найти объект по идентификатору
  818. MissionObject * Mission::FindObject(const ConstString & id)
  819. {
  820. //Поиск через таблицу
  821. if(id.IsEmpty()) return null;
  822. long hash = id.Hash();
  823. long index = GetIndexInFFTableFromHash(hash);
  824. long count = fastFindTable[index].mo.Size();
  825. MissionObject ** mos = fastFindTable[index].mo.GetBuffer();
  826. for(long i = 0; i < count; i++)
  827. {
  828. MissionObject * mo = mos[i];
  829. if(mo->GetObjectID() == id)
  830. {
  831. return mo;
  832. }
  833. }
  834. return null;
  835. }
  836. /*
  837. //Изменить состояние видимости объекта
  838. MissionObject * Mission::ObjectShow(const char * id, bool isShow)
  839. {
  840. MissionObject * mo = FindObject(id);
  841. if(!mo) return null;
  842. mo->Show(isShow);
  843. return mo;
  844. }
  845. //Изменить состояние активности объекта
  846. MissionObject * Mission::ObjectActivate(const char * id, bool isActive)
  847. {
  848. MissionObject * mo = FindObject(id);
  849. if(!mo) return null;
  850. mo->Activate(isActive);
  851. return mo;
  852. }*/
  853. //Получить итератор по группе
  854. MGIterator & Mission::GroupIterator(GroupId group, const char* cppFileName, long cppFileLine)
  855. {
  856. //Получаем группу
  857. Group * grp = FindGroup(group);
  858. if(!grp)
  859. {
  860. sysRegistry(group, null, null, 0);
  861. grp = FindGroup(group);
  862. }
  863. //Создаём итератор
  864. MGIterator * it = grp->list.CreateIterator(cppFileName, cppFileLine);
  865. Assert(it);
  866. return *it;
  867. }
  868. //Изменить состояние видимости группы
  869. void Mission::GroupShow(GroupId group, bool isShow)
  870. {
  871. for(MGIterator & it = GroupIterator(group, _FL_); !it.IsDone(); it.Next())
  872. {
  873. it.Get()->Show(isShow);
  874. }
  875. it.Release();
  876. }
  877. //Изменить состояние активности группы
  878. void Mission::GroupActivate(GroupId group, bool isActive)
  879. {
  880. for(MGIterator & it = GroupIterator(group, _FL_); !it.IsDone(); it.Next())
  881. {
  882. it.Get()->Activate(isActive);
  883. }
  884. it.Release();
  885. }
  886. //Получить игрока
  887. MissionObject * Mission::Player()
  888. {
  889. if(player) return player;
  890. static const ConstString name("Player");
  891. MissionObject * mo = FindObject(name);
  892. if(!mo) return null;
  893. /*( if(!mo->Is("AIObject"))
  894. {
  895. api->Trace("Player not AIObject!");
  896. return null;
  897. }*/
  898. player = mo;
  899. return player;
  900. }
  901. //Получить матрицу качки
  902. const Matrix & Mission::GetSwingMatrix()
  903. {
  904. return swingMatrix;
  905. }
  906. //Получить инверсную матрицу качки
  907. const Matrix & Mission::GetInverseSwingMatrix()
  908. {
  909. return swingInverseMatrix;
  910. }
  911. //Получить параметры качки
  912. const Vector & Mission::GetSwingParams()
  913. {
  914. return swingAngs;
  915. }
  916. //Установить параметры качки
  917. void Mission::SetSwingParams(const Vector & angs)
  918. {
  919. swingAngs = angs;
  920. swingMatrix.Build(swingAngs);
  921. swingInverseMatrix.Inverse(swingMatrix);
  922. }
  923. //============================================================================================
  924. //Инициализация
  925. bool Mission::Init()
  926. {
  927. //Получаем переменные
  928. largeshot = api->Storage().GetItemLong("system.screenshot.Largeshot", _FL_);
  929. largeshotPrjScale = api->Storage().GetItemFloat("system.screenshot.Projection scale", _FL_);
  930. largeshotPrjX = api->Storage().GetItemFloat("system.screenshot.Projection x", _FL_);
  931. largeshotPrjY = api->Storage().GetItemFloat("system.screenshot.Projection y", _FL_);
  932. //Получаем указатели на сервисы
  933. services.file = (IFileService *)api->GetService("FileService");
  934. if(!services.file)
  935. {
  936. api->Trace("Mission::Init -> FileService is not created!");
  937. return false;
  938. }
  939. services.render = (IRender *)api->GetService("DX9Render");
  940. if(!services.render)
  941. {
  942. api->Trace("Mission::Init -> DX9Render is not created!");
  943. return false;
  944. }
  945. services.render->SetBackgroundColor(Color((dword)0xff000000));
  946. IAnimationService * ass = (IAnimationService *)api->GetService("AnimationService");
  947. if(!ass)
  948. {
  949. api->Trace("Mission::Init -> AnimationService is not created!");
  950. return false;
  951. }
  952. services.animation = ass->CreateScene(_FL_);
  953. //
  954. services.geometry = (IGMXService *)api->GetService("GMXService");
  955. if(!services.geometry)
  956. {
  957. api->Trace("Mission::Init -> GMXService is not created!");
  958. return false;
  959. }
  960. soundService = (ISoundService *)api->GetService("SoundService");
  961. if(!soundService)
  962. {
  963. api->Trace("Mission::Init -> SoundService is not created!");
  964. return false;
  965. }
  966. services.sound = soundService->CreateScene("Mission", _FL_);
  967. if(!services.sound)
  968. {
  969. api->Trace("Mission::Init -> SoundService is not created sound context!");
  970. return false;
  971. }
  972. IParticleService * psrv = (IParticleService *)api->GetService("ParticleService");
  973. if(!psrv)
  974. {
  975. api->Trace("Mission::Init -> ParticleService is not created!");
  976. return false;
  977. }
  978. services.particles = psrv->CreateManager(null);
  979. if(!services.particles)
  980. {
  981. api->Trace("Mission::Init -> ParticleManager is not created!");
  982. return false;
  983. }
  984. IControlsService * ictrl = (IControlsService *)api->GetService("ControlsService");
  985. services.ctrl = ictrl->CreateInstance(_FL_);
  986. if(!services.ctrl)
  987. {
  988. api->Trace("Mission::Init -> Controls not created!");
  989. return false;
  990. }
  991. services.ctrl->ExecuteCommand(InputSrvLockMouse(true));
  992. services.colsole = (IConsole *)api->GetService("Console");
  993. if(!services.colsole)
  994. {
  995. services.colsole = &fakeConsole;
  996. }
  997. IPhysics * phs = (IPhysics *)api->GetService("PhysicsService");
  998. if(!phs)
  999. {
  1000. api->Trace("Mission::Init -> PhysicsService is not created!");
  1001. return false;
  1002. }
  1003. services.physics = phs->CreateScene();
  1004. if(!services.physics)
  1005. {
  1006. api->Trace("Mission::Init -> PhysycsScene is not created!");
  1007. return false;
  1008. }
  1009. services.liveService = (ILiveService *)api->GetService("LiveService");
  1010. if(!services.liveService)
  1011. {
  1012. api->Trace("Mission::Init -> LiveSrvice is not created!");
  1013. return false;
  1014. }
  1015. /*
  1016. IPhysicsScene * scene = services.physics;
  1017. IPhysEditableRagdoll * ragdoll = scene->CreateEditableRagdoll();
  1018. IPhysEditableRagdoll::IBone & bone = ragdoll->GetRootBone();
  1019. bone.SetBoxShape(Matrix(), Vector(1.0f), 1.0f);
  1020. IPhysEditableRagdoll::IBone & chld = bone.AddChild();
  1021. chld.SetCapsuleShape(Matrix(0.0f, Vector(0.0f, 2.5f, 0.0f)), 2.0f, 0.3f, 3.0f);
  1022. IPhysEditableRagdoll::SphericalJointParams params;
  1023. params.worldJointPosition = Vector(0.0f, 1.0f, 0.0f);
  1024. bone.CreateSphericalJoint(chld, params);
  1025. */
  1026. //Ограничивающий объём
  1027. Plane planes[6];
  1028. planes[0] = Plane(Vector(0.0f, 1.0f, 0.0f), Vector(0.0f, -1000.0f, 0.0f));
  1029. planes[1] = Plane(Vector(0.0f, -1.0f, 0.0f), Vector(0.0f, 2000.0f, 0.0f));
  1030. const float planeMaxDist = 50000.0f;
  1031. planes[2] = Plane(Vector(0.0f, 0.0f, 1.0f), Vector(0.0f, 0.0f, -planeMaxDist));
  1032. planes[3] = Plane(Vector(0.0f, 0.0f, -1.0f), Vector(0.0f, 0.0f, planeMaxDist));
  1033. planes[4] = Plane(Vector(1.0f, 0.0f, 0.0f), Vector(-planeMaxDist, 0.0f, 0.0f));
  1034. planes[5] = Plane(Vector(-1.0f, 0.0f, 0.0f), Vector(planeMaxDist, 0.0f, 0.0f));
  1035. PhysicsCollisionGroup boundGroups[] = {
  1036. phys_world, phys_ragdoll, phys_character,
  1037. phys_player, phys_ship, phys_physobjects,
  1038. phys_charitems};
  1039. boundPlanes.Reserve((ARRSIZE(planes))*(ARRSIZE(boundGroups)));
  1040. for(long i = 0; i < ARRSIZE(planes); i++)
  1041. {
  1042. Plane & p = planes[i];
  1043. for(long j = 0; j < ARRSIZE(boundGroups); j++)
  1044. {
  1045. IPhysPlane * pl = services.physics->CreatePlane(_FL_, p.N, p.D);
  1046. if(pl)
  1047. {
  1048. pl->SetGroup(boundGroups[j]);
  1049. boundPlanes.Add(pl);
  1050. }
  1051. }
  1052. }
  1053. //Объект орбновляющий партиклы
  1054. particlesUpdater = NEW ParticlesUpdater();
  1055. sysSetThisPointerToObject(particlesUpdater);
  1056. sysSetObjectIDBeforeCreate(particlesUpdater, "ParticlesUpdater");
  1057. sysSetObjectTypeBeforeCreate(particlesUpdater, "ParticlesUpdater");
  1058. sysSetUpdate(ML_TRIGGERS-1, particlesUpdater, (MOF_UPDATE)&ParticlesUpdater::UpdateParticles);
  1059. sysSetUpdate(ML_PARTICLES5, particlesUpdater, (MOF_UPDATE)&ParticlesUpdater::DrawParticles);
  1060. //Объект орбновляющий физику
  1061. physicsUpdater = NEW PhysicsUpdater();
  1062. sysSetThisPointerToObject(physicsUpdater);
  1063. sysSetObjectIDBeforeCreate(physicsUpdater, "PhysicsUpdater");
  1064. sysSetObjectTypeBeforeCreate(physicsUpdater, "PhysicsUpdater");
  1065. sysSetUpdate(ML_FIRST, physicsUpdater, (MOF_UPDATE)&PhysicsUpdater::StartFrame);
  1066. sysSetUpdate(ML_LAST, physicsUpdater, (MOF_UPDATE)&PhysicsUpdater::EndFrame);
  1067. //Объект орбновляющий анимацию
  1068. animationUpdater = NEW AnimationUpdater();
  1069. sysSetThisPointerToObject(animationUpdater);
  1070. sysSetObjectIDBeforeCreate(animationUpdater, "AnimationUpdater");
  1071. sysSetObjectTypeBeforeCreate(animationUpdater, "AnimationUpdater");
  1072. animationUpdater->scene = &Animation();
  1073. animationUpdater->srv = ass;
  1074. sysSetUpdate(ML_LAST, animationUpdater, (MOF_UPDATE)&AnimationUpdater::UpdateAnimation);
  1075. //Объект инициирующий рисование постэффектов
  1076. postEffectsUpdater = NEW PostEffectsUpdater();
  1077. sysSetThisPointerToObject(postEffectsUpdater);
  1078. sysSetObjectIDBeforeCreate(postEffectsUpdater, "PostEffectsUpdater");
  1079. sysSetObjectTypeBeforeCreate(postEffectsUpdater, "PostEffectsUpdater");
  1080. sysSetUpdate(ML_FIRST + 1, postEffectsUpdater, (MOF_UPDATE)&PostEffectsUpdater::PreparePostEffects);
  1081. sysSetUpdate(ML_POSTEFFECTS, postEffectsUpdater, (MOF_UPDATE)&PostEffectsUpdater::DrawPostEffects);
  1082. //Флажёк дебага
  1083. IIniFile * ini = services.file->SystemIni();
  1084. if(ini)
  1085. {
  1086. enableDebug = ini->GetLong("Mission", "Debug", 0) != 0;
  1087. #ifndef _XBOX
  1088. static bool isFirstStart = true;
  1089. if(isFirstStart && ini->GetLong("Mission", "Debug clear", 0) != 0)
  1090. {
  1091. isFirstStart = false;
  1092. services.file->Delete(MISSION_DEBUGFILENAME);
  1093. }
  1094. #endif
  1095. profileLevel = ini->GetLong("Mission", "Profile", 0);
  1096. }
  1097. const char * errorDB = "! error access to database !";
  1098. LogicDebug("\n\n\n%s", cutLine);
  1099. LogicDebug("Platform: %s", api->Storage().GetString("runtime.platform", errorDB));
  1100. LogicDebug("Core: %s", api->Storage().GetString("system.core.id", errorDB));
  1101. LogicDebug("Build time: %s", api->Storage().GetString("system.core.build", errorDB));
  1102. LogicDebug("Game start time: %s", api->Storage().GetString("system.core.starttime", errorDB));
  1103. char tmpbuf[128];
  1104. __time64_t ltime;
  1105. _time64(&ltime);
  1106. struct tm today;
  1107. crt_localtime64(&today, &ltime);
  1108. strftime(tmpbuf, sizeof(tmpbuf), "%d %B %Y, %H:%M:%S", &today);
  1109. LogicDebug("Mission load time: %s", tmpbuf);
  1110. LogicDebug("%s\n\n\n", cutLine);
  1111. //Будем исполняться
  1112. api->SetObjectExecution(this, "mission", 0x1000, &Mission::FrameUpdate);
  1113. #ifndef NO_CONSOLE
  1114. debugObjectCurrent[0] = 0;
  1115. Console().Register_PureC_Command("activate", "activate <mission object name> : activate some mission object", Console_ActivateObject);
  1116. Console().Register_PureC_Command("deactivate", "deactivate <mission object name> : Deactivate some mission object", Console_DeactivateObject);
  1117. Console().Register_PureC_Command("show", "show <mission object name> : Show some mission object", Console_ShowObject);
  1118. Console().Register_PureC_Command("hide", "hide <mission object name> : Hide some mission object", Console_HideObject);
  1119. Console().Register_PureC_Command("command", "command <mission object name> command_name command params: Send command to some mission object", Console_CommandToObject);
  1120. Console().Register_PureC_Command("state", "state <mission object name> : View state of some mission object", Console_ViewStateObject);
  1121. Console().Register_PureC_Command("starttrace", "Start trace debug messages from set objects", Console_OnLogicDebug);
  1122. Console().Register_PureC_Command("stt", "Start trace debug messages from set objects", Console_OnLogicDebug);
  1123. Console().Register_PureC_Command("stoptrace", "Stop trace debug messages from set objects", Console_OffLogicDebug);
  1124. Console().Register_PureC_Command("stp", "Stop trace debug messages from set objects", Console_OffLogicDebug);
  1125. Console().Register_PureC_Command("trace", "add <mission object name> : Add object to debug trace list", Console_AddDebugObject);
  1126. //Console().Register_PureC_Command("tc", "add <mission object name> : Add object to debug trace list", Console_AddDebugObject);
  1127. Console().Register_PureC_Command("notrace", "del <mission object name> : Remove object from debug trace list", Console_DelDebugObject);
  1128. //Console().Register_PureC_Command("ntc", "del <mission object name> : Remove object from debug trace list", Console_DelDebugObject);
  1129. Console().Register_PureC_Command("tracelist", "Show trace debug list", Console_ViewDebugObjects);
  1130. //Console().Register_PureC_Command("tl", "Show trace debug list", Console_ViewDebugObjects);
  1131. Console().Register_PureC_Command("clearlist", "Clear trace debug list", Console_ClearDebugObjects);
  1132. //Console().Register_PureC_Command("cll", "Clear trace debug list", Console_ClearDebugObjects);
  1133. Console().Register_PureC_Command("sounds", "sounds [none|2d|3d|lis|lis3d|all] [1|2]; default parameters: all 2", Console_ShowSoundsDebug);
  1134. Console().Register_PureC_Command("storage", "Show storage access commands", Console_Storage);
  1135. Console().Register_PureC_Command("fc", "Activate/deactivatre \"Free camere\"", Console_FreeCamera);
  1136. Console().Register_PureC_Command("locstrings", "Output to system log unuse loc strings", Console_TraceUnuse);
  1137. /*
  1138. Console().Register_PureC_Command("storageview", "storageview [field_name1 field_name2 ... field_nameX]", Console_StorageView);
  1139. Console().Register_PureC_Command("storageset", "storageset type(string,long,float) field_name value", Console_StorageSet);
  1140. Console().Register_PureC_Command("storagedel", "storagedel field_name", Console_StorageDel);
  1141. Console().Register_PureC_Command("storagecopy", "storagecopy field_name_from field_name_to", Console_StorageCopy);
  1142. */
  1143. #endif
  1144. return true;
  1145. }
  1146. //Создать миссионный объект в режиме игры
  1147. bool Mission::CreateObjectEx(const char * name, MOPReader & rd, const void * initData, long initDataSize)
  1148. {
  1149. MissionObject * obj = sysCreateObject(name, rd);
  1150. if(!obj)
  1151. {
  1152. return false;
  1153. }
  1154. sysSetObjectReaderDataBeforeCreate(obj, initData, initDataSize, null);
  1155. return true;
  1156. }
  1157. //Отрисовка
  1158. void __fastcall Mission::FrameUpdate(float dltTime)
  1159. {
  1160. if(isSleep) return;
  1161. #ifndef NO_CONSOLE
  1162. controlMission = this;
  1163. #endif
  1164. //Получим текущий коэфициент масштаба времени
  1165. float timeScale = 1.0f;
  1166. long timescaleGroupCount = timeModifiers;
  1167. float ** tms = timeModifiers.GetBuffer();
  1168. for(long i = 0; i < timescaleGroupCount; i++)
  1169. {
  1170. timeScale *= *tms[i];
  1171. }
  1172. dltTime *= timeScale;
  1173. if(loader)
  1174. {
  1175. if(loader->IsDone())
  1176. {
  1177. delete loader;
  1178. loader = null;
  1179. }else{
  1180. return;
  1181. }
  1182. }
  1183. #ifndef STOP_LOGICTRACE
  1184. /*
  1185. for(Mission ** missStart = &traceFirstInList; *missStart; missStart = &((*missStart)->traceNextInList))
  1186. {
  1187. Assert(*missStart != this);
  1188. }
  1189. *missStart = this;
  1190. traceNextInList = null;
  1191. */
  1192. //По рекурсии список выведеться задом наперёд
  1193. traceNextInList = traceFirstInList;
  1194. traceFirstInList = this;
  1195. traceDltTime = dltTime;
  1196. traceTimeScale = timeScale;
  1197. traceFPS = api->EngineFps();
  1198. traceIsOutHeader = false;
  1199. #endif
  1200. #ifndef _XBOX
  1201. if(api->DebugKeyState(VK_F7))
  1202. {
  1203. if(api->DebugKeyState(VK_SHIFT))
  1204. {
  1205. api->Trace("\nMemory statistics:");
  1206. api->Trace(" SHIFT+F7 - sort by size");
  1207. api->Trace(" SHIFT+1+F7 - sort by blocks count");
  1208. api->Trace(" SHIFT+2+F7 - sort by alloc frequency");
  1209. api->Trace(" SHIFT+3+F7 - sort by files\n");
  1210. if(api->DebugKeyState('1'))
  1211. {
  1212. CoreCommand_MemStat memStats(cmemstat_byblocks);
  1213. api->ExecuteCoreCommand(memStats);
  1214. }else
  1215. if(api->DebugKeyState('2'))
  1216. {
  1217. CoreCommand_MemStat memStats(cmemstat_byfreq);
  1218. api->ExecuteCoreCommand(memStats);
  1219. }else
  1220. if(api->DebugKeyState('3'))
  1221. {
  1222. CoreCommand_MemStat memStats(cmemstat_byfile);
  1223. api->ExecuteCoreCommand(memStats);
  1224. }else{
  1225. CoreCommand_MemStat memStats(cmemstat_bysize);
  1226. api->ExecuteCoreCommand(memStats);
  1227. }
  1228. }else{
  1229. StartProfile();
  1230. }
  1231. }else{
  1232. StopProfile();
  1233. }
  1234. if(api->DebugKeyState('R'))
  1235. {
  1236. if(api->DebugKeyState(VK_SHIFT))
  1237. {
  1238. api->SetTimeScale(6.0f);
  1239. }else{
  1240. api->SetTimeScale(3.0f);
  1241. }
  1242. }else
  1243. if(api->DebugKeyState('Y'))
  1244. {
  1245. if(api->DebugKeyState(VK_SHIFT))
  1246. {
  1247. api->SetTimeScale(0.05f);
  1248. }else{
  1249. api->SetTimeScale(0.3f);
  1250. }
  1251. }else{
  1252. api->SetTimeScale(1.0f);
  1253. }
  1254. if(isProcessMissionPause && api->DebugKeyState(VK_PAUSE))
  1255. {
  1256. isMissionPause = !isMissionPause;
  1257. MissionPause(isMissionPause);
  1258. Sleep(100);
  1259. }
  1260. #endif
  1261. /*
  1262. Вернуть когда будет переписан звуковой сервис
  1263. if(!isEditMode)
  1264. {
  1265. Files().LockFileAccess(true);
  1266. }
  1267. */
  1268. if(isMissionPause) dltTime = 0.0f;
  1269. Sound().SetListenerMatrix(Matrix(Render().GetView()).Inverse());
  1270. bool isCorrectPrj = largeshot ? largeshot->Get(0) != 0 : false;
  1271. for(executeIterator->Reset(); !executeIterator->IsDone(); executeIterator->Next())
  1272. {
  1273. if(isCorrectPrj && executeIterator->Level() > ML_CAMERAMOVE_FREE)
  1274. {
  1275. isCorrectPrj = false;
  1276. Matrix prj = Render().GetProjection();
  1277. float scale = largeshotPrjScale ? largeshotPrjScale->Get(8.0f) : 8.0f;
  1278. float x = largeshotPrjX ? largeshotPrjX->Get(0.0f) : 0.0f;
  1279. float y = largeshotPrjY ? largeshotPrjY->Get(0.0f) : 0.0f;
  1280. prj.vx.x *= scale;
  1281. prj.vy.y *= scale;
  1282. prj.vz.x = scale - 1.0f - x*2.0f;
  1283. prj.vz.y = scale - 1.0f - (scale - 1.0f - y)*2.0f;
  1284. Render().SetProjection(prj);
  1285. }
  1286. #ifdef _XBOX
  1287. #ifndef STOP_PROFILES
  1288. MissionObject * mo = executeIterator->Get();
  1289. if(mo)
  1290. {
  1291. // PIXBeginNamedEvent(0, mo->GetObjectType());
  1292. }
  1293. ProfileTimer timer;
  1294. #endif
  1295. #endif
  1296. executeList.ExecuteUpdate(dltTime, executeIterator);
  1297. #ifdef _XBOX
  1298. #ifndef STOP_PROFILES
  1299. if(mo)
  1300. {
  1301. timer.AddToCounter(mo->GetObjectType(), 1000.0f/50000000.0f);
  1302. // PIXEndNamedEvent();
  1303. }
  1304. #endif
  1305. #endif
  1306. }
  1307. soundService->DebugDraw();
  1308. for(dword i = 0; i < validateCacheCounter; i++)
  1309. {
  1310. validateCache[i].useCounter = 1;
  1311. }
  1312. Physics().DebugDraw(Render());
  1313. if(!isEditMode)
  1314. {
  1315. Files().LockFileAccess(false);
  1316. }
  1317. #ifndef STOP_LOGICTRACE
  1318. //Выводим сообщение об окончании кадра
  1319. if(traceIsOutHeader)
  1320. {
  1321. LogicDebug("---------<Frame end: frame = %d, mission name = %s>---------", framesCounter, name.c_str());
  1322. }
  1323. //Удаляем себя из списка активных
  1324. for(Mission ** missEnd = &traceFirstInList; *missEnd; )
  1325. {
  1326. if(*missEnd == this)
  1327. {
  1328. *missEnd = (*missEnd)->traceNextInList;
  1329. }else{
  1330. missEnd = &((*missEnd)->traceNextInList);
  1331. }
  1332. }
  1333. #endif
  1334. framesCounter++;
  1335. }
  1336. //Запустить встроенный профайлинг
  1337. void Mission::StartProfile()
  1338. {
  1339. #ifndef STOP_PROFILES
  1340. MissionProfiler::Start(profileLevel);
  1341. #endif
  1342. }
  1343. //Остановить встроенный профайлинг
  1344. void Mission::StopProfile()
  1345. {
  1346. #ifndef STOP_PROFILES
  1347. MissionProfiler::Stop();
  1348. #endif
  1349. }
  1350. bool Mission::CompareProfileElements(Element * const & grtElm, Element * const & lesElm)
  1351. {
  1352. #ifndef STOP_PROFILES
  1353. return lesElm->sum < grtElm->sum;
  1354. #else
  1355. return false;
  1356. #endif
  1357. }
  1358. bool Mission::CompareProfileObjects(const ProfileObject & grtElm, const ProfileObject & lesElm)
  1359. {
  1360. #ifndef STOP_PROFILES
  1361. return lesElm.sum < grtElm.sum;
  1362. #else
  1363. return false;
  1364. #endif
  1365. }
  1366. bool Mission::CompareProfileTypes(const ProfileType & grtElm, const ProfileType & lesElm)
  1367. {
  1368. #ifndef STOP_PROFILES
  1369. return lesElm.sum < grtElm.sum;
  1370. #else
  1371. return false;
  1372. #endif
  1373. }
  1374. bool Mission::CompareProfileCreations(const ProfileCreation & grtElm, const ProfileCreation & lesElm)
  1375. {
  1376. #ifndef STOP_PROFILES
  1377. return lesElm.time < grtElm.time;
  1378. #else
  1379. return false;
  1380. #endif
  1381. }
  1382. //Подвести итоги профайла загрузки
  1383. void Mission::CreationProfile()
  1384. {
  1385. #ifndef STOP_PROFILES
  1386. //Таблица по типам
  1387. array<ProfileType> profileTypeTable(_FL_);
  1388. double full = 0.0f;
  1389. for(long i = 0; i < creationTable; i++)
  1390. {
  1391. ProfileCreation & pc = creationTable[i];
  1392. full += (double)pc.time;
  1393. for(long j = 0; j < profileTypeTable; j++)
  1394. {
  1395. ProfileType & pt = profileTypeTable[j];
  1396. if(pc.type == pt.type || string::IsEqual(pc.type, pt.type))
  1397. {
  1398. pt.sum += (double)pc.time;
  1399. pt.counter++;
  1400. if(pt.max < (double)pc.time) pt.max = (double)pc.time;
  1401. break;
  1402. }
  1403. }
  1404. if(j >= profileTypeTable)
  1405. {
  1406. ProfileType & pt = profileTypeTable[profileTypeTable.Add()];
  1407. pt.type = pc.type;
  1408. pt.sum = pt.max = (double)pc.time;
  1409. pt.counter = 1;
  1410. }
  1411. }
  1412. profileTypeTable.QSort(&Mission::CompareProfileTypes);
  1413. //Выводим накопленные данные
  1414. static const char * stopLine = "------------------------------------------------------------------";
  1415. api->Trace(stopLine);
  1416. api->Trace("Mission creation profile info start");
  1417. api->Trace(stopLine);
  1418. api->Trace("");
  1419. api->Trace("Brake per type");
  1420. api->Trace("");
  1421. api->Trace("Brake\t\tpercents objectType objects average max total");
  1422. api->Trace("");
  1423. for(i = 0; i < profileTypeTable; i++)
  1424. {
  1425. ProfileType & t = profileTypeTable[i];
  1426. double average = t.sum/double(t.counter ? t.counter : 1);
  1427. api->Trace("%5d\t\t%4.4f\t %20s %8d %10.0f %10.0f %10.0f",
  1428. i + 1,
  1429. t.sum/full*100.0,
  1430. t.type,
  1431. t.counter ? t.counter : 1,
  1432. average + 0.5,
  1433. t.max + 0.5,
  1434. t.sum);
  1435. }
  1436. api->Trace("");
  1437. if(profileLevel > 1)
  1438. {
  1439. creationTable.QSort(&Mission::CompareProfileCreations);
  1440. api->Trace("");
  1441. api->Trace("Brake per object");
  1442. api->Trace("");
  1443. api->Trace("Brake\t\tpercents objectType object time");
  1444. api->Trace("");
  1445. for(long i = 0; i < creationTable; i++)
  1446. {
  1447. ProfileCreation & pc = creationTable[i];
  1448. api->Trace("%5d\t\t%4.4f\t %20s %32s %10.0f",
  1449. i + 1,
  1450. (double)pc.time/full*100.0,
  1451. pc.type,
  1452. pc.id,
  1453. (float)pc.time);
  1454. }
  1455. }
  1456. api->Trace(stopLine);
  1457. api->Trace("Total: %f", full);
  1458. api->Trace("Create objects: %i", creationTable.Size());
  1459. api->Trace(stopLine);
  1460. api->Trace("Mission creation profile info end");
  1461. api->Trace(stopLine);
  1462. api->Trace("\n\n");
  1463. creationTable.DelAll();
  1464. #endif
  1465. }
  1466. //Найти группу по имени
  1467. Mission::Group * Mission::FindGroup(GroupId group)
  1468. {
  1469. Group * g = entryGroups[group.id & (ARRSIZE(entryGroups) - 1)];
  1470. for(; g; g = g->next)
  1471. {
  1472. if(g->id.id == group.id) return g;
  1473. }
  1474. return null;
  1475. }
  1476. //Добавить миссионный объект в таблицу быстрого поиска
  1477. __forceinline void Mission::AddMissionObjectToFFTable(MissionObject * mo)
  1478. {
  1479. if(!mo) return;
  1480. long hash = mo->GetObjectID().Hash();
  1481. long index = GetIndexInFFTableFromHash(hash);
  1482. fastFindTable[index].mo.Add(mo);
  1483. }
  1484. //Удалить миссионный объект из таблицы быстрого поиска
  1485. __forceinline void Mission::RemoveMissionObjectFromFFTable(MissionObject * mo)
  1486. {
  1487. if(!mo) return;
  1488. long hash = mo->GetObjectID().Hash();
  1489. long index = GetIndexInFFTableFromHash(hash);
  1490. fastFindTable[index].mo.Del(mo);
  1491. }
  1492. //Получить индекс в таблице поизка из хэша
  1493. __forceinline long Mission::GetIndexInFFTableFromHash(long hash)
  1494. {
  1495. return hash & (ARRSIZE(fastFindTable) - 1);
  1496. }
  1497. //Установить объекту уникальный номер
  1498. __forceinline void Mission::SetObjectUId(MissionObject * mo)
  1499. {
  1500. //До сюда не должен счётчик дойти и через 100 лет работы в редакторе и никогда в игре
  1501. Assert(uIdCodeCounter < 0xfffffff0);
  1502. sysSetObjectUID(mo, uIdCodeCounter);
  1503. uIdCodeCounter++;
  1504. }
  1505. //============================================================================================
  1506. void Mission::sysRegistry(GroupId group, MissionObject * object, MOF_EVENT func, long level)
  1507. {
  1508. //Получаем группу
  1509. Group * grp = FindGroup(group);
  1510. if(!grp)
  1511. {
  1512. //Регистрируем группу
  1513. grp = NEW Group();
  1514. grp->id = group;
  1515. grp->next = entryGroups[group.id & (ARRSIZE(entryGroups) - 1)];
  1516. grp->list.SetId(grp->id);
  1517. entryGroups[grp->id.id & (ARRSIZE(entryGroups) - 1)] = grp;
  1518. this->group.Add(grp);
  1519. }
  1520. if(object)
  1521. {
  1522. MissionObjectsList::Func lfunc;
  1523. lfunc.funcEvent = func;
  1524. grp->list.Add(object, level, lfunc);
  1525. }
  1526. }
  1527. void Mission::sysUnregistry(GroupId group, MissionObject * object)
  1528. {
  1529. Group * grp = FindGroup(group);
  1530. if(grp)
  1531. {
  1532. grp->list.Del(object);
  1533. }
  1534. }
  1535. void Mission::sysUnregistryAll(MissionObject * object)
  1536. {
  1537. if(player == object) player = null;
  1538. for(dword i = 0; i < validateCacheCounter; i++)
  1539. {
  1540. if(validateCache[i].obj == object)
  1541. {
  1542. validateCache[i] = validateCache[--validateCacheCounter];
  1543. }
  1544. }
  1545. for(long i = 0; i < group; i++)
  1546. {
  1547. group[i]->list.Del(object);
  1548. }
  1549. }
  1550. void Mission::sysEvent(GroupId group, MissionObject * object)
  1551. {
  1552. for(MGIterator & it = GroupIterator(group, _FL_); !it.IsDone(); it.Next())
  1553. {
  1554. it.ExecuteEvent(object);
  1555. }
  1556. it.Release();
  1557. }
  1558. void Mission::sysSetUpdate(long level, MissionObject * obj, MOF_UPDATE func)
  1559. {
  1560. if(!func) return;
  1561. MissionObjectsList::Func lfunc;
  1562. lfunc.funcUpdate = func;
  1563. executeList.Add(obj, level, lfunc);
  1564. }
  1565. void Mission::sysDelUpdate(long level, MissionObject * obj, MOF_UPDATE func)
  1566. {
  1567. MissionObjectsList::Func lfunc;
  1568. lfunc.funcUpdate = func;
  1569. executeList.Del(obj, level, lfunc);
  1570. }
  1571. void Mission::sysDelUpdate(MissionObject * obj, MOF_UPDATE func)
  1572. {
  1573. MissionObjectsList::Func lfunc;
  1574. if(func)
  1575. {
  1576. lfunc.funcUpdate = func;
  1577. executeList.Del(obj, lfunc);
  1578. }else{
  1579. executeList.Del(obj);
  1580. }
  1581. }
  1582. void Mission::sysDeleteObject(MissionObject * object)
  1583. {
  1584. executeList.Del(object);
  1585. sysUnregistryAll(object);
  1586. RemoveMissionObjectFromFFTable(object);
  1587. objectsList.Del(object);
  1588. }
  1589. void Mission::sysUpdateObjectID(MissionObject * obj, const char * oldId, const char * newId)
  1590. {
  1591. RemoveMissionObjectFromFFTable(obj);
  1592. sysSetObjectIDBeforeCreate(obj, newId);
  1593. AddMissionObjectToFFTable(obj);
  1594. player = null;
  1595. }
  1596. void Mission::sysLogicDebug(MissionObject * mo, const char * format, void * data, bool isError)
  1597. {
  1598. #ifndef STOP_LOGICTRACE
  1599. if(isEditMode)
  1600. {
  1601. return;
  1602. }
  1603. if(enableDebug)
  1604. {
  1605. for(Mission ** mis = &traceFirstInList; *mis; mis = &((*mis)->traceNextInList))
  1606. {
  1607. if(!(*mis)->traceIsOutHeader)
  1608. {
  1609. (*mis)->traceIsOutHeader = true;
  1610. LogicDebug("---------<Frame start: frame = %d, dltTime = %f (timeScale = %f), fps = %f, mission name = %s>---------", (*mis)->framesCounter, (*mis)->traceDltTime, (*mis)->traceTimeScale, (*mis)->traceFPS, (*mis)->name.c_str());
  1611. }
  1612. }
  1613. FILE * f = crt_fopen(MISSION_DEBUGFILENAME, "a+t");
  1614. if(f)
  1615. {
  1616. #ifndef NO_CONSOLE
  1617. fseek(f, 0, SEEK_END);
  1618. long pos = ftell(f);
  1619. #endif
  1620. const char * space = logicDebugLevelString.GetBuffer();
  1621. if(mo) fprintf(f, "%sObject: \"%s\", type: %s\n", space, mo->GetObjectID().c_str(), mo->GetObjectType());
  1622. if(isError)
  1623. {
  1624. fprintf(f, "! <error> %s -> ", space);
  1625. }else{
  1626. fprintf(f, "%s%s", space, mo ? ">" : "");
  1627. }
  1628. vfprintf(f, format, (va_list)data);
  1629. fprintf(f, "\n");
  1630. #ifndef NO_CONSOLE
  1631. if(enableConsoleLogicDebug)
  1632. {
  1633. //Сохраняем имя объекта нулевого уровня
  1634. if(mo && logicDebugLevelString.IsEmpty())
  1635. {
  1636. const char * id = mo->GetObjectID().c_str();
  1637. for(long i = 0; i < ARRSIZE(debugObjectCurrent) && id[i]; i++)
  1638. {
  1639. debugObjectCurrent[i] = id[i];
  1640. }
  1641. debugObjectCurrent[ARRSIZE(debugObjectCurrent) - 1] = 0;
  1642. }
  1643. //Проверяем по фильтру
  1644. for(long i = 0; i < debugObjectsCounts; i++)
  1645. {
  1646. if(string::IsEqual(debugObjectCurrent, debugObjects[i]))
  1647. {
  1648. break;
  1649. }
  1650. }
  1651. bool isOut = (i < debugObjectsCounts);
  1652. if(mo)
  1653. {
  1654. const char * id = mo->GetObjectID().c_str();
  1655. for(long i = 0; i < debugObjectsCounts; i++)
  1656. {
  1657. if(string::IsEqual(id, debugObjects[i]))
  1658. {
  1659. isOut = true;
  1660. break;
  1661. }
  1662. }
  1663. }
  1664. if(isOut)
  1665. {
  1666. long len = ftell(f) - pos;
  1667. if(len > 0)
  1668. {
  1669. if(len > 4095) len = 4095;
  1670. char buf[4096];
  1671. fseek(f, pos, SEEK_SET);
  1672. pos = fread(buf, 1, len, f);
  1673. if(pos > len) pos = len;
  1674. buf[pos] = 0;
  1675. Console().Trace(COL_DESIGNERS, buf);
  1676. }
  1677. }
  1678. }
  1679. #endif
  1680. fclose(f);
  1681. }
  1682. }
  1683. #endif
  1684. }
  1685. void Mission::sysLogicDebugLevel(bool increase)
  1686. {
  1687. #ifndef STOP_LOGICTRACE
  1688. if(increase)
  1689. {
  1690. LogicDebug("{");
  1691. logicDebugLevelString += LOGICTRACE_SPACE;
  1692. }else{
  1693. dword size = sizeof(LOGICTRACE_SPACE) - 1;
  1694. if(logicDebugLevelString.Len() <= size)
  1695. {
  1696. logicDebugLevelString.Empty();
  1697. }else{
  1698. logicDebugLevelString.Delete(logicDebugLevelString.Len() - size, size);
  1699. }
  1700. LogicDebug("}");
  1701. if(logicDebugLevelString.IsEmpty())
  1702. {
  1703. debugObjectCurrent[0] = 0;
  1704. }
  1705. }
  1706. #endif
  1707. }
  1708. IMissionQTObject * Mission::sysQTCreateObject(GroupId group, MissionObject * mo, const char* cppFileName, long cppFileLine)
  1709. {
  1710. Group * grp = FindGroup(group);
  1711. if(!grp)
  1712. {
  1713. sysRegistry(group, null, null, null);
  1714. sysUnregistry(group, null);
  1715. grp = FindGroup(group);
  1716. if(!grp) return false;
  1717. }
  1718. return grp->findManager.CreateObject(mo, cppFileName, cppFileLine);
  1719. }
  1720. dword Mission::sysQTFindObjects(GroupId group, Vector minVrt, Vector maxVrt)
  1721. {
  1722. objectsFindList.Empty();
  1723. Group * grp = FindGroup(group);
  1724. if(grp)
  1725. {
  1726. grp->findManager.FindObjects(minVrt, maxVrt, objectsFindList);
  1727. }
  1728. return objectsFindList.Size();
  1729. }
  1730. IMissionQTObject * Mission::sysQTGetObject(dword index)
  1731. {
  1732. return objectsFindList[index];
  1733. }
  1734. void Mission::sysQTDraw(GroupId group, float levelScale)
  1735. {
  1736. Group * grp = FindGroup(group);
  1737. if(grp)
  1738. {
  1739. grp->findManager.Draw(services.render, levelScale);
  1740. }
  1741. }
  1742. void Mission::sysQTDump(GroupId group)
  1743. {
  1744. Group * grp = FindGroup(group);
  1745. char name[5];
  1746. name[0] = char(group.id >> 0);
  1747. name[1] = char(group.id >> 8);
  1748. name[2] = char(group.id >> 16);
  1749. name[3] = char(group.id >> 24);
  1750. name[4] = 0;
  1751. if(grp)
  1752. {
  1753. api->Trace("************************************************\nDump mission quad tree from group \"%s\"\n\n\n", name);
  1754. grp->findManager.Dump();
  1755. api->Trace("************************************************\n", name);
  1756. }else{
  1757. api->Trace("Can't dump mission quad tree from group \"%s\" - group not found", name);
  1758. }
  1759. }
  1760. bool Mission::sysFindObject(const ConstString * id, MissionObject * & object, dword & uid)
  1761. {
  1762. if(id)
  1763. {
  1764. object = FindObject(*id);
  1765. if(!object)
  1766. {
  1767. uid = 0;
  1768. return false;
  1769. }
  1770. }
  1771. Assert(object);
  1772. uid = object->GetObjectUID();
  1773. return true;
  1774. }
  1775. bool Mission::sysValidatePointer(MissionObject * object, dword uid, long & hashIndex)
  1776. {
  1777. return objectsList.InList(object, uid, hashIndex);
  1778. }
  1779. //============================================================================================
  1780. //Console functions
  1781. //============================================================================================
  1782. #ifndef NO_CONSOLE
  1783. void _cdecl Mission::Console_ActivateObject(const ConsoleStack & params)
  1784. {
  1785. MissionObject * mo = Console_GetMissionObject(params);
  1786. if(!mo) return;
  1787. mo->Activate(true);
  1788. if(mo->IsActive())
  1789. {
  1790. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" is active.", params.GetParam(0));
  1791. }else{
  1792. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" is not active.", params.GetParam(0));
  1793. }
  1794. }
  1795. void _cdecl Mission::Console_DeactivateObject(const ConsoleStack & params)
  1796. {
  1797. MissionObject * mo = Console_GetMissionObject(params);
  1798. if(!mo) return;
  1799. mo->Activate(false);
  1800. if(mo->IsActive())
  1801. {
  1802. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" active.", params.GetParam(0));
  1803. }else{
  1804. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" is not active.", params.GetParam(0));
  1805. }
  1806. }
  1807. void _cdecl Mission::Console_ShowObject(const ConsoleStack & params)
  1808. {
  1809. MissionObject * mo = Console_GetMissionObject(params);
  1810. if(!mo) return;
  1811. mo->Show(true);
  1812. if(mo->IsShow())
  1813. {
  1814. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" is show.", params.GetParam(0));
  1815. }else{
  1816. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" can't be show.", params.GetParam(0));
  1817. }
  1818. }
  1819. void _cdecl Mission::Console_HideObject(const ConsoleStack & params)
  1820. {
  1821. MissionObject * mo = Console_GetMissionObject(params);
  1822. if(!mo) return;
  1823. mo->Show(false);
  1824. if(mo->IsShow())
  1825. {
  1826. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" can't be hide.", params.GetParam(0));
  1827. }else{
  1828. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" is hide.", params.GetParam(0));
  1829. }
  1830. }
  1831. void _cdecl Mission::Console_CommandToObject(const ConsoleStack & params)
  1832. {
  1833. MissionObject * mo = Console_GetMissionObject(params);
  1834. if(!mo) return;
  1835. if(params.GetSize() < 2)
  1836. {
  1837. console->Trace(COL_CMD_OUTPUT, "Not define command name for mission object.");
  1838. return;
  1839. }
  1840. const char * cmdParams[64];
  1841. long paramsCount = params.GetSize() - 2;
  1842. if(paramsCount > ARRSIZE(cmdParams)) paramsCount = ARRSIZE(cmdParams);
  1843. if(paramsCount < 0) paramsCount = 0;
  1844. for(long i = 0; i < paramsCount; i++)
  1845. {
  1846. cmdParams[i] = params.GetParam(i + 2);
  1847. }
  1848. mo->Command(params.GetParam(1), paramsCount, cmdParams);
  1849. console->Trace(COL_CMD_OUTPUT, "Execute command for mission object \"%s\".", params.GetParam(0));
  1850. }
  1851. void _cdecl Mission::Console_ViewStateObject(const ConsoleStack & params)
  1852. {
  1853. MissionObject * mo = Console_GetMissionObject(params);
  1854. if(!mo) return;
  1855. console->Trace(COL_CMD_OUTPUT, "Mission object: \"%s\"", params.GetParam(0));
  1856. console->Trace(COL_CMD_OUTPUT, " Visible state: \"%s\"", mo->IsShow() ? "show" : "hide");
  1857. console->Trace(COL_CMD_OUTPUT, " Active state: \"%s\"", mo->IsActive() ? "active" : "not active");
  1858. MO_IS_IF(id_DamageReceiverObject, "DamageReceiver", mo)
  1859. {
  1860. DamageReceiver * ai = (DamageReceiver *)mo;
  1861. console->Trace(COL_CMD_OUTPUT, " HP: \"%f\"", ai->GetHP());
  1862. console->Trace(COL_CMD_OUTPUT, " Max HP: \"%f\"", ai->GetMaxHP());
  1863. console->Trace(COL_CMD_OUTPUT, " It is \"%s\"", ai->IsDead() ? "dead" : (ai->IsDie() ? "die" : "alive"));
  1864. }
  1865. console->Trace(COL_CMD_OUTPUT, " state: \"%s\"", mo->IsActive() ? "active" : "not active");
  1866. Matrix mtx; mtx.SetZero();
  1867. mo->GetMatrix(mtx);
  1868. for(long i = 0; i < 16; i++)
  1869. {
  1870. if(fabsf(mtx.matrix[i]) > 1e-30f) break;
  1871. }
  1872. if(i < 16)
  1873. {
  1874. console->Trace(COL_CMD_OUTPUT, " Position: (%f, %f, %f)", mtx.pos.x, mtx.pos.y, mtx.pos.z);
  1875. }
  1876. }
  1877. void _cdecl Mission::Console_OnLogicDebug(const ConsoleStack & params)
  1878. {
  1879. if(Console_NoExecute()) return;
  1880. enableConsoleLogicDebug = true;
  1881. console->Trace(COL_CMD_OUTPUT, "Start trace logic debug messages");
  1882. }
  1883. void _cdecl Mission::Console_OffLogicDebug(const ConsoleStack & params)
  1884. {
  1885. if(Console_NoExecute()) return;
  1886. enableConsoleLogicDebug = false;
  1887. console->Trace(COL_CMD_OUTPUT, "Stop trace logic debug messages");
  1888. }
  1889. void _cdecl Mission::Console_TraceLogicDebug(const ConsoleStack & params)
  1890. {
  1891. if(Console_NoExecute()) return;
  1892. const char * param = params.GetParam(0);
  1893. if(!param) param = "";
  1894. controlMission->LogicDebug(param);
  1895. }
  1896. void _cdecl Mission::Console_AddDebugObject(const ConsoleStack & params)
  1897. {
  1898. if(Console_NoExecute()) return;
  1899. if(params.GetSize() == 0)
  1900. {
  1901. console->Trace(COL_CMD_OUTPUT, "Invalidate mission object name.");
  1902. return;
  1903. }
  1904. if(strlen(params.GetParam(0)) > 127)
  1905. {
  1906. console->Trace(COL_CMD_OUTPUT, "Mission object name is very long.");
  1907. return;
  1908. }
  1909. for(long i = 0; i < debugObjectsCounts; i++)
  1910. {
  1911. if(string::IsEqual(debugObjects[i], params.GetParam(0)))
  1912. {
  1913. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" already in debug list.", params.GetParam(0));
  1914. return;
  1915. }
  1916. }
  1917. if(debugObjectsCounts >= 64)
  1918. {
  1919. console->Trace(COL_CMD_OUTPUT, "Can't addition object to list - debug list is full.");
  1920. return;
  1921. }
  1922. crt_strcpy(debugObjects[debugObjectsCounts++], 127, params.GetParam(0));
  1923. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" addition to debug list.", params.GetParam(0));
  1924. }
  1925. void _cdecl Mission::Console_DelDebugObject(const ConsoleStack & params)
  1926. {
  1927. if(Console_NoExecute()) return;
  1928. if(params.GetSize() == 0)
  1929. {
  1930. console->Trace(COL_CMD_OUTPUT, "Invalidate mission object name.");
  1931. return;
  1932. }
  1933. for(long i = 0; i < debugObjectsCounts; i++)
  1934. {
  1935. if(string::IsEqual(debugObjects[i], params.GetParam(0)))
  1936. {
  1937. for(debugObjectsCounts--; i < debugObjectsCounts; i++)
  1938. {
  1939. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" remove from debug list.", params.GetParam(0));
  1940. crt_strcpy(debugObjects[i], 127, debugObjects[i + 1]);
  1941. }
  1942. return;
  1943. }
  1944. }
  1945. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" not found in debug list.", params.GetParam(0));
  1946. }
  1947. void _cdecl Mission::Console_ViewDebugObjects(const ConsoleStack & params)
  1948. {
  1949. if(Console_NoExecute()) return;
  1950. console->Trace(COL_CMD_OUTPUT, "Debug list:");
  1951. for(long i = 0; i < debugObjectsCounts; i++)
  1952. {
  1953. console->Trace(COL_CMD_OUTPUT, " [%i] \"%s\"", i, debugObjects[i]);
  1954. }
  1955. console->Trace(COL_CMD_OUTPUT, "Total objects in debug list: %i", debugObjectsCounts);
  1956. }
  1957. void _cdecl Mission::Console_ClearDebugObjects(const ConsoleStack & params)
  1958. {
  1959. if(Console_NoExecute()) return;
  1960. debugObjectsCounts = 0;
  1961. }
  1962. void _cdecl Mission::Console_ShowSoundsDebug(const ConsoleStack & params)
  1963. {
  1964. if(Console_NoExecute()) return;
  1965. ISoundService * srv = (ISoundService *)api->GetService("SoundService");
  1966. ISoundService::DebugLevel level = ISoundService::dl_maximum;
  1967. ISoundService::DebugView view = srv->GetDebugView() != ISoundService::dv_none ? ISoundService::dv_none : ISoundService::dv_all;
  1968. for(dword i = 0; i < params.GetSize(); i++)
  1969. {
  1970. const char * p = params.GetParam(i);
  1971. if(string::IsEqual(p, "viewmin"))
  1972. {
  1973. level = ISoundService::dl_minimal;
  1974. }else
  1975. if(string::IsEqual(p, "viewmax"))
  1976. {
  1977. level = ISoundService::dl_maximum;
  1978. }else
  1979. if(string::IsEqual(p, "none"))
  1980. {
  1981. view = ISoundService::dv_none;
  1982. }else
  1983. if(string::IsEqual(p, "2d"))
  1984. {
  1985. view = ISoundService::dv_2d;
  1986. }else
  1987. if(string::IsEqual(p, "3d"))
  1988. {
  1989. view = ISoundService::dv_3d;
  1990. }else
  1991. if(string::IsEqual(p, "lis"))
  1992. {
  1993. view = ISoundService::dv_listener;
  1994. }else
  1995. if(string::IsEqual(p, "lis3d"))
  1996. {
  1997. view = ISoundService::dv_listener3d;
  1998. }else
  1999. if(string::IsEqual(p, "all"))
  2000. {
  2001. view = ISoundService::dv_all;
  2002. }else{
  2003. console->Trace(COL_CMD_OUTPUT, "Unknown parameter %i: \"%s\"", p);
  2004. }
  2005. }
  2006. srv->SetDebugLevel(level);
  2007. const char * slevel = "unknown";
  2008. switch(srv->GetDebugLevel())
  2009. {
  2010. case ISoundService::dl_minimal:
  2011. slevel = "1 (minimal)";
  2012. break;
  2013. case ISoundService::dl_maximum:
  2014. slevel = "2 (maximum)";
  2015. break;
  2016. };
  2017. srv->SetDebugView(view);
  2018. const char * sview = "unknown";
  2019. switch(srv->GetDebugView())
  2020. {
  2021. case ISoundService::dv_none:
  2022. sview = "none";
  2023. break;
  2024. case ISoundService::dv_2d:
  2025. sview = "2d";
  2026. break;
  2027. case ISoundService::dv_3d:
  2028. sview = "3d";
  2029. break;
  2030. case ISoundService::dv_listener:
  2031. sview = "lis";
  2032. break;
  2033. case ISoundService::dv_listener3d:
  2034. sview = "lis3d";
  2035. break;
  2036. case ISoundService::dv_all:
  2037. sview = "all";
  2038. break;
  2039. }
  2040. console->Trace(COL_CMD_OUTPUT, "Sounds: debug level is %s, show is %s sounds", slevel, sview);
  2041. }
  2042. void _cdecl Mission::Console_Storage(const ConsoleStack & params)
  2043. {
  2044. if(!console)
  2045. {
  2046. console = (IConsole *)api->GetService("Console");
  2047. if(!console) return;
  2048. }
  2049. if(params.GetSize() == 0)
  2050. {
  2051. console->Trace(COL_CMD_OUTPUT, "View storage fields:\nstorage view [field_name1 field_name2 ... field_nameX]\n");
  2052. console->Trace(COL_CMD_OUTPUT, "Set storage field:\nstorage set type(string,long,float|number) field_name value\n");
  2053. console->Trace(COL_CMD_OUTPUT, "Delete storage fields:\nstorage delete [field_name1 field_name2 ... field_nameX]\n");
  2054. console->Trace(COL_CMD_OUTPUT, "Copy storage field:\nstorage copy field_name_from field_name_to\n");
  2055. return;
  2056. }
  2057. if(string::IsEqual(params.GetParam(0), "view"))
  2058. {
  2059. Console_StorageView(params);
  2060. }else
  2061. if(string::IsEqual(params.GetParam(0), "set"))
  2062. {
  2063. Console_StorageSet(params);
  2064. }else
  2065. if(string::IsEqual(params.GetParam(0), "delete") || string::IsEqual(params.GetParam(0), "del"))
  2066. {
  2067. Console_StorageDel(params);
  2068. }else
  2069. if(string::IsEqual(params.GetParam(0), "copy"))
  2070. {
  2071. Console_StorageCopy(params);
  2072. }else{
  2073. console->Trace(COL_CMD_OUTPUT, "Unknown storage command: %s", params.GetParam(0));
  2074. }
  2075. }
  2076. void _cdecl Mission::Console_StorageView(const ConsoleStack & params)
  2077. {
  2078. if(!console)
  2079. {
  2080. console = (IConsole *)api->GetService("Console");
  2081. if(!console) return;
  2082. }
  2083. console->Trace(COL_CMD_OUTPUT, "Storage log:");
  2084. string buffer;
  2085. if(params.GetSize() > 1)
  2086. {
  2087. for(dword i = 1; i < params.GetSize(); i++)
  2088. {
  2089. const char * name = params.GetParam(i);
  2090. if(!string::IsEmpty(name))
  2091. {
  2092. buffer += "for ";
  2093. buffer += name;
  2094. buffer += ":\n";
  2095. api->Storage().Print(buffer, name);
  2096. buffer += "\n";
  2097. }
  2098. }
  2099. }else{
  2100. api->Storage().Print(buffer);
  2101. }
  2102. buffer += "\n";
  2103. console->Trace(COL_CMD_OUTPUT, buffer.c_str());
  2104. }
  2105. void _cdecl Mission::Console_StorageSet(const ConsoleStack & params)
  2106. {
  2107. if(!console)
  2108. {
  2109. console = (IConsole *)api->GetService("Console");
  2110. if(!console) return;
  2111. }
  2112. if(params.GetSize() < 4)
  2113. {
  2114. console->Trace(COL_CMD_OUTPUT, "Not enougth parameters...");
  2115. return;
  2116. }
  2117. const char * type = params.GetParam(1);
  2118. const char * name = params.GetParam(2);
  2119. const char * value = params.GetParam(3);
  2120. if(!value) value = "";
  2121. if(string::IsEqual(type, "string"))
  2122. {
  2123. if(api->Storage().SetString(name, value))
  2124. {
  2125. console->Trace(COL_CMD_OUTPUT, "Storage: string %s = \"%s\"", name, value);
  2126. }else{
  2127. console->Trace(COL_CMD_OUTPUT, "Storage error: cant set %s as string", name);
  2128. }
  2129. }else
  2130. if(string::IsEqual(type, "long"))
  2131. {
  2132. long v = atol(value);
  2133. if(api->Storage().SetLong(name, v))
  2134. {
  2135. console->Trace(COL_CMD_OUTPUT, "Storage: long %s = %i", name, v);
  2136. }else{
  2137. console->Trace(COL_CMD_OUTPUT, "Storage error: cant set %s as long", name);
  2138. }
  2139. }else
  2140. if(string::IsEqual(type, "float") || string::IsEqual(type, "number"))
  2141. {
  2142. float v = (float)atof(value);
  2143. if(api->Storage().SetFloat(name, v))
  2144. {
  2145. console->Trace(COL_CMD_OUTPUT, "Storage: float %s = %f", name, v);
  2146. }else{
  2147. console->Trace(COL_CMD_OUTPUT, "Storage error: cant set %s as float", name);
  2148. }
  2149. }else{
  2150. console->Trace(COL_CMD_OUTPUT, "Storage error: unknown storage type %s", type);
  2151. }
  2152. }
  2153. void _cdecl Mission::Console_StorageDel(const ConsoleStack & params)
  2154. {
  2155. if(!console)
  2156. {
  2157. console = (IConsole *)api->GetService("Console");
  2158. if(!console) return;
  2159. }
  2160. if(params.GetSize() <= 1)
  2161. {
  2162. console->Trace(COL_CMD_OUTPUT, "Not enougth parameters...");
  2163. return;
  2164. }
  2165. for(dword i = 1; i < params.GetSize(); i++)
  2166. {
  2167. const char * name = params.GetParam(i);
  2168. if(!string::IsEmpty(name))
  2169. {
  2170. api->Storage().Delete(name);
  2171. console->Trace(COL_CMD_OUTPUT, "Storage field \"%s\" is delete", name);
  2172. }
  2173. }
  2174. }
  2175. void _cdecl Mission::Console_StorageCopy(const ConsoleStack & params)
  2176. {
  2177. if(!console)
  2178. {
  2179. console = (IConsole *)api->GetService("Console");
  2180. if(!console) return;
  2181. }
  2182. if(params.GetSize() < 2)
  2183. {
  2184. console->Trace(COL_CMD_OUTPUT, "Not enougth parameters...");
  2185. return;
  2186. }
  2187. const char * from = params.GetParam(1);
  2188. const char * to = params.GetParam(2);
  2189. array<byte> buffer(_FL_, 1024);
  2190. api->Storage().Save(from, buffer);
  2191. dword readPointer = 0;
  2192. if(!api->Storage().Load(to, buffer.GetBuffer(), buffer.Size(), readPointer))
  2193. {
  2194. console->Trace(COL_CMD_OUTPUT, "Storage error: can't copy. Difference types? Try before copy delete destination folder.");
  2195. return;
  2196. }
  2197. console->Trace(COL_CMD_OUTPUT, "Copy from fields %s to %s", from, to);
  2198. }
  2199. void _cdecl Mission::Console_FreeCamera(const ConsoleStack & params)
  2200. {
  2201. if(Console_NoExecute()) return;
  2202. static const ConstString cameraName("Free camera");
  2203. MissionObject * mo = controlMission->FindObject(cameraName);
  2204. if(!mo)
  2205. {
  2206. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" not found.", cameraName.c_str());
  2207. return;
  2208. }
  2209. mo->Activate(!mo->IsActive());
  2210. console->Trace(COL_CMD_OUTPUT, "%s was %s.", cameraName.c_str(), mo->IsActive() ? "activated" : "deactivated");
  2211. }
  2212. void _cdecl Mission::Console_TraceUnuse(const ConsoleStack & params)
  2213. {
  2214. ILocStrings * ls = (ILocStrings *)api->GetService("LocStrings");
  2215. if(ls)
  2216. {
  2217. ls->TraceUnuse();
  2218. IConsole * console = (IConsole *)api->GetService("Console");
  2219. if(console)
  2220. {
  2221. console->Trace(COL_CMD_OUTPUT, "Look system_log.txt for results");
  2222. }
  2223. }
  2224. }
  2225. bool Mission::Console_NoExecute()
  2226. {
  2227. if(!controlMission)
  2228. {
  2229. console = null;
  2230. return true;
  2231. }
  2232. console = &controlMission->Console();
  2233. Assert(console);
  2234. return false;
  2235. }
  2236. MissionObject * Mission::Console_GetMissionObject(const ConsoleStack & params)
  2237. {
  2238. if(Console_NoExecute()) return null;
  2239. const char * name = params.GetParam(0);
  2240. if(!name) name = "";
  2241. MissionObject * mo = controlMission->FindObject(ConstString(name));
  2242. if(!mo)
  2243. {
  2244. console->Trace(COL_CMD_OUTPUT, "Mission object \"%s\" not found.", name);
  2245. }
  2246. return mo;
  2247. }
  2248. #endif