3#include <Tempest/Painter>
5#include <Tempest/TextCodec>
6#include <Tempest/Dialog>
24using namespace Tempest;
30 setFocusPolicy(ClickFocus);
31 setCursorShape(CursorShape::Hidden);
36 if(e.button==Event::ButtonRight) {
47 if(e.key==Event::K_ESCAPE) {
51 if(e.key==Event::K_W || e.key==Event::K_Up) {
55 if(e.key==Event::K_S || e.key==Event::K_Down) {
80 setFocusPolicy(ClickFocus);
81 setCursorShape(CursorShape::Hidden);
83 status = toStatus(
list.handle->user_string[0]);
87 if(e.button==Event::ButtonLeft) {
90 if(e.button==Event::ButtonRight) {
96 auto prev =
owner.curItem;
97 auto* next =
owner.selectedContentItem(&
list);
99 if(next==
nullptr || ql==
nullptr)
102 auto vis = next->visible;
103 next->visible =
true;
106 for(
size_t i=0; i<ql->entry.size(); ++i) {
107 text += ql->entry[i];
108 if(i+1<ql->entry.size())
112 next->handle->text[0] = text;
114 for(uint32_t i=0; i<zenkit::IMenu::item_count; ++i)
115 if(&
owner.hItems[i]==next) {
121 dlg.resize(
owner.owner.size());
124 owner.curItem = prev;
134 if(e.key==Event::K_Return) {
138 if(e.key==Event::K_ESCAPE) {
142 if(e.key==Event::K_W || e.key==Event::K_Up) {
146 if(e.key==Event::K_S || e.key==Event::K_Down) {
163 if(
list.value+1<
int(num))
178 for(
size_t i=0; i<ql->questCount(); ++i) {
179 auto& quest = ql->quest(ql->questCount()-i-1);
180 if(!isCompatible(quest,
status))
197 setFocusPolicy(ClickFocus);
198 setCursorShape(CursorShape::Hidden);
216 Event::KeyType
key = Event::K_ESCAPE;
217 Event::MouseButton
mkey = Event::ButtonNone;
222 setFocusPolicy(ClickFocus);
223 setCursorShape(CursorShape::Hidden);
237 if(e.key==Event::K_ESCAPE) {
242 if(e.key==Event::K_Return) {
247 if(e.key==Event::K_Back &&
text.size()>0) {
252 char ch[2] = {
'\0',
'\0'};
253 if((
'a'<=e.code && e.code<=
'z') || (
'A'<=e.code && e.code<=
'Z') ||
254 (
'0'<=e.code && e.code<=
'9') || e.code==
' ' || e.code==
'.')
255 ch[0] = char(e.code);
271 :owner(owner), keyCodec(keyCodec), vm(&vm), kClose(kClose) {
272 setCursorShape(CursorShape::Hidden);
278 auto* menuSectionSymbol = vm.find_symbol_by_name(menuSection);
279 if(menuSectionSymbol!=
nullptr) {
280 menu = vm.init_instance<zenkit::IMenu>(menuSectionSymbol);
282 Tempest::Log::e(
"Cannot initialize menu ", menuSection,
": Symbol not found.");
283 menu = std::make_shared<zenkit::IMenu>();
293 if(vm.find_symbol_by_name(
"MENU_INFO_X") !=
nullptr && vm.find_symbol_by_name(
"MENU_INFO_X") !=
nullptr) {
294 auto* symX = vm.find_symbol_by_name(
"MENU_INFO_X");
295 auto* symY = vm.find_symbol_by_name(
"MENU_INFO_Y");
297 infoX = float(symX->get_int())/
scriptDiv;
298 infoY = float(symY->get_int())/
scriptDiv;
300 setPosition(
int(infoX*
float(w())),
int(infoY*
float(h())));
302 setSelection(
Gothic::inst().isInGameAndAlive() ? menu->default_ingame : menu->default_outgame);
320 for(
int i=0; i<zenkit::IMenu::item_count; ++i){
321 hItems[i].handle =
nullptr;
329GameMenu::QuestStat GameMenu::toStatus(std::string_view str) {
330 if(str==
"CURRENTMISSIONS")
331 return QuestStat::Current;
332 if(str==
"OLDMISSIONS")
333 return QuestStat::Old;
334 if(str==
"FAILEDMISSIONS")
335 return QuestStat::Failed;
337 return QuestStat::Log;
338 return QuestStat::Log;
347int32_t GameMenu::numQuests(
const QuestLog* ql, QuestStat st) {
352 if(isCompatible(ql->
quest(i),st))
357void GameMenu::initItems() {
358 for(
int i=0; i<zenkit::IMenu::item_count; ++i){
359 if(menu->items[i].empty())
362 hItems[i].name = menu->items[i];
364 auto* menuItemSymbol = vm->find_symbol_by_name(hItems[i].name);
365 if (menuItemSymbol !=
nullptr) {
366 hItems[i].handle = vm->init_instance<zenkit::IMenuItem>(menuItemSymbol);
368 Tempest::Log::e(
"Cannot initialize menu item ", hItems[i].name,
": Symbol not found.");
369 hItems[i].handle = std::make_shared<zenkit::IMenuItem>();
374 if(hItems[i].handle->type==zenkit::MenuItemType::LISTBOX) {
375 hItems[i].visible =
false;
377 updateItem(hItems[i]);
385 p.setScissor(-x(),-y(),owner.w(),owner.h());
389 p.drawRect(0,0,w(),h(),
390 0,0,back->w(),back->h());
393 for(
auto& hItem:hItems)
396 if(menu->flags & zenkit::MenuFlag::SHOW_INFO) {
397 if(
auto sel=selectedItem()) {
398 auto& item = sel->handle;
399 if(item->text->size()>0) {
401 std::string_view txt = item->text[1];
402 int tw = fnt.textSize(txt).w;
404 fnt.drawText(p,(w()-tw)/2,h()-
int(7*scale),txt);
411 fnt.drawText(p, w()-fnt.textSize(
appBuild).w-
int(25*scale), h()-
int(25*scale),
appBuild);
415void GameMenu::drawItem(Painter& p,
Item& hItem) {
416 if(!hItem.visible || hItem.name.empty())
418 if(isHidden(hItem.
handle))
421 auto& item = hItem.
handle;
422 auto flags = item->flags;
423 getText(hItem,textBuf);
425 const int32_t dimx = (item->dim_x!=-1) ? item->dim_x : 8192;
426 const int32_t dimy = (item->dim_y!=-1) ? item->dim_y : 750;
428 const int x = int(
float(w()*item->pos_x)/
scriptDiv);
429 const int y = int(
float(h()*item->pos_y)/
scriptDiv);
430 int szX = int(
float(w()*dimx )/
scriptDiv);
431 int szY = int(
float(h()*dimy )/
scriptDiv);
433 if(hItem.img && !hItem.img->isEmpty()) {
434 p.setBrush(*hItem.img);
435 p.drawRect(x,y,szX,szY,
436 0,0,hItem.img->w(),hItem.img->h());
439 auto fnt = getTextFont(hItem);
443 AlignFlag txtAlign=NoAlign;
444 if(flags & zenkit::MenuItemFlag::CENTERED) {
445 txtAlign = AlignHCenter | AlignVCenter;
452 if((flags & zenkit::MenuItemFlag::MULTILINE) &&
453 std::min(tw,th)>100*2+fnt.pixelSize()) {
456 auto tRect = Rect(x+padd,y+fnt.pixelSize()+padd,
457 tw-2*padd, th-2*padd);
459 if(flags & zenkit::MenuItemFlag::MULTILINE) {
460 int lineCnt = fnt.lineCount(tRect.w,textBuf.data());
461 int linesInView = tRect.h/fnt.pixelSize();
463 hItem.scroll = std::min(hItem.scroll, std::max(lineCnt-linesInView,0));
464 hItem.scroll = std::max(hItem.scroll, 0);
465 if(lineCnt>linesInView+hItem.scroll) {
467 p.drawRect(x+(tw-down->w())/2, y+th-padd,
468 down->w(), down->h());
472 p.drawRect(x+(tw-up->w())/2, y+padd-up->h(),
476 tRect.h = std::max(tRect.h, fnt.pixelSize());
479 fnt.drawText(p, tRect.x,tRect.y, tRect.w, tRect.h,
480 textBuf.data(), txtAlign, hItem.scroll);
483 if(item->type==zenkit::MenuItemType::SLIDER && slider!=
nullptr) {
484 drawSlider(p,hItem,x,y,szX,szY);
486 else if(item->type==zenkit::MenuItemType::LISTBOX) {
488 const int px = int(
float(w()*item->frame_sizex)/
scriptDiv);
489 const int py = int(
float(h()*item->frame_sizey)/
scriptDiv);
491 auto st = toStatus(item->user_string[0]);
492 drawQuestList(p, hItem, x+px,y+py, szX-2*px,szY-2*py, *ql,st);
495 else if(item->type==zenkit::MenuItemType::INPUT) {
497 if(item->on_chg_set_option_section==
"KEYS") {
499 if(&hItem!=ctrlInput)
505 if(str.empty() && &hItem!=ctrlInput && saveSlotId(hItem)!=
size_t(-1))
507 if(&hItem!=ctrlInput)
508 textBuf = std::string_view(str);
else
514 szX, std::max(szY,fnt.pixelSize()),
520void GameMenu::drawSlider(Painter& p,
Item& it,
int x,
int y,
int sw,
int sh) {
521 float k = float(sh/2)/float(slider->h());
522 int w = int(
float(slider->w())*k);
523 int h = int(
float(slider->h())*k);
526 auto& sec = it.
handle->on_chg_set_option_section;
527 auto& opt = it.
handle->on_chg_set_option;
528 if(sec.empty() || opt.empty())
532 int dx = int(
float(sw-w)*std::max(0.f,std::min(v,1.f)));
533 p.drawRect(x+dx,y+(sh-h)/2,w,h,
534 0,0,p.brush().w(),p.brush().h());
537void GameMenu::drawQuestList(Painter& p,
Item& it,
int x,
int y,
int w,
int h,
538 const QuestLog& log, QuestStat st) {
541 int32_t listLen = numQuests(&log,st);
542 int32_t listBegin = it.scroll;
543 int32_t listEnd = listLen;
548 if(!isCompatible(quest,st))
555 if(listId==it.value && selectedItem()==&it)
559 auto sz = fnt.textSize(w,quest.name);
565 fnt.drawText(p,x,itY+
int(fnt.pixelSize()),w,sz.h,quest.name,Tempest::AlignLeft);
569 if(listBegin>it.value) {
570 it.scroll = std::max(it.scroll-1,0);
573 if(listEnd<=it.value) {
574 it.scroll = std::min(it.scroll+1,listLen);
578 if(listEnd<listLen && down!=
nullptr) {
580 p.drawRect(x+w-down->w(),y+h-down->h(),
581 down->w(),down->h());
583 if(listBegin>0 && up!=
nullptr) {
585 p.drawRect(x+w-up->w(),y,
595 auto sel = selectedItem();
596 if(sel!=
nullptr && isHorSelectable(sel->handle)) {
606 setSelection(
int(curItem)+dy, dy);
607 if(
auto s = selectedItem())
631 const float fx = 640.0f * scale;
632 const float fy = 480.0f * scale;
634 const float wx = float(owner.w());
635 const float wy = float(owner.h());
638 if(menu->flags & zenkit::MenuFlag::DONT_SCALE_DIMENSION) {
645 if(menu->flags & zenkit::MenuFlag::ALIGN_CENTER) {
646 setPosition((owner.w()-w())/2, (owner.h()-h())/2);
648 setPosition(
int(
float(menu->pos_x)/
scriptDiv*fx),
int(
float(menu->pos_y)/
scriptDiv*fy));
657GameMenu::Item *GameMenu::selectedItem() {
658 if(curItem<zenkit::IMenu::item_count)
659 return &hItems[curItem];
663GameMenu::Item* GameMenu::selectedNextItem(
Item *it) {
664 uint32_t cur=curItem+1;
665 for(uint32_t i=0;i<zenkit::IMenu::item_count;++i)
671 for(
int i=0;i<zenkit::IMenu::item_count;++i,cur++) {
672 cur%=zenkit::IMenu::item_count;
674 auto& it=hItems[cur].handle;
681GameMenu::Item* GameMenu::selectedContentItem(
Item *it) {
682 uint32_t cur=curItem+1;
683 for(uint32_t i=0;i<zenkit::IMenu::item_count;++i)
689 for(
int i=0;i<zenkit::IMenu::item_count;++i,cur++) {
690 cur%=zenkit::IMenu::item_count;
692 auto& it=hItems[cur].handle;
693 if(isEnabled(it) && it->type==zenkit::MenuItemType::TEXT)
699void GameMenu::setSelection(
int desired,
int seek) {
700 uint32_t cur=uint32_t(desired);
701 for(
int i=0; i<zenkit::IMenu::item_count; ++i,cur+=uint32_t(seek)) {
702 cur%=zenkit::IMenu::item_count;
704 auto& it=hItems[cur].handle;
705 if(isSelectable(it) && isEnabled(it)){
707 for(
size_t i=0;i<zenkit::IMenuItem::select_action_count;++i)
708 if(it->on_sel_action[i]==
int(zenkit::MenuItemSelectAction::EXECUTE_COMMANDS))
713 curItem=uint32_t(-1);
716void GameMenu::getText(
const Item& it, std::vector<char> &out) {
721 const auto& src = it.
handle->text[0];
722 if(it.
handle->type==zenkit::MenuItemType::TEXT) {
723 size_t size = src.size();
725 std::memcpy(out.data(),src.c_str(),size+1);
729 if(it.
handle->type==zenkit::MenuItemType::CHOICEBOX) {
730 strEnum(src,it.value,out);
735const GthFont& GameMenu::getTextFont(
const GameMenu::Item &it) {
738 if(!isEnabled(it.handle))
740 if(&it==selectedItem())
745bool GameMenu::isSelectable(
const std::shared_ptr<zenkit::IMenuItem>& item) {
746 return item !=
nullptr && (item->flags & zenkit::MenuItemFlag::SELECTABLE) && !isHidden(item);
749bool GameMenu::isHorSelectable(
const std::shared_ptr<zenkit::IMenuItem>& item) {
750 return item !=
nullptr && (item->flags & zenkit::MenuItemFlag::HOR_SELECTABLE) && !isHidden(item);
753bool GameMenu::isEnabled(
const std::shared_ptr<zenkit::IMenuItem>& item) {
763bool GameMenu::isHidden(
const std::shared_ptr<zenkit::IMenuItem>& item) {
766 if(item->hide_if_option_set.empty())
770 item->hide_if_option_set);
771 return opt==item->hide_on_value;
778 execSingle(*it,slideDx,hint);
else
779 execChgOption(*it,slideDx);
780 if(it->handle->flags & zenkit::MenuItemFlag::EFFECTS) {
781 auto next=selectedNextItem(it);
797 auto& onSelAction = item->on_sel_action;
798 auto& onSelAction_S = item->on_sel_action_s;
799 auto& onEventAction = item->on_event_action;
801 if(item->type==zenkit::MenuItemType::INPUT && slideDx==0) {
803 if(item->on_chg_set_option.empty()) {
804 SavNameDialog dlg{item->text[0]};
805 if(it.savHdr.version==0)
807 dlg.resize(owner.size());
814 keyCodec.
clear(item->on_chg_set_option_section, item->on_chg_set_option);
821 dlg.resize(owner.size());
825 if(dlg.key==Event::K_ESCAPE && dlg.mkey==Event::ButtonNone)
828 if(dlg.key==Event::K_ESCAPE)
831 keyCodec.
set(item->on_chg_set_option_section, item->on_chg_set_option, next);
837 for(
size_t i=0; i<zenkit::IMenuItem::select_action_count; ++i) {
838 auto action = zenkit::MenuItemSelectAction(onSelAction[i]);
840 case zenkit::MenuItemSelectAction::UNKNOWN:
842 case zenkit::MenuItemSelectAction::BACK:
846 case zenkit::MenuItemSelectAction::START_MENU:
847 if(vm->find_symbol_by_name(onSelAction_S[i]) !=
nullptr)
850 case zenkit::MenuItemSelectAction::START_ITEM:
852 case zenkit::MenuItemSelectAction::CLOSE:
855 if(onSelAction_S[i]==
"NEW_GAME") {
858 else if(onSelAction_S[i]==
"LEAVE_GAME") {
859 Log::i(
"Exiting, by item action (`LEAVE_GAME`)");
860 Tempest::SystemApi::exit();
862 else if(onSelAction_S[i]==
"SAVEGAME_SAVE") {
865 else if(onSelAction_S[i]==
"SAVEGAME_LOAD"){
866 if (!execLoadGame(it)){
872 case zenkit::MenuItemSelectAction::CON_COMMANDS:
875 case zenkit::MenuItemSelectAction::PLAY_SOUND:
878 case zenkit::MenuItemSelectAction::EXECUTE_COMMANDS:
879 execCommands(onSelAction_S[i],
true,hint);
884 if(onEventAction[
int(zenkit::MenuItemSelectEvent::EXECUTE)]>0){
885 auto* sym = vm->find_symbol_by_index(uint32_t(onEventAction[
int(zenkit::MenuItemSelectEvent::EXECUTE)]));
887 vm->call_function(sym);
890 execChgOption(it,slideDx);
893void GameMenu::execChgOption(
Item &item,
int slideDx) {
894 auto& sec = item.
handle->on_chg_set_option_section;
895 auto& opt = item.
handle->on_chg_set_option;
896 if(sec.empty() || opt.empty())
899 if(item.
handle->type==zenkit::MenuItemType::SLIDER && slideDx!=0) {
902 v = std::max(0.f,std::min(v+
float(slideDx)*0.03f,1.f));
905 if(item.
handle->type==zenkit::MenuItemType::CHOICEBOX) {
907 const int cnt = int(strEnumSize(item.
handle->text[0]));
908 if(slideDx==0 && cnt==2)
911 item.value += slideDx;
913 item.value = std::clamp(item.value,0,cnt-1);
else
919void GameMenu::execSaveGame(
const GameMenu::Item& item) {
920 const size_t id = saveSlotId(item);
924 string_frm fname(
"save_slot_",
int(
id),
".sav");
928bool GameMenu::execLoadGame(
const GameMenu::Item &item) {
929 const size_t id = saveSlotId(item);
933 string_frm fname(
"save_slot_",
int(
id),
".sav");
940void GameMenu::execCommands(std::string str,
bool isClick,
KeyCodec::Action hint) {
941 if(str.find(
"EFFECTS ")==0) {
943 const char* arg0 = str.data()+std::strlen(
"EFFECTS ");
944 for(uint32_t
id=0;
id<zenkit::IMenu::item_count; ++id) {
945 auto& i = hItems[id];
946 if(i.handle !=
nullptr && i.handle->type==zenkit::MenuItemType::LISTBOX) {
947 i.visible = (i.name==arg0);
948 if(i.visible && isClick) {
949 const uint32_t prev = curItem;
951 ListViewDialog dlg(*
this,i);
952 if(dlg.numQuests()==0) {
956 dlg.resize(owner.size());
966 if(str.find(
"RUN ")==0) {
967 const char* what = str.data()+4;
972 execSingle(i,0,hint);
974 if(str==
"SETDEFAULT") {
975 setDefaultKeys(
"KEYSDEFAULT0");
977 if(str==
"SETALTERNATIVE") {
978 setDefaultKeys(
"KEYSDEFAULT1");
982void GameMenu::updateItem(GameMenu::Item &item) {
985 updateSavTitle(item);
988void GameMenu::updateSavTitle(GameMenu::Item& sel) {
989 if(sel.handle->on_sel_action_s[0]!=
"SAVEGAME_LOAD" &&
990 sel.handle->on_sel_action_s[1]!=
"SAVEGAME_SAVE")
992 const size_t id = saveSlotId(sel);
997 std::snprintf(fname,
sizeof(fname)-1,
"save_slot_%d.sav",
int(
id));
1000 sel.handle->text[0] =
"---";
1008 reader.setEntry(
"header");
1010 if(
id!=0 || sel.handle->text[0].empty())
1011 sel.handle->text[0] = hdr.
name;
1012 sel.savHdr = std::move(hdr);
1014 if(reader.setEntry(
"priview.png"))
1015 reader.read(sel.savPriview);
1016 else if(reader.setEntry(
"preview.png"))
1017 reader.read(sel.savPriview);
1019 catch(std::bad_alloc&) {
1022 catch(std::system_error& e) {
1026 catch(std::runtime_error&) {
1031void GameMenu::updateSavThumb(GameMenu::Item &sel) {
1032 if(sel.handle->on_sel_action_s[0]!=
"SAVEGAME_LOAD" &&
1033 sel.handle->on_sel_action_s[1]!=
"SAVEGAME_SAVE")
1036 if(!implUpdateSavThumb(sel)) {
1037 set(
"MENUITEM_LOADSAVE_THUMBPIC",
static_cast<Texture2d*
>(
nullptr));
1038 set(
"MENUITEM_LOADSAVE_LEVELNAME_VALUE",
"");
1039 set(
"MENUITEM_LOADSAVE_DATETIME_VALUE",
"");
1040 set(
"MENUITEM_LOADSAVE_GAMETIME_VALUE",
"");
1041 set(
"MENUITEM_LOADSAVE_PLAYTIME_VALUE",
"");
1045void GameMenu::updateVideo() {
1047 set(
"MENUITEM_VID_RESOLUTION_CHOICE",
"full|upscale(75%)|upscale(half)");
1050void GameMenu::setDefaultKeys(std::string_view preset) {
1054bool GameMenu::implUpdateSavThumb(GameMenu::Item& sel) {
1055 const size_t id = saveSlotId(sel);
1060 std::snprintf(fname,
sizeof(fname)-1,
"save_slot_%d.sav",
int(
id));
1070 set(
"MENUITEM_LOADSAVE_THUMBPIC", &savThumb);
1071 set(
"MENUITEM_LOADSAVE_LEVELNAME_VALUE",hdr.
world);
1073 std::snprintf(form,
sizeof(form),
"%d.%d.%d - %d:%02d",
int(hdr.
pcTime.tm_mday),
int(hdr.
pcTime.tm_mon+1),
int(1900+hdr.
pcTime.tm_year),
int(hdr.
pcTime.tm_hour),
int(hdr.
pcTime.tm_min));
1074 set(
"MENUITEM_LOADSAVE_DATETIME_VALUE", form);
1077 set(
"MENUITEM_LOADSAVE_GAMETIME_VALUE", form);
1079 auto mins = hdr.
playTime/(60*1000);
1080 std::snprintf(form,
sizeof(form),
"%dh %dmin",
int(mins/60),
int(mins%60));
1081 set(
"MENUITEM_LOADSAVE_PLAYTIME_VALUE", form);
1085size_t GameMenu::saveSlotId(
const GameMenu::Item &sel) {
1086 const char* prefix[2] = {
"MENUITEM_LOAD_SLOT",
"MENUITEM_SAVE_SLOT"};
1087 for(
auto p:prefix) {
1088 if(sel.name.find(p)==0){
1089 size_t off=std::strlen(p);
1091 for(
size_t i=off;i<sel.name.size();++i){
1092 if(
'0'<=sel.name[i] && sel.name[i]<=
'9') {
1093 id=
id*10+size_t(sel.name[i]-
'0');
1104std::string_view GameMenu::strEnum(std::string_view en,
int id, std::vector<char> &out) {
1108 for(
size_t r=0; r<en.size(); ++r)
1114 for(;i<en.size();++i){
1116 for(
size_t r=i; r<en.size(); ++r,++i)
1123 std::memcpy(&out[0],&en[b],sz);
1130 for(
size_t i=0; i<en.size(); ++i){
1131 if(en[i]==
'#' || en[i]==
'|'){
1133 std::memcpy(&out[0],en.data(),i);
1142size_t GameMenu::strEnumSize(std::string_view en) {
1146 for(
size_t i=0; i<en.size(); ++i) {
1147 if(en[i]==
'#' || en[i]==
'|') {
1148 cnt += en[i]==
'|' ? 2 : 1;
1150 for(;i<en.size();++i) {
1159void GameMenu::set(std::string_view item,
const Texture2d *value) {
1167void GameMenu::set(std::string_view item,
const uint32_t value) {
1171void GameMenu::set(std::string_view item,
const int32_t value) {
1175void GameMenu::set(std::string_view item,
const int32_t value,
const int32_t max) {
1179void GameMenu::set(std::string_view item, std::string_view value) {
1182 i.handle->text[0] = value;
1187void GameMenu::updateValues() {
1192 set(
"MENU_ITEM_PLAYERGUILD",
"Debugger");
1193 set(
"MENU_ITEM_LEVEL",
"0");
1194 set(
"MENUITEM_AUDIO_PROVIDER_CHOICE",
"OpenGothic|GothicKit (Experimental)");
1195 for(
auto& i:hItems) {
1196 if(i.name==
"MENU_ITEM_CONTENT_VIEWER") {
1199 if(i.name==
"MENU_ITEM_DAY") {
1200 i.handle->text[0] = std::to_string(time.
day());
1202 if(i.name==
"MENU_ITEM_TIME") {
1204 std::snprintf(form,
sizeof(form),
"%d:%02d",
int(time.
hour()),
int(time.
minute()));
1205 i.handle->text[0] = form;
1209 if(
auto s = selectedItem())
1220 auto& sc = world->
script();
1222 auto* tal = sc.findSymbol(
"TXT_TALENTS");
1223 auto* talV = sc.findSymbol(
"TXT_TALENTS_SKILLS");
1225 if(gilds==
nullptr || tal==
nullptr || talV==
nullptr) {
1229 set(
"MENU_ITEM_PLAYERGUILD", gilds->get_string(uint16_t(pl.
guild())));
1231 set(
"MENU_ITEM_LEVEL", pl.
level());
1249 for(uint16_t i=0; i<talentMax; ++i) {
1250 auto& str = tal->get_string(i);
1257 set(
string_frm(
"MENU_ITEM_TALENT_",i,
"_TITLE"), str);
1258 set(
string_frm(
"MENU_ITEM_TALENT_",i,
"_SKILL"), strEnum(talV->get_string(i),sk,textBuf));
static const char * appBuild
static Tags mkTags(Tags daytime, Tags mode)
static GameMusic & inst()
zenkit::DaedalusSymbol * findSymbol(std::string_view s)
static void settingsSetI(std::string_view sec, std::string_view name, int val)
static float interfaceScale(const Tempest::Widget *w)
const World * world() const
Tempest::Signal< void(std::string_view)> onStartGame
void load(std::string_view slot)
auto version() const -> const VersionInfo &
static int settingsGetI(std::string_view sec, std::string_view name)
void save(std::string_view slot, std::string_view usrName)
static const MusicDefinitions & musicDef()
static void flushSettings()
static std::string_view settingsGetS(std::string_view sec, std::string_view name)
bool isInGameAndAlive() const
static void settingsSetF(std::string_view sec, std::string_view name, float val)
static float settingsGetF(std::string_view sec, std::string_view name)
void emitGlobalSound(std::string_view sfx)
const zenkit::IItem & handle() const
static auto keysStr(std::string_view keys) -> string_frm< 64 >
void set(std::string_view section, std::string_view key, int32_t code)
static int32_t keyToCode(Tempest::Event::KeyType t)
void setDefaultKeys(std::string_view preset)
void clear(std::string_view section, std::string_view key)
int32_t protection(Protection p) const
int32_t experience() const
int32_t hitChance(Talent t) const
int32_t talentSkill(Talent t) const
int32_t talentValue(Talent t) const
int32_t attribute(Attribute a) const
int32_t experienceNext() const
int32_t learningPoints() const
auto quest(size_t i) const -> const Quest &
size_t questCount() const
static const GthFont & font(const float scale)
static Tempest::Device & device()
static const Tempest::Texture2d * loadTexture(std::string_view name, bool forceMips=false)
static const char * renderer()
static Tempest::Texture2d loadTexturePm(const Tempest::Pixmap &pm)
GameScript & script() const
bool exists(const std::u16string &path)