OpenGothic
Open source reimplementation of Gothic I and II
Loading...
Searching...
No Matches
gothic.cpp
Go to the documentation of this file.
1#include "gothic.h"
2
3#include <Tempest/Log>
4#include <Tempest/TextCodec>
5
6#include <cstring>
7#include <cctype>
8#include <cassert>
9
10#include <zenkit/addon/daedalus.hh>
11
18
19#include "world/objects/npc.h"
20#include "graphics/shaders.h"
21
22#include "utils/fileutil.h"
23#include "utils/inifile.h"
24
25#include "commandline.h"
26#include "mainwindow.h"
27
28using namespace Tempest;
29using namespace FileUtil;
30
31Gothic* Gothic::instance = nullptr;
32
33static bool hasMeshShader() {
34 const auto& p = Resources::device().properties();
35 if(p.meshlets.meshShader && p.meshlets.taskShader)
36 return true;
37 return false;
38 }
39
40static bool hasBindless() {
41 const auto& p = Resources::device().properties();
42 if(p.descriptors.nonUniformIndexing && p.descriptors.maxTexture>=65000 && p.descriptors.maxStorage>=65000)
43 return true;
44 return false;
45 }
46
48 instance = this;
49
50 systemPackIniFile.reset(new IniFile(nestedPath({u"system",u"SystemPack.ini"},Dir::FT_File)));
51 showFpsCounter = systemPackIniFile->getI("DEBUG","Show_FPS_Counter");
52 opts.hideFocus = systemPackIniFile->getI("PARAMETERS","HideFocus");
53 opts.cameraFov = systemPackIniFile->getF("PARAMETERS","VerticalFOV");
54 opts.fpsLimit = std::max(0, systemPackIniFile->getI("PARAMETERS", "FPS_Limit", 0));
55 if(opts.cameraFov<1.f) {
56 opts.cameraFov = 67.5;
57 }
58 opts.interfaceScale = systemPackIniFile->getF("INTERFACE","Scale",1);
59 if(opts.interfaceScale<=0) {
60 opts.interfaceScale = 1;
61 }
62 opts.inventoryCellSize = systemPackIniFile->getI("INTERFACE","InventoryCellSize",opts.inventoryCellSize);
63 opts.inventoryCellSize = std::max(opts.inventoryCellSize, 10);
64
65 opts.newChapterSize.w = systemPackIniFile->getI("INTERFACE","NewChapterSizeX",opts.newChapterSize.w);
66 opts.newChapterSize.h = systemPackIniFile->getI("INTERFACE","NewChapterSizeY",opts.newChapterSize.h);
67
68 opts.saveGameImageSize.w = systemPackIniFile->getI("INTERFACE","SaveGameImageSizeX",opts.saveGameImageSize.w);
69 opts.saveGameImageSize.h = systemPackIniFile->getI("INTERFACE","SaveGameImageSizeY",opts.saveGameImageSize.h);
70
71 opts.showHealthBar = !(systemPackIniFile->getI("INTERFACE","HideHealthBar",0)!=0);
72 opts.showManaBar = uint8_t(std::clamp(systemPackIniFile->getI("INTERFACE","ShowManaBar",1), 0, 2));
73 opts.showSwimBar = uint8_t(std::clamp(systemPackIniFile->getI("INTERFACE","ShowSwimBar",1), 0, 2));
74
75#ifndef NDEBUG
76 setMarvinEnabled(true);
77 setFRate(true);
78#else
81#endif
83
84 auto& gpu = Resources::device().properties();
85 if(gpu.raytracing.rayQuery) {
87 opts.doRtGi = opts.doRayQuery && CommandLine::inst().isRtGi();
88 }
89
90 if(hasMeshShader()) {
92 }
93
94 if(hasBindless()) {
96 }
97
100 }
101
104 }
105 opts.doSoftwareRT = false;
106
108
109 wrldDef = CommandLine::inst().wrldDef;
110
111 baseIniFile.reset(new IniFile(nestedPath({u"system",u"Gothic.ini"},Dir::FT_File)));
112 iniFile .reset(new IniFile(u"Gothic.ini"));
113 if(!iniFile->has("INTERNAL", "vidResIndex")) {
114 iniFile->set("INTERNAL", "vidResIndex", 0); // full-res
115 }
116 {
117 defaults.reset(new IniFile());
118 defaults->set("GAME", "enableMouse", 1);
119 defaults->set("GAME", "mouseSensitivity", 0.5f);
120 defaults->set("GAME", "invCatOrder", "COMBAT,POTION,FOOD,ARMOR,MAGIC,RUNE,DOCS,OTHER,NONE");
121 defaults->set("GAME", "invMaxColumns", 5);
122 defaults->set("GAME", "animatedWindows", 1);
123 defaults->set("GAME", "useGothic1Controls", 1);
124 defaults->set("GAME", "highlightMeleeFocus", 0);
125 defaults->set("GAME", "useQuickSaveKeys", 1);
126
127 defaults->set("GAME", "animatedWindows", 1);
128 defaults->set("GAME", "subTitles", 1);
129 defaults->set("GAME", "subTitlesPlayer", 1);
130
131 // switch related language options
132 defaults->set("GAME", "language", -1);
133 defaults->set("GAME", "voice", -1);
134 defaults->set("GAME", "scaleVideos", 1);
135
136 defaults->set("SKY_OUTDOOR", "zSunName", "unsun5.tga");
137 defaults->set("SKY_OUTDOOR", "zSunSize", 200);
138 defaults->set("SKY_OUTDOOR", "zSunAlpha", 230);
139 defaults->set("SKY_OUTDOOR", "zMoonName", "moon.tga");
140 defaults->set("SKY_OUTDOOR", "zMoonSize", 400);
141 defaults->set("SKY_OUTDOOR", "zMoonAlpha", 255);
142
143 defaults->set("RENDERER_D3D", "zFogRadial", 1); // sunshafts
144 defaults->set("ENGINE", "zEnvMappingEnabled", 1); // reflections
145 defaults->set("ENGINE", "zCloudShadowScale", gpu.type==Tempest::DeviceType::Discrete); // ssao
146 defaults->set("INTERNAL", "vidResIndex", 0); // full-res
147
148 defaults->set("VIDEO", "zVidBrightness", 0.5f);
149 defaults->set("VIDEO", "zVidContrast", 0.5f);
150 defaults->set("VIDEO", "zVidGamma", 0.5f);
151
152 defaults->set("SOUND", "musicEnabled", 1);
153 defaults->set("SOUND", "musicVolume", 0.5f);
154 defaults->set("SOUND", "soundVolume", 0.5f);
155
156 //defaults->set("ENGINE", "zEnvMappingEnabled", 0);
157 //defaults->set("ENGINE", "zCloudShadowScale", 0);
158 defaults->set("ENGINE", "zWindEnabled", 1);
159 defaults->set("ENGINE", "zWindCycleTime", 4);
160 defaults->set("ENGINE", "zWindCycleTimeVar", 6);
161
162 defaults->set("KEYS", "keyEnd", "0100");
163 defaults->set("KEYS", "keyHeal", "2300");
164 defaults->set("KEYS", "keyPotion", "1900");
165 defaults->set("KEYS", "keyLockTarget", "4f00");
166 defaults->set("KEYS", "keyParade", "cf000d02");
167 defaults->set("KEYS", "keyActionRight", "d100");
168 defaults->set("KEYS", "keyActionLeft", "d300");
169 defaults->set("KEYS", "keyUp", "c8001100");
170 defaults->set("KEYS", "keyDown", "d0001f00");
171 defaults->set("KEYS", "keyLeft", "cb001000");
172 defaults->set("KEYS", "keyRight", "cd001200");
173 defaults->set("KEYS", "keyStrafeLeft", "d3001e00");
174 defaults->set("KEYS", "keyStrafeRight", "d1002000");
175 defaults->set("KEYS", "keyAction", "1d000c02");
176 defaults->set("KEYS", "keySlow", "2a003600");
177 defaults->set("KEYS", "keySMove", "38009d00");
178 defaults->set("KEYS", "keyWeapon", "39000e02");
179 defaults->set("KEYS", "keySneak", "2d00");
180 defaults->set("KEYS", "keyLook", "13005200");
181 defaults->set("KEYS", "keyLookFP", "21005300");
182 defaults->set("KEYS", "keyInventory", "0f000e00");
183 defaults->set("KEYS", "keyShowStatus", "30002e00");
184 defaults->set("KEYS", "keyShowLog", "31002600");
185 defaults->set("KEYS", "keyShowMap", "3200");
186 }
187
188 detectGothicVersion();
189
190 std::u16string_view mod = CommandLine::inst().modPath();
191 if(!mod.empty()){
192 modFile.reset(new IniFile(mod));
193 }
194
195 std::vector<std::u16string> modvdfs;
196 bool modFilter = true;
197 if(modFile!=nullptr) {
198 wrldDef = modFile->getS("SETTINGS","WORLD");
199 size_t split = wrldDef.rfind('\\');
200 if(split!=std::string::npos)
201 wrldDef = wrldDef.substr(split+1);
202 plDef = modFile->getS("SETTINGS","PLAYER");
203 gameDatDef = modFile->getS("FILES","GAME");
204 ouDef = modFile->getS("FILES","OUTPUTUNITS");
205
206 std::u16string vdf = TextCodec::toUtf16(modFile->getS("FILES","VDF"));
207 modFilter = modFile->has("FILES","VDF");
208 for(size_t start = 0, split = 0; split != std::string::npos; start = split+1) {
209 split = vdf.find(' ', start);
210 std::u16string mod = vdf.substr(start, split-start);
211 if(!mod.empty())
212 modvdfs.emplace_back(std::move(mod));
213 }
214 }
215 /*
216 '/work' seem to have lowest priority
217 load it last with zenkit::VfsOverwriteBehavior::NONE
218 any other order will interact with time-stamp based override, resulting in inconsistent behaviour
219 */
220 Resources::loadVdfs(modvdfs, modFilter);
221 Resources::mountWork(Gothic::nestedPath({u"_work"}, Dir::FT_Dir));
222
223 if(wrldDef.empty()) {
224 if(version().game==2)
225 wrldDef = "newworld.zen"; else
226 wrldDef = "world.zen";
227 }
228
229 if(plDef.empty())
230 plDef = "PC_HERO";
231
232 if(gameDatDef.empty())
233 gameDatDef = "GOTHIC.DAT"; else
234 gameDatDef += ".DAT";
235
236 if(ouDef.empty()) {
237 // suffixes added later in GameScript::loadDialogOU()
238 ouDef = "OU";
239 }
240
241 onSettingsChanged.bind(this,&Gothic::setupSettings);
242 setupSettings();
243 }
244
246 instance = nullptr;
247 }
248
250 assert(instance!=nullptr);
251 return *instance;
252 }
253
255 fight .reset(new FightAi());
256 camDef .reset(new CameraDefinitions());
257 soundDef .reset(new SoundDefinitions());
258 particleDef.reset(new ParticlesDefinitions());
259 vfxDef .reset(new VisualFxDefinitions());
260 music .reset(new MusicDefinitions());
261 }
262
264 return vinfo;
265 }
266
267bool Gothic::isInGame() const {
268 return game!=nullptr;
269 }
270
272 auto pl = Gothic::inst().player();
273 if(pl==nullptr || pl->isDead())
274 return false;
275 return isInGame();
276 }
277
278const World *Gothic::world() const {
279 if(game)
280 return game->world();
281 return nullptr;
282 }
283
285 if(game)
286 return game->world();
287 return nullptr;
288 }
289
290void Gothic::setGame(std::unique_ptr<GameSession> &&w) {
291 clearGame();
292 game = std::move(w);
293 }
294
295std::unique_ptr<GameSession> Gothic::clearGame() {
296 return std::move(game);
297 }
298
300 return game.get();
301 }
302
304 return game.get();
305 }
306
308 if(game)
309 return game->view();
310 return nullptr;
311 }
312
314 if(game)
315 return game->player();
316 return nullptr;
317 }
318
320 if(game)
321 return &game->camera();
322 return nullptr;
323 }
324
326 if(game)
327 return &game->script()->questLog();
328 return nullptr;
329 }
330
332 return loadProgress.load();
333 }
334
336 loadProgress.store(v);
337 }
338
339const Tempest::Texture2d* Gothic::loadingBanner() const {
340 return loadTex.isEmpty() ? &saveTex : &loadTex;
341 }
342
343SoundFx *Gothic::loadSoundFx(std::string_view name) {
344 if(name.empty())
345 return nullptr;
346
347 auto cname = std::string(name);
348
349 std::lock_guard<std::mutex> guard(syncSnd);
350 auto it=sndFxCache.find(cname);
351 if(it!=sndFxCache.end())
352 return &it->second;
353
354 try {
355 auto ret = sndFxCache.emplace(name,SoundFx(name));
356 return &ret.first->second;
357 }
358 catch(...) {
359 Tempest::Log::e("unable to load soundfx \"",cname,"\"");
360 return nullptr;
361 }
362 }
363
364SoundFx *Gothic::loadSoundWavFx(std::string_view name) {
365 auto snd = Resources::loadSoundBuffer(name);
366 auto cname = std::string(name);
367
368 std::lock_guard<std::mutex> guard(syncSnd);
369 auto it=sndWavCache.find(cname);
370 if(it!=sndWavCache.end())
371 return &it->second;
372
373 try {
374 auto ret = sndWavCache.emplace(name,SoundFx(std::move(snd)));
375 return &ret.first->second;
376 }
377 catch(...) {
378 Tempest::Log::e("unable to load soundfx \"",cname,"\"");
379 return nullptr;
380 }
381 }
382
383const VisualFx* Gothic::loadVisualFx(std::string_view name) {
384 return vfxDef->get(name);
385 }
386
387const ParticleFx* Gothic::loadParticleFx(std::string_view name, bool relaxed) {
388 return particleDef->get(name,relaxed);
389 }
390
392 return particleDef->get(base,key);
393 }
394
395void Gothic::emitGlobalSound(std::string_view sfx) {
397 }
398
400 if(sfx!=nullptr) {
401 bool loop = false;
402 auto s = sfx->load(sndDev,loop);
403 s.play();
404
405 for(size_t i=0;i<sndStorage.size();){
406 if(sndStorage[i].isFinished()){
407 sndStorage[i]=std::move(sndStorage.back());
408 sndStorage.pop_back();
409 } else {
410 ++i;
411 }
412 }
413 sndStorage.push_back(std::move(s));
414 }
415 }
416
417void Gothic::emitGlobalSound(const Tempest::Sound &sfx) {
418 auto s = sndDev.load(sfx);
419 s.play();
420
421 for(size_t i=0;i<sndStorage.size();){
422 if(sndStorage[i].isFinished()){
423 sndStorage[i]=std::move(sndStorage.back());
424 sndStorage.pop_back();
425 } else {
426 ++i;
427 }
428 }
429 sndStorage.push_back(std::move(s));
430 }
431
432void Gothic::emitGlobalSoundWav(std::string_view wav) {
433 auto s = sndDev.load(Resources::loadSoundBuffer(wav));
434 s.play();
435
436 for(size_t i=0;i<sndStorage.size();){
437 if(sndStorage[i].isFinished()){
438 sndStorage[i]=std::move(sndStorage.back());
439 sndStorage.pop_back();
440 } else {
441 ++i;
442 }
443 }
444 sndStorage.push_back(std::move(s));
445 }
446
447 const std::vector<ItmFlags>& Gothic::invCatOrder() {
448 return instance->inventoryOrder;
449 }
450
452 pauseSum++;
453 }
454
456 pauseSum--;
457 }
458
459bool Gothic::isPause() const {
460 return pauseSum;
461 }
462
464 return isMarvin;
465 }
466
468 isMarvin = m;
469 }
470
471float Gothic::interfaceScale(const Tempest::Widget* w) {
472 float mul = 1;
473 if(instance->opts.interfaceScale>0.0)
474 mul = instance->opts.interfaceScale;
475
476 while(w->owner()!=nullptr) {
477 w = w->owner();
478 }
479 if(auto window = dynamic_cast<const MainWindow*>(w))
480 return window->uiScale() * mul;
481 return mul;
482 }
483
485 return isBenchmark!=Benchmark::None;
486 }
487
489 return isBenchmark==Benchmark::CiTooling;
490 }
491
493 isBenchmark = b;
494 }
495
497 return instance->opts;
498 }
499
501 return loadingFlag.load();
502 }
503
505 auto state = checkLoading();
507 return false;
508 if(loadingFlag.compare_exchange_strong(state,LoadState::Idle)){
509 loaderTh.join();
510 if(pendingGame!=nullptr)
511 game = std::move(pendingGame);
512 saveTex = Texture2d();
513 loadTex = Texture2d();
515 return true;
516 }
517 return false;
518 }
519
520void Gothic::startSave(Tempest::Texture2d&& tex,
521 const std::function<std::unique_ptr<GameSession>(std::unique_ptr<GameSession>&&)> f) {
522 saveTex = std::move(tex);
523 implStartLoadSave("",false,f);
524 }
525
526void Gothic::startLoad(std::string_view banner,
527 const std::function<std::unique_ptr<GameSession>(std::unique_ptr<GameSession>&&)> f) {
528 implStartLoadSave(banner,true,f);
529 }
530
531void Gothic::implStartLoadSave(std::string_view banner,
532 bool load,
533 const std::function<std::unique_ptr<GameSession>(std::unique_ptr<GameSession>&&)> f) {
534 loadTex = banner.empty() ? Texture2d() : Resources::loadTextureUncached(banner);
535 loadProgress.store(0);
536
537 auto zero=LoadState::Idle;
539 if(!loadingFlag.compare_exchange_strong(zero,one)){
540 return; // loading already
541 }
542
544 auto g = clearGame().release();
545 try{
546 auto l = std::thread([this,f,g,one]() noexcept {
547 Workers::setThreadName("Loading thread");
548 std::unique_ptr<GameSession> game(g);
549 std::unique_ptr<GameSession> next;
550 auto curState = one;
552 try {
553 next = f(std::move(game));
554 pendingGame = std::move(next);
555 loadingFlag.compare_exchange_strong(curState,LoadState::Finalize);
556 }
557 catch(std::bad_alloc&){
558 Tempest::Log::e("loading error: out of memory");
559 loadingFlag.compare_exchange_strong(curState,err);
560 }
561 catch(std::system_error& e){
562 Tempest::Log::e("loading error: ", e.what());
563 loadingFlag.compare_exchange_strong(curState,err);
564 }
565 catch(std::runtime_error& e){
566 Tempest::Log::e("loading error: ",e.what());
567 loadingFlag.compare_exchange_strong(curState,err);
568 }
569 catch(std::bad_function_call&){
570 Tempest::Log::e("loading error: bad_function_call");
571 loadingFlag.compare_exchange_strong(curState,err);
572 }
573 catch(const std::exception&e) {
574 Tempest::Log::e("loading error: ", e.what());
575 loadingFlag.compare_exchange_strong(curState,err);
576 }
577 if(curState==LoadState::Saving) {
578 if(game!=nullptr)
579 pendingGame = std::move(game);
580 }
581 });
582 loaderTh=std::move(l);
583 //loaderTh.join();
584 //loaderTh = std::thread([](){});
585 }
586 catch(...){
587 delete g; // delete manually, if we can't start thread
588 }
589 }
590
592 if(loadingFlag.load()!=LoadState::Idle){
593 loaderTh.join();
594 loadingFlag.store(LoadState::Idle);
595 }
596 }
597
598void Gothic::tick(uint64_t dt) {
599 if(pendingChapter){
600 if(!isInDialog()) {
601 onIntroChapter(chapter);
602 pendingChapter=false;
603 }
604 }
605
606 if(game)
607 game->tick(dt);
608 }
609
610void Gothic::updateAnimation(uint64_t dt) {
611 if(game)
612 game->updateAnimation(dt);
613 }
614
616 save("save_slot_0.sav","Quick save");
617 }
618
620 load("save_slot_0.sav");
621 }
622
623void Gothic::save(std::string_view slot, std::string_view name) {
624 onSaveGame(slot,name);
625 }
626
627void Gothic::load(std::string_view slot) {
628 onLoadGame(slot);
629 }
630
631std::vector<GameScript::DlgChoice> Gothic::updateDialog(const GameScript::DlgChoice &dlg, Npc& player, Npc& npc) {
632 return game->updateDialog(dlg,player,npc);
633 }
634
635void Gothic::dialogExec(const GameScript::DlgChoice &dlg, Npc& player, Npc& npc) {
636 game->dialogExec(dlg,player,npc);
637 }
638
639void Gothic::openDialogPipe(Npc &player, Npc &npc, AiOuputPipe *&pipe) {
640 onDialogPipe(player,npc,pipe);
641 }
642
643bool Gothic::isNpcInDialog(const Npc& npc) const {
644 return isNpcInDialogFn(&npc);
645 }
646
647bool Gothic::isInDialog() const {
648 return isNpcInDialogFn(nullptr);
649 }
650
652 return *instance->fight;
653 }
654
656 return *instance->soundDef;
657 }
658
660 return *instance->music;
661 }
662
664 return *instance->camDef;
665 }
666
667std::string_view Gothic::messageFromSvm(std::string_view id, int voice) const {
668 if(!game)
669 return "";
670 return game->messageFromSvm(id,voice);
671 }
672
673std::string_view Gothic::messageByName(std::string_view id) const {
674 if(!game)
675 return "";
676 return game->messageByName(id);
677 }
678
679uint32_t Gothic::messageTime(std::string_view id) const {
680 if(!game)
681 return 0;
682 return game->messageTime(id);
683 }
684
685std::string_view Gothic::defaultWorld() const {
686 return wrldDef;
687 }
688
689std::string_view Gothic::defaultPlayer() const {
690 return plDef;
691 }
692
693std::string_view Gothic::defaultSave() const {
695 }
696
697std::string_view Gothic::defaultGameDatFile() const {
698 return gameDatDef;
699 }
700
701std::string_view Gothic::defaultOutputUnits() const {
702 return ouDef;
703 }
704
705std::string_view Gothic::menuMain() const {
706 if(game && game->script())
707 return game->script()->menuMain();
708 return ::menuMain;
709 }
710
711std::unique_ptr<zenkit::DaedalusVm> Gothic::createPhoenixVm(std::string_view datFile, const ScriptLang lang) {
712 auto sc = loadScript(datFile, lang);
714
715 auto vm = std::make_unique<zenkit::DaedalusVm>(std::move(sc), zenkit::DaedalusVmExecutionFlag::ALLOW_NULL_INSTANCE_ACCESS);
716 setupVmCommonApi(*vm);
717 return vm;
718 }
719
720zenkit::DaedalusScript Gothic::loadScript(std::string_view datFile, const ScriptLang lang) {
721 if(Resources::hasFile(datFile)) {
722 auto buf = Resources::getFileBuffer(datFile);
723 zenkit::DaedalusScript script;
724 script.load(buf.get());
725 return script;
726 }
727
728 const size_t segment = datFile.find_last_of("\\/");
729 if(segment!=std::string::npos && Resources::hasFile(datFile.substr(segment+1))) {
730 auto buf = Resources::getFileBuffer(datFile.substr(segment+1));
731 zenkit::DaedalusScript script;
732 script.load(buf.get());
733 return script;
734 }
735
736 char16_t str16[256] = {};
737 for(size_t i=0; i<datFile.size() && i<255; ++i)
738 str16[i] = char16_t(datFile[i]);
739
740 auto gscript = CommandLine::inst().scriptPath();
741 auto path = caseInsensitiveSegment(gscript,str16,Dir::FT_File);
742 if(!FileUtil::exists(path) && int(lang)>=0) {
743 gscript = CommandLine::inst().scriptPath(lang);
744 path = caseInsensitiveSegment(gscript,str16,Dir::FT_File);
745 }
746 if(!FileUtil::exists(path) && int(lang)>=0) {
747 datFile = datFile.substr(segment+1);
748 for(size_t i=0; i<datFile.size() && i<255; ++i)
749 str16[i] = char16_t(datFile[i]);
750 str16[datFile.size()] = u'\0';
751 gscript = CommandLine::inst().scriptPath(lang);
752 path = caseInsensitiveSegment(gscript,str16,Dir::FT_File);
753 }
754
755 auto buf = zenkit::Read::from(path);
756 zenkit::DaedalusScript script;
757 script.load(buf.get());
758 return script;
759 }
760
761void Gothic::setupCommonScriptClasses(zenkit::DaedalusScript& sc) {
762 // Use customized setup, instead of zenkit::register_all_script_classes
763 auto registerIfExists = [&](std::string_view sym, auto d) {
764 if(sc.find_symbol_by_name(sym) != nullptr) {
765 d(sc);
766 }
767 };
768
769 auto registerOpaque = [&](std::string_view sym){
770 if(auto ptr = sc.find_symbol_by_name(sym)) {
771 sc.register_as_opaque(ptr);
772 }
773 };
774
775 registerIfExists("C_GILVALUES", zenkit::IGuildValues::register_);
776 registerIfExists("C_NPC", zenkit::INpc::register_);
777 registerIfExists("C_MISSION", zenkit::IMission::register_);
778 registerIfExists("C_ITEM", zenkit::IItem::register_);
779 registerIfExists("C_FOCUS", zenkit::IFocus::register_);
780 registerIfExists("C_INFO", zenkit::IInfo::register_);
781 registerIfExists("C_ITEMREACT", zenkit::IItemReact::register_);
782 registerIfExists("C_SPELL", zenkit::ISpell::register_);
783 registerOpaque ("C_SVM"); // structure is very customizable, so better to use type-less mapping
784 registerIfExists("C_MENU", zenkit::IMenu::register_);
785 registerIfExists("C_MENU_ITEM", zenkit::IMenuItem::register_);
786 registerIfExists("CCAMSYS", zenkit::ICamera::register_);
787 registerIfExists("C_MUSICSYS_CFG", zenkit::IMusicSystem::register_);
788 registerIfExists("C_MUSICTHEME", zenkit::IMusicTheme::register_);
789 registerIfExists("C_MUSICJINGLE", zenkit::IMusicJingle::register_);
790 registerIfExists("C_PARTICLEFX", zenkit::IParticleEffect::register_);
791 registerIfExists("CFX_BASE", zenkit::IEffectBase::register_);
792 registerIfExists("C_PARTICLEFXEMITKEY", zenkit::IParticleEffectEmitKey::register_);
793 registerOpaque ("C_FIGHTAI"); // many mods get it wrong/corrupted. Opaque binding is one is a way to get around it
794 registerIfExists("C_SFX", zenkit::ISoundEffect::register_);
795 registerIfExists("C_SNDSYS_CFG", zenkit::ISoundSystem::register_);
796 }
797
798bool Gothic::settingsHasSection(std::string_view sec) {
799 if(instance->iniFile->has(sec))
800 return true;
801 if(instance->baseIniFile->has(sec))
802 return true;
803 // no defaults
804 return false;
805 }
806
807int Gothic::settingsGetI(std::string_view sec, std::string_view name) {
808 if(name.empty())
809 return 0;
810 if(instance->iniFile->has(sec,name))
811 return instance->iniFile->getI(sec,name);
812 if(instance->baseIniFile->has(sec,name))
813 return instance->baseIniFile->getI(sec,name);
814 if(instance->defaults->has(sec,name))
815 return instance->defaults->getI(sec,name);
816 return 0;
817 }
818
819void Gothic::settingsSetI(std::string_view sec, std::string_view name, int val) {
820 instance->iniFile->set(sec,name,val);
821 instance->onSettingsChanged();
822 }
823
824std::string_view Gothic::settingsGetS(std::string_view sec, std::string_view name) {
825 if(name.empty())
826 return "";
827 if(instance->iniFile->has(sec,name))
828 return instance->iniFile->getS(sec,name);
829 if(instance->baseIniFile->has(sec,name))
830 return instance->baseIniFile->getS(sec,name);
831 if(instance->defaults->has(sec,name))
832 return instance->defaults->getS(sec,name);
833 return "";
834 }
835
836void Gothic::settingsSetS(std::string_view sec, std::string_view name, std::string_view val) {
837 instance->iniFile->set(sec,name,val);
838 instance->onSettingsChanged();
839 }
840
841float Gothic::settingsGetF(std::string_view sec, std::string_view name) {
842 if(name.empty())
843 return 0;
844 if(instance->iniFile->has(sec,name))
845 return instance->iniFile->getF(sec,name);
846 if(instance->baseIniFile->has(sec,name))
847 return instance->baseIniFile->getF(sec,name);
848 if(instance->defaults->has(sec,name))
849 return instance->defaults->getF(sec,name);
850 return 0;
851 }
852
853void Gothic::settingsSetF(std::string_view sec, std::string_view name, float val) {
854 instance->iniFile->set(sec,name,val);
855 instance->onSettingsChanged();
856 }
857
859 instance->iniFile->flush();
860 }
861
862void Gothic::detectGothicVersion() {
863 int score[3]={};
864
865 auto gpath = CommandLine::inst().rootPath();
866 if(gpath.find(u"Gothic/")!=std::string::npos || gpath.find(u"gothic/")!=std::string::npos)
867 score[1]++;
868 if(FileUtil::exists(nestedPath({u"_work",u"Data",u"Scripts",u"content",u"CUTSCENE",u"OU.BIN"},Dir::FT_File)))
869 score[1]++;
870
871 if(FileUtil::exists(nestedPath({u"_work",u"Data",u"Scripts",u"content",u"CUTSCENE",u"OU.DAT"},Dir::FT_File)))
872 score[2]++;
873 if(baseIniFile->has("KEYSDEFAULT1"))
874 score[2]++;
875 if(baseIniFile->has("GAME","PATCHVERSION"))
876 score[2]++;
877 if(baseIniFile->has("GAME","useGothic1Controls"))
878 score[2]++;
879
880 if(score[1]>score[2])
881 vinfo.game = 1; else
882 vinfo.game = 2;
883
884 if(vinfo.game==2) {
885 vinfo.patch = baseIniFile->getI("GAME","PATCHVERSION");
886 }
887
888 if(CommandLine::inst().doForceG1()) {
889 vinfo.game = 1;
890 }
891 else if(CommandLine::inst().doForceG2()) {
892 vinfo.game = 2;
893 vinfo.patch = 0;
894 }
895 else if(CommandLine::inst().doForceG2NR()) {
896 vinfo.game = 2;
897 vinfo.patch = 5;
898 }
899 }
900
901void Gothic::setupSettings() {
902 if(game!=nullptr)
903 game->setupSettings();
904
905 const float soundVolume = settingsGetF("SOUND","soundVolume");
906 sndDev.setGlobalVolume(soundVolume);
907
908 auto ord = Gothic::settingsGetS("GAME","invCatOrder");
909 while(!ord.empty()) {
910 auto l = ord.find_first_of(" \t,");
911 auto name = ord.substr(0,l);
912
913 if(l!=std::string::npos)
914 ord = ord.substr(l+1); else
915 ord = std::string_view();
916
918 if(name=="COMBAT")
920 else if(name=="POTION")
921 v = ITM_CAT_POTION;
922 else if(name=="FOOD")
923 v = ITM_CAT_FOOD;
924 else if(name=="ARMOR")
925 v = ITM_CAT_ARMOR;
926 else if(name=="MAGIC")
927 v = ITM_CAT_MAGIC;
928 else if(name=="RUNE")
929 v = ITM_CAT_RUNE;
930 else if(name=="DOCS")
931 v = ITM_CAT_DOCS;
932 else if(name=="OTHER")
933 v = ITM_CAT_LIGHT;
934 else if(name=="NONE")
935 v = ITM_CAT_NONE;
936 else
937 continue;
938 inventoryOrder.push_back(v);
939 }
940 }
941
942std::unique_ptr<DocumentMenu::Show>& Gothic::getDocument(int id) {
943 if(id>=0 && size_t(id)<documents.size())
944 return documents[size_t(id)];
945 static std::unique_ptr<DocumentMenu::Show> empty;
946 return empty;
947 }
948
949std::u16string Gothic::nestedPath(const std::initializer_list<const char16_t*> &name, Tempest::Dir::FileType type) {
950 return CommandLine::inst().nestedPath(name,type);
951 }
952
953void Gothic::setupVmCommonApi(zenkit::DaedalusVm& vm) {
954 vm.register_default_external([](std::string_view name) { notImplementedRoutine(std::string {name}); });
955
956 if(auto sym = vm.find_symbol_by_name("C_SVM"))
957 vm.register_as_opaque(sym);
958 if(auto sym = vm.find_symbol_by_name("C_FIGHTAI"))
959 vm.register_as_opaque(sym);
960
961 vm.register_external("concatstrings", [](std::string_view a, std::string_view b) { return Gothic::concatstrings(a, b);});
962 vm.register_external("inttostring", [](int i) { return Gothic::inttostring(i); });
963 vm.register_external("floattostring", [](float f) { return Gothic::floattostring(f); });
964 vm.register_external("inttofloat", [](int i) { return Gothic::inttofloat(i); });
965 vm.register_external("floattoint", [](float f) { return Gothic::floattoint(f); });
966
967 vm.register_external("hlp_strcmp", [](std::string_view a, std::string_view b) { return Gothic::hlp_strcmp(a, b); });
968 vm.register_external("hlp_random", [this](int max) { return hlp_random(max); });
969
970 vm.register_external("introducechapter", [this](std::string_view title, std::string_view subtitle, std::string_view img, std::string_view sound, int time){ introducechapter(title, subtitle, img, sound, time); });
971 vm.register_external("playvideo", [this](std::string_view name){ return playvideo(name); });
972 vm.register_external("playvideoex", [this](std::string_view name, bool a, bool b){ return playvideoex(name, a, b); });
973 vm.register_external("printscreen", [this](std::string_view msg, int posx, int posy, std::string_view font, int timesec){ return printscreen(msg, posx, posy, font, timesec); });
974 vm.register_external("printdialog", [this](int dialognr, std::string_view msg, int posx, int posy, std::string_view font, int timesec){ return printdialog(dialognr, msg, posx, posy, font, timesec); });
975 vm.register_external("print", [this](std::string_view msg){ print(msg); });
976
977 vm.register_external("doc_create", [this](){ return doc_create(); });
978 vm.register_external("doc_createmap", [this](){ return doc_createmap(); });
979 vm.register_external("doc_setpage", [this](int handle, int page, std::string_view img, int scale){ doc_setpage(handle, page, img, scale); });
980 vm.register_external("doc_setpages", [this](int handle, int count){ doc_setpages(handle, count); });
981 vm.register_external("doc_printline", [this](int handle, int page, std::string_view text){ doc_printline(handle, page, text); });
982 vm.register_external("doc_printlines", [this](int handle, int page, std::string_view text){ doc_printlines(handle, page, text); });
983 vm.register_external("doc_setmargins", [this](int handle, int page, int left, int top, int right, int bottom, int mul){ doc_setmargins(handle, page, left, top, right, bottom, mul); });
984 vm.register_external("doc_setfont", [this](int handle, int page, std::string_view font){ doc_setfont(handle, page, font); });
985 vm.register_external("doc_setlevel", [this](int handle, std::string_view level){ doc_setlevel(handle, level); });
986 vm.register_external("doc_setlevelcoords", [this](int handle, int left, int top, int right, int bottom){ doc_setlevelcoords(handle, left, top, right, bottom); });
987 vm.register_external("doc_show", [this](int handle){ doc_show(handle); });
988
989 vm.register_external("exitgame", [this](){ exitgame(); });
990
991 vm.register_external("printdebug", [this](std::string_view msg){ printdebug(msg); });
992 vm.register_external("printdebugch", [this](int ch, std::string_view msg){ printdebugch(ch, msg); });
993 vm.register_external("printdebuginst", [this](std::string_view msg){ printdebuginst(msg); });
994 vm.register_external("printdebuginstch", [this](int ch, std::string_view msg){ printdebuginstch(ch, msg); });
995 }
996
997void Gothic::notImplementedRoutine(std::string_view fn) {
998 static std::set<std::string, std::less<>> s;
999
1000 if(s.find(fn)==s.end()){
1001 auto [v, _] = s.insert(std::string {fn});
1002 Log::e("not implemented call [",v->c_str(),"]");
1003 }
1004 }
1005
1006std::string Gothic::concatstrings(std::string_view a, std::string_view b) {
1007 return std::string {a} + std::string {b};
1008 }
1009
1010std::string Gothic::inttostring(int i){
1011 return std::to_string(i);
1012 }
1013
1014std::string Gothic::floattostring(float f) {
1015 return std::to_string(f);
1016 }
1017
1018int Gothic::floattoint(float f) {
1019 return static_cast<int>(f);
1020 }
1021
1022float Gothic::inttofloat(int i) {
1023 return static_cast<float>(i);
1024 }
1025
1026int Gothic::hlp_random(int max) {
1027 auto mod = uint32_t(std::max(1, max));
1028 return static_cast<int32_t>(randGen() % mod);
1029 }
1030
1031bool Gothic::hlp_strcmp(std::string_view a, std::string_view b) {
1032 return a == b;
1033 }
1034
1035void Gothic::introducechapter(std::string_view title, std::string_view subtitle, std::string_view img, std::string_view sound, int time) {
1036 pendingChapter = true;
1037 ChapterScreen::Show& s = chapter;
1038 s.time = time;
1039 s.sound = sound;
1040 s.img = img;
1041 s.subtitle = subtitle;
1042 s.title = title;
1043 }
1044
1045bool Gothic::playvideo(std::string_view name) {
1046 onVideo(name);
1047 return true;
1048 }
1049
1050bool Gothic::playvideoex(std::string_view name, bool, bool) {
1051 onVideo(name);
1052 return true;
1053 }
1054
1055bool Gothic::printscreen(std::string_view msg, int posx, int posy, std::string_view font, int timesec) {
1056 onPrintScreen(msg,posx,posy,timesec,Resources::font(font, Resources::FontType::Normal, 1));
1057 return false;
1058 }
1059
1060bool Gothic::printdialog(int, std::string_view msg, int posx, int posy, std::string_view font, int timesec) {
1061 onPrintScreen(msg,posx,posy,timesec,Resources::font(font, Resources::FontType::Normal, 1));
1062 return false;
1063 }
1064
1065void Gothic::print(std::string_view msg) {
1066 onPrint(msg);
1067 }
1068
1069int Gothic::doc_create() {
1070 for(size_t i=0;i<documents.size();++i){
1071 if(documents[i]==nullptr){
1072 documents[i].reset(new DocumentMenu::Show());
1073 return static_cast<int>(i);
1074 }
1075 }
1076 documents.emplace_back(new DocumentMenu::Show());
1077 return static_cast<int>(documents.size()) - 1;
1078 }
1079
1080int Gothic::doc_createmap() {
1081 for(size_t i=0;i<documents.size();++i){
1082 if(documents[i]==nullptr){
1083 documents[i].reset(new DocumentMenu::Show());
1084 return static_cast<int>(i);
1085 }
1086 }
1087 documents.emplace_back(new DocumentMenu::Show());
1088 return static_cast<int>(documents.size())-1;
1089 }
1090
1091void Gothic::doc_setpage(int handle, int page, std::string_view img, int scale) {
1092 //TODO: scale
1093 (void)scale;
1094
1095 auto& doc = getDocument(handle);
1096 if(doc==nullptr)
1097 return;
1098 if(page>=0 && size_t(page)<doc->pages.size()){
1099 auto& pg = doc->pages[size_t(page)];
1100 pg.img = img;
1102 } else {
1103 doc->img = img;
1104 }
1105 }
1106
1107void Gothic::doc_setpages(int handle, int count) {
1108 auto& doc = getDocument(handle);
1109 if(doc!=nullptr && count>=0 && count<1024){
1110 doc->pages.resize(size_t(count));
1111 }
1112 }
1113
1114void Gothic::doc_printline(int handle, int page, std::string_view text) {
1115 auto& doc = getDocument(handle);
1116 if(doc!=nullptr && page>=0 && size_t(page)<doc->pages.size()){
1117 doc->pages[size_t(page)].text += text;
1118 doc->pages[size_t(page)].text += "\n";
1119 }
1120 }
1121
1122void Gothic::doc_printlines(int handle, int page, std::string_view text) {
1123 auto& doc = getDocument(handle);
1124 if(doc!=nullptr && page>=0 && size_t(page)<doc->pages.size()){
1125 doc->pages[size_t(page)].text += text;
1126 doc->pages[size_t(page)].text += "\n";
1127 }
1128 }
1129
1130void Gothic::doc_setmargins(int handle, int page, int left, int top, int right, int bottom, int mul) {
1131 bottom *= mul;
1132 right *= mul;
1133 top *= mul;
1134 left *= mul;
1135
1136 auto& doc = getDocument(handle);
1137 if(doc==nullptr)
1138 return;
1139 if(page>=0 && size_t(page)<doc->pages.size()){
1140 auto& pg = doc->pages[size_t(page)];
1141 pg.margins = Tempest::Margin(left,right,top,bottom);
1143 } else {
1144 doc->margins = Tempest::Margin(left,right,top,bottom);
1145 }
1146 }
1147
1148void Gothic::doc_setfont(int handle, int page, std::string_view font) {
1149 auto& doc = getDocument(handle);
1150 if(doc==nullptr)
1151 return;
1152
1153 if(page>=0 && size_t(page)<doc->pages.size()){
1154 auto& pg = doc->pages[size_t(page)];
1155 pg.font = font;
1156 pg.flg = DocumentMenu::Flags(pg.flg | DocumentMenu::F_Font);
1157 } else {
1158 doc->font = font;
1159 }
1160 }
1161
1162void Gothic::doc_show(int handle) {
1163 auto& doc = getDocument(handle);
1164 if(doc!=nullptr){
1165 onShowDocument(*doc);
1166 doc.reset();
1167 }
1168
1169 while(documents.size()>0 && documents.back()==nullptr)
1170 documents.pop_back();
1171 }
1172
1173void Gothic::doc_setlevel(int handle, std::string_view level) {
1174 auto& doc = getDocument(handle);
1175 if(doc==nullptr)
1176 return;
1177
1178 std::string str {level};
1179 size_t bg = str.rfind('\\');
1180 if(bg!=std::string::npos)
1181 str = str.substr(bg+1);
1182
1183 for(auto& i:str)
1184 i = char(std::tolower(i));
1185
1186 if(auto w = world()) {
1187 doc->showPlayer = (w->name()==str);
1188 }
1189 }
1190
1191void Gothic::doc_setlevelcoords(int handle, int left, int top, int right, int bottom) {
1192 auto& doc = getDocument(handle);
1193 if(doc==nullptr)
1194 return;
1195 doc->wbounds = Rect(left,top,right-left,bottom-top);
1196 }
1197
1198void Gothic::exitgame() {
1199 Log::i("Exiting, by script call (`exitgame`)");
1200 Tempest::SystemApi::exit();
1201 }
1202
1203void Gothic::printdebug(std::string_view msg) {
1204 if(version().game==2)
1205 Log::d("[zspy]: ",msg);
1206 }
1207
1208void Gothic::printdebugch(int ch, std::string_view msg) {
1209 if(version().game==2)
1210 Log::d("[zspy,",ch,"]: ",msg);
1211 }
1212
1213void Gothic::printdebuginst(std::string_view msg) {
1214 if(version().game==2)
1215 Log::d("[zspy]: ",msg);
1216 }
1217
1218void Gothic::printdebuginstch(int ch, std::string_view msg) {
1219 if(version().game==2)
1220 Log::d("[zspy,",ch,"]: ",msg);
1221 }
std::string_view defaultSave() const
Definition commandline.h:50
bool isVirtualShadow() const
Definition commandline.h:42
bool isBindless() const
Definition commandline.h:41
bool isSoftwareShadow() const
Definition commandline.h:43
bool isRayQuery() const
Definition commandline.h:38
bool aaPreset() const
Definition commandline.h:49
std::u16string nestedPath(const std::initializer_list< const char16_t * > &name, Tempest::Dir::FileType type) const
std::u16string_view modPath() const
Definition commandline.h:32
bool isMeshShading() const
Definition commandline.h:40
std::u16string scriptPath() const
std::string wrldDef
Definition commandline.h:52
bool isRtGi() const
Definition commandline.h:39
static const CommandLine & inst()
std::u16string_view rootPath() const
void pushPause()
Definition gothic.cpp:451
Camera * camera()
Definition gothic.cpp:319
void dialogExec(const GameScript::DlgChoice &dlg, Npc &player, Npc &npc)
Definition gothic.cpp:635
static std::u16string nestedPath(const std::initializer_list< const char16_t * > &name, Tempest::Dir::FileType type)
Definition gothic.cpp:949
static void settingsSetI(std::string_view sec, std::string_view name, int val)
Definition gothic.cpp:819
Tempest::Signal< void()> onSettingsChanged
Definition gothic.h:182
bool isBenchmarkModeCi() const
Definition gothic.cpp:488
auto loadParticleFx(std::string_view name, bool relaxed=false) -> const ParticleFx *
Definition gothic.cpp:387
bool finishLoading()
Definition gothic.cpp:504
void setupGlobalScripts()
Definition gothic.cpp:254
~Gothic()
Definition gothic.cpp:245
std::string_view defaultPlayer() const
Definition gothic.cpp:689
static auto options() -> const Options &
Definition gothic.cpp:496
Tempest::Signal< void(std::string_view, int, int, int, const GthFont &)> onPrintScreen
Definition gothic.h:173
void openDialogPipe(Npc &player, Npc &npc, AiOuputPipe *&pipe)
Definition gothic.cpp:639
Gothic()
Definition gothic.cpp:47
Tempest::Signal< void(std::string_view)> onLoadGame
Definition gothic.h:167
void updateAnimation(uint64_t dt)
Definition gothic.cpp:610
static float interfaceScale(const Tempest::Widget *w)
Definition gothic.cpp:471
const World * world() const
Definition gothic.cpp:278
void popPause()
Definition gothic.cpp:455
LoadState checkLoading() const
Definition gothic.cpp:500
void load(std::string_view slot)
Definition gothic.cpp:627
static void settingsSetS(std::string_view sec, std::string_view name, std::string_view val)
Definition gothic.cpp:836
bool isBenchmarkMode() const
Definition gothic.cpp:484
void setFRate(bool f)
Definition gothic.h:134
static Gothic & inst()
Definition gothic.cpp:249
Tempest::Signal< void(Npc &, Npc &, AiOuputPipe *&)> onDialogPipe
Definition gothic.h:170
auto updateDialog(const GameScript::DlgChoice &dlg, Npc &player, Npc &npc) -> std::vector< GameScript::DlgChoice >
Definition gothic.cpp:631
std::string_view defaultSave() const
Definition gothic.cpp:693
std::string_view defaultWorld() const
Definition gothic.cpp:685
static const CameraDefinitions & cameraDef()
Definition gothic.cpp:663
zenkit::DaedalusScript loadScript(std::string_view datFile, const ScriptLang lang)
Definition gothic.cpp:720
auto questLog() const -> const QuestLog *
Definition gothic.cpp:325
static const FightAi & fai()
Definition gothic.cpp:651
std::string_view menuMain() const
Definition gothic.cpp:705
auto version() const -> const VersionInfo &
Definition gothic.cpp:263
auto clearGame() -> std::unique_ptr< GameSession >
Definition gothic.cpp:295
void startLoad(std::string_view banner, const std::function< std::unique_ptr< GameSession >(std::unique_ptr< GameSession > &&)> f)
Definition gothic.cpp:526
bool isNpcInDialog(const Npc &npc) const
Definition gothic.cpp:643
Tempest::Signal< void()> onStartLoading
Definition gothic.h:180
SoundFx * loadSoundFx(std::string_view name)
Definition gothic.cpp:343
std::unique_ptr< zenkit::DaedalusVm > createPhoenixVm(std::string_view datFile, const ScriptLang lang=ScriptLang::NONE)
Definition gothic.cpp:711
auto gameSession() const -> const GameSession *
Definition gothic.cpp:299
static int settingsGetI(std::string_view sec, std::string_view name)
Definition gothic.cpp:807
Tempest::Signal< void(std::string_view)> onVideo
Definition gothic.h:175
void save(std::string_view slot, std::string_view usrName)
Definition gothic.cpp:623
static const MusicDefinitions & musicDef()
Definition gothic.cpp:659
LoadState
Definition gothic.h:35
void cancelLoading()
Definition gothic.cpp:591
WorldView * worldView() const
Definition gothic.cpp:307
bool isInDialog() const
Definition gothic.cpp:647
std::string_view defaultGameDatFile() const
Definition gothic.cpp:697
int loadingProgress() const
Definition gothic.cpp:331
Tempest::Signal< void(const DocumentMenu::Show &)> onShowDocument
Definition gothic.h:178
static void flushSettings()
Definition gothic.cpp:858
uint32_t messageTime(std::string_view id) const
Definition gothic.cpp:679
static std::string_view settingsGetS(std::string_view sec, std::string_view name)
Definition gothic.cpp:824
void setupVmCommonApi(zenkit::DaedalusVm &vm)
Definition gothic.cpp:953
bool isInGameAndAlive() const
Definition gothic.cpp:271
bool isMarvinEnabled() const
Definition gothic.cpp:463
static bool settingsHasSection(std::string_view sec)
Definition gothic.cpp:798
static const SoundDefinitions & sfx()
Definition gothic.cpp:655
static void settingsSetF(std::string_view sec, std::string_view name, float val)
Definition gothic.cpp:853
std::string_view defaultOutputUnits() const
Definition gothic.cpp:701
static float settingsGetF(std::string_view sec, std::string_view name)
Definition gothic.cpp:841
bool isInGame() const
Definition gothic.cpp:267
Npc * player()
Definition gothic.cpp:313
auto loadingBanner() const -> const Tempest::Texture2d *
Definition gothic.cpp:339
void setBenchmarkMode(Benchmark b)
Definition gothic.cpp:492
void setLoadingProgress(int v)
Definition gothic.cpp:335
bool isPause() const
Definition gothic.cpp:459
std::function< bool(const Npc *)> isNpcInDialogFn
Definition gothic.h:171
void setGame(std::unique_ptr< GameSession > &&w)
Definition gothic.cpp:290
void emitGlobalSound(std::string_view sfx)
Definition gothic.cpp:395
Tempest::Signal< void(const ChapterScreen::Show &)> onIntroChapter
Definition gothic.h:177
void emitGlobalSoundWav(std::string_view wav)
Definition gothic.cpp:432
SoundFx * loadSoundWavFx(std::string_view name)
Definition gothic.cpp:364
Tempest::Signal< void(std::string_view)> onPrint
Definition gothic.h:174
void setMarvinEnabled(bool m)
Definition gothic.cpp:467
void quickLoad()
Definition gothic.cpp:619
Tempest::Signal< void(std::string_view, std::string_view)> onSaveGame
Definition gothic.h:168
void startSave(Tempest::Texture2d &&tex, const std::function< std::unique_ptr< GameSession >(std::unique_ptr< GameSession > &&)> f)
Definition gothic.cpp:520
std::string_view messageFromSvm(std::string_view id, int voice) const
Definition gothic.cpp:667
void setupCommonScriptClasses(zenkit::DaedalusScript &sc)
Definition gothic.cpp:761
void tick(uint64_t dt)
Definition gothic.cpp:598
std::string_view messageByName(std::string_view id) const
Definition gothic.cpp:673
static auto invCatOrder() -> const std::vector< ItmFlags > &
Definition gothic.cpp:447
auto loadVisualFx(std::string_view name) -> const VisualFx *
Definition gothic.cpp:383
void quickSave()
Definition gothic.cpp:615
Tempest::Signal< void()> onWorldLoaded
Definition gothic.h:179
Main application window handling game rendering and input.
Definition mainwindow.h:58
Definition npc.h:25
static void loadVdfs(const std::vector< std::u16string > &modvdfs, bool modFilter)
static const GthFont & font(const float scale)
static bool hasFile(std::string_view fname)
static Tempest::Device & device()
Definition resources.h:83
static std::unique_ptr< zenkit::Read > getFileBuffer(std::string_view name)
static Tempest::Sound loadSoundBuffer(std::string_view name)
static void mountWork(const std::filesystem::path &path)
static bool isRtsmSupported()
Definition shaders.cpp:325
static bool isVsmSupported()
Definition shaders.cpp:316
int32_t patch
Definition versioninfo.h:8
uint8_t game
Definition versioninfo.h:7
static void setThreadName(const char *threadName)
Definition workers.cpp:66
Definition world.h:31
ItmFlags
Definition constants.h:312
@ ITM_CAT_MAGIC
Definition constants.h:323
@ ITM_CAT_NONE
Definition constants.h:313
@ ITM_CAT_NF
Definition constants.h:314
@ ITM_CAT_FOOD
Definition constants.h:318
@ ITM_CAT_FF
Definition constants.h:315
@ ITM_CAT_RUNE
Definition constants.h:322
@ ITM_CAT_DOCS
Definition constants.h:319
@ ITM_CAT_MUN
Definition constants.h:316
@ ITM_CAT_POTION
Definition constants.h:320
@ ITM_CAT_ARMOR
Definition constants.h:317
@ ITM_CAT_LIGHT
Definition constants.h:321
Benchmark
Definition constants.h:537
ScriptLang
Definition constants.h:518
static bool hasMeshShader()
Definition gothic.cpp:33
static bool hasBindless()
Definition gothic.cpp:40
Main application window for OpenGothic.
bool exists(const std::u16string &path)
Definition fileutil.cpp:15
std::u16string caseInsensitiveSegment(std::u16string_view path, const char16_t *segment, Tempest::Dir::FileType type)
bool doVirtualShadow
Definition gothic.h:49
uint8_t showManaBar
Definition gothic.h:67
bool doMeshShading
Definition gothic.h:47
float interfaceScale
Definition gothic.h:59
Tempest::Size saveGameImageSize
Definition gothic.h:64
bool showHealthBar
Definition gothic.h:66
float cameraFov
Definition gothic.h:57
bool doSoftwareRT
Definition gothic.h:51
uint32_t aaPreset
Definition gothic.h:54
int inventoryCellSize
Definition gothic.h:60
bool hideFocus
Definition gothic.h:56
bool doSoftwareShadow
Definition gothic.h:50
uint8_t showSwimBar
Definition gothic.h:68
Tempest::Size newChapterSize
Definition gothic.h:62
bool doBindless
Definition gothic.h:48
bool doRayQuery
Definition gothic.h:45