Добавлен , опубликован

Основы программирования Корсаров

Содержание:
С++ язык со строгой типизацией. Это означает, что каждая переменная чётко определена для хранения конкретного типа данных и ничего другого в неё положить нельзя.
Возможно, это не даёт такого удобства в написании программы, как изменение данных в переменной на лету, но с другой - избавляет вас от постоянного поиска ошибок из-за несовпадения типов данных (ожидаемого и фактического).
Рассмотрим пример:
int a = 2;
Это целочисленная переменная. Попытка записать в неё строку приведёт к ошибке. Вы всегда можете быть уверены, что в этой переменной лежит целое число.
В языках без строгой типизации вы вполне можете записать в одну и ту же переменную сначала целое число, потом дробное, а позже - строку. А потом, передавая эту переменную в функцию, которая выполняет математические операции, вы не будете понимать, почему программа не работает. До тех пор, пока не отследите, что вы в эту функцию передали текст.
Поэтому лично я не склонен называть строгую типизацию - минусом. Да, иногда вам придётся объявлять больше переменных, чем могло бы понадобиться для работы, но зато проблема несовпадения типов у вас отсутствует как класс.

Приведение типов

В Корсарах наряду с базовыми типами С++ есть и свои собственные. Базовые в скриптах представлены далеко не все, однако основные есть и для работы этого достаточно.
int - целое число (сокр. от «integer»).
Может хранить целые числа (без дробной части), включая отрицательные.
int a = 12;
int b = -4;

float - число с плавающей запятой.
Хранит десятичные дроби, включая отрицательные.
float x = 12.58;
float y = -3.00;

string - строка.
Хранит текст. Присваиваемые значения всегда должны быть заключены в кавычки, даже если строка пустая.
string s = "";
string t = "мама мыла раму";
Сложение строк («конкатенация») производится при помощи оператора +.
Перенос текста на новую строку осуществляется при помощи конструкции \n. В некоторых случаях, вместо \n необходимо использовать функцию NewStr().
string m = "Вот это первая строка\nА это уже вторая";
string n = "Вот это первая строка" + NewStr() + "А это уже вторая";
Альтернативного варианта записи строки не существует. Поэтому вместо двойных кавычек внутри строки используются одинарные.
string g = "Табличка 'Таверна' висела прямо на уровне глаз.";

bool - логический тип данных.
Может принимать значения true и false.
Технически bool это целое число, где 1 равна значению true, а 0 == false.
bool b = false;
bool d = 1; // true
Существуют некоторые особенности использования целого числа как типа bool:
int a;

if (a == true) {}	// при таком обращении 1 возвращает true, а все остальные числа - false
if (a) {}			// а при таком - 0 возвращает false, a все остальные числа true
Цитата Rosarak:
Никогда не используйте тип данных float в качестве значений для bool'ов.
В ходе неявного преобразования типов значение 0.9 превратится в 0 и засчитается как false.

void - прямой перевод - «пустота», означает отсутствие любого типа данных.
В пределах скриптов Корсаров используется только для обозначения функции, которая не возвращает данных.
Объявить переменную с типом void нельзя.
void myFunc()
{
    // ...
}

object - объект (древовидная текстовая структура).
Здесь стоит остановиться подробнее. Как я говорил в самом начале - ООП в скриптах не доступно. Тем не менее, разработчики предоставили возможность создавать структуры, которые заменяют нам объекты классов.
Важно помнить, что все значения в таких структурах хранятся в виде строк (string).
Учиться работать с объектами и ссылками на них мы будем в отдельном уроке. //
object Cannon[CANNON_TYPES_QUANTITY];

ref - ссылка на объект (сокр. от «reference»).
Используется для обращения к структурам object. Сама ссылка создаётся при помощи функции:
object Items[ITEMS_QUANTITY];
ref itm;

makeref(itm, Items[n]);

aref - ссылка на атрибут объекта (сокр. от «attribute reference»).
Так как ваша структура object может быть любой - обращение к данным может быть очень длинным, составляя десятки слов и это не очень удобно, не говоря уже о том, что нечитабельно. Для этого используются ссылки на конкретные атрибуты объекта. Принцип такой же, как и в предыдущем типе:
object Items[ITEMS_QUANTITY];
ref itm;
aref  arItm;

makeref(itm, Items[n]);
itm.id = "patent_eng";
itm.type.arm = true;

makearef(arItm, itm.type);

if (sti(arItm.arm) == true)
{
    // ...
}

Преобразование типов

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

MakeInt - преобразование в целое число. Может принимать строку или число с плавающей точкой.
// синтаксис
int MakeInt(string value);
int MakeInt(float value);

// пример
int a;

a = MakeInt("33");
a = MakeInt(0.8);

MakeFloat - преобразование в число с плавающей точкой. Может принимать строку или целое число.
// синтаксис
float MakeFloat(string value);
float MakeFloat(int value);

// пример
float x;

x = MakeFloat("3.12");
x = MakeFloat(10);

sti - преобразование строки в целое число (сокр. от «string to integer»). В качестве аргумента принимает строку.
// синтаксис
int sti(string value);

// пример
int a = sti("4");

stf - преобразование строки в число с плавающей точкой (сокр. от «string to float»).
// синтаксис
float stf(string value);

// пример
float y = stf("12.44");

fts - преобразование числа с плавающей точкой в строку (сокр. от «float to string»). Принимает число с плавающей точкой, которое нужно преобразовать, а также количество цифр после запятой, которые будут сохранены.
// синтаксис
string fts(float value, int digits);

// пример
float pi = 3.141526535;

string s = fts(pi, 3); // 3.14
string d = fts(pi, 5); // 3.1415

Вообще, движок поддерживает прямое присвоение числа в строку:
int num = 12;
string s;

s = num; // "12"
Но с числами типа float есть нюансы.
Цитата Rosarak:
ОСОБЕННОСТЬ прямое присвоение строке чисел с плавающей запятой добавляет неожиданную дробную часть. Необходимо использовать специальные функции типа fts() или конструкцию вида s = "" + f
float f = 1.2;
string s;

s = f;
log_info(s);	// "1.200000007"

s = "" + f;
log_info(s);	// "1.2"

argb - сохраняет код цвета ARGB в виде целого числа в шестнадцатеричном формате. Аргументы: a - альфа-канал (0-255), r - красный (0-255), g - зелёный (0-255), b - синий (0-255).
// синтаксис
int argb(int a, int r, int g, int b);

// пример
int color = argb(255, 10, 10, 10);  // 0xAARRGGBB

`
ОЖИДАНИЕ РЕКЛАМЫ...
30
Чёт я не понял, а что в bool отрицательные числа пропали?
Ответы (5)
23
nazarpunk, по памяти я не смог воспроизвести, какое значение принимает bool, если передать туда отрицательное число, а тестировать было лень 😁
Исправлю))
23
nazarpunk, мне тоже так помнилось. Но это оказалось справедливым лишь для чистого С++.
А тест в игре показал, что -1 даёт false.
Здесь очень много особенностей, и порой они обескураживают.
23
nazarpunk, совместно с Rasarak удалось разгадать тайну работы bool в этой шайтан-машине:
int a;

if (a == true) {}	// при таком обращении 1 возвращает true, а все остальные числа - false
if (a) {}			// а при таком - 0 возвращает false, a все остальные числа true
30
avuremybe, в плюсах такое же поведение:
int main()
{
    
    int a = 0;
    std::cout<< (a == true) << (a == false) << (a ? 1 : 0) << "\n"; // 010
    
    int b = 1;
    std::cout<< (b == true) << (b == false) << (b ? 1 : 0) << "\n"; // 101
    
    int c = 2;
    std::cout<< (c == true) << (c == false) << (c ? 1 : 0) << "\n"; // 001
    
    int d = -2;
    std::cout<< (d == true) << (d == false) << (d ? 1 : 0) << "\n"; // 001

    return 0;
}
30
Строка должна быть заключена в двойные кавычки. А что делать, если в строке должна быть двойная кавычка?
Ответы (1)
23
nazarpunk, этого я пока не знаю.
В имеющихся в игре текстах везде используются одинарные. Полагаю, этому есть очень простое объяснение...
38
Мне больше про ptr интересно, как работает, как память выделяется
Ответы (3)
23
ScorpioT1000, ptr это pointer? т.е. указатель, ссылка?
38
avuremybe, про ref/aref, перепутал. Я помню из крестов как раз только всякие ptr из стандартных библиотек. А это std::ref?
23
ScorpioT1000, не, это не со стандартной библиотеки. Это проприетарные технологии))
Классов сюда не завезли, вместо них дали текстовые структуры данных.
ref это ссылка на саму структуру, чтобы обращаться к ней не как к массиву, а по названию, с доступом к атрибутам через привычную точку.
Крч это для имитации обращения к экземпляру класса.
aref этоа налогичного плана ссылка - сокращённое обращение к атрибуту любой вложенности. Необходимости в этом нету, просто для удобства работы.
Я где-нибудь опишу работу со всем этим. Правда пока не решил где именно это будет наиболее уместно.
23
Вышла новая версия! Прокрутить к ресурсу
Добавлено описание следующих нюансов:
  • Уточнение принимаемых значений bool, если передавать в него числа.
  • Передача float в bool.
  • Прямое присвоение float строке.
  • Особенности работы string.
30
Альтернативного варианта записи строки не существует.
Тоесть так не сработает?
string A = """A""";
string AB = "A" "B";
Ответы (2)
23
nazarpunk, в качестве эксперимента я попробую скормить это игре и посмотреть как оно себя поведет.
Уверее, что работать это не будет, интересно только как именно.
Из-за того, что нормальной компиляции нет, такие вещи могут вести себя очень непредсказуемо. Например выполнится до первой кавычки и отвалится до конца блока кода. А дальше опять всё будет выполняться
23
nazarpunk, ошибка на этапе запуска ;(
30
добавляет неожиданную дробную часть
Почему неожиданную? А как же классика:
book A = 0.1 + 0.2 == 0.3
Ответы (3)
23
nazarpunk, потому что вот это 0.000000007 вообще никак не ожидается
38
avuremybe, это не про компилятор, а как работает ieee float в современных процессорах, я бы посоветовал ссылаться на статьи на вики и не рекомендовать людям сравнивать флоаты через ==, а использовать epsilon
38
avuremybe,
Вот есть наглядная картинка по распределению точности. Чем дальше от нуля, тем для больших диапазонов будет одинаковое число возможных значений
Чтобы оставить комментарий, пожалуйста, войдите на сайт.