Войти на сайт Регистрация Лента форума Пользователи Правила сайта Поиск по форуму
Модератор форума: denis2000, FantomICW  
Форум » Моды для игр » Модостроение » Модостроение. Создание и редактирование квестов
Модостроение. Создание и редактирование квестов
denis2000Дата: Пн, 10.10.2011, 21:25 | Сообщение # 1
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Создание и редактирование квестов

Создание новых квестов и редактирование существующих

Если у вас появились вопросы по созданию и редактированию квестов, изменению существующих и добавлению новых в игру. Задавайте их в этой теме - умные головы,
модосторители и просто разбирающиеся в программировании люди вам ответят.


Много интересного материала здесь (wiki), Lua_help.script, Help из SDK 0.7

Сборник модостроения ЗП v10.10.11 (автор: XOBAH): *.CHM, *.HTML
[cut noguest=Если у вас не открывается файл CHM]Если у вас не открывается файл:
1. Запустите [Пуск]=>[Выполнить] (либо хот-кей [WIN]+[R])
2. Введите команду (без кавычек) "regsvr32 %windir%\system32\hhctrl.ocx"
3. Если вылезло окно об успешном завершении вы все сделали правильно и можете перезагружать компьютер (а может и не надо)
Также: файлы МОГУТ не открываться если в пути к файлу есть: символы кириллицы, "_", "#"
Также: есть не стандартные программы-просмоторщики CHM файлов. Например: FBReader[/cut]

[cut=Где найти лог игры после вылета]Что такое LOG ошибки, и как мне его найти?
Это система отладки происходивших вылетов, которая подается игрой в форме текста, хотя не всегда.
Для того чтоб найти LOG необходимо зайти вот сюда:

В Win хр лог находится:

C:\Documents and Settings\All Users\Документы\S.T.A.L.K.E.R. - Зов Припяти\logs

Затем открываете первый файл в формате TXT, и в нем отбираете с низу 25 строчек. После кидаете эти 25 строчек в сообщение на форум.

В Win7 лог находится C:\Users\Public\Documents\S.T.A.L.K.E.R. - Зов Припяти\logs

Путь к папке с логом можно найти открыв файл fsgame.ltx который находится в корневой директории ЗП, за это отвечает строка:
...
$app_data_root$ = true | false| $fs_root$| users\
(тут мы указываем что папка пользователя, будет хранится рядом с Fsgame.ltx)
...
$logs$ = true| false| $app_data_root$| logs\
(а тут мы указываем что в папке пользователя, в подпапке Logs будут храниться наши логи)
...
[/cut][cut=Получение более подробной информации о вылете (ХОВАН)]
Открываем файл _g.script и ищем такую функцию: function abort(fmt, ...)
Там есть заккомментированная строчка "--error_log(reason)", ее и надо расскомментировать, должно получиться вот так:
Code
function abort(fmt, ...)
                       local reason = string.format(fmt, ...)
                       error_log(reason)
end

Вот для примера два одинаковых вылета, первый с функцией по умолчанию, второй - с поправленной функцией

Первый:
Code
Expression    : !m_error_code
Function      : raii_guard::~raii_guard
File          : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp
Line          : 748
Description   : ....a.l.k.e.r. - Зов Припяти\gamedata\scripts\_g.script:478: bad argument #2 to 'format' (string expected, got nil)

Второй:
Code
Expression    : 0
Function      : ErrorLog
File          : D:\prog_repository\sources\trunk\xrServerEntities\script_engine_script.cpp
Line          : 49
Description   : 'Attempt to read a non-existant string field 'path_walk' in section 'walker@mechanic'

[/cut]


Перед тем, как задать вопрос в этой теме, прочтите все предыдущие страницы,
статьи в wiki по ссылке из шапки и соседнюю тему "Курс молодого бойца",
возможно Ваш вопрос уже рассматривался.


Если произошел вылет - выкладываем лог! Вопрос ставим четко, не забываем указывать версию игры, установленные моды их версии, установленные фиксы модов и подробно ваши правки.
Помните чем подробнее вопрос, тем точнее ответ.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
NIVДата: Ср, 25.09.2013, 12:59 | Сообщение # 151
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

Коллеги, как вы считаете, можно ли в ЗП вернуть в ПДА некоторые функции из ПДА ТЧ, а именно: 1) добавить страничку "проваленные задания" (всего-то нарисовать новый элемент GUI) и 2) вернуть таймер на задания, типа "осталось 16 часов до провала"; 3) и др. - "Энциклопедия" и т.п. ? А может, в каком-то моде это уже реализовано?

Добавлено (25.09.2013, 12:59)
---------------------------------------------
Volk66, здесь, конечно не очень хороший поиск, тогда юзай "расширенный поиск" Яндекса по этому форуму. И всё найдется, например, сообщения 206 - 207.


Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"
 
denis2000Дата: Вт, 01.10.2013, 09:13 | Сообщение # 152
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата (NIV)
Коллеги, как вы считаете, можно ли в ЗП вернуть в ПДА некоторые функции из ПДА ТЧ

Теоритически это вполне возможно, есть ли мод с такой реализацией в свободном доступе - не знаю, сам поищи.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
NIVДата: Сб, 05.10.2013, 22:29 | Сообщение # 153
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

Попробовал вместо таймера в ПДА сделать таймер на экране через sr_timer.script. Но поскольку он управляется из рестриктора, получается забавная вещь: уходишь с локации - таймера нет, возвращаешься - таймер продолжает отсчет. А хотелось бы, чтобы и на другой локации таймер продолжался.
Как можно считать остаток времени и передать его в качестве параметра рестриктору на новой локации?


Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"
 
FantomICWДата: Сб, 05.10.2013, 23:05 | Сообщение # 154
Лидер «Свободы»
Свобода
Сообщений: 4438
Награды: 44
Репутация: [ 1340 ]

NIV, рекомендую глянуть схему работы армейского таймера в SGM. Там все построено на очень простой форме в XML и скриптами, которые вполне реально разобрать.
[cut=XML-форма]
Код
<!-----[Военный таймер]------>
<army_timer_form x="69" y="518" width="281" height="229">
<texture>ui_mod_timer_main_wnd</texture>
<btn_start x="93" y="81" width="122" height="23">
<texture_e>ui_button_ordinary_e</texture_e>
<texture_t>ui_button_ordinary_t</texture_t>
<texture_h>ui_button_ordinary_h</texture_h>
<text font="letterica16">st_army_timer_start</text>
</btn_start>
<btn_stop x="93" y="115" width="122" height="23">
<texture_e>ui_button_ordinary_e</texture_e>
<texture_t>ui_button_ordinary_t</texture_t>
<texture_h>ui_button_ordinary_h</texture_h>
<text font="letterica16">st_army_timer_reset</text>
</btn_stop>
<btn_close x="93" y="168" width="122" height="23">
<texture_e>ui_button_ordinary_e</texture_e>
<texture_t>ui_button_ordinary_t</texture_t>
<texture_h>ui_button_ordinary_h</texture_h>
<text font="letterica16">st_menu_close</text>
</btn_close>
<timer_value x="115" y="35" width="220" height="16">
<text r="154" g="205" b="50" a="100" align="c" font="letterica16"></text>
</timer_value>
</army_timer_form>
[/cut]
[cut=Скриптовая прорисовка ]
Код
army_timer_value=0
army_timer_deprive=0
army_timer_active=false
class "army_timer" (CUIScriptWnd)
function army_timer:__init(owner) super()
self.owner = owner
self:InitControls()
self:InitCallBacks()
end
function army_timer:__finalize()
end
function army_timer:InitControls()
self:SetWndRect(Frect():set(0,0,1024,768))
local xml = CScriptXmlInit()
xml:ParseFile("ui_mod_elements.xml")
self.army_timer_form=xml:InitStatic("army_timer_form",self)
self:Register(xml:Init3tButton("army_timer_form:btn_start",self.army_timer_form),"btn_start")
self:Register(xml:Init3tButton("army_timer_form:btn_close",self.army_timer_form),"btn_close")
self:Register(xml:Init3tButton("army_timer_form:btn_stop",self.army_timer_form),"btn_stop")
self.timer_value=xml:InitStatic("army_timer_form:timer_value",self.army_timer_form)
end
function army_timer:Update()
CUIScriptWnd.Update(self)
if not object_alive(db.actor) then
self:btn_close()
end
if army_timer_active==true then
army_timer_value=string.format(math.floor(time_global()/1000))-army_timer_deprive
else
if army_timer_value>0 then
army_timer_value=0
end
end
self.timer_value:TextControl():SetText(army_timer_value)
end
function army_timer:InitCallBacks()
self:AddCallback("btn_start",ui_events.BUTTON_CLICKED,self.btn_start,self)
self:AddCallback("btn_stop",ui_events.BUTTON_CLICKED,self.btn_stop,self)
self:AddCallback("btn_close",ui_events.BUTTON_CLICKED,self.btn_close,self)
end
function army_timer:OnKeyboard(dik,keyboard_action)
CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
if dik == DIK_keys.DIK_ESCAPE then
self:btn_close()
end
end
return true
end
function army_timer:btn_start()
army_timer_active=true
army_timer_deprive=string.format(math.floor(time_global()/1000))
end
function army_timer:btn_stop()
army_timer_active=false
end
function army_timer:btn_close()
give_object_to_actor("army_timer")
self:HideDialog()
end
[/cut]





Сообщение отредактировал FantomICW - Сб, 05.10.2013, 23:07
 
NIVДата: Пн, 07.10.2013, 20:24 | Сообщение # 155
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

FantomICW, сам таймер, может быть и не сложный. Сложно все остальное. Сейчас пытаюсь понять идеологию (sgm_loader.script). Там есть менеджер сохранений, менеджер худа и менеджер таймера. И все их надо переносить. Я ничего не упустил?

Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"
 
FantomICWДата: Пн, 07.10.2013, 21:21 | Сообщение # 156
Лидер «Свободы»
Свобода
Сообщений: 4438
Награды: 44
Репутация: [ 1340 ]

NIV, да, есть там некий апдейт таймера. Тебя должна интересовать, в таком случае, строчка
Код
sgm_timers.timers_main()

Скажем так, вероятно, чтобы не впихивать в апдейт bind_stalker.script все SGM-скрипты, Николай вынес их в отдельный файл - sgm_loader.script. Строчки из bind_stalker.script:
Код
--/ SGM in
          if mod_update() then
             sgm_loader.sigerous_mod_main()
          end
          --/ SGM out

А там уже через функцию sigerous_mod_main запускается функция SGM-апдейта.
Выходит, вызов апдейта таймера можно вызвать просто через bind_stalker.script. Логично?
А теперь к самому таймеру. Итак, вызывается функция timers_main из sgm_timers.script, там уже и timers_update. Если важен только армейский таймер, все сокращается:
[cut=Код]
Код
function timers_main()
     timers_update()   
end
function timers_update()   
     --//Таймер армейских часов//-->
     if ui_mod_elements.army_timer_active==true then
        ui_mod_elements.army_timer_value=string.format(math.floor(time_global()/1000))-ui_mod_elements.army_timer_deprive
     else
        if ui_mod_elements.army_timer_value>0 then
           ui_mod_elements.army_timer_value=0
        end
     end
end   
[/cut]
Как-то так. Вроде не сложно?





Сообщение отредактировал FantomICW - Пн, 07.10.2013, 21:22
 
NIVДата: Вт, 08.10.2013, 18:10 | Сообщение # 157
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

Я почти перенес армейский таймер. Там важно использовать еще и менеджер худа (sgm_huds.scripts)(в нем есть такие строки: [cut]
Код
function CHudManager:hud_utils()

if timer.army_timer_active==true then
local data_timer=timer.army_timer_value
add_hud("hud_timer_wnd",data_timer)
else
-- if check_seconds(2) then
release_hud("hud_timer_wnd")
--end
end

(закомментировал уже я)[/cut] Пишу "почти перенес", потому что в SGM многое сделано через флаги , а чтобы перенести их обработку, нужно переносить слишком много функций. Например [cut] в (sgm_huds.scripts) есть переменнаяlocal hud_elements_precond=precond_hud(1). А в _g.script :
Код
function precond_hud(type)
         if type==nil or type==1 then
           return (not db.actor:is_talking()) and object_alive(db.actor) and check_ui_worked(true) and dont_has_alife_info("inventory_wnd_opened") and dont_has_alife_info("sleep_active") and dont_has_alife_info("actor_in_sleep") and dont_has_alife_info("screenshot_mode")

- а это проверки на функциях SGM и инфо оттуда же.
[/cut] Пришлось в тестовых целях убрать эти проверки.

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

P.S. Только что понял - армейский таймер показывает реальное время, а не игровое! Используется time_global(). А мне надо игровое - как перевести?


Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"

Сообщение отредактировал NIV - Вт, 08.10.2013, 20:42
 
FantomICWДата: Вт, 08.10.2013, 18:52 | Сообщение # 158
Лидер «Свободы»
Свобода
Сообщений: 4438
Награды: 44
Репутация: [ 1340 ]

NIV, попробуй еще это (на АМК нашел):
Код
local iTimer
local last
function start_timer_minutes_test(seconds)  
     if last~= nil  then
         iTimer = time_global()+last  --/ взводим таймер на остаток времени last
     else  
         iTimer = time_global() + 7*1000 --/ взводим таймер например 7 сек.
     end  
end

function timer_n_minutes_test() --/ вызывается из ':update' сталкер-биндера
     if iTimer then
         last=iTimer-time_global() -- присваиваем переменной остаток времени до конца работы таймера
         if iTimer < time_global() then  
             iTimer = nil --/ выключаем таймер
             last=nil
             СКРИПТ.ФУНКЦИЯ--/ выполняем действие
         end
     end
end  

-- выводим  значение таймера в обратном отсчете  на худ
function hud_static()  --/ вызывается из ':update' сталкер-биндера
local hud = get_hud()
local st
     if iTimer then  
     st = hud:GetCustomStatic("hud_timer")
         if st==nil then  
             hud:AddCustomStatic("hud_timer", true)  
             st = hud:GetCustomStatic("hud_timer")
         end
         if last~=nil then
             local hours = math.floor(last/3600000)
             local minutes = math.floor(last/60000 - hours*60)
             local seconds = math.floor(last/1000 - hours*3600 - minutes*60)
             local text = string.format("%02d:%02d:%02d",hours,minutes,seconds) -- выводим время в формате 00:00:00
             --local text=string.format("%.f",last/1000)
             st:wnd():SetTextST(text)   
         end  
     else  
         if hud:GetCustomStatic("hud_timer")~=nil then  
             hud:RemoveCustomStatic("hud_timer")
         end
     end
end



 
NIVДата: Сб, 12.10.2013, 15:26 | Сообщение # 159
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

Возвращаясь к таймерам: Реализовал убывающий таймер на основе армейского из SGM. Отсчёт времени происходит на основе переменных:
Код
niv_quest_timer_start_value=string.format(math.floor(time_global()/1000))  
и
  niv_quest_timer_value=niv_quest_timer_limit_timer_value-(string.format(math.floor(time_global()/1000))-niv_quest_timer_start_value)*11

Таймер работает от реального времени. На 11 умножаем для того, чтобы подогнать это время под игровое. При загрузке сейва, использовании спальника или перехода на другую локацию, таймер продолжает отсчёт, здесь всё нормально.

Но потом возникает проблема с перемоткой времени: например, при переходе между локациями, таймер меняется только на то время, которое проходит по часам компьютера*11, а не на 4 часа, как сдвигается игровое время.

Попробовал вместо time_global() использовать game.time(). При этом получается такой эффект: если ничего не трогать, таймер идёт нормально, но при переходе на другую локацию, от таймера отнимается 4 часа (как и нужно), а когда загружается другая локация, таймер показывает отрицательное время, порядка -11 тыс часов. Либо при сохранении и последующей загрузке таймер также показывает такое отрицательное время.

Я полагаю, что в этом случае либо неправильно сохраняются переменные, либо у них неправильный формат? Если пробовать поменять функцию на game.get_game_time() - то сразу вылет (неправильное использование???)

Требуется помощь: либо как ввести перемотку времени при использовании time_global(), либо как правильно использовать game.time() - подскажите, пожалуйста!


Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"
 
denis2000Дата: Сб, 12.10.2013, 16:35 | Сообщение # 160
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

NIV, Перемотка или установка времени в игре происходит при помощи функций из xr_effects.script (set_game_time и forward_game_time), используйте их для корректировки своего таймера.

"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
NIVДата: Сб, 12.10.2013, 17:17 | Сообщение # 161
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

denis2000, да, forward_game_time используется в рестрикторе левел-чейнджера. Но она меняет только игровое время, а не time_global(). Или я что-то не допонял?

Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"

Сообщение отредактировал NIV - Сб, 12.10.2013, 17:18
 
denis2000Дата: Сб, 12.10.2013, 18:54 | Сообщение # 162
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

NIV,
Если ваш таймер считает реальное время, то не понятно это заявление:
Цитата NIV ()
таймер меняется только на то время, которое проходит по часам компьютера*11, а не на 4 часа, как сдвигается игровое время.

Если ваш таймер считает игровое время, то в моем посте написан ответ на ваш вопрос! Компенсируйте значение вашего таймера в соответствии с игровым временем, измененным указанными функциями.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
NIVДата: Сб, 12.10.2013, 19:39 | Сообщение # 163
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

denis2000, когда в функции таймера используется time_global(), он считает реальное время (т.е. медленно). Чтобы компенсировать это, умножаем разность времени на 11, тогда время, отсчитываемое таймером, почти совпадает с игровым (то, которое показывают часы). Когда происходит переход на другую локацию, игровое время проматывается на 4 ч вперед функцией forward_game_time в спейс-рестрикторе, а таймер успевает уйти только на время, потраченное на загрузку игры (~15-20 минут игровых, 1-2 мин реальных). Вот эту разницу и надо как-то компенсировать.
Если же использовать в таймере функцию game.time() (игровое время), то при смене уровня таймер сначала реагирует на forward_game_time и время переводит, но после загрузки локации показывает сильно отрицательное время. Аналогично и при save/load (см. выше, #159). Так что, по большому счёту, мне не удалось добиться работоспособности таймера на игровом времени.

Добавлено (12.10.2013, 19:39)
---------------------------------------------

Цитата denis2000
нужно изменить окончательно и бесповоротно параметр time_global() или на худой конец game.time()?
Даже не знаю, не будешь же часы у компьютера переводить? Может, лучше из niv_quest_timer_limit_timer_value вычесть поправку?
Идеально было бы заставить работать таймер через game.time() или что-то наподобие. Не пойму, почему там не получается.


Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"

Сообщение отредактировал NIV - Сб, 12.10.2013, 19:16
 
denis2000Дата: Сб, 12.10.2013, 19:47 | Сообщение # 164
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата NIV ()
Может, лучше из niv_quest_timer_limit_timer_value вычесть поправку?

Вот это я и хотел от вас услышать! Что-то типа такого:
Код
niv_quest_timer_limit_timer_value = niv_quest_timer_limit_timer_value - поправка вычисленная из аргументов функции forward_game_time

Вот так например рассчитывается разница в секундах реального времени на основе игрового времени:
Код
local diff_sec = math.ceil(game.get_game_time():diffSec(inited_time)/level.get_time_factor())

где game.get_game_time() - текущее время, inited_time - время начала отсчета, level.get_time_factor() - коэффициент ускорения игрового времени относительно реального (11), :diffSec - функция рассчитывающая разницу времени в секундах, math.ceil - округление до ближайшего большего целого.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
NIVДата: Сб, 12.10.2013, 20:05 | Сообщение # 165
Полевой исследователь
Ученые сталкеры
Сообщений: 167
Награды: 4
Репутация: [ 180 ]

Ещё уточню - game.get_game_time() возвращает время в виде (Y, M, D, h, m и т.д.)? Может там можно делать арифметику типа time:set (Y, M, D, h + 4, m, s, ms)?

Да именно так - это матрица или массив временных параметров. И можно задать функцией :set(Y, M, D, h + delta, m, s, ms). denis2000


Изменяем реальность S.T.A.L.K.E.R. CoP: "Цена Новых Исследований" / "New Investigations' Value"

Сообщение отредактировал NIV - Сб, 12.10.2013, 20:07
 
Форум » Моды для игр » Модостроение » Модостроение. Создание и редактирование квестов
Поиск: