You are not logged in.
Сначала хотел выпустить это вместе с новой версией Sanny Builder, но со скуки решил сделать это раньше.
Итак,
первый посыл: адреса памяти San Andreas могут меняться также легко через SCM, даже без использования Xieon's MemPatch. Для этого используют массивы для получения доступа к ячейке памяти.
Более подробно об этом написано в статье Меняем игровую память через SCM (San Andreas).
Второй посыл: опкод
06D8: $hTrain = create_train_at 2285.1524 -1257.4997 23.0 type 0 direction 1
Он создает поезд с определенным числом вагонов. Вид поезда, количество вагонов определяется параметром type.
Всего существует 16 типов поездов:
Train Carriage1 Carriage2 Carriage3 Carriage4 Carriage5 ---------------------------------------------------------------------------- 0: #FREIGHT #FREIFLAT #FREIFLAT #FREIFLAT #FREIFLAT x 1,2,4,7,11: #STREAK #STREAKC #STREAKC x x x 3: #FREIGHT #FREIFLAT #FREIFLAT #FREIFLAT x x 5: #STREAK #STREAKC #STREAKC #STREAKC x x 6: #FREIGHT #FREIFLAT #FREIFLAT x x x 8: #TRAM #TRAM x x x x 9,14: #TRAM x x x x x 10: #FREIGHT #FREIFLAT x x x x 12: #FREIGHT #FREIFLAT #FREIFLAT #FREIFLAT #FREIGHT x 13: #FREIGHT #FREIFLAT #FREIFLAT #FREIFLAT #FREIFLAT #FREIFLAT 15: #STREAK x x x x x
Третий посыл: в San Andreas есть адрес 0x8D44F8.
Данный адрес - это начало перечня моделей для каждого типа поезда. Всего определено 16 блоков-перечней (по числу типов), каждый из которых содержит 16 чисел типа DWord, определяющих номер модели поезда и его вагонов.
Например, тип 0 содержит записанные подряд числа: 537, 569, 569, 569, 569, 0, 0, 0, 0, 0 и т.д.
Адреса всех типов:
0x8D44F8 тип 0 0x8D4538 тип 1 0x8D4578 тип 2 0x8D45B8 тип 3 0x8D45F8 тип 4 0x8D4638 тип 5 0x8D4678 тип 6 0x8D46B8 тип 7 0x8D46F8 тип 8 0x8D4738 тип 9 0x8D4778 тип 10 0x8D47B8 тип 11 0x8D47F8 тип 12 0x8D4838 тип 13 0x8D4878 тип 14 0x8D48B8 тип 15
Четвертый посыл: подпрограмма создания поезда читает эти цифры до тех пор, пока не найдет 0.
Анализируя эти посылы, легко догадаться что можно изменить типы поездов, чтобы создавать свои собственные вариации с очень большим числом вагонов (мне удавалось создавать 18 вагонов, хотя я не тестировал это детально).
Данные адреса памяти относятся к типу Data, так что их можно менять прямо в игре.
Собственно, сам код:
for 0@ = -382229 to -382216 wait 0 &0(0@,1i) = #STREAKC end
Этим циклом мы добавили 14 новых вагонов #STREAKC к типу 0 (т.е. к 4-м уже существующим вагонам, хотя ничто не мешало нам перезаписать старые модели и создать абсолютно новый тип).
О принципе получения чисел в цикле можно прочитать здесь. Думаю, в следующем релизе СанниБилдера я добавлю еще примеров.
Теперь можно создавать поезд.
for 0@ = -382229 to -382216 wait 0 &0(0@,1i) = #STREAKC end // type0 changed! // create a train #FREIGHT.Load #FREIFLAT.Load #STREAKC.Load while true if and Model.Available(#FREIGHT) Model.Available(#FREIFLAT) Model.Available(#STREAKC) then Break end wait 0 end // create train with new carriages 06D8: 1@ = create_train_at 2278.1771 -1144.8823 27.5108 type 0 direction 1 Actor.PutAt($PLAYER_ACTOR, 2270.1771, -1144.8823, 27.5108) Model.Destroy(#FREIGHT) Model.Destroy(#FREIFLAT) Model.Destroy(#STREAKC)
Поезд с 18 вагонами создан. Наслаждайтесь .
Скриншот (33 kb)
з.ы. При изменении типов имейте в виду, что при укорачивании поезда (уменьшении числа вагонов в данном типе), необходимо ненужные вагоны перезаписывать в ноль.
Last edited by Seemann (25-11-2006 05:58)
Offline
2Seemann
for 0@ = -382229 to -382216 wait 0 &0(0@,1i) = #STREAKC end
Почему используются отрицательные числа?
в San Andreas есть адрес 0x8D44F8.
Почему же в коде этот адрес не встречается?
Offline
В статье я приводил примеры с использованием подпрограмм
MemoryRead_DWORD, MemoryWrite_DWORD. Они есть в файле SA MemHack в папке examples новой версии.
Эти подпрограммы читают/меняют значения по адресу переданному в переменной 0@. Для этого они преобразуют его с учетом того, как игра работает с массивами (написано в статье). Однако, если подумать, то можно обходиться и без данных процедур, а рассчитать "магическое" число вручную.
Берем адрес первого набора вагонов: 0x8D44F8
Смотрим в подпрограмму:
:MemoryWrite_DWORD 0@ -= 0xA49960 0@ /= 4 008A: &0(0@,1i) = 1@ return
Теперь подставляем вместо 0@ наш адрес и считаем:
0x8D44F8 - 0xA49960 = 0xFFE8AB98 (-1528936)
-1528936 / 4 = -382234
-382234 это будет адрес для первого элемента в записи. В первом типе в этой ячейке записано #FREIGHT (смотри таблицу). Нам первые 4 вагона и сам локомотив не нужно менять (хотя, как я и говорил, ничто не мешает это сделать), поэтому мы прибавляем 5 к данному числу и получаем адрес для 5го вагона: -382229. В оригинальной игре этот адрес содержит 0, поэтому тип 0 создает только 4 вагона. И вот мы начинаем записывать новые значения циклом
-382229 - 5й вагон
-382228 - 6й вагон
и т.д.
Игра, когда парсит массив &0(0@,1i), она это -382229 преобразует в нужный глобальный адрес (см. статью).
Отвечая на твой вопрос, почему используются отрицательные числа: потому что блок вагонов в памяти содержится раньше чем тело main.scm, поэтому и оффсет отрицательный.
Сами адреса обнаруживаются при исследовании кода gta-sa.exe. Многие из них опубликованы на gtaforums.com и gtamodding.com
Почему же в коде этот адрес не встречается?
Если ты имеешь в виду код main.scm, то там он никогда не встретится, по причине написанной выше. Эти адреса можно обнаружить, если в диссассемблированном коде gta-sa.exe исследовать процедуру создания нового поезда.
P.S.
Дамп кода exe со списком всех типов поездов:
.data:008D44F8 TrainTypesModelPool dd 537 ; 0 .data:008D44FC dd 569 .data:008D4500 dd 569 .data:008D4504 dd 569 .data:008D4508 dd 569 .data:008D450C dd 0 .data:008D4510 dd 0 .data:008D4514 dd 0 .data:008D4518 dd 0 .data:008D451C dd 0 .data:008D4520 dd 0 .data:008D4524 dd 0 .data:008D4528 dd 0 .data:008D452C dd 0 .data:008D4530 dd 0 .data:008D4534 dd 0 .data:008D4538 dd 538 ; 1 .data:008D453C dd 570 .data:008D4540 dd 570 .data:008D4544 dd 0 .data:008D4548 dd 0 .data:008D454C dd 0 .data:008D4550 dd 0 .data:008D4554 dd 0 .data:008D4558 dd 0 .data:008D455C dd 0 .data:008D4560 dd 0 .data:008D4564 dd 0 .data:008D4568 dd 0 .data:008D456C dd 0 .data:008D4570 dd 0 .data:008D4574 dd 0 .data:008D4578 dd 538 ; 2 .data:008D457C dd 570 .data:008D4580 dd 570 .data:008D4584 dd 0 .data:008D4588 dd 0 .data:008D458C dd 0 .data:008D4590 dd 0 .data:008D4594 dd 0 .data:008D4598 dd 0 .data:008D459C dd 0 .data:008D45A0 dd 0 .data:008D45A4 dd 0 .data:008D45A8 dd 0 .data:008D45AC dd 0 .data:008D45B0 dd 0 .data:008D45B4 dd 0 .data:008D45B8 dd 537 ; 3 .data:008D45BC dd 569 .data:008D45C0 dd 569 .data:008D45C4 dd 569 .data:008D45C8 dd 0 .data:008D45CC dd 0 .data:008D45D0 dd 0 .data:008D45D4 dd 0 .data:008D45D8 dd 0 .data:008D45DC dd 0 .data:008D45E0 dd 0 .data:008D45E4 dd 0 .data:008D45E8 dd 0 .data:008D45EC dd 0 .data:008D45F0 dd 0 .data:008D45F4 dd 0 .data:008D45F8 dd 538 ; 4 .data:008D45FC dd 570 .data:008D4600 dd 570 .data:008D4604 dd 0 .data:008D4608 dd 0 .data:008D460C dd 0 .data:008D4610 dd 0 .data:008D4614 dd 0 .data:008D4618 dd 0 .data:008D461C dd 0 .data:008D4620 dd 0 .data:008D4624 dd 0 .data:008D4628 dd 0 .data:008D462C dd 0 .data:008D4630 dd 0 .data:008D4634 dd 0 .data:008D4638 dd 538 ; 5 .data:008D463C dd 570 .data:008D4640 dd 570 .data:008D4644 dd 570 .data:008D4648 dd 0 .data:008D464C dd 0 .data:008D4650 dd 0 .data:008D4654 dd 0 .data:008D4658 dd 0 .data:008D465C dd 0 .data:008D4660 dd 0 .data:008D4664 dd 0 .data:008D4668 dd 0 .data:008D466C dd 0 .data:008D4670 dd 0 .data:008D4674 dd 0 .data:008D4678 dd 537 ; 6 .data:008D467C dd 569 .data:008D4680 dd 569 .data:008D4684 dd 0 .data:008D4688 dd 0 .data:008D468C dd 0 .data:008D4690 dd 0 .data:008D4694 dd 0 .data:008D4698 dd 0 .data:008D469C dd 0 .data:008D46A0 dd 0 .data:008D46A4 dd 0 .data:008D46A8 dd 0 .data:008D46AC dd 0 .data:008D46B0 dd 0 .data:008D46B4 dd 0 .data:008D46B8 dd 538 ; 7 .data:008D46BC dd 570 .data:008D46C0 dd 570 .data:008D46C4 dd 0 .data:008D46C8 dd 0 .data:008D46CC dd 0 .data:008D46D0 dd 0 .data:008D46D4 dd 0 .data:008D46D8 dd 0 .data:008D46DC dd 0 .data:008D46E0 dd 0 .data:008D46E4 dd 0 .data:008D46E8 dd 0 .data:008D46EC dd 0 .data:008D46F0 dd 0 .data:008D46F4 dd 0 .data:008D46F8 dd 449 ; 8 .data:008D46FC dd 449 .data:008D4700 dd 0 .data:008D4704 dd 0 .data:008D4708 dd 0 .data:008D470C dd 0 .data:008D4710 dd 0 .data:008D4714 dd 0 .data:008D4718 dd 0 .data:008D471C dd 0 .data:008D4720 dd 0 .data:008D4724 dd 0 .data:008D4728 dd 0 .data:008D472C dd 0 .data:008D4730 dd 0 .data:008D4734 dd 0 .data:008D4738 dd 449 ; 9 .data:008D473C dd 0 .data:008D4740 dd 0 .data:008D4744 dd 0 .data:008D4748 dd 0 .data:008D474C dd 0 .data:008D4750 dd 0 .data:008D4754 dd 0 .data:008D4758 dd 0 .data:008D475C dd 0 .data:008D4760 dd 0 .data:008D4764 dd 0 .data:008D4768 dd 0 .data:008D476C dd 0 .data:008D4770 dd 0 .data:008D4774 dd 0 .data:008D4778 dd 537 ; 10 .data:008D477C dd 569 .data:008D4780 dd 0 .data:008D4784 dd 0 .data:008D4788 dd 0 .data:008D478C dd 0 .data:008D4790 dd 0 .data:008D4794 dd 0 .data:008D4798 dd 0 .data:008D479C dd 0 .data:008D47A0 dd 0 .data:008D47A4 dd 0 .data:008D47A8 dd 0 .data:008D47AC dd 0 .data:008D47B0 dd 0 .data:008D47B4 dd 0 .data:008D47B8 dd 538 ; 11 .data:008D47BC dd 570 .data:008D47C0 dd 570 .data:008D47C4 dd 0 .data:008D47C8 dd 0 .data:008D47CC dd 0 .data:008D47D0 dd 0 .data:008D47D4 dd 0 .data:008D47D8 dd 0 .data:008D47DC dd 0 .data:008D47E0 dd 0 .data:008D47E4 dd 0 .data:008D47E8 dd 0 .data:008D47EC dd 0 .data:008D47F0 dd 0 .data:008D47F4 dd 0 .data:008D47F8 dd 537 ; 12 .data:008D47FC dd 569 .data:008D4800 dd 569 .data:008D4804 dd 569 .data:008D4808 dd 537 .data:008D480C dd 0 .data:008D4810 dd 0 .data:008D4814 dd 0 .data:008D4818 dd 0 .data:008D481C dd 0 .data:008D4820 dd 0 .data:008D4824 dd 0 .data:008D4828 dd 0 .data:008D482C dd 0 .data:008D4830 dd 0 .data:008D4834 dd 0 .data:008D4838 dd 537 ; 13 .data:008D483C dd 569 .data:008D4840 dd 569 .data:008D4844 dd 569 .data:008D4848 dd 569 .data:008D484C dd 569 .data:008D4850 dd 0 .data:008D4854 dd 0 .data:008D4858 dd 0 .data:008D485C dd 0 .data:008D4860 dd 0 .data:008D4864 dd 0 .data:008D4868 dd 0 .data:008D486C dd 0 .data:008D4870 dd 0 .data:008D4874 dd 0 .data:008D4878 dd 449 ; 14 .data:008D487C dd 0 .data:008D4880 dd 0 .data:008D4884 dd 0 .data:008D4888 dd 0 .data:008D488C dd 0 .data:008D4890 dd 0 .data:008D4894 dd 0 .data:008D4898 dd 0 .data:008D489C dd 0 .data:008D48A0 dd 0 .data:008D48A4 dd 0 .data:008D48A8 dd 0 .data:008D48AC dd 0 .data:008D48B0 dd 0 .data:008D48B4 dd 0 .data:008D48B8 dd 538 ; 15 .data:008D48BC dd 0 .data:008D48C0 dd 0 .data:008D48C4 dd 0 .data:008D48C8 dd 0 .data:008D48CC dd 0 .data:008D48D0 dd 0 .data:008D48D4 dd 0 .data:008D48D8 dd 0 .data:008D48DC dd 0 .data:008D48E0 dd 0 .data:008D48E4 dd 0 .data:008D48E8 dd 0 .data:008D48EC dd 0 .data:008D48F0 dd 0 .data:008D48F4 dd 0
Еще, эти адреса не совпадают с реальными адресами в самом gta-sa.exe. Их рассчитывают программы-дизассеблеры, и реальный оффсет можно узнать там же.
Например, таблица вагонов в gta-sa.exe v1.0 хранится по адресу 5054712 (0x4D20F8).
Offline
Данный адрес - это начало перечня моделей для каждого типа поезда. Всего определено 16 блоков-перечней (по числу типов), каждый из которых содержит 16 чисел типа DWord, определяющих номер модели поезда и его вагонов.
Откуда взялись еще два вагона? Можно перезаписать другие типы? Тогда получается что можно создать 16 * 16 = 256 вагонов (теоретически).
Last edited by Sanchez (04-12-2006 08:45)
Offline
Откуда взялись еще два вагона?
Ты имеешь в виду, почему появилось 18 вагонов, если в одном типе максимум 16 (т.е. откуда еще два вагона)?
Ну да, этим циклом я, получается, "залез" в следующий тип и перезаписал его (там в оригинале 538, 570, 570). Игра ведь читает эти номера, пока не найдет 0, вот она после 18 и оставливается.Если ставить больше 18, то игра вылетает, кажется. Почему - пока не знаю.
Можно перезаписать другие типы?
Да. Если, например, работать с адресом 0x8D48B8, то можно перезаписать тип 15 и создавать поезд уже с этим типом
06D8: 1@ = create_train_at 2278.1771 -1144.8823 27.5108 type 15 direction 1
ну и т.д.
Тогда получается что можно создать 16 * 16 = 256 вагонов (теоретически).
Теоретически, да. Но в действительности игра, кажется, имеет определенный лимит на число вагонов, видимо ограничения самой записи для машины (т.е. записи в памяти, где хранятся все данные о конкретной машине).
У меня больше 18 вагонов не получалось - вылазила ошибка. Но повторюсь, детально это я не исследовал.
Last edited by Seemann (05-12-2006 10:14)
Offline
Решил написать скриптик на эту тему:
Теперь в СА ездят поезда реальной длинны и разых вариаций , составы типа "FREIGHT" генерятся рэндомно , тоесть всё как по-настоящему , а не тупо одно и тоже с 2 - 4 вагонами
:RealTrains
wait 0
var
1@ : integer
end
for 0@ = -382217 to -382204 //type 1
wait 0
&0(0@,1i) = #STREAKC
end
0@ = -382202 //type 2
&0(0@,1i) = #STREAK
for 0@ = -382201 to -382188
wait 0
&0(0@,1i) = #STREAKC
end
0@ = -382186 //type 3
&0(0@,1i) = #FREIGHT
for 0@ = -382185 to -382180
wait 0
:ChooseCarrige_t3
0099: 1@ = random_int_in_ranges 568 to 591
if or
1@ == 569
1@ == 590
Jf @ChooseCarrige_t3
&0(0@,1i) = 1@
end
0@ = -382170 //type 4
&0(0@,1i) = #STREAK
for 0@ = -382169 to -382160
wait 0
&0(0@,1i) = #STREAKC
end
0@ = -382138 //type 6
&0(0@,1i) = #FREIGHT
0@ = -382137
&0(0@,1i) = #FREIGHT
for 0@ = -382136 to -382128
wait 0
:ChooseCarrige_t6
0099: 1@ = random_int_in_ranges 568 to 591
if or
1@ == 569
1@ == 590
Jf @ChooseCarrige_t6
&0(0@,1i) = 1@
end
wait 60000
jump @RealTrains
Offline
При старой гтасе хотелось длинных поездов,но теперь у многих стоят электрички и очень неудобно получаются сборные поезда,а ехе в этом моде на них не влияет.
Поезда,лимит точек путей.<:Не знаете почему поезда складываются на путях если они длиннее оригинальных?,число точек подсчитано.Как добавить больше возможных остановок поезду скриптом?,если по траксу то игра вылетает.Есть ли скрипт посадки пассажиров для 2,3,4 путей?Как новых путей добавить 5,6,7,.,9,99. >.
Last edited by sitihlaml (23-10-2007 08:43)
Offline
2sitihlaml:
Для вопросов есть отдельный форум
Offline
Теперь по городу ездит такая хрень - это не тот поезд, что создаётся скриптом. Я думаю, надо вернуть какие-то значения в памяти.
Last edited by ~AquaZ~ (23-03-2010 16:20)
Offline
(в предыдущий пост не приаттачилось)
Offline
Правильно, нужно вернуть старые значения. В своём моде Новый алгоритм движения поездов я пользовался этой технологией - перед созданием поезда N типа я сохранял значения ID-номеров моделей вагонов поезда N+1 типа в переменных, затем перезаписывал адреса и создавал 18-вагонный поезд. После этого я восстанавливал прежние значения адресов.
Last edited by Den_spb (23-03-2010 18:20)
Offline
Я вот не сильно понял, вроде типу 0 принадлежат значения от -382234 до -382219, а цикл перезаписывает часть типа 1...
_________________________
Всё, дошло, прочитал внимательнее.
_________________________
Почему больше вагонов не получается? Я думал можно перезаписать до -381980!
Last edited by ~AquaZ~ (27-03-2010 08:59)
Offline
Чтобы создать длинный поезд, можно сцепить два (или больше - я не проверял) состава в один. Делается так:
{$CLEO} 0@ = -382106 // Переформируем тип поезда 8. Теперь он состоит из 14 вагонов #TRAM &0(0@,1i) = 449 // vagon 0 0@ = -382105 &0(0@,1i) = 449 // vagon 1 0@ = -382104 &0(0@,1i) = 449 // vagon 2 0@ = -382103 &0(0@,1i) = 449 // vagon 3 0@ = -382102 &0(0@,1i) = 449 // vagon 4 0@ = -382101 &0(0@,1i) = 449 // vagon 5 0@ = -382100 &0(0@,1i) = 449 // vagon 6 0@ = -382099 &0(0@,1i) = 449 // vagon 7 0@ = -382098 &0(0@,1i) = 449 // vagon 8 0@ = -382097 &0(0@,1i) = 449 // vagon 9 0@ = -382096 &0(0@,1i) = 449 // vagon 10 0@ = -382095 &0(0@,1i) = 449 // vagon 11 0@ = -382094 &0(0@,1i) = 449 // vagon 12 0@ = -382093 &0(0@,1i) = 449 // vagon 13 0@ = -382092 model.Load(449) repeat wait 0 until model.Available(449) 06D8: 0@ = create_train_at -2007.4158 219.1326 27.5953 type 8 direction 1 // создаём первый поезд 06D8: 1@ = create_train_at -2507.4158 219.1326 27.5953 type 8 direction 1 // создаём второй поезд model.Destroy(449) 06DE: 7@ = get_train 0@ last_carriage_handle // получаем хэндл последнего вагона первого поезда 0A97: 2@ = car 7@ struct 0085: 3@ = 2@ // (int) 2@ += 0x5D4 078A: 6@ = get_train 1@ carriage 0 handle 078A: 1@ = get_train 1@ carriage 1 handle // получаем хэндл первого вагона второго поезда car.Destroy(6@) // удаляем нулевой вагон второго поезда 0A97: 4@ = car 1@ struct 0085: 5@ = 4@ // (int) 4@ += 0x5D0 0A8C: write_memory 2@ size 4 value 5@ virtual_protect 0 // сцепляем два поезда в один 0A8C: write_memory 4@ size 4 value 3@ virtual_protect 0 0A93:
Без удаления нулевого вагона второго поезда сцепить составы у меня не получилось. При движении поезда на большой скорости, первый вагон второго поезда может немного отставать от последнего вагона первого поезда.
Пример - поезд из 27 вагонов: http://www.youtube.com/watch?v=o6e6Ai4K564
Offline
@Den_spb -
Делается так:
Попробовал, аццкая жесть получилась:D Весь этот состав у меня ехать перестал в итоге.
Кстати, можно как то через cleo вылечить такой глюк:
У меня этот трамвай ездит не по рельсам, а по воздуху, я хз почему так, но надо его опустить обратно. Остальные поезда норм, в том числе и этот трамвай во время миссии Test Drive.
Last edited by Sergey81 (30-12-2010 14:53)
Offline
Пример - поезд из 27 вагонов
Спасибо!
Тормозит игра... Как у меня!
Offline
Один раз второй поезд тупо пропал. В другой раз второй отделился и поехал в другую сторону... Надо что-то делать.
Offline