• Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!

GEngine: новые возможности для модостроения

Статус
В этой теме нельзя размещать новые ответы.

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
В этой теме я буду писать о добавленных скриптовых возможностях, которыми может воспользоваться тот, кто, возможно, будет делать мод непосредственно для GEngine. (Хотел создать эту тему позже, когда отлажу все баги, но раз народ спрашивает, отвечаю...)
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
I. Улучшенный режим Марвина.

В консоли появились новые команды:

1) MAXIMIZE - развернуть окно консоли на 3/4 экрана.
2) MINIMIZE - свернуть назад, к исходному размеру.
3) HELP - печатает справку о командах консоли, причем не только в окно zSpy, как оригинальный движок, но и прямо в окно консоли; HELP I - напечатает справку о всех командах, начинающихся с буквы I (INSERT и т.д.).
4) SPAWNMASS - призыв кучи монстров вокруг героя; команда была в оригинальном движке, но толком не работала. Починена вместе с вариацией SPAWNMASS GIGA - призыв сильных монстров (тролля, демона, ползуна-воина). Также добавлены SPAWNMASS ORC, SPAWNMASS UNDEAD - призыв орков и нежити. Можно в конце еще добавить число - множитель для численности монстров. Пример:
SPAWNMASS ORC 3
5) VAR - напечатать/изменить переменную скриптов, прямо во время игры.
Примеры:
VAR Kapitel - напечатает текущую главу,
VAR self.attribute[ATR_HITPOINTS] - напечатает здоровье героя в консоли,
VAR other.name - напечатает имя персонажа в фокусе,
VAR self.attribute[ATR_STRENGTH] = 100 - изменит силу героя.

По кнопке I можно залезать в сундук, не открывая его (и вообще к нему не подходя), а также торговать с NPC по крайне выгодным ценам, причем даже с теми, кто торговать с героем не хочет.

Кнопка G (показ анимаций и состояний) - работает как обычно, но дает больше информации - отображает имя инстанции героя, а также кто из NPC в данный момент времени его видит/слышит/обоняет. Используются сокращения: Se-вижу, He-слышу, Sm-обоняю (чувствую запах). Также там может встретиться буква f - не вижу, не слышу, не обоняю, но скрипт сейчас говорит, что я его должен чувстовать (такой эффект получается, если вызвана функция Npc_PerceiveAll).
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
II. Многостраничные книжки реализованы. Чтобы создать такую книжку, нужно просто вызвать в скриптах функцию Doc_SetPages, передав в качестве числа страниц 3 или больше, ну и соответственно далее в скриптах настроить дополнительные страницы. Листать в игре кнопками вправо/влево, там еще стрелочки будут появляться, если есть еще страницы справа/слева. Номер страницы не печатается, если он нужен, напишите его на странице сами.

Пример:
Код:
Doc_SetPages( nDocID, 55);
Doc_SetPage( nDocID, 0, "MyReferat_TitlePage.tga", 0); // титульник
Doc_SetPage( nDocID, 1, "MyReferat_WhiteA4.tga", 0); // задняя сторона титульника - просто белый лист
Doc_SetPage( nDocID, 2, "MyReferat_Contents.tga", 0); // оглавление
Doc_SetPage( nDocID, 3, "MyReferat_WhiteA4.tga", 0); // задняя сторона оглавления - просто белый лист
Doc_SetPage( nDocID, 4, "MyReferat_Text_1.tga", 0); // первая текстовая страница
Doc_SetPage( nDocID, 5, "MyReferat_WhiteA4.tga", 0); // задняя сторона первой текстовой страницы - просто белый лист
Doc_SetPage( nDocID, 6, "MyReferat_Text_2.tga", 0); // вторая текстовая страница
...
Doc_SetPage( nDocID, 53, "MyReferat_WhiteA4.tga", 0); // задняя сторона 25-ой текстовой страницы - просто белый лист
Doc_SetPage( nDocID, 54, "MyReferat_Text_26.tga", 0); // 26-ая текстовая страница
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
III. Карта мира. Для определения карты, которая должна показать на экране по нажатию кнопки M, теперь движком вызывается функция PLAYER_HOTKEY_SCREEN_MAP (как в Готике 2), и только если она в скриптах не найдена, используется стандартное для Г1 поведение - отображается карта ITWRWORLDMAP_ORC или ITWRWORLDMAP, если первой в инвентаре нет.

В GEngine добавлена новая external-функция (как в Г2):
FUNC VOID Doc_SetLevelCoords( VAR INT nDoc, VAR INT nLeft, VAR INT nTop, VAR INT nRight, VAR INT nBottom) {};​
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
IV. Управление LOD'ом. LOD, который так портил жизнь ранее при попытке сделать чуть более полигональную модель, чем это обычно принято, можно достаточно гибко настраивать.

Во-первых, есть параметр modelDetail в файле gengine.ini - он управляет применением LOD'а к моделям (всем сразу). Чем больше значение modelDetail, тем меньше используется LOD. Игра вычисляет выражение (1.15 - modelDetail * 0.6) и использует его как множитель для определения силы LOD'а. Допустимый диапазон для modelDetail в оригинале: 0..1, в GEngine расширен, теперь допустимы любые числа. Значение 2 (или больше) отключает LOD для всех моделей, отрицательные значения, наоборот, усиливают LOD на меньших расстояниях (можно использовать для тестирования). Параметр modelDetail настраивается также через меню игры (Графика-> Уровень детализации объектов).

В GEngine добавлена возможность применять разные параметры LOD'ов к разным моделям. Для этого нужно перед компиляцией модели (например, тролля) - компилировать, понятно, надо только движком GEngine), - добавить в каталог с исходниками модели файл с именем "<имя-исходника>-params.ini" (например, TRO_BODY-params.ini). Такой прием может применяться для статических мешей (меч), динамических моделей (доспех/шкура монстра), морфируемых мешей (голова/лук). Если такой файл при компиляции не будет найден, будут использованы параметры по умолчанию, которые зависят от типа модели:

1) для статического меша (пример имени файла: "ItMw_1H_Warhammer_01-params.ini"):
Код:
[PROGMESH]
LODStrength=1
LODStartDistance2=0
LODDynCollapseSpeed=0
LODMinVerts=0

2) для динамического меша (пример имени файла: "Hum_KDFM_ARMOR-params.ini"):
Код:
[PROGMESH]
LODStrength=1
LODStartDistance2=0
LODDynCollapseSpeed=0.03
LODMinVerts=0

3) для морфируемого меша (имя файла выглядит, например, так: "ORC_HEADSHAMAN-params.ini"):
Код:
[PROGMESH]
LODStrength=0.35
LODStartDistance2=0
LODDynCollapseSpeed=0.03
LODMinVerts=0

Параметры LOD'ов из файла "*-params.ini" используются только при компиляции модели, далее они сохраняются в MDM/MDL/MRM-файле и при последующих запусках загружаются уже оттуда. При том, что формат MDM/MDL/MRM-файлов я не менял, скомпилированные таким образом в GEngine модели можно использовать и для запуска в обычной Г1.

LODStrength - основной параметр, значение 0 отключает LOD для данного меша, значения, большие единицы, наоборот, увеличат эффект LOD'а. Игра использует выражение (LODStrength * (1.15 - modelDetail * 0.6)) для определения степени LOD'а.

Команда игровой консоли ZPROGMESHLOD переопределяет параметр LODStrength для всех моделей в текущей игровой сессии.
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
V. Арифметика.

Добавлены external-функции для выполнения операций с вещественными числами:

/* Складывает два числа. */
FUNC FLOAT FAdd( VAR FLOAT f1, VAR FLOAT f2 ) {};

/* Вычитает из первого второе. */
FUNC FLOAT FSub( VAR FLOAT f1, VAR FLOAT f2 ) {};

/* Умножает два числа. */
FUNC FLOAT FMul( VAR FLOAT f1, VAR FLOAT f2 ) {};

/* Делить первое на второе. */
FUNC FLOAT FDiv( VAR FLOAT f1, VAR FLOAT f2 ) {};

/* Находит абсолютное значение (модуль). */
FUNC FLOAT FAbs( VAR FLOAT f1 ) {};

/* Сравнивает два вещественных числа; возвращается 0, если числа равны; -1, если первое число меньше второго; 1, если первое число больше второго. */
FUNC INT FCmp( VAR FLOAT f1, VAR FLOAT f2 ) {};
Добавлены external-функции для выполнения операций со строками:

/* Сравнить две строки с учетом регистра; возвращается 0, если строки равны; -1, если первая строка предшествует второй (при сортировке по алфавиту); 1, если вторая строка предшествует первой (при сортировке по алфавиту). */
FUNC INT StrCmp( VAR STRING s1, VAR STRING s2 ) {};

/* Сравнить две строки без учета регистра; в остальном также, как и StrCmp. */
FUNC INT StrICmp( VAR STRING s1, VAR STRING s2 ) {};​

Примечание: новые external-функции не нарушают совместимости сохраненок GEngine с оригинальной Г1, пока они не используются.
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
VI. Кража и грабеж.

Добавлено несколько вызываемых движком функций
(ниже записаны реализации "по-умолчанию", которые используются, если таких функций в скриптах не объявлено):
Код:
/* Функция определяет, может ли npc SELF взять предмет ITEM с трупа npc OTHER; 
соответственно, перед ее вызовом инициализируются переменные SELF, OTHER, 
ITEM; функция должна вернуть TRUE или FALSE; если функция вернет FALSE, предмет не будет 
отображен в инвентаре жертвы при ограблении трупа. */
func int G_CanTakeItemFromDead()
{
	if (ITEM.mainflag == ITEM_KAT_ARMOR)
	{
		return FALSE;
	};
	return TRUE;
};

Код:
/* Функция определяет, может ли npc SELF взять предмет ITEM с лежащего 
без сознания npc OTHER; соответственно, перед ее вызовом инициализируются 
переменные SELF, OTHER, ITEM; функция должна вернуть TRUE или FALSE; 
если функция вернет FALSE, предмет не будет отображен в инвентаре жертвы при ограблении. */
func int G_CanTakeItemFromUnconsious()
{
	if (ITEM.mainflag == ITEM_KAT_ARMOR)
	{
		return FALSE;
	};
	return TRUE;
};

Код:
/* [I](было в оригинале, здесь указано для общего списка)[/I]
Функция определяет, возможна ли карманная кража npc SELF у npc OTHER; 
соответственно, перед ее вызовом инициализируются переменные SELF, OTHER; 
функция должна вернуть TRUE или FALSE; FALSE - кража невозможна, TRUE - можно красть. */
func int G_CanSteal()
{
	if	( ( other.npcType != NPCTYPE_FRIEND ) && ( other.npcType != NPCTYPE_MAIN ) )
	{
		return TRUE;
	}
	else
	{
		PrintScreen	(_STR_MESSAGE_CANNOTSTEAL, -1, _YPOS_MESSAGE_CANNOTSTEAL, _STR_FONT_ONSCREEN, _TIME_MESSAGE_CANNOTSTEAL );		
		
		return FALSE;
	};
};

Код:
/* Функция определяет шансы npc SELF украсть предмет ITEM 
(карманная кража) у npc OTHER; соответственно, перед ее вызовом 
инициализируются переменные SELF, OTHER, ITEM; функция должна вернуть 
число от 0.0 до 1.0, или -1.0, если кража данного предмета невозможна 
(ГГ даже пытаться не будет); 0.5 означает 50% шансы на успех; 
1.0 - 100% (жертва никогда ничего не заподозрит). */
func float G_CalcChanceOfStealItem()
{
	if ((ITEM.mainflag == ITEM_KAT_ARMOR) || ((ITEM.flag & ITEM_ACTIVE) != 0))
	{
		return -1.0;
	};
	return FSub(1.0, FDiv(IntToFloat(Npc_GetTalentValue(SELF, NPC_TALENT_PICKPOCKET)), 100.0));
}; 
/* здесь
const int ITEM_ACTIVE = 1 << 30; // флаг установлен, если предмет экипирован. */

Код:
/* Функция определяет, может ли npc SELF подложить предмет при
 карманной краже в инвентарь npc OTHER; соответственно, перед ее
 вызовом инициализируются переменные SELF, OTHER; функция должна
 вернуть TRUE или FALSE; FALSE - означает, что в чужой инвентарь
 ничего подложить нельзя. */
func int G_CanPlant()
{
	return FALSE;
};

Код:
/* Функция определяет шансы npc SELF подложить предмет ITEM 
при карманной краже в инвентарь npc OTHER; соответственно, перед ее
 вызовом инициализируются переменные SELF, OTHER, ITEM; функция
 должна вернуть число от 0.0 до 1.0, или -1.0, если подложить предмет
 нельзя (ГГ даже пытаться не будет); 0.5 означает 50% шансы на успех;
1.0 - 100% (жертва никогда ничего не заподозрит). */
func float G_CalcChanceOfPlantItem()
{
	return -1.0;
};

Примечание: Скриптовые функции, вызываемые движком GEngine, имеют префикс "G_".
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
VII. Торговля.

Добавлено несколько вызываемых движком функций
(ниже записаны реализации "по-умолчанию", которые используются, если таких функций в скриптах не объявлено):

Код:
/* Функция определяет, может ли npc SELF продать предмет ITEM npc
 OTHER; соответственно, перед ее вызовом движок инициализирует
 переменные SELF, OTHER, ITEM; функция возвращает TRUE или FALSE. 
ГГ может выступать и как продавец, и как покупатель. */
func int G_CanSellItem()
{
	if(!Npc_IsPlayer(SELF)
	{
		if ((ITEM.mainflag == ITEM_KAT_ARMOR) || ((ITEM.flag & ITEM_ACTIVE) != 0))
		{
			return FALSE;
		};
	};
	return TRUE;
};
/* здесь
const int ITEM_ACTIVE = 1 << 30; // флаг установлен, если предмет экипирован. */

Код:
/* Функция определяет множитель для цены предмета ITEM, который
 продает npc SELF покупателю OTHER; функция возвращает вещественное число, 
большее нуля, 1.0 - означает оригинальную цену предмета, 
которая указана в скриптах, в его инстанции. 
ГГ может выступать и как продавец, и как покупатель. */
// Реализация по умолчанию, если константа TRADE_VALUE_MULTIPLIER
// в скриптах найдена:
func float G_GetSellValueMultiplier()
{
	if(!Npc_IsPlayer(SELF))
	{
		return 1.0;
	};
	return TRADE_VALUE_MULTIPLIER;
};

// Реализация по умолчанию, если константа TRADE_VALUE_MULTIPLIER
// в скриптах не найдена:
func float G_GetSellValueMultiplier()
{
	if(!Npc_IsPlayer(SELF))
	{
		return 1.0;
	};
	return 0.5;
};

Код:
/* Функция вызывается при невозможности завершить заключить торговую сделку;
кнопка Enter нажата, а цены справа и слева не сошлись. 
Может использоваться для вывода сообщения игроку. */
func void G_CannotTrade()
{
};

Теперь также используется строковая константа TRADE_CURRENCY_INSTANCE (как в Г2), которая может быть объявлена в скриптах, и которая задает предмет, играющий роль денег (его цена обязательно должна быть равна 1).
Код:
const string TRADE_CURRENCY_INSTANCE = "ItMiNugget";
Если в скриптах константа TRADE_CURRENCY_INSTANCE не объявлена, используется значение опции invTradeCurrencyInstance из файла gengine.ini.

Еще на торговлю влияет целая константа TRADERS_HAVE_INFINITE_MONEY, которая означает, есть ли у торговцев бесконечные деньги, или нет.
Код:
const int TRADERS_HAVE_INFINITE_MONEY = FALSE;
Если этой константы в скриптах не найдено, то движок смотрит на константу TRADE_CURRENCY_INSTANCE, если она найдена, то у торговцев будут бесконечные деньги, иначе не будут.
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
VIII. Управление оверлеями.

Добавлены вызываемые движком функции, которые движок вызывает, чтобы определить нужный оверлей в различных ситуациях
(ниже записаны реализации "по-умолчанию", которые используются, если таких функций в скриптах не объявлено):
Код:
/* Функция вызывается, когда npc SELF пытается плыть медленно;
 функция должна возвратить имя оверлея, или пустую строку, если
 оверлей . */
func string G_GetSlowSwimOverlayName()
{
	if (SELF.guild < GIL_SEPERATOR_HUM)
	{
		return "HUMANS_SWIM.MDS";
	};
	return "";
};

Код:
/* Функция вызывается, когда npc SELF пытается зажечь факел; функция должна вернуть имя оверлея, или пустую строку, если оверлей применять не нужно. */
func string G_GetTorchOverlayName()
{
	if (self.guild < GIL_SEPERATOR_HUM)
	{
		return "HUMANS_TORCH.MDS";
	};
	if (self.guild > GIL_SEPERATOR_ORC)
	{
		return "ORC_TORCH.MDS";
	};
	return "";
};

Код:
/* Функция вызывается, когда npc SELF получает навык; функция должна вернуть имя оверлея, который должен быть применен, или пустую строку, если оверлей не нужен. */
func string G_GetTalentSkillOverlayName(var int talent, var int skill)
{
	if (self.guild >= GIL_SEPERATOR_HUM)
	{
		return "";
	};
	if (talent == NPC_TALENT_ACROBAT)
	{
		if (skill >= 1)
		{
			return "HUMANS_ACROBATIC.MDS";
		};
		return "";
	};
	if (talent == NPC_TALENT_1H)
	{
		if (skill >= 1)
		{
			return ConcatStrings(ConcatStrings("HUMANS_1HST", IntToString(skill)), ".MDS");
		};
		return "";
	};
	if (talent == NPC_TALENT_2H)
	{
		if (skill >= 1)
		{
			return ConcatStrings(ConcatStrings("HUMANS_2HST", IntToString(skill)), ".MDS");
		};
		return "";
	};
	if (talent == NPC_TALENT_BOW)
	{
		if (skill >= 1)
		{
			return ConcatStrings(ConcatStrings("HUMANS_BOWT", IntToString(skill)), ".MDS");
		};
		return "";
	};
	if (talent == NPC_TALENT_CROSSBOW)
	{
		if (skill >= 1)
		{
			return ConcatStrings(ConcatStrings("HUMANS_CBOWT", IntToString(skill)), ".MDS");
		};
		return "";
	};
	return "";
};
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
IX. Барьер.

Добавлены external-функции для управления барьером. В принципе вызывать эти функции можно когда угодно, можно даже реконфигурировать барьер на лету, в зависимости от квестов. Однако следует помнить, что конфигурация барьера в сохраненке не сохраняется, т.е. лучше всего настраивать барьер в функции INIT_<имя_мира>() - которая вызывается всякий раз при загрузке/старте мира.

/* Включить/отключить рендеринг барьера (только рендеринг, молнии, наносящие урон, настраиваются отдельно).
По умолчанию включено в любом Outdoor-мире, если в файле GENGINE.INI нет параметра zShowBarrier,
или в соответствии с этим параметром. Скриптовые функции имеют больший вес, т.е. значение, заданное в этой функции,
перебивает значение zShowBarrier из файла GENGINE.INI. */
FUNC VOID Barrier_EnableRendering( VAR INT nEnable ) {};

/* Узнать, включен ли рендеринг барьера. */
FUNC INT Barrier_IsRenderingEnabled() {return 0;};

/* Включить/отключить молнии, наносящие урон при приближении.
По умолчанию включено в том и только в том случае, если мир называется "WORLD.ZEN". */
FUNC VOID Barrier_EnableDamage( VAR INT nEnable ) {};

/* Узнать, включены ли молнии, наносящие урон при приближении. */
FUNC INT Barrier_IsDamageEnabled() {return 0;};

/* Включить/отключить урон молниями для указанного NPC (по умолчанию урон включен только для ГГ, но это можно поменять). */
FUNC VOID Barrier_EnableDamageForNpc( VAR C_NPC npc, VAR INT nEnable ) {};

/* Узнать, включен ли урон молниями для указанного NPC. */
FUNC INT Barrier_IsDamageEnabledForNpc( VAR C_NPC npc ) {return 0;};

/* Установить размер урона, наносимого барьером (сюда не включен урон, который ГГ дополнительно получит,
когда, отлетев, упадет на землю). По умолчанию урон всего 5, поэтому, превратившись в любое существо,
которое нельзя отбросить (шершень), можно легко преодолеть барьер. */
FUNC VOID Barrier_SetDamage( VAR INT nDamage ) {};

/* Установить расстояние до барьера, на котором барьер начинает бить молниями, в см. (по умолчанию 650). */
FUNC VOID Barrier_SetFireDist( VAR INT nDist ) {};

/* Установить расстояние до барьера, на котором появляется эффект, предупреждающий о близости к барьеру,
в см. (по умолчанию 1200). */
FUNC VOID Barrier_SetWarningDist( VAR INT nDist ) {};

/* Установить число точек, образующих контур барьера. */
FUNC VOID Barrier_SetPoints( VAR INT nNumPoints ) {};

/* Установить координаты точки, одной из тех, что образуют контур барьера. */
FUNC VOID Barrier_SetPoint( VAR INT nIndexOfPoint, VAR INT x, VAR INT z ) {};

По умолчанию барьер такой:
Barrier_SetWarningDist(1200);
Barrier_SetFireDist(650);
Barrier_SetDamage(5);
Barrier_SetPoints(38);
Barrier_SetPoint( 0, 57939, 1280);
Barrier_SetPoint( 1, 55954, 5422);
Barrier_SetPoint( 2, 52857, 10047);
Barrier_SetPoint( 3, 49452, 14908);
Barrier_SetPoint( 4, 44200, 20513);
Barrier_SetPoint( 5, 37684, 26271);
Barrier_SetPoint( 6, 30434, 31462);
Barrier_SetPoint( 7, 25574, 32693);
Barrier_SetPoint( 8, 21248, 35176);
Barrier_SetPoint( 9, 19451, 35205);
Barrier_SetPoint(10, 16263, 32800);
Barrier_SetPoint(11, 10756, 34744);
Barrier_SetPoint(12, 9737, 37990);
Barrier_SetPoint(13, 8219, 38393);
Barrier_SetPoint(14, 4065, 39018);
Barrier_SetPoint(15, 840, 39079);
Barrier_SetPoint(16, -9313, 38694);
Barrier_SetPoint(17, -19258, 40991);
Barrier_SetPoint(18, -29684, 40536);
Barrier_SetPoint(19, -39314, 36559);
Barrier_SetPoint(20, -49320, 31970);
Barrier_SetPoint(21, -54137, 26762);
Barrier_SetPoint(22, -62089, 21598);
Barrier_SetPoint(23, -66194, 12999);
Barrier_SetPoint(24, -66132, 6204);
Barrier_SetPoint(25, -63855, -5701);
Barrier_SetPoint(26, -59385, -10082);
Barrier_SetPoint(27, -56014, -22393);
Barrier_SetPoint(28, -47250, -28502);
Barrier_SetPoint(29, -37137, -38319);
Barrier_SetPoint(30, -24665, -46688);
Barrier_SetPoint(31, -7861, -48967);
Barrier_SetPoint(32, 4877, -49691);
Barrier_SetPoint(33, 23148, -47875);
Barrier_SetPoint(34, 48722, -39489);
Barrier_SetPoint(35, 55902, -31910);
Barrier_SetPoint(36, 61239, -23413);
Barrier_SetPoint(37, 60230, -6642);
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 

Kerrax

Почетный форумчанин
Регистрация
19 Фев 2008
Сообщения
222
Благодарности
682
Баллы
220
{Резерв}
 
Статус
В этой теме нельзя размещать новые ответы.
Сверху Снизу