На сайте онлайн (человек): 78 
|  |
|
 | |
Изменение параметров тренировки десанта и абордажа с помощью HEX-редак... |  |
|  |
 | |
|
Terran Conflict (X3TC) / Форум / Скрипты и моды для X3 Terran Conflict / Гайд-Парк
|
Изменение параметров тренировки десанта и абордажа с помощью HEX-редактора. Модификация obj-файла.
Инструментарий: 1. Дизассемблер obj-файлов. 2. X3 Editor 2. Качайте версию поновее - не ошибетесь. 3. Любой HEX-редактор. HxD, UltraEdit, Hiew - в общем любой.
Необходимые знания: 1. X3Editor - нужно! 2. Программирование - не больно то и нужно , но если есть базовые познания в ассемблере, будет проще разобраться.
Причина возникновения данного урока: Весьма частый и весьма справедливый вопрос: почему десант тренируется дольше, чем длится сюжетка + все побочные + миссии корпораций + "та када ж они там натренируются?" + "надоело уже ждать" + "та я уже на хаб натаскал всего, а они еще трениру...". В общем, надеюсь, понятно.
Сразу оговорюсь, что этот урок ни в коем случае не пособие по читерству. Если Вы считаете, что этого делать не нужно, что можно воспользоваться чит меню, что так будет неинтересно играть, что читерство хуже чем быть депутатом - то, собсно, какого черта Вы это тогда читаете?
Дополнительно добавлю, что здесь рассматривается как-раз "грубая" модификация obj (я бы даже сказал "взлом"), а не через дизассемблер - ассемблер.
Урок будет делаться на чистой Х3ТС v 3.2.
Итак, подготовка.
1. Выдираем X3Editor-ом файл x3story.obj, который находится в 13.cat (справедливо для чистой Х3ТС 3.2) 2. Создаем где вам удобно папку и называем ее, к примеру, "asm". В этой папке мы будем держать исходный + декомпилированный x3story.obj. 3. Помещаем в вашу папку "asm" все файлы из архива с декомпилятором, в эту же папку закидываем свежевыдранный x3story.obj 4. В папке "asm" находим файл "dobj.exe", жмем правой мышей и выбираем пункт "создать ярлык". Потом выбираем только что созданный ярлык, жмем его правой мышей, выбираем "свойства" и в самом конце дописываем x3story.obj после пробела (!!!) 5. Запускаем сей ярлык. После непродолжительного черного окошка с бегущими буквами/цифрами видим в папке "asm" кучу файлов. Нас интересует один - "x3story.out" - в этом файле приведен листинг на ассемблере, а слева вид в машинном коде, самое то, что доктор прописал.
Собственно, подготовка закончена, теперь немного матчасти.
Прежде всего следует прочитать этот материал, чтобы хоть немного понять, почему мы будем менять те или иные коды в нашем подопытном x3story.obj.
Сразу выделю основные данные из вышеприведенной статьи, а именно: 1. Время (одного быстрого курса)
| Продолжительность (в минутах) быстрого обучения по одной дисциплине составляет: 5 + (<текущий уровень> / 5 + 1)2 |
| |
2. Бабос (за один быстрый курс)
| Стоимость быстрого обучения по одной дисциплине составляет: 5000 + 2000 x (<текущий уровень> / 5 + 1) |
| |
По логике вещей, чем выше уже натренированный уровень, тем дольше/дороже будет тот самый быстрый курс.
Давайте вычислим.
Задача: имеем двух десов, дес1 и дес2. Необходимо рассчитать время/сумму быстрого обучения хакерству при следующих условиях: дес1 - текущее хакерство = 5 дес2 - текущее хакерство = 87
Ответ: 1.а) время быстрого курса для дес1 = 5 + ( 5 / 5 + 1) * (5 / 5 + 1) = 6 минут, ясен пень, игровых 1.б) бабос быстрого курса для дес1 = 5т + 2т * (5 / 5 + 1) = 5т + 2т * 2 = 9т, что, в общем, недорого 2.а) время быстрого курса для дес2 = 5 + ( 87 / 5 + 1) * (87 / 5 + 1) = 5 + 18,4 * 18,4 = 343,56 минут, то есть примерно 6 часов 2.б) бабос быстрого курса для дес2 = 5т + 2т * (87 / 5 + 1) = 5т + 2т * 18,4 = 41800, что, в общем, опять недорого
Немного отвлекусь. Для более-менее успешного захвата М6 вам необходимы как минимум 8 хорошо прокачанных десов, минимум 2 из которых должны быть "мега-механикусами", 2 - "кулхацкерами", остальные какие-никакие "технари", иначе они развялят жертву так и не добравшись до заветного статуса "взлом ядра". Предположим вы долго играете и поэтому богаче, чем генеральный директор "Плутарх майнинг". Потратиться на обучение вы себе позволить можете. Но есть одно но - покупая на станции хакера, вы замечаете, что он не драчун, так сказать. То же с механиками и технарями. Поэтому, когда вся эта разнорасовая банда ломится по кораблю, логика программы расчитана так, чтобы на каждой палубе дохли слабейшие по характеристикам боя. Справедливо, ничего не попишешь. А кто у нас слабейшие по бою? Как раз они, кулхацкеры. У тренированных hacker-only шанс добраться до последней палубы катастрофически приближается к нулю с каждой палубой, а там то они как раз и нужны. Итог: для сколачивания команды вы должны найти 8 нихрена себе бойцов, 2 из которых потом натренируете на хак, 2 других на пробой корпуса (механики), а остальных натаскаете на технику.
Приведу цитату из статьи про захват ракетного фрегата, которая описывает создание деса "на продажу":
| Создание десантника: Создается десантник с навыком боя от 1 до 40 и остальными навыками от 1 до 15. С вероятностью 20% на этом процесс создания заканчивается. В остальных 80% случаев случайно выбирается один навык и он повышается на 20-49 единиц.
Последствия: У хороших бойцов все прочие навыки не дотягивают даже до одной звезды. Максимальный боевой уровень десанта, доступного в продаже - 89 (пять звезд). Максимальный уровень небоевых навыков - 64 (три звезды). Максимальный боевой уровень хорошего хакера, механика или инженера - 40 (две звезды). |
| |
Итого, покупая деса-бойца, вы получаете никакого хакера/технаря/механика, с небоевым навыком максимум 15. Предоставлю вам самостоятельно посчитать, сколько по времени займет тренировка от 15 до заветных 98-100 одного деса.
Итак, с матчастью закончили, "начинаем хак системы".
Для целей урока я установил себе x3_tc_cheats и начал новую "свою игру" (без сюжета). Потом я через чит меню создал себе корабль TM, установил в него биосканер, добавил бабоса, открыл все сектора и стыковался с военным аванпостом в секторе "Черное солнце". Да простят меня все "античитеры", но мне хочется объяснить как это сделать, но не хочется летать туда-сюда.
В списке "продажных" десов был некий Элисон Дана с такими характеристиками: бой - 65, техника - 5, механика - 6, хакерство - 13. Я его купил нанял и решил замерить сколько времени займет тренировка одного подробного курса по хакерству.
Сохранив игру прямо перед тренировкой, я запустил тренировку Элисона на хакерство - подробно (95000 кредитов)
Тренировка начата в "00:11:58" по игровому времени. Я не стал дожидаться окончания тренировки, а остановил замеры на 20% тренировки. Игровое время было "01:24:10". Итого разница примерно 1 час 12 минут. Если умножить на 5 - то на полную тренировку нужно было бы почти 6 часов игрового времени. При этом дес добрался бы до уровня хакерства от 38 до 58. Последующая тренировка заняла бы еще большее время. Нас это не устраивает.
В полученном нами раньше x3story.out находится двойной листинг почти всей логики Х3ТС. За время/стоимость подготовки десанта отвечает класс "SHIP_SPEAKER", а именно два метода этого класса "GetNextTrainingCost" и "GetNextTrainingDuration". За сам процесс подготовки, отвечеат метод "RunTraining", класса "STATION". Этот метод вызывается из метода "StartTraining" того-же класса.
Давайте сначала разберем код метода "RunTraining".
Открываем x3story.out любым редактором, к примеру, блокнотом и ищем в нем следующий текст "RunTraining" до тех пор, пока не найдем следующий код: Листинг 1.
| Код:- ;
- ; === RunTraining ===============================================
- ; function STATION.RunTraining();
- ;
- | STATION.RunTraining:
- 0008B44A: 6E 0006 | 0 enter 0, 6
- 0008B44D: 0F 0027 | 0 L0008B44D: read STATION.var_2016_29 ; [39d ; 27h]
- 0008B450: 34 0008B469 | 1 if SP[0]=0 then jump L0008B469
- 0008B455: 0F 0027 | 0 read STATION.var_2016_29 ; [39d ; 27h]
- 0008B458: 02 | 1 push 1
- 0008B459: 82 0000057A | 2 callasm SE_ArraySize
- 0008B45E: 34 0008B469 | 1 if SP[0]=0 then jump L0008B469
- 0008B463: 02 | 0 push 1
- 0008B464: 32 0008B46A | 1 jump L0008B46A
- 0008B469: 01 | 0 L0008B469: push 0
- 0008B46A: 34 0008B4F8 | 1 L0008B46A: if SP[0]=0 then jump L0008B4F8
- [color=yellow]0008B46F: 06 03E8 | 0 pushw 1000d ; 03E8h[/color]
- 0008B472: 02 | 1 push 1
- [color=yellow]0008B473: 82 00002561 | 2 callasm TI_Delay[/color]
- 0008B478: 24 | 1 pop
- 0008B479: 01 | 0 push 0
- 0008B47A: 0F 0027 | 1 read STATION.var_2016_29 ; [39d ; 27h]
- 0008B47D: 02 | 2 push 1
- 0008B47E: 82 0000057A | 3 callasm SE_ArraySize
- 0008B483: 02 | 2 push 1
- 0008B484: 4B | 3 sub SP[0],SP[1]
|
| |
Процесс начала и хода тренировки выглядит так: 1. При начале тренировки система запрашивает сколько времени "GetNextTrainingDuration" и бабоса "GetNextTrainigCost" необходимо для повышения выбранных навыка(-ов) текущего деса. 2. Если у игрока хватает кредитов, бабос снимается со счета, данные о времени заносятся в специальный внутренний массив, который потом использует функция "RunTraining" 3. Функция "RunTraining" ежесекундно отнимает от оставшегося на тренировку времени по секунде и, когда оставшихся на тренировку секунд = 0, передает управление на метод "FinishedTraining", который увеличивает тренируемый навык на 5 + SE_Random(5) и маячит игроку о том, что "тут чувак, накачался, ждет тебя там-то"
Как мы можем это использовать: Вариант 1. "Заставить" систему чаще отнимать одну секунду. Обратите внимание на две желтых строчки кода, которые я выделил. Переводя на понятный нам, гуманоидам, язык - в первой желтой строчке устанавливается время задержки в миллисекундах, во второй желтой строчке, вызывается сама задержка (TI_Delay), после которой уже и идет отнимание секунд и прочая программистская дрянь, которая нам сейчес не суть важна.
Давайте вместо 1000d сделаем задержку в 0001d. По логике, метод "RunTraining" будет задерживаться на тысячу раз меньше, соответственно система будет вызывать его в тысячу раз чаще, что приведет к тысячекратному увеличению скорости тренировки.
Приступим. Внутри папки, в которую вы установили игру, есть папка "L". Если нет создайте ее. Внутрь этой папки необходимо поместить файл x3story.obj, который раньше мы выдрали из 13.cat. Теперь откройте этот файл любым HEX-редактором. Я использовал HxD. Теперь вернемся к листингу программы. В первой желтой строчке указано 16-ричное смещение от начала файла, в котором находится необходимый нам машинный код, а именно помещение в вершину стека значения задержки - 1000. В НЕХ-редакторе нам нужно перейти/прокрутить до тех пор, пока мы не встретим данный адрес. В HxD я нажал CTRL+G и ввел туда адрес 0008B46F. Сразу оговорюсь, что декомпилятор не всегда точно определяет смещение внутри obj-файла. Но именно здесь нам поможет то, что в файле x3story.out слева указаны машинные коды необходимых нам команд. Поэтому мы начинаем искать ту последовательность цифр, которая указана сразу после адреса, а именно 06 03E8. Я обнаружил эти цифры чуть дальше по ходу, в адресе 0008B483. Если вы не хотите искать или не можете найти, тогда просто переходите в НЕХ-редакторе по найденному мной адресу. Теперь мы должны заменить 06 03E8 на 06 0001 и сохранить изменения.
Запускаем Х3ТС и повторно пытаемся тренировать того-же Элисона Дану. Тренировка начата "00:11:53", закончена в "00:16:26" - итог примерно 4,5 минуты. Проверяем данные Элисона - все ОК, хакерство 53.
Подведем итоговую черту под Вариантом №1. Плюсы: 1. Мы добились увеличения скорости тренировки. А теперь минусы: тут поболее будет 1. Мы не уменьшили время тренировки, а увеличили частоту вызова функции 2. Исходя из п.1 мы "нагрузили" систему, заставив ее 1000 раз в секунду исполнять то, что расчитано на 1 раз в секунду 3. Если у вас установлен мод, который показывает время тренировки, то вы обнаружите, что время идет не посекудно, а скачками по несколько секунд 4. СУВ (SETA) может слабо влиять на время тренировки, т.к. компьютер просто не будет успевать выделять необходимые 1000 вызовов процессорного времени на нашу функцию "RunTraining" 5. Мы не добились снижения стоимости тренировки
Результат: данный вариант можно использовать как "ленивый", или когда мы хотим увеличить скорость например в 2-3 раза, то есть подставлять вместо 1000, 500 или к, примеру 300. При всем при этом нам не важно, что моды типа "время тренировки десанта" будут врать.
Вариант 2. Действительно уменьшить время/стоимость тренировки одного быстрого курса.
Прежде всего, в папку "L" внутри папки с игрой заново скопируем исходный x3story.obj, так как там находится "исковерканный" вариантом 1.
Давайте снова вернемся к вышеприведенным цитатам:
| Продолжительность (в минутах) быстрого обучения по одной дисциплине составляет: 5 + (<текущий уровень> / 5 + 1)2 Стоимость быстрого обучения по одной дисциплине составляет: 5000 + 2000 x (<текущий уровень> / 5 + 1) |
| |
Сначала попробуем "выделить" числа, которые, скажем так, "константны".
В формуле расчета времени - это исходные 5 минут, делитель на 5 и, как видим, возведение в квадрат. Заменим исходные "5 + (<..." на "0 + (<...". Что это нам дает? Возьмем навык 87 и рассчитаем быстрый курс по навыку: 0 + (87 / 5 + 1) * (87 / 5 + 1) = (17,4 + 1) * (17,4 + 1) = 338,56 = 5 часов 64 минуты. М-да. Не фонтан! Теперь давайте заменим делитель (т.е. "<текущий уровень> / 5") Возьмем навык 87 и рассчитаем быстрый курс по навыку при делителе 50: 5 + (87 / 50 + 1) * (87 / 50 + 1) = 5 + 2,74 * 2,74 = примерно 13 минут. Вот это уже похоже на "оно". Если же мы еще и возведение в квадрат заменим сложением, тогда вообще десант будет тренироваться за считанные минуты.
То же с денюжкой: 5000 + 2000 * (<текущий уровень> / 5 + 1) Например заменив "2000 * (<..." на "500 * (<..." мы заметим резкое снижение стоимости тренировки. Причем это будет заметно на более высоких уровнях тренировки.
Давайте перейдем к делу.
Сначала найдем в нашем декомпилированном x3sotry.out необходимые функции. Как мы уже выяснили это функции "GetNextTrainingCost" и "GetNextTrainingDuration"
Листинг 2. (GetNextTrainingCost)
| Код:- ;
- ; === GetNextTrainingCost =======================================
- ; function SHIP_SPEAKER.GetNextTrainingCost(arg1, arg2);
- ;
- | SHIP_SPEAKER.GetNextTrainingCost:
- 000C628B: 6E 0008 | 0 enter 2, 8
- 000C628E: 01 | 0 push 0
- ... тут коды-коды-коды и вот то, что нам нужно...
- 000C6312: 0D 0002 | 3 L000C6312: push SP[1] ; loc2
- 000C6315: 05 05 | 4 pushb 5
- 000C6317: 51 | 5 div SP[0],SP[1]
- 000C6318: 02 | 4 push 1
- 000C6319: 46 | 5 add SP[0],SP[1]
- 000C631A: 0D 0004 | 4 push SP[3] ; loc1
- [color=yellow]000C631D: 06 1388 | 5 pushw 5000d ; 1388h[/color]
- 000C6320: 0D 0003 | 6 push SP[2] ; loc4
- [color=yellow]000C6323: 06 07D0 | 7 pushw 2000d ; 07D0h[/color]
- 000C6326: 50 | 8 mul SP[0],SP[1]
- 000C6327: 46 | 7 add SP[0],SP[1]
- 000C6328: 46 | 6 add SP[0],SP[1]
- 000C6329: 14 0005 | 5 mov SP[4],SP[0] ; loc1
- 000C632C: 24 | 5 pop
- 000C632D: 0D 0003 | 4 push SP[2] ; loc2
|
| |
В листинге 2 мы снова обнаруживаем наши "константные числа", поменяв которые мы сможем уменьшить стоимость тренировки. Итак, по накатанной, в НЕХ-редакторе открываем x3stroy.obj, переходим по адресу 000C6323, чуть "дальше" ищем 06 07D0 и меняем на 06 01F4, что в "переводе" на ассемблер будет значить "pushw 500d ; 01F4h".
Запускаем Х3ТС, пытаемся тренировать нашего многострадального Элисона Дану - стоимость вместо 95000 равна 42500.
В итог, мы безболезненно для системы уменьшили стоимость тренировки.
Сразу пойдем дальше, ведь еще необходимо уменьшить и время тренировки. Находим функцию "GetNextTrainingDuration".
Листинг 3. (GetNextTrainingDuration)
| Код:- ;
- ; === GetNextTrainingDuration ===================================
- ; function SHIP_SPEAKER.GetNextTrainingDuration(arg1, arg2);
- ;
- | SHIP_SPEAKER.GetNextTrainingDuration:
- 000C634B: 6E 0008 | 0 enter 2, 8
- 000C634E: 01 | 0 push 0
- ... коды-коды-коды, стоп, кажется нашли...
- 000C63D2: 0D 0002 | 3 L000C63D2: push SP[1] ; loc2
- 000C63D5: 05 05 | 4 pushb 5 ; ДЕЛИТЕЛЬ
- 000C63D7: 51 | 5 div SP[0],SP[1]
- 000C63D8: 02 | 4 push 1
- 000C63D9: 46 | 5 add SP[0],SP[1]
- 000C63DA: 0D 0004 | 4 push SP[3] ; loc1
- 000C63DD: 06 012C | 5 pushw 300d ; 012Ch исходные 5 минут * 60 сек
- 000C63E0: 0D 0003 | 6 push SP[2] ; loc4
- 000C63E3: 0D 0004 | 7 push SP[3] ; loc4
- 000C63E6: 50 | 8 mul SP[0],SP[1] ; возведение в квадрат
- 000C63E7: 05 3C | 7 pushb 60d ; 3Ch
- 000C63E9: 50 | 8 mul SP[0],SP[1] ; умножение результата в минутах на 60 сек
- 000C63EA: 46 | 7 add SP[0],SP[1]
- 000C63EB: 46 | 6 add SP[0],SP[1]
- 000C63EC: 14 0005 | 5 mov SP[4],SP[0] ; loc1
- 000C63EF: 24 | 5 pop
|
| |
Ну, здесь я уже не буду в подробностях расписывать как заменить. Возможностей - куча: Если по адресу 000C63D5 (не забудьте, что в НЕХ-е искать надо чуть "дальше") 000C63D5: 05 05 | 4 pushb 5 ; заменить 0505 на 0532 - получим делитель не 5 а 50 000C63D5: 05 32 | 4 pushb 50d ; 32h
Если по адресу 000C63DD 000C63DD: 06 012C | 5 pushw 300d ; 012Ch ; // исходные 5 минут * 60 сек заменить 06012C на 060000 - исходные 5 минут станут 0 000C63DD: 06 0000 | 5 pushw 0d ; 0000h ; // исходные 5 минут * 60 сек
Если по адресу 000C63E6 000C63E6: 50 | 8 mul SP[0],SP[1] ; возведение в квадрат заменить 50 на 46 - вместо квадрата получим просто сложение двух результатов 000C63E6: 46 | 8 add SP[0],SP[1] ; сложение!!!
Ну и на закуску: Если по адресу 000C63E7 000C63E7: 05 3C | 7 pushb 60d ; 3Ch заменить 053C на 0501 - вместо (Х минут * 60 сек) получим (Х минут * 1 сек.) 000C63E7: 05 01 | 7 pushb 1
Фух, устал! Ладно, вроде изменить время/стоимость тренировок мы умеем. А что же по поводу абордажа. Вернее по поводу уничтожения оборудования. Давайте рассмотрим такую ситуацию с абордажем: Летит себе такой не спеша М1. А куда ему торопиться? У него 2ГДж щитов пара-тройка, десятки больших пух, да и сам по себе он не какой-то там М5. Мы его закидали ракетами, сняли щиты, позагоняли на него кучу десантников, которые "Есть! Входим в корабль... Пошли!", "Смотреть, куда стреляете", "Санитар! Здесь раненый!" и "Мы в центре управления...". Наконец слышим заветное "Передача управления кораблем завершена". Классно, короче. И вот, после взлома компьютера, начинается самое, я бы сказал, фееричное. Исчезает практически все! Куда оно все девается? Если, по замыслу разрабов, десы воруют, тогда почему не слышно фраз типа "Ребята, тащите эту фотонку на капсулу, столкнем на торговой станции". Или, может, десы все переломали. Ну, например, 8 выживших десантников от счастья забухали и давай пинать "берцами" щиты. Огромные такие, которые могут держать мощные выстрелы фотонок. А щиты же не приспособлены, чтобы их ногами пинали. Вот и ломаются. Так десам этого мало, они еще и пухи все давай пинать. А потом идет пятизвездочный Мули Ха по второй палубе, а там к корме прыжковый двигатель прикручен. И рядом пара тысяч DURACELL сложена. Он такой, типа "А эт чё за ...?!?!". И давай это все добро пинать "берцами". В общем не понравилась мне эта задумка разрабов. Конечно, кто-нибудь скажет, что так интереснее, надо сначала захватить, потом по новой оснастить, и т.д. Но, не нравится мне такая задумка и все. Хоть ты трескни! Решил я это дело подправить, заодно и вам расскажу как уменьшить потери оборудования от неумеренного злоупотребления десантников.
Итак, вернемся к нашему файлу x3story.out. В нем описан класс "SHIP", у которого есть метод "DowngradeTakeOver". Метод этот вызывается в двух случаях: когда вражеский пилот сливается с мелкого корабля и когда наши развеселые десы захватывают бигшип. А в самом методе описывается алгоритм исчезновения оборудования. Давайте взглянем на листинг: Листинг 4.
| Код:- ;
- ; === DowngradeTakeOver =========================================
- ; function SHIP.DowngradeTakeOver();
- ;
- | SHIP.DowngradeTakeOver:
- 000BB93C: 6E 0009 | 0 enter 0, 9
- 000BB93F: 06 03E8 | 0 pushw 1000d ; 03E8h
- 000BB942: 02 | 1 push 1
- 000BB943: 82 00002561 | 2 callasm TI_Delay
- 000BB948: 24 | 1 pop
- 000BB949: 01 | 0 push 0
- 000BB94A: 01 | 1 push 0
- 000BB94B: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BB94E: 24 | 2 pop
- 000BB94F: 0D 0001 | 1 L000BB94F: push SP[0] ; loc1
- 000BB952: 05 08 | 2 pushb 8
- 000BB954: 02 | 3 push 1
- 000BB955: 82 000002E2 | 4 callasm SA_GetNumSubTypes
- 000BB95A: 5C | 3 if SP[0]<=SP[1] then push 0 else push 1
- 000BB95B: 34 000BB9CE | 2 if SP[0]=0 then jump L000BB9CE
- 000BB960: 32 000BB973 | 1 jump L000BB973
- 000BB965: 0D 0001 | 1 L000BB965: push SP[0] ; loc1
- 000BB968: 02 | 2 push 1
- 000BB969: 46 | 3 add SP[0],SP[1]
- 000BB96A: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BB96D: 24 | 2 pop
- 000BB96E: 32 000BB94F | 1 jump L000BB94F
- 000BB973: 01 | 1 L000BB973: push 0
- 000BB974: 0D 0002 | 2 push SP[1] ; loc1
- 000BB977: 05 08 | 3 pushb 8
- 000BB979: 03 | 4 push 2
- 000BB97A: 88 000A8CB9 | 5 call88 SHIP.GetWareTypeCount
- 000BB97F: 14 0002 | 3 mov SP[1],SP[0] ; loc2
- 000BB982: 34 000BB9C8 | 3 if SP[0]=0 then jump L000BB9C8
- 000BB987: 0F 000C | 2 read SHIP.var_2004_2 ; [12d ; 0Ch]
- 000BB98A: 05 07 | 3 pushb 7
- 000BB98C: 03 | 4 push 2
- 000BB98D: 82 00000E2C | 5 callasm SA_GetTypeDefaultRace
- 000BB992: 05 07 | 3 pushb 7
- 000BB994: 5B | 4 if SP[0]<>SP[1] then push 0 else push 1
- 000BB995: 0D 0001 | 3 push SP[0] ; loc3
- 000BB998: 34 000BB9A4 | 4 if SP[0]=0 then jump L000BB9A4
- [color=yellow]000BB99D: 05 32 | 3 pushb 50d ; 32h[/color]
- 000BB99F: 32 000BB9A6 | 4 jump L000BB9A6
- [color=yellow]000BB9A4: 05 5A | 3 L000BB9A4: pushb 90d ; 5Ah[/color]
- 000BB9A6: 05 64 | 4 L000BB9A6: pushb 100d ; 64h
- 000BB9A8: 02 | 5 push 1
- 000BB9A9: 82 000002C4 | 6 callasm SE_Random
- 000BB9AE: 0D 0002 | 5 push SP[1] ; loc4
- 000BB9B1: 5C | 6 if SP[0]<=SP[1] then push 0 else push 1
- 000BB9B2: 34 000BB9C5 | 5 if SP[0]=0 then jump L000BB9C5
- 000BB9B7: 0D 0003 | 4 push SP[2] ; loc2
- 000BB9BA: 65 | 5 neg SP[0]
- 000BB9BB: 0D 0005 | 5 push SP[4] ; loc1
- 000BB9BE: 03 | 6 push 2
- 000BB9BF: 88 000A4A76 | 7 call88 SHIP.AddLaser
- 000BB9C4: 24 | 5 pop
- 000BB9C5: 23 0002 | 4 L000BB9C5: popx 2
- 000BB9C8: 24 | 2 L000BB9C8: pop
- 000BB9C9: 32 000BB965 | 1 jump L000BB965
- 000BB9CE: 01 | 1 L000BB9CE: push 0
- 000BB9CF: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BB9D2: 24 | 2 pop
- 000BB9D3: 0D 0001 | 1 L000BB9D3: push SP[0] ; loc1
- 000BB9D6: 05 09 | 2 pushb 9
- 000BB9D8: 02 | 3 push 1
- 000BB9D9: 82 000002E2 | 4 callasm SA_GetNumSubTypes
- 000BB9DE: 5C | 3 if SP[0]<=SP[1] then push 0 else push 1
- 000BB9DF: 34 000BBA2F | 2 if SP[0]=0 then jump L000BBA2F
- 000BB9E4: 32 000BB9F7 | 1 jump L000BB9F7
- 000BB9E9: 0D 0001 | 1 L000BB9E9: push SP[0] ; loc1
- 000BB9EC: 02 | 2 push 1
- 000BB9ED: 46 | 3 add SP[0],SP[1]
- 000BB9EE: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BB9F1: 24 | 2 pop
- 000BB9F2: 32 000BB9D3 | 1 jump L000BB9D3
- 000BB9F7: 01 | 1 L000BB9F7: push 0
- 000BB9F8: 0D 0002 | 2 push SP[1] ; loc1
- 000BB9FB: 05 09 | 3 pushb 9
- 000BB9FD: 03 | 4 push 2
- 000BB9FE: 88 000A8CB9 | 5 call88 SHIP.GetWareTypeCount
- 000BBA03: 14 0002 | 3 mov SP[1],SP[0] ; loc2
- 000BBA06: 34 000BBA29 | 3 if SP[0]=0 then jump L000BBA29
- 000BBA0B: 05 64 | 2 pushb 100d ; 64h
- 000BBA0D: 02 | 3 push 1
- 000BBA0E: 82 000002C4 | 4 callasm SE_Random
- [color=yellow]000BBA13: 05 5A | 3 pushb 90d ; 5Ah[/color]
- 000BBA15: 5C | 4 if SP[0]<=SP[1] then push 0 else push 1
- 000BBA16: 34 000BBA29 | 3 if SP[0]=0 then jump L000BBA29
- 000BBA1B: 0D 0001 | 2 push SP[0] ; loc2
- 000BBA1E: 65 | 3 neg SP[0]
- 000BBA1F: 0D 0003 | 3 push SP[2] ; loc1
- 000BBA22: 03 | 4 push 2
- 000BBA23: 88 000A48AC | 5 call88 SHIP.AddShield
- 000BBA28: 24 | 3 pop
- 000BBA29: 24 | 2 L000BBA29: pop
- 000BBA2A: 32 000BB9E9 | 1 jump L000BB9E9
- 000BBA2F: 01 | 1 L000BBA2F: push 0
- 000BBA30: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BBA33: 24 | 2 pop
- 000BBA34: 0D 0001 | 1 L000BBA34: push SP[0] ; loc1
- 000BBA37: 05 0A | 2 pushb 10d ; 0Ah
- 000BBA39: 02 | 3 push 1
- 000BBA3A: 82 000002E2 | 4 callasm SA_GetNumSubTypes
- 000BBA3F: 5C | 3 if SP[0]<=SP[1] then push 0 else push 1
- 000BBA40: 34 000BBA90 | 2 if SP[0]=0 then jump L000BBA90
- 000BBA45: 32 000BBA58 | 1 jump L000BBA58
- 000BBA4A: 0D 0001 | 1 L000BBA4A: push SP[0] ; loc1
- 000BBA4D: 02 | 2 push 1
- 000BBA4E: 46 | 3 add SP[0],SP[1]
- 000BBA4F: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BBA52: 24 | 2 pop
- 000BBA53: 32 000BBA34 | 1 jump L000BBA34
- 000BBA58: 01 | 1 L000BBA58: push 0
- 000BBA59: 0D 0002 | 2 push SP[1] ; loc1
- 000BBA5C: 05 0A | 3 pushb 10d ; 0Ah
- 000BBA5E: 03 | 4 push 2
- 000BBA5F: 88 000A8CB9 | 5 call88 SHIP.GetWareTypeCount
- 000BBA64: 14 0002 | 3 mov SP[1],SP[0] ; loc2
- 000BBA67: 34 000BBA8A | 3 if SP[0]=0 then jump L000BBA8A
- 000BBA6C: 05 64 | 2 pushb 100d ; 64h
- 000BBA6E: 02 | 3 push 1
- 000BBA6F: 82 000002C4 | 4 callasm SE_Random
- [color=yellow]000BBA74: 05 5A | 3 pushb 90d ; 5Ah[/color]
- 000BBA76: 5C | 4 if SP[0]<=SP[1] then push 0 else push 1
- 000BBA77: 34 000BBA8A | 3 if SP[0]=0 then jump L000BBA8A
- 000BBA7C: 0D 0001 | 2 push SP[0] ; loc2
- 000BBA7F: 65 | 3 neg SP[0]
- 000BBA80: 0D 0003 | 3 push SP[2] ; loc1
- 000BBA83: 03 | 4 push 2
- 000BBA84: 88 000A61DC | 5 call88 SHIP.AddMissile
- 000BBA89: 24 | 3 pop
- 000BBA8A: 24 | 2 L000BBA8A: pop
- 000BBA8B: 32 000BBA4A | 1 jump L000BBA4A
- 000BBA90: 05 0B | 1 L000BBA90: pushb 11d ; 0Bh
- 000BBA92: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BBA95: 24 | 2 pop
- 000BBA96: 0D 0001 | 1 L000BBA96: push SP[0] ; loc1
- 000BBA99: 05 10 | 2 pushb 16d ; 10h
- 000BBA9B: 5E | 3 if SP[0]<SP[1] then push 0 else push 1
- 000BBA9C: 34 000BBB28 | 2 if SP[0]=0 then jump L000BBB28
- 000BBAA1: 32 000BBAB4 | 1 jump L000BBAB4
- 000BBAA6: 0D 0001 | 1 L000BBAA6: push SP[0] ; loc1
- 000BBAA9: 02 | 2 push 1
- 000BBAAA: 46 | 3 add SP[0],SP[1]
- 000BBAAB: 14 0002 | 2 mov SP[1],SP[0] ; loc1
- 000BBAAE: 24 | 2 pop
- 000BBAAF: 32 000BBA96 | 1 jump L000BBA96
- 000BBAB4: 01 | 1 L000BBAB4: push 0
- 000BBAB5: 01 | 2 push 0
- 000BBAB6: 14 0002 | 3 mov SP[1],SP[0] ; loc2
- 000BBAB9: 24 | 3 pop
- 000BBABA: 0D 0001 | 2 L000BBABA: push SP[0] ; loc2
- 000BBABD: 0D 0003 | 3 push SP[2] ; loc1
- 000BBAC0: 02 | 4 push 1
- 000BBAC1: 82 000002E2 | 5 callasm SA_GetNumSubTypes
- 000BBAC6: 5C | 4 if SP[0]<=SP[1] then push 0 else push 1
- 000BBAC7: 34 000BBB22 | 3 if SP[0]=0 then jump L000BBB22
- 000BBACC: 32 000BBADF | 2 jump L000BBADF
- 000BBAD1: 0D 0001 | 2 L000BBAD1: push SP[0] ; loc2
- 000BBAD4: 02 | 3 push 1
- 000BBAD5: 46 | 4 add SP[0],SP[1]
- 000BBAD6: 14 0002 | 3 mov SP[1],SP[0] ; loc2
- 000BBAD9: 24 | 3 pop
- 000BBADA: 32 000BBABA | 2 jump L000BBABA
- 000BBADF: 0D 0001 | 2 L000BBADF: push SP[0] ; loc2
- 000BBAE2: 0D 0003 | 3 push SP[2] ; loc1
- 000BBAE5: 03 | 4 push 2
- 000BBAE6: 88 000A8CB9 | 5 call88 SHIP.GetWareTypeCount
- 000BBAEB: 0D 0001 | 3 push SP[0] ; loc3
- 000BBAEE: 34 000BBB1C | 4 if SP[0]=0 then jump L000BBB1C
- 000BBAF3: 02 | 3 push 1
- 000BBAF4: 02 | 4 push 1
- 000BBAF5: 0D 0003 | 5 push SP[2] ; loc3
- 000BBAF8: 46 | 6 add SP[0],SP[1]
- 000BBAF9: 02 | 5 push 1
- 000BBAFA: 82 000002C4 | 6 callasm SE_Random
- 000BBAFF: 46 | 5 add SP[0],SP[1]
- 000BBB00: 02 | 4 push 1
- 000BBB01: 82 000002C4 | 5 callasm SE_Random
- 000BBB06: 0D 0002 | 4 push SP[1] ; loc3
- 000BBB09: 65 | 5 neg SP[0]
- 000BBB0A: 0D 0002 | 5 push SP[1] ; loc4
- 000BBB0D: 46 | 6 add SP[0],SP[1]
- 000BBB0E: 0D 0004 | 5 push SP[3] ; loc2
- 000BBB11: 0D 0006 | 6 push SP[5] ; loc1
- 000BBB14: 04 | 7 push 3
- 000BBB15: 87 0000000C | 8 call87 AddWare
- 000BBB1A: 24 | 5 pop
- 000BBB1B: 24 | 4 pop
- 000BBB1C: 24 | 3 L000BBB1C: pop
- 000BBB1D: 32 000BBAD1 | 2 jump L000BBAD1
- 000BBB22: 24 | 2 L000BBB22: pop
- 000BBB23: 32 000BBAA6 | 1 jump L000BBAA6
- 000BBB28: 0F 0003 | 1 L000BBB28: read GBODY.var_1000_3 ; [3]
- 000BBB2B: 34 000BBB58 | 2 if SP[0]=0 then jump L000BBB58
- 000BBB30: 05 11 | 1 pushb 17d ; 11h
- 000BBB32: 05 10 | 2 pushb 16d ; 10h
- 000BBB34: 03 | 3 push 2
- 000BBB35: 88 000A8E67 | 4 call88 SHIP.GetWareTypeCountWithPredefined
- 000BBB3A: 0F 0003 | 2 read GBODY.var_1000_3 ; [3]
- 000BBB3D: 03 | 3 push 2
- 000BBB3E: 82 0000E253 | 4 callasm SA_SetExtraSpeed
- 000BBB43: 24 | 2 pop
- 000BBB44: 05 12 | 1 pushb 18d ; 12h
- 000BBB46: 05 10 | 2 pushb 16d ; 10h
- 000BBB48: 03 | 3 push 2
- 000BBB49: 88 000A8E67 | 4 call88 SHIP.GetWareTypeCountWithPredefined
- 000BBB4E: 0F 0003 | 2 read GBODY.var_1000_3 ; [3]
- 000BBB51: 03 | 3 push 2
- 000BBB52: 82 0000E264 | 4 callasm SA_SetExtraRotSpeed
- 000BBB57: 24 | 2 pop
- 000BBB58: 24 | 1 L000BBB58: pop
- 000BBB59: 01 | 0 push 0
- 000BBB5A: 83 | 1 ret
|
| |
Вкратце, суть алгоритма такая. Программа запрашивает количество лазеров на борту. Потом проверяет - если они хаакские, значит устанвливается нижняя планка шанса на 50
| Код:- 000BB99D: 05 32 | 3 pushb 50d ; 32h
|
| |
иначе - на 90
| Код:- 000BB9A4: 05 5A | 3 L000BB9A4: pushb 90d ; 5Ah
|
| |
Если шаровое число до 100 меньше, чем нижняя планка шанса, то все, нет больше лазеров. Потом то же со щитами, но там уже побоку чьи, наши, ваши, любой щит исчезает с 90% вероятностью. Потом - ракеты. Затем по замысловатой формуле все оборудование и груз. Формула, кстати, хорошо описана здесь
Так вот, чтобы долго не заморачиваться, я пометил желтым цветом те строки, в котроых назначаются минимальные границы шансов. Образно говоря, если все эти числа установить в 0, то при захвате любого корабля, хоть мелкого, хоть бигшипа, щиты, пухи, ракеты всегда будут целыми. Ну, а как поменять эти значения, я думаю, вы уже поймете. |
|
дерево темы → Гайд-Парк
Гайд-Парк »
Список игр
|  |
|  |
 |  |  | |
| | | |
|  |