Войти на сайт Регистрация Лента форума Пользователи Правила сайта Поиск по форуму
Модератор форума: denis2000, FantomICW  
Модостроение. Редактирование и создание скриптов
denis2000Дата: Пн, 10.10.2011, 21:17 | Сообщение # 1
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Редактирование и создание скриптов

Редактирование и создание скриптов на языке LUA

Если у вас появились вопросы по применению скриптов в игре. Задавайте их в этой теме - умные головы,
модосторители и просто разбирающиеся в программировании люди вам ответят.


Много интересного материала здесь (wiki), Lua_help.script, Help из SDK 0.7

Сборник модостроения ЗП v10.10.11 (автор: XOBAH): *.CHM, *.HTML
[cut noguest=Если у вас не открывается файл CHM]Если у вас не открывается файл:
1. Запустите [Пуск]=>[Выполнить] (либо хот-кей [WIN]+[R])
2. Введите команду (без кавычек) "regsvr32 %windir%\system32\hhctrl.ocx"
3. Если вылезло окно об успешном завершении вы все сделали правильно и можете перезагружать компьютер (а может и не надо)
Также: файлы МОГУТ не открываться если в пути к файлу есть: символы кириллицы, "_", "#"
Также: есть не стандартные программы-просмоторщики CHM файлов. Например: FBReader[/cut]

[cut=Где найти лог игры после вылета]Что такое LOG ошибки, и как мне его найти?
Это система отладки происходивших вылетов, которая подается игрой в форме текста, хотя не всегда.
Для того чтоб найти LOG необходимо зайти вот сюда:

В Win хр лог находится:

C:\Documents and Settings\All Users\Документы\S.T.A.L.K.E.R. - Зов Припяти\logs

Затем открываете первый файл в формате TXT, и в нем отбираете с низу 25 строчек. После кидаете эти 25 строчек в сообщение на форум.

В Win7 лог находится C:\Users\Public\Documents\S.T.A.L.K.E.R. - Зов Припяти\logs

Путь к папке с логом можно найти открыв файл fsgame.ltx который находится в корневой директории ЗП, за это отвечает строка:
...
$app_data_root$ = true | false| $fs_root$| users\
(тут мы указываем что папка пользователя, будет хранится рядом с Fsgame.ltx)
...
$logs$ = true| false| $app_data_root$| logs\
(а тут мы указываем что в папке пользователя, в подпапке Logs будут храниться наши логи)
...
[/cut][cut=Получение более подробной информации о вылете (ХОВАН)]
Открываем файл _g.script и ищем такую функцию: function abort(fmt, ...)
Там есть заккомментированная строчка "--error_log(reason)", ее и надо расскомментировать, должно получиться вот так:
Code
function abort(fmt, ...)
                             local reason = string.format(fmt, ...)
                             error_log(reason)
end

Вот для примера два одинаковых вылета, первый с функцией по умолчанию, второй - с поправленной функцией

Первый:
Code
Expression    : !m_error_code
Function      : raii_guard::~raii_guard
File          : D:\prog_repository\sources\trunk\xrServerEntities\script_storage.cpp
Line          : 748
Description   : ....a.l.k.e.r. - Зов Припяти\gamedata\scripts\_g.script:478: bad argument #2 to 'format' (string expected, got nil)

Второй:
Code
Expression    : 0
Function      : ErrorLog
File          : D:\prog_repository\sources\trunk\xrServerEntities\script_engine_script.cpp
Line          : 49
Description   : 'Attempt to read a non-existant string field 'path_walk' in section 'walker@mechanic'

[/cut]


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


Если произошел вылет - выкладываем лог! Вопрос ставим четко, не забываем указывать версию игры, установленные моды их версии, установленные фиксы модов и подробно ваши правки.
Помните чем подробнее вопрос, тем точнее ответ.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
denis2000Дата: Вт, 22.01.2013, 22:26 | Сообщение # 136
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

yakuti, Из скрипта можно выполнить любую консольную команду кодом:
Код
get_console():execute("ТЕКСТ КОММАНДЫ"))


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
yakutiДата: Ср, 23.01.2013, 09:06 | Сообщение # 137
Отмычка
Пользователи
Сообщений: 46
Награды: 0
Репутация: [ 7 ]

А какой текст команды, подскажите плиз
 
denis2000Дата: Ср, 23.01.2013, 22:49 | Сообщение # 138
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

yakuti, demo_record x - начинается запись всего происходящего где x - это любая цифра или слово на английской раскладке!

"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
GeonezisДата: Пт, 25.01.2013, 22:23 | Сообщение # 139
Разработчик «Смерти вопреки»
Свобода
Сообщений: 2360
Награды: 30
Репутация: [ 71 ]

Здравствуйте. Наверное глупый вопрос.
Где можно посмотреть список всех возможных параметров актора подобного типа:
Код

db.actor.health
db.actor.power
db.actor.radiation
db.actor.bleeding

Это те, которые вспомнил.


Смерти Вопреки
Spectrum Project
AP_Prodaction
 
denis2000Дата: Пт, 25.01.2013, 23:39 | Сообщение # 140
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Geonezis, В файле lua_help.script, объект класса game_object обладает свойствами (property):
Код
property bleeding;
property health;
property morale;
property power;
property psy_health;
property radiation;


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
АзазельДата: Вс, 27.01.2013, 17:59 | Сообщение # 141
Новичок
Пользователи
Сообщений: 77
Награды: 0
Репутация: [ 0 ]

Доброго времени суток. Сейчас занимаюсь фиком для пака Fraser. И попутно вспомнил что в SGM версси что будет. Сделана g36 с двойным прицеливанием. Реально ли сделать так чтобы скажем на ПКМ прицеливание шло по колиматору. А при нажатии на СКМ идет по целику ?

Движок в курсе ваших желаний? denis2000
 
ted80Дата: Чт, 31.01.2013, 23:08 | Сообщение # 142
Гражданский
Пользователи
Сообщений: 15
Награды: 0
Репутация: [ 0 ]

Здравствуйте denis2000, решил подправить скрипт выдачи сообщений о смерти НПС, что-бы было похоже на то, как описывается в книгах - с сообщениями об убийстве НПС - актором и др. НПС все прошло гладко.

[cut noguest=ПРИМЕР] if victim and IsStalker(victim) and IsStalker(who) then
local dead_news = "Сообщение \\nПогиб сталкер !!! \\n%c[255,255,160,160]Имя: %c[default]"..victim:character_name().."\\n%c[255,160,255,160]Группировка: %c[default]\""..game.translate_string(victim:character_community()).."\"\\n%c[255,160,160,160]Локация: %c[default]"..game.translate_string(level.name()).."\\n%c[255,225,100,100]Убийца: %c[default]"..who:character_name().." \""..game.translate_string(who:character_community()).."\""
db.actor:give_game_news(dead_news, "ui\\ui_iconsTotal", Frect():set(498,188,83,47), 2000, 5000)
end[/cut]
[cut noguest=СКРИН][/cut]

Но вот с сообщениями о смерти от монстров и аномалий, проблема - как, при отсылке сообщений, получить названия монстров и аномалий, причастных к смерти НПС

[cut noguest] if victim and IsStalker(victim) and IsMonster(who) then
local dead_news = "Сообщение \\nПогиб сталкер !!! \\n%c[255,255,160,160]Имя: %c[default]"..victim:character_name().."\\n%c[255,160,255,160]Группировка: %c[default]\""..game.translate_string(victim:character_community()).."\"\\n%c[255,160,160,160]Локация: %c[default]"..game.translate_string(level.name()).."\\n%c[255,225,160,160]Причина смерти:%c[default]"..""
db.actor:give_game_news(dead_news, "ui\\ui_iconsTotal", Frect():set(498,188,83,47), 3, 4000)
end

if victim and (IsStalker(victim) and (who == nil or (not IsStalker(who) and not IsMonster(who))) ) then
local dead_news = "Сообщение \\nПогиб сталкер !!! \\n%c[255,255,160,160]Имя: %c[default]"..victim:character_name().."\\n%c[255,160,255,160]Группировка: %c[default]\""..game.translate_string(victim:character_community()).."\"\\n%c[255,160,160,160]Локация: %c[default]"..game.translate_string(level.name()).."\\n%c[255,225,160,160]Причина смерти: Аномалия"..""
db.actor:give_game_news(dead_news, "ui\\ui_iconsTotal", Frect():set(498,188,83,47), 1, 4000)
end[/cut]

Стабильный вылет: attempt to call method 'section_name' (a nil value)

Таки заработало : who:section() таким макаром
[cut noguest=скрин][/cut]

теперь выглядит так: "..game.translate_string(who:section()).."

[cut noguest=Скрин][/cut]

Спасибо что подсказали где искать - теперь буду ковырять аномалии biggrin




Сообщение отредактировал ted80 - Пт, 01.02.2013, 17:42
 
denis2000Дата: Пт, 01.02.2013, 19:54 | Сообщение # 143
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

ted80, Пробуй получать имя секции объекта who:section_name() и в зависимости от полученной строки составляй текст.

Цитата (ted80)
who:section() таким макаром

Ну или так, или можно еще по классам объектов clsid


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
ПpизpакДата: Пн, 25.02.2013, 19:10 | Сообщение # 144
Новичок
Пользователи
Сообщений: 64
Награды: 0
Репутация: [ 14 ]

Здравствуйте. Может кто-нибудь объяснить что такое нет пакет?
Сегодня лазил по файлам АМК-мода и нашел там вот такой код:

[cut noguest]--- Читает STATE и UPDATE нет-пакеты сталкера и разбирает их
-- @param sobj Серверный объект сталкера
-- @return Таблица параметров сталкера
Код
function read_stalker_params(sobj)
   g_stpk:w_begin(0)
   g_uppk:w_begin(0)
   sobj:STATE_Write(g_stpk)
   sobj:UPDATE_Write(g_uppk)
   g_stpk:r_seek(2)
   g_uppk:r_seek(2)
   local tbl=parse_se_stalker({}, g_stpk, g_uppk)
   return tbl
end
[/cut]

В ACDC видел что то подобное. Они(нет пакеты) как-то связаны со спавном?


Комп: Intel Core i5 2400 3.1GHz, 8gb RAM, GeForce GTX 570 1gb, Win 7 64bit
Stalker 1.0004 + НС от 03.09.10 + DMX 1.3.5 + фикс 1.3.5 + свои правки
Stalker 1.6.02 + SGM 1.7 + свои правки


Сообщение отредактировал Пpизpак - Пн, 25.02.2013, 19:11
 
denis2000Дата: Пн, 25.02.2013, 21:40 | Сообщение # 145
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Пpизpак, net_packet - это один из вспомогательных классов. Представляет собой буфер размером ровно 8 кбайт (т.е. 8192 байта). Из буфера можно последовательно читать и записывать данные, используя методы класса. Имеется текущая позиция чтения и записи. Теперь подробности.
[cut=Информация из lua_help.script]class net_packet {
net_packet ();

number w_tell();
number r_tell();
void w_begin(number);
function r_begin(number&);
function r_advance(number);
function r_seek(number);
number r_elapsed();
bool r_eof();

number r_u8();
void w_u8(number);
number r_s8();

number r_u16();
void w_u16(number);
number r_s16();
void w_s16(number);
number r_u24();
void w_u24(number);

number r_u32();
void w_u32(number);
number r_s32();
void w_s32(number);

number r_u64();
void w_u64(unsigned __int64);
number r_s64();
void w_s64(__int64);

number r_float();
function w_float(number);
string r_stringZ();
void w_stringZ(string);
bool r_bool();
void w_bool(bool);

vector r_vec3();
void w_vec3(const vector&);
matrix r_matrix();
void w_matrix(matrix&);

vector r_sdir();
void w_sdir(const vector&);
vector r_dir();
void w_dir(const vector&);

number r_angle8();
void w_angle8(number);
number r_angle16();
void w_angle16(number);

function r_float_q8(number&, number, number);
function w_float_q8(number, number, number);
function r_float_q16(number&, number, number);
function w_float_q16(number, number, number);

function w_chunk_open8(number&);
function w_chunk_open16(number&);
function w_chunk_close16(number);
function w_chunk_close8(number);

ClientID r_clientID();
void w_clientID(ClientID&);
};[/cut]
[cut=Более подробно о методах класса]net_packet() - конструктор, вызывается в виде глобальной функции так:
local packet = net_packet()
созданный пакет по умолчанию имеет позиции чтения и записи установленные в 0
Не всегда надо создавать свой пакет. Часто приходится иметь дело с уже готовым пакетом (см. следующую статью об использовании нетпакетов)

w_tell() - возвращает текущую позицию записи
r_tell() - возвращает текущую позицию чтения
r_advance(shift) - смещает позицию чтения на shift байт. Смещение может быть отрицательным.
r_seek(pos) - устанавливает позицию чтения в pos
r_elapsed() - возвращает w_tell() - r_tell()
r_eof() - возвращает true, если r_tell() < w_tell(), иначе false

w_begin(number) - пишет двухбайтовое число в начало пакета и устанавливает позицию записи равной 2. Единственным другим способом начать запись с начала пакета - это создать новый пакет, у которого позиция записи установлена в 0.
r_begin(number&) - Непонятный метод. По аналогии с w_begin должен читать с начала пакета два байта и устанавливать позицию чтения в 2. Однако у меня приводит к вылету. Ну, в любом случае можно обойтись и без него.

Важный момент! Нет никакого способа узнать, что в процессе чтения или записи позиция чтения или записи вышла за пределы пакета. При чтении подразумевается, что прочитать можно столько, сколько записано. Для этого и есть функции r_elapsed() и r_eof(). А вот при записи никакой границы сверху нет, поэтому можно запросто записать больше, чем 8 кбайт. Ясно, что при этом произойдёт переполнение буфера с почти обязательным последующим вылетом игры. Так что надо самостоятельно следить за размером позиции записи и проверять, чтобы при последующей записи она не вышла бы за размеры пакета. Для этого надо знать, сколько мы запишем, ещё до того, как запишем. В особенности это важно для строк, которые имеют переменную длину. Поступаем примерно так:
Код
if string.len(s) + 1 + packet:w_tell() > 8192 then
-- здесь делаем что-то, например крашим игру и выводим сообщение, что не надо жадничать =)
end
packet:w_stringZ(s)Обратите внимание на "+ 1" в вычислении новой позиции записи. Строки имеют дополнительный невидимый нулевой символ в конце, и их физическая длина на один больше, чем длина в символах, которую возвращает функция string.len().

Остальные методы предназначены собственно для чтения и записи. Описывать их все в подробностях нет смысла, только общий принцип. Читаем так:
local value = packet:r_XXX()
здесь XXX - это тип значения, которое читается. Значение читается из буфера начиная с текущей позиции чтения, а позиция чтения увеличивается на размер читаемого значения. В переменную value будет помещено значение того типа, которое прочитано.
аналогично пишем в буфер:
packet:w_XXX(value)
Значение пишется начиная с текущей позиции записи, а позиция записи увеличивается на размер типа XXX.
для целых типов:
u - знаковое значение
s - беззнаковое значение
8, 16, 24, 32, 64 - один, два, три, четыре, восемь байт соответственно
Обратите внимаение, что для типа s8 (знаковый байт) нет метода записи. Подозреваю, что вместо него можно использовать соответствующий метод для беззнакового типа.
float - число с плавающей запятой одинарной точности, 4 байта
stringZ - строка (размер равен длине + 1 байт)
bool - логическое значение (1 байт)
vec3 - объект типа vector - вектор из трёх float (12 байт)
matrix - объект типа matrix. Состоит из 4-х векторов (48 байт)
sdir - ? непонятно, на запись берёт вектор и пишет 6 байт
dir - ? аналогично, но пишет 2 байта
angle8 - ? берёт float и пишет 1 байт
angle16 - ? аналогично, но пишет 2 байта
четыре последних метода при чтении у меня вызывают вылет. зачем нужны, неизвестно.
ClientID - объект класа ClientID. Судя по всему, это надо для сетевой игры.
float_q8, float_q16 - пока непонятно
Назначение методов с w_chunk_ вообще непонятно, тем более, что для них отсутствуют соответствующие методы на чтение.[/cut]
[cut=Использование объектов класса net_packet]Собственно, законное использование нетпакетов - это буфер, в котором объект сохраняет своё состояние. Скорее всего это используется в первую очередь при передаче данных по сети. Потому и net_packet, т.е. буквально "сетевой пакет". Сначала объект записывает себя в пакет, затем он отправляется по сети. Похоже, однако, что используется не только при передаче по сети, но и для сохранения объектов вообще.
Теперь конкретнее.
1. Сохранение состояния серверного класса
На серверной стороне есть классы, унаследованные от cse_abstract. У них есть методы STATE_Read и STATE_Write.
метод STATE_Read вызывается при загрузке состояния объекта из сохранёнки, в нём данные читаются из переданного методу пакета. STATE_Write вызывается при сохранении объекта, в нём данные объекта сохраняются в пакет.
Если создать свой класс и перегрузить эти методы, то увидим такую картину:
Код
class "se_my_server_class" (<имя_базового_класса>)

function se_my_server_class:STATE_Write(packet)
<имя_базового_класса>.STATE_Write(self, packet) -- базовый класс сохраняет свои данные
-- здесь можно сохранить какие-то данные, в дополнение к данным базового класса
packet:w_stringZ("моя строка")
end

function se_my_server_class:STATE_Read(packet, size)
<имя_базового_класса>.STATE_Read(self, packet) -- здесь базовый класс читает своё состояние из пакета
-- здесь можно прочитать состояние своего класса, которое было сохранено ранее
local s = packet:r_stringZ() -- получим строку "моя строка"
end
2. Сохранение состояния клиентского класса
На клиентской стороне также имеется нечто подобное. Это реализуется методами биндера save и load. При создании биндера (см. мою статью насчёт класса object_binder) можно в этих методах что-то сохранить. Однако, нетпакет используется для сохранения в методе save. в этом он подобен методу STATE_Write серверного класса. А вот при загрузке почему-то вместо нетпакета передаётся поток на чтение (класс reader). Таким образом трюкачество, описанное в следующем пункте для клиентских объектов не выйдет.

3. Перепаковка серверных объектов с целью изменения их параметров
Предыдущие два варианта использования нетпакетов - это так сказать "законное" их использование. Но это не всё. Ничто не мешает вызывать методы STATE_Read и STATE_Write в произвольный момент времени, имитируя процесс сохранения и загрузки объекта. При этом можно сделать следующее:
Код
local packet = net_packet() -- создаём пустой пакет
sobj:STATE_Write(packet) -- загрузили в наш пакет состояние серверного объекта
-- используя методы класса net_packet меняем нужные нам значения.
sobj:STATE_Read(packet, packet:w_tell()) -- записали в объект изменённое состояние обратно, имитируя процесс его загрузки
Несколько замечаний:
- Все эти манипуляции надо проводить над объектами в оффлайне, поскольку онлайновый объект регулярно обновляет серверную часть и полностью его переписывает, так что любые изменения такого рода будут потеряны.
- Надо знать структуру нетпакета для того объекта, который Вы собираетесь изменить. При таких хирургических операциях запросто можно всё испортить.[/cut]
По информации front


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
ПpизpакДата: Ср, 27.02.2013, 10:29 | Сообщение # 146
Новичок
Пользователи
Сообщений: 64
Награды: 0
Репутация: [ 14 ]

denis2000, Спасибо. А STATE и UPDATE чем различаются? STATE для серверного, UPDATE для клиентского?

Добавлено (27.02.2013, 10:29)
---------------------------------------------
denis2000,
Цитата (denis2000)
u - знаковое значение
s - беззнаковое значение

Цитата (denis2000)
что для типа s8 (знаковый байт)

Как это понимать? Насколько я знаю, здесь должно быть вот так:
u(unsigned) - беззнаковое значение
s(signed) - знаковое значение
возможно Вы/автор ошиб(лись)ся при написании статьи.

P.S. Для информации: в С++ у типа int есть модификатор unsigned, который принимает только неотрицательные(беззнаковые) значения.


Комп: Intel Core i5 2400 3.1GHz, 8gb RAM, GeForce GTX 570 1gb, Win 7 64bit
Stalker 1.0004 + НС от 03.09.10 + DMX 1.3.5 + фикс 1.3.5 + свои правки
Stalker 1.6.02 + SGM 1.7 + свои правки


Сообщение отредактировал Пpизpак - Ср, 27.02.2013, 10:30
 
denis2000Дата: Ср, 27.02.2013, 13:54 | Сообщение # 147
Полевой исследователь
Ученые сталкеры
Сообщений: 2399
Награды: 35
Репутация: [ 1918 ]

Цитата (Пpизpак)
Как это понимать?

Как написано в "Справочнике по функциям и классам" на сталкерине так и понимать. Все вопросы не ко мне, а в тему на АМК форуме.


"Он ловко выхватил из-под себя табуретку и очень метко и сильно бросил ее в докладчика..."
(Чугунный всадник)
 
KADARДата: Вт, 05.03.2013, 17:35 | Сообщение # 148
Бывалый
Пользователи
Сообщений: 126
Награды: 2
Репутация: [ 21 ]

Ребята, всем привет помощь нужна. решил адаптировать нано-броню из Monnoroch addons 1.5.2 для DMX мода 1.3.5. Делал-делал, за помощью обратился к одному человеку, ну и до делался до того что все вроде бы в норме, кроме одного в режиме брони костюм должен восстанавливать состояние костюма, но упорно этого не делает.
Все скрипты перенес что связаны с костюмом из аддона Monnoroch addons 1.5.2 и еще добавлял скрипт bind_stalker из уже вырезанного варианта этой брони для ТЧ, при этом костюм работает, но не работают функции DMX мода. Следовательно я попытался (с помощью) адаптировать скрипт bind_stalker который содержится в DMX моде, функции DMX заработали, а режим брони перестал восстанавливать состояние костюма, что делать?
Вот скрипт bind_stalker из уже вырезанного варианта этой брони для ТЧ который урезал возможности DMX. http://rghost.ru/44286613
А вот тот который адаптировался и после которого режим брони перестал восстанавливать состояние костюма
http://rghost.ru/44286659
 
banananuaДата: Ср, 06.03.2013, 09:39 | Сообщение # 149
Удаленные



Всем привет , подскажите пожалуста почему при установке немецкой озвучки отряд альфа не разговаривает на немецком икак это можно реализовать ?
 
KADARДата: Ср, 06.03.2013, 15:56 | Сообщение # 150
Бывалый
Пользователи
Сообщений: 126
Награды: 2
Репутация: [ 21 ]

banananua, нуу должны разговаривать НАЕМНИКИ если не ошибаюсь. Ты не совсем туда пишешь
 
Поиск: