Перейти к содержимому


Фотография

Скриптинг в GTA IV


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 215

#141 mass

mass

    Участник

  • Пользователи
  • PipPip
  • 10 сообщений

Отправлено 26 July 2009 - 09:56

спаисибо

#142 mass

mass

    Участник

  • Пользователи
  • PipPip
  • 10 сообщений

Отправлено 26 July 2009 - 11:18

для открытия исполняемых файлов нужен дизассемблер. Лучше всего использовать IDA 5 Pro. Искать на cracklab.ru


открывать понятно,но как после етого их засунуть в borland? да и редоктировать не очень удобно в этой проге

#143 listener

listener

    Активный участник

  • Главные администраторы
  • PipPipPip
  • 356 сообщений
  • Пол:Мужчина
  • Город:Ft.Lauderdale


Отправлено 26 July 2009 - 12:22

открывать понятно,но как после етого их засунуть в borland? да и редоктировать не очень удобно в этой проге


А что, вообще, хочется сделать? (И что именно не удобно редактировать?)

PS. Предлагаю переместиться сюда: http://forums.gtamod...p?showtopic=423
You think your day was surreal? Try mine.

#144 Гость_squilky_*

Гость_squilky_*
  • Гости

Отправлено 14 September 2009 - 10:26

В 4-й гта есть новый способ писания скриптов раньше было а main.scm или подобных а сейчас можно как то подключать отдельные скриптовые файлы, скажите пожалуйста, как можно их создавать и какой там язык может есть уже ечебники?.

#145 listener

listener

    Активный участник

  • Главные администраторы
  • PipPipPip
  • 356 сообщений
  • Пол:Мужчина
  • Город:Ft.Lauderdale


Отправлено 14 September 2009 - 12:39

Увы, на текущий момент нет не только учебликов, но и какого-либо транслятора. Как только появится транслятор, будут и учебники.
You think your day was surreal? Try mine.

#146 Capushon

Capushon

    Активный участник

  • Пользователи
  • PipPipPip
  • 39 сообщений
  • Пол:Мужчина
  • Город:Украина

Отправлено 14 September 2009 - 19:53

В 4-й гта есть новый способ писания скриптов раньше было а main.scm или подобных а сейчас можно как то подключать отдельные скриптовые файлы

Я пока не встретил ни одного (!) стабильного модуля из .asi, .net.dll, .lua ... Переюзал около 3-х десятков различных модов, каждый из них "подвешивал" игру в разных ситуациях.

скажите пожалуйста, как можно их создавать и какой там язык может есть уже ечебники?.

.asi, .net.dll, .lua - это тупиковый путь развития скриптинга, т.к.
1. Слишком сложно в реализации.
2. Невозможность редактирования.
3. Только во внутреннем скрипте (script.img) можно предусмотреть все конфликтные ситуации, при которых работа скрипта может быть аварийно завершена, но никак не во внешних .asi, .net.dll, .lua ...

Сообщение отредактировал Capushon: 15 September 2009 - 09:41

Сначала ты надежда и гордость, Потом о спину ломают аршин. ©БГ

#147 Capushon

Capushon

    Активный участник

  • Пользователи
  • PipPipPip
  • 39 сообщений
  • Пол:Мужчина
  • Город:Украина

Отправлено 15 September 2009 - 17:56

2:

как то подключать отдельные скриптовые файлы, скажите пожалуйста, как

Будем надеется что listener, Alexander, или Seemann в скором времени создаст что-нибудь в чём можно было бы редактировать script.img, а дальше дело пойдёт :)

ps: Иначе на скриптинге, в том виде, в каком он всем был доступен - можно ставить крест ...
Сначала ты надежда и гордость, Потом о спину ломают аршин. ©БГ

#148 Seemann

Seemann

    Активный участник

  • Главные администраторы
  • PipPipPip
  • 266 сообщений
  • Пол:Мужчина
  • Город:Россия, Иркутск/СПб

Отправлено 15 September 2009 - 18:00

.asi, .net.dll, .lua - это тупиковый путь развития скриптинга, т.к.
1. Слишком сложно в реализации.
2. Невозможность редактирования.
3. Только во внутреннем скрипте (script.img) можно предусмотреть все конфликтные ситуации, при которых работа скрипта может быть аварийно завершена, но никак не во внешних .asi, .net.dll, .lua ...


1. все зависит от знания того или иного языка и опыта работы с программой для редактирования. Программисту с опытом работы с Дельфи или Visual Studio написать такой модуль проще чем программисту без опыта. (для сравнения: скриптеру с опытом работы в саннике гораздо легче написать скрипт чем новичку).

2. скрипты lua поддаются редактированию (хотя может я отстал от жизни). Опять же в этом есть свои плюсы (защита собственных скриптов и все такое, тебе ли не знать ;)

3. опыт работы с CLEO подсказывает, что самые хорошие скрипты - те, которые не используют ресурсы других скриптов (в т.ч. оригинальных). если это условие выполняется, кол-во конфликтов снижается до минимального кол-ва (и их можно избежать простыми проверками)

#149 VcSaJen

VcSaJen

    Активный участник

  • Пользователи
  • PipPipPip
  • 270 сообщений
  • Пол:Мужчина
  • Интересы:GTA, скриптинг в GTA.


Отправлено 19 November 2009 - 08:55

@JNikc -

Но у меня есть опыт (небольшой :-) в синтаксических интерпретаторах.

Сможешь сделать динамическую автоподстановку переменных, констант, типов, native и скриптовых функций, полей структур с учётом инклудов в своём редакторе? Этого очень не хватает. После выхода компилятора SCO выйдет тыща облочек для него, и автоподстановка - весомый аргумент будет для популярности твоей оболочки.

Если все это запустить на другом компе, то скорее всего все будет недоступным, потому что пути к программам в INI нужно переписать.

Путь к Delphi 7 хранится в реестре: раздел HKEY_CURRENT_USER\Software\Borland\Delphi\7.0 ключ RootDir. Путь к SA (в короткой форме) хранится в разделе HKEY_LOCAL_MACHINE\SOFTWARE\Rockstar Games\GTA San Andreas\Installation ключ ExePath. Путь к SB3 в реестре нет. И вообще INI-плагины - тупиковый путь, оттуда сложно что-либо сделать.

Насчёт плагинов (dll) - должна быть возможность добавления пунктов главного и контекстного меню прямо из плагина, а не редактировать текстовую таблицу вручную.

И наверное лучше открыть отдельную темку для обсуждения KEdit, если конечно планируется дальше её развивать.

У меня такое предложение. Вместо однократного объявления в interface: ... определить классы Player, Ped, Vehicles, и т.д., опубликовать функции:

С классами (В SCO) конечно удобнее, но если вручную их писать одному человеку получится очередной долгострой как классы к SB (которые так и не были доделаны за 5 лет существования). IMHO, безполезно, если определены только часть полей, а не все...

Сообщение отредактировал VcSaJen: 20 November 2009 - 04:48


#150 VcSaJen

VcSaJen

    Активный участник

  • Пользователи
  • PipPipPip
  • 270 сообщений
  • Пол:Мужчина
  • Интересы:GTA, скриптинг в GTA.


Отправлено 09 February 2010 - 06:40

Сейчас делаю гоночную миссию для GTA IV и я натолкнулся на:

1) Функция SetMissionFlag во-первых, только включает режим миссии, но не выключает, во-вторых в игре всё равно можно сохраниться или запустить другую миссию. Как нормально включить/отключить режим миссии? В OpenIV есть описание глобальной переменной g_OnMision, но она никак не используется в оригинальных миссиях.

2) Как вывести заголовок миссии? Есть функция SetMsgForLoadingScreen, но она только ставит запись посередине экрана маленьким шрифтом и в углу появляется кнопка OK.

3) Как отправить игроку SMS-сообщение? По всему видимому, за это отвечает скриптовая функция:
function sub_36b2(var0)
{
   auto var3, var4, var5, var6, var7, var8, var9, var10;

   var4 = 0;
   strcpy(&var5, 16, "TM_NAME_");
   if (G[91].v135)
   {
	   return 0;
   }
   else if (G[569][G[569] - 1 * 6].v0[0] != -1)
   {
	   if (!sub_36f8())
	   {
		   sub_aee(0);
	   }
   }
   if (*(var0 + 24) != -1)
   {
	   return 0;
   }
   else
   {
	   var9 = sub_3777(*(var0 + 0).v0, *(var0 + 0).v1, *(var0 + 0).v2, *(var0 + 0).v3, *(var0 + 0).v4, *(var0 + 0).v5);
	   if (var9 != -1)
	   {
		   sub_aee(var9);
	   }
	   var3 = 0;
	   while (var3 <= (G[569] - 1))
	   {
		   if (G[569][var3 * 6].v0[0] == -1)
		   {
			   G[569][var3 * 6].v0 = *(var0 + 0).v0;
			   G[569][var3 * 6].v1 = *(var0 + 0).v1;
			   G[569][var3 * 6].v2 = *(var0 + 0).v2;
			   G[569][var3 * 6].v3 = *(var0 + 0).v3;
			   G[569][var3 * 6].v4 = *(var0 + 0).v4;
			   G[569][var3 * 6].v5 = *(var0 + 0).v5;
			   *(var0 + 24) = var3;
			   var3 = G[569];
			   var4 = var4 + 1;
			   if (var4 > 1)
			   {
				   SET_PHONE_HUD_ITEM(1, "UNREAD_MESSAGES", var4);
			   }
			   else
			   {
				   strcati(&var5, 16, sub_9d0(0, *(var0 + 0).v0, *(var0 + 0).v1, *(var0 + 0).v2, *(var0 + 0).v3, *(var0 + 0).v4, *(var0 + 0).v5));
				   SET_PHONE_HUD_ITEM(1, &var5, var4);
			   }
			   G[91].v130 = 1;
			   PLAY_AUDIO_EVENT("MOBILE_PHONE_SMS_RECIEVE");
			   if (G[555] == 9)
			   {
				   G[91].v101 = 1015;
			   }
			   else if (G[91].v0 == 1014)
			   {
				   G[91].v23 = 1;
			   }
			   INCREMENT_INT_STAT_NO_MESSAGE(300, 1);
			   G[15654][17] = 1;
		   }
		   else if (sub_9d0(4, G[569][var3 * 6].v0, G[569][var3 * 6].v1, G[569][var3 * 6].v2, G[569][var3 * 6].v3, G[569][var3 * 6].v4, G[569][var3 * 6].v5) == 0)
		   {
			   var4 = var4 + 1;
		   }
		   var3 = var3 + 1;
	   }
	   SET_MESSAGES_WAITING(1);
	   return 1;
   }
}
она присутствует во всех скриптах, отправляющих SMS игроку.
Но при попытке переписать её для Delphi я попал в сеть перекрёстных вызовов функций.

4) Что означает в декомпиляторе OpenIV код:
Var1 + 8 + 0 = Var1 + 8 + 0 - 24;
Возможно, правильнее будет:
*(&Var1 + 8 + 0) := *(&Var1 + 8 + 0) - 24;
или
*(Var1 + 8 + 0) := *(Var1 + 8 + 0) - 24;
Или что имелось ввиду?

Некоторый код в OpenIV отличается от SparkIV:
Local[701][8(3)] в SparkIV декомпилирует как L[701][8 * 3]
Ещё пара: Var3 + 0[0(1)] в SparkIV превращается в &((*(var2 + 0))[0])
Это недоработки?

5) Как сделать так, чтобы в такси можно было выбрать иконку добавленной миссии?

6) Как скрипту-плагину перехватить управление за миг до начала записи сохранения? (Что-бы до сохранения удалить объекты Ext-скрипта)

7) Кодировка русских букв в версии 1.0.0.4 поменялась или нет?

8) Как загрузить WTD и вывести текстуру на экран? DrawBox и TextDraw прекрасно рисуется, а текстуры нет. Пробовал загружать по-обычному и через StreamedTxd - не рисуется.

P.S. Полезный совет: когда вы пишете миссии в Delphi, надо контролировать, умер ли игрок или арестован и немедленно прекратить миссию при этом. Проще всего это сделать так:
uses
  ScriptNatives,
  ScriptTypes,
  ScriptUseful,
  SysUtils;

type
  EPlayerDead=class(Exception);

{...}

procedure Mission;
  procedure Wait(Time: Cardinal);
  var t1,t2: Cardinal; t: integer;
  begin
	if Time<60 then
	begin
	  ScriptNatives.Wait(Time);
	  if not IsPlayerPlaying(playerId) then
	  begin
		raise EPlayerDead.Create('Player dead or arrested!');
	  end;
	  Exit;
	end;

	GetGameTimer(@t1);
	t:=0;
	while Cardinal(Abs(t))<Time do
	begin
	  ScriptNatives.Wait(1);
	  GetGameTimer(@t2);
	  t:=t2-t1;
	  if not IsPlayerPlaying(playerId) then
	  begin
		raise EPlayerDead.Create('Player dead or arrested!');
	  end;
	end;
  end;

begin
  try
	try
	  {...Здесь пишем код миссии...}
	  
	  
	finally
	  {Очистка}
	end;
  except
	on EPlayerDead do
	begin
	  {Действия при провале}
	  Exit;
	end;
  end;
end;

{...}


Ещё совет: что-бы не перезапускать GTA каждый раз при изменении ext-скрипта, создайте файл clear.bat в папке Alice со следующим содержанием:
del MyScript.~ext
ren MyScript.ext MyScript.~ext
вместо MyScript нужно подставить имя скрипта. Перед компиляцией нужно запустить этот bat'ник.

#151 listener

listener

    Активный участник

  • Главные администраторы
  • PipPipPip
  • 356 сообщений
  • Пол:Мужчина
  • Город:Ft.Lauderdale


Отправлено 14 February 2010 - 13:35

Сразу предудпреждаю: все, что я здесь пишу, нужно проверять (что-то я просто не помню, для чего-то поменялись концепции)

1) Функция SetMissionFlag во-первых, только включает режим миссии, но не выключает, во-вторых в игре всё равно можно сохраниться или запустить другую миссию. Как нормально включить/отключить режим миссии? В OpenIV есть описание глобальной переменной g_OnMision, но она никак не используется в оригинальных миссиях.


Для каждой миссии, используется отдельный скрипт, запущенный в отдельном потоке.
Флаг того, это mission script - выставляется во внутреннем поле структуры потока.

3) Как отправить игроку SMS-сообщение? По всему видимому, за это отвечает скриптовая функция:
она присутствует во всех скриптах, отправляющих SMS игроку.
Но при попытке переписать её для Delphi я попал в сеть перекрёстных вызовов функций.

Еще одна иллуюстрация:
074:00000627: ---- Function (1/10) {
  v_4 = 0;
  v_5 = "T1_NAME_" /*[16]*/;
  if ((g_15._f21C))
	return 0;
  if ((g_1f2[/*6*/ (g_1f2)-1]._f0[/*1*/ 0])!=-1)
	if (!sub_66b ())
	  sub_798 (0);
  if (((v_0)._f18)!=-1)
	return 0;
  v_9 = sub_86d ({((v_0)._f0/* 6 */)});
  if ((v_9)!=-1)
	sub_798 ((v_9));
  v_3 = 0;
  while ((v_3)<=(g_1f2)-1) {
	if ((g_1f2[/*6*/ (v_3)]._f0[/*1*/ 0])==-1) {
	  g_1f2[/*6*/ (v_3)] = {((v_0)._f0/* 6 */)}/* 6 */;
	  (v_0)._f18 = (v_3);
	  v_3 = (g_1f2);
	  v_4 = (v_4)+1;
	  if ((v_4)>1) {
		$SET_PHONE_HUD_ITEM ({1, "UNREAD_MESSAGES", (v_4)});
	  } else {
		v_5 += sub_691 ({0, ((v_0)._f0/* 6 */)})/*S:[16]:I*/;
		$SET_PHONE_HUD_ITEM ({1, v_5, (v_4)});
	  }
	  g_15._f208 = 1;
	  $PLAY_AUDIO_EVENT ("MOBILE_PHONE_SMS_RECIEVE");
	  if ((g_1e5)==9) {
		g_15._f194 = 1016;
	  } else
		if ((g_15._f0)==1015)
		  g_15._f5C = 1;
	  $INCREMENT_INT_STAT_NO_MESSAGE ({300, 1});
	  g_3d24[/*1*/ 2] = 1;
	} else
	  if (sub_691 ({4, (g_1f2[/*6*/ (v_3)]/* 6 */)})==0)
		v_4 = (v_4)+1;
	v_3 = (v_3)+1;
  }
  $SET_MESSAGES_WAITING (1);
  return 1;
}

4) Что означает в декомпиляторе OpenIV код:

Var1 + 8 + 0 = Var1 + 8 + 0 - 24;
Возможно, правильнее будет:
*(&Var1 + 8 + 0) := *(&Var1 + 8 + 0) - 24;
или
*(Var1 + 8 + 0) := *(Var1 + 8 + 0) - 24;
Или что имелось ввиду?


Правильнее будет: var1._f8._f0 -= 24;
А указателей там нет, как явления. Только ссылки.

Некоторый код в OpenIV отличается от SparkIV:
Local[701][8(3)] в SparkIV декомпилирует как L[701][8 * 3]
Ещё пара: Var3 + 0[0(1)] в SparkIV превращается в &((*(var2 + 0))[0])
Это недоработки?


В целом, да. От того, что нормальных описаний типов нет.
Spark пишет для массива смещние в байтах. Open - как и положено, индекс. (и указывает в скобках размер элемента).
Конструкция вида var3+0[0(1)] - предположительно имелась в виду var3.length

5) Как сделать так, чтобы в такси можно было выбрать иконку добавленной миссии?

Это как-то связано с блипами. Предположительно, нужно добавить блип соответствующего типа.

6) Как скрипту-плагину перехватить управление за миг до начала записи сохранения? (Что-бы до сохранения удалить объекты Ext-скрипта)

А этого делать не надо. Нужно выставлять потоку этого скрипта флаг DONT_SAVE

7) Кодировка русских букв в версии 1.0.0.4 поменялась или нет?

Я не видел русскую кодировку до этого. В 1.0.0.4 - UTF8



Вот, что вспомнил.
С остальным попробую разобраться, как будет свободная минутка.
You think your day was surreal? Try mine.

#152 VcSaJen

VcSaJen

    Активный участник

  • Пользователи
  • PipPipPip
  • 270 сообщений
  • Пол:Мужчина
  • Интересы:GTA, скриптинг в GTA.


Отправлено 17 February 2010 - 01:51

@Listener -

6) Как скрипту-плагину перехватить управление за миг до начала записи сохранения? (Что-бы до сохранения удалить объекты Ext-скрипта)


А этого делать не надо. Нужно выставлять потоку этого скрипта флаг DONT_SAVE

Я скрипчу на Alice *.EXT плагины-скрипты. А там хотя скрипты не сохраняются, но всё, что было создано скриптом, сохраняется при сохранении. Т.е. например скрипт создал три маркера, а затем если сохраниться-загрузиться, то будет уже шесть маркеров (три сохранились, а три создались заново).
А для выставления этого флага есть только функция THIS_SCRIPT_SHOULD_BE_SAVED() без параметров (не работающая в Alice).

И ещё насчёт режима миссии: как всё таки он переключается? (когда значки других миссий скрываются и нельзя сохраниться)

#153 кандидат'09

кандидат'09

    Новичок

  • Неактивированные
  • Pip
  • 6 сообщений
  • Город:Газмясск

Отправлено 18 February 2010 - 16:15

Пишу плагин под с++ хук.
Как бы сделать красиво случайную выборку константы из перечисления?

enum eWeather
{
	WEATHER_EXTRA_SUNNY,
	WEATHER_SUNNY,
	WEATHER_SUNNY_WINDY,
	WEATHER_CLOUDY,
	WEATHER_RAINING,
	WEATHER_DRIZZLE,
	WEATHER_FOGGY,
	WEATHER_LIGHTNING,
	WEATHER_EXTRA_SUNNY_2,
	WEATHER_SUNNY_WINDY_2,
};

А то только всякое непотребство в голову лезет типа:

...
	int rnd = (double)rand()/(RAND_MAX+1)*9;
	switch(rnd)
	{
		case 0:
			weather = WEATHER_EXTRA_SUNNY;
			break;
		case 1:
			weather = WEATHER_SUNNY;
			break;
		case 2:
			weather = WEATHER_SUNNY_WINDY;
			break;
		case 3:
			weather = WEATHER_CLOUDY;
			break;
		case 4:
			weather = WEATHER_RAINING;
			break;
		case 5:
			weather = WEATHER_DRIZZLE;
			break;
		case 6:
			weather = WEATHER_FOGGY;
			break;
		case 7:
			weather = WEATHER_LIGHTNING;
			break;
		case 8:
			weather = WEATHER_EXTRA_SUNNY_2;
			break;
		case 9:
			weather = WEATHER_SUNNY_WINDY_2;
			break;
	}
	ForceWeatherNow(weather);
	SetSyncWeatherAndGameTime(1);
	...


#154 Johnix

Johnix

    Активный участник

  • Пользователи
  • PipPipPip
  • 87 сообщений
  • Пол:Мужчина
  • Город:Новосибирск

Отправлено 18 February 2010 - 17:18

полноценные миссии на данный момент писать в гта4 можно? с роликами, текстом и собственно самой миссией? использовать возможности гта4 в том числе звонок телефона , интернет и прочее можно? я не следил за этим. просто скажите да\нет и дайте ссыль на прогу. если вам не сложно
Изображение
Изображение

#155 VcSaJen

VcSaJen

    Активный участник

  • Пользователи
  • PipPipPip
  • 270 сообщений
  • Пол:Мужчина
  • Интересы:GTA, скриптинг в GTA.


Отправлено 24 February 2010 - 00:56

полноценные миссии на данный момент писать в гта4 можно?

Можно, я уже написал гоночную миссию.

я не следил за этим. просто скажите да\нет и дайте ссыль на прогу. если вам не сложно

Если ты умеешь программировать, то есть для Delphi - Alice от Alexander'a, для С++ - С++ Script Hook от Aru, и для C# .NET Script Hook.

#156 Johnix

Johnix

    Активный участник

  • Пользователи
  • PipPipPip
  • 87 сообщений
  • Пол:Мужчина
  • Город:Новосибирск

Отправлено 03 March 2010 - 19:39

ну это хорошо

Можно, я уже написал гоночную миссию.

а в какой программе?

Если ты умеешь программировать

неа гылол
буду учиться
ничего подобного санни билдеру не делается? или вообще невозможно и тока на нормальных языках программирования можно? ну ладно буду учиться
Изображение
Изображение

#157 VcSaJen

VcSaJen

    Активный участник

  • Пользователи
  • PipPipPip
  • 270 сообщений
  • Пол:Мужчина
  • Интересы:GTA, скриптинг в GTA.


Отправлено 04 March 2010 - 04:16

Научиться программировать гораздо легче, чем ты думаешь :) . Я например, с ходу начал делать свою программу, имея только опыт в SB.

#158 listener

listener

    Активный участник

  • Главные администраторы
  • PipPipPip
  • 356 сообщений
  • Пол:Мужчина
  • Город:Ft.Lauderdale


Отправлено 04 March 2010 - 09:08

Johnix
Делается, но неспешно и вялотекуще.
Если в жизни не будет никаких резких перемен, где-то через месяц будет закрытая бета.
You think your day was surreal? Try mine.

#159 Johnix

Johnix

    Активный участник

  • Пользователи
  • PipPipPip
  • 87 сообщений
  • Пол:Мужчина
  • Город:Новосибирск

Отправлено 04 March 2010 - 12:01

Так где ты написал гоночную миссию?
Изображение
Изображение

#160 VcSaJen

VcSaJen

    Активный участник

  • Пользователи
  • PipPipPip
  • 270 сообщений
  • Пол:Мужчина
  • Интересы:GTA, скриптинг в GTA.


Отправлено 06 March 2010 - 05:59

Delphi+Alice
Исходники:

RaCon.dpr
library RaCon; {$R *.res} {$E ext}

uses
  ScriptNatives,
  ScriptTypes,
  ScriptUseful,
  SysUtils,
  ClipBrd,
  Windows,
  Math,
  UnitRacesClass in 'UnitRacesClass.pas';

{$DEFINE DEBUG}

const
  Rus	   ='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя';
  EncodedRus='ЋЏђ‘’“”•–—˜™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМН';

function EncodeRus(const text: string): string;
var I,p: Integer;
begin
  Result:=Text;
  for I:=1 to Length(Result) do
  begin
	if Result[i]='ё' then Result[i]:='е';
	if Result[i]='Ё' then Result[i]:='Е';
	p:=pos(Result[i], Rus);
	if p>0 then Result[i]:=EncodedRus[p];
  end;
end;

function DecodeRus(const text: string): string;
var I,p: Integer;
begin
  Result:=Text;
  for I:=1 to Length(Result) do
  begin
	p:=pos(Result[i], EncodedRus);
	if p>0 then Result[i]:=Rus[p];
  end;
end;

procedure ShowText(text: string; time: integer = 5000);
begin
  PrintStringWithLiteralStringNow('string', PChar(EncodeRus(text)), time, 1);
end;

function Round(X: Extended): Int64;
begin
  Result:=System.Round(X);
end;

type
  EPlayerDead=class(Exception);
  TVector3=record
	X,Y,Z: Single;
  end;
  TDynIntArray=array of Integer;

  //Массивы миссии
var
  RaceCars: array of Cardinal;
  Drivers: array of Cardinal;
  RaceNames: array of string;
  RaceFinishTimes: array of Cardinal;
  ModelHashs: array of Cardinal;
  Checkpoints: array of TVector3;
  CarCurCP: array of Integer;
  RiderBlips: array of Cardinal;
  CarInOutR: array of Boolean;

procedure main(); export;
const
  AngleStep=15.0;

var
  {
  Car, DM: Cardinal;
  XForce,YForce: Single;
  CurForce: Single;
  I: Integer;
  D0,D1,D2,D3,D4: Integer;}
  X,Y,Z,Angle: Single;
  PlayerId : i32;
  PlayerChar : Ped;


procedure Mission(Id: Integer);
  procedure Wait(Time: Cardinal);
  var t1,t2: Cardinal; t: integer;
  begin
	if Time<60 then
	begin
	  ScriptNatives.Wait(Time);
	  if not IsPlayerPlaying(playerId) then
	  begin
		raise EPlayerDead.Create('Player dead or arrested!');
	  end;
	  Exit;
	end;

	GetGameTimer(@t1);
	t:=0;
	while Cardinal(Abs(t))<Time do
	begin
	  ScriptNatives.Wait(1);
	  GetGameTimer(@t2);
	  t:=t2-t1;
	  if not IsPlayerPlaying(playerId) then
	  begin
		raise EPlayerDead.Create('Player dead or arrested!');
	  end;
	end;
  end;

{const
  ModelsCount=3;
  Models: array [0..ModelsCount-1] of string
								 = ('infernus',
									'banshee',
									'comet');}

//Массивы миссии см. выше
var
  I: Integer;
  N: Integer;
  CPMarker: Cardinal;
  CPBlip, CPNextBlip: Cardinal;
  CPType: Integer;
  B{, PlInCar}: boolean;

  function CompareCars(Index1, Index2: Integer): Integer;
  var
	dist1, dist2: Single;
	X,Y,Z: Single;
  begin
	Result:=CompareValue(CarCurCP[Index1], CarCurCP[Index2]);
	if Result=0 then
	begin
	  if CarCurCP[Index1]>High(Checkpoints) then
	  begin
		Result:=-CompareValue(RaceFinishTimes[Index1],
							  RaceFinishTimes[Index2]);
	  end else
	  begin
		GetCarCoordinates(RaceCars[Index1],@X,@Y,@Z);
		GetDistanceBetweenCoords3D(Checkpoints[CarCurCP[Index1]].X,
								 Checkpoints[CarCurCP[Index1]].Y,
								 Checkpoints[CarCurCP[Index1]].Z,
								 X, Y, Z, @dist1);

		GetCarCoordinates(RaceCars[Index2],@X,@Y,@Z);
		GetDistanceBetweenCoords3D(Checkpoints[CarCurCP[Index2]].X,
								 Checkpoints[CarCurCP[Index2]].Y,
								 Checkpoints[CarCurCP[Index2]].Z,
								 X, Y, Z, @dist2);
		Result:=-CompareValue(dist1,dist2);
	  end;
	end;
	Result:=-Result;
  end;

  function GetRacersPos: TDynIntArray;
  var
	Size: Integer;
	k: integer; // текущий элемент массива
	i: integer; // индекс для ввода и вывода массива
	changed: boolean; // TRUE, если в текущем цикле были обмены
	buf: integer; // буфер для обмена элементами массива
  begin
	Size:=Length(RaceCars);
	SetLength(Result, Size);
	for I:=0 to Size-1 do
	begin
	  Result[I]:=I;
	end;
	//Сортировка
	repeat
	  Changed:=FALSE; // пусть в текущем цикле нет обменов
	  for k:=0 to SIZE-2 do
	  begin
		if CompareCars(Result[k], Result[k+1])=1 then
		begin // обменяем k-й и k+1-й элементы
		  buf := Result[k];
		  Result[k] := Result[k+1];
		  Result[k+1] := buf;
		  changed := TRUE;
		end;
	  end;
	until not changed; // если не было обменов, значит
					   // массив отсортирован

  end;

  function GetMetresToFinish(Index: Integer): Single;
  var
	I, N0: Integer;
	X,Y,Z,D: Single;
  begin
	Result:=0.0;
	N0:=CarCurCP[Index];
	if N0>High(Checkpoints) then Exit;
	GetCarCoordinates(RaceCars[Index],@X,@Y,@Z);
	GetDistanceBetweenCoords3D(X,Y,Z,Checkpoints[N0].X,
									 Checkpoints[N0].Y,
									 Checkpoints[N0].Z,
									 @D);
	Result:=D;
	for I:=N0 to High(Checkpoints)-1 do
	begin
	  GetDistanceBetweenCoords3D(Checkpoints[I].X,
								 Checkpoints[I].Y,
								 Checkpoints[I].Z,
								 Checkpoints[I+1].X,
								 Checkpoints[I+1].Y,
								 Checkpoints[I+1].Z,
								 @D);
	  Result:=Result+D;

	end;
	{Windows.Beep(2000, 50);
	ShowText(IntToStr(N0)+', '+IntToStr(Index));
	Wait(0);
	Sleep(1000);}

  end;

  function GetBehindInMetres(Index: Integer): string;
  var G: Integer;
  begin
	if Index=0 then
	begin
	  Result:='---';
	  Exit;
	end;
	G:=System.Round(GetMetresToFinish(0)-
					GetMetresToFinish(Index));
	Result:=IntToStr(G);
	if G>0 then Result:='+'+Result;
  end;

  procedure DrawPos;
  const
	LineH=0.039;
	ScaleX=0.18;
	StartPos=0.9;
  var
	Poss: TDynIntArray;
	I, Len: Integer;
	s: string;
  begin
	Poss:=GetRacersPos;
	Len:=High(RaceCars)+1;
	DrawRect(StartPos, 0.2729+(LineH*Len)/2, ScaleX, LineH*Len, 200, 200, 255, 150);

	for I:=0 to Len-1 do
	begin
	  SetTextScale(0.40 * 0.75, 0.40);
	  SetTextColour(240,240,255,255);
	  SetTextDropshadow(0,0,0,0,0);
	  SetTextEdge(1,0,0,128,255);
	  s:='';
	  if Poss[I]<>0 then
	  begin
		if IsCarDead(RaceCars[Poss[I]]) or IsCharDead(Drivers[Poss[I]]) then
		begin
		  SetTextColour(128,128,128,255);
		  SetTextEdge(1,64,64,64,255);
		  //s:=' (Мёртв)';
		end;
		if CarCurCP[Poss[I]]>High(Checkpoints) then
		begin
		  SetTextColour(198,0,198,255);
		  //SetTextEdge(1,255,0,128,255);
		  //s:=' (На финише)';
		end;
	  end;
	  SetTextDrawBeforeFade(False);
	  DisplayTextWithLiteralString(StartPos-(ScaleX/2)+0.01, 0.2729+(LineH*I)+(LineH/8),
				   'string', PChar(EncodeRus(IntToStr(I+1)+'. '+RaceNames[Poss[I]]+s)));
	  UsePreviousFontSettings;
	  DisplayTextWithLiteralString(StartPos+(ScaleX/2)-0.05, 0.2729+(LineH*I)+(LineH/8),
				   'string', PChar(GetBehindInMetres(Poss[I])));
	  //Windows.Beep(2000, 100);
	  //Sleep(500);

	  SetSpritesDrawBeforeFade(False);
	  if Poss[I]=0 then
		DrawRect(StartPos, 0.2729+(LineH*I)+LineH/2, ScaleX, 0.0332, 200, 200, 255, 150);
	end;
	Poss:=nil;
  end;
  function GameTimer: Cardinal;
  begin
	GetGameTimer(@Result);
  end;
  function IsCarStopped(veh : Vehicle): b8;
  begin // Из-за кривого названия в Alice
	Result:=IsCarStoppedestrian(veh);
  end;
  procedure ShowNumber(N: Integer);
	function Cube(V: Single): Single;
	begin
	  Result:=V*V*V*V*V;
	end;
	function S10(V: Single): Single;
	begin
	  Result:=V*V*V*V*V*V*V*V*V*V;
	end;
  var
	LastT: Cardinal;
	X,Y,T,Sc,Al: Single;
  begin
	T:=0;
	LastT:=GameTimer;
	while T<=1 do
	begin
	  //X:=Cube((T-0.5)*1.53)+0.25+T*0.5;
	  //Y:=1*Sqr(X-0.5)+0.2;
	  X:=Cube((T-0.5)*1.8)+0.25+T*0.5;
	  Y:=1*Sqr(X-0.5)+0.2;
	  Al:=-S10((X-0.5)*2)+1;
	  Al:=Al*255;
	  if Al>255 then Al:=255;
	  if Al<0 then Al:=0;
	  Sc:=((1/(T*50+1))-0.1);
	  if Sc<0 then Sc:=0;
	  Sc:=Sc+0.1;
	  SetTextScale(Sc*12.0*0.75, Sc*12.0);
	  SetTextDropshadow(2, 10,10,10,Round(Al));
	  SetTextColour(191,234,66,Round(Al));
	  SetTextCentre(True);
	  DisplayTextWithNumber(X,Y,'number',N);
	  T:=T+(GameTimer-LastT)/1500;
	  LastT:=GameTimer;
	  Wait(16);
	end;
  end;

  var LastT: Cardinal; T: Single;

  procedure TickShowGo(Text: string);
	function S10(V: Single): Single;
	begin
	  Result:=V*V*V*V*V*V*V*V*V*V;
	end;
  var
	Sc,Al: Single;
  begin
	if T<=1 then
	begin
	  //SetTextDropshadow(0, 0,0,0,0);
	  
	  SetTextCentre(True);
	  Al:=-S10((T-0.5)*2)+1;
	  Al:=Al*255;
	  if Al>255 then Al:=255;
	  if Al<0 then Al:=0;

	  Sc:=-5*T+1;
	  if Sc<0 then Sc:=0;
	  Sc:=Sc+0.1;
	  SetTextScale(Sc*12.0*0.75, Sc*12.0);
	  SetTextColour(191,234,66 ,Round(Al));
	  SetTextDropshadow(2, 10,10,10,Round(Al));

	  DisplayTextWithLiteralString(0.5,0.4,'string',PChar(EncodeRus(Text)));

	  T:=T+(GameTimer-LastT)/1500;
	  LastT:=GameTimer;
	end;
  end;

var LastUpsidedown{,Temp}: Integer;
const P1=1;P2=0;P3=3;P4=10;
		{1 0 3 10}
begin
  with Ra[Id].Environment do
  begin
	//DONE: Доделать погоду и окружение
	if EnableWeather then
	  ForceWeather(Weather);
	if EnableTime then
	  SetTimeOfDay(Hours, Minutes);
	SetCarDensityMultiplier(TrafficDensity);
	SetPedDensityMultiplier(PedsDensity);
  end;

  SetLength(CheckPoints, Ra[Id].CPsCount);

  for N:=0 to Ra[Id].CPsCount-1 do
  begin
	CheckPoints[N].X:=Ra[Id].CPs[N].Pos.X;
	CheckPoints[N].Y:=Ra[Id].CPs[N].Pos.Y;
	CheckPoints[N].Z:=Ra[Id].CPs[N].Pos.Z;
  end;

  SetLength(ModelHashs, Ra[Id].UsedModelsCount);
  for I:=0 to Ra[Id].UsedModelsCount-1 do
  begin
	ModelHashs[I]:=Ra[Id].UsedModels[I];
  end;
  CPMarker:=0;
  try
	try
	  SetLength(RaceCars,  Ra[Id].RacersCount);
	  SetLength(Drivers,   Ra[Id].RacersCount);
	  SetLength(CarCurCP,  Ra[Id].RacersCount);
	  SetLength(RiderBlips,Ra[Id].RacersCount);
	  SetLength(RaceNames, Ra[Id].RacersCount);
	  SetLength(RaceFinishTimes,Ra[Id].RacersCount);
	  SetLength(CarInOutR, Ra[Id].RacersCount);
	  for I:=0 to Ra[Id].RacersCount-1 do
	  begin
		RaceNames[I]:=Ra[Id].Racers[I].RacerName;
	  end;

	  for i:=0 to High(ModelHashs) do
		RequestModel(ModelHashs[I]);

	  LoadAllObjectsNow;

	  for I:=0 to High(RaceCars) do
	  with Ra[Id].Racers[I] do
	  begin
		CarCurCP[I]:=0;
		CarInOutR[I]:=False;

		CreateCar(GetHashKey(PChar(CarModel)), StartPos.X, StartPos.Y, StartPos.Z, @RaceCars[I], True);

		if ColorEnabled then
		begin
		  ChangeCarColour(RaceCars[I], CarColor1, CarColor2);
		end;

		SetCarHeading(RaceCars[I], StartAngle);
		with CarProofs do
		  SetCarProofs(RaceCars[I],BP,FP,EP,CP,MP);
		//if I<>0 then
		//  SetVehicleSteerBias(RaceCars[I],SteerBias);
		LockCarDoors(RaceCars[I],DoorState);

		FreezeCarPosition(RaceCars[I],true);
		AddBlipForCar(RaceCars[I], @RiderBlips[I]);
		ChangeBlipScale(RiderBlips[I], 0.6);
	  end;
	  SetBlipAsFriendly(RiderBlips[0], true);
	  ChangeBlipScale(RiderBlips[0], 1.0);
	  ChangeBlipDisplay(RiderBlips[0], 0);


	  WarpCharIntoCar(PlayerChar, RaceCars[0]);
	  {$IFDEF DEBUG}
	  //SetCharAllAnimsSpeed(PlayerChar,2.0);
	  //SetCharMoveAnimSpeedMultiplier(PlayerChar,0.3);
	  //SetCharGravity(PlayerChar,5E-15);
	  {$ENDIF}
	  for I:=1 to High(RaceCars) do
	  begin
		CreateRandomCharAsDriver(RaceCars[I],@Drivers[I]);
		SetCharGetOutUpsideDownCar(Drivers[I],false);
		//AddStuckCarCheckWithWarp(RaceCars[I], 1.0, 2000, true, true, true, Boolean(-1));
		//AddUpsideDownCarCheck(RaceCars[I]);
		SetBlipAsShortRange(RiderBlips[I], True);
	  end;
	  CPMarker:=CreateCheckpoint(2,CheckPoints[0].X,
								   CheckPoints[0].Y,
								   CheckPoints[0].Z+1.0,
								   CheckPoints[1].X,
								   CheckPoints[1].Y,
								   CheckPoints[1].Z,
								   1.0);

	  AddBlipForCoord(CheckPoints[0].X,CheckPoints[0].Y,CheckPoints[0].Z,@CPBlip);
	  AddBlipForCoord(CheckPoints[1].X,CheckPoints[1].Y,CheckPoints[1].Z,@CPNextBlip);
	  ChangeBlipScale(CPNextBlip,0.6);
	  DimBlip(CPNextBlip,True);
	  SetCamBehindPed(PlayerChar);

	  DoScreenFadeIn(750);
	  Wait(750);
	  {PlayAudioEvent('FRONTEND_OTHER_RACE_321');
	  PrintWithNumberBig('NUMBER', 3, 1000, true);
	  Wait(1000);
	  PlayAudioEvent('FRONTEND_OTHER_RACE_321');
	  PrintWithNumberBig('NUMBER', 2, 1000, true);
	  Wait(1000);
	  PlayAudioEvent('FRONTEND_OTHER_RACE_321');
	  PrintWithNumberBig('NUMBER', 1, 1000, true);
	  Wait(1000);}
	  ShowNumber(3);
	  ShowNumber(2);
	  ShowNumber(1);
	  PlayAudioEvent('FRONTEND_OTHER_RACE_GO');

	  for I:=1 to High(RaceCars) do
	  begin
		TaskCarDriveToCoord(Drivers[I],RaceCars[I],
								CheckPoints[0].X,
								CheckPoints[0].Y,
								CheckPoints[0].Z,
								Ra[Id].CPs[0].Speed, P1, P2, P3, Ra[Id].CPs[0].Radius, P4);
	  end;
	  for I:=0 to High(RaceCars) do
	  begin
		FreezeCarPosition(RaceCars[I], False);
	  end;
	  LastUpsidedown:=GameTimer;
	  LastT:=GameTimer;
	  T:=0;
	  while true do
	  begin
		TickShowGo('Старт!');
		for I:=1 to High(RaceCars) do
		begin
		  with Ra[Id].CPs[CarCurCP[I]] do
		  if LocateCar3D(RaceCars[I],
						 CheckPoints[CarCurCP[I]].X,
						 CheckPoints[CarCurCP[I]].Y,
						 CheckPoints[CarCurCP[I]].Z,
						 Radius, Radius, Radius, False) then
		  begin
			Inc(CarCurCP[I]);
			CarInOutR[I]:=False;
			//ClearCharTasks(Drivers[I]);
			if CarCurCP[I]<=High(CheckPoints) then
			begin
			  TaskCarDriveToCoord(Drivers[I],RaceCars[I],
								  CheckPoints[CarCurCP[I]].X,
								  CheckPoints[CarCurCP[I]].Y,
								  CheckPoints[CarCurCP[I]].Z,
								  Speed, P1, P2, P3, Radius, P4);
			  SetCarForwardSpeed(RaceCars[I], 20.0);
			end
			else begin
			  if RaceFinishTimes[I]=0 then RaceFinishTimes[I]:=GameTimer;
			  CarCurCP[I]:=High(CheckPoints)+1;
			end
		  end;
		  {if LocateCar3D(RaceCars[I],
						 CheckPoints[CarCurCP[I]].X,
						 CheckPoints[CarCurCP[I]].Y,
						 CheckPoints[CarCurCP[I]].Z,
						 50.0, 50.0, 50.0, False) then
		  begin

		  end;}
		end;
		{DONE: При взрыве машины игрока - провал}
		{DONE: Если гонщик взорвался, то прибавть к имени (Умер)}
		{DONE: Если гонщик финишировал, то прибавть к имени (---)}
		{DONE: Сделать счётчик как в NFS:MW}
		{DONE: Сделать показ расстояния отставания/опережения}
		{DONE: Сделать так, чтобы при финишировании оставался порядок (массив вреиён финиширования)}

		if IsCarDead(RaceCars[0]) then
		begin
		  ShowText('~r~Вы остались без машины!');
		  raise EPlayerDead.Create('CarDead');
		end;

		if IsCarUpsidedown(RaceCars[0]) and
			IsCharInCar(PlayerChar, RaceCars[0]) then
		begin
		  if ((GameTimer-LastUpsidedown) > 5000) then
		  begin
			SetPlayerControl(PlayerId, False);
			DoScreenFadeOut(2500);
			while IsScreenFading do Wait(50);
			GetCarCoordinates(RaceCars[0], @X, @Y, @Z);
			GetClosestCarNodeWithHeading(X,Y,Z,@X,@Y,@Z,@Angle);
			SetCarCoordinates(RaceCars[0], X, Y, Z);
			SetCarHeading(RaceCars[0], Angle);
			DoScreenFadeIn(750);
			SetPlayerControl(PlayerId, True);
		  end
		end else LastUpsidedown:=GameTimer;
		if not IsCharInCar(PlayerChar, RaceCars[0]) then
		begin
		  AddNextMessageToPreviousBriefs(False);
		  ShowText('Сядьте в ~b~автомобиль',100);
		  ChangeBlipDisplay(RiderBlips[0],2);
		end else
		if LocateCar3D(RaceCars[0],
					   CheckPoints[CarCurCP[0]].X,
					   CheckPoints[CarCurCP[0]].Y,
					   CheckPoints[CarCurCP[0]].Z,
					   10.0, 10.0, 10.0, False) then
		begin
		  ChangeBlipDisplay(RiderBlips[0],0);
		  Inc(CarCurCP[0]);
		  DeleteCheckpoint(CPMarker);
		  PlayAudioEvent('FRONTEND_GAME_PICKUP_CHECKPOINT');
		  if CarCurCP[0]>High(CheckPoints) then
		  begin
			B:=true;
			for I:=1 to High(RaceCars) do
			begin
			  B:=B and (CarCurCP[I]<High(CheckPoints)+1);
			end;
			if B then
			begin
			  AddScore(playerId, 12000);
			  TriggerMissionCompleteAudio(1);
			  ShowText('Вы победили!');
			end else ShowText('~r~Вы проиграли.');

			Break;
		  end;
		  if CarCurCP[0]=High(CheckPoints)
		  then CPType:=3
		  else CPType:=2;

		  CPMarker:=CreateCheckpoint(CPType,
									 CheckPoints[CarCurCP[0]].X,
									 CheckPoints[CarCurCP[0]].Y,
									 CheckPoints[CarCurCP[0]].Z+1.0,
									 CheckPoints[CarCurCP[0]+1].X,
									 CheckPoints[CarCurCP[0]+1].Y,
									 CheckPoints[CarCurCP[0]+1].Z,
									 1.0);
		  RemoveBlip(CPBlip);
		  RemoveBlip(CPNextBlip);

		  AddBlipForCoord(CheckPoints[CarCurCP[0]].X,
						  CheckPoints[CarCurCP[0]].Y,
						  CheckPoints[CarCurCP[0]].Z,
						  @CPBlip);
		  if CarCurCP[0]=High(CheckPoints) then
			ChangeBlipSprite(CPBlip, 65);

		  if CarCurCP[0]<High(CheckPoints) then
		  begin
			AddBlipForCoord(CheckPoints[CarCurCP[0]+1].X,
							CheckPoints[CarCurCP[0]+1].Y,
							CheckPoints[CarCurCP[0]+1].Z,
							@CPNextBlip);
			if (CarCurCP[0]+1)=High(CheckPoints) then
			  ChangeBlipSprite(CPNextBlip, 65);
			ChangeBlipScale(CPNextBlip,0.6);
			DimBlip(CPNextBlip,True);
		  end;
		end;
		DrawPos;
		Wait(1);
	  end;



	finally
	  SetCarDensityMultiplier(1.0);
	  SetPedDensityMultiplier(1.0);
	  DeleteCheckpoint(CPMarker);
	  RemoveBlip(CPBlip);
	  RemoveBlip(CPNextBlip);
	  for i:=0 to High(ModelHashs) do
		MarkModelAsNoLongerNeeded(ModelHashs[I]);
	  for I:=1 to High(RaceCars) do
	  begin
		//RemoveStuckCarCheck(RaceCars[I]);
		//RemoveUpsidedownCarCheck(RaceCars[I]);
		MarkCarAsNoLongerNeeded(@RaceCars[I]);
		MarkCharAsNoLongerNeeded(@Drivers[I]);
		RemoveBlip(RiderBlips[I]);
	  end;
	  MarkCarAsNoLongerNeeded(@RaceCars[0]);
	  RemoveBlip(RiderBlips[0]);
	  ReleaseWeather;

	  Finalize(RaceCars	   );
	  Finalize(Drivers		);
	  Finalize(RaceNames	  );
	  Finalize(RaceFinishTimes);
	  Finalize(ModelHashs	 );
	  Finalize(Checkpoints	);
	  Finalize(CarCurCP	   );
	  Finalize(RiderBlips	 );
	  Finalize(CarInOutR	  );
	end;
  except
	on EPlayerDead do
	begin
	  Exit;
	end;
  end;
end;

var
  //Font: Cardinal;
  WTD, MyTexture,r: cardinal;
  {t1,t2:cardinal;
  t: Integer;}
  F: TextFile;
  //rChar: Cardinal;
  //x2,y2,z2,d: Single;
  Hash,hash2,Car,ped: Cardinal;
  I: Integer;
  blips: array of Cardinal;

var
  MemInfo: TMemoryBasicInformation;
  ModName: array[0..MAX_PATH] of Char;
  S: string;
begin
  Wait(2000);

  try
  //TODO: Добавить время отставанья/опереженья
  AssignFile(F, 'coords.log');
  Rewrite(F);
  CloseFile(F);

  Ra:=TRaces.Create('Alice\RaCon');
  SetLength(blips, ra.Count);
  //ShowText('Count='+IntToStr(ra.Count));
  //Wait(5000);
  for I:=0 to Ra.Count-1 do
  begin
	//ShowText('(blips)I='+IntToStr(I), 2000);
	//Wait(2000);
	with Ra[I].General.BlipPos do
	  AddBlipForContact(X, Y, Z, @(Blips[I]));
	ChangeBlipSprite(Blips[I], Ra[I].General.BlipSprite);
	ChangeBlipDisplay(Blips[I], 2);
	ChangeBlipNameFromAscii(Blips[I], PChar(EncodeRus(Ra[I].General.RaceName)));
  end;

  //2
  //3-только на общей карте
  //4
  //5-только на радаре
  while True do
  begin
	PlayerId := GetPlayerId();
	if PlayerId >= 0 then
	if IsPlayerPlaying(PlayerId) then
	if PlayerHasChar(PlayerId) then
	begin
	  GetPlayerChar(PlayerId, @PlayerChar);
	  if PlayerChar > 0 then
	  begin
		{$IFDEF DEBUG}
		//SetCarDensityMultiplier(0.0);
		//SetPedDensityMultiplier(0.0);
		//SetRandomCarDensityMultiplier(0.0);
		//SetParkedCarDensityMultiplier(10.0);
		SetCharProofs(PlayerChar,true,false,false,false,true);
		ClearWantedLevel(playerId);
		{$ENDIF}
		for I := 0 to Ra.Count-1 do
		with Ra[I].General do
		begin
		  //ShowText('(Ra)I='+IntToStr(I),2000);
		  //Wait(2000);
		  DrawColouredCylinder(BlipPos.X, BlipPos.Y, BlipPos.Z, 2.5, 2.5, MarkerColor.Red, MarkerColor.Green, MarkerColor.Blue, 255);
		  if LocateCharAnyMeans3D(PlayerChar, BlipPos.X, BlipPos.Y, BlipPos.Z, 2.5, 2.5, 2.5, False) then
		  begin
			{TODO: Узнать, как делается запись вместо Загрузки}
			{TODO: Узнать, как нормально поставить флаг миссии}
			{TODO: Поставить PTFX на старте как в Most Wanted}

			//SetMsgForLoadingScreen('M_43');
			//Hash:=5 div Round(Sin(0));
			//Hash:=ScriptNatives.Round(-1.0);
			//ShowText(IntToStr(Hash));
			//PInteger($DDDDDDDD)^:=-1;
			//hash:=GetHashKey('admiral');
			//RequestModel(hash);
			//LoadAllObjectsNow;
			//GetOffsetFromCharInWorldCoords(PlayerChar,0.0,3.0,0.0,@X,@Y,@Z);
			//for hash2:=0 to 100 do CreateCar(hash, X, Y, Z+1.0, @Car, False);


			DoScreenFadeOut(750);
			while IsScreenFading do Wait(50);
			SetMissionFlag(True);
			PCardinal(GetGlobalsArray+10978*4)^:=1;
			Mission(I);
			PCardinal(GetGlobalsArray+10978*4)^:=0;

			SetMissionFlag(False);
			Break;

		  end;
		end;

		if KeyPressed(Ord('I')) then
		begin
		  Append(F);

		  GetCharCoordinates(PlayerChar, @X,@Y,@Z);
		  DecimalSeparator:='.';
		  //Format('%.4f, %.4f, %.4f', [X,Y,Z])
		  Clipboard.AsText:=FloatToStr(X)+', '+FloatToStr(Y)+', '+FloatToStr(Z)+', ';
		  WriteLn(F,X:1:4,', ',Y:1:4,', ',Z:1:4,', ');
		  ShowText('Скопировано.',1000);
		  CloseFile(F);
		end;
		{$IFDEF DEBUG}
		if KeyPressed(Ord('U')) then
		begin
		  GetCharHeading(PlayerChar,@Angle);
		  //GetCharCoordinates(PlayerChar,@x,@y,@z);
		  Windows.Beep(200,20);
		  //if GetClosestChar(X,Y,Z,10.0, 1, 1, @rChar) then
		  //begin

			//GetCharCoordinates(rChar,@x2,@y2,@z2);
			//GetDistanceBetweenCoords3D(X,Y,Z,x2,y2,z2,@d);
			Angle:=Angle+90.0;
			X:=ScriptNatives.Cos(Angle)*5.0;
			Y:=ScriptNatives.Sin(Angle)*5.0;
			Z:=20.0;

			//SetCharVelocity(rChar,X2,Y2,Z2);
			//ApplyForceToPed(rChar,1,X,Y,Z,0.0,0.0,0.0,1,1,1,10000);

			SwitchPedToRagdollWithFall(PlayerChar, 2000, 3000, 0, X, Y, Z, 50.0, 0.0,0.0,0.0,0.0,0.0,0.0);
		  //  Windows.Beep(5000,50);
			Wait(200);
		  //end;
		end;
		if KeyPressed(Ord('J')) then
		begin
		  hash:=GetHashKey('admiral');
		  hash2:=GetHashKey('ig_Gordon');

		  GetOffsetFromCharInWorldCoords(PlayerChar,0.0,3.0,0.0,@X,@Y,@Z);

		  RequestModel(hash);
		  RequestModel(hash2);
		  LoadAllObjectsNow;
		  CreateCar(hash,X,Y,Z,@Car,true);

		  GetOffsetFromCharInWorldCoords(PlayerChar,1.0,0.0,0.0,@X,@Y,@Z);
		  CreateChar(5,hash2,X,Y,Z, @Ped, True);
		  TaskEnterCarAsPassenger(Ped,Car,60000,1);
		  //TaskEnterCarAsDriver(Ped,Car,60000);

		  LockCarDoors(Car,6);//1. Открыто
							  //2. Закрыто
							  //3. Закрыто только для игрока
							  //4. Заперто (если внутри, то невозможно выйти)
							  //5. Открыто?
							  //6. Открыто?
							  //7. Закрыто, но можно разбить окно
							  //8. Закрыто (не оглядывается)

		  MarkModelAsNoLongerNeeded(hash);
		  MarkModelAsNoLongerNeeded(hash2);
		  wait(5000);
		  //WarpCharIntoCar(PlayerChar,Car);
		end;
		if KeyPressed(Ord('L')) then
		begin
		  GetScriptRendertargetRenderId(@R);
		  SetTextRenderId(R);


		  SetTimerA(0);
		  wtd:=LoadTxd('Qub3d');
		  //RequestStreamedTxd('zombie.wtd', true);
		  Windows.Beep(10000,5);
		  //LoadAllObjectsNow;
		  //while not HasStreamedTxdLoaded('zombie.wtd') do
		  //begin
		  //  Wait(50);
		  //end;
		  //MyTexture:=GetTextureFromStreamedTxd('zombie.wtd', 'zlogo.dds');


		  MyTexture:=GetTexture(wtd, 'QUB3D_LOGO_150906');


		  //Windows.Beep(10000,50);
		  //while not IsFontLoaded(Font) do Wait (50);
		  Windows.Beep(5000,100);
		  while TimerA<5000 do
		  begin
			//SetTextFont(Font);
			DrawSprite(MyTexture, 0.5, 0.5, 0.8, 0.8, 0.0, 255,255,255,255);
			DrawCurvedWindow(0.4, 0.4, 0.2, 0.2, 240);
			//DrawRect(0.0,0.0, 0.1,0.1, 255,0,0,255);

			//DisplayText(0.5, 0.5, 'M_43');
			Wait(1);
		  end;
		  ReleaseTexture(MyTexture);
		  RemoveTxd(wtd);
		  //MarkStreamedTxdAsNoLongerNeeded('zombie.wtd');

		  Windows.Beep(1000,100);
		  //Inc(Font);
		end;
		{$ENDIF}
	  end;
	end;
	Wait(50);
  end;
  except
	on E: Exception do
	begin

	  Windows.Beep(100, 100);
	  Windows.Beep(1600, 100);
	  Windows.Beep(100, 100);
	  Windows.Beep(1600, 100);
	  Windows.Beep(100, 100);
	  Windows.Beep(1600, 100);

	  ShowText('-------------------------------',0);
	  ShowText('или в крайнем случае на ящик VcSaJen@ya.ru',0);
	  ShowText('Пожалуйста сообщите эти данные автору в темке RaCon на http://forums.gtamodding.ru/',0);

	  ShowText('Адрес: '+IntToHex(Integer(ExceptAddr),8),0);
	  ShowText('Адрес Main: '+IntToHex(Integer(@main),8),0);

	  VirtualQuery(ExceptAddr, MemInfo, SizeOf(MemInfo));
	  if (MemInfo.State = MEM_COMMIT) and
		 (GetModuleFileName(THandle(MemInfo.AllocationBase), ModName, SizeOf(ModName)) <> 0) then
	  begin
		S:=ModName;
		Delete(S, Pos(GetCurrentDir,S), Length(GetCurrentDir)+1);
		//ShowText('Локальный адрес Base: '+IntToHex(Integer(ExceptAddr)-Integer(MemInfo.BaseAddress),8),0);
		ShowText('Локальный адрес: '+IntToHex(Integer(ExceptAddr)-(Integer(MemInfo.AllocationBase)+$1000),8),0);
		//ShowText('Base: '+IntToHex(Integer(MemInfo.BaseAddress),8),0);
		ShowText('Allocation base: '+IntToHex(Integer(MemInfo.AllocationBase),8),0);
		ShowText('Модуль: '+S,0);
	  end
	  else begin

	  end;

	  ShowText(E.Message,0);
	  ShowText('Класс: '+E.ClassName,0);
	  ShowText('-------------------------------',0);
	  ShowText('  Информация об ошибке:',0);
	  ShowText('-------------------------------',0);

	  AddNextMessageToPreviousBriefs(False);
	  ShowText('В RaCon возникла ошибка. Перепишите информацию об ошибке и перезагрузите игру.',5000);

	  Wait(5000);
	  {'~r~'+E.ClassName+': '+E.Message}
	  AddNextMessageToPreviousBriefs(False);
	  ShowText('Информацию об ошибке смотрите в "Истории" (Briefs) в меню (2-й пункт, сразу после "Карты").',60000);
	  //Clipboard.AsText:=E.Message;
	  Exit;
	end;
  end;
end;

procedure aDLLProc(Reason: Integer);
begin
  // if game is ended, destroy the player
  if Reason = DLL_PROCESS_DETACH then
  begin
	Finalize(RaceCars	   );
	Finalize(Drivers		);
	Finalize(RaceNames	  );
	Finalize(RaceFinishTimes);
	Finalize(ModelHashs	 );
	Finalize(Checkpoints	);
	Finalize(CarCurCP	   );
	Finalize(RiderBlips	 );
	Finalize(CarInOutR	  );
  end;
end;

exports main;

begin
  DllProc:=@aDLLProc;
end.

UnitRacesClass.pas
unit UnitRacesClass;

interface

uses SysUtils, IniFiles, Classes, ScriptNatives;

type
  TVector3=record
	X,Y,Z: Single;
  end;
  TRot3=TVector3;
  TProofs=record
	BP,FP,EP,CP,MP: Boolean;
  end;
  //TPedData=record
  //  RandomPedModel: Boolean;
  //  PedModel: string;
  //  Weapon: Integer;
  //  PedProofs: TProofs;
  //end;
  TRacerData=record
	RacerName: string;
	CarModel: string;
	ColorEnabled: Boolean;
	CarColor1,CarColor2: Integer;
	//Driver: TPedData;
	//Passengers: array [0..2] of TPedData;
	CarProofs: TProofs;
	StartPos: TVector3;
	StartAngle: Single;
	DoorState: Byte;
	SteerBias: Single;
  end;
  TCPData=record
	Pos: TVector3;
	Radius: Single;
	Speed: Single;
  end;
  TObjData=record
	Model: string;
	Pos: TVector3;
	Rot: TRot3;
	Collision: Boolean;
	Indestructible: Boolean;
	Freeze: Boolean;
	Comment: string;
  end;
  TRGBColor=record
	Red,Green,Blue: Byte;
  end;
  TGeneralData=record
	RaceName: string;
	RaceType: Integer;
	OftenTimes: Boolean;
	Award: Integer;
	BlipSprite: Integer;
	MarkerColor: TRGBColor;
	BlipPos: TVector3;
	RequiredPassedCount: Integer;
	RequiredPassed: array of string;
	NoneIsPassed: Boolean;
  end;
  TViewData=record
	ShowRacersList: Boolean;
  end;
  TEnvironmentData=record
	EnableWeather: Boolean;
	Weather: Integer;
	EnableTime: Boolean;
	Hours: Integer;
	Minutes: Integer;
	TrafficDensity: Single;
	PedsDensity: Single;
  end;
  TRaces=class; 

  TRace=class(TObject)
  private
	//FOwnerRaces: TRaces;
	FRacersCount: Integer;
	FRacers: array of TRacerData;
	FCheckpointsCount: Integer;
	FCheckpoints: array of TCPData;
	FObjectsCount: Integer;
	FObjects: array of TObjData;
	FGeneral: TGeneralData;
	FView: TViewData;
	FEnvironment: TEnvironmentData;
	FUsedModels: array of Integer;
	FUsedModelsCount: Integer;
	function GetCPs(Index: Integer): TCPData;
	function GetObjs(Index: Integer): TObjData;
	function GetRacers(Index: Integer): TRacerData;
	function GetModel(Index: Integer): Integer;
  protected
	procedure UpgUsedModels;
  public
	property General: TGeneralData read FGeneral;

	property RacersCount: Integer read FRacersCount;
	property Racers[Index: Integer]: TRacerData read GetRacers;

	property CPsCount: Integer read FCheckpointsCount;
	property CPs[Index: Integer]: TCPData read GetCPs;

	property ObjsCount: Integer read FObjectsCount;
	property Objs[Index: Integer]: TObjData read GetObjs;

	property View: TViewData read FView;
	property Environment: TEnvironmentData read FEnvironment;

	property UsedModelsCount: Integer read FUsedModelsCount;
	property UsedModels[Index: Integer]: Integer read GetModel;

	constructor Create(FileName: string);
	destructor Destroy; override;
	procedure Open(FileName: string);
  end;

  TRaces=class(TObject)
  private
	FRaces: array of TRace;
	FCount: Integer;
	function GetRace(Index: Integer): TRace;
  public
	property Races[Index: Integer]: TRace read GetRace; default;
	property Count: Integer read FCount;
	constructor Create(Dir: string);
	destructor Destroy; override;
	procedure Open(Dir: string);
  end;

var
  Ra: TRaces;

implementation

{ TRace }

constructor TRace.Create(FileName: string);
begin
  inherited Create;
  Open(FileName);
end;

destructor TRace.Destroy;
begin
  Finalize(FRacers);
  Finalize(FCheckpoints);
  Finalize(FObjects);
  Finalize(FUsedModels);
  inherited;
end;

function TRace.GetCPs(Index: Integer): TCPData;
begin
  Result:=FCheckpoints[Index];
end;

function TRace.GetObjs(Index: Integer): TObjData;
begin
  Result:=FObjects[Index];
end;

function TRace.GetRacers(Index: Integer): TRacerData;
begin
  Result:=FRacers[Index];
end;

function TRace.GetModel(Index: Integer): Integer;
begin
  Result:=FUsedModels[Index];
end;

procedure TRace.Open(FileName: string);
var
  Ini: TIniFile;
  I, Count: Integer;
  S: string;
  List: TStringList;
begin
  DecimalSeparator:='.';
  Ini:=TIniFile.Create(FileName);
  List:=TStringList.Create;
  with ini do
  try
	//Общее
	with FGeneral do
	begin
	  RaceName:=ReadString('general', 'RaceName', '***НЕ УКАЗАНО***');
	  RaceType:=ReadInteger('general', 'RaceType', 0);
	  OftenTimes:=ReadBool('general', 'OftenTimes', False);
	  Award:=ReadInteger('general', 'Award', 0);
	  BlipSprite:=ReadInteger('general', 'BlipSprite', 0);
	  MarkerColor.Red:=ReadInteger('general', 'MarkerColor.Red', 0);
	  MarkerColor.Green:=ReadInteger('general', 'MarkerColor.Green', 0);
	  MarkerColor.Blue:=ReadInteger('general', 'MarkerColor.Blue', 0);
	  BlipPos.X:=ReadFloat('general', 'Blip.X', 0.0);
	  BlipPos.Y:=ReadFloat('general', 'Blip.Y', 0.0);
	  BlipPos.Z:=ReadFloat('general', 'Blip.Z', 0.0);
	  List.CommaText:=ReadString('general', 'RequiredPassed', '');
	  SetLength(RequiredPassed, List.Count);
	  RequiredPassedCount:=List.Count;
	  for I:=0 to List.Count-1 do
	  begin
		RequiredPassed[I]:=List[I];
	  end;
	  NoneIsPassed:=ReadBool('general', 'NoneIsPassed', True);
	end;

	// Гонщики
	Count:=ReadInteger('racers', 'Count', 0);
	SetLength(FRacers, Count);
	Self.FRacersCount:=Count;
	for I:=0 to Count-1 do
	begin
	  with FRacers[I] do
	  begin
		S:='Racer'+IntToStr(I);
		RacerName:=ReadString(S,'RacerName','***Ошибка INI***');
		StartPos.X:=ReadFloat(S,'StartPos.X',0);
		StartPos.Y:=ReadFloat(S,'StartPos.Y',0);
		StartPos.Z:=ReadFloat(S,'StartPos.Z',0);
		StartAngle:=ReadFloat(S,'StartAngle',0);
		CarModel:=ReadString(S,'CarModel','banshee');
		ColorEnabled:=ReadBool(S,'ColorEnabled',False);
		CarColor1:=ReadInteger(S,'CarColor1',0);
		CarColor2:=ReadInteger(S,'CarColor2',0);
		SteerBias:=ReadFloat(S,'SteerBias',5.0);
		CarProofs.BP:=ReadBool(S,'CarProofs.BP',true);
		CarProofs.FP:=ReadBool(S,'CarProofs.FP',true);
		CarProofs.EP:=ReadBool(S,'CarProofs.EP',true);
		CarProofs.CP:=ReadBool(S,'CarProofs.CP',true);
		CarProofs.MP:=ReadBool(S,'CarProofs.MP',true);
		DoorState:=ReadInteger(S,'DoorState',1);
	  end;
	end;

	//Контрольные точки
	Count:=ReadInteger('CPs', 'Count', 0);
	SetLength(FCheckpoints, Count);
	FCheckpointsCount:=Count;

	for I:=0 to Count-1 do
	begin
	  with FCheckpoints[I] do
	  begin
		S:='CP'+IntToStr(I);
		Pos.X:=ReadFloat(S,'Pos.X',0);
		Pos.Y:=ReadFloat(S,'Pos.Y',0);
		Pos.Z:=ReadFloat(S,'Pos.Z',0);
		Radius:=ReadFloat(S,'Radius',7);
		Speed:=ReadFloat(S,'Speed',200);
	  end;
	end;

	//Вид
	FView.ShowRacersList:=ReadBool('view', 'ShowRacersList', true);

	//Среда
	with FEnvironment do
	begin
	  EnableWeather:=ReadBool('environment', 'EnableWeather', False);
	  Weather:=ReadInteger('environment', 'Weather', -1);
	  EnableTime:=ReadBool('environment', 'EnableTime', false);
	  Hours:=ReadInteger('environment', 'Hours', 12);
	  Minutes:=ReadInteger('environment', 'Minutes', 0);
	  TrafficDensity:=ReadFloat('environment', 'TrafficDensity', 1.0);
	  PedsDensity:=ReadFloat('environment', 'PedsDensity', 1.0);
	end;

	//Объекты
	Count:=ReadInteger('objects', 'Count', 0);
	SetLength(FObjects, Count);
	FObjectsCount:=Count;
	for I:=0 to Count-1 do
	begin
	  with FObjects[I] do
	  begin
		S:='Object'+IntToStr(I);
		Model:=ReadString(S,'Model','null');
		Pos.X:=ReadFloat(S,'Pos.X',0);
		Pos.Y:=ReadFloat(S,'Pos.Y',0);
		Pos.Z:=ReadFloat(S,'Pos.Z',0);
		Rot.X:=ReadFloat(S,'Rot.X',0);
		Rot.Y:=ReadFloat(S,'Rot.Y',0);
		Rot.Z:=ReadFloat(S,'Rot.Z',0);
		Collision:=ReadBool(S,'Collision',true);
		Indestructible:=ReadBool(S,'Indestructible',false);
		Freeze:=ReadBool(S,'Freeze',false);
		Comment:=ReadString(S,'Comment','***ОШИБКА INI***');
	  end;
	end;
	UpgUsedModels;
  finally
	Ini.Free;
	List.Free;
  end;
end;

procedure TRace.UpgUsedModels;
var
  List: TStringList;
  I: Integer;
begin
  List:=TStringList.Create;
  List.Sorted:=True;
  List.Duplicates:=dupIgnore;
  List.CaseSensitive:=False;
  for I := 0 to FRacersCount-1 do
  begin
	List.Add(FRacers[I].CarModel);
  end;
  for I := 0 to FObjectsCount-1 do
  begin
	List.Add(FObjects[I].Model);
  end;

  SetLength(FUsedModels, List.Count);
  FUsedModelsCount:=List.Count;
  for I := 0 to List.Count-1 do
  begin
	FUsedModels[I]:=GetHashKey(PChar(List[I]));
  end;
  List.Free;
end;

{ TRaces }

constructor TRaces.Create(Dir: string);
begin
  inherited Create;
  Open(Dir);
end;

destructor TRaces.Destroy;
var I: Integer;
begin
  for I:=0 to FCount-1 do
  begin
	FRaces[I].Free;
  end;
  Finalize(FRaces);
  inherited;
end;

function TRaces.GetRace(Index: Integer): TRace;
begin
  Result:=FRaces[Index];
end;

procedure TRaces.Open(Dir: string);
var
  Rec: TSearchRec;
  N: Integer;
  E: Integer;
begin
  N:=0;
  E:=FindFirst('.\Alice\RaCon\*.RaCon', $3, Rec);
  try
	while E=0 do
	begin
	  if FileExists('Alice\RaCon\'+Rec.Name) then
	  begin
		Inc(N);
		SetLength(FRaces, N);
		FRaces[N-1]:=TRace.Create(GetCurrentDir+'\Alice\RaCon\'+Rec.Name);
		E:=FindNext(Rec);
	  end;
	end;
  finally
	FCount:=High(FRaces)+1;
	FindClose(Rec);
  end;
end;



initialization

finalization
  Ra.Free;
end.





Количество пользователей, читающих эту тему: 2

0 пользователей, 2 гостей, 0 анонимных