Просмотр сообщений

В этом разделе можно просмотреть все сообщения, сделанные этим пользователем.


Сообщения - SeregaZ

Страницы: [1] 2 3 4 5 ... 79 Далее
1
да я тоже не понимаю зачем ты делаешь свой плагин к иде. но ты ведь его делаешь :) значит оно кому-то нужно. в смысле весь этот бред с костылями - ида, питон, плагин, эмулятор... бред собачий :) делай сразу единую ОДНУ прогу, без костылей и ошибок. сразу чтоб в одном флаконе было и эмулятор, и весь разбор, и нормальное сохранение, и сразу компилер, и чтоб все происходило в памяти, без создания временных файлов на диске. (главное конечно чтоб ошибок в коде не рожало. типа как сейчас прозевал разницу .s и .w кажись... где-то там... забыл где. jsr наверное. где джамп сам на себя какой-то корявый. и еще что-то там, уже всё и не упомню...)


Отвлеклись. Продолжаем упарываться. То что уже сделано, то есть общая конструкция - можно сказать это уже готовый патчер для рома. Типа нам что-то известно - адреса и значения, и этим проектом можно что-то там исправить по известным адресам, втуливая туда нужные исправленные значения. Однако продолжая тему GUI - хотелось бы сделать программу более вежливой, а именно добавить диалоги указания файла к примеру. Или сделать окошко для ввода ручками на теле программы значения какого-то параметра. И только потом уже делать сохранение.

В начале определяемся с внешним видом окна. Берем в руки пейнт и рисуем что мы там хотим увидеть. Думаю должно быть что-то типа такого:



На первоначальном этапе тип пусть так и остается long - 4 байта. А чтобы не держать файл рома открытым все это время - прочитаем его в образ в памяти и будем работать с ним оттуда, а не с жесткого диска. Типа если вдруг что-то пойдет не так, то оригинальный файл мы не повредим... точнее повредим конечно, но в момент записи. А до этого - чтение файла (ReadFile) будет вполне себе безопасным.

Память.
Чтобы с ней работать - нужно сначала её зарезервировать: AllocateMemory. Это как бы объяснить... у нас есть картина метр на метр. Чтобы с ней успешно работать - нужен стол в мастерской, размером не меньше метр на метр. Вот это резервирование и есть как бы создание стола, куда мы положим наш квадрат Малевича и будем с ним работать. А так запись и чтение происходит аналогично как в случае с файлом, только что главное нам не вылезьти за размеры этого стола, иначе наступит конец света. Так-же разница между работой с файлом и памятью заключается в том, что надо отдельно отслеживать позицию куда мы пишем или читаем из памяти. Если с файлом что-то читается, то позиция сама автоматически сдвигается дальше - это как глаз, который читает текст - то есть прочитал слово, а глаз сам прыгнул на начало следующего слова и читает дальше. Вот в случае с памятью это не работает и надо отдельно вести счетчик где мы читаем и работать уже с ним.

Еще там будут нюансы с окошком диалога выбора пути до нужного файла. Там можно будет выставить ограничение на показ файлов - вместо *.* поставить что-то конкретное. Хочу поставить *.bin чтобы показывались только ромы, без всяких прочих других файлов типа exe, картинок, музыки...

Для окошек ввода текста поставим ограничение на ввод больших букв (параметр #PB_String_UpperCase), чтобы было что-то типа 45A4C1 вместо 45a4c1... А окошку "значение из файла" дополнительно поставим флаг "только для чтения" #PB_String_ReadOnly.

Хм... пока писал код - понял, что нужна отдельно кнопка "считать". Чтобы после ввода адреса в окошко её нажать, чтобы система прочитала из памяти по нужном адресу и вывела в окошке. Старость :)

; перечисление окон, гаджетов и файлов
Enumeration
  #Window
 
  #TextPutDoRoma
  #StrokaPutDoRoma
  #KnopkaPutDoRoma
 
  #TextAdresParametra
  #TextAdrerParametra2 ; значок доллара будет
  #StrokaAdresParametra
 
  #TextZnachenieParametra
  #TextZnachenieParametra2 ; $ 
  #StrokaZnachenieParametra
  #ProchitatZnachenieParametra
 
  #TextNovoeZnachenie
  #TextNovoeZnachenie2 ; $ 
  #StrokaNovoeZnachenie
  #ZadatNovoeZnachenie 
 
  #File
EndEnumeration


; создание окна
If OpenWindow(#Window, 100, 100, 410, 155, "Я у мамы программист.", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
 
  ; рисуем гаджеты на окне
 
 
  ; текстовой с надписью путь до рома
  TextGadget(#TextPutDoRoma, 10, 10, 200, 20, "путь до рома:") 
  ; строчка, куда мы будем указывать путь, выбранный через кнопку "обзор"
  StringGadget(#StrokaPutDoRoma, 10, 30, 330, 20, "", #PB_String_ReadOnly) 
  ; сама кнопка обзор
  ButtonGadget(#KnopkaPutDoRoma, 350, 30, 50, 20, "обзор")
 
 
  ; адрес параметра
  TextGadget(#TextAdresParametra, 25, 70, 70, 20, "адр. парам.:")
  ; доллар. без америки никуда. 92 - чуть ниже чем 90, чтобы визуально доллар был на одной линии
  TextGadget(#TextAdrerParametra2, 10, 92, 20, 20, "$")
  ; само окошко ввода адреса
  StringGadget(#StrokaAdresParametra, 25, 90, 70, 20, "", #PB_String_UpperCase)
 
  ; значение из файла
  TextGadget(#TextZnachenieParametra, 135, 70, 70, 20, "значение:")
  ; доллар.
  TextGadget(#TextZnachenieParametra2, 120, 92, 20, 20, "$")
  ; окошко адреса из файла
  StringGadget(#StrokaZnachenieParametra, 135, 90, 70, 20, "", #PB_String_UpperCase | #PB_String_ReadOnly)
  ; кнопка прочитать
  ButtonGadget(#ProchitatZnachenieParametra, 80, 120, 70, 20, "прочитать")
 
 
  ; новое значение
  TextGadget(#TextNovoeZnachenie, 250, 70, 70, 20, "новое знач.:")
  ; доллар.
  TextGadget(#TextNovoeZnachenie2, 235, 92, 20, 20, "$")
  ; окошко нового значения
  StringGadget(#StrokaNovoeZnachenie, 250, 90, 70, 20, "", #PB_String_UpperCase)
  ; кнопка задать
  ButtonGadget(#ZadatNovoeZnachenie, 330, 90, 70, 20, "задать")
 
 
  ; бесконечный цикл обработки событий окна
  Repeat
   
     ; определяем с чем именно мы имеем дело
     Select WaitWindowEvent()
         
       ; событие касается какого-то гаджета 
       Case #PB_Event_Gadget
         
         ; раз событие касается гаджетов, то надо перебрать какой именно гаджет имеет это событие
         Select EventGadget()
             
           Case #KnopkaPutDoRoma
             ;{ событие на кнопке указания пути до рома
             
             If EventType() = #PB_EventType_LeftClick
               ; если событие клик левой кнопкой мышки

               ; открываем диалог указания пути до файла рома
               PutDoRoma$ = OpenFileRequester("укажите путь до файла рома", "", "Rom bin file | *.bin", 0)
               If PutDoRoma$
                 ; если путь все-таки был указан, то...
                 
                 If ReadFile(#File, PutDoRoma$)
                   ; если файл прочитался, то...
                   
                   ; в начале сбрасываем память, а то может мы уже второй ром открываем.
                   ; то есть возможно в памяти уже висит старый ром,
                   ; а значит надо освободить старую память
                   If *MemoryID
                     FreeMemory(*MemoryID)
                     *MemoryID = 0
                   EndIf
                   ; далее зачистить окошки адреса и того старого значения. а так-же нового.
                   SetGadgetText(#StrokaAdresParametra, "")
                   SetGadgetText(#StrokaZnachenieParametra, "")
                   SetGadgetText(#StrokaNovoeZnachenie, "")
                   
                   ; получаем размер файла
                   length = Lof(#File)
                   
                   If length
                     ; если размер файла больше нуля.
                     ; эта проверка на случай если файл поврежден.
                     
                     ; резервируем память по размеру файла
                     *MemoryID = AllocateMemory(length)
                     
                     If *MemoryID
                       ; если память зарезервировалась, то все хорошо. играем дальше.
                       
                       ; читаем файл с жесткого диска в подготовленную память
                       ; то есть файл - #File, в какую память - *MemoryID, размер сколько читать - length.
                       ReadData(#File, *MemoryID, length)
                       
                       ; раз у нас есть чтение чего-то в память, значит делаем вывод что все хорошо
                       ; указываем путь в окошке для пути
                       SetGadgetText(#StrokaPutDoRoma, PutDoRoma$)
                       
                     Else
                       ; какая-то ошибка с памятью. опять выводим окошко с ошибкой.
                       MessageRequester("ошибка", "проблема с резервированием памяти.")                       
                     EndIf
                     
                   Else
                     ; выходит размер файла все-таки 0. значит ошибка. вывести предупреждение.
                     MessageRequester("ошибка", "файл рома видимо поврежден и имеет размер 0 байт.")
                   EndIf
                   
                   ; закрываем файл
                   CloseFile(#File)
                   
                 Else
                   ; выходит файл прочитать не смогли
                   MessageRequester("ошибка", "файл не может быть прочитан. возможно занят другой программой.")
                 EndIf
                   
               EndIf
               
             EndIf
             ;}
             
           Case #ProchitatZnachenieParametra
             ;{ кнопка прочитать из памяти значение по какому-то адресу
             If EventType() = #PB_EventType_LeftClick
               ; если событие клик левой кнопкой мышки
               
               ; надо удостоверится, что файл рома был считан и существует память, куда все записалось
               If length And *MemoryID
                 
                 ; надо удостоверися, что у нас есть адрес откуда читать
                 Address$ = GetGadgetText(#StrokaAdresParametra)
                 If Address$
                   ; надо перевести текст адреса в число
                   ; и сравнить нет ли превышения размера рома length
                   ; чтобы не начать читать за пределами нужной памяти
                   
                   ; к текстовому значению Address$ был прибавлен символ доллара,
                   ; чтобы команда Val поняла, что текст это хекс, а не обычные десятичные числа
                   Address = Val("$" + Address$)
                   
                   If Address < length
                     ; все в порядке. адрес в нужных пределах рома
                     
                     ; просчитываем место в памяти, откуда следует читать
                     mem = *MemoryID + Address
                     ; читаем 4 байта из памяти по одному байту и сдвигаем итоговое значение
                     Result = PeekA(mem) << 8
                     Result | PeekA(mem + 1)
                     Result << 8
                     Result | PeekA(mem + 2)
                     Result << 8
                     Result | PeekA(mem + 3)
                     
                     ; выводим в окошке на теле программы итоговое значение с переводом в хекс
                     SetGadgetText(#StrokaZnachenieParametra, Hex(Result, #PB_Long))
                     
                   Else
                     ; превышение. выдать предупреждение.
                     MessageRequester("ошибка", "вы пытаетесь прочитать за пределами файла рома.")
                   EndIf
                   
                 Else
                   ; нет адреса, откуда читать.
                   MessageRequester("ошибка", "кто-то забыл указать адрес откуда нам читать (1C английскими).")

                 EndIf
                 
               Else
                 ; ром еще видимо незагружен
                 MessageRequester("ошибка", "ром еще не был загружен.")
               EndIf
               
             EndIf
             ;}
             
           Case #ZadatNovoeZnachenie
             ;{ кнопка внести новое значение в файл
             If EventType() = #PB_EventType_LeftClick
               ; если событие клик левой кнопкой мышки
               
               ; надо удостоверится, что файл рома был считан и существует память, куда все записалось
               If length And *MemoryID
                 
                 ; надо удостоверися, что у нас есть адрес куда писать
                 Address$ = GetGadgetText(#StrokaAdresParametra)
                 If Address$
                   ; надо перевести текст адреса в число
                   ; и сравнить нет ли превышения размера рома length
                   ; чтобы не начать писать за пределами нужной памяти
                   
                   ; к текстовому значению Address$ был прибавлен символ доллара,
                   ; чтобы команда Val поняла, что текст это хекс, а не обычные десятичные числа
                   Address = Val("$" + Address$)
                   
                   If Address < length
                     ; все в порядке. адрес в нужных пределах рома
                     
                     ; просчитываем место в памяти, куда следует писать
                     mem = *MemoryID + Address
                     
                     ; проверяем есть ли какое-то число в окошке, которое нам надо записать в память
                     Zapis$ = GetGadgetText(#StrokaNovoeZnachenie)
                     ; по старой схеме переводим текст в число, с учетом что это хекс, а не десятичное
                     Zapis = Val("$" + Zapis$)
                     ; разбиваем значение на 4 байта
                     first.a = Zapis >> 24
                     secnd.a = Zapis >> 16
                     third.a = Zapis >> 8
                     fourd.a = Zapis
                     ; пишем в память
                     PokeA(mem, first)
                     PokeA(mem + 1, secnd)
                     PokeA(mem + 2, third)
                     PokeA(mem + 3, fourd)
                     
                     ; вроде как в памяти у нас уже сидит новое значение.
                     ; значит надо перезаписать весь файл целиком
                     ; читаем путь до рома из окошка в программе
                     PutDoRoma2$ = GetGadgetText(#StrokaPutDoRoma)
                     If PutDoRoma2$
                       ; перепроверяем что он действительно существует
                       
                       ; создаем файл по новой
                       If CreateFile(#File, PutDoRoma2$)
                         
                         ; пишем туда образ памяти
                         ; то есть куда - #File, какая именно память - *MemoryID, размер сколько писать - length
                         WriteData(#File, *MemoryID, length)
                         
                         ; закрываем файл
                         CloseFile(#File)
                         
                         MessageRequester("победа!", "вроде бы все записалось куда надо. надо открыть наш ром в хекс редакторе и посмотреть что там куда записалось.")
                         
                       Else
                         ; файл создать не получилось
                         MessageRequester("ошибка", "файл не создался. может быть открыт в другой программе или еще чего.")
                       EndIf
                     Else
                       MessageRequester("ошибка", "нет пути до файла рома.")
                     EndIf
                     
                   Else                     
                     ; превышение. выдать предупреждение.
                     MessageRequester("ошибка", "вы пытаетесь прочитать за пределами файла рома.")
                   EndIf
                   
                 EndIf
                 
               Else
                 ; ром еще видимо незагружен
                 MessageRequester("ошибка", "ром еще не был загружен.")
               EndIf
               
             EndIf
             ;}
             
         EndSelect
         
       ; событие касается закрытия окна
       Case #PB_Event_CloseWindow
         qiut = 1
   
     EndSelect
     
     ; цикл крутится, пока не сработает закрытие окна и соответственно qiut станет равен 1
   Until qiut = 1
   

EndIf


; завершение программы
End

2
дааааа кто понял - тот понял, а кто не понял - тот Филлип Киркоров. ой. то есть тот Yoti.

Продолжаем упарываться. У нас есть отдаленное понимание как построить окно программы и как худо бедно читать и писать в файл. Пора совместить. Для начала думаю можно сделать так, что при запуске программы - она будет читать файл нашего "рома", показывать оригинальное значение $12345678 и будет иметь кнопку, жмакая которую мы будем производить вписывание этого самого числа куда нужно.

; перечисление окон, гаджетов и файлов
Enumeration
  #Window
 
  #TextPrivetMir
  #TextHex
  #KnopkaSave
 
  #File
EndEnumeration

; читать файл можно до создания окна.
; а докучи если файл не смог быть прочитан - окно можно даже не создавать
; а сразу написать, что шеф, все пропало!

; ReadFile - читаем, то есть файл недоступен для записи, а только читаем для безопасности.
If ReadFile(#File, "D:\SEGA\Forum\testfile.bin")
 
  ; прыгаем на известный нам адрес $1C внутри файла
  FileSeek(#File, $1C)
 
  ; читаем в нужном виде нашу переменную long размером 4 байта
  x = ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
 
  ; закрываем файл
  CloseFile(#File)
 
Else
  ; условите "Иначе"
  ; то есть если программа не смогла найти или не смогла открыть наш файл рома
  ; выходит случилась ошибка
  ; выводим сообщение об ошибке и закрываем программу
  MessageRequester("Алярм!!!111расрас", "Ошибка! Я вся такая не смогла прочитать файл. Или не нашла его, или он открыт в другой программе. Черт знает что там случилось.")
  ; прыгаем в конец программы, чтобы не открывать окно.
  ; окно получается бесполезно - мы же не смогли прочитать оригинальный файл
  Goto marker
 
EndIf


; создание окна
If OpenWindow(#Window, 100, 100, 300, 100, "Я у мамы программист.", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
 
  ; рисуем гаджеты на окне
 
  ; в х у нас сидит число. а числа текстовой гаджет показывать не умеет.
  ; ему надо перевести число в текст. это делается с помощью Str(x)
  ; текстовая переменная должна иметь значок доллара в конце
  ; типа x$. то есть х это число, а x$ это текст.
  x$ = Str(x) ; но это в десятичном виде. а нам надо в хекс
  TextGadget(#TextPrivetMir, 10, 10, 200, 20, "Оригинальное число: " + x$)
 
  x$ = Hex(x, #PB_Long) ; вот теперь в тексте x$ сидит число в виде хекс
  TextGadget(#TextHex, 10, 30, 200, 20, "В хекс виде: $" + x$)
 
 
  ButtonGadget(#KnopkaSave, 10, 60, 50, 20, "Вписать")
 
  ; бесконечный цикл обработки событий окна
  Repeat
   
     ; определяем с чем именно мы имеем дело
     Select WaitWindowEvent()
         
       ; событие касается какого-то гаджета 
       Case #PB_Event_Gadget
         
         ; раз событие касается гаджетов, то надо перебрать какой именно гаджет имеет это событие
         Select EventGadget()
             
           Case #KnopkaSave ; оказывается гаджет кнопки
             If EventType() = #PB_EventType_LeftClick
               ; если событие клик левой кнопкой мышки
               
               ; тут мы открываем файл для записи. если что-то пойдет не так - можно испортить файл.
               If OpenFile(#File, "D:\SEGA\Forum\testfile.bin")
                 
                 ; прыгаем в нужное для записи место
                 FileSeek(#File, $3C)
                 
                 ; в х все еще сидит нужное нам число
                 ; производим специальную операцию записи в нужном нам виде
                 y = x >> 24
                 WriteAsciiCharacter(#File, y)
                 y = x >> 16
                 WriteAsciiCharacter(#File, y)
                 y = x >> 8
                 WriteAsciiCharacter(#File, y) 
                 WriteAsciiCharacter(#File, x)
                 
                 ; закрываем файл
                 CloseFile(#File)
               Else
                 ; если файл мы не смогли открыть - надо сообщить об ошибке
                 MessageRequester("опять ошипка :(", "Сохранение файла не удалось. Или он открыт в другой программе, или еще какая катавасия случилась.")
               EndIf
               
             EndIf

         EndSelect
         
       ; событие касается закрытия окна
       Case #PB_Event_CloseWindow
         qiut = 1
   
     EndSelect
     
     ; цикл крутится, пока не сработает закрытие окна и соответственно qiut станет равен 1
   Until qiut = 1
   

EndIf

; метка для досрочного завершения программы, когда файла рома не нашлось
marker:

; завершение программы
End

3
Работа с файлами.

Для нас цифры это цифры. Типа написал ручкой на бумажке 500 и понятно что это 500. В случае записи в файл - тут не все так однозначно :) Там есть такое понятие как тип переменной - byte, word, long. В чем разница? Дело в размере, который будет занят подобным числом. Если нам надо записать число 13 - достаточно будет byte. А если 1300 - то байта уже не хватит. Понадобится word. А если нам надо записать какоенить 128 000 то даже word не хватит - и нужен будет long. Размеры сколько байт они занимают и какие у них лимиты чисел откуда и докуда - можно посмотреть в таблице. нас интересует верхняя часть, красным.



Тип переменной и её размер мы вроде как уяснили. Теперь обсудим отображение этих чисел для глаз. С точки зрения компьютера то нет никакой разницы, а вот нам - человекам - надо кое что уточнить... В основном их используется 3 типа:
обычные десятичные, как у нас, у людей: 8, 9, 10, 11, 12...
число в хексе, обычно так выглядит в хекс редакторе: 8, 9, A, B, C (чтобы уточнить, что это именно хекс, то обычно пишут значок бакса, и потом уже число $8, $9, $A, $B, $C... либо, если аллергия на валюту: 0х08, 0х09, 0х0A, 0x0B, 0x0C)
бинарный код, то есть нули и единички: 00001000, 00001001, 00001010, 00001011, 00001100 (чтобы уточнить что это в бинарном виде, то обычно пишут значок процента и потом уже число %00001000, %00001001, %00001010)

Но и это еще не все. Запись переменных word и long может быть двух видов. Big-Endian и Little-Endian. Иначе говоря один порядок правильный, второй перевернутый. Какой из них какой - черт его знает :) PB, зараза, может читать и писать только в перевернутом. А обычно в файлах рома порядок правильный. Типа для примера long:
в роме $12, $34, $56, $78
PB прочитает как $78, $56, $34, $12
Эту проблему с невозможностью писать в нужном для нас виде отметим, но пока отложим. Вернемся к ней попозже.


Теперь переходим к практике. Во вложении будет прикреплен тестовой файл. Для понимания процесса хорошо бы чтоб на компьютере был установлен WinHex - чтобы можно было проверять правильность работы нашей программы.



Работа с файлом может происходить двумя способами:
открываем и работаем с файлом прямо на месте, то есть на жестком диске.
открываем, читаем в память, закрываем, работаем в памяти, если надо сохранить, переписываем файл из памяти на жесткий диск.

На первоначальном этапе думаю мы пойдем первым путем.

Нам понадобятся команды открытия и закрытия файлов, чтения, записи и прыжка в нужное место файла. Из скрина выше нам известен адрес, где лежит наша переменная $12345678 - $1C и мы знаем что она long. Значит нам надо открыть файл, прыгнуть на этот адрес $1C и прочитать. Вроде задача не сложная.


Enumeration
  #File 
EndEnumeration

If ReadFile(#File, "D:\SEGA\Forum\testfile.bin")
 
  FileSeek(#File, $1C)
 
  x = ReadLong(#File)
 
  CloseFile(#File)
EndIf


Debug x                ; как десятичное. не интересно.
Debug Hex(x, #PB_Long) ; в виде хекс. то что надо.


И нас ждет эпик фейл :) Так как число прочиталось в перевернутом виде. Вместо $12345678 мы видим $78563412.



Чтобы выкрутится - можно сделать так: читать не как long - то есть 4 байта за раз - ReadLong, а читать 4 раза по одному байту - ReadAsciiCharacter, и просто потом их сдвигать в нужное место. Звучит конечно страшно и не понятно, но тут можно особо не вникать, так как код все сделает. Я всегда так делаю: если код не понятный, но работает - просто принимаешь на веру и радуешься :)


Enumeration
  #File 
EndEnumeration

If ReadFile(#File, "D:\SEGA\Forum\testfile.bin")
 
  FileSeek(#File, $1C)
 
  ;x = ReadLong(#File) ; заккоментировали, и поэтому текст зеленый и не считается
  x = ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
 
  CloseFile(#File)
EndIf


Debug x                ; как десятичное. не интересно.
Debug Hex(x, #PB_Long) ; в виде хекс. то что надо.


Что касается сдвига, а в данном случае x << 8 тут надо немного уточнить. 1 байт состоит из 8 битов. Эти самые биты можно увидеть отобразив число в бинарном виде. Например:
x = 120 ; это десятичный вид
Debug Bin(x)
покажет как %1111000 - бинарный, или биты (на самом деле %01111000 просто нолики в начале съедает.)
если мы это число "сдвигаем" << 8, то это означает добавляем нолики в конце.
было %01111000 стало %0111100000000000
типа 120 в хекс это: $78
$78 << 8 = $7800

то-же самое если мы сдвигаем в другую сторону. например было число $789A
$789A >> 8 = $78

С этим разобрались. Теперь усложним наш код и изменим ReadFile на OpenFile, так-же прочитаем из нужного места и перевернем наше число, и попытаемся его записать в другое нужное место.


Enumeration
  #File 
EndEnumeration

If OpenFile(#File, "D:\SEGA\Forum\testfile.bin")
 
  FileSeek(#File, $1C)
 
  ;x = ReadLong(#File) ; заккоментировали, и поэтому текст зеленый и не считается
  x = ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
 
 
  FileSeek(#File, $3C)
 
  WriteLong(#File, x)
 
  CloseFile(#File)
EndIf

Запускаем, смотрим наш файл в хекс редакторе и видим, что там ошибка. Да, мы прыгнули в нужное место записи - $3C, но записывать надо было не стандартными методами PB - WriteLong - 4 байта за раз, а точно так-же разбив long на 4 байта по одной штуке и писать их по очереди. А то получается мы записали число задом наперед :)

Enumeration
  #File 
EndEnumeration

If OpenFile(#File, "D:\SEGA\Forum\testfile.bin")
 
  FileSeek(#File, $1C)
 
  ;x = ReadLong(#File) ; заккоментировали, и поэтому текст зеленый и не считается
  x = ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
  x << 8
  x + ReadAsciiCharacter(#File)
 
 
  FileSeek(#File, $3C)
 
  ;WriteLong(#File, x) ; выкидываем
  y = x >> 24
  WriteAsciiCharacter(#File, y)
  y = x >> 16
  WriteAsciiCharacter(#File, y)
  y = x >> 8
  WriteAsciiCharacter(#File, y) 
  WriteAsciiCharacter(#File, x)

 
  CloseFile(#File)
EndIf

Здесь как раз используется сдвиг в другую сторону x >> 8. И глядя на код вы можете сказать:
- Но, позвольте! x >> 24 я согласен, что превратит $12345678 в $12, но ведь x >> 16 сделает не нужные нам $34, а $1234 - а это совершенно не правильно!
Хорошее замечание. Придется ответить:
- А тут все дело в команде записи - WriteAsciiCharacter - она записывает только 1 байт. Поэтому независимо от того, что в нашем числе сейчас сидит двухбайтовое $1234 - запишутся в файл только последние $34 - то что нам и надо.

4
Тема создана с целью наиболее простым языком описать процесс создания своего какого-то инструмента для редактирования чего-либо в игре. Это не ромхакинг. Это предполагается, что ромхакер уже знает что где лежит в роме и в каком формате. И это что-то существующими доступными программами не редактируется, а хотелось бы сделать что-то свое, однокликовое, с блекджеком и легкодоступными женщинами.

Будет для статьи использоваться не совсем удобное и знаменитое, а докучи еще и платное - PureBasic. Ну и, понятно, Windows. Как бы он тоже платный... главное что некоему Билли Г. что автору PB не рассказывать о существовании торрентов.

Как понятно из названия - это Basic, только что с плюшками современными. Но в общем и целом те-же яйца, только в профиль. И нас интересует портабельная версия, чтобы ничего не устанавливать.




Дальше теория. Код обычно выполняется сверху вниз построчно. Типа пробежался сверху вниз, закончился, и получились какие-то результаты. Однако мы хотим создать окно "Привет Мир!" и чтобы оно висело по середине экрана и радовало пользователя своим висением. Следовательно код должен будет бежать сверху вниз, дойти до момента создания окна, создания элементов внутри окна - то есть надписи "Привет Мир!", и после этого дальше начать по кругу гонять бесконечный цикл "ожидание событий" - без этого цикла окно мелькнет и исчезнет, а нам нужно продолжительное висение, пока пользователь не нажмет "закрыть окно".

В этом самом бесконечном цикле есть разбор событий и нам нужно будет добавить событие "закрыть окно". Этот разбор разбирает какое это окно, где событие случилось, какой элемент внутри окна имеет событие, какое именно событие происходит - движение мышкой или может быть клик левой кнопки, или может правой. То есть получается у самого окна, у всех его элементов, у событий - есть свои уникальные номера, чтобы программа понимала что с ней творится. Можно прям так и объявлять: окно 0, кнопка 1, картинка 2... Как бы все будет работать, но визуально для глаз удобнее все-же давать "человеческие" названия окнам и кнопкам. типа окно #Window, кнопка #Button или если это скажем кнопка сохранения #ButtonSave... или даже #KnopkaSave чтобы вообще все было понятно. Эти названия друг за дружкой можно перечислять в верхней части кода, в разделе Enumeration. Визуально мы - человеки - будем понимать где какая кнопка, а с точки зрения программы это будут те-же самые цифры 0, 1, 2, 3...

Дальше элементы внутри окна. Они называются гаджеты. Их там небольшой список и они различаются по внешнему виду и функционалу. Типа скажем текстовая строчка, или кнопка, или картинка, или ниспадающий список, или гаджет с отметкой галки (CheckBoxGadget)... У каждого свои задачи и свой набор событий. Типа кнопка может получить и обработать нажатие левой кнопки мышки (правой к сожалению нет, хотя порой очень надо). И так далее.




По итогу код нашей программы для взлома пынтагона выглядит так:

Enumeration
  #Window
 
  #TextPrivetMir
  #KnopkaOK
EndEnumeration


If OpenWindow(#Window, 100, 100, 300, 100, "Я у мамы программист.", #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
 
  TextGadget(#TextPrivetMir, 10, 10, 100, 20, "Привет Мир!")
 
  ButtonGadget(#KnopkaOK, 10, 50, 50, 20, "OK")
 
  Repeat
     Select WaitWindowEvent()

       Case #PB_Event_Gadget

         Select EventGadget()
           
           Case #KnopkaOK
             If EventType() = #PB_EventType_LeftClick
               Debug "была нажата кнопка ОК"
             EndIf

         EndSelect

       Case #PB_Event_CloseWindow
         qiut = 1
   
     EndSelect
   Until qiut = 1

EndIf

End

То есть сначала наверху блок Enumeration, где перечислены окна и кнопки, которые мы будем использовать. Потом создание окна программы OpenWindow - где внутри указаны начальные координаты окна, ширина и высота, и заголовок в кавычках. Специальные параметры в конце в количестве два штуки говорят программе, что надо рисовать наше окно в центре экрана и чтобы была кнопка "свернуть программу", ну и крестик "закрыть программу".

После создания окна идет рисование гаджетов - в данном случае текстового TextGadget и кнопки ButtonGadget. У них так-же как и у окна есть стартовые координаты, но теперь уже не экрана - а координаты на самом окне, высота и ширина, и надписи в кавычках.

Потом начинается тот самый бесконечный цикл - Repeat и он крутится до строчки Until qiut = 1, то есть пока переменная qiut - выход, или закрытие программы, не будет ровняться единичке. Внутри этого цикла происходит разбор где произошло событие - то есть в данном случае перечислены два варианта: тело самой программы (типа пользователь нажал кнопку "закрыть") и какой-то гаджет (в данном случае кнопка).

Что касается Debug - это просто вывод текста в специальное окошко. Оно нам нужно будет удостоверится, что событие - клик по кнопке ОК - действительно обрабатывается.

На каждую команду типа OpenWindow или TextGadget можно будет в PureBasic навести мышкой, кликнуть и нажать F1 - вылезет подсказка с полным разбором где какой параметр за что отвечает. И даже примеры кода, которые можно будет скопировать в новое окошко и позапускать - посмотреть результаты.

И да - везде где не попадя стоят If - If OpenWindow, If EventType()... PB это вообще очень не уверенный в себе язык программирования и поэтому лучше на всякий случай добавлять эти самые условия - If - Если. Если открылось окно, то... Если событие было кликом мышки, то... OpenWindow в принципе будет работать и без If, но мало ли в каких-либо случаях Windows не даст создать окно, а программа то захочет выполнятся дальше и дальше по коду идет рисование текстового гаджета - а где она его нарисует, если окно не создалось? Программа вылетит с ошибкой. А так у нас стоит If - окно не открылось? Ничего страшного. Просто завершаем работу, как будто программа не стартовала вовсе. Ну или можно вывесить сообщение, что дескать по какой-то причине мы не смогли создать окно, а следовательно кина не будет.


Пока, надеюсь, все понятно :)

п.с.: пошел на кухню и понял что понятно не всё. надо скопировать текст программы, вставить в PureBasic и чтобы не елозить по менюшкам - нажать F5.

Добавлено позже:
а как тут начать новый пост, чтобы он был новым постом, а не *добавлено позже ?

5
надо тему стартануть :) чтоб с описанием, как для детей с тремя классами церковно-приходской школы с айтишным уклоном, как у меня, как создавать простые редакторы по потребностям для ромхакинга.

6
так ты главное начни :) а там само собой пойдет. я вот тоже не силен... я больше идеи и чужой код в одну кучу собираю и худо бедно заставляю их вместе работать :) когданить книгу напишу как я с приключениями с мира по нитке собирал свой проект :)

7
сделай себе что-то типа самодельного gif редактора и там ваяй движущиеся картинки. это не сложно. сразу чтоб вставляло 24битную картинку налету, с произведением пастеризации и созданием палитры и чтоб сразу все совместимо было.

8
прислали тут ссыль :) неудержался чтоб копирнуть сюда :)))
https://duaneandbrando.bandcamp.com/track/battletoads-2

9
дело в том, что чтобы рисовать рамку - надо рисовать эту самую рамку. а памяти совсем нет свободной для тайлов полосок рамки. отчасти можно конечно тайлы курсора использовать, но за чей счет? рисовать спрайтами? или рисовать на втором слое? не говоря уже про оперативную память, которая под завязку. на самом деле если бы была там такая свободная вещь, то первое что нужно сделать это не рамка и селект кучи юнитов - а просчет путей, чтобы юниты не застревали или не ездили длинными путями, когда есть путь короче.

10
на тот момент дефлемаск еще был в тренде :) потом Делек объявил что переходит на платную основу и все начало скатываться. потом стартанул Furnace и весь народ туда ломанулся, так как там блек джек обещали с женщинами и еще и бесплатно.

11
да это просто люди не понимают объема блудняка, в который надо вписаться, чтобы все это сделать :) я уже пол года искаю кто бы музыку сделал, не говоря уже о художниках, и прочих высокоодухотворенных персон, которые нужны и которые нужны хорошие, и чтоб еще денег не требовали до кучи. так даже конвертер из миди в дефлемаск сделал и там прям на теле программы написал: что дескать ищу кто может сделать каверы Игры Престолов... типа вот специально для вас музыкантов конвертер, пользуйтесь, и может быть кто-то захочет сделать каверы. и чего? нуль эмоций :)))) а уже лет 5 наверное прошло как он по сетям гуляет... даже архив с миди файлами там в теле программы приложен и краткое техническое описание мелодий, что нужны чтобы их заюзать в ромхаке. высокодуховные и высоколенивые, заразы :) посему то оптимизма в этом неблагодарном деле быть не может. ведь чтобы реально сделать полноценный ромхак, а считай Джим Червяк 3, то нужна бригада разнорабочих, где каждый разбирается в своем деле. а не так, чтобы и жрец и пьец и на дуде игрец в одном лице.

12
I predict his next post:
Цитата
I accidentally blew up my console. help me fix it.

13
если шрифт сдвинуть во второй сегмент памяти, то лимит может быть увеличен и картинка может быть более детальной. может и в третий можно, но там кажись места не хватит чтоб все символы шрифта влезли.

14
Не дружу с тобой больше
блииин... как не удобно получилось...

поцоны, знаете, МК3 такая классная игра!

Добавлено позже:
И пару батников - один для сборки гемсовых потрохов, второй для сборки рома
неповеришь, но в Дюне это примерно плюс минус так и сделано :)))) то есть если ты на экране редактирования музыки - и жмешь собрать ром - собираются гемс банки. если ты на любом другом экране, скажем редактирование заводов - то при сборе рома - гемс банки не пересобираются.

правда если ты был на экране музыки, изменил что-то, переключился на другой экран и собираешь ром... тогда изменения не попадут в ром. или я это тоже продумал? блин. не помню :) должен был. но далеко не факт что все-таки сделал этот флаг проверки какого-либо изменения в банках.

Добавлено позже:
Тоже мне... Сравнил файтинг с платформером.
и это не я сравнил! :) это в ответ на реплику собеседника :) вот он сравнил, он! все шишки ему!

15
страшный страшный секрет. никому не рассказывайте. но там алгоритм куда круче творит магию с цветами, чем мой встроенный в редактор  :cry:  :cry:  :cry:  :cry:  :cry:

https://rilden.github.io/tiledpalettequant/

16
я ему говорил пиши по буржуйский, нет он с переводчиком пытается :) чем еще больше запутывает.

вобщем как я понял лицензия или заводская штамповка - играет нормально. а как только пихает болванки писанные (говорит минимальная скорость записи там 16х) то начинаются приключения.

17
кстати, возвращаясь к Джиму - по идее надо чтоб в этом дизасме банки GEMS были сдвинуты в конец рома. и тогда для пересбора звуков можно будет использовать специальный менеджер. но я так понял что у вас тут не кошерный ASM68K.exe, а что-то другое :) просто манагер использует как раз ASM68K.exe... хотя думаю это не будет прям такой большой проблемой.

18
Цитата
Кто-то долежен прикрутить API для модов и обвернуть это удобно, что бы каждый мог сделать замену спрайтов за пару кликов.
это не ко мне - мне лень :) но на самом деле это - да, полезная херня. тут ведь как - программеров раз два и обчелся. а вот всяких генераторов идей - пруд пруди. а тут получается таким людям-генераторам дадут в руки флаг и барабан на шею и они начнут творить сотни своих говнохаков. и это есть хорошо, так как хоть какой-то интерес к геймдеву подогревается и у сообщества есть какое никакое движение. и, внезапно, по закону статистики среди всей тонны говнохаков раз в пять лет может и будет появляться жемчужина. вот например vetalfox очень давно воюет с MK3 в плане графики. а адекватного инструмента, чтоб результаты его работы, будучи не программером с семью пядями во лбу а всего-лишь с тремя классами церковно-приходской, втулить в игру - нет. снижение порога вхождения в тему очень бы помогло сообществу, даже пусть там в начале и будет миллион говнохаков, прежде чем что-то путное начнет появляться.

19
4 поколение / Замена ОУ на Mega Drive 2
« : 14 Апрель 2024, 18:46:44 »
даешь Мега Драйв на ламповом усилителе!!!111

20
как так? как ты мог забыть про стелс-пихоту с пневмопыхами?

21
UMK3, Dune, RnR Racing, тот же соник тоже сделаны на высоком уровне, тем не менее хаки на них делают
не... это не то :) да, это классные игры, но все-таки это несколько разные весовые категории. графоний в Червяке и Комиксе все-таки космический. а червяк еще и разнообразием геймплея тащит. MK3 не требует каких-то продуманных уровней, красиво нарисованных разнообразных врагов, какие-то секреты, разнообразный подход к убийству врагов - там повторяющиеся арены и противники, в количестве одна штука. тоже самое RRR - конечно там меняется графоний планет, и даже физика некоторая - типа фигурное катание на коньках, но все-ж не то. в Дюне конечно размах для влезания корявых ручек больше, но вот графония там кот наплакал. ибо там из-за ограничений возможностей приставки или мухи или котлеты. а вот чтоб все вместе и графоний и разнообразие геймплея, как в Черве - низя. Соник - не играл и осуждаю :)

в кратце: в этих перечисленных играх нет ощущения волшебства я бы сказал. а что касается этих двух игр ожидать какого-то прям полноценного ромхака Червяка и Комикса не стоит. это практически не реально создать что-то такого-же уровня и качества, как оригинальные игры :) а мелкие правки - это ромхак-неромхак. это так... баловство.

22
дело конечно хорошее... да только толку с него :) Червяк - он как Комикс Зон - изначально сделан на таком высоком уровне, что никто не сможет сделать толковый ромхак :)

вы копаете не в том направлении! чтобы глобально расширить коллекцию игр Сеги - надо ковырять NES и делать конвертер игр оттуда сюда. например единственное что я люблю на дендях - Jackal. один мой буржуйский товарищ грозится портануть... но у него миллион проектов :) и я уже не верю в позитивный исход.

23
завезли вторую часть в эти наши интернеты... и оказывается харвестеры не должны давить фрименов :)))))

24
на даты то смотрите :) все закончилось еще в тыщадевятсотпятом.

на самом деле не сложно это дело найти и выгрузить. но папки начали выступать строго негативно, дескать контент из их хаков воровать будут. посему доделывать сию функцию в редакторе не стал.

25
так жеж то-ли Fusion, то-ли Gens. по идее как бы оба, но на одном из них у меня не завелось.

26
Monica Bellucci is the best!

27
аааа... ну ежели оно прям из коробки такое поддерживает - тогда я согласный :) я думал один мультитап сразу в оба порта приставки пихается. а ежели оно в один порт и делит на 4 геймпада - то тогда все ок :)

28
это видимо какойнить типа кастомный картридж надо. чтоб на нем дополнительные разъемы были. ну и чтоб два раза не ходить - так-же чтоб на нем же был разъем RJ45 и WiFi, для подключения к роутеру и выхода в интернет. чтоб первую ММО игру для Сеги забабахать. правда наверное еще надо будет чтоб в этом картридже был вшит 32х, чтобы хоть маленько добавить мозгов приставке, чтобы она могла тянуть все эти извращения.

где-то уже писал, но повторюсь: первые ММО для приставки могли бы повторять путь, который прошли браузерки в начале 2к. типа от всяких галимых Комбатов - удар, блок... до, как же она была то... забыл название. браузерка-ммошка по Команд Конкуер. как-то она тибериум альянс чтоль называлась. не помню :) стройка и апгрейд баз, и прямого управления юнитами не было. типа выставляешь в линии свои юниты в атаке или обороне, жмешь в бой, и они сами там по своим линиям едут и стреляются с противниками. а ты сидишь и надеешься что твое построение разнесет противника.

29
так мож у них 1 апреля это совсем не наше 1 апреля... может не поймет :)

30
по моему спустится на тот пункт где 2 игрока и жмакать толи влево толи вправо...

Страницы: [1] 2 3 4 5 ... 79 Далее