Пример #1
0
# when switching levels. This isn't required, but it will make the generated
# code smaller as it avoids inlining many additional copies of the main loops.
# Since there isn't a jump we can easily replace here, we'll replace a
# "mov si, 8" instruction with a smaller variant and a tail-call.
b.patch('0E3B:2C04', 'mov si, 8', length=1)
b.patch('0E3B:2C05', 'call 0x2C07', length=1)
b.patch('0E3B:2C06', 'ret')

# Break control flow at remaining locations that wait for keyboard
for call_site in [
        '0E3B:3B8D',  # Menu for "?" key
        '0E3B:3B9A',  # Menu for "ESC" key
        '0E3B:6921',  # "To go back to the room you just left, press Enter"
        '0E3B:B5A7',  # Computer disk terminal in world 4
]:
    call_site = sbt86.Addr16(str=call_site)
    continue_at = call_site.add(1)
    subroutine = b.jumpTarget(call_site)
    b.patchAndHook(
        call_site, 'ret', 'g.hw->output.pushDelay(20);'
        'g.proc->continueFrom(r, &sub_%X);' % continue_at.linear)
    b.patch(continue_at, 'call 0x%04x' % subroutine.offset, length=2)
    b.markSubroutine(continue_at)

# Break control flow in the transporter animation loop,
# it's too long to store in the output queue.
video_blit_frame = sbt86.Addr16(str='0E3B:1700')
for call_site in [
        '0E3B:6E77',  # Sewer -> Subway
        '0E3B:898B',  # Subway -> Town
        '0E3B:958A',  # Town -> Comp
Пример #2
0
basedir = sys.argv[1]
b = sbt86.DOSBinary(os.path.join(basedir, 'menu.exe'))

b.decl('#include <string.h>')

bt_common.patchJoystick(b)
bt_common.patchFramebufferTrace(b)
b.hook(b.entryPoint, 'enable_framebuffer_trace = true;')

# Time everything in this EXE, not just sound subroutines
sbt86.Subroutine.clockEnable = True

# Dynamic branch for cutscene sound effects
b.patchDynamicBranch('019E:0778', [
    sbt86.Addr16(str='019E:0788'),
    sbt86.Addr16(str='019E:07D0'),
    sbt86.Addr16(str='019E:07AB')
])

# This isn't actually self-modifying code, but some data stored in the code segment
# will trigger some warnings that we can silence by marking the area explicitly as data.
b.patchDynamicLiteral('019E:0517', length=2)
b.patchDynamicLiteral('019E:0519', length=2)

# The main menu is a subroutine with a single caller;
# inline it to make cutting the control flow easier. Also disable framebuffer traces
# while drawing the main menu, so we can draw it faster.
b.patchAndHook('019E:012A', 'jmp 0x310', 'enable_framebuffer_trace = false;')
b.patchAndHook('019E:034A', 'jmp 0x12d', 'enable_framebuffer_trace = true;')
Пример #3
0
b.patch('0D63:5CFB', 'jmp 0x5D14')

# Remove model "A disk error has occurred"
b.patch('0D63:5E3E', 'ret')

# Remove modal "Insert disk 1" message before exiting back to menu
b.patch('0D63:5FFD', 'jmp 0x6016')

# Break control flow at remaining locations that wait for keyboard
for call_site in [
        '0D63:26D7',  # Menu for "?" key
        '0D63:26E4',  # Menu for "ESC" key
        '0D63:7F78',  # Chip data editor (press "?" while holding a chip)
        '0D63:821D',  # Help for chip data editor ("?" in editor)
]:
    call_site = sbt86.Addr16(str=call_site)
    continue_at = call_site.add(1)
    subroutine = b.jumpTarget(call_site)
    b.patchAndHook(
        call_site, 'ret', 'g.hw->output.pushDelay(20);'
        'g.proc->continueFrom(r, &sub_%X);' % continue_at.linear)
    b.patch(continue_at, 'call 0x%04x' % subroutine.offset, length=2)
    b.markSubroutine(continue_at)

# Inline the single-caller chip data editor so we can insert continuations
# within the editor's help screen without losing control flow in the outer editor.
b.patch('0D63:7F5F', 'jmp 0x7FB1')
b.patch('0D63:8061', 'jmp 0x7F62')
b.patch('0D63:8232', 'jmp 0x7F62')

# Inline check_main_game_keys too, since the chip editor's outer event loop ends
Пример #4
0
bt_common.patchJoystick(b)
bt_common.patchFramebufferTrace(b)
b.hook(b.entryPoint, 'enable_framebuffer_trace = true;')

# Go directly to the new-game cutscene after we get the SHW file reader setup
b.patch('019E:00F8', 'jmp 0x1A6')

# Launch the game once this cutscene ends
b.patchAndHook('019E:04DB', 'ret', 'g.hw->exec("game.exe");')

# Time everything in this EXE, not just sound subroutines
sbt86.Subroutine.clockEnable = True

# Dynamic branch for cutscene sound effects
b.patchDynamicBranch('019E:0778', [
    sbt86.Addr16(str='019E:0788'),
    sbt86.Addr16(str='019E:07D0'),
    sbt86.Addr16(str='019E:07AB')
])

# This isn't actually self-modifying code, but some data stored in the code segment
# will trigger some warnings that we can silence by marking the area explicitly as data.
b.patchDynamicLiteral('019E:0517', length=2)
b.patchDynamicLiteral('019E:0519', length=2)

# This binary uses wallclock time for some delays.
# A save function is called before drawing the screen, to store a seconds timestamp.
# Then, one of two fixed-duration delay functions are called to wait 4 seconds or 1 second
# after the timestamp that was saved earlier.

# Stub out the function which saves the wallclock time ref
Пример #5
0
import sbt86
import bt_common

basedir = sys.argv[1]
b = sbt86.DOSBinary(os.path.join(basedir, 'menu2.exe'))

bt_common.patchJoystick(b)
bt_common.patchFramebufferTrace(b)
b.hook(b.entryPoint, 'enable_framebuffer_trace = true;')

# Time everything in this EXE, not just sound subroutines
sbt86.Subroutine.clockEnable = True

# Dynamic branch for cutscene sound effects
b.patchDynamicBranch('019E:068B', [
    sbt86.Addr16(str='019E:069B'),
    sbt86.Addr16(str='019E:06E3'),
    sbt86.Addr16(str='019E:06BE')
])

# This isn't actually self-modifying code, but some data stored in the code segment
# will trigger some warnings that we can silence by marking the area explicitly as data.
b.patchDynamicLiteral('019E:0434', length=2)
b.patchDynamicLiteral('019E:0436', length=2)

# Remove the unneeded splashscreen and main menu
b.patch('019E:0102', 'ret')

# At the very end of the final cutscene, we're greeted with an
# infinite loop. Break that loop with a delay.
final_loop = sbt86.Addr16(str='019E:0221')