ВНИМАНИЕ! Наша конференция посвящена космической тематике и компьютерным играм. Политические вопросы и происходящие в мире события в данный момент на нашем сайте не обсуждаются!
|
» X2-ASM - это проcто! | страница 1 |
|
|
|
Канал X2: The Threat: «X2-ASM - это проcто!» |
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Добрый день, добрый!
Небольшой ассемблер, который позволяет патчить OBJ файлы.
Что необходимо в работе и с чего начать.
1. Дизассемблер dobj.exe. Это утилита позволит восстановить obj файл в текстовый вид.
2. Собственно ассемблер xa_asm.exe.
3. Описание и голова.
Перво-наперво натравливаем дизассемблер на obj файл. Например
dobj.exe x2story.obj
Получаем несколько файлов, среди которых нас в первую очередь будет интересовать x2story.asm. Изучаем неспеша. Находим интересующий кусок текста, копируем его (этот кусок) в отдельный файл, например patch1.asm. По образу и подобию примеров из архива xa_xxx.zip правим его. И натравливаем на этот файл ассемблер:
xa_asm patch1.asm
Если ошибок не было,то в результате получаем файл листинга, и файл patch1.cod - это результат нашего патча, слинкованный с x2story.
Этот patch1.cod можно теперь переименовать в x2story.obj и скопировать в папку с игрой.
Благодарности.
- Снимаю шляпу перед DF, Blueboar, Shaddie, выполнивших титаническую
работу по расковыриванию структуры obj-файлов XT.
- Пилотам EliteGames за поддержку.
Дизассемблер.
Версия 03.29b
- правки ошибок, оптимизация
Ассемблер.
Версия 03.32b
Эта версия может компилить асм-файлы до полнофункциональных обжей.
Сбылась мечта идиота - перевожу из альфы в бету!
По мере сил и возможностей буду в эту тему постить примеры и доп. описание.
-- EDIT
На всякий случай останется зеркало на народ.ру. В случае проблем - ищите там.
xa3_32.zip |
Описание: |
|
Имя файла: |
xa3_32.zip |
Размер файла: |
114.68 KB |
Скачано: |
1276 раз(а) |
do3_29.zip |
Описание: |
Дизассемблер. Версия 03.29b |
|
Имя файла: |
do3_29.zip |
Размер файла: |
101.04 KB |
Скачано: |
1359 раз(а) |
Последний раз редактировалось: CheckerTwo (16:35 12-03-2011), всего редактировалось 20 раз(а) |
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Пример номер 1.
Код: |
.title example 1
.ident X2
.radix 16d
.loadobj "x2story.obj"
;
; Нужно не забывать, что адреса процедур отличаются в x2story от x2galedit!
;
; 1. объявляем секцию ABS (абсолютная секция) - т.е. будем писать код поверх
; того, что там находится. "Правим по живому"
.section code, abs
;
; 2. Находим в дизассемблерном файле кусок, который нужно исправить
; Например, хотим, что бы ракеты все, крутее Шершня, разбивали астероид
; Смотрим - по адресу 0001F684 находится константа, которая определяет
; это ограничение. Вместо следующей команды на неравенство нужно будет
; вставить команду "if SP[0]>=SP[1] then push 0 else push 1"
; Вот так и делаем.
;
; | TASTEROID.KilledBy:
;0001F666: 0055 000E | setmem 0Eh ; 14d
;0001F66A: 0005 0004 | push SP[3]
;0001F66E: 000E | push 5 ; 5
;0001F670: 004F | if SP[0]<>SP[1] then push 0 else push 1
;0001F672: 0033 0000FB47 | if SP[0]=0 then jump L0001F696
;0001F678: 0005 0006 | push SP[5]
;0001F67C: 000A | push 1 ; 1
;0001F67E: 005A 00000641 | callasm SA_GetSubType ; 00000641
;0001F684: 000D | push 4 ; 4
;0001F686: 004F | if SP[0]<>SP[1] then push 0 else push 1
; Устанавливаем счетчик команд на этот адрес и пишем/правим команду
$ = 0001F686h
if SP[0]>SP[1] then push 0 else push 1
; Note: Если нужно, что бы Шершень не разбивал астероид - условие должно быть изменено
;if SP[0]>=SP[1] then push 0 else push 1
;
;0001F688: 0033 0000FB47 | if SP[0]=0 then jump L0001F696
;0001F68E: 000A | push 1 ; 1
;0001F690: 0031 0000FB48 | jump L0001F698
;0001F696: 0009 | L0001F696: push 0 ; 0
;0001F698: 0032 0000FB7E | L0001F698: if SP[0]<>0 then jump L0001F704
;
; Собственно все. Больше ничего не нужно.
;
;
.end
|
|
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Небольшое вступление и замечания.
Команды, сохраняющие значение в стеке, сначала инкрементируют указатель стека, затем записывают в стек значение. Например, команду push можно расписать следующим образом:
Код: |
push SP[3] === SP := SP + 1 Увеличение SP до выполнения операции
acc := SP[3]
SP[0] := acc
|
Команды, которые вытаскивают из стека число, сначала читают его из стека, затем делают декремент указателя стека. Следует обратить внимание на команду возврата из функции ret. Эта команда:
1. вытаскивает из стека и запоминает значение результата функции
2. вытаскивает из стека адрес возврата
3. вытаскивает из стека число параметров функции
4. корректирует указатель стека, тем самым удаляя из стека параметры
5. заталкивает в стек результат функции
6. выполняет безусловный переход по адресу
Передача параметров функции: Глобальные функции.
Функции бывают разные. И вызов функции зависит от ее типа.
Если функция глобальная, то она должна вызываться командой call58.
Глобальная функция описывается директивой .func. Например:
Код: |
;
; Описываем глобальную функцию.
.func FunctionWithArg
.func FunctionWithoutArg
;Вызов объявленной таким образом функции, будет выглядеть так:
push <arg1> ; аргумент (параметр) функции
push 1 ; число фактических аргументов функции
call58 FunctionWithArg
;Если функция не имеет аргументов, то она должна вызываться вот так:
push 0 ; у функции нет аргументов
call58 FunctionWithoutArg
|
Директива .func сохраняет имя функции в секции STRG, и создает запись
в таблице SYMB. Но эта запись еще неинециализирована. Ее инициализация
выполняется командой setmem <num>, дополняя адресом и размером стека.
Код: |
;
; Вход в функцию
; Простая функция, которая вытаскивает значение переданного ей параметра
; и увеличивает его на 100
;
FunctionWithArg:
setmem 2
; вытащим на вершину стека параметр
push SP[3] ; это значение <arg1>, переданное нашей функции
push 100d ; число 100
add SP[0], SP[1] ; сложить SP[1] + SP[0] -> SP[0]
;
; функция всегда возвращает результат, даже когда он никому не нужен.
; число в стеке SP[0] будет возвращено вызывающей программе
ret ; возврат из функции
|
Если функция ничего не должна возвращать, все равно нужно в стек записать
что-нибудь. Минимально возможная функция выглядит так:
Код: |
.func SuperSimple
SuperSimple:
setmem 1
push 0 ;
ret ; возврат из функции
|
Вернемся к нашему примеру. FunctionWithArg складывает переданное ей значение
с числом 100 и возвращает результат. Передадим в качестве аргумента число 30.
Таким образом, вызов нашей функции должен будет выглядеть так:
Код: |
push 30 ; аргумент (параметр) функции
push 1 ; число аргументов функции
call58 FunctionWithArg ; <arg> + 100
;
; результат работы функции содержится в стеке, так, что его можно
; получить. Либо выбросить, если выполнить команду pop.
pop ; выбросили результат
|
Не бывает функций, которые "ничего" не возвращают. Для них всегда нужна команда pop.
Передача параметров функции: Функции-методы.
Вызов функции-метода внутри одного класса немного отличается от вызовов
глобальных функций. Для этого испльзуется команда call.
Например
Предположим, что мы написали свой собственный класс, в котором описаны
несколько функций.
Код: |
;
; пример объявления класса с единственной функцией
;
.classdef TAdd, 1000d
.func Addition
.endclass TAdd
;
; функция, которая складывает аргумент с числом 200 и возвращает его
;
TAdd.Addition:
setmem 2
; вытащим на вершину стека параметр
push SP[3] ; это значение <arg1>, переданное нашей функции
push 200d ; число 200
add SP[0], SP[1] ; сложить SP[1] + SP[0] -> SP[0]
ret ;
;
; объявление более сложного класса
;
.classdef TTestClass, 1001d
.func Addition
.func Test
.func TestGlobal
.func TestAnother
.endclass
;
; функция, которая складывает аргумент с числом 300 и возвращает его
;
TTestClass.Addition:
setmem 2
; вытащим на вершину стека параметр
push SP[3] ; это значение <arg1>, переданное нашей функции
push 300d ; число 300
add SP[0], SP[1] ; сложить SP[1] + SP[0] -> SP[0]
ret ;
;
; функция Test вызывает метод этого же класса
;
TTestClass.Test:
setmem 3 ;
push 30d ; передаем нашей функции Addition параметр = 30
push 1 ; один параметр
get_object ; записать в стек идентификатор нашего объекта
;
; при вызове функции-метода имя класса можно не писать, или написать
; (TTestClass.Addition), но оно будет игнорироваться.
;
call Addition ; складываем (+300)
ret ; результат в стеке, его и возвращаем
;
; функция TestGlobal вызывает глобальную функцию
;
TTestClass.TestGlobal:
setmem 2 ;
push 30d ; передаем нашей функции Addition параметр = 30
push 1 ; один параметр
call58 FunctionWithArg ; складываем (+ 100)
ret ; результат в стеке, его и возвращаем
;
; функция TestAnother вызывает метод чужого класса
;
TTestClass.TestAnother:
setmem 3 ;
push 30d ; передаем нашей функции Addition параметр = 30
push 1 ; один параметр
push 1000d ; записать в стек идентификатор чужого объекта
call59 TAdd.Addition ; складываем (+200)
ret ; результат в стеке, его и возвращаем
|
=======
EDIT : Немного поправил функции, чтобы легче было разобраться, где какая функция. Глобальная функция FunctionWithArg добавляет 100,
TAdd.Addition добавляет 200, TTestClass.Addition - 300.
EDIT : Исправил косяки. Спасибо Nihil.
EDIT : Исправил неточности. Спасибо X3-Protector.
Последний раз редактировалось: CheckerTwo (22:26 31-10-2008), всего редактировалось 1 раз |
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Работа с переменными.
Переменные в Х2 (по сравнению с ХТ) стали типизированными.
Определены 4 типа переменных - целые, строковые, массивы и таблицы.
Код: |
.vint i ; объявляем переменную целого типа
.vstr str ; строковая переменная
.varray array ; одномерный массив значений
.vtable tbl ; таблица - многомерный массив
|
-------------
Небольшой пример использования переменных
Код: |
.section code, con
.vint i1 ; объявляем глобальную переменную
;
; простая функция, которая читает значение глобальной переменной
;
.func GetValue
GetValue: setmem 1 ;
readvar i1 ; читаем глобальную переменную в стек
ret ; функция возвращает значение i1
;
; Эта функция записывает число 100 в глобальную переменную
; и возвращает его в качестве результата
;
.func SetValue
SetValue: setmem 1 ;
push 100d ; sp[0] <- 100d
writevar i1 ; i1 <- sp[0], команде не изменяет указатель стека
pop ; поэтому восстанавливаем указатель стека ручками
readvar i1 ; читаем значение из переменной
ret ; функция возвращает его
;
; Теперь рассмотрим как работать с переменными, объявленными в классе
;
.classdef Test, 1000d
.vint i1 ; объявили целочисленную переменную
.func GetValue ; эта функция будет читать переменную
.func SetValue ; а эта записывать в нее
.endclass Test
;
; функция, принадлежащая классу Test, которая просто читает число,
; записанное в переменной Test.i1
;
Test.GetValue:
setmem 1
read Test.i1 ; sp[0] <- i1
ret ; result = Test.i1
;
; функция записывает 100 в переменную, но читает глобальную
; переменную и возвращает ее значение.
;
Test.SetValue:
setmem 1 ;
push 100d ; sp[0] <- 100d
write Test.i1 ; Test.i1 <- sp[0]
pop ; восстанавливаем стек
readvar i1 ; читаем глобальную i1 в sp[0]
ret ; result = global.i1
|
Note: Команды write, writevar не изменяют стек.
Команда сохранения значения в локальной переменной объекта write не изменяет
указатель стека. Это может быть использовано для присвоения одного и того же
значения нескольким переменным. Например:
Код: |
.classdef TTest, 1000h
.vint test1
.vint test2
.vint test3
.vint test4
.endclass TTest
........
push 100h ; значение 100h засылается в стек
write TTest.test1 ; переменные test1, test2, test3, test4
write TTest.test2 ; объекта TTest инициализируются
write TTest.test3 ; одним значением
write TTest.test4 ;
pop ; очистить стек
Этот же способ может быть использован для инициализации глобальных переменных
с помощью команды writevar.
|
|
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Маленькие трюки: Изменение размера доступного функции стека.
Всякая функция начинается с объявления директивой .func, независимо от того, глобальная это функция или это метод объекта. Кроме того, в начале каждой функции обязательно должна стоять команда setmem <num>, которая выделяет стековую память в функции под временные переменные. Команда проверяет наличие метки. Предположим, что нам необходимо изменить данную функцию - дополнить функциональность и пр... Но для этого потребуется увеличить размер стековой памяти. Если размер стека не изменять, то игруха вылетит в виндовс безо всяких предупреждений.
Например дизассемблировали, посмотрели:
Код: |
;
; | TASTEROID.KilledBy:
;0001F666: 0055 000E | setmem 0Eh ; функция использует 14 ячеек стека
; .................
|
Просто изменить команду setmem нельзя. Например следующий код не будет транслироваться ассемблером:
Код: |
;
.section code, abs
;TASTEROID.KilledBy:
; setmem 0Eh ; 14d
$ = 0001F666h
setmem 1Eh ; указываем новое значение локальной памяти
; .................
|
setmem без метки транслироваться не будет, потому что она размещает информацию о размере стека в таблицах SYMB. Для решения проблемы вы должны указать имя функции. Примерно так:
Код: |
.section code, abs
; | TASTEROID.KilledBy:
;0001F666: 0055 000E | setmem 0Eh ; 14d
$ = 0001F666h
TASTEROID.KilledBy:
setmem 1Eh ; указываем новое значение локальной памяти
; ..............
|
В этом случае все пройдет нормально. Наша новая функция будет иметь увеличенный размер стека, и этот размер вставится в таблицы SYMB.
|
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Маленькие трюки: правка переходов команды switch.
Сразу несколько слов об этой команде.
Команда switch представляет собой "многовариантный" переход по таблице адресов. Вся конструкция switch ...casejump...endswitch считается одной командой. Она имеет опкод 0055 и следом таблицу адресов переходов. Эта команда требует один параметр в стеке - индекс перехода.
Причем его значение не проверяется на допустимые границы. Компилятор ES для проверки диапазона входных значений вставляет дополнительный код.
Это что-то похожее на ассемблеровскую x86 команду "jump JUMPTABLE[ebx]".
Код: |
; компилятор ES вначале вставляет код для проверки диапазона входного значения
;
push SP[0] ; input value X
push 3 ; ; MAX value
if SP[0]<SP[1] then push 0 else push 1 ;
if SP[0]<>0 then jump L0000919E ;
pop ;
push 0 ; 0 ; X > HIGH
L0000919E: switch ;
case jump L000091AC ; X = 0
case jump L000090B8 ; X = 1
; .......
case jump L00000008 ; <- ????
endswitch ;
L000091AC: .................. ;
|
Команда switch может быть очень большой. Иногда встречаются более 600 вариантов. Как это все отлаживали в ES трудно представить. Для исправления части этой длинной команды можно использовать директиву .long <num>. Надо только не забывать, что в таблице подставляются адреса не байтовые, и должны вычисляться по формуле: (address_label - 8) / 2
Предположим, что мы разобрались в коде и выяснили, что в одном из вариантов команды switch нужно перейти не на метку L00000832, а на нашу собственную.
Код: |
.section code, abs
; ..................
; switch ; команда многовариантного перехода
; case jump L000008D0 ; переход на метку L000008D0
; case jump L00000832 ; переход на метку L00000832
; Вот этот переход мы должны исправить на наш собственный.
;
$ = 000008B8h ; адрес "case jump L00000832"
.long (lab_case1 - 8) / 2 ; переход на нужный адрес - наш патч
; все, дальше остается как есть...
;
; case jump L00000854
; case jump L00000008
; case jump L00000008
; endswitch
; .................
;
; Наш патч будем располагать в конце кода.
;
.section code, con
; Вот сюда перейдет управление из команды switch
lab_case1:
.......
jump lab_return_from_patch
|
|
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Маленькие трюки: Локальные метки.
В некоторых случаях, особенно при больших программах, в командах переходов удобно пользоваться так называемыми локальными метками, для того, что бы не изобретать новых имен под метки. Блок локальных меток (т.е. часть программы, где доступны эти метки) ограничивается двумя нелокальными метками, либо директивами определения секции.
Локальные метки начинаются с символа '$' и содержат только цифры.
Например метка $1001 - локальная, а $100A - считается нелокальной. Внутри локального блока такие метки работают аналогично простым. Снаружи
локального блока они не видны.
Например (это всего лишь пример):
Код: |
; Небольшой пример использования локальных меток.
; Предположим у нас есть две похожие функции. предположим, что символьные
; имена меток уже надоели и от них рябит в глазах или не лезет в голову
; подходящее имя. Или уже столько меток, что не помнится - использовали
; или нет. :) Самое время воспользоваться локальными метками!
.func test1
.func test2
test1: setmem 2
push SP[3]
push 2
if SP[0]<=SP[1] then push 0 else push 1
if SP[0]=0 then jump $02
push 1
$01: ret
$02: push 0
jump $01
;
; Новая функция начинается с нелокальной метки "test2", при этом
; автоматически объявляется новый блок локальных меток. Поэтому конфликта
; имен не будет.
;
;
test2: setmem 2
push SP[3]
push 6
if SP[0]<=SP[1] then push 0 else push 1
if SP[0]=0 then jump $02
push 4
$01: ret
$02: push 6
jump $01
.end
|
В этом примере функции отличаются незначительно, выдумывать уникальные имена меток переходов неинтересно. Так что вот.
|
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
> Все какие-то пуши-попы, а что-нибудь полезное будет когда-нибудь?
> Все это конечно интересно, но хочется чего-то более...
Эх, со временем напряг. Ну, хорошо. Давайте напишем какой-нибудь
полезный пример.
Допустим мы написали какой-то интересный патч. Запустили - не работает.
Что нужно в первую очередь? Посмотреть - какие значения у переменных и
вообще выполняются ли условия и пр... Напишем маленькую библиотечку,
которая немного упростит отладку нашей программы.
Вывод на экран значения переменной и текстовую строку простым способом
получить не удалось. Возможно это связано с тем, что этот тупой вывод
на экран инфы тут же затирается с частотой нашего fps. Поэтому пойдем
другим путем - выводить будем через стандартный менюшный интерфейс.
Это не намного сложнее, может даже проще, потому что не нужно будет
разбираться в системных вызовах и обработкой событий...
Для упрощения кода и для уменьшения объема исправлений мы не будем
встраивать нашу отладочную менюшку в общий цикл отработки событий.
Т.е. наша менюшка не будет отрабатывать кнопки.
Итак, что нам нужно:
1. Создаем класс TMENU_DBG, который наследует все свойства и методы уже существующего в игре TMENU_ID.
2. В нашем классе объявим 2 переменные, значения которых будем выводить в окне.
dbg_CurValue - здесь будем хранить число
dbg_CurString - а здесь строку.
3. Пишем несколько служебных методов этого класса.
Код: |
.classdef TMENU_DBG(TMENU_ID), 28C8h
; variables
.vint dbg_CurValue ; здесь будем хранить число
.vstr dbg_CurString ; здесь - строка
; procedures
.func Create ; конструктор
.func GetName ; возвращает имя окна
.func GetObjectBody ; возвращает номер body, на основе которого строится менюшка
.func SpecialMenu ; инициализирует специфические переменные менюшки
.func SpecialUpdate ; форматирует выводимый в окно текст
.func GetClass ; возвращает идентификатор нашего класса
.func IsClass ; true, если это наш класс
.func ExitMenu ; служебный метод для закрытия менюшки
.endclass TMENU_DBG
|
Чтобы не плодить дополнительных методов, значения выводимой переменной и
строки будем задавать при вызове конструктора Create нашей менюшки.
Так, что создание нашего класса будет выглядеть примерно так:
Код: |
push SP[4] ; выводимая строка
push SP[4] ; выводимое число
push 2 ; число параметров у Create
push 28C8h ; идентификатор нашего класса
create_object ; создаем класс
call TMENU_DBG.Create ; и вызываем конструктор
|
Чтобы каждый раз не вспоминать детали нашей менюшки (идентификатор например), оформим все это в виде вспомогательной функцим:
Код: |
;
; Global support routine
;
; Вывод строки и числа на экран
; вызов
; push <str> ; строка - сообщение
; push <val> ; число
; push 2 ; число параметров
; call58 global.OutText ;
; pop
;
.func OutText
OutText: setmem 4d
push SP[4] ; строка
push SP[4] ; число
push 2 ; число параметров
push 28C8h
create_object
call TMENU_DBG.Create
ret
|
Замечательно. Теперь распишем собственно методы нашей отладочной менюшки.
Код: |
TMENU_DBG.Create:
setmem 3
push SP[4] ;
write TMENU_DBG.dbg_CurString ; сохраняем строку в переменной объекта
pop
push SP[3] ;
write TMENU_DBG.dbg_CurValue ; сохраняем число в переменной объекта
pop
push 0 ; вызываем конструктор родительского
push 1 ; объекта
push 08A2h ;
call TMENU_ID.Create ;
ret
TMENU_DBG.GetName:
setmem 1 ; возвращаем заголовок меню
get_strg dbg_title ; "Mini debug"
ret
TMENU_DBG.GetObjectBody:
setmem 1 ; возвращаем номер Body на осное
push 0BEh ; которого строится изображение меню
ret
TMENU_DBG.GetClass:
setmem 1
push 28C8h
ret
TMENU_DBG.IsClass:
setmem 3
push SP[3]
push 28C8h ;
if SP[0]<>SP[1] then push 0 else push 1
if SP[0]<>0 then jump $01
push SP[3]
push 1 ; 1
push 08A2h ; 2210d
call TMENU_ID.IsClass ; 00000FB5
ret
$01: push 1
ret
TMENU_DBG.SpecialMenu:
setmem 2 ; 2
push 0 ; 0
write TMENU.me_FirstLineInfo ; [0Bh ; 11d]
pop
push 8 ; 8
write TMENU.me_PageLinesInfo ; [0Dh ; 13d]
pop
push 2 ; 2
write TMENU.me_TopLineInfo ; [0Eh ; 14d]
pop
push 0 ; 0
push 08A2h ; 2210d
call TMENU_ID.SpecialMenu ; 00007A6B
pop
push 0 ; 0
ret
TMENU_DBG.SpecialUpdate:
setmem 03h
push 0
get_object
call TMENU.StartInfo ; начало модификации окна
pop
get_strg dbg_subtt ; "Output value of variable"
push 1
get_object
call TMENU.AddInfoLine ;
pop
;
; нашу тестовую строку
;
read TMENU_DBG.dbg_CurString
push 1
get_object
call TMENU.AddInfoLine ;
pop
;
; выводим строку со значением нашего тестируемого числа "Variable = %04d "
; спецификация %04d - вывод числа длиной 4 с лидирующими "0" задана
; здесь только в качестве примера. Ну чтоб поиграться с форматами...
; строка может быть (да и должна) изменена на %d
;
read TMENU_DBG.dbg_CurValue
get_strg dbg_fmt ; "Variable = %04d "
push 2 ;
callasm SE_SPrintf ;
push 1 ;
get_object
call TMENU.AddInfoLine ;
pop
push 0
get_object
call TMENU.EndInfo ; закончили вывод в окно
pop
push 0
ret
TMENU_DBG.ExitMenu:
setmem 3
read TMENU.me_Object ;
if SP[0]=0 then jump $01 ;
read TMENU.me_Object ;
push 1 ;
callasm SE_ObjectExists ;
if SP[0]=0 then jump $01 ;
push 1 ;
jump $02 ;
$01: push 0 ;
$02: if SP[0]=0 then jump $03 ;
push 0 ;
push 1 ;
read TMENU.me_Object ;
call SetUpdateFocus ;
pop
$03: push 0 ;
push 08A2h ;
call TMENU.ExitMenu ;
pop
push 0
ret
.section strg, con
dbg_title: .ascii "Mini debug"
dbg_subtt: .ascii "Output value of variable"
dbg_fmt: .ascii "Variable = %04d"
|
Хорошо. Как теперь воспользоваться всем этим? А очень просто.
В нужном месте нашей патч-программы вставляем, например вот такой код
Код: |
get_strg str_01 ; выводим строку, чтоб понять где мы и что мы...
push 1 ; выводим число
push 2 ; 2 - это число параметров функции OutText
call58 global.OutText ; выводим менюшку
pop
;и в секцию STRG добавляем нашу строку
.section strg, con
str_01: .ascii "test string"
|
Вот собственно и все! В качестве примера добавим вызов наше йотладочной менюшки
в какой-нибудь простенький патч. Допустим в патч где ракеты должны разбивать
астероиды:
Код: |
.title example 5
.ident X2
.radix 16d
.loadobj "x2story.obj"
.include "dbg_menu.inc"
.section code, abs
; | TASTEROID.KilledBy:
;0001F666: 0055 000E | setmem 0Eh ; 14d
;0001F66A: 0005 0004 | push SP[3]
;0001F66E: 000E | push 5 ; 5
;0001F670: 004F | if SP[0]<>SP[1] then push 0 else push 1
;0001F672: 0033 0000FB47 | if SP[0]=0 then jump L0001F696
;0001F678: 0005 0006 | push SP[5]
;0001F67C: 000A | push 1 ; 1
;0001F67E: 005A 00000641 | callasm SA_GetSubType ; 00000641
;0001F684: 000D | push 4 ; 4
$ = 0001F684h
jump ctwo_ptch1
;0001F686: 004F | if SP[0]<>SP[1] then push 0 else push 1
;0001F688: 0033 0000FB47 | if SP[0]=0 then jump L0001F696
;0001F68E: 000A | push 1 ; 1
;0001F690: 0031 0000FB48 | jump L0001F698
;
; переходим сюда, если нужно уничтожить астероид
;
$ = 0001F690h
ctwo_dstr:
;0001F696: 0009 | L0001F696: push 0 ; 0
;
; или сюда, если ракета просто разбилась о каменный монолит
;
$ = 0001F696h
ctwo_nodstr:
;0001F698: 0032 0000FB7E | L0001F698: if SP[0]<>0 then jump L0001F704
;0001F69E: 0005 0004 | push SP[3]
;0001F6A2: 000B | push 2 ; 2
;
; переходим в конец секции CODE, основное тело нашего патча будет здесь
.section code, con
ctwo_ptch1:
push 2
if SP[0]>=SP[1] then push 0 else push 1
if SP[0]=0 then jump $01
;
; есть - ок, раздолбать астероид
get_strg str_dstr ; выводим строку "destruct asteroid"
push 1 ; выводим число 1
push 2 ;
call58 global.OutText ; выводим менюшку
pop
push 1 ; 1-разрушить астероид проверяется позже
jump ctwo_dstr
;
; нет эффекта
$01: get_strg str_ndst ; выводим строку "no destruct asteroid"
push 2 ; выводим число 2
push 2
call58 global.OutText ; выводим менюшку
pop
jump ctwo_nodstr
.section strg, con
str_dstr: .ascii "destruct asteroid"
str_ndst: .ascii "no destruct asteroid"
.end
|
Запускаем ассемблер, сгенерированный obj файл копируем на место x2story.obj.
Теперь попробуем взлететь и раздолбать какой-нибудь астероид.
Наблюдаем видео-эффекты...
Полный пример можно вытянуть здесь:
dbgmenu.zip
|
|
|
Shaddie
556 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Серебряная медаль SETI@Home, EG team (208976 credits)](/conference/images/ranks/medals/seti_silver_new.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Активист (+25 EGP)](/conference/images/ranks/medals/activist.gif) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) Рейтинг канала: 4(60) Репутация: 118 Сообщения: 261 Откуда: Томск Зарегистрирован: 09.09.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
AlexYar : |
2Shaddie: Чекер в теме Х3-моддинг писал способ сделать в х3 в меню только один муз трек (только чтобы он один всегда играл).
Сейчас он пропал, а мне самому не сообразить. Можешь сделать asm или inc файлик для твоей проги (для Х2 ессно), чтобы до кучи и эта фича прикрутилась?
|
В оригинале в главном меню случайно выбирается один из 4 музыкальных треков 03001 - 03004.
Этот патч изменяет x2intro.obj таким образом, что будет проигрываться только один заданный трек.
Так же можно изменить версию игры выводимую в главном меню.
Применение.
1. Скачиваете последнюю версию ассемблера (не ниже v03.17) с сайта
Ссылки на narod.ru запрещены! Используйте пожалуйста другие, более нормальные хостинги. или по ссылке в первом посте этой темы.
Прямая ссылка на ассемблер: http://Ссылки на narod.ru запрещены! Используйте пожалуйста другие, более нормальные хостинги./xa3_17.zip.
2. Создаете новую папку, например ASM, в любом месте.
3. В эту папку копируете:
файлы из архива xa3_17.zip (можно только xa_asm.exe и xa_asm.ini);
собственно патч - файлы onetrack.asm;
файл x2intro.obj из папки l игры (ОРИГИНАЛЬНЫЙ!!!).
4. Если необходимо, то в файле onetrack.asm, любым текстовым редактором
изменяете значения:
Music_Track_Num - номер музыкального трека (изменять от 32 до 32767);
.ascii "Incoming 2.0" - версия мода (изменять, то что в двойных кавычках).
5. В командной строке набрать: xa_asm.exe onetrack.asm
Так же можно перетащить мышкой файл onetrack.asm на xa_asm.exe.
6. В результате работы xa_asm.exe должны появиться два новых файла onetrack.lst
и onetrack.cod. Последний из них следует переименовать в x2intro.obj
и скопировать его в папку l.
Код: |
.title one music track and mod version into main menu
.ident X2
.radix 16d
.loadobj "x2intro.obj"
; Только для X2 версии 1.4! В других версиях адреса могут сдвинуться!
; В оригинале в главном меню случайно выбирается один из 4 музыкальных треков 03001 - 03004.
; Этот патч изменяет x2intro.obj таким образом, что будет проигрываться только один заданный трек.
; Если его в папке X2/soundtrack нет, то нужно будет добавить самостоятельно.
; Так же можно изменить версию игры выводимую в главном меню.
; Задаем номер музыкального трека (32 <= MusicTrackNum <= 32767):
Music_Track_Num = 3000d
; Задаем версию игры/мода (строка в двойных кавычках)
.section strg, con
S0010000: .ascii "Incoming 2.0"
.section strg, con
; Начало патча
.section code, abs
; Выбор музыкального трека возможен в двух местах
; Первый участок кода, который выбирает один из 4 треков:
;00009B4C: 0053 | 1 L00009B4C: begin_critical
;00009B4E: 0032 00004DC4 | 2 if SP[0]<>0 then jump L00009B90
;00009B54: 000D | 1 push 4
;00009B56: 000A | 2 push 1
;00009B58: 005A 0000010D | 3 callasm SE_Random ; 0000010D
;00009B5E: 000A | 2 push 1
;00009B60: 003E | 3 add SP[0],SP[1]
;00009B62: 0001 03E8 | 2 push 1000d ; 03E8h
;00009B66: 000A | 3 push 1
;00009B68: 005A 000000F2 | 4 callasm TI_Delay ; 000000F2
;00009B6E: 002C | 3 pop
;00009B70: 0001 0BB8 | 2 push 3000d ; 0BB8h
;00009B74: 0005 0002 | 3 push SP[1] ; loc2
;00009B78: 003E | 4 add SP[0],SP[1]
;00009B7A: 000A | 3 push 1
;00009B7C: 000A | 4 push 1
;00009B7E: 0059 0000151F 000003B8 | 5 call59 TX_AUDIO.ChangeTrackMusic ;
;00009B88: 002C | 3 pop
;00009B8A: 002E 0001 | 2 popx 1
;00009B8E: 0054 | 1 end_critical
; Устанавливаем счетчик на адрес, с которой начинаем писать наш код (18 word)
$ = 00009B54h
push 1000d
push 1
callasm TI_Delay
pop
push Music_Track_Num
push 1
push 1
call59 TX_AUDIO.ChangeTrackMusic
pop
end_critical
; Вот и все теперь забиваем то что осталось (12 word) левыми командами:
push 0
pop
push 0
pop
push 0
pop
push 0
pop
push 0
pop
push 0
pop
; Второй участок кода, который выбирает один из 4 треков:
;00011072: 0053 | 1 L00011072: begin_critical
;00011074: 0032 00008857 | 2 if SP[0]<>0 then jump L000110B6
;0001107A: 000D | 1 push 4
;0001107C: 000A | 2 push 1
;0001107E: 005A 0000010D | 3 callasm SE_Random ; 0000010D
;00011084: 000A | 2 push 1
;00011086: 003E | 3 add SP[0],SP[1]
;00011088: 0001 03E8 | 2 push 1000d ; 03E8h
;0001108C: 000A | 3 push 1
;0001108E: 005A 000000F2 | 4 callasm TI_Delay ; 000000F2
;00011094: 002C | 3 pop
;00011096: 0001 0BB8 | 2 push 3000d ; 0BB8h
;0001109A: 0005 0002 | 3 push SP[1] ; loc2
;0001109E: 003E | 4 add SP[0],SP[1]
;000110A0: 000A | 3 push 1
;000110A2: 000A | 4 push 1
;000110A4: 0059 0000151F 000003B8 | 5 call59 TX_AUDIO.ChangeTrackMusic ;
;000110AE: 002C | 3 pop
;000110B0: 002E 0001 | 2 popx 1
;000110B4: 0054 | 1 end_critical
; Устанавливаем счетчик на адрес, с которой начинаем писать наш код (18 word)
$ = 0001107Ah
push 1000d
push 1
callasm TI_Delay
pop
push Music_Track_Num
push 1
push 1
call59 TX_AUDIO.ChangeTrackMusic
pop
end_critical
; Вот и все теперь забиваем то что осталось (12 word) левыми командами:
push 0
pop
push 0
pop
push 0
pop
push 0
pop
push 0
pop
push 0
pop
; Теперь сделаем вывод версии мода в меню
; За него отвечает следующий участок кода
;000113E6: 000D | 24 push 4
;000113E8: 0056 000010F5 | 25 get_strg S00010F5 ; 4341d ; 000010F5h ; "1.%d"
;000113EE: 000B | 26 push 2
;000113F0: 005A 0000059C | 27 callasm SE_SPrintf ; 0000059C
; Устанавливаем счетчик на адрес, с которой начинаем писать наш код (8 word)
$ = 000113E6h
get_strg S0010000
push 32d
pop
push 0
pop
; Конец патча
.end
|
onetrack.rar |
Описание: |
One music track and mod version into main menu Версия 0.01 |
|
Имя файла: |
onetrack.rar |
Размер файла: |
2.29 KB |
Скачано: |
1460 раз(а) |
|
|
|
Zman
65 EGP
![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) Репутация: 12 Сообщения: 54 Откуда: Galaxy far, far away... Зарегистрирован: 17.01.2006
![Вы не можете голосовать](images/tool_cool.gif) |
|
народ, есть вопросы по асму! (перенес из соседней темы)
1)
ассемблер версии x00.09a (а также 03.17 или какие там последние версии) не компилирует .asm файл созданный дизассеблером (без исправлений),
в основном из-за этой ошибки:
Код: |
000008B0: 0009 | 0008 push 0
000008B2: 005E | 0009 L000008B2: switch
000008B4: 00000464 | 0008 case jump L000008D0 ; 0
000008B8: 00000415 | 0008 case jump L00000832 ; 1
000008BC: 00000426 | 0008 case jump L00000854 ; 2
000008C0: 00000437 | 0008 case jump L00000876 ; 3
000008C4: 00000000 | 0008 case jump L00000008 ; 4 *
000008C8: 00000000 | 0008 case jump L00000008 ; 5 *
000008CC: 00000000 | 0008 case jump L00000008 ; 6 *
000008CC: | endswitch
000008D0: 0005 000C | 0008 L000008D0: push SP[11d] ; arg1
000008D4: 0001 0075 | 0009 push 75h ; 117d
|
(смотреть строки, отмеченные - * )
метка L000008 - не существует, тут вообще она неверно генерится!
CheckerTwo, у тебя делается так: DWORD * 2 + 8 и получается адрес для перехода (0*2+8), но надо еще проверять на 0!
00000000 - это типа 'case else', то есть на их месте должны стоять NOP-ы и выполнение идет дальше
соответственно править/компилить файл не получается
2)
кажется я нашел место, где задается имя файла, из которого читается список голосовых сообщений, но у меня такое впечатление, что это имя фиксированное - "001хх.xml" и в моей версии 1.4US есть обработка только для двух языков - 44 и 49, то есть только два файла можно открыть.
(это предварительные данные)
Вопрос: у кого игра на русском, там сделано как ?
a) languageid=7 и отдельные файлы для языка, типа 00107.xml, либо
b) languageid=44 и просто все сообщения в файле 00144.xml изменены на русские (вместо английского)?
если у вас вариант а) тогда пришлите мне плиз код из x2story.asm
начиная от метки
TX_AUDIO.SetVoicestream1:
; ...
и до первого RET
для сверки
3)
по поводу аудио команд... у меня в меню скриптов показывает 5 команд:
play sample
play sample: incoming transmission <?>, from object <?>
<?> send audio message <?> to player
send incoming message <?> to player: display it=<?>
<RetVar/IF/START> speak text: page=<pagenum> id=<idnum> priority=<priority>
в .xml файле у меня вот это:
Код: |
<t id="200">play sample %0</t>
<t id="201">play sample: incoming transmission %0, from object %1</t>
<t id="202">%0 send audio message %1 to player</t>
<t id="203">send incoming message %0 to player: display it=%1</t>
<t id="204">%0 -= %1</t>
<t id="205">%0 = %1 * %2</t>
<t id="206">%0 *= %1</t>
<t id="207">%0 = %1 / %2</t>
<t id="208">%0 /= %1</t>
<t id="209">%0 = %1 modulo %2</t>
<t id="210">%0 modulo= %1</t>
<t id="211">%0 = - %1</t>
|
то есть команды speak text: там нету! начиная с id=204 идет непонятно что...
Вопрос: значит бывают внутренние команды, которые не фигурируют в .xml ?
как тогда они связаны с x2story.obj и где их обработка/код?
4)
[deleted/resolved]
5)
2 CheckerTwo - пожелания по поводу дизасма (некритичные, просто косметика)
5a) вот сгенеренный .асм:
Код: |
setmem 2 ; 2
push SP[3]
push 1 ; 1
callasm SFX_SetMasterVolume ; 00000189
|
пожелание: комментарии хотелось бы видеть вот так:
Код: |
setmem 2 ; 2
push SP[3]
push 1 ; 1
callasm SFX_SetMasterVolume ; 00000189
|
то есть как это принято в любом асме - размещать их на одной позиции в строке, а иначе очень неудобно читать исходник
5b) еще кусок:
Код: |
push 1 ; 1
callasm SFX_SetMasterVolume ; 00000189
|
в комментарии 189 означает смещение, но это неявно, то есть выглядит как константа (confusing короче), может есть смысл писать какой-то префикс ?
например:
Код: |
push 1 ; 1
callasm SFX_SetMasterVolume ; @00000189 or .00000189
|
5c) константы хотелось бы видеть с leading zeros
Код: |
push 1h ; 1d
push 0x0001h ; 1d
|
(вторую строку вместо первой)
читабельность опять же выше, так как сразу видно WORD, к тому же несколько строк подряд показывают выравненные значения.
(короче в HIEW посмотрите дизасм как выводит )
6)
еще вопросы:
- как в окне debug trace script/log оставить только один мой скрипт ?
(по умолчанию там крутятся всякие фоновые, пишут кучу мусора в лог)
- я так и не понял, х2 может работать когда все .cat .dat распакованы или нет ? у меня не работает почему-то...
===================================================
Himmel прислал мне доп. инфу, спасибо!
на данный момент мои выводы совпадают с его данными:
нумерация файлов голосовых сообщений выглядит как: MOV\SSSLL.DAT
где SSS - номер потока (stream), LL - language id
значение stream задается в файле MOV/000LL.xml
но там только один вариант, stream=1, нигде не упоминается stream=2 или другой
я думаю EGOSOFT хотел сделать так, чтобы можно было использовать много файлов с ресурсами, раздельно с ними работать...
но судя по всему позже, при написании/доведении кода они поняли что могут положить все в один файл и упростили себе задачу , поэтому обработки значения stream просто нету!
об этом точно говорит код в x2story.asm
код процедуры TX_AUDIO.SetVoicestream1
там проверяется languageid и в зависимости от него жестко подставляется имя файла 00144 или 00149 (и может быть также 001LL, я еще не до конца понял), но там нельзя открыть 00244, нету этого кода!
я думаю, что если это место исправить, то все будет работать как нужно
к сожалению я эти все эти потроха сегодня увидел в первый раз, поэтому не настолько силен в х2 асме, чтобы сразу это исправить
но похоже, что направление верное, вопрос сейчас чисто технический, в реализации...
вместо процедуры TX_AUDIO.SetVoicestream1, которая всегда подставляет stream=1
надо написать общую процедуру TX_AUDIO.SetVoicestream, которая должна делать примерно так:
читается номер stream из списка в файле MOV/000LL.xml, затем из него и language id делается имя файла,
то есть:
filename = string( stream * 100 + languageid) + '.dat'
пример: stream=2, languageid=7;
filename= 2*100 + 7 = 00207.dat
вызывается эта процедура всего 1 или 2 раза в x2story.obj
какие будут комментарии ?
Zman
_________________ THX2U |
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Zman : |
народ, есть вопросы по асму! (перенес из соседней темы)
|
Вот и закончился мой длинный-длинный монолог.
Zman : |
1) ассемблер ... не компилирует .asm файл созданный дизассеблером (без исправлений),
|
Да, не компилирует. Нужно присвоить L0000008 = 0h или вместо case jump L0000008 писать case jump 0. Вообще эти нули - это косяк генератора кода ES. Они код неправильно генерировали для табличного перехода.
Ну, например можно так:
Код: |
L00000008 = 0
L000008B2: switch
case jump L000008D0 ; 0
case jump L00000832 ; 1
case jump 0h ; 2
case jump L00000008 ; 3
endswitch
|
Zman : |
но надо еще проверять на 0!
|
По хорошему надо было не городить конструкцию вида switch - case - endswitch, а просто написать одну команду косвенной адресации и, за ней, таблицу адресов-переходов. Выглядело бы примерно вот так:
Код: |
L000008B2: xjump SP[0]
.long (L000008D0-8)/2 ; 0
.long (L00000832-8)/2 ; 1
.long 0h ; 2
|
Но что-то никто не поддержал.
Zman : |
00000000 - это типа 'case else', то есть на их месте должны стоять NOP-ы и выполнение идет дальше
|
Не, это не case else. Это как раз и есть баг егософта. Они в Х3 исправили его. А команды NOP похоже нет вообще.
Zman : |
2)
кажется я нашел место, где задается имя файла, из которого читается список голосовых сообщений,
|
Ага, все правильно - TX_AUDIO.SetVoicestream1.
Код: |
| TX_AUDIO.SetVoicestream1:
00000E36: 0055 0003 | 0000 setmem 3
00000E3A: 0009 | 0000 push 0
00000E3C: 005A 0000001F | 0001 callasm SFX_GetLanguage ; 0000001F
00000E42: 0001 0064 | 0001 push 64h ; 100d
00000E46: 003E | 0002 add SP[0],SP[1]
00000E48: 000A | 0001 push 1
00000E4A: 0006 0007 | 0002 read TX_AUDIO.voicestreams ; [7]
00000E4E: 002D | 0003 put_to_array
00000E50: 002C | 0001 pop
00000E52: 0009 | 0000 push 0
00000E54: 0035 | 0001 ret
|
Zman : |
3)
то есть команды speak text: там нету! начиная с id=204 идет непонятно что...
|
Она дальше:
<t id="1042">%0speak text: page=%1 id=%2 priority=%3</t>
Zman : |
5)
пожелания по поводу дизасма (некритичные, просто косметика)
...комментарии...
то есть как это принято в любом асме - размещать их на одной позиции в строке, а иначе очень неудобно читать исходник
|
Размер выходного файла уже сейчас довольно большой. Не хотелось бы раздувать его комментариями. Тем более, что 90% они не очень нужны...
Я уж и так ужимал. Но, если будешь настаивать - я сделаю
Zman : |
в комментарии 189 означает смещение, но это неявно, то есть выглядит как константа (confusing короче), может есть смысл писать какой-то префикс ?
например:
Код: |
push 1 ; 1
callasm SFX_SetMasterVolume ; @00000189 or .00000189
|
|
Не очень понял. 00000189 - это абсолютный байтовый адрес имени функции в секции STRG. По большому счету вообще нафиг не нужен. Но. Есть одно но. Когда пишешь какую-нибудь программу, компилируешь, а потом дизассемблируешь ее для проверки, глюки искать немного легче. Хотя, могу выбросить...
Zman : |
5c) константы хотелось бы видеть с leading zeros
push 0x0001h
читабельность опять же выше, так как сразу видно WORD, к тому же несколько строк подряд показывают выравненные значения.
|
Можно такое сделать, только без 0х - это к С скорее.
Zman : |
- я так и не понял, х2 может работать когда все .cat .dat распакованы или нет ? у меня не работает почему-то...
|
Нормально работает.
Zman : |
вместо процедуры TX_AUDIO.SetVoicestream1, которая всегда подставляет stream=1 надо написать общую процедуру TX_AUDIO.SetVoicestream, которая должна делать примерно так:
...
какие будут комментарии ?
|
TX_AUDIO.SetVoicestream1 вызывается фактически один раз - во время загрузки сейва. При этом в массиве (кажись из 2х элементов) TX_AUDIO.voicestreams запоминается, как ты совершенно верно заметил, номер файла с аудиотреками.
Задача следующая: Нам нужно по команде из скрипта проиграть трек.
Либо старый (тот, который уже есть в игре), либо из нашего файла.
Можно попробовать реешить задачу след образом:
Если задается page/номер_трека больший чем описан например в 00007.xml, нужно вместо значения TX_AUDIO.voicestreams подсовывать другой номер.
Т.е. править нужно там, где используется этот voicestreams.
А используется он в TX_AUDIO.SpeakWithPriorityAndNoise.
|
|
|
Zman
65 EGP
![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) Репутация: 12 Сообщения: 54 Откуда: Galaxy far, far away... Зарегистрирован: 17.01.2006
![Вы не можете голосовать](images/tool_cool.gif) |
|
появились еще вопросы по дизассемблеру dobj
1)
Код: |
00003372: 0005 0001 | 0001 L00003372: push SP[0] ; loc1
00003376: 000A | 0002 push 1
00003378: 003F | 0003 sub SP[0],SP[1]
0000337A: 002A 0002 | 0002 mov SP[1],SP[0] ; loc1
0000337E: 0009 | 0002 push 0
00003380: 004D | 0003 if SP[0]>SP[1] then push 0 else push 1 ; *
00003382: 0033 00001AC1 | 0002 if SP[0]=0 then jump L0000358A
00003388: 0009 | 0001 push 0
0000338A: 0005 0002 | 0002 push SP[1] ; loc1
0000338E: 0031 000019E5 | 0003 jump L000033D2
|
почему любой push увеличивает указатель стека на 1, а строка, отмеченная * - уменьшает на 1 ?
2)
почему вот тут две почти одинаковые функции, но во второй ошибка переполнения стека ? (а по счетчику вроде все нормально)
Код: |
| TPATCH.Set:
00002EAA: 0055 0001 | 0000 setmem 1
00002EAE: 0009 | 0000 push 0
00002EB0: 002B 0000 | 0001 write TPATCH.pa_Version ; [0]
00002EB4: 002C | 0001 pop
00002EB6: 0009 | 0000 push 0
00002EB8: 0035 | 0001 ret
| TPATCH.CheckPatch:
00002EBA: 0055 0000 | 0000 setmem 0
00002EBE: 0009 | 0000 push 0
;Error: stack overflow condition at command addr = 00002EBE; stack = 1 limit = 0
00002EC0: 0035 | 0001 ret
|
3)
опять же по указателю стека:
Код: |
0000107E: 000A | 0010 push 1 ; +
00001080: 005A 000001E7 | 0011 callasm SE_StringToInt ; 000001E7
00001086: 002A 0003 | 0010 mov SP[2],SP[0] ; loc14
0000108A: 002C | 0010 pop ; -
0000108C: 0005 0003 | 000F push SP[2] ; loc13
00001090: 0051 | 0010 if SP[0]=0 then push 1 else push 0 ; ???
00001092: 0033 00000851 | 0010 if SP[0]=0 then jump L000010AA ; ??
00001098: 0005 0002 | 000F push SP[1] ; loc14
0000109C: 0033 00000851 | 0010 if SP[0]=0 then jump L000010AA ; ??
000010A2: 000A | 000F push 1 ; +
000010A4: 0031 00000852 | 0010 jump L000010AC
|
в комментариях к каждой строке:
+: указатель стека+1, ок
-: указатель стека-1, ок
??: почему эта команда уменьшает его на 1 ? не должен меняться вообще
???: почему эта команда не изменяет указатель стека ? должен быть +1
4)
опечатка в dobj.ini:
2201 = "MENU_BACKGRAUND"
должно быть:
2201 = "MENU_BACKGROUND"
_________________ THX2U |
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Zman : |
появились еще вопросы по дизассемблеру dobj
|
1)
Zman : |
Код: |
if SP[0]>SP[1] then push 0 else push 1 ; * |
почему любой push увеличивает указатель стека на 1, а строка, отмеченная * - уменьшает на 1 ?
|
Команда if SP[0]>SP[1] then push 0 else push 1 перед сравнением читает из стека два числа, потом заталкивает в стек 0/1. Получается, что стек меняется как раз на -1.
if SP[0]=0 then push 1 else push 0 - Эта команда не меняет значение указателья стека. Потому как вытащила из стека число, сравнила с нулем, и затолкала в стек 0/1
if SP[0]=0 then jump L000010AA - Эта комада уменьшит указатель стека на 1, потому как вытащит из стека число и все...
2)
Zman : |
почему вот тут две почти одинаковые функции, но во второй ошибка переполнения стека ? (а по счетчику вроде все нормально)
Код: |
| TPATCH.Set:
00002EAA: 0055 0001 | 0000 setmem 1
00002EAE: 0009 | 0000 push 0
00002EB0: 002B 0000 | 0001 write TPATCH.pa_Version ; [0]
00002EB4: 002C | 0001 pop
00002EB6: 0009 | 0000 push 0
00002EB8: 0035 | 0001 ret
| TPATCH.CheckPatch:
00002EBA: 0055 0000 | 0000 setmem 0
00002EBE: 0009 | 0000 push 0
;Error: stack overflow condition at command addr = 00002EBE; stack = 1 limit = 0
00002EC0: 0035 | 0001 ret
|
|
В TPATCH.CheckPatch в команде setmem резервируется 0 слов под стек. В то время как в стек заталкивается результат функции. Движок ES, в некоторых пределах, может вполне справляться с такими плюхами. Чем меньше подобных ошибок, тем стабилнее будет работать.
4)
Zman : |
опечатка в dobj.ini:
2201 = "MENU_BACKGRAUND"
должно быть:
2201 = "MENU_BACKGROUND"
|
Спасибо!
|
|
|
Zman
65 EGP
![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) Репутация: 12 Сообщения: 54 Откуда: Galaxy far, far away... Зарегистрирован: 17.01.2006
![Вы не можете голосовать](images/tool_cool.gif) |
|
CheckerTwo : |
Нужно присвоить L0000008 = 0h или вместо case jump L0000008 писать case jump 0.
|
так я не понял, что происходит если я прыгаю на эту ветку ?
переход на абс. адрес 0 ??
или ты думаешь, что на эти ветки переходов вообще не бывает ?
по моему бывает... и куда я попаду ?
CheckerTwo : |
Она дальше:
<t id="1042">%0speak text: page=%1 id=%2 priority=%3</t>
|
что-то я не понял... я искал текстовым поиском по всему хмл и не нашел
Zman : |
размещать их на одной позиции в строке, а иначе очень неудобно читать исходник
|
предлагаю компромисс : дополнять не пробелами, а табами с размером 8, я пользуюсь исключительно ФАРом, там это корректно работает...
у тебя на строку добавится 2-3 символа, не больше
Zman : |
Код: |
push 1 ; 1
callasm SFX_SetMasterVolume ; @00000189 or .00000189
|
Не очень понял. 00000189 - это абсолютный байтовый адрес имени функции в секции STRG. По большому счету вообще нафиг не нужен. Но. Есть одно но. Когда пишешь какую-нибудь программу, компилируешь, а потом дизассемблируешь ее для проверки, глюки искать немного легче. Хотя, могу выбросить...
|
я и говорю - смещение... не надо выбрасывать!, может тогда просто выводить как STRG.000000189 ?
CheckerTwo : |
Можно такое сделать, только без 0х - это к С скорее.
|
вообще это стандартная форма записи хексов...
ну как тебе удобно, лишь бы длина была выровнена
CheckerTwo : |
TX_AUDIO.SetVoicestream1 вызывается фактически один раз - во время загрузки сейва. При этом в массиве (кажись из 2х элементов) TX_AUDIO.voicestreams запоминается, как ты совершенно верно заметил, номер файла с аудиотреками.
Задача следующая: Нам нужно по команде из скрипта проиграть трек.
Либо старый (тот, который уже есть в игре), либо из нашего файла.
Можно попробовать реешить задачу след образом:
Если задается page/номер_трека больший чем описан например в 00007.xml, нужно вместо значения TX_AUDIO.voicestreams подсовывать другой номер.
Т.е. править нужно там, где используется этот voicestreams.
А используется он в TX_AUDIO.SpeakWithPriorityAndNoise.
|
я не вполне уверен...
чтобы сохранить логическую последовательность и структуру хотелось бы корректно задавать значения stream page и номер семпла, чтобы можно было использовать несколько адд-он файлов. то есть добавлять различные файлы много раз, чтобы при этом ничего не переделывать.
оптимальный вариант: в каждом новом файле стоит свой номер стрима и на него идет ссылка, тогда при открытии будет обращение к нужному файлу.
блин, у меня все материалы и исходники на другой машине...
предлагаю оба куска TX_AUDIO.SetVoicestream1 и TX_AUDIO.SpeakWithPriorityAndNoise здесь подробно рассмотреть и прокомментировать, тогда будет более понятно каким лучше путем подходить.
я по прежнему не до конца ориентируюсь в языке, больно уж запись переменных в стеке неудобно выглядит
_________________ THX2U |
|
|
CheckerTwo
550 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Автор программы под Х2 (+25 EGP)](/conference/images/ranks/medals/x2_prog.gif) ![Автор программы под Х3: Reunion (+25 EGP)](/conference/images/ranks/medals/x3_prog.gif) Рейтинг канала: 4(96) Репутация: 103 Сообщения: 412 Откуда: Tomsk Зарегистрирован: 18.08.2004
![Вы не можете голосовать](images/tool_cool.gif) |
|
Zman : |
CheckerTwo : |
Нужно присвоить L0000008 = 0h или вместо case jump L0000008 писать case jump 0.
|
так я не понял, что происходит если я прыгаю на эту ветку ? переход на абс. адрес 0 ?? или ты думаешь, что на эти ветки переходов вообще не бывает ? по моему бывает... и куда я попаду ?
|
На них управление никогда не передается. Перед командой switch идет код, который ограничивает "значение сверху".
Zman : |
CheckerTwo : |
Она дальше:
<t id="1042">%0speak text: page=%1 id=%2 priority=%3</t>
|
что-то я не понял... я искал текстовым поиском по всему хмл и не нашел
|
Ну и я тоже текстовым поиском. Дал фару "speak" - он и нашел.
Zman : |
предлагаю компромисс : дополнять не пробелами, а табами с размером 8, я пользуюсь исключительно ФАРом, там это корректно работает...
у тебя на строку добавится 2-3 символа, не больше
|
Ладно, уговорил. Только длина имен процедур и переменных может быть очень большая - тебе к какой позиции комментарий прилепить?
Zman : |
я и говорю - смещение... не надо выбрасывать!, может тогда просто выводить как STRG.000000189 ?
|
А есть глубокий физический смысл? Т.е. ты хочешь сказать, что читабельность текста повысится, если такие адреса помечать с префиксам секций?
Код: |
call59 TX_AUDIO.SpeakWithPriority ; CODE.000009F3 STRG.00000505
|
Zman : |
ну как тебе удобно, лишь бы длина была выровнена
|
Ну, ладно...
Zman : |
я по прежнему не до конца ориентируюсь в языке, больно уж запись переменных в стеке неудобно выглядит
|
Да, эт точно. Код виртуальной машины не для ручной правки.
Zman : |
предлагаю оба куска TX_AUDIO.SetVoicestream1 и TX_AUDIO.SpeakWithPriorityAndNoise здесь подробно рассмотреть и прокомментировать, тогда будет более понятно каким лучше путем подходить.
|
Ну в TX_AUDIO.SetVoicestream1 чего там разбираться-то. Сложили 100 и код локализации, записали в TX_AUDIO.voicestreams[1] - вот и все.
Zman : |
чтобы сохранить логическую последовательность и структуру хотелось бы корректно задавать значения stream page и номер семпла, чтобы можно было использовать несколько адд-он файлов. то есть добавлять различные файлы много раз, чтобы при этом ничего не переделывать. оптимальный вариант: в каждом новом файле стоит свой номер стрима и на него идет ссылка, тогда при открытии будет обращение к нужному файлу.
|
Да, конечно. Но это задача максимум
|
|
|
Zman
65 EGP
![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) Репутация: 12 Сообщения: 54 Откуда: Galaxy far, far away... Зарегистрирован: 17.01.2006
![Вы не можете голосовать](images/tool_cool.gif) |
|
CheckerTwo : |
L0000008 = 0h или вместо case jump L0000008 писать case jump 0.
...
На них управление никогда не передается.
|
я уже разобрался...
проблема в том, что у меня совсем другой x2story.obj !
у меня версия 1.4US... а я сижу и пытаюсь туда подставить LangID=7 и думаю - как же оно может работать ??
а почему бы тебе в диазсме все таки не проверять на 0 и не писать "jump 0h" вместо L0000008 ?
CheckerTwo : |
Она дальше:
<t id="1042">%0speak text: page=%1 id=%2 priority=%3</t>
...
Ну и я тоже текстовым поиском. Дал фару "speak" - он и нашел.
|
короче у меня и .xml какие-то не такие , НЕТУ этой команды, искал везде, включая такой ID, текст "speak" итд
CheckerTwo : |
тебе к какой позиции комментарий прилепить?
|
64
CheckerTwo : |
выводить как STRG.000000189 ?
...
А есть глубокий физический смысл? Т.е. ты хочешь сказать, что читабельность текста повысится, если такие адреса помечать с префиксам секций?
|
как тебе сказать... когда я на той неделе первый раз это увидел, было совсем непонятно , сейчас уже легче, но все равно...
вообщем это не самая большая проблема, оставь на потом
Zman : |
я по прежнему не до конца ориентируюсь в языке, больно уж запись переменных в стеке неудобно выглядит
Да, эт точно. Код виртуальной машины не для ручной правки.
|
основная проблема в том, что у тебя везде идет работа с текущим указателем стека, отсюда появляются такие несуразности как
Код: |
...
push 0
push SP[5] ; arg2
push SP[5] ; arg1
push 2
create_array
push 2
...
|
то есть пушится тот же самый аргумент, а на самом деле разные переменные...
а вот как в полноценном (это не наезд! ) дизасме выглядит :
Код: |
CODE:00444FE8 ; Attributes: bp-based frame
CODE:00444FE8
CODE:00444FE8 sub_444FE8 proc near ; CODE XREF: Forms::TApplication::ShowException(Sysutils::Exception *)+95p
CODE:00444FE8
CODE:00444FE8 Rect = tagRECT ptr -50h
CODE:00444FE8 var_40 = dword ptr -40h
CODE:00444FE8 var_3C = dword ptr -3Ch
CODE:00444FE8 var_38 = dword ptr -38h
CODE:00444FE8 var_34 = dword ptr -34h
CODE:00444FE8 var_30 = dword ptr -30h
CODE:00444FE8 var_18 = dword ptr -18h
CODE:00444FE8 var_14 = dword ptr -14h
CODE:00444FE8 var_10 = dword ptr -10h
CODE:00444FE8 hWnd = dword ptr -0Ch
CODE:00444FE8 var_8 = dword ptr -8
CODE:00444FE8 var_4 = dword ptr -4
CODE:00444FE8 arg_0 = dword ptr 8
CODE:00444FE8
CODE:00444FE8 push ebp
CODE:00444FE9 mov ebp, esp
CODE:00444FEB add esp, 0FFFFFFB0h
CODE:00444FEE push ebx
CODE:00444FEF push esi
CODE:00444FF0 push edi
CODE:00444FF1 mov edi, ecx
CODE:00444FF3 mov esi, edx
CODE:00444FF5 mov [ebp+var_4], eax
CODE:00444FF8 mov ebx, [ebp+arg_0]
CODE:00444FFB call GetActiveWindow
|
то есть при входе в новую функцию указатель стека замораживается в EBP и потом от него легче плясать, а так у тебя в каждой новой строке - новое смещение непонятно куда... слишком много надо держать в голове, в итоге "за деревьями леса не видно"
это просто мысли вслух, я понимаю, что такое написать - надо отдельно помучиться... но мы бы все выиграли, имея более удобный инструмент...
CheckerTwo : |
Ну в TX_AUDIO.SetVoicestream1 чего там разбираться-то. Сложили 100 и код локализации, записали в TX_AUDIO.voicestreams[1] - вот и все.
|
в том то и дело, что у тебя так! а у меня там вообще тихий ужас
я не буду приводить код, потому что там пордяка 40-50 строк...
я только сейчас это понял, посмотрев твой кусок и сравнив с моим...
кто-нибудь может мне объяснить, какая у вас версия файлов ?
все ставили русский патч поверх европейской версии что ли ?
у меня 1.4US, как я уже несколько раз говорил, русский ставить не хотелось бы (люблю оригиналы)... Надо как то договориться и синхронизировать файлы, а то я об одном, а ты о другом
CheckerTwo : |
Zman : |
чтобы сохранить логическую последовательность и структуру хотелось бы корректно задавать значения stream page и номер семпла, чтобы можно было использовать несколько адд-он файлов. то есть добавлять различные файлы много раз, чтобы при этом ничего не переделывать. оптимальный вариант: в каждом новом файле стоит свой номер стрима и на него идет ссылка, тогда при открытии будет обращение к нужному файлу.
|
Да, конечно. Но это задача максимум
|
короче говоря я сегодня потратил время и все проанализировал в исходнике... все никак не мог понять какой там speak with NOISE ??
оказывается это после собщения по радио, после него/или до ? дополнительно играется короткий кусок шума (как при нажимании на кнопку передачи в радио станции ), это вавы с номерами 930.wav 931.wav 932.wav в каталоге S - можете их прогирать отдельно
вот этот кусок в переводе на человеческий язык
Код: |
// play random "communication stop" noise if page id = 1271! or start noise ? :)
L000019DE: SFX_PlaySample( 930, 0, 0, 250, 10, 64 );
goto L00001A7C;
L00001A00: SFX_PlaySample( 931, 0, 0, 250, 10, 64 );
goto L00001A7C
L00001A22: SFX_PlaySample( 932, 0, 0, 250, 10, 64 );
goto L00001A7C
L00001A4A: if Loc1?+1 > 3 then goto L00001A5E;
TX_AUDIO.current_speak_sample :=0;
TX_AUDIO.current_speak_page := 0;
Loc1 := 0;
Exit;
|
но речь не об этом, я кажется нашел нужные нам места!
вот короткий кусок из этой же функции, в переводе на человеческий язык , назовем его кусок 1
Код: |
function TX_AUDIO.SpeakWithPriorityAndNoise( arg1, arg2, arg3, arg4, arg5 );
...
L0000189C: if Loc1 < 0 then goto L00001916;
MOV_GetVoiceStream( SFX_GetLanguage(), arg1 );
// LangID={ 44 | 49 | 7 } - (english/german/russian); arg1 = page id!?
// read "start" value from mov\000LL.xml ?
TX_AUDIO.current_voicestream := TX_AUDIO.voicestreams[0];
// { 00144 | 00149 | 00107 } ?
Loc3 := Loc2 + MOV_GetVoiceLength( SFX_GetLanguage(), arg1, arg2 );
// LangID={ 44 | 49 | 7 }; arg1 = page id!? arg2 = itemid ?
// read "length" from mov\000LL.xml ?
goto L0000196C
|
судя по всему это кусок, где читаются параметры голосового сообщения (начало и длина), эти данные в файлах mov\000LL.xml
потом идет куча всяких проверок, и вот сам проигрыш участка:
назовем его кусок 2
Код: |
L00001B9A: if TX_AUDIO.current_voicestream = 0 then goto L00001BD2;
if MOV_PlayMovieVoice( TX_AUDIO.current_voicestream, SFX_GetLanguage(), arg1, arg2 ) = 0 then goto L00001BD2;
// arg1 = page id!? arg2 = itemid ?
|
именно в этих двух местах и задается откуда читать звуковое сообщение!
теперь у меня такое предложение по сруктуре изменений:
ИМХО лучше всего, легче всего и нагляднее всего использовать специальные page ID для новых звуков и на основе них открывать нужные файлы.
я проверил существующие сейчас в игре page ID:
max page ID = 2040; (и звуки, и все остальное)
прделагаю сделать так:
1) зарезервировать для новых моддерских звуков page ID = [10002..10999];
2) пропатчить x2story.obj так, чтобы
2a) все старые/оригинальные pageID (которые всегда <10000) игрались как и раньше из файла mov\001LL.dat
2b) новые page ID обрабатывались таким образом, чтобы:
Код: |
pageID = 10002, filename = mov\002LL.dat
pageID = 10003, filename = mov\003LL.dat
pageID = 10004, filename = mov\004LL.dat
...
pageID = 10998, filename = mov\998LL.dat
pageID = 10999, filename = mov\999LL.dat
|
то есть по формуле:
Код: |
if PageID > 10001
then
filename := (PageID-10000)*100+LanguageID
else
filename := LanguageID+100;
|
PageID=10001 таким образом использовать нельзя, чтобы он не перекрывался с существующим файлом mov\001LL.dat
при таком подходе мы получим гибкое решение и два варианта использования:
1) каждый, кто хочет сделать свой мод, присваивает фиксированный pageID и сам следит, чтобы он не пересекался с другими установленными модами на этой машине
2) если мы хотим моды распространять, тогда надо к файлам
mov\PPPLL.xml
mov\PPPLL.dat
дополнительно в моде держать инсталлятор, который будет проверять уже установленные PageID, и при установке патчить новые файлы, чтобы увеличивать PageID. После установки это новое максимальное значение можно сохранить в файле или в реестре и при установке следующего мода брать оттуда же. Таким образом мы получим 998 возможных апгрейдов на одну машину
у кого есть другие предложения ?
_________________ THX2U |
|
|
Zman
65 EGP
![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) Репутация: 12 Сообщения: 54 Откуда: Galaxy far, far away... Зарегистрирован: 17.01.2006
![Вы не можете голосовать](images/tool_cool.gif) |
|
да, забыл совсем...
я заменил все L0000008, но все равно не компилируется
вот список ошибок
pass2:(x2story.asm:9737) Err: Command SETMEM without a label.
pass2:(x2story.asm:21359) Err: Command SETMEM without a label.
pass2:(x2story.asm:22038) Err: Command SETMEM without a label.
pass2:(x2story.asm:32641) Err: Error in command or expression.
pass2:(x2story.asm:32642) Err: Invalid command.
pass2:(x2story.asm:144775) Err: Undefined identifier 'Cmd_EscortObject_T'.
pass2:(x2story.asm:183245) Err: Undefined identifier 'SetLatency'.
pass2:(x2story.asm:187447) Err: Undefined identifier 'SetLeader'.
pass2:(x2story.asm:187458) Err: Undefined identifier 'SetRelativePos'.
pass2:(x2story.asm:187470) Err: Undefined identifier 'SetRelativePos'.
pass2:(x2story.asm:193411) Err: Error in command or expression.
pass2:(x2story.asm:193412) Err: Invalid command.
pass2:(x2story.asm:196890) Err: Undefined identifier 'S000657B'.
pass2:(x2story.asm:315003) Err: Undefined identifier 'GetQtyLogRecords'.
pass2:(x2story.asm:315018) Err: Undefined identifier 'GetLogRecord'.
pass2:(x2story.asm:393024) Err: Undefined identifier 'DisableAnswer'.
pass2:(x2story.asm:407452) Err: Error in string.
pass2:(x2story.asm:407453) Err: Error in command or expression.
pass2:(x2story.asm:407454) Err: Invalid command.
причем я эти места посмотрел - ничего особо криминального нет, как сгенерилось, так и написано, я ничего не правил
в одном место точно знаю почему ошибка!
CheckerTwo, у тебя длина строки 255, когда ты читаешь исохдник .asm в ассемблере, а там есть строки и длинее!
_________________ THX2U |
|
|
AlexYar
1848 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (20 лет)](/conference/images/ranks/medals/veteran20.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Создатель модов для X2 (+25 EGP)](/conference/images/ranks/medals/x2_mods.gif) ![Лучший пилот вселенной Х года 2005 (+50 EGP)](/conference/images/ranks/medals/xt.gif) ![Создатель модов для X3: Reunion (+30 EGP)](/conference/images/ranks/medals/x3_mods.gif) ![Знаток Х3: Reunion (+15 EGP)](/conference/images/ranks/medals/x3_turn.gif) ![Знаток игр 2010 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Знаток игр 2011 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Заслуженный знаток игр (+25 EGP)](/conference/images/ranks/medals/kdi_znatok.png) ![Активист (+25 EGP)](/conference/images/ranks/medals/activist.gif) ![Знаток игр 2016 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Лучший пилот вселенной Х года 2017 (+50 EGP)](/conference/images/ranks/medals/xt.gif) ![Знаток игр 2017 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Знаток Elite: Dangerous (+15 EGP)](/conference/images/ranks/medals/ed_expert.png) Рейтинг канала: 6(434) Репутация: 328 Сообщения: 31540
Зарегистрирован: 26.10.2003
![Вы не можете голосовать](images/tool_cool.gif) |
|
Zman : |
у меня версия 1.4US... а я сижу и пытаюсь туда подставить LangID=7 и думаю - как же оно может работать ??
|
Работать может. В корне игры создай файл Lang.dat (текстовый), чтобы в нем была только цифра 7.
Zman : |
короче у меня и .xml какие-то не такие , НЕТУ этой команды, искал везде, включая такой ID, текст "speak" итд
|
Похоже, что у тебя не 1.4US версия, а неправильно пропатченная 1.3 Поэтому и не сходится ничего.
Zman : |
все ставили русский патч поверх европейской версии что ли ?
|
Нет. Европейский патч на американку ставить нельзя, так же нельзя европейский патч ставить на русскую версию.
Здесь у всех либо:
1. US патч на Русскую (от НД)
2. Рус патч на Русскую (Патч от НД на НД)
3. US на US.
Европеек вроде нет ни у кого. Европейка - кастрат.
Вобщем - игру тебе надо переустанавливать, так как у тебя сборная солянка глюкобагов, а не игра Ставь All_In_One на свою игру, и все вопросы отпадут.
Оригинальный x2story.obj версии 1.4 имеет размер 1750848 байт.
Zman : |
оказывается это после собщения по радио, после него/или до ? дополнительно играется короткий кусок шума (как при нажимании на кнопку передачи в радио станции), это вавы с номерами 930.wav 931.wav 932.wav в каталоге S - можете их прогирать отдельно
|
В 1.4 версии нет микшевания шумов ни к голосам, ни к звукам.
Zman : |
2) если мы хотим моды распространять, тогда надо к файламmov\PPPLL.xmlmov\PPPLL.datдополнительно в моде держать инсталлятор, который будет проверять уже установленные PageID, и при установке патчить новые файлы, чтобы увеличивать PageID.
|
Зачем? Я же уже говорил, что не существует двух модов, которые бы были совместимы друг с другом (о скриптах не говорю). Поэтому установка двух и более модов исключена в принципе.
В крайнем случае тот, кто сам своими руками путем глубокого моддинга решит на своей машине скрестить несколько модов, то если у него хватит знаний и умений для этого, то уж для правки адресов озвучки у него само-собой тоже хватит знаний и умений.
Поэтому инсталлер только ради озвучки не нужен, он ничего не даст.
Zman : |
1) зарезервировать для новых моддерских звуков page ID = [10002..10999];
|
Ты не понял концепции организации озвучки. Ничего резервировать нельзя, новая озвучка должна работать и для всех старых страниц и ИД! Никаких 10000-10999. А если кто-то захочет новую озвучку для названий старых секторов ввести? Их страницу и ИД менять категорически нельзя, они строго фиксированы для игры.
В PAGE и ID никаких проблем и так нет. Они берутся любые.
Проблема - в файле разметки! Который лежит в папке mov. Вот этот файл должен быть так же отдельный свой для каждого мода. И в нем номера страниц и ИД только дублируют номера из основного файл-описателя из папки T.
И задача - не только читать новый *.dat , но и новый *.xml к этому dat-у.
Т.е. вся задача сводится к простому -
1. При старте новой игры или загрузке сохраненки игра проверяет наличие всех существующих файлов разметки (*.xml) в папке MOV и
2. грузит одноименные файлы звука (*.dat).
Причем приоритет у файла-разметки 00207.xml должен быть больше приоритета файла-разметки 00007.xml, т.е. повторяющиеся страницы и ИД должны браться из файла с большей цифрой в третьем знаке.
Т.е. точно так же, как и с файлами-описателями из папки T.
Пример:
Т.е. если в файле 00007.xml написано:
<page id="101" stream="1">
<t id="1" s="0" l="2202"/>
а в файле 00207.xml написано:
<page id="101" stream="2">
<t id="1" s="0" l="2202"/>
то звук для ID=1 должен браться из файла 00207.dat !
Так же следует учесть, что у первого файла-разметки нет цифры "1" в имени, а у всех остальных должна быть своя цифра, повторяющая имя файла со звуком.
И еще главное - не путайте xml-файлы описатели из папки T с xml-файлами разметки из папки MOV, а то я смотрю уже всё в кучу смешано.
Файлы описатели из папки Т к этой задаче не имеют вообще никакого отношения. Не надо их трогать и тем более - вводить ограничения на номера page и id.
|
|
|
Zman
65 EGP
![Ветеран Elite-Games (15 лет)](/conference/images/ranks/medals/veteran15.png) Репутация: 12 Сообщения: 54 Откуда: Galaxy far, far away... Зарегистрирован: 17.01.2006
![Вы не можете голосовать](images/tool_cool.gif) |
|
AlexYar : |
Похоже, что у тебя не 1.4US версия, а неправильно пропатченная 1.3 Поэтому и не сходится ничего.
|
у меня 2-х дисковая версия от девианс, потом поверх нее последовательно патчи 1.1 1.2 1.3 1.4US, потом "x2.exe - 1.4US noCD official"
больше ничего
AlexYar : |
Вобщем - игру тебе надо переустанавливать, так как у тебя сборная солянка глюкобагов, а не игра Ставь All_In_One на свою игру, и все вопросы отпадут.
|
пока сюжет не пройду - не буду ничего менять, а то сейвы пропадут
AlexYar : |
Оригинальный x2story.obj версии 1.4 имеет размер 1750848 байт.
|
спасибо, проверю
AlexYar : |
В 1.4 версии нет микшевания шумов ни к голосам, ни к звукам.
|
не "к", а после!
то есть читается сообщение, потом щелчок, как будто связь отключается
(ну или сначала щелчок, потом сообщение )
AlexYar : |
Поэтому установка двух и более модов исключена в принципе.
|
это точно ? все согласны ?
кстати говоря есть в самой игре возможность установки модов, я правда не смотрел как это делать.... факт что сканируется mod\*.cat
AlexYar : |
А если кто-то захочет новую озвучку для названий старых секторов ввести? Их страницу и ИД менять категорически нельзя, они строго фиксированы для игры.
|
мне казолось речь идет о дополнительных звуках, а не замене сушествующих ?
если ты хочешь заменить сушествующие звуки - надо заменить существующие mov\001LL.dat mov\001LL.mov, какой смысл класть второй дополнительный файл, если старый не будет использоваться ?
AlexYar : |
И задача - не только читать новый *.dat , но и новый *.xml к этому dat-у
|
ну это было ясно изначально...
AlexYar : |
1. При старте новой игры или загрузке сохраненки игра проверяет наличие всех существующих файлов разметки (*.xml) в папке MOV и
2. грузит одноименные файлы звука (*.dat).
Причем приоритет у файла-разметки 00207.xml должен быть больше приоритета файла-разметки 00007.xml, т.е. повторяющиеся страницы и ИД должны браться из файла с большей цифрой в третьем знаке.
|
начсет приоритетов я думаю будет довольно сложно....
AlexYar : |
И еще главное - не путайте xml-файлы описатели из папки T с xml-файлами разметки из папки MOV, а то я смотрю уже всё в кучу смешано.
|
кто где путает ?
вся структура прозрачна и понятна... вот у меня на бумажке расписано
AlexYar : |
Файлы описатели из папки Т к этой задаче не имеют вообще никакого отношения. Не надо их трогать и тем более - вводить ограничения на номера page и id.
|
а если ты захотел добавить новые сообщения вместе с субтитрами ?
все равно и там тоже надо менять что-то...
вообщем по-моему мы хотим разного
давайте тогда точно определяться, пусть все заинтересованые выскажутся плиз
_________________ THX2U |
|
|
AlexYar
1848 EGP
![Золотая звезда (+100 EGP)](/conference/images/ranks/medals/gold.gif) ![Ветеран Elite-Games (20 лет)](/conference/images/ranks/medals/veteran20.png) ![Автор программы под X-Tension (+25 EGP)](/conference/images/ranks/medals/xt_prog.gif) ![Создатель модов для X2 (+25 EGP)](/conference/images/ranks/medals/x2_mods.gif) ![Лучший пилот вселенной Х года 2005 (+50 EGP)](/conference/images/ranks/medals/xt.gif) ![Создатель модов для X3: Reunion (+30 EGP)](/conference/images/ranks/medals/x3_mods.gif) ![Знаток Х3: Reunion (+15 EGP)](/conference/images/ranks/medals/x3_turn.gif) ![Знаток игр 2010 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Знаток игр 2011 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Заслуженный знаток игр (+25 EGP)](/conference/images/ranks/medals/kdi_znatok.png) ![Активист (+25 EGP)](/conference/images/ranks/medals/activist.gif) ![Знаток игр 2016 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Лучший пилот вселенной Х года 2017 (+50 EGP)](/conference/images/ranks/medals/xt.gif) ![Знаток игр 2017 года (+50 EGP)](/conference/images/ranks/medals/kdi_znatok_god.png) ![Знаток Elite: Dangerous (+15 EGP)](/conference/images/ranks/medals/ed_expert.png) Рейтинг канала: 6(434) Репутация: 328 Сообщения: 31540
Зарегистрирован: 26.10.2003
![Вы не можете голосовать](images/tool_cool.gif) |
|
Zman : |
потом поверх нее последовательно патчи 1.1 1.2 1.3 1.4US
|
Ну вот 1.4 как раз у тебя и не встал. Торговые станции и Доки оборудования продаются на верфях? Миссии по вторжению ксенонов есть? На станциях доп.слоты в консоли есть?
Поставь АИО сразу на 1.0 версию (есть АИО 1.0-1.4), и всё будет в ажуре Сейвы не должны попортиться (сохрани на всяк пож.).
Zman : |
то есть читается сообщение, потом щелчок, как будто связь отключается(ну или сначала щелчок, потом сообщение
|
К видеокартинке "нуаз" добавляется (помеха), это точно. А чтобы к голосу звук - не замечал ни разу (даже сам хотел приделать).
Zman : |
кстати говоря есть в самой игре возможность установки модов, я правда не смотрел как это делать....
|
В папку Mods в корне игры кидаются запакованные моды и по одиночке подключаются. Т.е. подключение одновременно двух модов невозможно.
К тому же, если кто будет клеить моды, тот и озвучку склеит. Делов-то.
Zman : |
мне казолось речь идет о дополнительных звуках, а не замене сушествующих ?
|
Замена существующих - основа создания чего-то нового. Это обязательное условие. А уж добавление новых - это придаток.
Zman : |
если ты хочешь заменить сушествующие звуки - надо заменить существующие mov\001LL.dat mov\001LL.mov, какой смысл класть второй дополнительный файл, если старый не будет использоваться ?
|
Ответ прост - размер файла. Если я хочу изменить всего пару десятков старых звучков, то неужели я своим плохоньким мопедом буду в инет пихать файло на 140 Мегабайт? И других заставлять его скачивать?
В том-то и соль - сделать возможность считывания нового маленького файла озвучки, чтобы выборочно заменить старые звуки новыми (а не целиком весь файл).
Zman : |
начсет приоритетов я думаю будет довольно сложно....
|
Я дополнил предыдущее сообщение примером. Работу с приоритетами можно скатать с функций считывания файл-описателей из папки T.
Т.е. сделать по образу и подобию.
Zman : |
а если ты захотел добавить новые сообщения вместе с субтитрами ?все равно и там тоже надо менять что-то...
|
Новые сообщения, которые будут дублироваться субтитрами, я добавлю в новый файл описатель (70009 к примеру), и игра будет брать новые тексты оттуда (игре пофиг откуда тексты брать). Главное, чтобы она речевое сообщение к этому тексту по его PAGE и ID считала из 00207.xml и 00207.dat соответственно, даже если старое с этой PAGE и ID есть в 00007.xml и 00107.dat.
Понятна суть?
Zman : |
вообщем по-моему мы хотим разного
|
Нет. Просто у тебя недостаточно информации по устройству игры. Но это дело поправимое
И определяться тут нечего, надо делать. Причем делать не новые ограничения, а делать новые возможности
|
|
|
|
|
|
Канал X2: The Threat: «X2-ASM - это проcто!» |
|
К списку каналов | Наверх страницы |
Цитата не в тему: Люди, знайте, если никак на конфу не зайти - значит, наша администрация играет на серваке в Дум 3 (void*)
|
» X2-ASM - это проcто! | страница 1 |
|