Elite Games - Свобода среди звезд!
.
  » X2-ASM - это проcто! | страница 1
Конференция предназначена для общения пилотов. Для удобства она разделена на каналы, каждый из которых посвящен определенной игре. Пожалуйста, открывайте темы только в соответствующих каналах и после того, как убедитесь, что данный вопрос не обсуждался ранее.

Поиск | Правила конференции | Фотоальбом | Регистрация | Список пилотов | Профиль | Войти и проверить личные сообщения | Вход

   Страница 1 из 12
На страницу: 1, 2, 3 ... 10, 11, 12  След.    Перейти:   Все страницы
Поиск в этой теме:
Канал X2: The Threat: «X2-ASM - это проcто!»
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Добрый день, добрый! Улыбка

Небольшой ассемблер, который позволяет патчить 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
 Описание:
Ассемблер. Версия 03.32b
 Имя файла:  xa3_32.zip
 Размер файла:  114.68 KB
 Скачано:  629 раз(а)
do3_29.zip
 Описание:
Дизассемблер. Версия 03.29b
 Имя файла:  do3_29.zip
 Размер файла:  101.04 KB
 Скачано:  709 раз(а)


Последний раз редактировалось: CheckerTwo (16:35 12-03-2011), всего редактировалось 20 раз(а)
    Добавлено: 08:36 05-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Пример номер 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
    Добавлено: 08:39 05-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Небольшое вступление и замечания.

Команды, сохраняющие значение в стеке, сначала инкрементируют указатель стека, затем записывают в стек значение. Например, команду 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 раз
    Добавлено: 08:47 05-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Работа с переменными.

Переменные в Х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.
    Добавлено: 17:04 06-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Маленькие трюки: Изменение размера доступного функции стека.

Всякая функция начинается с объявления директивой .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.
    Добавлено: 08:50 16-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Маленькие трюки: правка переходов команды 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

    Добавлено: 09:20 16-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Маленькие трюки: Локальные метки.

В некоторых случаях, особенно при больших программах, в командах переходов удобно пользоваться так называемыми локальными метками, для того, что бы не изобретать новых имен под метки. Блок локальных меток (т.е. часть программы, где доступны эти метки) ограничивается двумя нелокальными метками, либо директивами определения секции.
Локальные метки начинаются с символа '$' и содержат только цифры.
Например метка $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

В этом примере функции отличаются незначительно, выдумывать уникальные имена меток переходов неинтересно. Так что вот. Улыбка
    Добавлено: 09:34 16-10-2005   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
> Все какие-то пуши-попы, а что-нибудь полезное будет когда-нибудь?
> Все это конечно интересно, но хочется чего-то более...
Улыбка
Эх, со временем напряг. Ну, хорошо. Давайте напишем какой-нибудь
полезный пример.
Допустим мы написали какой-то интересный патч. Запустили - не работает.
Что нужно в первую очередь? Посмотреть - какие значения у переменных и
вообще выполняются ли условия и пр... Напишем маленькую библиотечку,
которая немного упростит отладку нашей программы.

Вывод на экран значения переменной и текстовую строку простым способом
получить не удалось. Возможно это связано с тем, что этот тупой вывод
на экран инфы тут же затирается с частотой нашего 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
    Добавлено: 11:26 16-10-2005   
Shaddie
 550 EGP


Рейтинг канала: 4(60)
Репутация: 118
Сообщения: 259
Откуда: Томск
Зарегистрирован: 09.09.2004
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
 Скачано:  838 раз(а)
    Добавлено: 13:18 19-01-2006   
Zman
 65 EGP

Репутация: 12
Сообщения: 54
Откуда: Galaxy far, far away...
Зарегистрирован: 17.01.2006
народ, есть вопросы по асму! (перенес из соседней темы)

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
    Добавлено: 18:01 22-01-2006   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
Shaddie :
Применение.


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.
    Добавлено: 16:30 23-01-2006   
Zman
 65 EGP

Репутация: 12
Сообщения: 54
Откуда: Galaxy far, far away...
Зарегистрирован: 17.01.2006
появились еще вопросы по дизассемблеру 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
    Добавлено: 16:38 23-01-2006   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
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"

Спасибо!
    Добавлено: 17:01 23-01-2006   
Zman
 65 EGP

Репутация: 12
Сообщения: 54
Откуда: Galaxy far, far away...
Зарегистрирован: 17.01.2006
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
    Добавлено: 17:09 23-01-2006   
CheckerTwo
 550 EGP


Рейтинг канала: 4(96)
Репутация: 103
Сообщения: 412
Откуда: Tomsk
Зарегистрирован: 18.08.2004
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 и номер семпла, чтобы можно было использовать несколько адд-он файлов. то есть добавлять различные файлы много раз, чтобы при этом ничего не переделывать. оптимальный вариант: в каждом новом файле стоит свой номер стрима и на него идет ссылка, тогда при открытии будет обращение к нужному файлу.

Да, конечно. Но это задача максимум Улыбка
    Добавлено: 17:34 23-01-2006   
Zman
 65 EGP

Репутация: 12
Сообщения: 54
Откуда: Galaxy far, far away...
Зарегистрирован: 17.01.2006
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
    Добавлено: 16:09 24-01-2006   
Zman
 65 EGP

Репутация: 12
Сообщения: 54
Откуда: Galaxy far, far away...
Зарегистрирован: 17.01.2006
да, забыл совсем...
я заменил все 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
    Добавлено: 16:26 24-01-2006   
AlexYar
 1605 EGP


Рейтинг канала: 6(409)
Репутация: 342
Сообщения: 24593

Зарегистрирован: 26.10.2003
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.
    Добавлено: 17:42 24-01-2006   
Zman
 65 EGP

Репутация: 12
Сообщения: 54
Откуда: Galaxy far, far away...
Зарегистрирован: 17.01.2006
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
    Добавлено: 18:15 24-01-2006   
AlexYar
 1605 EGP


Рейтинг канала: 6(409)
Репутация: 342
Сообщения: 24593

Зарегистрирован: 26.10.2003
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 :
вообщем по-моему мы хотим разного


Нет. Просто у тебя недостаточно информации по устройству игры. Но это дело поправимое Да.

И определяться тут нечего, надо делать. Причем делать не новые ограничения, а делать новые возможности Улыбка
    Добавлено: 19:30 24-01-2006   
Канал X2: The Threat: «X2-ASM - это проcто!»
На страницу: 1, 2, 3 ... 10, 11, 12  След.    Перейти:   Все страницы
  
Показать: 
Предыдущая тема | Следующая тема |
К списку каналов | Наверх страницы
Цитата не в тему: Меня уже вторую неделю в чат не пускает!.. (жалуется Corund, создатель чата.)

  » X2-ASM - это проcто! | страница 1
Каналы: Новости | Elite | Elite: Dangerous | Freelancer | Star Citizen | X-Tension/X-BTF | X2: The Threat | X3: Reunion | X3: Terran Conflict | X Rebirth | EVE Online | Orbiter | Kerbal Space Program | Evochron | VoidExpanse | Космические Миры | Онлайновые игры | Другие игры | Цифровая дистрибуция | play.elite-games.ru | ЗВ 2: Гражданская война | Творчество | Железо | Игра Мечты | Сайт
   Дизайн Elite Games V5 beta.18