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

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


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

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

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

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

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

 

[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 пользователей

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