Hackear el clásico Sonic the Hedgehog para Sega

En este artículo quiero desmontar el dispositivo interno del legendario juego Sonic the Hedgehog para Sega Mega Drive, así como las formas de modificarlo o, como dicen, piratear. Este juego tiene alrededor de un centenar de hacks , incluido un trabajo realmente digno (como Pana Der Hejhog o Sonic Remastered ) y extraño e incluso espeluznante (como An Ordinary Sonic ROM Hack ). Para comprender cómo crearlos, debe descubrir cómo escribir en el lenguaje ensamblador Motorola 68K (generalmente los juegos para consolas de aquellos tiempos se escribieron en ensamblador), dónde obtener la versión desmontada del juego y qué arquitectura tiene su motor.


Hacks sónicos


El desmontaje de los archivos ROM para Sega se realiza utilizando el desensamblador comercial y el depurador IDA Pro . Luego hay un proceso minucioso de marcado, estructuración y peinado del código de ensamblador sin procesar utilizando el depurador (y el ingenio). Este proceso requiere una buena comprensión de las características técnicas de la plataforma Sega Mega Drive y sus juegos.


Afortunadamente, GitHub ya ha desmontado y etiquetado versiones de todos los juegos de la serie Sonic the Hedgehog, creados por entusiastas con el apoyo del sitio web de Sonic Retro . El código fuente del primer juego de la serie está mejor marcado y estructurado. Esta versión del código se encuentra en el repositorio sonicretro / s1disasm y se analizará en el artículo.


La inmersión en la estructura interna del juguete comenzará con la teoría.




Sega Mega Drive ( Sega Genesis) 32- Motorola MC68000 ( Motorola 68K) Zilog Z80 ( Z80 ). (RAM) – 64K. ( ) – 320x224 .


Motorola 68K . , . Motorola 68K Apple Macintosh.


Mega Drive Yamaha YM7101 80 . ; Sega Mega Drive " Sega Mega Drive: Video Display Processor".


AS. 82 . : ResearchGate Intel Core i7 338 .


32- : D0D7. . A0A7. - . A7 SP.


. .l (long) 32- . .w (word) .b (byte) 16- 8- .


Motorola 68K.



move – .


:


  • move.l #48, d4 – 48 d4.
  • move.w d5, d6 – 16 d5 d6.
  • move.w #$12FF, obStatus(a0) – 12FF , obStatus , a0.

, #. #$.


:


  • move.l #5, (a0) – 5 , a0.
  • move.l (a1), d2 – , a1, d2.

(a*).



  • add – .
  • sub –  .
  • mulu – ; muls – .
  • divu – ; divs – .

:


  • add.b #$08, d0 – 08 d0.
  • sub.w (v_screenposx).w, d1d1 v_screenposx ( 16- ).
  • mulu.w #10, d0 –  d0 10 ( d0 ).
  • divs.w #$68, d2 –  d2 68 ( d2 ).


  • jmp, bra – .
  • jsr, bsr – , rts – ( call ret x86).

:


jmp .foo  ;     .foo
nop       ;    (nop)   
.foo:     ;  .foo

SubRoutine:  ;   SubRoutine
nop
rts          ;   

bsr SubRoutine  ;   SubRoutine


68K CCR (Condition Code Register). cmp, tst btst () , beq, bne, bge, ble .


  • cmp –  .
  • tst – .
  • btst – .
  • beq/bne – , / .
  • bge/ble – , / .

:


cmp.w   #32,d0  ;  d0  32
bge.s   .foo    ;  d0 > 32,    .foo

btst    #0,d0  ;   ()  d0  
bne.s   .foo   ;     ,    .foo

Motorola 68K ( ) , .



s1disasm Python-, . Sonic the Hedgehog "Kosinski compression", ( ).


, , git- AS (git checkout AS) :


./build.py

ROM- s1built.bin. Sega Mega Drive. macOS, , OpenEmu.



sonic.asm. : Zilog Z80 (WaitForZ80), (VDPSetupGame) . GameInit MainGameLoop, .


, Variables.asm. RAM, .


v_gamemode. :


  • 00 –  "Sega",
  • 01 –  ,
  • 08 – ,
  • 0C – ,
  • 10 – special stage,
  • 14 – "Continue",
  • 18 – ,
  • 1C – ,
  • 8C – .

move.b #id_Sega,(v_gamemode).w GameInit v_gamemode , . id_Sega id_Title ./build.py, , "Sega" , .


v_gamemode , . , id_Title GM_Title, id_Level – GM_Level.



, Variables.asm . v_sonspeedmax, v_sonspeedacc v_sonspeeddec.


, Sonic_Main, : , , :


move.w  #$600,(v_sonspeedmax).w  ; Sonic's top speed
move.w  #$C,(v_sonspeedacc).w    ; Sonic's acceleration
move.w  #$80,(v_sonspeeddec).w   ; Sonic's deceleration

, 256. , 0xC / 256 = 0.046875, – 0x80 / 256 = 0.5 ( ).



Mega Drive Sega 315‑5313 (Video Display Processor, VDP). VDP , vdp_data_port vdp_control_port. VDPSetupGame, VDPSetupArray. , , . , GM_Level. VDP Sega Retro.


Low Color ( Mode Register 1 ):



Video Display Processor – background ( B) foreground ( A), , . 8x8 . ; – 4x4 . , 32x32 .


(LoadTilesAsYouMove, DrawChunks) (BuildSprites) , :



, LoadTilesAsYouMove . Sonic the Hedgehog 64x32 512x256 .


foreground- Green Hill Zone, GIF-, 5 :

, , . , . , 3D- . Sonic the Hedgehog.


Marble Zone, GIF-, 1 :


8192 RAM . v_objspace. , . : , , , , , . DisplaySprite.


Objetos sonoros del juego


64 . , , Constants.asm. a0. , :


  • ObX(a0), ObY(a0) –  .
  • ObVelX(a0), ObVelX(a1) – 1/256 .
  • obHeight(a0), obWidth(a0) – .
  • obSubtype(a0) – (: ).
  • obStatus(a0) – .
  • obRoutine(a0) – .

, X , Y, .


ExecuteObjects . , . Object Pointers.asm. _incObj.


, (, , , "" ). , , obRoutine.


SpeedToPos. , .


: no-ring challenge


, : no-ring challenge. . , ( ).


"" – Ring_Main (bra) :


Ring_Main:  ; Routine 0
    bra.w   Ring_Delete ;      

    lea (v_objstate).w,a2
    moveq   #0,d0
    move.b  obRespawnNo(a0),d0
    ; ...

. "" 26 Monitor.asm. obSubtype 1 . , 6. cmp beq , :


Mon_Main:   ; Routine 0
    cmp.b   #6,obSubtype(a0)  ;   ?
    beq     DeleteObject      ;  ,  

    addq.b  #2,obRoutine(a0)
    move.b  #$E,obHeight(a0)
    ; ...

, ROM' , . GitHub. , - , .


:


, . Sonic the Hedgehog 3 – .


GIF-, , 1 :

Sonic the Hedgehog 3


, , Sonic Retro. , , , 64 , . . 0.1875 , . , 0.75.


, , , , , "" .



"", 25 & 37 Rings.asm. :


Ring_Index:
ptr_Ring_Main:      dc.w Ring_Main-Ring_Index
ptr_Ring_Animate:   dc.w Ring_Animate-Ring_Index
ptr_Ring_Collect:   dc.w Ring_Collect-Ring_Index
ptr_Ring_Sparkle:   dc.w Ring_Sparkle-Ring_Index
ptr_Ring_Delete:    dc.w Ring_Delete-Ring_Index

: Main – ; Animate – ; Collect –  ; Sparkle – ; Delete – . , , ptr_Ring_Animate.


obStatus. , . obStatus ( ) . bset, , – btst.


Ring_Animate , , , 64 :


Ring_Animate: ; Routine 2
    tst.b   (v_shield).w  ;    ?
    beq.s   .animate      ;  , 

.dist_from_sonic:
    ;    
    move.w  (v_player+obX).w,d0  ;     X  d0
    sub.w   obX(a0),d0           ; d0 =   X
    move.w  (v_player+obY).w,d1  ;     Y  d1
    sub.w   obY(a0),d1           ; d1 =   Y

.check_magnetised:
    ; ,        
    btst    #0,obStatus(a0)  ;   obStatus  0?
    bne.s   .attract         ;   =>  ,   .attract

.check_near_x:
    ;    ,  
    cmp.w   #64,d0    ;   X > 64?
    bge.s   .animate  ;  , 
    cmp.w   #-64,d0   ;   X < -64?
    ble.s   .animate  ;  , 

.check_near_y:
    cmp.w   #64,d1    ;   Y > 64?
    bge.s   .animate  ;  , 
    cmp.w   #-64,d1   ;   Y < -64?
    ble.s   .animate  ;  , 

    ;    64x64,   
    bset    #0,obStatus(a0)

.attract:
    ;      

.animate:
    ; ...

, , . :


if sign(obVelX) == sign(distX):

, ( Motorola 68K) , 0 , 1 – . "" – XOR (eor Motorola 68K).


, ( ) , (0.1875 0.75) 256 ( 48 192 ).


:


.attract:
    ;     X
    move.w #48,d4          ;   d4  48
    move.w  obVelX(a0),d3  ;     X  d3
    eor.w   d0, d3         ;      
    btst    #$F,d3         ;  15-   1 ( )...
    beq.s   .x_towards     ;   x_towards
    move.w #192,d4         ;   ,   d4  192

.x_towards:
    ;    ,    (neg)   (d4)
    cmp.w   #0,d0
    bge.s   .attract_x
    neg d4

.attract_x:
    ;     X    X
    add.w   d4,obVelX(a0)

    ;      Y:
    move.w #48,d4
    move.w  obVelY(a0),d3
    eor.w   d1,d3
    btst    #$F,d3
    beq.s   .y_towards
    move.w #192,d4

.y_towards:
    cmp.w   #0,d1
    bge.s   .attract_y
    neg d4

.attract_y:
    add.w   d4,obVelY(a0)

.animate:
    ; ...

, , SpeedToPos:


.animate:
    jsr (SpeedToPos).l

ROM , — — Sonic 3 Sonic 1!


GIF- , 3.5 :

GitHub , .



. (SonED2, Chaos), , . / Motorola 68K EASy68K, , Sega.


, , . , - , , .




All Articles