Створюємо телепорт
Теорія цієї справи
У грі існує такий об'єкт як "zone_teleport", але якщо ми його створимо через create, то він виглядатиме і переливатиметься як справжній телепорт, але телепортувати нас кудись на жаль не зможе. Пов'язано це з тим, що, у аномалій (а телепорт це такий різновид аномалії) параметри задаються хитромудро, через all.spawn. Втім штатним способом телепорт без повнофункціонального редактора карт не отримати (хоча можливо я не прав вже після написання цього тексту з'явилися ідеї як це зробити через all.spawn ). Значить на нашу частку залишаються способи "не штатні";) Реалізуємо найпростіший. Вважатимемо що у нас на карті є квадрат із заданими координатами при попаданні в який актора має перемістити в крапку з іншими координатами. Для цього періодично перевірятимемо координати актора, і якщо він у квадраті - переміщуємо. Ось у краці принцип дії нашого саморобного телепорту.
Реалізація
У каталозі gamedata\scripts\ Створимо файл bind_mteleport.script із логікою роботи нашого телепорту.
-- ************************************************ -- ** Imp ** -- ** Біндер саморобних телепортів ** -- ** Підтримує роботу самопальних телепортів ** -- ******************* *********************** local teleport_binders = { } -- Список телепортів function abs_comp ( a, b ) -- Службова функція обчислення різниці if ( a < b ) then return ( b - a ) else return ( a - b ) end end function teleportate ( x, y, z ) - Функція телепортації local a = vector ( ) - Задаємо координати ax = x ay = y az = z -- Сама телепортація db.actor: set_actor_position ( a ) - Звуковий супровід local snd_obj = xr_sound.get_safe_sound_object ( [ [ affects \ tinnitus3a ] ] ) snd_obj : play_no_feedback _ end function actor_update ( delta ) local i,v,acter_poz,s - Отримаємо позицію актора (щоб кожен раз не запитувати) acter_poz = db.actor:position ( ) -- Перевіряємо наші телепорти for i, v in pairs ( teleport_binders ) do s = v.parametrs local obj = level.object_by_id ( i ) if obj ~= nil then -- Наш телепорт в онлайні перевіряємо далі if s.teleporte ~= nil and s.teleporte ~= false then -- Телепорт запущено if ( time_global ( ) <= s time ) then -- Якщо час відведений на показ спецефектів -- минув , проводимо телепортацію teleportate ( s.poz_x,s.poz_y,s.poz_z ) if s.rotate ~= nil then db.actor:set_actor_direction ( s.rotate ) end s.teleporte = false end return end -- Поровіримо чи не забрів актор у наш телепорт if ( abs_comp ( sx, acter_poz.x ) < v.parametrs.radius and abs_comp ( sz, acter_poz.z ) < v.parametrs.radius and abs_comp ( sy, acter_poz.y ) < v.parametrs.z_radius ) then -- Актор у зоні дії телепорту, запустимо телепорт s [ "teleporte" ] = true s [ "time" ] = time_global ( ) + 500 -- Запускаємо спецефекти телепортації level.add_pp_effector ( " teleport.ppe " , 2006 , false ) end end end end function bind ( obj ) obj: bind_object ( restrictor_teleport ( obj ) ) end -------------------------------------------------- -------------------------------------------------- class "restrictor_teleport" ( object_binder ) function restrictor_teleport:__init ( obj, char_ini ) super ( obj ) end function restrictor_teleport:net_spawn ( data ) local char_ini = system_ini ( ) -- Якщо це телепорт то занесемо його до спеціального списку телепортів if self.teleport == true then teleport_binders [ self.object:id ( ) ] = self -- Заповнимо таблицю параметрів self [ "parametrs" ] = { } if char_ini:line_exist ( self.section, "radius" ) then self.parametrs [ "radius" ] = tonumber ( char_ini:r_string ( self.section, "radius") ) ) else self.parametrs [ "radius" ] = 2 - Дефолтний радіус xy end if char_ini:line_exist ( self.section, "z_radius" ) then self.parametrs [ "z_radius" ] = tonumber ( char_ini:r_string ( self .section, "z_radius" ) ) else self.parametrs [ "z_radius" ] = self.parametrs [ "radius" ] -- якщо радіус висоти не заданий то задаємо рівним радіусу xy end -- Запам'ятаймо позицію щоб кожен раз не рахувати local s_obj = alife ( ) :object ( self.object:id ( ) ) self.parametrs [ " x " ] = tonumber ( s_obj.position.x ) ; self.parametrs [ "y" ] = tonumber ( s_obj.position.y ) ; self.parametrs [ "z" ] = tonumber ( s_obj.position.z ) ; - Запам'ятаємо координати куди телепортуємо self.parametrs [ "poz_x" ] = tonumber ( char_ini:r_string ( self.section, "poz_x" ) ) self.parametrs [ "poz_y" ] = tonumber ( char_ini : r_string ( self.section, poz_y" ) ) self.parametrs [ "poz_z" ] = tonumber ( char_ini:r_string ( self.section, "poz_z" ) ) if char_ini:line_exist ( self.section, "rotate" ) then self.parametrs [ "rotate" ] = tonumber ( char_ini:r_string ( self.section, "rotate" ) ) end end return true end function restrictor_teleport:net_destroy ( ) -- Видаляємо наш телепорт teleport_binders [ self.object:id ( ) ] = nil self.parametrs = nil object_binder.net_destroy ( self ) end function restrictor_teleport:reload ( section ) local char_ini = system_ini ( ) self.section = section -- Якщо це телепорт if char_ini ~= nil and char_ini:line_exist ( self.section, "teleport" ) then self [ "teleport" ] = true end end
Для постійного оновлення потрібно причепити функцію actor_update() до біндера актора, для чого у файлі bind_stalker.script знайдемо функцію:
function actor_binder:update(delta)
У ній знайдемо виклик оновлення рестрикторів bind_restrictor.actor_update(delta) під яким вставимо рядок із викликом нашої функції оновлення: bind_mteleport.actor_update(delta)
Усі з програмною частиною закінчили, тепер задаємо дані телепорту.
У каталозі gamedata\config\misc відкриваємо файл zone_teleport.ltx і в кінці файлу додаємо наступні рядки, що описують конкретний телепорт:
[ m_teleport_1 ] :zone_teleport teleport = standart script_binding = bind_mteleport.bind ;Параметри нашого телепорту radius = 2 ;Висота захоплення телепорту z_radius = 2 ;Куди телепортуємось (телепортація завжди йде в межах карти) poz_x = 22.78 poz_y = 20.35 poz_z = 659.24 ; Кут зору у разі. Якщо параметра немає, то не змінюється. rotate = 1.5
Параметри нашого телепорту:
- radius - насправді не радіус, а половина довгі сторони нашого квадрата (на початку я хотів зробити його навколо, але вважав, що краще не витрачати процесорний час порожньо). Центром квадрата є точка респавна телепорту.
- z_radius – висота нашого телепорту.
- poz_x, poz_y, poz_z – координати точки телепортації.
- rotate - Кут повороту після телепортації від осі X (я не розбирався в яких одиницях задається, але 1.5 приблизно дорівнює 90 градусів). Якщо параметр видалити то залишатиметься кут під яким актор увійшов у телепорт.
Використання
Тепер за допомогою create створимо наш телепорт: Приклад:
local obj local a = vector ( ) ax = -244.55 ay = -19.46 az = -125.42 obj = alife ( ) :create ( "m_teleport_1" ,a, 12829 , 8 , 65535 )
Створить телепорт біля виходу із бункера Сидоровича. Наш телепорт перекидає гравця на вежу блокпоста (перед виходом з рівня).