--[[------------------------------------------------------------------------------------------------------------------ Управление диалогами групп сталкеров Чугай Саша Сделать: Описание: Чтоб в какой-то момент начался диалог, нужно, чтоб у ВСЕХ членов команды был вызван 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