7

I'm curious if it is possible to fool an in game timers in an old DOS game. Specifically, King's Quest 3 makes you wait 15 minutes at one point. I don't know how that timing system works or how time works in DOS. I'm wondering if there's a way to set it to just before daylight savings time and then have the clock tick forward an hour during the wait to fool the clock. I don't know whether or not that makes sense with how DOS kept time or how DOS based games adjusted their own timers.

EDIT: To clarify, I'm curious because it is a major delay in world record attempts. I am not capable of playing the game at world record speeds, but I find it interesting. The techniques they use must be achievable on period hardware, though they typically play on emulators. I'm wondering if there is a way that speed runners could skip some of that delay (which seems unaffected by speeding up the clock cycle, though other aspects of the game are).

14
  • 2
    The question seems a little too broad-scoped. Are you asking about King’s Quest specifically, or whether it's possible to intercept timekeeping interfaces in general? If the latter, there'd be a lot to write about. Apr 7, 2022 at 15:08
  • 1
    It depends on which TSR you clobber. You could clobber the timer TSR and speed it up or slow it down. It would play havoc with the system clock.
    – cup
    Apr 7, 2022 at 17:09
  • 4
    Given how rabid some old-timers are about experiencing retro as it was, maybe you should consider putting up with the delay :-) Otherwise, it's not really King's Quest 3.
    – paxdiablo
    Apr 7, 2022 at 22:42
  • 1
    using a debugger to hack it, I don't think it can easily be done with this game. This is a virtual machine language. You have to understand the interpreter and change the bytecode to hack it. This can be done directly, but this is really trickier and limited. Anyway, you're not supposed to cheat if you want to break a record... Apr 8, 2022 at 6:38
  • 1
    DST switchover usually needs to be done manually on DOS systems, as there are no tools or mechanisms which handle this task. So this is not usable for you.
    – ecm
    Apr 8, 2022 at 7:28

1 Answer 1

12

many old games uses PIT (IIRC i8253 programmable interrupt timer chip) for timing without touching its settings. So its easily possible to chage its frequency from original 18.2 Hz to anything up to ~1192755.2 Hz fooling DOS time too (will be much faster).

I used this a lot back in the 286 days for games like Tunneler had made a simple command line utility where you specify how much faster the clock should run and you use it prior to execute your game.

I found the old (heh 20 years) TASM source for it (its simple *.com file) called QUICK.COM:

    .386P
    IDEAL
    MODEL TINY

    DATASEG
    hdr db 'SPEKTRA software & hardware Time quicker ver 2.0',13
        db '    Made in XX XXXXX 21.12.1998 by Spektre.',13
        db 'usage: quick.com n    ... n number <18,65535>',13
        db '       n < 19  ... normal clock speed 18.2 Hz',13
        db '       n > 19  ... increased clock speed n Hz',13
    msg0    db 'No parameter found,normal clock selected.',13
    msg1    db 'Parameter found,time clock selected to      ',0
        db ' Hz',13

    CODESEG
    STARTUPCODE
    jmp main
                    ;print txt
print:  mov ah,13           ;SI-adr data,DI-adr scrn
    push di             ;save pozition on the screen
prnl0:  mov al,[ds:si]
    cmp al,ah
    jz prnr0
    or al,al
    jz prnr1
    mov [es:di],al
prnr0:  inc di
    inc di
    inc si
    cmp al,ah
    jnz prnl0
    pop di
    add di,160          ;next line
    ret
prnr1:  pop ax              ;end without ENTER 
    inc di
    inc di
    inc si
    ret
                    ;text to number
tton:   mov si,130
    sub bx,bx
    sub ah,ah
ttonl0: mov al,[ds:si]
    inc si
    sub al,48
    cmp al,9
    ja ttonr0
    mov dx,bx
    mov cx,9
ttonl1: add bx,dx
    loop ttonl1
    add bx,ax
    jmp ttonl0
ttonr0: mov ax,bx
    ret 
                    ;number to text
ntot:   mov bx,10           ;print AX number on DI pozition
    push di
ntotl0: sub dx,dx
    div bx
    add dl,48
    mov [es:di],dl
    sub dl,48
    dec di
    dec di
    or ax,ax
    jnz ntotl0
    pop di
    inc di
    inc di
    ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                    ;Time quicker (PIT frequency)
main:   mov ax,3
    int 16
    mov ax,0B800h
    mov es,ax

    mov di,160
    lea si,[hdr];
    call print
    call print
    add di,160
    call print
    call print
    call print

    mov bx,129
    mov al,[ds:bx]
    cmp al,13
    jz noparam

param:  call tton
    cmp ax,19
    jb pitrst
    push ax
    
    mov dx,12h          ;set PIT freq.
    mov bx,ax
    mov ax,34ddh
    div bx
    mov bx,ax
    mov al,34h
    out 43h,al
    mov ax,bx
    out 40h,al
    xchg al,ah
    out 40h,al

    add di,160
    lea si,[msg1]
    call print
    pop ax
    call ntot
    call print
    jmp ende

noparam:add di,160
    lea si,[msg0]
    call print

pitrst: mov al,34h          ;reset PIT freg.
    out 43h,al
    sub ax,ax
    out 40h,al
    out 40h,al

ende:   EXITCODE
    END

But its simple as just doing several out instructions to configure the PIT ...

If you want to speed up the time only for a specific moment you could make an TSR with hooking keyboard ISR and if specific key combination is hit activate or deactivate the speed ... This way you can workaround also games that configure PIT with their own settings (unless they hook the keyboard without running original ISR in such case use different interrupt like mouse or whatever)...

Here asm code of one of mine ancient DOS games:

Inspect the int09 ISR how it is hooked up and how it works. And here ancient TASM template for TSR programs (also *.com file):

    intnum  equ 5

    .386P
    IDEAL
    MODEL TINY

    CODESEG
    STARTUPCODE
    
    jmp main
ints:                   ;zaciatok int
    cli
    push ds
    pusha

    mov ah,09h          ;rezident
    push cs
    pop ds
    lea dx,[txt]
    int 21h

    popa
    pop ds
    sti
intov:  jmp far 0000:0000

    id  dw 10           ;ID string (detection):lenght,string
        db 'SPEKTRA S.& H. slower v 1.0'
    txt db 'No printer found.',13,10,'$'
inte:                   ;koniec int

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    msg0    db 'Program has been succesfully installed.',13,10,'$'
    msg1    db 'Program has been succesfully uninstalled.',13,10,'$'

main:   mov al,intnum       ;test if TSR is in memory
    mov ah,35h
    int 21h
    mov di,bx
    add di,id+2-ints
    mov si,offset id+2
    mov cx,[word ptr id]
    rep cmpsb

    jz unin
    mov [word ptr intov+1],bx
    mov [word ptr intov+3],es
    mov al,intnum
    mov ah,25h
    lea dx,[ints]
    int 21h
    mov ah,09h
    lea dx,[msg0]
    int 21h
    mov dx,offset inte+16
    int 27h
unin:   push ds
    mov dx,[word ptr es:intov+1]
    mov ax,[word ptr es:intov+3]
    mov ds,ax
    mov al,intnum
    mov ah,25h
    int 21h
    pop ds
    mov ah,49h
    int 21h
    mov ah,09h
    lea dx,[msg1]
    int 21h
    ret 

    end

P.S. here is my VC.EXT extention entry for Volkov Commander association to compile in single hit with keyboard):

asm:@c:\language\compil\tasm\tasm !.! /ic:\language\source\tasm\inc
    @c:\language\compil\tasm\tlink !.obj /t /x
    @del !.obj

You can extract the compilation and linking switches from it in case you want to compile the above code... You need TASM and TLINK for that ...(IIRC TLINK can be found in bin folder of any ancient Borland Turbo C or Turbo Pascal)

The /ic:\language\source\tasm\inc switch is just my include folder but the code above does not use any lib anyway... the !.! means your source code filename with extention and !.obj is the same but with changed extention to obj ...

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .