• Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!

Вопросы по union

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Myszax, here are two test funcs. Try it, maybe something will work:
C++:
namespace GOTHIC_ENGINE {

// The function returns the slot number of the last save,
// using information about the date and time of saving
// Returns:
// "0" - if the last quick save slot was
// "-1" - if there are no save files,
// "1 ... 20" - in other cases
int GetLastSaveGameSlot()
{
    int lastSaveSlot = -1;        // variable to store the current slot number
    long lastTime;                // variable to store the current timestamp
    const int maxSlots = 20;    // maximum number of slots for save files

    // full path to the internal save folder
    zSTRING fullPathToSaves = zoptions->GetDirString(zTOptionPaths::DIR_ROOT) + zoptions->GetDirString(zTOptionPaths::DIR_SAVEGAMES);

    // name of the subfolder with save files
    // (first check the quick save folder, then regular slots)
    zSTRING subPath = "quicksave";

    // full path to the save file
    // (constantly generated in a loop)
    zSTRING fullPathToSaveFile = "";

    // declare a structure for receiving file parameters
    zFILE_STATS stats;

    // go through all save slots (quicksave and 1-20)
    for (int i = 0; i <= maxSlots; i++)
    {
        // the first thing to check is the "quicksave" subfolder,
        // in other cases: "savegame" + slot number
        if (i > 0)
            // so, we form the name of the subfolder
            subPath = "savegame" + Z(i);

        // then create the full path to the main save file
        // under the selected slot (save folder + subfolder + file)
        fullPathToSaveFile = fullPathToSaves + subPath + "\\SAVEDAT.SAV";

        // open access to the file
        zFILE_FILE file(fullPathToSaveFile);

        // if file parameters are not received
        if (file.GetStats(stats) != zERR_NONE)
            // means we move on to checking the next slot
            continue;

        // Otherwise, we work with the save file.
        // Check if the current slot is not yet designated,
        // this means there was no first record with which we can compare something
        if (lastSaveSlot == -1)
        {
            // therefore we record in a variable the date and time of saving,
            // expressed in seconds, relative to 1900
            lastTime = stats.modifyDate.ToTime_t();

            // remember the slot standard
            lastSaveSlot = i;

            // continue searching through slots
            continue;
        }

        // Otherwise, there is something to compare with.
        // Therefore, we compare timestamps to determine the new current save.
        // To do this, we convert the date and time the file was saved into an equivalent number of seconds.
        long currentTime = stats.modifyDate.ToTime_t();

        // Check if the current save was made later
        if (currentTime > lastTime)
        {
            // update data about the last save
            lastTime = currentTime;

            // remember the slot number
            lastSaveSlot = i;
        }

    } /* end of loop */

    // at the end of the function - return the current number of the storage slot
    return lastSaveSlot;
}





// Test - Loading the last saved game,
// when you press the F12 key, in the menu of any mode!
void TestFunc_LoadLastSaveGame()
{
    // if the F12 key is not pressed
    if (!zKeyToggled(KEY_F12)            /* || zCMenu::inGameMenu */)
        // exit
        return;

    // otherwise, we get the last save slot (-1 ... 20)
    int lastSlotNr = GetLastSaveGameSlot();

    // display the slot number to the console (for debugging)
    cmd << "\nLastSaveGameSlot = " << lastSlotNr << endl;

    // if no saves are found
    if (lastSlotNr < 0)
    {
        // report this to the console
        cmd << "Saves not found -> Exit!" <<endl;

        // and exit
        return;
    }

    // otherwise, we get a pointer to the active menu
    zCMenu* menu = zCMenu::GetActive();

    // if the menu is open
    if (menu)
        // close it
        menu->HandleEvent(KEY_ESCAPE);

    // and finally load the game in the specified slot
    gameMan->Read_Savegame(lastSlotNr);
}





// Set focus to the last save,
// when pressing the F12 key, only in main menu mode
void TestFunc_SetFocusToLastSaveGame()
{
    // focus flag on the last save (1 - on, 0 - off)
    static BOOL bUseQuickFocus = FALSE;


    /********************/
    //  Execution block
    /********************/
    // if focusing on the last save is started
    if (bUseQuickFocus == TRUE)
    {
        // trying to get a pointer to the save loading menu
        zCMenu* menuLoadSaveGame = zCMenu::GetByName("MENU_SAVEGAME_LOAD");

        // if the pointer is received
        if (menuLoadSaveGame)
        {
            // get the last save slot
            // (after preliminary check, it will already be from 1 to 15)
            int lastSlotNr = GetLastSaveGameSlot();

            // set focus to the selected slot (this is safe, because access to the element has been pre-evaluated)
            menuLoadSaveGame->SetActiveItem(menuLoadSaveGame->m_listItems[lastSlotNr + 8]);

            // simulate focus switching back and forth
            // to update the save information of the selected item
            menuLoadSaveGame->HandleEvent(KEY_UP);
            menuLoadSaveGame->HandleEvent(KEY_DOWN);


            /*******************************/
            // Start a save (if required)
            /*******************************/
            // simulate pressing the "Enter" key
            // menuLoadSaveGame->HandleEvent(KEY_RETURN);
        }

        // focus attempt used,
        // so we reset the flag
        bUseQuickFocus = FALSE;

        // and exit the function
        return;
    }




    /****************************/
    //  Block issuing the task
    /****************************/
    // if the F12 key is not pressed OR the menu is already called in the game OR the focusing process is already running
    if (!zKeyToggled(KEY_F12) || zCMenu::inGameMenu || bUseQuickFocus == TRUE)
        // exit
        return;

    // (for debugging)
    cmd << "\nF12" << endl;

    // otherwise, we try to get a pointer to the main menu
    zCMenu* menuMain = zCMenu::GetByName("MENU_MAIN");

    // and menu element for loading saves
    zCMenuItem* menuItemLoadSaveGame = zCMenuItem::GetByName("MENUITEM_MAIN_SAVEGAME_LOAD");

    // if pointers are not received
    if (!menuMain || !menuItemLoadSaveGame)
        // exit the function
        return;

    // otherwise, we get the last save slot (-1 ... 20)
    int lastSlotNr = GetLastSaveGameSlot();

    // if there are no saves or there are, but only "quick save"
    if (lastSlotNr < 1) // (-1, 0)
    {
        // error comment
        string comment = "";

        // if the last save is 'quick save'
        if (lastSlotNr == 0)
            comment = ", is quick save.";
        else // otherwise, no save files are found in the range from (1 to 20)
            comment = ", saved files not found.";


        // Can't set focus to last save!
        cmd << string::Combine("Can not set focus on your last save game! (lastSlotNr = '%i')%s", lastSlotNr, comment) << endl;

        // exit the function, because The "Archolos" mod does not have a 'quick save' item in the save loading menu
        return;
    }

    // otherwise, we try to get a pointer to the save loading menu
    zCMenu* menuLoadSaveGame = zCMenu::GetByName("MENU_SAVEGAME_LOAD");

    // if the pointer is received
    if (menuLoadSaveGame)
    {
        // calculate the index of the selected element in this menu
        lastSlotNr += 8;

        // get the number of items in the save loading menu
        int numItems = menuLoadSaveGame->m_listItems.GetNum();

        // if the index of the selected element is beyond the lower or upper limit of the array
        if ((lastSlotNr < 0) || (lastSlotNr > numItems - 1))
        {
            // warn about this
            cmd << string::Combine("Element %i/%i is out of range!", lastSlotNr, numItems) << endl;

            // and exit the function
            return;
        }

        // otherwise, take the intended focus element in the save loading menu
        zCMenuItem* focusItem = menuLoadSaveGame->m_listItems[lastSlotNr];

        // if the internal name of the element does not contain the keyword "SLOT"
        if (!focusItem->GetName().HasWordI("SLOT"))
        {
            // print a warning that the intended focus element is not what we want
            cmd << string::Combine("Element '%z' is not menu item slot", focusItem->GetName()) << endl;

            // exit
            return;
        }
    }


    // otherwise, launch the save loading menu
    menuMain->ForceSelAction(SEL_ACTION_STARTMENU, "MENU_SAVEGAME_LOAD", menuItemLoadSaveGame);

    // and allow focus to be controlled in this menu
    // (but already in the next iteration of the menu cycle, in which we will get to the 'Execution block')
    bUseQuickFocus = TRUE;
}


// Loop while menu rendering
void Game_MenuLoop()
{
    // Call test 1
    // TestFunc_LoadLastSaveGame();

    // Or call test 2
    TestFunc_SetFocusToLastSaveGame();
}


// some base and your funcs ...


} /* end of namespace */
[Google translate]


Enable menu loop func:
UseMenuLoopFunc.jpg


And in my opinion, in the 'Archolos' mod, in the loading menu, there is no choice of a quick save slot (maximum 15 slots). So the idea of simulating switching to a specific slot is not suitable in this case.
ListItemsOf_MENU_SAVEGAME_LOAD.jpg


To see messages in the console, enable the option in the "SystemPack.ini" file:
INI:
[CORE]
ShowDebugWindow = true
 
Последнее редактирование:

Xeдин


Модостроитель
Регистрация
3 Дек 2008
Сообщения
1.450
Благодарности
1.977
Баллы
365

Myszax

Участник форума
Регистрация
12 Май 2022
Сообщения
11
Благодарности
2
Баллы
40
Try something like this:
C++:
namespace NAMESPACE
{
    Sub inMenu(ZSUB(GameEvent::MenuLoop), []
        {
            if (zCMenu* menu = zCMenu::GetActive())
                if (!menu->inGameMenu)
                    if (zKeyToggled(KEY_F12))
                    {
                        menu->m_exitState = zCMenu::BACK;
                       
                        for (zCMenu* subMenu : menu->menuList)
                            if (oCMenuSavegame* saveMenu = dynamic_cast<oCMenuSavegame*>(subMenu))
                                saveMenu->m_selSlot = 6;

                        gameMan->Read_Savegame(6);
                    }
        });
}
I don't understand ZSUB or Sub in your code but you fixed my problem :D
I abandoned solution with ForceSelAction because it was not needed.
The key thing that I was missing was to set m_selSlot on saveMenu. When I did this there are no more errors and game is loading perfectly :)
It could be even simplified by removing for loop since pointer to menu_load_savegame exist in gameMan.

C++:
namespace NAMESPACE

{

    Sub inMenu(ZSUB(GameEvent::MenuLoop), []

        {

            if (zCMenu* menu = zCMenu::GetActive())

                if (!menu->inGameMenu)

                    if (zKeyToggled(KEY_F12))

                    {

                        menu->m_exitState = zCMenu::BACK;
                        gameMan->menu_load_savegame->m_selSlot = 6;
                        gameMan->Read_Savegame(6);

                    }

        });

}


Jr13San, thanks for your effort. It works too but only if game supports useQuickSaveKeys which Gothic 1 or TCoM doesn't.

Xeдин, it seems that Union_SaveLoadManager does not support loading save straight from main menu.



I have another question.
I am looking for solution to close all active menus.
I tried something like:
C++:
for (int i = zCMenu::activeList.GetNum()-1; i > 0; i--)
{
    auto item = zCMenu::activeList[i];
    item->HandleEvent(KEY_ESCAPE);
}
or use ForceSelAction with BACK option on first item in menu, but no positive outcome.
zCMenu::GetActive() is also not works, it is not updating right after menu is closed.
 

Myszax

Участник форума
Регистрация
12 Май 2022
Сообщения
11
Благодарности
2
Баллы
40
Slavemaster, Sure it's SEL_ACTION_BACK I just did not remeber it when writing my post :p

As I said I want to close all active menus by pressing single hotkey (eg. F12) without MENU_MAIN (so thats why i > 0) then set zCMenu::activeList[0]->m_exitState = zCMenu::BACK; after loop.

I've tried this three options, combined together or not.
C++:
for (int i = zCMenu::activeList.GetNum() - 1; i > 0; i--) {
    auto item = zCMenu::activeList[i];

    // item->HandleEvent(KEY_ESCAPE);                                   // option 1
    // item->m_exitState = zCMenu::BACK;                                // option 2
    // item->ForceSelAction(SEL_ACTION_BACK, "", item->m_listItems[0]); // option 3
}
zCMenu::activeList[0]->m_exitState = zCMenu::BACK;
Still got the same problem. It is only exiting single menu, which wast opended most recently.
To reproduce this: Open game; then enter Options; then enter Game/Graphics/Sound whatever options; then press F12 and you will see that it will only close Game/Graphics/Sound options and back to Options menu (not Main Menu).
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.083
Благодарности
1.901
Баллы
320
Myszax, you can hook zCMenu::Run to keep the actual list of active menus.
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
I want to close all active menus by pressing single hotkey (eg. F12)
C++:
void Game_MenuLoop()
{
    static BOOL bCloseAllMenuToMain = FALSE;

    if (zKeyToggled(KEY_F12))
    {
        // if proc not active
        if (!bCloseAllMenuToMain)
            // activate "close menu process"
            bCloseAllMenuToMain = TRUE;
    }

    // if "close menu process" is active
    if (bCloseAllMenuToMain == TRUE)
    {
        // get active menu
        zCMenu* activeMenu = zCMenu::GetActive();
       
        // if main menu is not active
        if (activeMenu && activeMenu->GetName() != "MENU_MAIN")
        {
            // call exit for current menu
            activeMenu->m_exitState = zCMenu::BACK;

            // debug msg
            cmd << "Close menu '" << activeMenu->GetName() << "'" << endl;
        }
        else
        {
            // stop "close menu process"
            bCloseAllMenuToMain = FALSE;

            // and start load save game process...
            cmd << "Load save game..." << endl;
        }
    }
}
 
Последнее редактирование:

Myszax

Участник форума
Регистрация
12 Май 2022
Сообщения
11
Благодарности
2
Баллы
40
Slavemaster, I want to close them :p So why hook to zCMenu::Run?
Jr13San, I was looking for other way to do it, but thanks :) You helped me. I managed to use Game_MenuLoop() and did what I wanted to do :]
Btw. even in New Balance if you load game from options menu then game will load but main menu will still be visible until you spam ESC to close it.
 

DAMROCK

Участник форума
Регистрация
23 Янв 2017
Сообщения
22
Благодарности
5
Баллы
160
Я хочу попробовать добавить серебро в экономику, возникшие проблемы: 1) жёсткая привязка обменной валюты к C_ITEM, не могу понять какую функцию хукать. 2) нужно добавить в инвентарь строку кол-ва серебра, проблема заключается в том, что отрисовка текста надписи при рендере происходит раньше наложения рамки и в итоге текст выходит тёмный. 3) не понимаю какие функции соотносятся к отображению инвентаря игрока, а какие торговые и контейнера. P.S. для меня инвентарь это какая-то дремучая штуковина и если есть какие-нибудь исходники с его работой, или более полная инфа по работе с ним, было бы просто шикарно.
 

MEG@VOLT

★★★★★★★★★
ТехАдмин
Регистрация
24 Мар 2006
Сообщения
9.862
Благодарности
6.742
Баллы
1.625

SuperDave500

Участник форума
Регистрация
26 Янв 2021
Сообщения
97
Благодарности
32
Баллы
75
Я не знаю, правильно ли это место спрашивать. Я спрашиваю из любопытства. Почти во всех современных MMO панели быстрого доступа и другие элементы пользовательского интерфейса можно настроить так, чтобы они имели прозрачность от 0% до 100%, которую можно регулировать с помощью ползунка или числового процента. Возможно ли такое сделать в моддинге Готики? Если да, то будет ли разработчику мода очень сложно сделать такое? Существует множество модов, добавляющих новые элементы пользовательского интерфейса, которые могут получить от этого пользу.
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Почти во всех современных MMO панели быстрого доступа и другие элементы пользовательского интерфейса можно настроить так, чтобы они имели прозрачность от 0% до 100%, которую можно регулировать с помощью ползунка или числового процента. Возможно ли такое сделать в моддинге Готики?
Да, возможно.

Если да, то будет ли разработчику мода очень сложно сделать такое?
Нейросетка пишет, что всё зависит от конкретной задачи и навыков самого разработчика.
1) Если нужна статическая прозрачность (без возможности регулировки), то можно попробовать настроить альфа-канал у выбранных текстур.
Но иногда, одна и та же текстура может использоваться в разных местах, и изменение прозрачности повлияет на все места её применения.

2) Если нужна регулируемая прозрачность, или если существует какая-то специфическая или сложная задача, то придётся прибегнуть к С++ и Union API.
 

SuperDave500

Участник форума
Регистрация
26 Янв 2021
Сообщения
97
Благодарности
32
Баллы
75
У меня есть несколько модов, которые меняют только изображение меню, диалоговых окон и т.п. Моды содержат только файлы .Tex (без скриптов). Я извлек содержимое всех модов в один и тот же каталог (_WORK\DATA\TEXTURES\_COMPILED\). Затем я использовал GothicVDFS для создания нового тома. Я использовал корневой каталог \_WORK. Мод стал .mod. Я переименовал его в .vdf. Я поместил его в /Gothic 2/Data. Мод вообще не работает. Что я делаю не так?
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.131
Благодарности
5.627
Баллы
910
TImeShamp должен быть большим (например 2039 год)

Ну и проверить полученную иерархию папок в vdf файле надо. Просто открыть свой файл и сравнить с оригинальным textures.vdf например.
 

SuperDave500

Участник форума
Регистрация
26 Янв 2021
Сообщения
97
Благодарности
32
Баллы
75
TImeShamp должен быть большим (например 2039 год)

Ну и проверить полученную иерархию папок в vdf файле надо. Просто открыть свой файл и сравнить с оригинальным textures.vdf например.


Есть ли письменное руководство, показывающее, как шаг за шагом создать файл .vdf с помощью GothicVDFS? Это не может быть видео, мне нужно его перевести.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.131
Благодарности
5.627
Баллы
910

MW 7


Модостроитель
Регистрация
26 Мар 2004
Сообщения
2.003
Благодарности
971
Баллы
295
Всем привет! а как в формате .patch получить путь к каталогу с игрой?
 
Сверху Снизу