Я уже говорил, что ООП в Корсарах нет. И тем не менее, в уроке о типах данных я писал о неких структурах, которые называются объектами. Давайте разбираться.
Объекты
Объект представляет собой древовидную текстовую структуру произвольной формы. Это означает, что он может хранить любое количество полей в текстовой форме (string), хотя указание числа без кавычек тоже допускается.
// синтаксис
object object_name;
// пример
object Sky;
if (!isEntity(&Sky))
{
CreateEntity(&Sky, "Sky");
}
Sky.State = "sunset";
Sky.Size = 10;
Sky.Angle = "25.0f";
float skyAngle = stf(Sky.Angle); // 25.0f
int skySize = sti(Sky.Size); // 10
Не забываем, что данные в структуре хранятся в текстовом формате string. Поэтому перед использованием их необходимо конвертировать в соответствующий тип данных при помощи функций, которые мы рассматривали в разделе преобразование типов.
Неинициализированные объекты по-прежнему могут создаваться и использоваться в скриптах, за исключением того, что они не будут восприниматься таковыми API движка.
К объектам также можно получить доступ по ссылке, определяемой как ref. Обычно это используется для доступа к определенному объекту внутри массива. Сама ссылка создается при помощи функции makeref(). Синтаксис использования ссылки идентичен использованию объекта.
// синтаксис
object obj_name;
ref ref_name;
makeref(ref, obj);
// пример
object SkyStates[SKY_STATES_N];
ref Sky;
int n = 0;
// итерируем элементы
makeref(Sky, SkyStates[n]);
Sky.State = "sunset";
Sky.Size = "10";
Sky.Angle = "25.0f";
n++;
К атрибуту объекта также можно получить доступ по ссылке типа aref. Аналогично ref, для создания такой ссылки есть специальная функция makearef():
// синтаксис
obj obj_name;
aref aref_name;
makearef(aref, obj);
// пример
object Item;
aref ItemType;
Item.type = "sword";
makearef(ItemType, Item.type);
Если вы обращаетесь к атрибуту через переменную, следует поместить эту переменную в скобки:
aref aSky;
string attribute = "d20";
aSky.Dir.d20 = "NNE"; // OK
aSky.Dir.(attribute) = "NNE"; // OK
aSky.Dir.attribute = "NNE"; // ошибка
Цитата Rosarak:
Движок по-разому воспринимает числа, переданные в виде int и string.
Нужно быть очень внимательным и, во избежание путаницы, конвертировать все числа в string при помощи ф-ций вроде its(i) или сложение с пустой строкой s = "" + i. А лучше вообще отказаться от числовых имен атрибутов и всегда добавлять к имени какую-то букву.int iNumber = 4; string sNumber = "4"; pchar.biba.(iNumber).boba = "some data"; // это один атрибут pchar.biba.(sNumber).boba = "some data"; // а это совсем другой string sNumber = its(iNumber); pchar.biba.(sNumber).boba = "some data"; // а вот это попадет в тот же атрибут, что на предыдущей строке string sNumber = "" + iNumber; pchar.biba.(sNumber).boba = "some data"; // и это тоже
Атрибуты
Для удобной работы с атрибутами есть целый ряд функций. Они позволяют уйти от ручного доступа к атрибутам объекта, позволяя таким образом автоматизировать обработку и поиск атрибутов в цикле, а также создавать унифицированные функции.
GetAttributesNum
// синтаксис
int GetAttributesNum(object obj);
int GetAttributesNum(ref obj);
int GetAttributesNum(aref attribute);
// пример
int count = GetAttributesNum(arRoot);
for (i = 0; i < count; i++)
{
aref attribute = GetAttributeN(arRoot, i);
// ...
// Манипуляции с атрибутом
// ...
}
GetAttributesNum - подсчитывает, сколько дочерних атрибутов имеет объект (нерекурсивно).
object obj, ref obj, aref attribute - объект или атрибут, для которого будут посчитаны дочерние атрибуты.
Как правило, эта функция используется вместе с GetAttributeN() для итерирования атрибутов.
GetAttributeN
// синтаксис
aref GetAttributeN(object obj, int index);
aref GetAttributeN(ref obj, int index);
aref GetAttributeN(aref attribute, int index);
// пример
int count = GetAttributesNum(arRoot);
for (i = 0; i < count; i++)
{
aref attribute = GetAttributeN(arRoot, i);
// ...
// Манипуляции с атрибутом
// ...
}
GetAttributeN - осуществляет доступ к дочернему атрибуту по индексу.
object obj, ref obj, aref attribute - объект или атрибут, дочерние атрибуты которого перебираются.
int index - порядковый номер атрибута, к которому осуществляется доступ.
Эта функция, в основном, используется в цикле, совместно с GetAttributeNum(), для перебора атрибутов объекта.
GetAttributeName
// синтаксис
string GetAttributeName(object obj);
string GetAttributeName(ref obj);
string GetAttributeName(aref attribute);
// пример
object Test;
Test.value = "hello";
string attrName = GetAttributeName(Test.value); // "value"
GetAttributeName - возвращает имя переданного атрибута или объекта.
object obj, ref obj, aref attribute - объект или атрибут, имя которого нужно получить.
GetAttributeValue
// синтаксис
string GetAttributeValue(object obj);
string GetAttributeValue(ref obj);
string GetAttributeValue(aref attribute);
// пример
object Test;
Test.value = "hello";
string attrValue = GetAttributeValue(Test.value); // "hello"
GetAttributeValue - возвращает значение переданного атрибута или объекта.
object obj, ref obj, aref attribute - объект или атрибут, значение которого нужно получить.
Помните, что каждое значение хранится как строка! Сохраненные объекты, числа с плавающей точкой и целые числа необходимо преобразовать соответствующим образом перед использованием.
CopyAttributes
// синтаксис
void CopyAttributes(object &destination, object source);
// пример
object Tmp;
CopyAttributes(&Tmp, CargoOne);
CopyAttributes - копирует все атрибуты объекта в новый объект.
object &destination - ссылка на объект, в который будут скопированы атрибуты.
object source - объект, с которого будет снята копия.
DumpAttributes
// синтаксис
void DumpAttributes(object obj);
void DumpAttributes(ref obj);
void DumpAttributes(aref attribute);
// пример
trace("nConditionsNum : " + nConditionsNum);
DumpAttributes(conditions);
DumpAttributes - трассировка (лог) всех данных об атрибутах заданного объекта.
object obj, ref obj, aref attribute - объект или атрибут, с которого снимается дамп.
CheckAttribute
// синтаксис
bool CheckAttribute(object &obj, string attribute);
// пример
if (!CheckAttribute(&Weather, "Stars.Enable"))
{
Weather.Stars.Enable = false;
};
CheckAttribute - проверка существует ли атрибут.
object &obj - ссылка на объект, для которого проверяется атрибут.
string attribute - имя атрибута.
TestRef
// синтаксис
bool TestRef(ref target);
bool TestRef(aref target);
// пример
bool LAi_CheckCharacter(aref chr, string out)
{
if (!TestRef(chr))
{
Trace("LAi_CheckCharacter -> invalid aref, call from " + out);
return false;
}
return true;
}
TestRef - проверка, что атрибут или объект все еще существует.
ref target, aref target - ссылка на объект или атрибут, который проверяем.
DeleteAttribute
// синтаксис
void DeleteAttribute(object obj, string attribute);
// пример
DeleteAttribute(&Sky, ""); // очистить объект
DeleteAttribute(pchar, "Items"); // удалить все предметы у персонажа
string sQuest2 = "quest.Deposits." + city + "_Type2";
DeleteAttribute(pchar, sQuest2);
DeleteAttribute - удаляет атрибут (поле и данные) из указанного объекта.
object obj - объект, из которого удаляем.
string attribute - имя атрибута, который удаляем.
Если передать "" (пустую строку) в качестве имени атрибута - будут удалены все атрибуты объекта.
И что там со временем жизни ссылок, про стек, про аллокацию в хип
А то они сейчас выглядят как документация, а не обучающий материал для новичка. 😅
Ред. avuremybe
Проблема была в восприятии движком числа в int и числа в string по-разному.