Skip to content

Fenia global triggers

Ruffina Koza edited this page Oct 9, 2019 · 9 revisions

Глобальные триггеры

Можно объявить так называемые 'глобальные' триггера, которые будут вызываться всегда, как только в мире происходит какое-то событие. Например, триггер onDeath, объявленный на конкретном персонаже, вызовется только во время смерти этого персонажа, тогда как глобальный триггер onDeath будет вызываться при смерти каждого.

Для каждого глобального события можно задать несколько независимых обработчиков, см. ниже.

Список существующих триггеров

onDeath(ch, killer) - персонаж ch умер, его убийца - это killer (может быть равен как самому персонажу ch, так и null в некоторых случаях).

onSpeech(ch, msg) - персонаж ch произнес реплику msg.

onLore(ch, obj) - персонаж выполнил команду легенды (lore) на этот предмет и умение выучено достаточно хорошо. Вывести персонажу дополнительную информацию по предмету.

onSpec(ch) - вызывается каждые 4 секунды только для PC.

(далi буде)

Объявление триггеров

Для удобной работы с глобальными триггерами используется команда fenia. Вот ее краткий синтаксис:

Использование:
fenia add <trigger> <label> - добавить новый триггер с меткой или редактировать существующий
fenia del <trigger> <label> - удалить триггер с данной меткой
fenia list                  - перечислить все объявленные триггера и метки

По команде fenia add будет открыт веб-редактор для сценариев, поэтому эта команда работает только из веб-редактора.

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

Если после запуска fenia add и нажатия на кнопку Save в редакторе выдается синтаксическая ошибка, это значит, что сценарий не выполнился успешно и триггер не присвоился. Продолжить его редактировать и исправлять ошибку можно двумя способами: командой cs web и той же командой fenia add, нажав после открытия редактора Ctrl z.

Примеры:

fenia add onReset show_limits        - добавляем новый обработчик события onReset с меткой show_limits
fenia add onReset update_counters    - добавляем новый обработчик события onReset с меткой update_counters
fenia list                           - смотрим, какие обработчики и для каких событий уже объявлены
fenia add onReset show_limits        - редактируем существующий обработчик с этой меткой
fenia del onReset show_limits        - удаляем этот обработчик

Системные заметки

Все триггера хранятся в глобальном Array под названием .tmp.gtrig. Ключом служит полное название триггера (onLore, onReset), а значением - еще один Array. Таким образом, каждый вид триггера может иметь несколько независимых реализаций.

Примеры:

  • .tmp.gtrig["onDeath"]["spellbook"] - загружает в труп моба книгу заклинаний
  • .tmp.gtrig["onDeath"]["artifact"] - загружает в труп моба некий артефакт
  • .tmp.gtrig["onDeath"]["tattoo"] - загружает в труп моба рисунок татуировки
  • .tmp.gtrig["onLore"]["describe_fenia"] - иносказательно выдает по команде lore информацию о существующих триггерах на предмете

Когда в мире происходит событие (умер моб, набрали команду lore), вызывается феневая функция .tmp.trigger_handler. Ей в параметры передается название триггера (например, onDeath) и список аргументов для этого типа триггера (например, ch и killer). Функция .tmp.trigger_handler вызовет подряд все ф-ии, объявленные внутри, к примеру, .tmp.gtrig["onDeath"].

Команда fenia и .tmp.trigger_handler реализованы в этом сценарии, хотя не исключено, что они будут разнесены по разным сценариям в будущем.

Пример триггера onDeath

Для работы с этим примером наберите fenia add onDeath example и скопируйте тело примера в окно редактора, заменив его содержимое.

.tmp.gtrig["onDeath"]["example"] = function(vict, killer) {
	// Пример того, как с некоторой вероятностью при смерти
	// моба у него в трупе появляется случайная драгоценность.
	// А также пример "предсмертного хрипа".
	
	// Ничего не делать, если умер персонаж игрока.
	if (!vict.is_npc())
		return;
	
	// Ничего не делать, если умерли от яда или еще как-то странно
	if (killer == null || vict == killer)
		return;
	
	// При желании, можно сделать чтоб не реагировала на убийства от мобов.
	if (killer.is_npc())
		return;
		
	// Шанс можно сильно уменьшить.
	//if (.chance(10))
	//    return;
		
	// Генерировать драгоценность только для гномов.
	// На локальной версии нету мобов-гномов, их придется создать или
	// изменить это условие.
	if (vict.race.name == "gnome") {
		var gem_vnum, gem;
		
		// Один из драгоценных камней в Мидгаарде.
		gem_vnum = .number_range(3374, 3377);
		gem = .get_obj_index(gem_vnum).create();
		// Дать жертве в инвентарь, чтобы в итоге оказалось в ее трупе.
		gem.obj_to_char(vict);
		return;
	}
	
	// Мобы из арии Долина Титанов перед смертью что-то произносят,
	// что имено - слышит только убийца, стоЯщий рядом.
	if (vict.pIndexData.area.filename == "titan.are") {
		vict.rvecho(killer, "%^C1 хрипит какие-то слова на древнем наречии.", vict);
		
		if (killer.in_room == vict.in_room) {
			var phrase;
			
			// Quote some Edda at them.
			phrase = .List().add(
				"Ask veit ek standa, heitir Yggdrasill", 
				"Sol varm sunnan, sinni mana",
				"Hljoths bith ek allar, helgar kindir"
				).random();
				
			killer.act("%^C1 хрипит, указывая на тебя: {c%s...{x", vict, phrase);
			killer.act("Ты чувствуешь древнюю силу, заключенную в этих словах.");
		}   
		return;
	}
}

Пример триггера onSpeech

.tmp.gtrig["onSpeech"]["example"] = function(ch, msg) {
	// В этом триггере описаны реакции на реплики, произнесенные где угодно
	// в мире. Некоторые слова, сказанные вслух, обладают особыми свойствами.
	// Но чтобы слова сработали, они должны быть "известны" персонажу, т.е.
	// запомнены в его поле phrases. К примеру, персонаж должен был услышать
	// это слово от убитого им моба.
	
	// Для тестирования выполните:
	// eval phrases=.List().add("ellisande")
	// eval get_char_room("vasya").phrases = .List().add("carai", "ellisande")
	
	var phrase;
	
	// Не реагировать на реплики мобов.
	if (ch.is_npc())
		return;
		
	// Этот блок должен быть в другом сценарии, но для простоты отладки объявлен
	// здесь. .tmp.phrases - глобальное хранилище слов и их спецэффектов.
	if (.tmp.phrases == null) {
		.tmp.phrases = .Array();
		.tmp.phrases["carai"] = function(ch) {
			if (ch.fighting != null)
				ch.spell("fireball", 100, ch.fighting);
			else
				ch.spell("bless", 100, ch);
		};
		.tmp.phrases["ellisande"] = function(ch) {
			ch.spell("healing light", 100);
		};
	}
	
	// Пытаемся найти сказанную фразу в хранилище слов. Если фраза найдена,
	// переменная phrase будет содержать соответствующую функцию.
	phrase = .tmp.phrases[msg.toLower()];
	if (phrase == null)
		return;
	
	// Пытаемся найти фразу среди тех, что известны этому персонажу.
	if (ch.phrases == null || !ch.phrases.has(msg.toLower())) {
		ch.act("...и ничего не происходит.");
		return;
	}
	
	// Всё хорошо, вызываем функцию со спецэффектом.
	ch.act("Ты чувствуешь древнюю силу произнесенных слов.");
	phrase(ch);
	
	// Здесь можно "забыть" фразу или уменьшить ее силу (если хранить на персонаже
	// не список, а например массив.
}
You can’t perform that action at this time.