e4s-sdk/gamedata/scripts/xr_dialogs.script
2026-06-17 23:06:51 +03:00

249 lines
7 KiB
Text
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

--[[------------------------------------------------------------------------------------------------------------------
Управление диалогами групп сталкеров
Чугай Саша
Сделать:
Описание:
Чтоб в какой-то момент начался диалог, нужно, чтоб у ВСЕХ членов команды был вызван enable. Один единственный вызов
disable и диалог не начнётся. Для начала диалога выбирается любой член команды, если нету никого рядом с ним, то диалог
не начнётся. Для повторных реплик выбирается любой член команды (кроме только что говорившего) из числа тех, кто нахо-
дится рядом с последним говорившим; если таких нету, то диалог прерывается.
--------------------------------------------------------------------------------------------------------------------]]
local teams = {} -- группы сталкеров, сгруппированных для диалога
local snd = { themes = {} }
local idle_min, idle_max = 20, 60 -- пределы периода молчанки между диалогами в секундах
local pause_min, pause_max = 1, 2 -- пределы величины паузы между фразаим в секундах
local dist_max = 100 -- квадрат максимального расстояния между собеседниками
local avail = {}
----------------------------------------------------------------------------------------------------------------------
-- деревья диалогов
----------------------------------------------------------------------------------------------------------------------
local dialogs = {
place = {
[1] = { snd = "place1", next = 2 },
[2] = { snd = "place2" }
},
}
----------------------------------------------------------------------------------------------------------------------
-- класс управления диалогами (только звуками)
----------------------------------------------------------------------------------------------------------------------
class "dialog_mgr"
function dialog_mgr:__init()
end
function dialog_mgr:reset( npc, team )
self.object = npc
if self.team ~= team then
-- если сталкер в команде
if self.team then
-- убрать из текущей команды
self:finalize()
end
self.team = team
if team then
if not teams[team] then
teams[team] = { npcs = {}, npcs_num = 0, idle_end = 0 }
end
self.a = teams[team]
-- self.a.npcs[npc:id()] = npc
table.insert( self.a.npcs, npc )
-- printf( "[dialogs] adding %s to dlgteam %s", npc:name(), team )
end
end
end
function dialog_mgr:finalize()
if self.team then
-- убрать сталкера из списка
for i, v in pairs(self.a.npcs) do
if v:id() == self.object:id() then
table.remove( self.a.npcs, i )
break
end
end
self.team = nil
-- если никого не осталось, сбросить диалог
if #self.a.npcs == 0 then
self:reset_dialog()
end
end
end
-- включить возможность начала диалога
function dialog_mgr:enable( dlgs )
if self.team then
self.a.dlgs = dlgs
end
end
-- выключить возможность начала диалога
function dialog_mgr:disable()
if self.team then
self.a.dlgs = nil
end
end
-- текущий активный диалог
function dialog_mgr:active()
return self.team and self.a.cur_dlg
end
-- начало нового диалога
function dialog_mgr:new_dialog()
-- выбор нового диалога
if #self.a.dlgs > 1 then
local r = math.random( 1, #self.a.dlgs - 1 )
if self.a.dlgs[r] == self.a.last_dlg then
r = r + 1
end
self.a.cur_dlg = self.a.dlgs[r]
else
self.a.cur_dlg = self.a.dlgs[1]
end
self.a.last_dlg = self.a.cur_dlg
-- printf( "!!!!! NEW_DIALOG="..self.a.cur_dlg )
-- попробовать выбрать первую фразу
if not self:new_phrase() then
-- если не смогли, то диалог начаться не может
self:reset_dialog()
-- следующую проверку возможности начала диалога отложить на небольшое время
self.a.idle_end = time_global() + 5000
end
end
-- сбросить диалог
function dialog_mgr:reset_dialog()
self.a.dlgs = nil
self.a.cur_dlg = nil
self.a.cur_phrase = nil
self.a.cur_npc = nil
-- следующий диалог может начаться лишь по истечению периода молчанки
self.a.idle_end = time_global() + math.random( idle_min, idle_max ) * 1000
-- printf( "reset dialog" )
end
-- отменить текущий период молчанки между диалогами
function dialog_mgr:reset_idle()
if self.team then
self.a.idle_end = 0
end
end
-- подготовка новой фразы
function dialog_mgr:new_phrase()
clear_table( avail )
-- если диалог уже был начат (т.е. есть текущий говорящий)
if self.a.cur_npc then
-- выбрать того, кто ответит. он должен быть недалеко от предыдущего говорящего
for i, v in pairs(self.a.npcs) do
if v:id() ~= self.a.cur_npc:id() and self.a.cur_npc:position():distance_to_sqr( v:position() ) <= dist_max then
table.insert( avail, v )
end
end
if #avail == 0 then
-- если отвечать некому, то фраза не выбрана
return false
end
-- выбор нового говорящего
self.a.cur_npc = avail[math.random( 1, #avail )]
else
-- попытка выбора нового говорящего
self.a.cur_npc = self.a.npcs[math.random( 1, #self.a.npcs )]
-- посмотреть, может ли кто-то потенциально продолжить диалог
local flg
for i, v in pairs(self.a.npcs) do
if v:id() ~= self.a.cur_npc:id() and self.a.cur_npc:position():distance_to_sqr( v:position() ) <= dist_max then
flg = true
break
end
end
if not flg then
-- если нет, то даже и не начинать диалог
return false
end
end
-- выбор новой фразы
if not self.a.cur_phrase then
printf( self.a.cur_dlg )
self.a.cur_phrase = dialogs[self.a.cur_dlg][1]
else
local p = self.a.cur_phrase.next
if not p then
-- следующей фразы нету
return false
end
if type( p ) == "table" then
p = p[math.random( 1, #p )]
end
self.a.cur_phrase = dialogs[self.a.cur_dlg][p]
end
-- установить задержку перед новой фразой
self.a.phrase_delay_end = time_global() + math.random( pause_min, pause_max ) * 1000
self.a.phrase_playing = false
-- printf( "phrase selected" )
return true
end
-- обновление
function dialog_mgr:update()
-- если сталкер не состоит в команде для диалогов
if not self.team then
return
end
if self.a.cur_dlg then -- активен ли диалог?
if self.object:id() == self.a.cur_npc:id() then -- обновление текущего говорящего?
if self.a.phrase_delay_end < time_global() then -- окончилась ли необходимая задержка перед фразой?
if self.a.phrase_playing then -- начали ли уже играть звук?
if self.a.cur_npc:active_sound_count() == 0 then -- звук закончился?
if not self:new_phrase() then
-- если новая фраза не выбрана, то наступил конец диалога
self:reset_dialog()
end
end
else
-- произнести фразу
snd.themes[1] = self.a.cur_phrase.snd
xr_sound.sound_update( self.a.cur_npc, snd, true )
self.a.phrase_playing = true
-- printf( "SNDSNDNSNDND = " .. snd.themes[1] )
end
end
end
else
-- если можно, начать диалог и у нас не один говорящий
if self.a.dlgs and self.a.idle_end < time_global() and #self.a.npcs > 1 then
self:new_dialog()
end
end
end