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

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


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


7-icon-d6949c2e87c4f53ebe9e144c56bd549c.___31-icon-160a560baabc6dadb18a21e53978b1fd___ 50-icon-a62970b61b25e77f0b79bb2b3ffb0ab6

 



Тема не для общения.

Сообщения оставлять только с уроками в таком же формате.

Предложения и замечания пишем в личку авторов уроков.
С вопросами - в тему ковырялок: [soC], [CS], [CoP].

Изменено пользователем HellRatz
Ссылка на комментарий

Для начала нужно создать диалог, сделаем его у Волка:


Заходим в gamedata\config\gameplay\dialogs_escape.xml и в самом конце до строчки </game_dialogs> пишем:
<dialog id="escape_volk_ak74u_quest">
    <has_info>esc_kill_bandits_quest_done</has_info>
    <dont_has_info>escape_volk_ak74u_start</dont_has_info>
    <phrase_list>
        <phrase id="0">
            <text>escape_volk_ak74u_quest_0</text>
            <next>1</next>
        </phrase>
        <phrase id="1">
            <text>escape_volk_ak74u_quest_1</text>
            <next>2</next>
            <next>3</next>
        </phrase>
        <phrase id="2">
            <text>escape_volk_ak74u_quest_2</text>
            <give_info>escape_volk_ak74u_start</give_info>
            <action>new_life.spawn_ak74u</action>
        </phrase>
        <phrase id="3">
            <text>escape_volk_ak74u_quest_3</text>
            <action>dialogs.break_dialog</action>
        </phrase>
    </phrase_list>
</dialog>

<dialog id="escape_volk_ak74u_quest_completed">
    <precondition>new_life.escape_volk_ak74u_have</precondition>
    <has_info>escape_volk_ak74u_have</has_info>
    <dont_has_info>escape_volk_ак74u_done</dont_has_info>
    <phrase_list>
        <phrase id="0">
            <text>escape_volk_ak74u_quest_completed_0</text>
            <next>1</next>
        </phrase>
        <phrase id="1">
            <text>escape_volk_ak74u_quest_completed_1</text>
            <next>2</next>
        </phrase>
        <phrase id="2">
            <text>escape_volk_ak74u_quest_completed_2</text>
            <give_info>escape_volk_ak74u_done</give_info>
            <action>new_life.give_volk_ak74u</action>
            <next>3</next>
        </phrase>
        <phrase id="3">
            <text>escape_volk_ak74u_quest_completed_3</text>
            <action>new_life.complete_volk_quest</action>
        </phrase>
    </phrase_list>
</dialog>

Теперь нужно прописать эти диалоги Волку, для этого заходим в gamedata\config\gameplay\character_desc_escape.xml и находим профиль Волка(он называется esc_wolf), перед строкой </specific_character> пишем:

<actor_dialog>escape_volk_ak74u_quest</actor_dialog>
<actor_dialog>escape_volk_ak74u_quest_completed</actor_dialog>

Нам понадобятся два диалога: 1 для получения квеста, 2 для передачи автомата.
<dialog id="escape_volk_ak74u_quest"> - Это название диалога
<has_info>esc_kill_bandits_quest_done</has_info> - эта строка означает что квест появится только если получен инфопоршень esc_kill_bandits_quest_done
<dont_has_info>escape_volk_ak74u_start</dont_has_info> - эта строка означает что если получен инфопоршень escape_volk_ak74u_start, то этот диалог больше не появится.
<text>escape_volk_ak74u_quest_0</text> - это ссылка на текст фразы меченого
<next>1</next> - это ссылка на текст с id= 1 , а id= 1 это <text>escape_volk_ak74u_quest_1</text> (ссылка на текст Волка)
<next>2</next>
<next>3</next>
- эти две строчки означают что идет разветвление диалога
<give_info>escape_volk_ak74u_start</give_info> - выдача инфопоршня, после которого начинается квест
<action>new_life.spawn_ak74u</action> - функция вызываемая из скрипта new_life, в данном случае спаунится предмет AK74У
<action>dialogs.break_dialog</action> - функция отвечающая за выход из диалога

Во втором диалоге есть строка <precondition>new_life.escape_volk_ak74u_have</precondition> - она отвечает за появление диалога если выполняется функция escape_volk_ak74u_have

Теперь нужно сделать текст диалога на русском языке, для этого заходим в gamedata\config\tex\rus\stable_dialogs_escape.xml и в нём пишем следующее(в конце перед </string_table>):

<string id="escape_volk_ak74u_quest_0">
    <text>Здорова Волк, для меня есть какая-нибудь работа?</text>
</string>
<string id="escape_volk_ak74u_quest_1">
    <text>Да, есть одно дело: вобщем шёл сюда в лагерь к Сидырычу, решил пройти через тоннель чтоб воякам денег не платить, а там собак было штук десять. Ну я начал отстреливаться, где-то шестерых убил и патроны кончились, пришлось АКСУ выкинуть, чтоб от стаи собак убежать. Таки лежит там наверно АКСУ. \nНу как, возьмёшься? Только осторожней там, после последнего выброса появились в тоннеле перещающиеся аномалии электра.</text>
</string>
<string id="escape_volk_ak74u_quest_2">
    <text>Да, я как раз буду рядом проходить, конечно принесу...</text>
</string>
<string id="escape_volk_ak74u_quest_3">
    <text>Нет, Волк, сам туда иди...</text>
</string>
<string id="escape_volk_ak74u_quest_completed_0">
    <text>Привет, Волк, ну как оно?...</text>
</string>
<string id="escape_volk_ak74u_quest_completed_1">
    <text>Сидор водку не даёт, хе хе, а так всё хорошо.</text>
</string>
<string id="escape_volk_ak74u_quest_completed_2">
    <text>Вот, нашел я твой АКСУ.</text>
</string>
<string id="escape_volk_ak74u_quest_completed_3">
    <text>Эх спасибо тебе Меченый, вот держи, может на что-нибудь хватит.</text>
</string>

Итак, диалог готов, теперь нужно сделать сам квест, для этого заходим в gamedata\config\gameplay\tasks_escape.xml и в самом конце пишем:

<game_task id="escape_volk_ak74u">
    <title>Найти потерянный АКСУ</title>
    <objective>
        <text>Найти потерянный АКСУ</text>
        <icon>ui_iconsTotal_weapons</icon>
        <infoportion_complete>escape_volk_ak74u_done</infoportion_complete>
        <article>tex_escape_volk_ak74u</article>
    </objective>
    <objective>
        <text>Найти АКСУ</text>
        <function_complete>new_life.escape_volk_ak74u_have</function_complete>
        <infoportion_set_complete>escape_volk_ak74u_have</infoportion_set_complete>
    </objective>
    <objective>
        <text>Принести АКСУ Волку</text>
        <map_location_type hint="Волк">blue_location</map_location_type>
        <object_story_id>Escape_novice_lager_volk</object_story_id>
        <infoportion_complete>escape_volk_ak74u_done</infoportion_complete>
    </objective>
</game_task>

<game_task id="escape_volk_ak74u"> - id квеста;
<title>Найти потерянный АКСУ</title> - название квеста;
<text>Найти потерянный АКСУ</text> - название подзадачи;
<icon>ui_iconsTotal_weapons</icon> - иконка задания;
<infoportion_complete>escape_volk_ak74u_done</infoportion_complete> - квест будет выполнен, если был получен инфопоршень escape_volk_ak74u_done;
<article>tex_escape_volk_ak74u</article> - ссылка на текстовый файл с описанием задания;
<text>Найти АКСУ</text> - название подзадачи;
<function_complete>new_life.escape_volk_ak74u_have</function_complete> - проверка на наличие предмета;
<infoportion_set_complete>escape_volk_ak74u_have</infoportion_set_complete> если функция new_life.escape_volk_ak74u_have выполнилась, то выдаётся инфопоршень escape_volk_ak74u_have и выполняется подзадача;
<text>Принести АКСУ Волку</text> - название второй подзадачи;
<map_location_type hint="Волк">blue_location</map_location_type> - указатель на Волка;
<object_story_id>Escape_novice_lager_volk</object_story_id> - id Волка в Файле gamedata\config\game_story_ids.ltx[/i][/b];
<infoportion_complete>escape_volk_ak74u_done</infoportion_complete> - если будет получен этот инфопоршень, то выполнится подзадача и соответственно сам квест.

Нужно сделать инфопоршни, заходим в gamedata\config\gameplay\info_l01escape.xml и в нём в конце до строчки </game_information_portions> пишем:


<info_portion id="escape_volk_ak74u_start">
    <task>escape_volk_ak74u</task>
</info_portion>
<info_portion id="escape_volk_ak74u_have"></info_portion>
<info_portion id="escape_volk_ak74u_done"></info_portion>

Теперь нужно сделать описание квеста, заходим в gamedata\config\gameplay\storyline_info_escape.xml и пишем в конце:

<article id="tex_escape_volk_ak74u" name="Найти потерянный ак74u" article_type="task">
<texture x="0" y="800" width="200" height="100">ui\ui_icon_equipment</texture>
<text>tex_escape_volk_ak74u</text>
</article>

Сделаем описание на русском, заходим в stable_dialogs_escape.xml и в конце до строки </string_table> пишем:

<string id="tex_escape_volk_ak74u">
<text>Волк попросил принести потерянный в туннеле АКСУ</text>
</string>

Теперь создадим скриптовый файл new_life в gamedata\scripts\new_life.script и пишем:

function spawn_ak74u()
    amk.spawn_item("wpn_ak74u",vector():set(-78.85,-1.29,154.74),163,189935) -- спавн ak74u в тоннеле на кордоне
end

function escape_volk_ak74u_have()
    return sak.have_item_namber("wpn_ak74u",1) ~= false -- проверка на нахождение предмета в рюкзаке
end

function give_volk_ak74u(first_speaker, second_speaker) -- передача предмета
    sak.out_item_namber("wpn_ak74u", 1)
end

function complete_volk_quest(first_speaker, second_speaker) -- получение награды
    dialogs.relocate_money(second_speaker, 1500, "in")
end

Чтобы эти скрипты заработали, нужно создать файлы amk.script и sak.script.
В аmk.script пишем:

function spawn_item(spawn_item, pos, gv,lv)
if gv==nil then gv=db.actor:game_vertex_id() end
if lv==nil then lv=db.actor:level_vertex_id() end
return alife():create(spawn_item, pos, lv, gv)
end

function remove_item_from_inventory(remove_item,npc)
if npc==nil then npc=db.actor end
if remove_item~=nil then
-- npc:mark_item_dropped(remove_item)
alife():release(alife():object(remove_item:id()), true)
return true
end
return false
end

В sak.script пишем:

local items_count=0
local itemin=nil

function have_item_namber(itm,need_namber)
local actor=db.actor
items_count=0
itemin=itm
actor:iterate_inventory(cheking_item,actor)
if items_count>=need_namber then
return true
else
return false
end
end

function cheking_item(actor,item)
local items=item:section()
if items==itemin then
items_count=items_count+1
end
end

function create_items(npc,section,number)
for i=1,number do
alife():create(section,
npc:position(),
npc:level_vertex_id(),
npc:game_vertex_id(),
npc:id())
end
end

local reloc_params={}
local stalk
function out_item_namber(itm_section,need_number)
reloc_params.itm_section=itm_section
reloc_params.itm_cnt=need_number
reloc_params.itm_cnt_found=0
db.actor:iterate_inventory(checkout_items_count,db.actor)
reloc_params.itm_cnt_found=0
if reloc_params.itm_cnt_found<=reloc_params.itm_cnt then
db.actor:iterate_inventory(out_items_count,db.actor)
end
news_manager.relocate_item(db.actor, "out", itm_section)
reloc_params={}
end

function relocate_item_namber(stalker,itm_section,need_number)
stalk=stalker
reloc_params.itm_section=itm_section
reloc_params.itm_cnt=need_number
reloc_params.itm_cnt_found=0
db.actor:iterate_inventory(checkout_items_count,db.actor)
reloc_params.itm_cnt_found=0
if reloc_params.itm_cnt_found<=reloc_params.itm_cnt then
db.actor:iterate_inventory(reloc_items_count,db.actor)
end
news_manager.relocate_item(db.actor, "out", itm_section)
reloc_params={}
end

function checkout_items_count(actor,item)
if item.section and item:section()==reloc_params.itm_section then
reloc_params.itm_cnt_found = reloc_params.itm_cnt_found + 1
end
end

function reloc_items_count(actor,item)
if item.section and item:section()==reloc_params.itm_section and reloc_params.itm_cnt_found<reloc_params.itm_cnt then
db.actor:transfer_item(item, stalk)
reloc_params.itm_cnt_found = reloc_params.itm_cnt_found + 1
end
end

function out_items_count(actor,item)
if item.section and item:section()==reloc_params.itm_section and reloc_params.itm_cnt_found<reloc_params.itm_cnt then
amk.remove_item_from_inventory(item, actor)
reloc_params.itm_cnt_found = reloc_params.itm_cnt_found + 1
end
end

Всё! Можно тестировать.

Примечание!!! Если вы делаете такой квест на оригинальном сталкере, то ОБЯЗАТЕЛЬНО нужно создать файлы amk.script и sak.script.
Если вы делаете квест на amk моде, то нужно создать только файл sak.script

Автор: sasha47007

Изменено пользователем World_Stalker
  • Нравится 1
  • Не нравится 1
  • Полезно 3
Ссылка на комментарий

Тутор по гулагам.
Вот IG-2007 на оф.форуме осенью прошлого года написал такой тутор по гулагам. Здесь показана работа в гулаге для сталкера. Днем он гуляет (walker), а ночью сидит у костра (kamp).

1) Пропишите в all.spawn своему смарту такую custom_data:
custom_data = <<END
[smart_terrain]
type = esc_new_lager
capacity = 1
END

2) Пропишите в all.spawn два пути: один из нескольких точек для схемы walker (esc_new_lager_npc1_walk), другой из одной точки (центр кампа) для kamp (esc_new_lager_npc1_kamp)
3) Откройте файл config\misc\gulag_escape.ltx и добавьте в самый конец работу для своего сталкера:

[logic@esc_new_lager_npc1]
active = walker@esc_new_lager_npc1

[walker@esc_new_lager_npc1]
path_walk = npc1_walk
on_info = {!is_day} kamp@esc_new_lager_npc1

[kamp@esc_new_lager_npc1]
center_point = npc1_kamp
on_info = {=is_day} walker@esc_new_lager_npc1

4) Откройте файл gulag_escape.script и добавьте в него:
4.1) в функцию load_job:

if type == "esc_new_lager" then
    t = { section = "logic@esc_new_lager_npc1",
    idle = 0,
    prior = 5, state = {0},
    online = false,
    in_rest = "", out_rest = ""
    }
    table.insert(sj, t)
end

4.2) в функцию load_states:

if type == "esc_new_lager" then
    return function (gulag)
        return 0
    end
end

4.3) в функцию checkStalker:

if gulag_type == "esc_new_lager" then
    return npc_community == "stalker"
end

 


И кстати. По тутору по работе с алл.спавн. Хочется внести ясность по одному из них.
Вот эту информацию написал я, а не Rezaniy. Получается, что он чужую работу выдает за свою.

По распаковке алл.спавна с помощью acdc.
Расскажу, как делать это без батников.
Если надо распаковать алл.спавн.
1. Помещаем файл алл.спавн в папку, где находятся файлы от acdc. Лучше создать ее на диске С:
2. Нажимаем ПУСК - Выполнить. Появляется командное окно.
3. Вводим команду cmd. Появляется черное окно.
4. В нем пишем cd\ Далее нажимаем enter. Происходит перенос на другую строчку. Эта команда задает диск С для работы с ним.
5. Далее пишем cd C:\"название папки, куда поместили acdc". Нажимаем enter. Переход на другую строчку. Теперь задали папку с которой будем работать. Вот здесь и надо будет вводить команды для acdc.
6. Вводим acdc.pl -d all.spawn Нажимаем enter.
7. Если асдс подходит для данного алл.спавна, то вскоре все распакуется и распакованные файлы можно будет обнаружить в папке с асдс.
8. Если асдс не подходит, то он выдаст ошибку. Тут же в этом черном окне. Надо будет внимательно прочитать о чем ошибка. Обычно для разных модов не хватает какого-нибудь описания чего-нибудь. Например, может ругаться что не может найти af_soul.
Тогда надо будет открыть файл acdc.pl блокнотом. Там найти, где описываются артефакты и в конце строк с артефактами сделать запись для af_soul, напримере других артефактов. После сохранить файл и заново набрать команду по распаковке.
9. После того, как сделали изменения в алл.спавне, надо будет таким же образом войти в папку с acdc, как описывалось раньше.
10. Набрать следующую команду: acdc.pl -c all.ltx
11. Если все сделали правильно в алл.спавне, то через некоторе время в папке с асдс появится файл all.spawn.new. Его надо будет переименовать в all.spawn
12. Правило при работе с алл.спавном - не забывайте правильно пронумеровывать вновь создаваемые секции. Для этого надо найти самый большой номер секции в алл.спавне. И присваивать своим секциям номера по порядку за этим номером.

 

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

Кто весел - тот смеется, кто хочет - тот добьется, кто ищет - тот всегда найдет!

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

Тутор по системе апгрейдов (ЧН)

Для редактирования уже существующих апгрейдов на примере АК74 нам

обязательно понадобятся файлы:
1. configs\weapons\upgrades\w_ak74_up.ltx
2. configs\text\rus\st_items_weapons_upgrades.xml
3. configs\weapons\upgrades_properties.ltx
4. configs\weapons\w_ak74.ltx
5. configs\ui\textures_descr\ui_ingame2_common.xml

Итак, начнём, открыв файл №1. Видим уже привычную нам параметро-секционную структуру файла:
[секция1]
параметр1 = значение1
параметр2 = значение2
параметр3 = значение3
...

[секция2]
параметр1 = значение1
параметр2 = значение2
...

Все секции в файле №1 можно разбить на три типа:
1. Показывающие стоимость, изменения и значения описаний при апгрейде. Эти секции - не главные, на них идёт ссылка с секций вторых типов. Рассмотрим параметры на примере секции:

[up_sect_c_ak74]
cost                      = 1600
value                    = -30

cam_dispersion              = -0.21;0.7
cam_dispersion_inc             = -0.21;0.7
cam_step_angle_horz            = -0.21;0.7

zoom_cam_dispersion          = -0.2;0.6
zoom_cam_dispersion_inc      = -0.2;0.6
zoom_cam_step_angle_horz     = -0.2;0.6

Параметр cost означает цену, которую должен заплатить игрок для осуществления апгрейда.

Параметр value. Мы знаем, что во множестве апгрейдов есть такие, описания которых сводится к типу: [характеристика] [+ или -] [значение]%. Например: "Отдача -30%". Значение, которое показывается в данном случае берётся из параметра value (остальные случаи, в которых описание не подходит под эту схему, например, "не стреляет дробью" рассмотрим потом). Внимание: это значение является словесным описанием и никак не влияет на характеристики оружия". Т.е. можно в нашей секции поставить value = -10000. Суть апгрейда не изменится, изменяется только его описание.

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

cam_dispersion = 0.7

Указав в параметрах в файле №1:

cam_dispersion = -0.21

в результате получаем:

cam_dispersion = 0.49

2. Главные секции апгрейда. Опять рассмотрим параметры:

[up_c_ak74]
scheme_index            = 0, 2
known                   = 1
effects                 = up_gr_ac_ak74
section                 = up_sect_c_ak74
property                = prop_recoil

precondition_functor    = inventory_upgrades.precondition_functor_a
precondition_parameter  = true

effect_functor          = inventory_upgrades.effect_functor_a
effect_parameter        = something_here

; ui
prereq_functor          = inventory_upgrades.prereq_functor_a
prereq_tooltip_functor  = inventory_upgrades.prereq_tooltip_functor_a
prereq_params           = up_c_ak74
name                    = st_upg_porsh_recoil
description             = st_upg_porsh_recoil_descr
icon                    = ui_wp_upgrade_41

Параметр scheme_index указывает положение иконки апгрейда в дереве апгрейдов (оно появляется при нажатии кнопки "улучшить") Подробнее на этом параметре остановимся во втором спойлере.

Параметр effects. Всем хорошо известно, что ап №1 во втором столбце дерева апов можно получить только тогда, когда проведены апы №1 и №3 в первом столбце. Для открытия апов после проведения других и служит параметр effects, включающий другие апгрейды. Он даёт ссылку на секцию №3. Подробнее на них остановимся чуть ниже.

Параметр section указывает ссылку на секцию №1. От этого значения зависит изменения при апе.

Параметр property указывает тип проводимого апа. Типы апов можно взять в начале файла №3. Подробнее об этом параметре в спойлере №3.

Типы апов:

prop_weight;; Вес
prop_silencer;; Глушитель
prop_underbarrel_slot;; Крепление подствольника
prop_reliability;; Надежность
prop_bullet_speed;; Настильность
prop_recoil;; Отдача
prop_ammo_size;; Патроны
prop_grenade_launcher;; Подствольник
prop_scope_4x;; Прицел 4
prop_scope_1.6x;; Прицел 1.6
prop_rpm;; Скорострельность
prop_calibre;; калибр (9x18, 5x45)
prop_dispersion;; Точность
prop_inertion;; Удобство

prop_armor;;Броня
prop_damage;;Повреждение
prop_durability;;Износостойкость (прочность)
prop_restore_bleeding;;Уменьшение кровотечения
prop_restore_health;;Восстановление здоровья
prop_night_vision;;Прибор ночного виденья
prop_power;;Восстановление стамины
prop_tonnage;;Переносимый вес
prop_radio_chem;;Радио-хим защита
prop_thermo_electro;;Термо-электро защита
prop_psy;;Пси защита
prop_artefact;;Слот для артефактов

Параметр prereq_params. В значении параметра указывайте секцию, в которой находится параметр. Нужно для скриптовых целей.

Параметр name содержит ссылку на текстовый блок из файла №2. В нашем случае:

name                    = st_upg_porsh_recoil
<string id="st_upg_porsh_recoil">
    <text>Модификация газового поршня</text>
</string>

Параметр description похож на параметр name, но касается описания апгрейда. Здесь:

description             = st_upg_porsh_recoil_descr
<string id="st_upg_porsh_recoil_descr">
    <text>Установка компенсатора газового поршня позволяет уменьшить отдачу</text>
</string>

Параметр icon содержит указатель на описание иконок в файле №5.
Вот структура файла:

<texture id="[указатель на иконку]" x="[координата x верхнего левого пикселя иконки]" y="[координата y верхнего левого пикселя иконки]" width="[ширина иконки]" height="[высота]" />

В нашем случае:

<texture id="ui_wp_upgrade_41" x="420" y="944" width="70" height="40" />

3. Секции, объединяющие апгрейды в группы апгрейдов. (в единственном параметре elements указываются апгрейды, входящие в группу, т.е. ссылки на секции вторых типов) Из группы апгрейдов может быть проведён только один апгрейд (в первом столбце может быть проведён только один из апгрейдов - №1 или №2). При включении группы апгрейдов включаются все апгрейды, входящие в группу. Для включения группы необходимо, чтобы все апгрейды с эффектом включения этой группы были проведены. (Для открытия группы апгрейдов up_gr_ac_ak74 необходимо, чтобы были проведены апгрейды up_gr_a_ak74 и up_gr_c_ak74. Названия тут ни при чём: в главных секциях (тип секции №2) этих двух апгрейдов параметр effects принимает значение up_gr_ac_ak74)

Таким образом, каждый апгрейд:
1. Имеет какие-то характеристики.
2. Имеет какое-то описание.
3. Принадлежит к какой-то группе апгрейдов.

Теперь несколько важных замечаний:
1. В файле №4 (конфиг самого АК74 и его уникальных модификаций) присутствует несколько параметров:

Параметр upgrades. В его значениях перечисляются группы апгрейдов, апгрейды которых могут быть проведены на чистом АК74. Перечисление идёт через запятую. После последней группы апгрейдов запятая не нужна.
Параметр installed_upgrades указывает апгрейды, которые уже проведены в этом оружии. Здесь указываются не группы апгрейдов, а сами апгрейды, т.е. секции второго типа.

Нам необходимо иметь 7 файлов:
1. configs\weapons\upgrades\w_ak74_up.ltx
2. configs\text\rus\st_items_weapons_upgrades.xml
3. configs\weapons\upgrades_properties.ltx
4. configs\ui\inventory_upgrade_16.xml (для широкоформатных)
5. configs\weapons\w_ak74.ltx
6. configs\ui\textures_descr\ui_ingame2_common.xml
7. scripts\inventory_upgrades.script

Перед прочтением текста ниже рекомендуется прочитать содержание первого спойлера.

Итак, начнём по порядку:
1. Создадим главную секцию (секцию типа №2) нового апгрейда, скопировав любую другую и поменяв параметры и само название секции:

[up_pack_a_ak74]
scheme_index            = 3, 0
known                   = 1
effects                 =
section                 = up_sect_pack_a_ak74
property                = prop_pack

precondition_functor    = inventory_upgrades.precondition_functor_a
precondition_parameter  = true

effect_functor          = inventory_upgrades.effect_functor_a
effect_parameter        = something_here

; ui
prereq_functor          = inventory_upgrades.prereq_functor_a
prereq_tooltip_functor  = inventory_upgrades.prereq_tooltip_functor_a
prereq_params           = up_pack_a_ak74
name                    = st_upg_pack_a_ak74
description             = st_upg_pack_a_ak74_descr
icon                    = ui_wp_upgrade_30

Как видим, в параметре property "prop_pack", мы указали не существующий тип. Мы его создадим самостоятельно чуть позже.

2. Теперь создадим секцию типа №1, которую мы указали в параметре section "up_sect_pack_a_ak74":

[up_sect_pack_a_ak74]
cost                      = 5120
value                    = desc_value_pack_a
rpm                     = 100
cam_dispersion              = -0.21;0.7
cam_dispersion_inc             = -0.21;0.7
cam_step_angle_horz            = -0.21;0.7
zoom_cam_dispersion          = -0.2;0.6
zoom_cam_dispersion_inc      = -0.2;0.6
zoom_cam_step_angle_horz     = -0.2;0.6
grenade_launcher_status = 2
grenade_launcher_name   = wpn_addon_grenade_launcher
grenade_launcher_x      = 126
grenade_launcher_y      = 24
control_inertion_factor    = -0.2
inv_weight                = -0.3
PDM_disp_vel_factor     = -0.3;1.7
PDM_disp_accel_factor   = -0.3;1.7

Здесь я собрал все улучшения четырёх апгрейдов, суммировав цену и делая скидку 20% (1600*4*0.8 = 5120) Отсюда и название апгрейда - st_upg_pack_a_ak74. В значении value я поставил "desc_value_pack_a". В данном случае в value присутствует ссылка на текстовый блок, а не кол-во процентов.

3. Теперь вернёмся в главную секцию. Т.к. апгрейд является пакетом апгрейдов up_sect_a_ak74,up_sect_c_ak74,up_sect_e_ak74,up_sect_g_ak74, то после проведения нашего апгрейда, четыре выше упомянутые должны выключиться. Для этого запишем наш апгрейд одновременно в несколько секций типов №3:

[up_gr_ab_ak74]
elements                = up_a_ak74, up_b_ak74, up_pack_a_ak74

[up_gr_cd_ak74]
elements                = up_c_ak74, up_d_ak74, up_pack_a_ak74

[up_gr_ef_ak74]
elements                = up_e_ak74, up_f_ak74, up_pack_a_ak74

[up_gr_gh_ak74]
elements                = up_g_ak74, up_h_ak74, up_pack_a_ak74

Т.к. из одной группы апгрейдов можно провести только один, то при проведении нашего апгрейда остальные "соседи" по группе апгрейдов выключатся.

4. Теперь, пользуясь файлом №2 запишем текстовые блоки, упомянутые в секциях типов №1 и №2.

    <string id="st_upg_pack_a_ak74">
        <text>Пакет апгрейдов №1</text>
    </string>
    <string id="st_upg_pack_a_ak74_descr">
        <text>Пакет апгрейдов №1, включающий в себя увеличение темпа стрельбы, уменьшение отдачи, установку крепежа для подствольного гранатомёта, уменьшение веса оружия</text>
    </string>
    <string id="st_upg_pack_a_ak74">
        <text>Пакет апгрейдов №1 Убийца</text>
    </string>

5. Теперь создадим ui для нашего апгрейда для того, чтобы кнопка апгрейда была видна в дереве апгрейдов. В парамре scheme_index мы указали "3,0". Это значит, что в дереве апгрейдов этот апгрейд будет в 3-ем столбце и 0-ой строке. К каждому оружию предлагается своя схема дерева апгрейдов. Чтобы узнать схему АК74 откроем его конфиг (файл №5) и найдём параметр upgrade_scheme. Его значение - upgrade_scheme_u17b. Откроем файл №4 со схемами апгрейдов. Вот его общая структура:

<template name="[название схемы]">

      [нулевой столбец]<column>
        [нулевая строка нулевого столбца. [b]Соответствует индексу 0,0[/b]]<cell x="[координата x]" y="[координата y]"   />
        [первая строка нулевого столбца. [b]Соответствует индексу 0,1[/b]]<cell x="[координата x]" y="[координата y]"  />
        ...
      [конец нулевого столбца]</column>

      [начало первого столбца]<column>
        [нулевая строка первого столбца. [b]Соответствует индексу 1,0[/b]]<cell x="[координата x]" y="[координата y]"  />
        ...
      [конец первого столбца]</column>
      ...
    [конец схемы]</template>

Найдём интересующую нас схему и добавим столбец и строку:

   <template name="upgrade_scheme_u17b">

      <column>
        <cell x="17" y="5"   />
        <cell x="17" y="50"  />
        <cell x="17" y="100" />
        <cell x="17" y="145" />
        <cell x="17" y="195" />
        <cell x="17" y="240" />
        <cell x="17" y="290" />
        <cell x="17" y="335" />
        <cell x="17" y="385" />
      </column>

      <column>
        <cell x="100" y="50"  />
        <cell x="100" y="100" />
        <cell x="100" y="240" />
        <cell x="100" y="290" />
        <cell x="100" y="385" />
       </column>

      <column>
        <cell x="183" y="145" />
        <cell x="183" y="195" />
        <cell x="183" y="385" />
      </column>
      
      <column>
        <cell x="183" y="5" />
      </column>

    </template>

6. Создадим новый тип апгрейдов: prop_pack. Для этого воспользуемся файлом №3.
Для начала добавим наш тип в начало файла:

[upgrades_properties]
prop_pack
prop_weight;; Вес
prop_silencer;; Глушитель
prop_underbarrel_slot;; Крепление подствольника
...

Теперь создадим новую секцию:

[prop_pack]
name     = st_prop_weight
icon     = ui_wp_propery_11
functor  = inventory_upgrades.property_functor_d
params   = hit_power, rpm, cost

В нашем случае важен только один параметр:

functor  = inventory_upgrades.property_functor_d

Он указывает, какая скриптовая функция будет составлять описание. Вы можете сами рассмотреть остальные параметры: name - название типа апгрейда (даётся ссылка на текстовый блок), icon - ссылка на указатель иконок из файла №6.

7. Составим функцию описания апгрейда inventory_upgrades.property_functor_d. Для этого откроем файл №7 и впишем туда маленькую функцию:

function property_functor_d( param1, name )
    local prorerty_name = char_ini:r_string(name, "name")
    local value_table = utils.parse_names(param1)
    local section = value_table[1]
    if section then
        local value = char_ini:r_string(section, "value")
        if value then
            return game.translate_string(value)
        end
    end
    return game.translate_string(prorerty_name)
end

 

 

Изменено пользователем World_Stalker
  • Спасибо 2
  • Согласен 1
Ссылка на комментарий

Для начинающих модмейкеров.

Добавление вещей в рюкзак сталкера после смерти.


Редактируем файл death_items_by_communities.ltx:
[stalker];Указывается вероятность заспаунить или нет (будет ли у сталкера данный предмет после смерти)
;Артефакты
af_medusa                = 0.015;(если заменить 0.015 на 1.0), то будет 100% вероятность что после смерти у сталкера в рюкзаке будет артефакт медуза
af_cristall_flower        = 0.01
af_night_star            = 0.005
af_vyvert                = 0.015
af_gravi                = 0.01
af_gold_fish            = 0.005
af_blood                = 0.015
af_mincer_meat            = 0.01
af_soul                    = 0.005
af_electra_sparkler        = 0.015
af_electra_flash        = 0.01
af_electra_moonlight    = 0.005
af_rusty_thorn            = 0.015
af_rusty_kristall        = 0.01
af_rusty_sea-urchin        = 0.005
af_ameba_slime            = 0.015
af_ameba_slug            = 0.01
af_ameba_mica            = 0.005
af_drops                = 0.015
af_fireball                = 0.01
af_cristall                = 0.005
af_dummy_glassbeads        = 0.005
af_dummy_pellicle        = 0.005
af_dummy_battery        = 0.005
af_dummy_dummy            = 0.005
af_dummy_spring            = 0.005
af_fuzz_kolobok            = 0.005

;Аммуниция
ammo_9x18_fmj            = 1
ammo_9x18_pmm            = 1
ammo_9x19_pbp            = 1
ammo_9x19_fmj            = 1
ammo_11.43x23_hydro        = 1
ammo_11.43x23_fmj        = 1
ammo_12x70_buck            = 1
ammo_12x76_dart            = 1
ammo_12x76_zhekan        = 1
ammo_5.45x39_ap            = 1
ammo_5.45x39_fmj        = 1
ammo_9x39_sp5            = 1
ammo_9x39_ap            = 1
ammo_9x39_pab9            = 1
ammo_5.56x45_ss190        = 1
ammo_5.56x45_ap            = 1
ammo_7.62x54_7h14        = 1
ammo_7.62x54_7h1        = 1
ammo_7.62x54_ap            = 1
ammo_gauss                = 1
ammo_og-7b                = 1
ammo_vog-25p            = 0.1
ammo_vog-25                = 0.1
grenade_f1                = 0.1;(если поставить 1.0, то после смерти вы 100% найдете гранату F1)
grenade_rgd5            = 0.1
ammo_m209                = 0.1

;Медикаменты
bandage                    = 0.4;(если поставить 0, то после смерти вы не найдете у сталкера бинты)
medkit                    = 0.2;(если поставить 0, то после смерти вы не найдете у сталкера аптечку)
medkit_army                = 0
medkit_scientic            = 0.05;(если поставить 1, то после смерти вы 100% найдете у сталкера научную аптечку)
antirad                    = 0.2

;Еда
bread                    = 0.2;(если поставить 1, то после смерти вы 100% найдете у сталкера булку аптечку)
kolbasa                    = 0.2;(если поставить 0.02, то после смерти вы с 2% вероятностью найдете у сталкера колбасу)
conserva                = 0.1
vodka                    = 0.1
energy_drink            = 0.1

 

Как изменить фальшивые концовки...
Правим xr_effects.script:

function sar_monolith_miracle(actor, npc)
    --' Убил лидеров группировок
    if has_alife_info("mil_lukash_dead") and    -- При убийстве Воронина и Лукаша покажут видео
        has_alife_info("bar_voronin_dead")
    then
        game.start_tutorial("mov_desire_3")        -- "Я хочу править миром"
        return                                              
    end

    --' Много денег
    if db.actor:money() >= 50000 then            -- Если поменять 50000 на 500000, то при кол-ве денег 500000 покажут
        game.start_tutorial("mov_desire_2")        -- Видео "Хочу стать богатым"
        return
    end
    --' Хорошая репутация
    if db.actor:character_reputation() >= 1000 then    -- Если поменять на 100 то при репутации 100 у гг, покажут
        game.start_tutorial("mov_desire_1")            -- Видео "Хочу что-бы зона исчезла"
        return
    end

    --' плохая репутация
    if db.actor:character_reputation() <= -1000 then -- Если поменять на -100 то при репутации -100 у гг, покажут
        game.start_tutorial("mov_desire_4")             -- Видео "Хочу уничтожить человечество"
        return
    end

    game.start_tutorial("mov_desire_5")        -- Хочу стать бессмертным
end

 

Делается это так: в файле xr_effects.script ищем строку:

function after_credits(actor, npc)

и ниже находим вот что c:

execute("disconnect")

Меняем "disconnect" например на hud_crosshair 1
и все вместо того чтобы после концовок (похоже даже фальшивых) будет возможно продолжить игру...

Только осталось добавить level_changer (например на Припять и все freeplay работает.)

 

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

SC2dCs2.png

 

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

Данный урок довольно прост.


Для реализации сего дива нам понадобится парочка музыкальных треков (music_1, music_2...), предварительно разбитых на два моно канала и переведенных в OGG формат с частотой 44kHz(64kbps). В этом может помочь Adobe Audition 2.0(по крайней мере я ним пользуюсь).
Также есть еще один вариант: Если уж очень лень - Музычку можно вытащить из различных МОДов, обычно в каждом, разработчики, как правило, засовывают новую музыку, которая лежит в "gamedata\sounds\music".
И так берем наши OGG треки и засовываем, в выше указанную папку, gamedata\sounds\music, не забывая про то, что каждая дорожка должна состоять из левого и правого моно канала "magnitofon_l.ogg"- левый канал и "magnitofon_r.ogg"- правый!
Причем количество дорожек не ограничено .
Далее нам понадобится ui_mm_main.xml, который лежит в "gamedata\config\ui" и находим там вот такой текст:
<menu_sound random="0" >
        <!--whell_sound>car\apc_run</whell_sound>
        <whell_click>car\test_car_stop</whell_click-->
        
        <menu_music>music\Terrapack-Empty_noise</menu_music>
        
        <!--menu_music>music\guitar_2</menu_music>
        <menu_music>music\guitar_1</menu_music>
        <menu_music>music\guitar_3</menu_music-->
        
    </menu_sound>
И проводим с ним некоторые манипуляции:
1. В строчке
<menu_sound random="0" >
и цифру "0" меняем на число соответствующие количеству наших муз. композиций, правда на одну единицу больше.
2. Далее после строчки
<menu_music>music\Terrapack-Empty_noise</menu_music>
ниже, на ее примере прописываем новые композиции
<menu_music>music\music_1</menu_music>
И в конечном итоге получится примерно так
    <menu_sound random="7" >
        <!--whell_sound>car\apc_run</whell_sound>
        <whell_click>car\test_car_stop</whell_click-->
        
        <!--whell_sound>car\apc_run</whell_sound>
        <whell_click>car\test_car_stop</whell_click-->    
        <menu_music>music\Terrapack-Empty_noise</menu_music>
        <menu_music>music\music_1</menu_music>
        <menu_music>music\music_2</menu_music>
        <menu_music>music\music_3</menu_music>
        <menu_music>music\music_4</menu_music>
        <menu_music>music\music_5</menu_music>
        <!--menu_music>music\guitar_2</menu_music>
        <menu_music>music\guitar_1</menu_music>
        <menu_music>music\guitar_3</menu_music-->
        
    </menu_sound>
Сохраняем. И теперь при каждом входе в главное меню у нас будут играть рандомно 7 музыкальных композиций!

Изменено пользователем World_Stalker
  • Нравится 2

Мои работы ТЫЦ

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

Эффект критического ранения.
Авторы: amk

1. Создаем файл effect_blood.script и записываем туда следующее:
lite_treshold = 0.05 -- насколько должно уменьшиться здоровье с предыдущего обновления чтоб экран окрасился в красный
crit_treshold = 0.30 -- насколько должно уменьшиться здоровье с предыдущего обновления чтоб ГГ начало шатать
drop_item_on_crit_prob = 0.20 -- вероятность того что ГГ выронит оружие
effector_power_coeff = 0.7
prev_health = -1
chk_h_t = 0

function wounded_pp_update()
  if (chk_h_t or 0) < time_global() then
    chk_h_t = time_global()+1000
    if prev_health > (db.actor.health + lite_treshold) then
      level.add_pp_effector("fire_hit.ppe", 2011, false)
      local effector_power = (prev_health - db.actor.health)*100*effector_power_coeff
      level.set_pp_effector_factor(2011, effector_power)
      if prev_health > db.actor.health + crit_treshold then
        level.add_cam_effector("camera_effects\\fusker.anm", 999, false, "")    
        local snd_obj = xr_sound.get_safe_sound_object([[actor\pain_3]])
        snd_obj:play_no_feedback(db.actor, sound_object.s2d, 0, vector(), 1.0)
        if math.random() < drop_item_on_crit_prob then
          local active_item = db.actor:active_item()
          if active_item and active_item:section() ~= "bolt" and active_item:section()~= "wpn_knife" then
            db.actor:drop_item(active_item)
          end
        end
      end
    end
    prev_health = db.actor.health
  end
end

2. Далее открываем bind_stalker.script:
после строчек:


function actor_binder:update(delta)
  object_binder.update(self, delta)
  local time = time_global()
  game_stats.update (delta, self.object)

пишем:

effect_blood.wounded_pp_update()

 

 

Изменено пользователем World_Stalker
Ссылка на комментарий

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

1. Синтаксические ошибки в коде. Как правило, лог при этом содержит что-то вроде

attempt to index global '<имя файла>' (a nil value)

т.е. движку не удалось скомпилить модуль и его значение (модуля) равно нулю

 

2. Ошибки времени выполнения Lua. Лог обычно содержит указание ошибки модуль и строку, в которой ошибка произошла. Типа такого:

LUA error: ....k.e.r. 1.0004\gamedata\scripts\<имя файла>.script:<номер строки>: attempt to index global 'npc' (a nil value)

К типичным ошибка относятся попытки вызвать несуществующий метод класса (и вообще индексировать что-бы то ни было несуществующим ключом) или, к примеру, конкатенация строки с nil.

 

3. Ошибки времени выполнения самого игрового движка. Лога обычно нет, т.е. движок тихо слетает, сам в лог ничего не пишет, а забуферизированный до этого момента лог теряется. Иногда, правда, что-то в логе есть, но бывает это весьма редко. Ошибки движка вызваны неправильным использованием функций самого движка. Например, попытка заспавнить объект с несуществующей секцией.

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

 

Довольно часто надо проверить некий фрагмент кода, заспавнить объект, проверить некую синтаксическую конструкцию и т.п.

1. Пишу скрипт и получаю вылет игры без лога, если влез в один из заранее прекомпилируемых файлов и сделал там тупую синтаксическую ошибку.

2. Выношу скрипт в отдельный файл и получаю вылет игры с до ужаса информативным сообщением в лог-файле "attempt to index global 'my_cool_script' (a nil value)".

Это значит, что тупую синтаксическую ошибку я сделал в файле my_cool_script.script

Можно до хрипоты говорить о пользе предварительной синтаксической проверки, но как часто мы её не делаем, не так ли?

3. Наконец-то умнею и проверяю скрипт на вшивость заранее. Запускаю игру, загружаю уровень.

загружаю уровень...

загружаю уровень......

Получаю вылет игры, лезу в лог и ищу в конце коротенькое сообщение, из которого следует, что надо поменять пару символов или добавить/стереть одну строчку.

4. Меняю скрипт, повторяю всё заново, скрипт отрабатывает, но делает не то, что мне надо. Чтобы изменения в скрипте вступили в силу, надо перегрузить уровень.

так что повторяю пп.3 и 4, пока не получу то, что мне было нужно.

 

Вот для частичного решения этой проблемы в своё время был сделан специальный тестовый полигон, который позволяет менять и вызывать определённый скрипт, не выходя из игры. Кроме того, часть ошибок (а именно ошибки Lua) блокируются и не приводят к вылетам. Полигон этот сэкономил мне кучу времени.

 

[spoiler=Тестирование скриптов без обрушения и перезапуска игры]Тестирование скриптов без обрушения и перезапуска игры

Ключевыми элементами являются две функции из стандартной библиотеки Lua:

dofile - позволяет загрузить и выполнить как chunk внешний файл.

pcall - позволяет выполнить произвольную функцию в т.н. защищённом режиме. Это значит, что любая ошибка интерпретатора Lua не выйдет за пределы функции, вызванной таким образом. Напомню, что обычно любая ошибка времени выполнения Lua передаётся хост-программе, т.е. игре, и вызывает её вылет.

 

Ну и собственно рецепт пилюли

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

 

    local res, err = pcall(my_proxy.start_chunk_from_file)
    get_console():execute(res and "Succesfull!" or string.gsub(err, " ", "_")) --имитация тернарного оператора

pcall возвращает два значения. Первое - результат запуска. Если все прошло пучком, то true. Второе - добавочное значение с сообщением об ошибке, если ошибка была. Иначе nil.

 

файл my_proxy.script содержит всего одну функцию

 

function start_chunk_from_file()
    local chunk, err = dofile("..\\gamedata\\scripts\\test.lua")
    if err then
        get_console():execute("err="..tostring(string.gsub(err, " ", "_")))
    end
end

dofile принимает имя файла со скриптом, загружает его и выполняет как функцию. Путём экспериментов я выяснил, что текущим каталогом Lua считает папку bin. Так что если хотим держать скрипт там, где и все остальные, то пишем путь относительно этой папки "..\\gamedata\\scripts\\test.lua".

test.lua - это отлаживаемый скрипт.

Обработка ошибок осуществляется аналогично pcall.

 

 

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

Само-собой, если сделаем что-то, что фатально затронет игровую логику или что-то из ошибок категории 3, то обрушение может всё равно случиться. Сразу или в другом месте. В основном, в таких случаях уже ничего не поделаешь. Однако, довольно часто можно свести потенциальную ошибку времени выполнения движка к ошибке Lua. Например, если вызвать функцию get_console():execute(<аргумент>) с нулевым аргументом, то получим вылет без лога. Однако ничто не мешает сделать так:

get_console():execute("value="..obj)

В этом случае сначала будет выполняться конкатенация двух строк. Если obj будет равно nil, то получим ошибку Lua, а её тестовый полигон не пропустит, и обрушения игры не будет.

 

И ещё. Это всё работает для ТЧ. Для ЧН мне наладить такой же полигон не удалось. Что-то там изменено в движке, что вызывает у него аллергию на функцию pcall.

Изменено пользователем malandrinus
  • Нравится 1
  • Полезно 3
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

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


Периодически на различных форумах появляются посты с просьбами объяснить, как можно сделать иконки для игры STALKER. Так как в рамках форума достаточно долго и проблематично это объяснить, а оставлять без ответа желающих тоже не хочется решил написать что-то вроде "мануала" про то как создаю иконки я.

Не претендую на могучее мастерство в этой области, также не претендую на авторство методы я лишь добавил кое какие мелочи, мысли, наработки от себя и написал данный мануал.



формат - exe (в архиве PDF), вес - 14.15 Мб (распакованный 17.6 Мб), объём - 72 страницы с картинками.


Мануал для тех кто страдает "хроническим дефицитом времени" или просто не хочет глубоко вникать в принципы работ с текстурами, а между тем сделать, что-либо хочет. Мануал, про скажем так - "полуавтоматический" способ создания "бампа" с помощью которого можно добиться вполне приличных результатов.
Не претендую на могучее мастерство в этой области, также не претендую на авторство методы я лишь добавил кое какие мелочи, мысли, наработки от себя и написал данный мануал.



формат - 7z SFX (в архиве PDF), вес - 20,88 Мб (распакованный 25.3 Мб), объём - 74 страницы с картинками.


Как-то столкнулся с задачей создания на текстуре оружия "насечек" (вы наверное видели такие "насечки" на некоторых вариантах глушителей, рукояток, стволов и т.д.).
Немного "покумекав" сообразил, как это можно сделать максимально просто, при этом не пожертвовав качеством.
Это не столько «узкоспециализированная инструкция» про создание «насечек», сколько показательная инструкция, про то, что можно решить достаточно «геморройные» и нудные графические задачи, достаточно простым способом. И соответственно решил поделиться данным способом. )




формат - 7z SFX (в архиве PDF), вес - 10.67 Мб (распакованный 12.0 Мб), объём - 28 страницы и все с картинками.


Всё что нас не убивает, то нас делает сильней.

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

Вообщем разобрались сегодня как располагать\передвигать карты локаций на глобальной карте.

Вот статья - Скачать (1 МБ) (ссылка прямая)
Авторы: Руся, Xmk

Если что-то непонятно - пишем smile.gif

Изменено пользователем World_Stalker
Ссылка на комментарий

Сразу оговорюсь, что вся информация ниже предназначена для ТЧ. В ЧН экспортировано пространство имён

io и проблемы как-бы и нет вовсе.

 

Имеются экспортированные в Lua функции log(string), error_log(string) и flush(). И эти функции не работают! По крайней мере никому до сих пор не удалось заставить их работать в релизной версии движка.

Так что общепринятым способом является использование консоли. Известно, что всё, что пишется в консоль, пишется одновременно и в лог-файл. Файл этот находится в месте, определяемом переменной $logs$, которая в свою очередь находится в файле fsgame.ltx.

Для управления консолью имеется класс CConsole. Экземпляр этого класса можно получить с помощью глобальной функции get_console().

В этом классе нет функций, которые позволили бы вывести на консоль (и соответственно в лог) произвольную строку. Однако имеется функция execute(string), которая предназначена для выполнения команд консоли. Разумеется, выполнить можно только те команды, которые поддерживает движок. Если команда не поддерживается, то в консоль выводится сообщение:

! Unknown command: <команда_которую_пытался_выполнить>

Вот так и можно вывести некий текст. Пишем его вместо команды и он попадёт в консоль и в лог в составе сообщения об ошибке. Т.е. можно выводить сообщения так:

get_console():execute(<моё_сообщение>)

У метода есть недостатки.

Первое, сообщение не должно быть командой. Обычно с этим не возникает проблем, но всё-таки следить надо.

Второе, если в сообщении есть пробельные символы, то движок воспринимает как команду только последовательность символов до первого такого символа. Остальное - это как бы аргументы команды. В лог выведется только "команда", а остальное пропадёт. Есть два способа для решения этой проблемы. Первый состоит в замене всех пробелов на другой символ, например знак подчеркивания. Тогда команда вывода в лог будет выглядеть так:

get_console():execute(string.gsub(<моё_сообщение>, " ", "_"))

Функция string.gsub(str, ptrn, rep) заменяет в строке str все вхождения строки ptrn на строку rep.

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

get_console():execute("load ~~~ "..<сообщение>)

Поскольку файла, начинающегося с "~~~" точно не существует, то это сработает всегда. Сообщение в логе в этом случае выглядит так:

! Cannot find saved game ~~~ моё сообщение

При таком способе в сообщении могут быть пробелы и они отобразятся нормально. Кроме того, нет риска, что сообщение окажется командой консоли.

Недостаток метода - лишнее обращение к жёсткому диску на предмет проверки существования сейва. Кроме того, этот метод аккуратно обходится только с пробелами. Прочие специальные символы конвертируются в пробелы.

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

get_console():execute("flush")

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

 

Но есть и ещё один способ, который может компенсировать эти недостатки. Оказывается, можно перенаправить консольный вывод движка в текстовый файл. После этого в этот файл можно выводить что угодно функцией Lua print(). Описание этой функции можно посмотреть на сайте Lua. Скажу только, что в сочетании с функцией форматирования текста string.format() так можно вывести в файл совершенно произвольно оформленный текст.

Для реализации метода можно запускать игру через батник примерно такого содержания:

XR_3DA.exe -nointro >> log.txt

 

У метода замечен только один недостаток. Нет никакой возможности принудительно записать файл на диск. Функция Flush осталась в неэкспортированном пространстве имён io. Хотя в отличие от консольного лога этот файл записывается на диск сам, но из-за буферизации часть его может таки пропасть в случае краша игры. При нормальном выходе из игры всё естественно запишется как надо.

 

  • Спасибо 1
  • Полезно 3
 

Плагины Total Commander для работы с игровыми архивами:

Архиваторный плагин (для работы с одиночным архивом): link1 link2

Системный плагин (для распаковки установленной игры): link1 link2

 

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

Спросите для чего это надо? Отвечу коротко и надеюсь понятно.


Для более удобного совмещения модов.
1) Создадим файл dialogs_zver_kopdon.txt далее его с помощью тотал командера( или чем вы пользуетесь) меняем окончание
.txt на .xml и получаем готовый файл. dialogs_zver_kopdon.xml
Открываем его и вставляем в него следующее:
<?xml version="1.0" encoding="windows-1251" ?>
<string_table>




</string_table>

Всё наш файл готов к работе, здесь можно прописывать русскоязычные диалоги.
Помещаем его по адресу .....\S.T.A.L.K.E.R\gamedata\config\text\rus
Что бы его игра увидела нужно его прописать. Открываем файл localization.ltx
который находится по адресу ....\S.T.A.L.K.E.R\gamedata\config
Находим строку

;список xml файлов, содержащих таблицы символов

и в самом конце списка через запятую прописываем dialogs_zver_kopdon
Всё, можно работать!!!

 

2) Создадим файл zver_kordon_dialogs.xml пропустим создание, так как оно подробно расписано выше.
Откроем файл и и вставим:

<?xml version="1.0" encoding="windows-1251" ?>
<game_dialogs>





</game_dialogs>

Файл готов к работе. Здесь формулу диалога. Положим его по адресу:
...\S.T.A.L.K.E.R\gamedata\config\gameplay
Прописываем что бы видела игра по адресу
...\S.T.A.L.K.E.R\gamedata\config\system.ltx
Находим строку: [dialogs] в конце списка прописываем zver_kordon_dialogs
Всё, работаем!!!

3) Создадим файл инфо где будут прописываться инфопоршни.
Создадим файл info_zver_kordon.xml
Откроем файл и вставим:

<?xml version='1.0' encoding="windows-1251"?>

<game_information_portions>




</game_information_portions>

Файл готов к работе.Положим его по адресу:
...\S.T.A.L.K.E.R\gamedata\config\gameplay
Прописываем что бы видела игра по адресу
...\S.T.A.L.K.E.R\gamedata\config\system.ltx
Находим строку: [info_portions] в конце списка прописываем info_zver_kordon.xml
Всё, можно работать!!!

4) Про файл скрипт, он тоже нам нужен в квестописании.
просто создаём файл zver_1.script и помещаем его по адресу:
....\S.T.A.L.K.E.R\gamedata\scripts
Всё, можно работать!!!

И как бонус создние файла из серии character_desc_......xml
Создадим файл character_desc_zver.xml

Откроем файл и вставим:

<?xml version='1.0' encoding="windows-1251"?>

<xml>



</xml>

Файл готов к работе.Здесь мы прописываем профили неписей. Положим его по адресу:
...\S.T.A.L.K.E.R\gamedata\config\gameplay
Прописываем что бы видела игра по адресу
...\S.T.A.L.K.E.R\gamedata\config\system.ltx
Находим строку: [profiles] в конце списка прописываем character_desc_zver
Всё, работаем!!!

 

Изменено пользователем World_Stalker
  • Нравится 3
  • Полезно 1
Ссылка на комментарий
Базовый урок , ничего сложного, смарт-терейны не переписывал, сами будете добавлять....
Назовем нашу группировку (айди) grom
1) Открываем файл gamedata\configs\creatures\game_relations.ltx
;названия группировок (порядок должен совпадать с communities_relations)
communities        = actor, 0, bandit, 1, dolg, 2, ecolog, 3, freedom, 4, killer, 5, army, 6, monolith, 7, monster, 8, stalker, 9, zombied, 10, grom, 11

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

[communities_relations]
;              |actor|bandit| dolg|ecolog|freedom|killer|    army|monolith|monster|stalker| zombied|grom
;===============================================================================
====================
actor         =     0,     0,     0,     0,       0, -1000,       0,   -5000,  -5000,      0,   -5000
bandit        =     0,  5000,-5000,     0,  -5000,     0,   -5000,   -5000,  -5000,  -1000,   -5000, -5000
dolg          =     0, -5000, 5000,     0,  -5000,     0,       0,   -5000,  -5000,      0,   -5000, 0
ecolog        =     0,     0,    0,     0,      0,     0,       0,       0,      0,      0,       0, 0, 0, 0, 0
freedom       =     0, -5000,-5000,     0,   5000,     0,       0,   -5000,  -5000,      0,   -5000, 0
killer        = -1000,     0,    0,     0,      0,  1000,   -5000,   -5000,  -5000,      0,   -5000, 0
army            =     0, -5000,    0,     0,      0, -5000,    1000,   -5000,  -5000,      0,   -5000, 0
monolith      = -5000, -5000,-5000,     0,  -5000, -5000,   -5000,    1000,  -5000,  -5000,    1000, -5000
monster       = -5000, -5000,-5000,     0,  -5000, -5000,   -5000,   -5000,      0,  -5000,   -5000, -5000
stalker       =     0, -1000,    0,     0,      0,     0,       0,   -5000,  -5000,      0,   -5000, 5000
zombied       = -5000, -5000,-5000,     0,  -5000, -5000,   -5000,    1000,  -5000,  -5000,    1000, -5000
grom        =  -5000, -1000,    0,     0,      0,     0,       0,   -5000,  -5000,      0,   -5000, 5000

Добавляем группировку в таблицу, прописываем отношение к другим группировкам, НЕ ЗАБЫВАЕМ добавлять по еще одному значению по вертикали!

;(порядок должен совпадать с communities_relations)
[communities_sympathy]
actor            =        0.0
bandit            =        0.0
dolg            =        0.0
ecolog            =        0.0
freedom            =        0.0
killer            =        0.0
army            =        0.0
monolith        =        0.0
monster            =        0.0
stalker            =        0.0;0.01
zombied            =        0.0
grom                =         0.0

Сюда тоже добавляем в таком же порядке...

2) Создаем профайл сталкера в gamedata\configs\gameplay\character_desc_general.xml (ну или другой, который вы прописали, или на уровнях)

<specific_character id="grom spez" team_default = "1">
    <name>GENERATE_NAME_stalker</name>
    <icon>ui_inGame2_merc_4</icon>
    <map_icon x="1" y="0"></map_icon>
    <bio>Опытный сталкер. Детальная информация отсутствует.</bio>

    <class>grom_specnaz</class>
    <community>grom</community> <terrain_sect>stalker_terrain</terrain_sect>
    <snd_config>characters_voice\human_03\killer\</snd_config>

    <rank>60</rank>
    <money min="5000" max="10000" infinitive="0"/>
    <reputation>0</reputation>

    <visual>actors\stalker_merc\stalker_merc_4</visual>
    <supplies>
      [spawn] \n
      
      wpn_fn2000 \n
      ammo_5.56x45_ap = 1 \n
      wpn_usp \n
      ammo_11.43x23_hydro = 1 \n
      grenade_f1 = 4 \n

#include "gameplay\character_items_nd.xml"
#include "gameplay\character_food.xml"
#include "gameplay\character_drugs_4.xml"
#include "gameplay\character_drugs_sci.xml"
#include "gameplay\character_drugs_mil.xml"
    </supplies>
#include "gameplay\character_criticals_4.xml"
#include "gameplay\character_dialogs.xml"
  </specific_character>

3) в файле gamedata\configs\gameplay\npc_profile.xml создаем класс нпс, вписываем его айди из профайла и класс.

<character id="grom spez">
        <class>grom_specnaz</class>
    </character>

В файле gamedata\configs\creatures\spawn_sections_general.ltx создаем секцию для спавна:

[ваше название секции]:stalker
$spawn = "respawn\ваше название секции"
character_profile = grom spez -айди нпс_профайла
spec_rank = novice
community = grom ---группировка как в профайле

4) Добавляем в скрипт death_manager.script нашу группировку:

local community_list = { "stalker", "dolg", "freedom", "bandit", "army", "zombied", "ecolog", "killer", "monolith","grom"}

5) В файле gamedata\configs\misc\death_items_by_communities.ltx
Добавляем секцию с группировкой, и продукты для нее...., теоретически можно не трогать этот файл, все будет по дефолту и вылетов не будет тоже, проверял.

6) Чтоб название было по русски в любом файле с текстами

<string id="grom">
<text>Вольный сталкер</text>
</string>

7) Осталось заспавнить, берем секции из spawn_sections_....

 

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

Что-то кончается, что-то начинается...

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

В этой статье я не буду писать тупые и неинтересные уроки, которые есть в любом факе по модмейкерству, а буду помещать лишь интересные (на мой взгляд) уроки и небольшие статьи


Добавим в файл config\gameplay\encyclopedia_zone.xml новую статью:

<!-------------------------------- Activation - Basic ----------------------------->
<article id="zone_anomalies_activation_basic" name="zone_anomalies_activation-basic" group="Anomalies">
<texture x="500" y="150" width="100" height="100">ui_icon_photo</texture>
        <text>enc_zone_anomalies_activation_basic</text>
    </article>

Здесь:


article id - внутреннее имя статьи, именно на него ссылаются в файлах игры
name - имя статьи, отображаемое в игре, подгружается из строкового массива
texture - картинка и её позиция в статье, в данном случае мы использовали обычный белый шум
text - текст статьи, отображаемый в игре, подгружается из строкового массива
 
Добавим например в config\gameplay\info_l01escape.xml (инфопорции уровня "Кордон") ссылку на получение статьи - скажем, к трупу у туннеля, при обыске которого выдается информация о аномалиях в туннеле (вы его обнаруживаете, проходя второе спецзадание от Сидоровича). Найдем эти строки и дополним их:

Так как в статье у нас есть такое поле:

<text>enc_zone_anomalies_activation_basic</text>

Да и название тоже не написано прямо, а ссылается на определенную строку, то добавим этот самый text в config\text\rus\string_table_enc_zone.xml, в нашем случае:

<string id="enc_zone_anomalies_activation-basic">
<text>Активация - базис</text>
</string>
<string id="enc_zone_anomalies_activation_basic">
<text>С артефактами связана, помимо всего прочего, ''(ну, и так далее, там большой текст)''...</text>
</string>

Дополнительно.
Чтобы статья добавлялась при получении определенного задания, в ..._task.xml (вместо ... стоит название уровня) нужно прописать конструкцию вида:

<article>название_задания_descr</article>

<!-- труп у аномалии -->
<info_portion id="esc_tutorial_dead_novice">
<article>tutorial_moving_anomaly</article>
<article>zone_anomalies_activation_basic</article>
</info_portion>
Главное - никогда не путайте article id, name и text статьи. Я в данном примере это сделать легко. Лучше называйте их непохожими друг на друга названиями.


В файле gamedata\scripts\xr_kamp.script находим:

-- играть на гармошке
-- if npc:object("harmonica_a") then
-- self.npc[npc_id].states["play_harmonica"] = true
-- self.npc[npc_id].states["wait_harmonica"] = true
-- self.kamp_states["pre_harmonica"] = true
-- self.kamp_states["harmonica"] = true
-- self.kamp_states["post_harmonica"] = true
-- else

Раскомментируем эти строки, для этого удалим --. перед строками, исключения строка "-- играть на гармошке"
Затем нужно добавить музыку. Например сталкерам, открываем папку gamedata\sounds\characters_voice\human_01\stalker\music и добавляем туда свою музыку. Имя файла должно быть harmonica_* (где *, 1, 2, 3 и т.д.). Формат файла должен быть *.ogg. Таким же образом добавляем музыку остальным группировкам.


При заходе на экран главного меня муз. заставка будет выбираться случайно из добавленных вами.
1. В директорию gamedata\sounds\music положить два канальных ogg-файла с нужной музыкой, например: my_music_l.ogg (левый канал) и my_music_r.ogg (правый канал)
2. Открыть файл gamedata\config\ui\ui_mm_main.xml, найти в нем строку:

<menu_sound random="0" >

и заменить на:

<menu_sound random="1" >

3. В этом же файле найти строку:

<menu_music>music\wasteland2</menu_music>

и ниже нее выставить следующую строку:

<menu_music>music\my_music</menu_music>

4. Сохранить файл.
5. Если требуется вставить больше муз. заставок, то в параметре random укажите их количество.

!!! Возьмите на заметку !!!
в строке <menu_sound random="0" >
вместо 0 указывайте не количество композиций, а количество композиций - 1, то есть, если вы добавили скажем еще одну мелодию, к той, что была по дефаулту у вас получится примерно так:

<menu_sound random="1" >
	<menu_music>music\wasteland2</menu_music>
<menu_music>music\my_music</menu_music>


1. Кладём ролик в папку gamedata\textures\sleep\. Собственно, в любую папку, лишь бы она была в каталоге textures. Просто в sleep лежат ролики сна в оригинале.
имя файла любое, формат ogm, а разрешение ролика вроде можно сделать любое. Я не стал заморачиваться и просто скопировал существующий ролик сна с монолитом.
2. Озвучку ролика кладем по той-же схеме в папку в корневом каталогу gamedata\sounds\. У меня папка называется my_sleep. Имена файлов для левого и правого канала должны выглядеть так

my_sleep_sound_l.ogg

и

my_sleep_sound_r.ogg

длина звуков может быть разной и вообще говоря не совпадать с длиной ролика.
3. Правим файл gamedata\config\ui\ui_movies.xml. Добавляем туда что-то в этом роде:

    <my_dream>
        <play_each_item>1</play_each_item>
        <global_wnd x="0" y="0" width="1024" height="768">
            <auto_static x="0" y="0" width="1024" height="768" stretch="1">
                <window_name>back</window_name>
                <texture>intro\intro_back</texture>
            </auto_static>
        </global_wnd>
	        <item type="video">
            <sound>my_sleep\my_sleep_sound</sound>
            <pause_state>on</pause_state>
            <function_on_stop>sleep_manager.stopper</function_on_stop>
            <video_wnd x="0" y="0" width="1024" height="768" stretch="1">
                <texture x="0" y="1" width="512" height="286">sleep\dream_sarcofag</texture>
            </video_wnd>
        </item>
    </my_dream>

Название тега my_dream - это моё имя для сна. Если я верно всё понимаю, то вся эта фигня описывает окно, в котором играется видеоролик.
4. Теперь собственно добавляем сон. Правим файл gamedata\config\misc\dream.ltx.
Там есть секции с именами [regular_dream#] где # - это номера снов. Сейчас там есть regular_dream1, regular_dream2 и regular_dream3. Добавляем секцию

[regular_dream4]
dream       = my_dream
probability = 40
type        = happy

параметры:
dream - это ранее заданное имя сна (в нашем случае my_dream).
probability - ясное дело, что нужно для вычисления вероятности появления именно этого сна. Но я пока не понял по какому алгоритму она вычисляется на основе этого параметра. Я просто сделал число побольше, дабы протестировать побыстрее.
type - может быть nightmare, normal и happy. По названию вроде понятно, что это. Но на что влияет пока не ясно.
 
5. Ну и завершающий этап. В этом же файле в секцию [dreams] к параметру regular добавляем к списку новый сон regular_dream4. Вроде такого:

regular = regular_dream1, regular_dream2, regular_dream3, regular_dream4

Тестируем... Опа! Новый сон. Поскольку я звуки взял случайно, то при этом в левом ухе у меня орет кот, а в правом играет мрачный эмбиент =)
Ну и естественно работать будет только при установленном АМК. Что там именно сделано, для того чтобы сон вообще был, я пока не разбирался.


  • Полезно 3

Thank you for your honesty.

Now fuck off and die.

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

Вот решил добавить статейку на STLKER mod-портал по партиклам ссылка

Надеюсь меня за это не расстреляют :ny_ph34r:

Пока еще неполная и есть повторения с другой статьи.

Может кому поможет... :ny_thumbsup:

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

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

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

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

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

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

Войти

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

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

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