External Script – что это такое и как с ним работать?
External Script – что это такое и как с ним работать?
External Script – внешний скрипт используется только в GTA San Andreas. Он находится отдельно от main.scm, поэтому он и называется «внешний». Внешний скрипт является скомпилированным бинарным файлом, имеющим расширение .scm. В отличии от main.scm внешний скрипт не имеет заголовка. Вся информация о нем находится в заголовке main.scm.
DEFINE EXTERNAL_SCRIPTS 0 // Use -1 in order not to compile AAA script
//DEFINE SCRIPT {NAME} AT {LABEL} @
Внешние скрипты расположены в файле script.img в папке script (data/script). Максимальное количество внешних скриптов - 82. Максимальное количество внешних скриптов, которые могут использоваться одновременно равно 70.
Оригинальная игра в настоящий момент имеет 78 внешних скриптов.
Список внешних скриптов можно взять на http://www.gtamodding.com
Внешний скрипт, как и миссия нуждается в запуске, т.е. нужен стартер внешнего скрипта. Для примера будем использовать очищенный main.scm (stripped.txt). Найти его можно в папке SannyBuilderdatasa.
Открываем stripped.txt в SannyBuilder’е и над комментарием
{
use macro (Ctrl+J) "headsa"
to insert a file header
}
или вместо него ставим курсор и нажимаем Ctrl+J. В появившемся списке выбираем "headsa" и нажимаем ENTER. Этой незатейливой операцией мы добавили в наш файл (stripped.txt) заголовок:
DEFINE MISSIONS 0
//DEFINE MISSION {ID} 0 AT {LABEL} @
DEFINE EXTERNAL_SCRIPTS 0 // Use -1 in order not to compile AAA script
//DEFINE SCRIPT {NAME} AT {LABEL} @
DEFINE UNKNOWN_EMPTY_SEGMENT 0
DEFINE UNKNOWN_THREADS_MEMORY 0
В строке DEFINE EXTERNAL_SCRIPTS записывается общее количество внешних скриптов. Изменим 0 на 1, то есть, указываем компилятору, что у нас будет добавлен 1 внешний скрипт.
Следующая строка
DEFINE SCRIPT {NAME} AT {LABEL} @
где NAME – имя внешнего скрипта, назовем его, например, MILITIA и чтобы не путаться с метками назовем ее также @MILITIA. Теперь заголовок у нас получился такой:
DEFINE MISSIONS 0
//DEFINE MISSION {ID} 0 AT {LABEL} @
DEFINE EXTERNAL_SCRIPTS 1 // Use -1 in order not to compile AAA script
DEFINE SCRIPT MILITIA AT @MILITIA // 0
Теперь нам нужно добавить сам внешний скрипт. Его можно написать самому, но в целях экономия времени воспользуемся стандартным. Это скрипт вышибалы (External script 39 (BOUNCER)). Я внес в него небольшие правки и переименовал в MILITIA. Добавим его в наш файл после строки
// put your external scripts here.
Сохраняем файл, компилируем и запускаем игру.
Ну что же половина дела сделано, осталось заставить его работать.
Тут нам понадобится стартер внешнего скрипта. Есть разные варианты запуска внешних скриптов. Рассмотрим усе. :)
Для начала нужно сказать, что существует возможность привязать внешний скрипт к нужному вам объекту. Делается это опкодом:
0929: init_external_script_trigger 7 (ARCADE) with_object_model #CJ_COIN_OP_3 priority 100 radius 4.0 type -1
привязываем к объекту #CJ_COIN_OP_3 (игровой автомат space monkey) внешний скрипт видео игры.
Или
0929: init_external_script_trigger 10 (GATES_SCRIPT) with_object_model #GATE_AUTOL priority 100 radius 80.0 type -1
тут, соответственно, к объекту #GATE_AUTOL (решётка левая) привязываем внешний скрипт открытия Ворот Аэропорта.
Так же можно привязать внешний скрипт к интерьеру:
07D3: 'HOUSE' = init_external_script_named_handle 23 (BURG_BRAINS)
или объявить название внешнего скрипта
0884: 'DANCER' = init_external_script_named_handle 52 (DANCER)
замечу, что принцип работы опкодов 07D3 и 0884 мне не известен, а так же не понятно работают они или нет.
Можно привязать внешний скрипт к модели актера
0928: init_external_script_trigger 19 (DEALER) with_actor_model #BMYDRUG priority 100
В оригинальном майне этот опкод идет в паре с
08E8: assign_external_script_handle 'DEALER' to_model #BMYDRUG
мне кажется, что опкод 08E8 привязывает модель актера #BMYDRUG к потоку с именем (названием) ' DEALER ' ( 03A4: name_thread ' DEALER ').
Ну что же для начала воспользуемся опкодом 0928.
Еще раз запустим игру. Подходим к барышне в светлой кепке и темной футболке с номером 31. Наносим ей удар в челюсть (хук справа :) ) и наблюдаем ее реакцию.
Теперь добавим к нашему майну в поток 'MAIN' над строкой end_thread такую запись:
0928: init_external_script_trigger 0 (MILITIA) with_actor_model #BFYST priority 100
08E8: assign_external_script_handle 'MILITIA' to_model #BFYST
компилируем и запускаем игру.
Подходим к барышне в светлой кепке и темной футболке с номером 31. Наносим ей удар в челюсть (хук справа :) ) и наблюдаем ее реакцию. Заметили, что ее реакция изменилась. Итак, наш внешний скрипт запущен и работает. Убедится в этом можно также и по наличию у данной барышни оружия (model #COLT45). Но стоит получить оду звезду розыска, как барышня будет атаковать игрока. А если игрок начнет стрелять (при наличии звез), то барышня будет атаковать игрока с применением оружия.
Немного поясню принцип работы опкода 0928.
Игра генерирует случайных актеров, опкодом 0928 мы указываем игре привязать к модели актера #BFYST наш внешний скрипт. Теперь при каждом создании случайного актера с моделью #BFYST игра применит к этому актеру внешний скрипт.
При таком запуске внешний скрипт будет работать всегда, вне зависимости от того на миссии игрок или нет. Для нашего случая это не смертельно, поскольку он у нас один. Но для оригинального майна существует лимит количества одновременно запущенных внешних скриптов, и превышать его не рекомендуется.
Теперь пришло время рассмотреть вариант запуска внешнего скрипта при выполнении условия (условий). Для этого напишем стартер внешнего скрипта:
:STARTEX
03A4: name_thread 'STARTEX'
00D6: if and
0038: $ONMISSION == 0 // не на миссии
0256: player $PLAYER_CHAR defined
004D: jump_if_false @STARTEX_120
0226: 0@ = actor $PLAYER_ACTOR health
00D6: if
8039: not 0@ == 0
// если здоровье игрока равно 0 то идем на метку завершения внешнего скрипта
004D: jump_if_false @STARTEX_131
0926: $Script_Status = external_script_status 0 (MILITIA)
//определяем запущен внешний скрипт или нет
00D6: if
0038: $Script_Status == 0 // при 0 запускаем внешний скрипт
004D: jump_if_false @STARTEX_120
// если $Script_Status = 1 то соответственно второй раз запускать скрипт не нужно
08A9: load_external_script 0 (MILITIA) // загружаем внешний скрипт
00D6: if
08AB: external_script 0 (MILITIA) loaded //проверяем загружен ли скрипт
004D: jump_if_false @STARTEX_120
0913: run_external_script 0 (MILITIA) // запускаем внешний скрипт
:STARTEX_120
0001: wait 0 ms
0002: jump @STARTEX
:STARTEX_131
090F: end_external_script 0 (MILITIA) // останавливаем работу скрипта
0001: wait 0 ms
0002: jump @STARTEX
ну что же стартер внешнего скрипта работает, но он не подходит нам, поскольку в нашем скрипте нет создания актера, а стало быть, наш внешний скрипт не работает полностью.
Добавим в стартер создание актера актера
:STARTEX
03A4: name_thread 'STARTEX'
00D6: if and
0038: $ONMISSION == 0
0256: player $PLAYER_CHAR defined
004D: jump_if_false @STARTEX_120
0226: 0@ = actor $PLAYER_ACTOR health
00D6: if
8039: not 0@ == 0
004D: jump_if_false @STARTEX_131
0926: $Script_Status = external_script_status 0 (MILITIA)
00D6: if
0038: $Script_Status == 0
004D: jump_if_false @STARTEX_120
08A9: load_external_script 0 (MILITIA)
00D6: if
08AB: external_script 0 (MILITIA) loaded
004D: jump_if_false @STARTEX_120
04C4: store_coords_to 2@ 3@ 4@ from_actor $PLAYER_ACTOR with_offset 1.0 3.0 -0.9
009A: 1@ = create_actor_pedtype 24 model #MALE01 at 2@ 3@ 4@
0913: run_external_script 0 (MILITIA) 1@
:STARTEX_120
0001: wait 0 ms
0002: jump @STARTEX
:STARTEX_131
090F: end_external_script 0 (MILITIA)
0002: jump @STARTEX
Опкодом 04C4: - записываем в переменные 2@ 3@ 4@ координаты относительно актера $PLAYER_ACTOR со смещением 1.0 3.0 -0.9.
Опкодом 009A: - создаем актера с в координатах 2@ 3@ 4@,
модели #MALE01 и #NULL не требуют предварительной загрузки.
0913: run_external_script 0 (MILITIA) 1@ - запускаем внешний скрипт с созданным нами актером. Это запуск внешнего скрипта с параметрами.
:STARTEX_170
090F: end_external_script 0 (MILITIA)
0001: wait 0 ms
0002: jump @STARTEX
Вот Вам второй вариант. Опкодом 061D: - записываем в переменную 6@ последовательность 5@ действий в точке 7@ 8@ 9@. Опкодом 0621: - в переменную 10@ записываем создание актера с типом 6 (полицейский), моделью #NULL с последовательностью действий 6@
Теперь рассмотрим запуск внешнего скрипта с различными параметрами.
Например для запуска GF_MEETING используется такая запись
0913: run_external_script 24 (GF_MEETING) $Girlfriend 10@ 11@ 12@ 13@
где соответственно:
$Girlfriend – актер
10@ - X
11@ - Y
12@ - Z
13@ - угол
а для запуска GF_SEX:
0913: run_external_script 26 (GF_SEX) $Girlfriend 1 3@ 10@ 11@ 12@ 13@
10@, 11@, 12@, 13@ - X, Y, Z, угол
3@ - интерьер
1 – пока не совсем понятно
или такой
0913: run_external_script 26 (GF_SEX) 40@ 41@ 0 2037.651 2723.871 9.8352 0.0702
Я долго не мог понять почему для разных скриптов порядок передачи параметров разный. В одних переменная актера стоит первой
0913: run_external_script 26 (GF_SEX) $Girlfriend 1 3@ 10@ 11@ 12@ 13@
а в других, переменная актера может быть в любом другом месте
0913: run_external_script 1 (PARACHUTE) -1 -10.0 10.0 -5.0 -2.0 10.0 12.0 1 70@
где
70@ - переменная актера.
Теперь могу сказать, что очередность параметров определяется во внешнем скрипте,
(СПАСИБО Seemann’у за помощь :))
Рассмотрим пример передачи параметров
Для этого напишем простейший внешний скрипт
:MILITIA
03A4: name_thread 'MILITIA'
:MILITIA_1
009A: 4@ = create_actor_pedtype 24 model 0@ at 1@ 2@ 3@
:MILITIA_2
wait 0
if
8118: not actor 4@ dead
jf @MILITIA_717
062E: unknown_get_actor 4@ task 1506 status_store_to 5@ // ret 7 if not found
00D6: if
04A4: 5@ == 7 // @ == any
004D: jump_if_false @MILITIA_2
05E2: AS_actor 4@ kill_actor $PLAYER_ACTOR
jump @MILITIA_2
:MILITIA_717
01C2: remove_references_to_actor 4@ // Like turning an actor into a random pedestrian
004E: end_thread
и стартер внешнего скрипта
:STARTEX
03A4: name_thread 'STARTEX'
00D6: if and
0038: $ONMISSION == 0
0256: player $PLAYER_CHAR defined
004D: jump_if_false @STARTEX_159
0226: 10@ = actor $PLAYER_ACTOR health
00D6: if
8039: not 10@ == 0
004D: jump_if_false @STARTEX_170
0926: $Script_Status = external_script_status 0 (MILITIA)
00D6: if
0038: $Script_Status == 0
004D: jump_if_false @STARTEX_159
08A9: load_external_script 0 (MILITIA)
00D6: if
08AB: external_script 0 (MILITIA) loaded
004D: jump_if_false @STARTEX_159
04C4: store_coords_to 1@ 2@ 3@ from_actor $PLAYER_ACTOR with_offset 1.0 3.0 -0.9
0913: run_external_script 0 (MILITIA) #MALE01 2482.72 -1658.6648 13.3372
:STARTEX_159
0001: wait 250 ms
0002: jump @STARTEX
:STARTEX_170
090F: end_external_script 0 (MILITIA)
0001: wait 0 ms
0002: jump @STARTEX
Очередность передачи зависит от очередности локальных переменных во внешнем скрипте.
Мы запускаем внешний скрипт с параметрами
0913: run_external_script 0 (MILITIA) #MALE01 2482.72 -1658.6648 13.3372
где
#MALE01 передается переменной 0@ во внешнем скрипте,
2482.72 - 1@
-1658.6648 - 2@
13.3372 - 3@
:MILITIA_1
009A: 4@ = create_actor_pedtype 24 model 0@ at 1@ 2@ 3@
Готовые примеры качаем c http://yelmi.narod.ru/downloads/prim.rar.
1118 Прочтений • [External Script – что это такое и как с ним работать?] [13.05.2012] [Комментариев: 0]