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

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

Спасибо за развёрнутый коммент

Хочу кое-что добавить

 

Всё пока не буду комментировать. Остановлюсь на первом:

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

Чтобы решать такие тонкие вопросы, как использование шаблонов, нужно крайне точно ставить
задачи. Я конечно понимаю что в итоге хотелось получить, но если следовать формулировке,
то если строка начинается с пробела (ну вдруг) :
local line = ' abc'
а в условии сказано что ищем с первого символа (^ - т.е. с начала строки) и берем любые
символы кроме пробела (%S как раз и будет до первого пробела).
local var = line:match('^%S*')

то получим пустую строку (ту, что перед пробелом)

print(var) --> ''
Это соответствует условию, но не соответствует желанию.
Получается что формулировку нужно подкорректировать (вариаций множество, но нужно
остановиться на ближайшей к исходной - всё кроме пробелов) хотя бы так:

Функция возвращает первое вхождение не пробельных символов

И если так, то нужно и искать не пробельные символы :

local var = line:match('%S+')
А чтобы функция, при отсутствии вхождения, возвращала не 'nil' а пустую строку,
(в исходнике упоминание тут - if not contains(line," ") then return "" end) то:
local var = line:match('%s*(%S*)')

Хотел остановиться только на первом, но скажу и о проверке "на дурака".

if line == nil then return nil end
-- или
local var = line and line:len()
От дурака нужно защищаться по полной.
В первом случае проверятся что 'line' не 'nil', во втором что ещё и не 'false'.
И всё. А что если 'line' будет каким-либо другим типом данных, отличных от 
'string' ? Правильно - защита ни к черту.
 
Я уже где-то писал, что использовать методы библиотеки 'string' нужно тогда,
когда вы уверены что 'line' всегда будет строкой и только строкой.
Вызов функции 'string.match(line, ...)' допускает передачу в 'line' помимо строки
ещё и числа. Но этого всё равно мало "от дурака".
 
Нужно явно проверять то, что 'line' это 'строка', если используете метод (line:match),
или "строка или число" если используете функцию (string.match(line, ...)).
 
А если не хочется в каждой функции писать проверки, создайте защищенные (protected)
функции строк. Типа :
function string.pmatch(s, p)
    local t = type(s)
    if t == 'string' or t == 'number' then
        return string.match(s, p)
    end
    -- тут можно выдать сообщение о не верном аргументе
    return '' -- раз функция защищенная, то и возвращать стоит пустую строку а не nil
              -- впрочем пусть каждый сам для себя решает, что ему нужнее
end

 

 

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

 

 

Хочу кое-что добавить

Спасибо, что Вы заметили эту проблему. А это именно проблема, т.к. в «Сталкере» строковые типы являются по сути основными (вспомните все идентификаторы, секции, просто текстовые строки, xml и т.д. и т.п) и самыми «перекидываемыми» между всеми другими методами данными. Но, вот внимания к ним, «подумаешь строка», прослеживается явно пренебрежительное. Напрасно. Я не собирал статистики, но просматривая сообщения на разных форумах, увидел, что доля вылетов в различных модах - так или иначе связаны с некорректной работой именно с данными типа “string”. Лично я в своих поделках использую тип, который для себя называю «суперстрока» - “sstring”. Это разумеется никакое не «супер», а просто некоторые расширения базового типа и много - много разных проверок. Лишние затраты ресурсов есть? Обязательно. Выгоды есть? Мне кажется да. Небольшую часть из этого типа я привёл в своём сообщении и то только в качестве примеров подхода, а не конечной реализации. Из этого надо и исходить.

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

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

Подскажите, пожалуйста, как узнать значение отношения группировки к гг?

То есть я изменяю значение так: relation_registry.set_community_goodwill ("stalker", db.actor:id (), 5000)

К примеру как должна работать правильно проверка?:

 

if relation_registry.set_community_goodwill ("stalker", db.actor:id ()) > 2000 then

действие

end

 

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

@Kirgudu, Спасибо большое))).

Если разбираешь подскажи ещё как тоже узнать личное отношение персонажа?

И вообще есть общая функция, в которую уже все входит, чтобы определить суммарное отношение(личное отношение, отношение группировки, и т.п.) к актеру?

Ссылка на комментарий
npc:goodwill(db.actor) -- результат - число
npc:relation(db.actor) -- результат - одно из значений game_object.enemy | game_object.neutral | game_object.friend

Примеры использования можно найти в оригинальных скриптах игры.

Вообще, поиск по файлам с помощью, например, TC, может дать много интересной и полезной информации.

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

 

 

Примеры использования можно найти в оригинальных скриптах игры. Вообще, поиск по файлам с помощью, например, TC, может дать много интересной и полезной информации.

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

 

Сорри за флуд, не мог пройти мимо.

Сталкер - наше всё!

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

 

 

подскажи ещё как тоже узнать личное отношение персонажа? И вообще есть общая функция, в которую уже все входит, чтобы определить суммарное отношение(личное отношение, отношение группировки, и т.п.) к актеру?

goodwill

general_goodwill

relation_registry.community_goodwill

расшифровывать думаю излишне, должно быть понятно из названий ф-ций...

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

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

function hud_bread()
local act_it = db.actor:active_item()
if act_it and act_it:section() == "bread" then
Ссылка на комментарий

 

 

а функции использования предмета неправильная.

в таком виде она не может быть правильной. Метод active_item() возвращает клиентский объект в активном слоте.

Правда, я ни разу не пробовал стрельнуть из "батона", но что-то мне подсказывает, что такое вряд-ли возможно и позтому act_it:section() == "bread" всегда будет false.

Но, я могу и ошибаться.

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

Вопрос к знающим.

Модуль se_stor на ЗП периодически, на переходе между локами, не сохраняет статистику ГГ, либо же не может её считать из сохранения.

В ЗП переход осуществляется же посредством проводников, и сохранения делаются дважды - первое на старой локе, возле проводника, именное, а второе - автосейв при переходе на локу, как в остальных играх серии. Так вот, иногда при переходе автосейв бъётся. Вылет с руганью, что se_stor не может прочитать статистику из чанка. При этом, если загрузиться с предыдущего сохранения, которое именное ("... - переход с ... на ...), и опять перейти, то уже переход осуществляется нормально, и статистика сохраняется и считывается. И в дальнейшем можно играть без проблем довольно продолжительное время, и переходить с локи на локу без каких-либо проблем, до момента Х, когда при очередном переходе не сохраняется, либо не считывается опять статистика.

При сохранении в чанки тоже стоит предохранительный выкид из игры, если вдруг какие-то данные для сохранения будут неверные/пустые. Но он никогда не срабатывал. Только при загрузке.

Просто хотелось бы понять, в сторону чего копать: железо, сам se_stor, движок?

Скрипты статистики я не трогал, сразу говорю...

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

Шаман - СисАдмин

Всяко-разно: для ЧН

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

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

-- Записываем переменную
function save_variable(variable_name, value)
	xr_logic.pstor_store(db.actor, variable_name, value)
end

-- Загружаем переменную
function load_variable(variable_name, value_if_not_found)
	return xr_logic.pstor_retrieve(db.actor, variable_name, value_if_not_found)
end

-- Удаляем переменную
function del_variable(variable_name)
	if db.storage[db.actor:id()].pstor[variable_name] then
		db.storage[db.actor:id()].pstor[variable_name] = nil
	end
end

читая в xr_logic , понял, что таким образом сохраняются переменные в пакеты. Но был бы не против, что бы мне разжевали эту тему по самые самые. Есть ли подводные камни, или ограничения? Смогу ли я допустим туда целый текст запихнуть? или что то в этом духе. Или , скажем, на каждую аномалию записывать на неё какие то уникальные значения, которые можно будет использовать? Где вообще найти какой Faq про сохранение переменных или текста в игре, что бы всё яснопонятно?

... А наше дело маленькое - с ружьём да по болотам. (с)

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

Модуль se_stor на ЗП периодически, на переходе между локами, не сохраняет статистику ГГ, либо же не может её считать из сохранения.

Проблема нами с автором вопроса решена, исправленный модуль se_stor выложен в теме «Сборочный цех».

 

Что касается обещанных мной подробностей.

Как известно, при создании нового net-пакета в ЗП и ЧН позиция записи может не быть автоматически установлена на начало, и чтобы запись в пакет происходила как положено, позиция записи должна быть изменена принудительно методом packet:w_begin(0). Об этом уже неоднократно писалось, например здесь.

Однако было обойдено вниманием (или, по крайней мере, я не нашёл на форуме соответствующей информации) то, что для «чистого» net-пакета может не быть нулём также и позиция чтения. При этом packet:r_tell() для этого пакета возвращает, например, 263.

Такая ситуация встречается как минимум в ЗП, вероятно и в ЧН тоже.

@Artos не учёл это в модуле se_stor, либо просто забыл исправить, что и привело к вышеописанным вылетам. Теперь данной ошибки модуль лишён.

 

А решение простое - после создания нового net-пакета следует принудительно выставлять как позицию записи, так и позицию чтения:

local packet = net_packet()
packet:w_begin(0) --/ установка позиции записи в начало net-пакета (+2 технологических байта)
packet:r_seek(0) --/ установка позиции чтения с начала net-пакета

@Max_Raf, указанным тобой способом данные сохраняются в pstor игрока, а значит имеют ограниченный общий объём, не превышающий размера net-пакета для соотв. платформы (около 8 КБ для ТЧ и 16 КБ для ЧН/ЗП). «Войну и мир» ты в них не запихнёшь, так как переполнение гарантированно приведёт к порче сохранений.

Если есть необходимость сохранять что угодно и сколько угодно, лучше посмотреть в сторону так называемых универсальных хранилищ. Что это такое - неоднократно тут объяснялось и обсуждалось, с примерами, инструкциями и т. п. Информацию легко найти; достаточно сделать поиск по форуму или, для начала, заглянуть в тему «Сборочный цех».

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

 

 

в таком виде она не может быть правильной
А как быть тогда? Может быть так?
function use_bread_oz(obj)
    if obj ~= nil then
        if obj:section() == "bread" then
            for i = 1, 1 do --Совершаем спавн 1 раз
           alife():create(:"Любой предмет", db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id(), db.actor:id())
       end
end
    end
end
Ссылка на комментарий

 

 

Может быть так?

Можно и так, но лучше немного причесать.

Но, главное здесь, на мой взгляд, "не как"?, а для чего это надо и отсюда вытекает, где это событие надо отлавливать и реализовывать. Если Вы хотите, чтобы вместо "закусить" ГГ получил ещё бутылёк - это одна цель. Или же при покупке  батона у торговца за 20 р., он плучал вместо этого "Вал" - то это другая. Могут быть ещё и масса других.

А сама процедура спавна или замены одного объекта другим тривиальна и очень подробно описана во многих местах.

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

Возник вопрос - как запустить определенный код (речь о Lua)  после начала новой игры в CoP (т.е. оно должно отработать 1 раз).

Найти чего-то подходящего именно к такому случаю - я не смог, запихнуть в actor_proxy:net_spawn - вариант, но в случае CoP - срабатывает оно ещё до полной загрузки, а в update - как-то не айс запихивать сюда одноразовое событие же.

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

@alex4321, другого не дано, только апдейт, заюзай системы событий, подпишешь - отпишешь.

Спасибо, пытаюсь приюзать xs_sandbox. Вроде как устройство вполне прозрачное, но вызвать обработчик пока не получается.

В _g.script инициализация добавлена.

-- list of registered modules, can have dependence one from other (must be grouped in table)
-- in every module must be an "init()" function for module's initialization
-- for some events (like packet save or load) order is VERY important
binds = {
	"a4_system",
}
function actor_binder:update(delta)
	object_binder.update(self, delta)

	if string.find(command_line(), "-designer") then
		return
	end
--надо бы проверить, не отработал ли этот return
	if self.already_jumped==false and jump_level.need_jump==true and (device().frame > self.spawn_frame+2000) then
		jump_level.try_to_jump()
		self.already_jumped = true
		return
	end
...
	event("actor_update"):trigger({})
end

 

Соответственно, если я всё делаю правильно - то будет вызван обработчик, повешенный к actor_update

function a4_message()  
  local actor = alife():actor()
  local cactor = level.object_by_id(sactor.id)
  cactor:give_game_news(
    "Свободу тушканам!\\nТушканчики всех стран, объединяйтесь!", -- строка сообщение, может быть многострочной
    "ui\\ui_npc_monster",        --текстура, из которой берется аватара "отправителя"
    Frect():set(0,215,163,105),  --координаты и размеры вырезаемого из текстуры изображения
    1000,     --начало показа сообщения с текущего момента (в миллисекундах)
    50000                         --длительность показа сообщения (в миллисекундах)
  )
end

function a4_on_update()
  -- Вполне вероятные ошибки в работе с net_packet-м, но доэтой стадии не доходит, т.к. попытка вызвать a4_message() ни к чему не приводит
  local packet = net_packet()
  local new_game = packet:r_u8() != 1
  if new_game then
    event("game_new"):trigger({})
    packet:w_u8(1)
  end
  event("actor_update"):unregister(a4_on_update)
end

function a4_on_new_game()
  a4_message()
end

function init()
  event("game_new"):register(a4_on_new_game)
  event("actor_update"):register(a4_on_update)
end

 

Но (см. комментарий) сообщения нет. 

з.ы. и да, проблема не в выводе сообщения - даже явное return 1/0 не приводит к вылету :-) (т.ею. до a4_message не доходит, при этом - даже если она вызывается из a4_on_update)

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

Портянки прячем под спойлер!

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

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

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

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

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

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

Войти

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

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

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

AMK-Team.ru

×
×
  • Создать...