Skip to content
AliceCyber edited this page Jan 25, 2022 · 3 revisions

Объекты -- это единицы сцены, с которыми взаимодействует игрок.

Создание обектов

obj {
    nam = 'стол';
    dsc = 'В комнате стоит {стол}.';
    act = 'Гм... Просто стол...';
};

Имя объекта ''nam'' используется при попадании его в инвентарь. Хотя, в нашем случае, стол вряд ли туда попадет. Если у объекта определен 'disp', то при попадании в инвентарь для его отображения будет использоваться именно этот атрибут. Например:

obj {
    nam = 'стол';
    disp = 'угол стола';
    dsc = 'В комнате стоит {стол}.';
    tak = 'Я взялся за угол стола';
    inv = 'Я держусь за угол стола.';
};

Все-таки стол попал к нам в инвентарь.

Вы можете скрывать отображение предмета в инвентаре, если 'disp' атрибут будет равен 'false'.

'dsc' -- описание объекта. Оно будет выведено в динамической части сцены, при наличии объекта в сцене. Фигурными скобками отображается фрагмент текста, который будет являться ссылкой в окне INSTEAD. Если объектов в сцене много, то все описания выводятся одно за другим, через пробел,

'act' -- это обработчик события, который вызывается при действии пользователя (действие на объект сцены, обычно -- клик мышкой по ссылке). Его основная задача -- вывод (возвращение) строки текста, которая станет частью событий сцены, и изменение состояния игрового мира.

Инвентарь

Простейший вариант сделать объект, который можно брать -- определить обработчик 'tak'.

Например:

obj {
	nam = 'яблоко';
	dsc = 'На столе лежит {яблоко}.';
	inv = function(s)
		p 'Я съел яблоко.'
		remove(s); -- удалить яблоко из инвентаря
	end;
	tak = 'Вы взяли яблоко.';
};

При этом, при действии игрока на объект "яблоко" (щелчок мыши на ссылку в сцене) -- яблоко будет убрано из сцены и добавлено в инвентарь. При действии игрока на инвентарь (двойной щелчок мыши на названии объекта) -- вызывается обработчик 'inv'.

В нашем примере, при действии игроком на яблоко в инвентаре -- яблоко будет съедено.

Конечно, мы могли бы реализовать код взятия объекта в ''act'', например, так:

obj {
	nam = 'яблоко';
	dsc = 'На столе лежит {яблоко}.';
	inv = function(s)
		p 'Я съел яблоко.'
		remove(s); -- удалить яблоко из инвентаря
	end;
	act = function(s)
		take(s)
		p 'Вы взяли яблоко.';
	end
};

Если у объекта в инвентаре не объявлен обработчик 'inv', будет вызван 'game.inv'.

Если обработчик 'tak' вернет false, то предмет не будет взят, например:

obj {
	nam = 'яблоко';
	dsc = 'На столе лежит {яблоко}.';
	tak = function(s)
		p "Оно же червивое!"
		return false
	end;
};

Объект "Мир"

Игровой мир представлен объектом типа world. Имя такого объекта 'game'. Существует ссылка-переменная, которая также называется game.

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

Например, переменная game.codepage содержит кодировку исходного кода игры, и по-умолчанию равна "UTF-8". Я не рекомендую использовать другие кодировки, но иногда, выбор кодировки может стать необходимостью.

Переменная game.player -- содержит текущего игрока.

Кроме того, как вы уже знаете, объект 'game' может содержать обработчики по умолчанию: 'act', 'inv', 'use', 'tak', которые будут вызваны, если в результате действий пользователя не будут найдены никакие другие обработчики (или все они вернули false). Например, вы можете написать в начале игры:

game.act = 'Не получается.';
game.inv = 'Гм.. Странная штука..';
game.use = 'Не сработает...';
game.tak = 'Не нужно мне это...';

Конечно, все они могут быть функциями.

Также, объект game может содержать обработчики: onact, ontak, onuse, oninv, onwalk -- которые могут прерывать действия, в случае возврата false.

Еще, у объекта game можно задать обработчики: afteract, afterinv, afteruse, afterwalk -- которые вызываются в случае успешного выполнения соответствующего действия.

Декорации

Объекты, которые могут быть перенесены из одной сцены в другую (или попадать в инвентарь), обычно имеют имя и/или переменную-ссылку. Так как таким образом вы всегда можете найти объект где угодно и работать с ним.

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

Таких объектов может быть очень много, и более того, обычно это однотипные объекты вроде деревьев и тому подобных объектов.

Для создания декораций можно использовать различные подходы.

Один и тот же объект в нескольких комнатах

Вы можете создать один объект, например, 'дерево' и помещать их в разные комнаты.

obj {
	nam = 'дерево';
	dsc = [[Тут стоит {дерево}.]];
	act = [[Все деревья выглядят похожими.]];
}

room {
	nam = 'Лес';
	obj = { 'дерево' };
}

room {
	nam = 'Улица';
	obj = { 'дерево' };
}

Использование тегов вместо имен

Если вам не нравится придумывать уникальные имена для однотипных декоративных объектов, вы можете использовать для таких объектов теги. Теги задаются атрибутом tag и всегда начинаются с символа '#':

obj {
	tag = '#цветы';
	dsc = [[Тут есть {цветы}.]]
}

В данном примере, имя у объекта будет сформировано автоматически, но обращаться к объекту вы сможете по тегу. При этом объект будет искаться в текущей комнате. Например:

dprint(_'#цветы') -- ищем в текущей комнате первый объект с тегом '#цветы'

Теги, это в каком то смысле, синоним локальных имен, поэтому существует альтернативная запись создания предмета с тегом:

obj {
	nam = '#цветы';
	dsc = [[Тут есть {цветы}.]]
}

Если имя у объекта начинается с символа '#', то такой объект получает тег и автоматически сгенерированное числовое имя.

Функции, которые возвращают объекты

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

  • в символах [ ] описаны необязательные параметры;
  • 'что' или 'где' - означает объект (в том числе комнату), заданный тегом, именем или переменной-ссылкой;

Итак, основные функции:

  • '_(что)' - получить объект;
  • 'me()' возвращает текущего объекта-игрока;
  • 'here()' возвращает текущую сцену;
  • 'where(что)' возвращает комнату или объект в котором находится заданный объект, если объект находится в нескольких местах, то можно передать второй параметр -- таблицу Lua, в которую будут добавлены эти объекты;
  • 'inroom(что)' аналогично where(), но вернет комнату, в которой расположен объект (это важно для объектов в объектах);
  • 'from([где])' возвращает прошлую комнату, из которой игрок перешел в заданную комнату. Необязательный параметр -- получить прошлую комнату не для текущей комнаты, а для заданной;
  • 'seen(что, [где])' возвращает объект или переход, если он присутствует и видим, есть второй необязательный параметр -- выбрать сцену или объект/список в котором искать;
  • 'lookup(что, [где])' возвращает объект или переход, если он существует в сцене или объекте/списке;
  • 'inspect(что)' возвращает объект, если он виден/доступен на сцене. Поиск производится по переходам и объектам, в том числе, в объектах игрока;
  • 'have(что)' возвращает объект, если он есть в инвентаре и не отключен;
  • 'live(что)' возвращает объект, если он присутствует среди живых объектов (описано далее);

Эти функции в основном используются в условиях, либо для поиска объекта с последующей модификацией. Например, вы можете использовать 'seen' для написания условия:

onexit = function(s)
	if seen 'монстр' then -- если у функции 1 параметр,
		--- скобки писать не обязательно
		p 'Монстр загораживает проход!'
		return false
	end
end

А также, для нахождения объекта в сцене:

use = function(s, w)
	if w^'окно' then
		local ww = lookup 'собака'
		if not ww then
			p [[А где моя собака?]]
			return
		end
		place(ww, 'улица')
		p 'Я разбил окно! Моя собака выпрыгнула на улицу.'
		return
	end
	return false
end

Пример с функцией 'have':

...
act = function(s)
	if have 'нож' then
		p 'Но у меня же есть нож!';
        return
	end
	take 'нож'
end
...

Может возникнуть вопрос, в чем разница между функциями lookup и _ ()? Дело в том, что lookup() ищет объект, и в случае, если объект не найден -- просто ничего не вернет. А запись _ () предполагает, что вы точно знаете, что за предмет вы получаете. Другими словами, _ () это безусловное получение объекта по имени. Эта функция в общем случае не занимается поиском. Только если в качестве параметра задан тег, будет осуществлен поиск среди доступных объектов. Если вы используете _ () на несуществующий объект или недоступный тег -- вы получите ошибку!

Объекты, связанные с другими объектами

Объекты тоже могут содержать в себе атрибут 'obj' (или конструкцию 'with'). При этом, при выводе объектов, INSTEAD будет разворачивать списки последовательно. Такая техника может использоваться для создания объектов-контейнеров или просто для связывания нескольких описаний вместе. Например, поместим на стол яблоко.

obj {
	nam = 'яблоко';
	dsc = [[На столе лежит {яблоко}.]];
	act = 'Взять что-ли?';
};

obj {
	nam = 'стол';
	dsc = [[В комнате стоит {стол}.]];
	act = 'Гм... Просто стол...';
	obj = { 'яблоко' };
};

room {
    nam = 'Дом';
	obj = { 'стол' };
}

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

Также, следует отметить, что оперируя объектом 'стол' (например, перемещая его из комнаты в комнату) мы автоматически будем перемещать и вложенный в него объект 'яблоко'.

Конечно, данный пример мог бы быть написан и по другому, например, так:

room {
	nam = 'Дом';
}:with {
	obj {
		nam = 'стол';
		dsc = [[В комнате стоит {стол}.]];
		act = 'Гм... Просто стол...';
	}: with {
		obj {
			nam = 'яблоко';
			dsc = [[На столе лежит {яблоко}.]];
			act = 'Взять что-ли?';
		};
	}
}

Выбирайте тот способ, который для вас понятней.