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

Уроки по модостроению


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

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

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

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", и копируем, повторяем эту процедуру со всеми остальными файлами.
Вроде Все, заходим в игру и радуемся. Удачи.

 

  • Нравится 1
  • Сомнительно 1

ba9599747b.png  36914dd0ee.png

Ссылка на комментарий
Решил создать гайд по спавну через программу 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
  • Спасибо 2
  • Нравится 1

NL-Vincenz.gif

Ссылка на комментарий

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

 

[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
  • Нравится 4
Ссылка на комментарий

@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
  • Нравится 2
  • Полезно 2
Ссылка на комментарий

 

 

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

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

Ссылка на комментарий

Создание 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
  • Спасибо 2
  • Полезно 2
Ссылка на комментарий

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

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

Файлы: 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

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

  • Полезно 3
Ссылка на комментарий

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

 

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

Платформа: проверялось на 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
  • Полезно 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,

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

  • Нравится 1
  • Не нравится 1
  • Полезно 1

...в конце концов, важен лишь, машинный код.

СТАЛКЕР только для ПК!

Ссылка на комментарий

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

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

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

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

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

Войти

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

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

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