Перейти к контенту

Рекомендуемые сообщения

PlayMod   

Перенос оружия.
Сложность. Средняя

Вот мой способ как перенести оружие с одного мода на другой. Это работает только (ТЧ на ТЧ), (ЗП НА ЗП), и (ЧН на ЧН).
Опытные знают это, так что расскажу новичка, итак поехали.

1.И так для начала возьмем наш файл, к примеру w_ak74.ltx, копируем его из другого мода в наш с заменой, открываем его и ищем там snd_*****(это звуки оружия, и где они находятся), пример weapons\ak47\ak47_draw, и т.д.

2.Идем по этому тому адресу и копируем все файлы в нашу папку с игрой, именно по такому адресу.
3. Далее идем в папку meshes\weapons\ak74\wpn_ak74_hud, открываем любым текстовым радактором (желательно Notepad ++), нажимаем Ctrl+F, и вводим "Wpn", там будет примерно такое "wpn\wpn_ak74", (по разному), значит идем по этому адресу textures\wpn\wpn_ak74, копируем этот файл в нашу папку по тому же адресу, (так же как и звуки), потом еще раз нажимаем "Wpn", и копируем, повторяем эту процедуру со всеми остальными файлами.
Вроде Все, заходим в игру и радуемся. Удачи.

 


  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Решил создать гайд по спавну через программу ACDC ТЧ. Для тех, кто вообще не знает даже что такое ACDC и с чем его едят.
Думаю кому-нибудь пригодиться. Несомненно спавнить лучше через SDK, но есть такие люди которые не умеют пользоваться сие инструментом.


1. Скачиваем программу Active Perl на сайте: www.activestate.com/activeperl (По непонятным мне причинам с AMK форума нельзя перейти на данный сайт, так-что копируйте и вставляйте в строку браузера.) Обращаем внимание на свою систему. Если у вас x64 качаем для x64, если x86 то x86. Думаю понятно. Устанавливаем.
 
2. Далее в корне игры создаем папку gamedata, в неё кидаем файл game.graph из распакованого сталкера. Ссылка на распаковщик для сталкера: http://yadi.sk/d/iMeW6v0reQPW4
Далее в папке gamedata создаем папку spawns в неё кидаем файл all.spawn из того-же распакованого сталкера.
 
3. Далее качаем программу ACDC по ссылке: http://yadi.sk/d/aEFtlI_veQE6m распаковываем архив видим папку acdc, эту папку кидаем в свою папку spawns.
 
4. Заходим в папку ACDC видим два батника:
acdc_compile - Это компиляция.
acdc_decompile - Это декомпиляция.
Нажимаем декомпиляцию, пойдет процесс. Когда процесс будет окончен, нажимаем любую клавишу окно исчезнет. Делее мы видим папку unpack.
 
5. Давайте заспавним сталкера!
Открываем alife_l01_escape. "escape" это название локации. Что мы видим? Всякие не понятные секции, символы.. Страшно? Все просто! Листаем в самый конец. Последняя секция под номером [869], после неё создаем свою секцию, так-же при помощи комментариев поясню что к чему:
 


[870] ; 870 номер секции, после неё 871, 872 и так-далее.
 
; cse_abstract properties
section_name = stalker
name = esc_vagon ; это имя пишем свое.
position = -199.870178222656,-19.8877372741699,-137.10905456543 ; Координаты.
direction = 0,0.00316426996141672,0.062321275472641
version = 118
script_version = 6
 
; cse_alife_trader_abstract properties
money = 5000
character_profile = esc_vagon  ; это ваше имя сталкера из characters_desc_*****
 
; cse_alife_object properties
game_vertex_id = 57 ; гейм вертекс.
distance = 9.80000019073486
level_vertex_id = 52330 ; левел вертекс.
object_flags = 0xffffffbf
custom_data = <<END
[logic] ; ЛОГИКА!!!
active = walker@stay_at_position,
danger = danger_ignore
 
[danger_ignore]
ignore_distance = 5
 
[walker@stay_at_position]
path_walk = esc_lager_petruha_walk ; точка где он будет стоять. ps. имя вводите свое но что бы вконце было walk. А в начале имя локации esc - esc_lager_petruha_walk.
path_look = esc_lager_petruha_look ; точка куда он будет смотреть. ps. имя вводите свое но что бы вконце было look. А в начале имя локации esc - esc_lager_petruha_look.
END
story_id = 5481 ; ВАЖНО! SID. Прописываем его в файле [b]game_story_ids[/b] который лежит в папке [i]config[/i].
 
; cse_visual properties
visual_name = actors\novice\green_stalker_2
 
; cse_alife_creature_abstract properties
g_team = 0
g_squad = 1
g_group = 5
health = 1
dynamic_out_restrictions =                  
dynamic_in_restrictions =                  
upd:health = 1
upd:timestamp = 0x617a6b75
upd:creature_flags = 0x6b
upd:position = -199.870178222656,-19.8877372741699,-137.10905456543 ; теже самые координаты что и вверху
upd:o_model = 0
upd:o_torso = 0.00316426996141672,0.062321275472641,0
upd:g_team = 0
upd:g_squad = 1
upd:g_group = 5
 
; cse_alife_monster_abstract properties
upd:next_game_vertex_id = 65535
upd:prev_game_vertex_id = 65535
upd:distance_from_point = 0
upd:distance_to_point = 0
equipment_preferences = 2,2,0,1,1
main_weapon_preferences = 0,2,0,2
 
; cse_ph_skeleton properties
 
; cse_alife_human_stalker properties
upd:start_dialog =                  
 
; se_stalker properties
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

6. Далее.. Идем в игру снимаем координаты, где он будет стоять и куда он будет смотреть.
 
7. Прописываем пути в файле way_l01_escape, что находиться в папке unpack. Идем в самый конец.
И после:


[escape_factory_look_common]
points = p0
p0:name = wp00|n=1
p0:flags = 0x1
p0:position = 114.742797851563,-7.17558288574219,-33.0148315429688
p0:game_vertex_id = 125
p0:level_vertex_id = 417148

Ставим:


[esc_lager_petruha_walk] ; точка где он стоит, имя из ЛОГИКИ!
points = p0
p0:name = name00
p0:flags = 0x400
p0:position = -60.1297874450684,-5.67141437530518,6.7514533996582 ; координаты где он стоит
p0:game_vertex_id = 113 ; гейм вертекс
p0:level_vertex_id = 347680 ; левел вертекс
 
[esc_lager_petruha_look] ; точка куда он смотрит, имя из ЛОГИКИ!
points = p0
p0:name = name00
p0:flags = 0x400
p0:position = 106.122169494629,-3.09708905220032,-7.83051156997681 ; координаты куда он смотрит
p0:game_vertex_id = 117 ; гейм вертекс
p0:level_vertex_id = 407096 ; левер вертекс

Сохраняем!
8. Далее в character_desc_escape или еще где-то у вас должен быть прописан НПС. Если не прописали, прописываем.


   <specific_character id="esc_vagon" team_default = "1"> ; имя в name = esc_vagon что вверху.
                   <name>esc_vagon_name</name>
                   <icon>ui_npc_u_stalker_bandit_master</icon>
                   <bio>esc_vagon_bio</bio>
 
                   <class>esc_petruha</class>
                   <community>stalker</community> <terrain_sect>stalker_terrain</terrain_sect>
                          
                   <rank>534</rank>
                   <reputation>234</reputation>
                          
                   <snd_config>characters_voice\human_03\stalker\</snd_config>
                   <crouch_type>0</crouch_type>
 
                   <visual>actors\bandit\stalker_bandit_master</visual>                   
                   <supplies>
                    [spawn] \n
                    wpn_pm \n
                    ammo_9x18_fmj = 1 \n
#include "gameplay\character_items.xml" \n
#include "gameplay\character_food.xml"
                   </supplies>                  
                            
#include "gameplay\character_criticals_5.xml"
#include "gameplay\character_dialogs.xml"
                   <start_dialog>hello_dialog</start_dialog>
                  </specific_character>

 
9. Идем в npc_profile, что в папке gameplay, прописываем в конце нашего НПС:


<character id="esc_vagon">
<class>esc_vagon</class>
<specific_character>esc_vagon</specific_character>
</character>

Надеюсь, вы справитесь.
 
10. Идем в папку acdc. Нажимаем acdc_compile, пойдет процесс компиляции. ВСЕ! Если вы меня правильно поняли и все сделали как надо, то по указанным координатам должен появиться НПС, который будет смотреть в вашу заданную точку.

ВНИМАНИЕ!!! Все мои комментарии после знака ; и знак сам - удаляем!

Изменено пользователем NL-Vincenz

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 2
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Samber13   

Продолжу тему о шрифтах http://www.amk-team.ru/forum/index.php?showtopic=6458&p=902166

 

@FantomICW рассказал о списке доступных шрифтов и их регистрации. И упомянул о fonts.ltx Рассмотрим его получше.


В этом файле список шрифтов и их параметров. В качестве примера рассмотрим секцию:
[ui_font_arial_14]
shader			= hud\font
texture			= ui\ui_font_arial_14_1024
texture800		= ui\ui_font_arial_14_800
texture1600		= ui\ui_font_arial_14_1600

Параметр "shader", как не сложно догадаться назначает шейдер на шрифт. Подробней чуть позже. Параметр "texture" указывает на текстуру с этим самым шрифтом. Цифры в параметрах вида "texture800" означают разрешение монитора, при котором будет использована та или иная текстура. Текстуры с префиксами "_west","_cent" означают кодировки.
По умолчанию во всех шрифтах используется шейдер "hud\font". Если мы попробуем поменять его, скажем на "hud\default", то получится нечто подобное:

42637fe2f0f691b04b6e3a3521a5eb2bd90fc720

Связано это с особенностью текстур. Немного отвлечёмся. Попробовав открыть такую текстуру плагином nvidia для фотошопа, я получил нечто абсолютно бесформенное. Кроме квадрата Малевича, был альфа-канал, на котором не отчётливо можно было разобрать контуры некоторых символов. Сторонние вьюверы и редакторы показывали подобный неоднозначный результат. Но затратив немного времени и сил я разобрался с этим и перевёл этот 8-битный одноканальный файл в привычный DXT5.

И так возвращаемся к шейдерам. Если на DXT5 текстуру шрифта назначить шейдер "hud\default", то она будет отображаться правильно. Цвет шрифта будет взят напрямую из RGB каналов текстуры, а не из назначенных параметров. Минусы такого шейдера очевидны, но если скажем, вам нужны чёрные контуры на символах или по вашей задумке буквы должны быть радужными, то это может, пригодится. Если же на DXT5 текстуру шрифта назначить шейдер "hud\font", то символы считываются с альфа-канала без ошибок, так же как и с оригинальной текстуры. RGB-каналы при этом не используются. Именно по этой причине разработчики сжали текстуры шрифтов.

У каждой текстуры шрифта есть свой ".ini" файл, в котором, одна постоянная секция "symbol_coords". Не сложно догадаться, что здесь вписаны координаты каждого символа. И так же встречается секция "width_correction" - поправка по ширине.

Надеюсь, что статья будет полезной. Добра и удачи в разработке :) 

 

Изменено пользователем Samber13

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 2
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 5

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создание LOD статических объектов.

 

 

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

 

 


  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 2
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 3
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

По просьбам трудящихся...

Создание играющего магнитофона\радио для ЗП.

0. Первый пункт - если вы будете складывать секции звуков в отдельный файл. Если добавляете в уже имеющийся (например, script_sound_zaton) - переходите к пункту 2.

1. Сначала мы зарегистрируем наши звуки. Для этого пройдём в configs\misc\script_sound.ltx  и сделаем регистрацию нашего нового файла с музыкой (можно сделать в уже существующем). Для этого после строки:

#include "script_sound_underpass.ltx"

Вставим нашу регистрацию нового файла:

#include "script_sound_bar.ltx" ;Допустим, я работаю с локацией Бар - поэтому, _bar, но названия могут быть и произвольными

А также добавим наш файл в лист:

[list]: list_music_and_stories, list_script_sound_zaton, list_script_sound_jupiter, list_script_sound_pripyat, list_script_sound_underpass, list_script_sound_bar ;Вот он: последний в списке

2. Зарегистрировали, перейдём к файлу, для этого создадим его под именем list_script_sound_bar (новый текстовый документ -> сменить имя и расширение на .ltx). Наполняем:

[list_script_sound_bar] ;Имя с секциями звуков в этом файле
bar_music_main

[bar_music_main] ;Конкретно секция нужного нам звука
type 	    = 3d
npc_prefix  = false
path 	    = music\radio\bar_main_ ;Путь до наших звуков
shuffle	    = rnd
idle        = 2,4,100 

Подробно о настройке можно (и нужно) почитать вот эту хорошую статейку: http://stalkerin.gameru.net/wiki/index.php?title=CoP._Разбор_звуковых_конфигов_в_script_sound_***

3. Соответственно, в папку sounds\music\radio положим файлы в формате .ogg с именем bar_main_<Номер_звука>.

Со звуками закончили, теперь надо создать логику для объекта, который будет проигрывать наши звуки.

4. Идём в папку configs\scripts\bar (как вы помните, имя папки bar у каждого будет своя) и создаём там файл bar_a1_radio.ltx. Наполним его:

[logic]
active = ph_sound@idle

[ph_sound@idle]
sound      = bar_music_main

Также подробнее про схему ph_sound можно почитать тут: http://stalkerin.gameru.net/wiki/index.php?title=Настройка_логики._Часть_4

Дело за малым, нужно создать само радио.

5. Тут уж, кто как: кто в all.spawn добавлять секцию будет, кто в СДК.

5.1. All.spawn

[49]
; cse_abstract properties
section_name = physic_destroyable_object
name = bar_radio
position = -141.697998046875,-22.3415851593018,-353.995544433594 :Позиция, вертексы, направление - это вы знаете
direction = -1.70000002981396e-005,3.14159202575684,0

; cse_alife_object properties
game_vertex_id = 1407
distance = 0
level_vertex_id = 747615
object_flags = 0xffffff3a
custom_data = <<END
[logic]
cfg = configs\scripts\bar\bar_a1_radio.ltx ;Путь до логики
END

; cse_visual properties
visual_name = dynamics\el_tehnika\radio ;Путь до визуала

; cse_ph_skeleton properties

; cse_alife_object_physic properties
physic_type = 0x3
mass = 3
fixed_bones = link ;кость, которая будет зафиксирована, чтобы не утащили 

5.2. СДК

dffa4f8802bae1dc90960df739582357.png

 

6. Последний штрих - нужно вернуть в ЗП схему проигрывания звуков объектами - она в оригинале отключена за ненадобностью.

Идём в scripts\modules.script и после строки №60 (ph_oscillate) пишем

load_scheme("ph_sound",						"ph_sound",		stype_item)

Скрипт схемы нужно создать и заполнить его таким содержимым:

--[[ Сталкер Лом
Чуть переделал схему: 
* Настроил на проигрывание звуков из ltx файла - так привычнее. 
* Соответственно, теперь не надо указывать в секции логики тип звука - берётся из ltx файла
19.02.14 ]]

class "snd_source"
function snd_source:__init (obj, storage)
	self.object = obj
	self.st	= storage
	self.destructed = false
end
function snd_source:reset_scheme(loading)
	self.last_update = 0
	self.st.signals = {}
	self.played_sound = nil

	
	self.first_sound = true
    self.st.pause_time = 0	
    self.st.sound_set = true
    if loading == false then
	   self.destructed = false
	else
	   self.destructed = xr_logic.pstor_retrieve (self.object, "destr")
	end   
end

function snd_source:save ()
	xr_logic.pstor_store (self.object, "destr",  self.destructed)
end

function snd_source:hit_callback(obj, amount, local_direction, who, bone_index)
    if self.st.no_hit == true then return end
    printf ("SOUND SOURCE HAVE A HIT")
	local who_name
	if who then
		who_name = who:name()
	else
		who_name = "nil"
	end

	printf("_bp: snd_source:hit_callback obj='%s', amount=%d, who='%s'", obj:name(), amount, who_name)

    if self.played_sound ~= nil then
       self.played_sound:stop ()
       self.played_sound = nil
    end
    self.destructed = true
end


function snd_source:update(delta)
    if self.destructed == true then return end

	if xr_logic.try_switch_to_another_section (self.object, self.st, db.actor) then
		return
	end

    if self.st.pause_time - device ():time_global () > 0 then
        return
    end
       
    self.st.pause_time = 0
    if self.st.sound_set == true then
        self.st.sound_set = false

--[[		if self.st.random then
			self.played_sound = xr_sound.get_sound_object(self.st.theme, "random")
		elseif self.st.looped then
			self.played_sound = xr_sound.get_sound_object(self.st.theme, "looped")
		else
			self.played_sound = xr_sound.get_sound_object(self.st.theme, "seq")
		end ]]
		
		self.played_sound = xr_sound.set_sound_play(self.object:id(), self.st.theme)

		if self.played_sound ~= nil then
			self.played_sound:play_at_pos (self.object, self.object:position ())
		else
			self.st.signals["theme_end"] = true
		end
		self.first_sound = false
	end   

       
    if self.last_update == 0 then
       self.last_update = device ():time_global ()
    else
       if device ():time_global () - self.last_update > 50 then
          self.last_update = 0
       else
          return     
       end          
    end
       
	if self.played_sound ~= nil then 
		if self.played_sound:playing () == false then
			if self.first_sound == false then
				self.st.signals["sound_end"] = true
			end
	                
			self.st.sound_set = true
			if self.st.pause_min ~= 0 or self.st.pause_max ~= 0 then
				local time = math.random (self.st.pause_min, self.st.pause_max)
				self.st.pause_time = device ():time_global () + time
			end 
			self.first_sound = false
		else
			self.played_sound:set_position (self.object:position ())
		end
	end       
end

function snd_source:deactivate ()
    if self.played_sound ~= nil then
       self.played_sound:stop ()
       self.played_sound = nil
    end
end



function add_to_binder (npc, ini, scheme, section, storage)
	local new_action = snd_source (npc, storage)
	-- Зарегистрировать все actions, в которых должен быть вызван метод reset_scheme при изменении настроек схемы:
	xr_logic.subscribe_action_for_events(npc, storage, new_action)
	
end

function set_scheme(npc, ini, scheme, section, gulag_name)
	local st    = xr_logic.assign_storage_and_bind(npc, ini, scheme, section)
	st.logic    = xr_logic.cfg_get_switch_conditions(ini, section, npc)
	st.theme    = utils.cfg_get_string(ini, section, "sound",	npc, false, "")
--	st.looped   = utils.cfg_get_bool (ini, section, "looped", npc, false, false)
--	st.random   = utils.cfg_get_bool (ini, section, "random", npc, false, true)
	st.pause_min = utils.cfg_get_number (ini, section, "min_idle", npc, false, 0)
	st.pause_max = utils.cfg_get_number (ini, section, "max_idle", npc, false, 0)
	st.no_hit   = utils.cfg_get_bool (ini, section, "no_hit", npc, false, true)
	if st.pause_max < st.pause_min then
	   abort ("PH_SOUND - invalid time range !!!")
    end	    
end
     

 

 

Это чуть правленая мною схема, чтобы можно было использовать звуки из ltx файлов, как это принято в ЗП.

Вот, собственно, и всё.

 

 

Да, конечно, есть урок из поста 42, но каждый раз править скрипт, добавляя\убирая звуки - не гуд, а вот делать всё через ltx файлы гораздо удобнее. Стандартизация, так сказать.

В общем, кому что, а мне так сподручнее, может быть и вам будет лучше.

Изменено пользователем Сталкер Лом

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 2
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 2
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
sneik   

А если в файле логики записать вот так.

 

[logic]
active = ph_idle@wait
 
[ph_idle@wait]
hit_on_bone = 0| nil
on_info = {=actor_in_zone(название_рестрактора, покрывающего,зону_звучания_радио)} ph_idle@play %=play_sound(bar_music_main)%
 
[ph_idle@play]
hit_on_bone = 0| nil %=stop_sound%
on_info = {!actor_in_zone(название_рестрактора, покрывающего,зону_звучания_радио)} ph_idle@wait %=stop_sound%
on_info2 = {!is_playing_sound} ph_idle@wait
 
То ни каких правок скрипта делать не надо. Радио звучит только тогда когда ГГ в зоне звучания, вышел - радио заглохло.
Изменено пользователем sneik

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 4

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создание LOD динамических объектов.

 

 

Пожелания, критика приветствуется

 


  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 4
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 3

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Clayman   

Создание модуля автоматического получения game_vertex и level_vertex любой локации мода, для спавна динамических аномалий.

Категория: для новичков.

Платформа: ЗП (не вижу причин, чтобы это не работало на ЧН и ТЧ).

 

Для кого-то это будет "изобретать вилосипед", кому-то, надеюсь, пригодится.



Прикручивая модуль динамических аномалий для своего пака локаций (ЗП) я пересмотрел несколько готовых решений (АМК ЗП в частности и другие). Практически во всех модах, где реализуется спавн аномалий по рандомным гейм-вертексам локации присутствуют подобные конструкции:



local level_vertexes={
escape = 597179,
garbage = 1045075
}
local game_vertexes={
escape = {0,240},
garbage = {241,500}
}



Т.е таблицы с прописанными диапазонами гейм-вертексов и максимальными значениями левел-вертексов всех локаций. Где эти значения брать? Обычно запускают специальный скрипт в игре, с помощью которого получаем эти данные. Я в частности, использовал подобные скрипты, описанные на сталкервики (на их базе и создан этот модуль).

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

 

Итак, в нужном вам модуле (динамические аномалии) пишем две функции:

 

-- Функция получает таблицы левел-вертексов всех уровней и возвращает нужную (по уровню)
function GetLevelsVertexes(level)
 local lvtab ={}
 local i = 0
 while game_graph():valid_vertex_id(i) do  
  local lv = game_graph():vertex(i):level_vertex_id() 
  local ln = alife():level_name(game_graph():vertex(i):level_id()) 
  if  not  lvtab[ln] then 
   lvtab[ln] ={}  
  end       
  table.insert(lvtab[ln], lv)
  i = i+1
 end
 return lvtab[level]
end
------------
--Функция получает таблицы всех гейм-вертексов и возвращает нужную (по уровню)
function GetGameVertexes(level)
 local gvtab ={}
        local i = 0
        while game_graph():valid_vertex_id(i) do
  local ln = alife():level_name(game_graph():vertex(i):level_id())
  if  not  gvtab[ln] then
  gvtab[ln] ={}
  end
        table.insert(gvtab[ln], i)
  i = i+1
    end
 return gvtab[level]
end

 

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

 

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

 

 local level_name = level.name()
 local lvtab = GetLevelsVertexes(level_name)
 local lvx = math.max(unpack(lvtab))
 local lv = math_random(1,lvx) --//рандомный левел-вертекс

 

Получение диапазона гейм-вертексов для текущего уровня:

 

local lname = level.name()

local gvtab = GetGameVertexes(lname)
local gv_min = math.min(unpack(gvtab))
local gv_max = math.max(unpack(gvtab))

 

Вот и все. Теперь при любых изменениях с гейм-графом и аи-сеткой вы будете автоматически вычислять нужные значения. Очевидные, но очень удобные вещи.

Скрипт не претендует на шедевр программирования, улучшения от профессионалов приветствуются ;)

 

 

Изменено пользователем Clayman

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 3
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Nazgool   

@Clayman, Функции я бы написал малость по другому. В таком плане :

local lvtab = setmetatable({}, {__index = function (t,k) t[k] = {} return t[k] end})function GetLevelsVertexes(level)    local i = 0    local graph = game_graph()    local sim = alife()    while graph:valid_vertex_id(i) do        local v = graph:vertex(i)        local data = lvtab[sim:level_name(v:level_id())]        data[#data+1] = v:level_vertex_id()        i = i+1    end    return lvtab[level]end

Это раза в 3 быстрее (простое кеширование глобальных функций и методов).

Да и setmetatable позволяет, элегантнее что-ли, автоматизировать заполнение lvtab.

 

 

 

@Clayman, сорри. Я не правильно понял задачу. Прочитал ещё раз внимательнее.

Ведь нужно при каждом вызове функции обновлять данные для определенной локации?

Тогда никаких внешних таблиц не нужно. Все проще, и ещё малость быстрее.

function GetLevelsVertexes(level)    local t = {}    local i = 0    local graph = game_graph()    local sim = alife()    while graph:valid_vertex_id(i) do        local v = graph:vertex(i)        local ln = sim:level_name(v:level_id())        if ln == level then            t[#t+1] = v:level_vertex_id()        end        i = i+1    end    return tend

 

 

Изменено пользователем BFG

  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 2
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Последние оставшиеся уроки от Wo1fRam, которые он не удалил. Бэкап с закрытой ныне темы.

 

Перенос моделей артефактов из ЧН/ЗП в ТЧ

 

 

 

Перенос моделей артефактов из ЧН/ЗП в ТЧ и обратно.

 

Автор: Wo1fRam.

 

Вступление.

Наверное, многие задавались вопросом «А как же перенести модель артефакта из ЧН/ЗП в ТЧ?». Или наоборот, может некоторым новые модели артефактов в ЧН/ЗП не нравятся, и они хотят их заменить на более привычные из ТЧ. Некоторые разобрались и сделали (и не рассказывают, жабы), некоторые пытаются что-то мудрить в 3d редакторах, а некоторые вообще не знают что делать и при этом говорят другим, что такое невозможно. Ещё как возможно! Сначала я тупо перетащил модель из ЗП в ТЧ, но получил вылет. Потом я, не на что особо не надеясь, попробовал перенести через СДК. И, к моему удивлению, всё заработало! Итак,

 

нам понадобятся:

1. X-Ray SDK 0.4 (или 0.5/0.7, если переносите из ТЧ в ЧН/ЗП)

2. Настроенный конвертер Бардака.

3. Распакованные файлы ТЧ и ЧН/ЗП.

 

Начнём, пожалуй.

Давайте сперва определимся, модель какого артефакта мы хотим перенести. Я решил перенести «Каменный цветок» из ЗП в ТЧ. При небольшом знании английского языка, модель найти достаточно легко. Она находится в директорииgamedata\meshes\dynamics\artefacts и называется af_cristall_flower.ogf. Копируем её в папку с конвертером Бардака (у меня это папка level_editor). Нам нужно преобразовать модель в формат .object. Создаём батник с таким кодом:

 

converter -ogf -object af_cristall_flower.ogf

pause

 

Запускаем батник, ждём долю секунды и видим в папке свежесозданный файл af_cristall_flower.object.

 

Запускаем ActorEditor и подгружаем в него этот файл. Если ругается на недостающие текстуры – возьмите их из ЧН/ЗП и добавьте в свою геймдату. Теперь нажимаем File-->Export-->Export OGF... и сохраняем модель. Вообще, чтобы в дальнейшем не париться с переносом конфига, а, следовательно, чтобы было легче адаптировать модель артефакта для любого мода на ТЧ, надо задать модели то имя, которое имеет стандартная модель. Только в ТЧ модели артефактов как-то странно названы. Но можно поглядеть в файле gamedata\config\misc\artefacts.ltx. Там нас тоже спасёт небольшое знание «инглиша». В случае с «Каменным цветком», имя секции в конфиге будет, как ни странно, [af_cristall_flower], а путь к модели:

 

visual                                      = physics\anomaly\artefact_blackdrip_2.ogf

 

Следовательно, сохраняем модель в директорию <gamedata вашего мода>\meshes\physics\anomaly\ под именемartefact_blackdrip_2.ogf. Если вы задали своё имя, то пропишите его в конфиге вместо оригинального. Естественно, тогда придётся копировать к себе ещё и конфиг.

 

Вот и всё!

Теперь дело за малым: протестировать. 

Примечание:

Модели артефактов из ТЧ в ЧН/ЗП переносятся точно так же, только с использованием соответствующего СДК.

 

© Wo1fRam

При размещении на различных сайтах и форумах не забывайте указывать автора.

 

 

Создание тайников в Зове Припяти

 

 

КАК СОЗДАТЬ СВОЙ ТАЙНИК

в Зове Припяти

Автор: Wo1fRam

 

От автора:
Подобные уроки не раз встречались на различных форумах и на сталкерине. Но, они были какими-то сухими. Это вставить туда, это сюда... А зачем, почему, что это даст?.. Кто на эти вопросы ответит? В данном туторе я попытался объяснить всё как можно подробнее.

 

Внимание!
Данный тутор рассчитан на тех, кто имеет представление о работе в X-Ray SDK, а именно: работа со спавн-элементами, компиляция спавна.

 

Инструменты и оборудование:
1. Настроенный X-Ray SDK 0.7.
2. Файлы: configs\misc\secret_zaton.ltx
2. Прямые руки и голова (желательно с мозгами внутри  :) ).

 

Вступление:
В ЗП система тайников была сильно переработана. Это не бездонный рюкзак, в который может поместиться сколько угодно вещей. Это просто лежащие в укромном местечке предметы, при поднятии которых появляется сообщение «Найден тайник».
Такой тайник сделать очень просто при наличии вышеперечисленных инструментов. Ковыряние all.spawn мы разбирать не будем, поскольку это уже «прошлый век».

 

Работа:
Итак, открываем в СДК, к примеру, Затон. Ищем место, где хотим сделать тайник. Спавним предметы (например, калаш, 3 пачки патронов к нему, аптечку и бутылку водки). Затем выделяем их и в графе “Custom Data” пишем:

 

[secret]
name = zat_hiding_place_my

 

Здесь [secret] – это секция, указывающая на то, что эти вещи являются тайником; zat_hiding_place_my – имя нашего тайника.
И не забудьте в свойствах предметов снять галочки с параметров “Used AI locations”, “Useful for AI” и “Visible for AI”. Это нужно, чтобы предметы появились в нужном месте и чтобы их никто не спионерил.

Также рядом с тайником нужно разместить спейс-рестриктор. Имя его должно быть zat_hiding_place_my, то есть которое мы указали в свойствах предметов. В “Custom Data” пишем следующее:

 

[secret]
cfg = misc\secret_zaton.ltx

 

Здесь [secret] – секция, указывающая на то, что этот рестриктор контролирует тайник; cfg = misc\secret_zaton.ltx – ссылка на файл с описанием тайника.
Также снимаем галочку с параметра “Used AI locations”, чтобы рестриктор мог находиться вне АИ-сетки, и ставим тип рестриктора “NOT A restrictor”.

Всё, работа в СДК закончена. Сохраняем, компилируем спавн.

 

Теперь перейдём к настройке конфигов. Помните, мы в свойствах рестриктора писали ссылку на файл? Так вот, открываем этот файл (configs\misc\secret_zaton.ltx) и в конце секции [list_zaton] пишем имя нашего тайника: zat_hiding_place_my. Это мы зарегистрировали наш тайник. Теперь создадим его описание. Для этого в самом конце файла создадим следующую секцию:

 

[zat_hiding_place_my]
wpn_ak74 = 1, 1
ammo_5.45x39_fmj = 3, 1
medkit = 1, 1
vodka = 1, 1

 

Теперь разберёмся что к чему: в квадратных скобках написано название тайника; wpn_ak74 – это предмет (в данном случае калаш); первое число – количество предметов; второе – я так и не понял зачем оно нужно, поэтому лучше писать 1).

 

Вот и всё. Сохраняем изменения и бежим тестировать!

 

 

Изменено пользователем HellRatz

  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 7

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

второе – я так и не понял зачем оно нужно, поэтому лучше писать 1).

ИМХО, это вероятность (в данном случае 100-процентная) выпадения этого предмета...

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Atin   

Создание LOD динамических объектов.

 

От себя дополню, хоть и запоздало.

 

Суть создания LOD (level of detail - уровень детализации) заключается в снижении триангуляжа/полигонажа модели.

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

 

Нюансы по созданию LOD`ов:

1. LOD должен быть минимум в два раза легче, чем оригинальная модель. Каждый последующий LOD так же должен быть легче предыдущего в два раза или больше. Пример: оригинал домика 6000 треугольников; LOD1 3000; LOD2 1500; LOD3 750; LOD4 100 (так как расстояние уже большое и можно хоть коробкой делать).

 

2. Основной задачей LOD`а является сохранение приемлемого внешнего вида на дистанции, но с хорошей оптимизацией. Важно осознавать на какой дистанции будет вестись переключение LOD`ов. При создании LOD`а крайне важно не искажать крупные формы объекта, чтобы не было видно тех самых переключений, которые будут бросаться в глаза, когда LOD сильно отличается по форме от оригинала. Лёгкие искажения допустимы.

 

3. Сокращение числа полигонов/трианглов нужно вести от мелких элементов к крупным. На дальних LOD`ах можно мелкие элементы удалять вовсе (дверные петли, ручки и прочее). Чтобы не рисковать запороть LOD удалением мелких элементов стоит делать дубликат и сначала не удалять элементы, а просто их скрыть и свериться, если нормально, то удалять совсем.

 

4. Хорошим приёмом будет прямо в 3D max выставлять LOD`ы по дистанции переключения и смотреть не сильно ли бросается в глаза их низкая детализация. Выравниваем оригинал по LOD`у (который, к примеру, на 15 метрах от нуля) и смотрим из камеры на нулевой точке; включаем/выключаем оригинал и определяем не сильно ли бросаются в глаза искажения основных форм объекта.

 

5. Самый дальний LOD с простейшей формой называется Impostor. Обычно это или скрещенные плейны или коробка.

 

 

 

Пока такой список навскидку получился.

Изменено пользователем HellRatz

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 2
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 2

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Serge!   

Учим ТЧ русскому языку.

Сложность: Легко

Файлы: ui_save_dialog.script и ui_mm_save_dlg.xml

 

Сначала проделаем маленькую, но необходимую работу. Нам надо в окне диалога определить индикатор текущего языка ввода. Для этого открываем файл ui_mm_save_dlg.xml и в конец тега form добавим строчки, чтобы получилось так:

        <st_lang x="280" y="400" width="30" height="20">
            <text font="graffiti22" align="c" />
            <text_color> <e r="227" g="199" b="178"/> <h r="255" g="0" b="0"/> </text_color>
        </st_lang>
    </form>
Закрываем файл. Он нам больше не понадобится.

В отдельном файле (например, ui_save_dlg_rus.script) создаем таблицу перекодировки. Это массив ключами которого являются коды печатных символов английского алфавита, а значениями - соответствующие им коды криллицы. Выглятит она следующим образом:

local tbl_lang = {
[034] = 221,	-- " --> Э
[039] = 253,	-- ' --> э
[044] = 225,	-- , --> б
... 		-- и т.д.
}
local tbl_ansii = {
	[ 039 ] = 253, -- ' --> э
	[ 044 ] = 225, -- , --> б
	[ 046 ] = 254, -- . --> ю
	[ 047 ] = 046, -- / --> .
	[ 058 ] = 198, -- : --> Ж
	[ 059 ] = 230, -- ; --> ж
	[ 060 ] = 193, -- < --> Б
	[ 062 ] = 222, -- > --> Ю
	[ 065 ] = 212, -- A --> Ф
	[ 066 ] = 200, -- B --> И
	[ 067 ] = 209, -- C --> С
	[ 068 ] = 194, -- D --> В
	[ 069 ] = 211, -- E --> У
	[ 070 ] = 192, -- F --> А
	[ 071 ] = 207, -- G --> П
	[ 072 ] = 208, -- H --> Р
	[ 073 ] = 216, -- I --> Ш
	[ 074 ] = 206, -- J --> О
	[ 075 ] = 203, -- K --> Л
	[ 076 ] = 196, -- L --> Д
	[ 077 ] = 220, -- M --> Ь
	[ 078 ] = 210, -- N --> Т
	[ 079 ] = 217, -- O --> Щ
	[ 080 ] = 199, -- P --> З
	[ 081 ] = 201, -- Q --> Й
	[ 082 ] = 202, -- R --> К
	[ 083 ] = 219, -- S --> Ы
	[ 084 ] = 197, -- T --> Е
	[ 085 ] = 195, -- U --> Г
	[ 086 ] = 204, -- V --> М
	[ 087 ] = 214, -- W --> Ц
	[ 088 ] = 215, -- X --> Ч
	[ 089 ] = 205, -- Y --> Н
	[ 090 ] = 223, -- Z --> Я
	[ 091 ] = 245, -- [ --> х
	[ 093 ] = 250, -- ] --> ъ
	[ 097 ] = 244, -- a --> ф
	[ 098 ] = 232, -- b --> и
	[ 099 ] = 241, -- c --> с
	[ 100 ] = 226, -- d --> в
	[ 101 ] = 243, -- e --> у
	[ 102 ] = 224, -- f --> а
	[ 103 ] = 239, -- g --> п
	[ 104 ] = 240, -- h --> р
	[ 105 ] = 248, -- i --> ш
	[ 106 ] = 238, -- j --> о
	[ 107 ] = 235, -- k --> л
	[ 108 ] = 228, -- l --> д
	[ 109 ] = 252, -- m --> ь
	[ 110 ] = 242, -- n --> т
	[ 111 ] = 249, -- o --> щ
	[ 112 ] = 231, -- p --> з
	[ 113 ] = 233, -- q --> й
	[ 114 ] = 234, -- r --> к
	[ 115 ] = 251, -- s --> ы
	[ 116 ] = 229, -- t --> е
	[ 117 ] = 227, -- u --> г
	[ 118 ] = 236, -- v --> м
	[ 119 ] = 246, -- w --> ц
	[ 120 ] = 247, -- x --> ч
	[ 121 ] = 237, -- y --> н
	[ 122 ] = 255, -- z --> я
	[ 123 ] = 213, -- { --> Х
	[ 125 ] = 218, -- } --> Ъ
}

Теперь основное. Возможны два варианта решения задачи руссификации. Мы рассмотрим их оба.

 

Первый.

Это упрощённый вариант, который тем не менее вполне устроит подавляющее число пользователей.

Преимущества: очень простая реализация с минимальными правками дистрибутивных скриптов. Решается стандартными средствами Lua и не требуется никаких дополнительный функций и внешних скриптов (кроме таблицы перекодировки)

Недостатки: Ввод смешанного текста хоть и допускается, но при этом полностью теряется возможность корректировки введённого текста. При вводе однородного текста - корректировка корректна.

 

Открываем в редакторе файл ui_save_dialog.script.

1. Вверху, сразу под комментариями описания, определяем переменную подключающую таблицу перекодировки:

local t_lang = ui_save_dlg_rus.tbl_ansii
2. Создадим индикатор текущего языка ввода текста.

Договоримся, что переключать раскладку будем щелчком левой кнопки мыши по индикатору или клавишей левый-Ctrl (причем она бутет работать как тригер), а перевключать режим временного изменения языка ввода будем при нажатой и удерживаемой клавише левый-Alt.

Для этого в методе save_dialog:InitControls() в самом конце вставим:

self.ind_lan = xml:Init3tButton("form:st_lang", self.form)
self:Register(self.ind_lan, "button_lang")
self.ind_lan:SetText("Рус")
self.mode_lang = true
Где: self.mode_lang - флаг текущего языка ввода (true - русский, false - английский)

 

Таким образом индикатор режима ввода мы создали, теперь надо обеспечить его функционирование.

Для этого в функцию InitCallBacks() вставим строку

self:AddCallback("button_lang", ui_events.BUTTON_CLICKED, self.OnChg_lan, self)
а под блоком вставляем функцию:

function save_dialog:OnChg_lan()
    self.mode_lang = not self.mode_lang
    if self.mode_lang then self.ind_lang:SetText("Рус")
    else self.ind_lang:SetText("Eng") end
end

Здесь всё янсно - сначала инвертируем флаг текущего языка ввода и потом меняем текст индикатора.

 

Далее функцию function save_dialog:OnKeyboard(dik, keyboard_action), в конец условного блока (перед end), добавляем строки:

    elseif keyboard_action == ui_events.WINDOW_KEY_PRESSED then		-- вызываются на нажатие клавиши
        if dik == DIK_keys.DIK_LCONTROL or dik == DIK_keys.DIK_LMENU then
            self:OnChg_lan()
        end
    elseif keyboard_action == ui_events.WINDOW_KEY_RELEASED then	-- вызываются на отпускание клавиши
        if dik == DIK_keys.DIK_LMENU then
            self:OnChg_lan()
        end
3. Чтобы отслеживать изменения в поле редактирования и проводить перекодировку введенного теста, в функцию InitCallBacks() дабавим строку:

    self:AddCallback("edit_filename",  ui_events.EDIT_TEXT_CHANGED,  self.OnEdit_CHANGED, self)
Теперь надо, чтобы это отработало. Для этого под функцией save_dialog:OnChg_lan() вставляем еще одну свою ффункцию:

function save_dialog:OnEdit_CHANGED()
    if self.mode_lang then					-- /1
        local str_edit = self:GetEditBox("edit_filename")	-- /2
        local txt, copy_txt, cls = str_edit:GetText(), ""	-- /3
        for n = 1, txt:len() do
            cls = txt:byte(n)								-- /4
            if t_lang[cls] ~= nil then copy_txt = copy_txt..string.char(t_lang[cls])	-- /5
            else copy_txt = copy_txt..string.char(cls) end				-- /6
        end
        str_edit:SetText(copy_txt)							-- /7
    end
end
Рассмотрим построчно, что эта функция делает:

- проверяем установлен ли флаг ввода кириллицы (1)

- если установлен, то подключаем окно поля редактирования (2)

- получаем строку введенного текста и инициализируем переменную для её копии (3)

- в цикле получаем код каждого символа строки ввода (4)

- ищем в таблице перекодировки соответствующий русский символ (стандартный ввод всегда английский) и если находим, то заменяем     английский символ на русский (5)

- если же не находим, то оставляем исходный (6)

- возвращаем строку в поле редактирования (7)

 

На этом всё. Данный алгоритм, с учетом отмеченных выше ограничений, вполне стабильно работает на всех модах платформы ТЧ, в которые я играл.

 

 

 

Все необходимые откорректированные файлы этого урока будут доступны через сутки от даты публикации в течении месяца здесь:

https://yadi.sk/d/UAn5jdKRjUmrz

Второй вариант реализации этой же задачи мы рассмотрим в следующем уроке.


  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 3

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Очень бы хотелось, чтобы пользователи проверяли функции или скрипты, которые они выклыдавают.

function название функции(actor, npc)

dialogs.relocate_money(npc,количество,"out")
end

 


  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1
  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/thumb.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Serge!   

Учим ТЧ русскому языку (продолжение).

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

function save_dialog:OnEdit_CHANGED()
    local str_edit = self:GetEditBox("edit_filename")
    local txt = str_edit:GetText()
    txt = txt:gsub(".$", function(ch)
        local _ch = t_lang[ch:byte()]
        return _ch and string.char(_ch) or ch
        end)
    str_edit:SetText(txt)
end

Какой из вариантов Вас больше устраивает, определитесь самостоятельно, ну а мы идём дальше.

Всё, что в первом уроке было написано до подзаголовка «Первый» остаётся в силе с одним замечанием.
В таблице перекодировки, ссылка на которую дана в первом уроке, отсутствует пара символов. Добавьте их самостоятельно в самое начало таблицы.

[034] = 221,	-- " --> Э
[035] = 185,	-- # --> №

Второй.
На первом уроке мы научились вводить символы кириллицы в поле EditBox. Однако наш вариант имел существенный недостаток – в нём отсутствовала возможность корректного исправления текста вводимой строки. Давайте попробуем это исправить.
Рассмотрим все возможные операции при корректировке:
1 - добавление символа в конец строки;
2 - удаление последнего введенного символа;
3 – перемещение по строке влево/вправо;
4 – вставка символа в позиции курсора в середине строки;
5 – удаление символа в позиции курсора в середине строки;
6 - удаление символа перед позицией курсора в середине строки.

Большую часть этих операций движок замечательно проделывает сам и нам остаётся только отслеживать результат его работы и учитывать его. А вот две операции требуют нашего активного вмешательства: это 2 и 4, которые связаны с вводом новых символов.

1. Добавим две новых переменных к той, что была определена в п. 1 первого урока:

local edb_Pos, edb_Str =  1, {}

Где: edb_Pos – позиция курсора в поле EditBox (инициируется 1) и edb_Str – массив, в котором мы будем сохранять символы вводимого текста.

2. В пункте 2 (урока 1) менять ничего не требуется, поэтому берем его, целиком как есть, а вот пункт 3 подлежит коренной реконструкции.

3. Так как мы решили, что все события производимые пользователем в поле EditBox будем контролировать сами, то первым делом отключаем прерывание генерируемое движком при изменении поля. Для этого в функции save_dialog:InitCallBacks() удаляем добавленную нами в первом уроке строку:

self:AddCallback("edit_filename",  ui_events.EDIT_TEXT_CHANGED,  self.OnEdit_CHANGED, self)

Саму нашу функцию save_dialog:OnEdit_CHANGED() пока не трогаем.
Далее пойдём от простого к более сложному. Простое - это отследить те моменты, которые мы договорились отдать на откуп самому движку, т.е. перемещение по строке и удаление. Делать это будем в функции save_dialog:OnKeyboard(dik, keyboard_action). Для этого добавляем в неё, после уже вставленных нами ранее (в 1 уроке) несколько дополнительных строк, чтобы в итоге получилось так:

    if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
        if dik == DIK_keys.DIK_LCONTROL or dik == DIK_keys.DIK_LMENU then
            self: OnChg_lan()
        elseif dik == DIK_keys.DIK_LEFT then
            if edb_Pos > 1 then edb_Pos = edb_Pos - 1 end
        elseif dik == DIK_keys.DIK_RIGHT then
            if edb_Pos <= #edb_Str then edb_Pos = edb_Pos + 1 end
        elseif dik == DIK_keys.DIK_DELETE then
            if edb_Pos <= #edb_Str then table.remove(edb_Str,edb_Pos) end
        elseif dik == DIK_keys.DIK_BACK then
            if edb_Pos > 1 then edb_Pos = edb_Pos-1 end
            table.remove(edb_Str,edb_Pos)
        elseif (dik > 1   and dik <= 13) or 
               (dik >= 16 and dik <= 27) or 
               (dik >= 30 and dik <= 40) or
               (dik >= 44 and dik <= 53) or
                dik == 57 or 
               (dik >= 71 and dik <= 83) then self:OnEdit_CHANGED()
        end

Здесь всё достаточно просто. При перемещении стрелками проверяем новое положение курсора и, если оно в пределах строки, то запоминаем его позицию. При удалении символа из строки удаляем соответствующий элемент из массива копии строки и опять же запоминаем текущую позицию ввода.
Теперь осталось только разобрать со вставкой символа. Для этого отлавливаются прерывания от всех клавиш с печатными символами и, если такое обнаружено, то вызывается функция обработчик, т.е. наша OnEdit_CHANGED(). Обратите внимание, что мы даже не пытаемся отловить ввод буквы ‘ё’, т.к. на этой же клавише размещена тильда ‘~’, которую движок обрабатывает специальным образом для вывода окна консоли.
И так, если мы зафиксировали факт нажатия клавиши с печатным символом, то вызываем OnEdit_CHANGED(), которая теперь не привязана к сообщениям от движка и находится под полным нашим контролем. Вот этим контролем и займёмся.

Убираем в ней все содержимое и вставляем новое. Должно получиться следующее:

function save_dialog:OnEdit_CHANGED()
    local str_edit = self:GetEditBox("edit_filename") 	-- /1
    local sim = str_edit:GetText():match ('.', edb_Pos) -- /2
    local cls = self.mode_lang and t_lang[sim:byte()]	-- /3
    sim = cls and string.char(cls) or sim		-- /4
    table.insert(edb_Str, edb_Pos, sim)			-- /5
    edb_Pos = #edb_Str + 1				-- /6
    str_edit:SetText(table.concat(edb_Str))		-- /7
end

Здесь тоже нет особых сложностей, но, тем не менее, прокомментируем наши действия.
Подключаемся к контролу EditBox (1) и получаем символ, находящийся в текущей позиции ввода (2). Если включен режим кириллицы, то ищем код переданного движком символа (он всегда английский) в таблице перекодировки и при его наличии получаем соответствующий код русского символа (3). Если код найден, то подменяем английский символ русским, а если нет, то оставляем всё как есть (4). Заносим полученный символ в массив копии строки ввода в соответствии со значение текущей позиции курсора (5). Устанавливаем новую текущую позиции ввода (6), преобразуем массив символов в строку и возвращаем её в поле ввода (7).

Если Вы всё проделами правильно, то теперь можете вводить имя сохраняемого файла в английской, русской или смешанной кодировке, а также корректировать вводимый текст без искажения его синтаксиса.

Послесловие:
Этот алгоритм имеет отличие от стандартной обработки строки редактирования, которое выражается в том, что при вставке символа в середину строки, позиции ввода следующего символа всегда устанавливается в её конец, тогда как в “штатной” – текущей становится следующая позиция. В этой ситуации есть свой плюс и свой минус, однако в любом случае, как побороть это, я просто не знаю.

 


  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 4

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Как лечить раненных НПС-врагов
Сложность: оч. легко
Совместимость с модами: легко совместимо
Многие люди в своих модификациях хотят добавить возможность лечить раненных врагов, как, например, в Солянке. Я тоже однажды заинтересовался этим вопросом и, не найдя на него ответа в интернете, занялся решением проблемы сам. В итоге мне это удалось и теперь выкладываю плоды своих стараний на просторы интернета :) .


Запрет диалога с раненными противниками находится в файле xr_wounded.script, и выглядит так (я снабдил его комментариями, если вы не сильно шарите в скриптах):

	if self.object:relation(db.actor) == game_object.enemy then --если отношение НПС к ГГ = отношению к врагум
		self.object:disable_talk() --блокировать диалоги
	else --иначе 
		self.object:enable_talk() --разрешить диалог
	end --конец условия (if)

Дабы позволить ГГ говорить с врагами (только раненными) достаточно удалить лишнее и оставить всего одну строку:

		self.object:enable_talk() 

Но! Если ГГ попробует обратиться к раненным представителям бандитов, монолитовцев, наёмников, зомби (возможно), военных или противников на Арене - скорее всего произойдёт Фатал Еррор с логом на отсутствие подходящей фразы для диалога (в оригинальной игре с вероятностью 99%). Так вот, лично для себя я нашёл простое решение, которое подходило и по концепции моего мода - запретить диалог с данными группировками. Вот таким макаром:

	local comm = self.object:character_community() --переменной обозначил "понятие" группировки обьекта (НПС)
	if comm == "zombied" or  --если НПС - зомби, или
	comm == "bandit" or  --НПС - бандит, или
	comm == "monolith" or  --НПС - монолитовец, или
	comm == "arena_enemy" or  --НПС - боец арены, или
	comm == "killer" or  --НПС - наёмник, или
	comm == "military" then  --НПС - вояка, тогда
		self.object:disable_talk()  --запретить диалог
	else  -- иначе
		self.object:enable_talk()  --разрешить диалог
	end  -- The End!

просто заменить изначальные строки этими и теперь ГГ сможет лечить врагов одиночек, долговцев, свободовцев и учёных.
Но есть ещё один момент. При лечении врагов, если всё сделать как было написано будет ещё одна проблемка - они так и останутся врагами после лечения и будут дальше атаковать ГГ.
Разумно было бы сделать НПС если не другом, то по крайней мере нейтралом. Для этого необходимо в файле dialogs.script кусок скрипта

        if second_speaker:relation(first_speaker) ~= game_object.enemy then
		second_speaker:set_relation(game_object.friend, first_speaker)
	end
		first_speaker:change_character_reputation(10);
	end

заменить на

	if second_speaker:relation(first_speaker) == game_object.enemy then
		second_speaker:set_relation(game_object.friend, first_speaker)
		first_speaker:set_relation(game_object.friend, second_speaker)
	end
	        first_speaker:change_character_reputation(10);
        end

Всё! ;)


Да и уже готовый файл xr_wounded.script и dialogs.script со всеми описанными правками прилагается https://yadi.sk/d/-ZEwRBo7kPwCP.

Как сделать костюм с системой автолечения (изначально для ТЧ)
Сложность: легко
Совместимость с модами: придётся поработать <_< 
Подобную схему делал для своего мода, теперь выкладываю здесь ее аналог, мало мальски продуманный для оригинального ТЧ:

Принцип работы
Функция (скрипт), указанная в бинд_сталкер.скрипт (кто не знает что это - загуглите :)) выполняется движком несколько раз в секунду. Задача функции - проверять одет ли на ГГ нужный костюм, сколько у ГГ здоровья и если здоровья мало - использовать медикаменты (если у ГГ они есть, разумеется). Вот и всё!
Порядок работы (для оригинального ТЧ)
Создаём новый костюм. Можно конечно и для существующего прописать всё, но лучше потратить на минутку больше и сделать качественнее. 
В файл gamedata/config/misc/unique_items.ltx в конец добавляем новую секцию:

[outfit_stalker_m3]:stalker_outfit			;Комбез с системой автоприёма медикаментов
$spawn							= "outfit\uniq\outfit_stalker_m3"
inv_name						= stalker_outfit_name_m3
inv_name_short						= stalker_outfit_name_m3
description						= stalker_outfit_description_m3 
inv_grid_x						 = 16
inv_grid_y						 = 24 

В файл gamedata/config/text/rus/string_table_outfit.xml в конец перед тэгом </string_table> дописываем:

	<string id="stalker_outfit_name_m3">
		<text>Прототип мед. комбинезона</text>
	</string>
	<string id="stalker_outfit_description_m3">
		<text>Данный образец является прототипом защитного комбинезона сталкера. От оригинала он отличается наличием уникальной системы приёма медикаментов. Если здоровье хозяина опуститься ниже 20% будет автоматически использован мед. препарат.</text>
	</string> 

 
Делаем схему рабочей
В файле bind_stalker.script под строкой function actor_binder:update(delta) пишем med_outfit.main() --лечащий костюм, примерно так (таким образом мы будем вызывать наш будущий скрипт несколько раз в секунду):

	function actor_binder:update(delta)
	med_outfit.main() --Лечащий костюм 

Создаём файл med_outfit.script в соответствующей папке и в сам файл пишем:

function main() 
local medkit = db.actor:object("medkit") 
local medkit_army = db.actor:object("medkit_army") 
local medkit_scientic = db.actor:object("medkit_scientic") 
local outfit = db.actor:item_in_slot(6) --определяем предмет в слоте 6 (костюм)
local snd = sound_object([[device/pda/pda_tip]]) --звук сообщения
if outfit and outfit:section() == "outfit_stalker_m3" and db.actor.health < 0.20 and db.actor.health > 0.005 then
  if medkit then  
	db.actor:eat(medkit)
	snd:play_no_feedback(db.actor,sound_object.s2d, 0, vector():set(0, 0, 0), 1)
	db.actor:give_game_news("\n%c[255,255,0,0]Была автоматически использована аптечка.", "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 2000) 
	elseif medkit_army then
	db.actor:eat(medkit_army)
	snd:play_no_feedback(db.actor,sound_object.s2d, 0, vector():set(0, 0, 0), 1)
	db.actor:give_game_news("\n%c[255,255,0,0]Была автоматически использована армейская аптечка.", "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 2000) 
	elseif medkit_scientic then
	db.actor:eat(medkit_scientic)
	snd:play_no_feedback(db.actor,sound_object.s2d, 0, vector():set(0, 0, 0), 1)
	db.actor:give_game_news("\n%c[255,255,0,0]Была автоматически использована научная аптечка.", "ui\\ui_iconsTotal", Frect():set(0,0,83,47), 1, 2000)
  end
end 
end

Теперь если ХП у актёра меньше 20%, одет нужный костюм и есть аптечка - она автоматически используется.
Чтобы Волк выдал его в начале игры в файле escape_dialog.script в функции give_weapon_to_actor допишем:

    dialogs.relocate_item_section(trader, "outfit_stalker_m3", "in") 

Готово, можно тестировать!

 

Изменено пользователем HellRatz

  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 2
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 3

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

1. В выложенном dialogs.script ничего не исправлено. 

2. Выложенный dialogs.script сильно отличается от оригинала ЗП 1.6.02

Всё там исправлено. Готовые файлы сделаны на основе ТЧ.


  • http://www.amk-team.ru/forum/uploads//ratings/bf.gif × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах
Forser   

Реализация хита артефактов из инвентаря, слотов и пояса.

 

Сложность: средняя

Платформа: проверялось на SoC

Требование: наличие исходников движка и базовые знания работы в MVS 2005 и выше.

 

И так, открывает Actor.cpp из состава xrGame и ищем метод HitArtefactsOnBelt

и UpdateArtefactsOnBelt, а в них строки:

for(TIItemContainer::iterator it = inventory().m_belt.begin(); 		inventory().m_belt.end() != it; ++it)
И меняем m_belt на m_all.

P.S. Есть хотим, чтоб хит выдавался только из рюкзака, то в HitArtefactsOnBelt, в место m_belt, пишим m_ruck. (Не проверял, только догадка)

 

Изменено пользователем Forser

  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/spellcheck.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Решил я как то заспавнить скриптом машинку в Зов Припяти, машинка за спавнилась, но физики нет у машинки. Начал ковырять, ковырял, ковырял, и понял что нет класса SCRPTCAR.

Восстанавливаем класс SCRPTCAR.

cs_register(object_factory, "CCar", "se_car.se_car", "SCRPTCAR", "car_s")

 

Это добавляем после hanging_lamp

Серверный объект.

---------------------------------------------------------------------
class "se_car" (cse_alife_car)
--------------------
function se_car:__init (section) super (section)
--log("_bp: set_car:__init")
self.ini = nil
self.spawner_present = false
end
--------------------
function se_car:can_switch_offline ()
return cse_alife_car.can_switch_offline(self)
end
--------------------
function se_car:can_switch_online ()
if not self.ini then
self.ini = self:spawn_ini()
self.spawner_present = self.ini:section_exist("spawner")
end
if self.ini == nil or self.spawner_present == false then
return cse_alife_car.can_switch_online(self)
end
return xr_spawner.check_spawn(self)
end
--------------------

 

Ещё желательно надо добавить файл ph_car.script из мода GLADIATORII

Или ещё проще, задать класс C_NIVA. Нива если кто помнит первая машинка из древних билдов.

В общем, как то так.

Изменено пользователем Kirgudu

Добавлено Kirgudu,

Перенёс из «Ковырялки ТЧ»


  • http://www.amk-team.ru/forum/uploads//ratings/thumb_up.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/thumb.png × 1
  • http://www.amk-team.ru/forum/uploads//ratings/wrench_orange.png × 1

Поделиться этим сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или авторизуйтесь, чтобы оставить комментарий

Комментарии могут оставлять только зарегистрированные пользователи

Создать аккаунт

Зарегистрировать новый аккаунт в нашем сообществе. Это несложно!

Зарегистрировать новый аккаунт

Войти

Есть аккаунт? Войти.

Войти

  • Недавно просматривали   0 пользователей

    Ни один зарегистрированный пользователь не просматривает эту страницу.

×