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

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

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.432
Благодарности
4.771
Баллы
625
  • Первое сообщение
  • #1
1767600363729.png

RU EN

 

Вложения

  • Union_Primary_Universal 12.02.2022.zip
    44 MB · Просмотры: 28.433
  • Union 1.0m 26.06.2022.zip
    11,8 MB · Просмотры: 977
  • Union 1.0m 26.06.2022 v2.zip
    11,8 MB · Просмотры: 627
  • Union 1.0m 26.06.2022 v3.zip
    11,8 MB · Просмотры: 30.733

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.432
Благодарности
4.771
Баллы
625
А значит, можно отправить в топку пирог из оверлеев. И сделать отдельную ветку прокачки только топоров. Я за то, чтобы каждый тип имел свой блок анимаций в mds скриптах.
Ну определись какие блоки нужны, отсюда будет понятно хватит ли резерва. Если нет, то можно сразу смотреть в сторону динамики - указываешь двуручное или одноручное оружие и какую приставку блока должно использовать. Типа так.
Daedalus:
instance ITMW_AssCutter(C_ITEM)
{
    ...
    SetFightScheme("2HA", "ZS_LongAxe"); // какой блок использовать, в какой слот помещать
};
 

MaGoth

★★★★★★★★★★★
Администратор
Регистрация
7 Янв 2003
Сообщения
19.377
Благодарности
7.861
Баллы
995

Pag

Участник форума
Регистрация
7 Ноя 2013
Сообщения
100
Благодарности
62
Баллы
180
У меня на Юнионе странная проблема с колесиком мыши, оно листает вверх/вниз на 2 пункта, например в инвентаре листает сразу на два предмета, то же самое в любых меню, диалогах итд. Раньше никогда такого не было. Из плагинов использую только квиклут/квиксейв от Ликера (тот который можно поставить в самом Юнионе не работал :confused:), и еще дх11.
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.432
Благодарности
4.771
Баллы
625
Pag, опрос мышки происходит 1 раз в кадр. Я бы на твоем месте для начала удостоверился, что в ее работу не лезет сам DX11 и все ли ок с настройками самой мыши.
Также можешь пошариться в настройках SystemPack.ini и найти там раздел Mouse. В твоем случае (возможно) может помочь отключение параметра EnableWrapper:
1605638216227.png
 

Pag

Участник форума
Регистрация
7 Ноя 2013
Сообщения
100
Благодарности
62
Баллы
180
Gratt, EnableWrapper пофиксил проблему, благодарю!
 

alexeich2019

Участник форума
Регистрация
28 Июн 2019
Сообщения
191
Благодарности
73
Баллы
175
Подскажите, как реализовать запрет автопропуск диалога, после завершения звуковой дорожки. Чтобы игрок сам пропускал диалог, нажимая Esc или правую клавишу мыши, стандартными клавишами, в общем.
Вещь не всем нужная, но тем, кто играет в иностранные моды и не совсем понимает иностранную речь - актуальная. Но как реализовать ее в коде - не соображу.
 

Goth_Man

Участник форума
Регистрация
27 Окт 2014
Сообщения
196
Благодарности
33
Баллы
190
Вещь не всем нужная
Мне вот такое было нужно поскольку не успевал читать диалоги, поэтому по моей просьбе MaGoth добавил параметр (название его не помню давно выставил и забыл) в SP на который домножается время показа диалога рассчитанное системой, пользуюсь им (поставил увеличить в 20 раз) хоть он и глючит в катсценах (играл в какой то мод название не помню) из за того что там, там как раз заблокирован его сброс и когда сцена уже давно закончена диалоги ещё долго вылазят.
 

N1kX

Участник форума
Регистрация
13 Ноя 2009
Сообщения
6.590
Благодарности
6.199
Баллы
940
А зайти и прочитать в тему? :)
MaxTimePerPhrase=30.0 ; ... максимальное время в секундах для отображения субтитров без файла озвучки.
TimePerChar=100.0 ; ... время в миллисекундах для отображения одного символа субтитров без файла озвученного диалога. Например, при значении TimePerChar=200.0, фраза: "Ты можешь научить меня сражаться?" содержит 33 символа, ; значит отображаться она будет 33*200/1000=6.6 секунд.

Так что меняем параметры на очень большие и скипаем диалоги вручную, но не относится к модам, где есть озвучка.
Возможно это идея для плагина (Если существует озвучка), но не для самой платформы.
 
Последнее редактирование:

Goth_Man

Участник форума
Регистрация
27 Окт 2014
Сообщения
196
Благодарности
33
Баллы
190
А зайти и прочитать в тему
Так пусть тот кому нужно название сам ищет, главное придать направление.
но не относится к модам, где есть озвучка
Походу я отстал от жизни, мне припоминалось что вроде на озвучу пофиг, правда у меня до сих пор тестовая версия SP может в ней что по другому
 

N1kX

Участник форума
Регистрация
13 Ноя 2009
Сообщения
6.590
Благодарности
6.199
Баллы
940
Так пусть тот кому нужно название сам ищет, главное придать направление.

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

Я проверил и звуковой файл перекрывает любые настройки, движок сразу же закончит диалог, как заканчивается звуковой файл.
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.147
Благодарности
2.021
Баллы
320

N1kX

Участник форума
Регистрация
13 Ноя 2009
Сообщения
6.590
Благодарности
6.199
Баллы
940
Так пробовал?

Код:
[SUBTITLES]
Control = 1
TimeMultiplier = 20

Ну, только значение ставить овердохренашное
Например
TimeMultiplier = 10000.0
Потому что при включенном управлении субтитрами, файлы без озвучки становятся зависимыми от TimeMultiplier, а не от MaxTimePerPhrase и TimePerChar
При TimeMultiplier = 20 скипаются очень быстро, при TimeMultiplier = 200, чуть медленее, но быстро, TimeMultiplier = 2000 уже хорошо, но длинные диалоги не успел прочитать
TimeMultiplier > 10000 позволяет полностью контролировать процесс.

Но мне кажется, что посыл был в том, чтобы игрок сам прожимал пропустить диалог, а не игра это делала, даже спустя час ожидания.
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.147
Благодарности
2.021
Баллы
320
как реализовать запрет автопропуск диалога
НПС, произносящий диалоговую реплику, обрабатывает событие oCMsgConversation с подтипом EV_PLAYANISOUND.
Основная обработка события происходит в методе oCNpc::EV_PlaySound:
- реплика прекращается по истечении таймера stop = (csg->f_no <= 0), который устанавливается при первом вызове метода !csg->IsInUse()
- изначальное значение таймера передается во вьюшку вызовом zCView::DialogMessageCXY
- когда значение таймера становится <= 500, НПС завершает все говорильные анимации

Соответственно, чтобы предотвратить автоматическую смену диалогов нужно исправить условие окончания реплики и в вызовах zCView::DialogMessageCXY передавать достаточно большое значение времени. Но есть некоторый нюансы:
- баг в oCNpc::Output_SVM и oCNpc::Output_SVM_Overlay: используется вызов oCNpc::StartTalkingWith вместо oCNpc::SetTalkingWith. Из-за этого, если во время диалоговой реплики в сторону ГГ кто-либо произнесёт внедиалоговую реплику, то диалоговую реплику пропустить уже не получится (игра будет считать, что ГГ ведет диалог с тем, кто кинул реплику). Возможно, будет допустимым просто убрать эти вызовы.
- в oCNpc::StopRunnngOU не должны обрабатываться удалённые сообщения csg->IsDeleted()
- в oCNpc::StopRunnngOU не должен прерываться звук и закрываться вьюшки для неинициализированных сообщений csg->IsInUse() == false
- в oCNpc::StopRunnngOU должна закрываться только одна вьюшка, индекс которой хранится в csg->f_yes
- значение csg->f_yes перезаписывается при каждом вызове метода oCNpc::EV_PlaySound (этот оператор нужно убрать)

Всё это, в идеале, должно делаться с помощью патч-файла.
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.432
Благодарности
4.771
Баллы
625
Ну вот например. Движок будет скипать фразу лишь спустя StaticTalkTime, если включен параметр StaticTalkTimeEnabled. Параметры появятся после первого запуска спатчем в sp ini. По умолчанию время пропуска равно 600000мс = 10мин. Проверил на г1, на вторую скопировал, но не проверял. Напишете если чё.

Но есть некоторый нюансы:
Это про всякие 'Эй ты' и подобные? Щас пока не могу их проверить. Если, как ты говоришь, пираньи перепутали функции, то никто не мешает вызвать другую функцию тем же патчем
 

Вложения

  • TalkTime.7z
    525 байт · Просмотры: 26
Последнее редактирование:

Raven25

Участник форума
Регистрация
18 Дек 2018
Сообщения
187
Благодарности
79
Баллы
190
Здравья! Есть вопрос, как в коде понять то что мы копаемся в чужом инвентаре (при воровстве, при оберании мёртвого, при торговле)
Пост автоматически объединён:

Просто есть такая вот проблема, при попытке достать предмет из инвентаря труппа\торговца\при воровсте плагин перехватывает комбинацию клавиш (ctrl и стрелка в право)
Пост автоматически объединён:

Вот код

C++:
// Supported with union (c) 2020 Union team
// Union SOURCE file

namespace GOTHIC_ENGINE {
    // Add your code here . . .

#define KeyClick(a) zinput->KeyToggled(a)
#define KeyPress(a) zinput->KeyPressed(a)
    int playerWantsToThrow = 0;

    void oCNpc::DoThrowItem( zCVob * pItem, float force ) {
        if ( !pItem )
            return;

        // кидаем
        DoThrowVob( pItem, force );
        // т.к. в функции oCAIVobMove::Init force(мощность) броска обрезается в 1, нам нужно сделать это вручную.
        // берем матрицу и вычисляем угол
        zMAT4 matrix = trafoObjToWorld;
        zMAT4 trafo = matrix * Alg_Rotation3DN( zVEC3( 1, 0, 0 ), -20 );
        // берем направление
        zVEC3     direction = trafo.GetAtVector();
        // задаем мощность броска, в данном случае стоит 1000
        pItem->GetRigidBody()->SetVelocity( direction * force );
    }

    void oCNpc::AI_PlayAni( zSTRING ani ) {
        oCMsgConversation* pConv = new oCMsgConversation( oCMsgConversation::EV_PLAYANI_NOOVERLAY, ani );
        pConv->number = 0;
        this->GetEM( FALSE )->OnMessage( pConv, this );
    }

    void ThrowLoop() {
        if ( playerWantsToThrow ) {
            // если герой вошел в любой боевой режим, вещь из правой руки автоматом выпадает, режи броска отключается.
            if ( player->fmode != NPC_WEAPON_NONE ) {
                playerWantsToThrow = FALSE;
                return;
            }

            // герой хочет чего-то там бросить и инвентарь закрыт
            if ( !player->inventory2.IsOpen() ) {
                zCModel* pModel = player->GetModel();
                // если зажата правая клавиша мыши, то стартуем аниму прицеливания
                if ( zinput->GetState( zLOGICKEY_ACTION ) ) {
                    if ( pModel ) {
                        if ( !pModel->IsAnimationActive( "S_IAIM" ) ) {
                            player->AI_PlayAni( "T_STAND_2_IAIM" );
                            player->AI_PlayAni( "S_IAIM" );
                        }
                    }
                }

                // если гг целится и правая кнопка мыши не зажата, включаем аниму перехода с прицеливания на STAND
                if ( playerWantsToThrow == 1 && !zinput->GetState( zLOGICKEY_ACTION ) && pModel->IsAnimationActive( "S_IAIM" ) ) {
                    if ( pModel->IsAnimationActive( "S_IAIM" ) ) {
                        player->GetEM( FALSE )->Clear();
                        player->AI_PlayAni( "T_IAIM_2_STAND" );
                    }
                }

                // если гг целится и игрок нажимает левую кнопку мыши, начинаем анимацию броска
                if ( playerWantsToThrow == 1 && zinput->GetState( zLOGICKEY_UP ) && pModel->IsAnimationActive( "S_IAIM" ) ) {
                    player->GetEM( FALSE )->Clear();
                    player->AI_PlayAni( "T_IAIM_2_ITHROW" );
                    playerWantsToThrow = 2;
                }

                // разрешение вертеть персонажем во время прицеливания
                if ( pModel->IsAnimationActive( "S_IAIM" ) || pModel->IsAnimationActive( "S_ITHROW" ) ) {
                    player->human_ai->PC_Turnings( 1 );
                }

                // если герой начал анимацию броска и дошел до нужной стадии,
                // бросаем вещь и активируем анимацию перехода в спокойное состояние, отключаем режим броска
                if ( playerWantsToThrow == 2 && pModel->IsAnimationActive( "S_ITHROW" ) ) {
                    player->GetEM( FALSE )->Clear();
                    player->DoThrowItem( player->GetRightHand(), 1000 );
                    player->AI_PlayAni( "T_ITHROW_2_STAND" );

                    playerWantsToThrow = 0;
                }
            }
        }


        if (player->inventory2.IsOpen()) {
            if (zinput->GetState(zLOGICKEY_ACTION) && zinput->KeyToggled(KEY_RIGHT)) {
                oCItem* newItem = player->inventory2.GetSelectedItem();
                if (newItem) {
                    zinput->ClearKeyBuffer();
                    // закрываем инвентарь
                    player->CloseInventory();
                    // забираем одну вещь(если их много, чтобы все не выкидывать)
                    newItem = player->RemoveFromInv(newItem->GetInstance(), 1);

                    if (newItem) {
                        // кладем вещь в слот правой руки
                        player->PutInSlot("ZS_RIGHTHAND", newItem, FALSE);
                        playerWantsToThrow = TRUE;
                    }
                }
            }
        } //IsOpen
    }
}
 
Последнее редактирование:

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.147
Благодарности
2.021
Баллы
320
Есть вопрос, как в коде понять то что мы копаемся в чужом инвентаре (при воровстве, при оберании мёртвого, при торговле)
Посмотреть все открытые контейнеры в oCItemContainer::contList

oCNpc::game_mode флаг указывающий текущий режим инвентарчяЧ: enum { NPC_GAME_NORMAL, NPC_GAME_PLUNDER, NPC_GAME_STEAL };(нормал - гг смотри свой инвентераь.. пландер - обыскивает труп, стил - ворует
 
Последнее редактирование модератором:

Trazege

Участник форума
Регистрация
20 Фев 2008
Сообщения
1.760
Благодарности
1.394
Баллы
340
Кто знает, как удалить директорию из под игры...путь получаю правильный, но не очень понятен принцип работы DirRemove для класса zFILE_FILE?
Кроме этого не ясно, как теперь перевести готический стринг в const wchar_t* для использования _wrmdir. В родном коде используется обычная команда rmdir которую убрали и которая работала с обычном стрингом с преобразованием в char. Порылся в инете - примеры есть но они работают с каким то своим стрингом ) не настолько силен в плюсах.
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.147
Благодарности
2.021
Баллы
320
не очень понятен принцип работы DirRemove для класса zFILE_FILE
Удаляет только пустые директории, видимо.
Кроме этого не ясно, как теперь перевести готический стринг в const wchar_t* для использования _wrmdir.
Смысла нет, так как есть функция _rmdir, которая принимает char*. Плюс эти функции тоже только пустые директории удаляют.

Кто знает, как удалить директорию из под игры...
Как вариант:
C++:
bool DeleteDir(const char* path)
{
    size_t length = strlen(path);
    char* buffer = new char[length + 2];
    strcpy(buffer, path);
    buffer[length + 1] = 0;

    SHFILEOPSTRUCTA op;
    ZeroMemory(&op, sizeof(op));
    op.pFrom = buffer;
    op.wFunc = FO_DELETE;
    op.fFlags = FOF_NO_UI;

    int result = SHFileOperationA(&op);
    delete[] buffer;

    return result == 0;
}
 

Trazege

Участник форума
Регистрация
20 Фев 2008
Сообщения
1.760
Благодарности
1.394
Баллы
340
Удаляет только пустые директории, видимо.

Так в том то и дело, не ясно как задавать папку для удаления. Я покопался в коде там идет привязка как раз на функцию _rmdir, которую не нашел :)

Смысла нет, так как есть функция _rmdir, которая принимает char*. Плюс эти функции тоже только пустые директории удаляют.

Подскажешь, как ее вызвать? я вижу только функцию _wrmdir. и она работает как раз с const wchar_t*.

Спасибо, все удалилось. Теперь только осталось понять как сделать реиницилизацию списка в меню загрузки сейвов, чтобы он перестал видеть удаленную запись
 
Последнее редактирование:

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.147
Благодарности
2.021
Баллы
320
Я покопался в коде там идет привязка как раз на функцию _rmdir, которую не нашел
C++:
#include <direct.h>
Но эта функция удаляет только пустые директории.
А твой пример удалит папку с вложенными файлами?
Да.
Так в том то и дело, не ясно как задавать папку для удаления.
Путь до файла/папки в конструктор zFILE_FILE передаётся.
 
Сверху Снизу