Image Map Image Map
Page 6 of 21 FirstFirst ... 234567891016 ... LastLast
Results 51 to 60 of 204

Thread: MagiDuck, a DOS / CGA text mode game project

  1. #51

    Default

    Quote Originally Posted by deathshadow View Post
    If you're going to play with the timer, you REALLY should be putting your own ISR on it. My question would be are you using TIMER to simply loop to wait until it's time for the next frame, or are you using it to scale the game logic in realtime so it can run more frames on faster machines while still being the same "speed" of play?

    If we assume the former, and that you're running the divisor at 8192 for that 8x speed...
    Many thanks for the code! I think you saved me some years there. My sprite masking logic was already stolen from you, but now I've got some actual copy-pasted lines too, dang. Credit will be given, of course

    That's right, the game only waits for the next frame and doesn't scale any transformations by time. Testing collisions would've been quite a bit more expensive if time was accounted for.

    I added your routines to my library and got things working after a few days of fiddling and reading. Nothing wrong with your code of course, but MASM didn't like some things and I lost plenty of hours because I'd copied 3508 as decimal instead of hex, hah. Ended up learning more this way, so no big deal

    One disconcerting side effect appeared though, Quickbasic tends to crash after a few minutes if I run the game from the editor... I wonder what QB does with the timer, since the original timers memory location is the same, whether it's requested from a compiled runtime or from the interpreted version (0000:FEA5).

    Compiled versions of the game seem stable (running and exiting the game five times), so I ended up ditching the Qbasic editor and started using Notepad++ and compiling from command line.

    Sometimes QB gets far enough before crashing to show a "String space corrupt" -error, so I think more testing with the runtime should be in order though.
    Last edited by mangis; March 17th, 2015 at 08:50 AM.

  2. #52
    Join Date
    Aug 2006
    Location
    Chicagoland, Illinois, USA
    Posts
    4,427
    Blog Entries
    1

    Default

    Quote Originally Posted by deathshadow View Post
    Code:
    %define countInc WORD 0x4000
    %define countDec WORD 0x09B9
    
    timerISR:
        inc   WORD [cs : timerTick]
        sub   [cs : timerCount], countDec
        js    .oldCall
        push  ax
        mov   al, 0x20
        out   0x20, al
        pop   ax
        iret
    .callOldTimerISR:
        add   [cs : timerCount], countInc
        db   0xEA
    oldTimerISR:
        dd   0x00000000
    I just noticed this -- why are you adding to cs:timerCount when calling the old handler? A single op should be all that is necessary, ie.:

    Code:
            add     [cs:timerCount],PITDIVRATE ;add to our BIOS counter
            jc      @@handlebiostick        ;if didn't roll over, skip BIOS tick
            push    ax
            mov     al,20h                  ;acknowledge PIC so others may fire
            out     20h,al                  ;ok to do this here since we are
            pop     ax                      ;top priority in PIC chain
            iret
    @@handlebiostick:
            db      0xEA
    oldTimerISR:
            dd      0x00000000
    ...or equivalent. timerCount is your own var; no need to do special handling just because you're chaining to the BIOS int...
    Offering a bounty for:
    - Documentation and original distribution disks for: Panasonic Sr. Partner, Corona PPC-400, Zenith Z-160 series
    - Music Construction Set, IBM Music Feature edition (has red sticker on front stating IBM Music Feature)
    - Any very old/ugly IBM joystick (such as the Franklin JS-123)

  3. #53

    Default

    Heh, good catch. I was thinking bresenham in my head, reversing the logic (so PITDIVRATE would be... 0x26E4?) would give the same result.

    So used to coding line-draw where the 'inc' is never a fixed value... I just automatically did it that way without thinking about it.

    Thanks. Probably won't have a significant performance impact, but it sure can't hurt.
    From time to time the accessibility of a website must be refreshed with the blood of owners and designers. It is its natural manure.
    CUTCODEDOWN.COM

  4. #54
    Join Date
    Aug 2006
    Location
    Chicagoland, Illinois, USA
    Posts
    4,427
    Blog Entries
    1

    Default

    Quote Originally Posted by deathshadow View Post
    (so PITDIVRATE would be... 0x26E4?)
    Exactly, to fire twice per CGA refresh rate.
    Offering a bounty for:
    - Documentation and original distribution disks for: Panasonic Sr. Partner, Corona PPC-400, Zenith Z-160 series
    - Music Construction Set, IBM Music Feature edition (has red sticker on front stating IBM Music Feature)
    - Any very old/ugly IBM joystick (such as the Franklin JS-123)

  5. #55

    Default

    Quote Originally Posted by Krille View Post
    When you add to or subtract from a 16-bit register and the low byte of the immediate value is zero, like this;
    Code:
    sub cx, 4000
    then you can save a byte by doing it like this;
    Code:
    sub ch, 40
    Oops! I just noticed that the above numbers are in decimal format. My advice applies only when the numbers are in hexadecimal format. Sorry if this wasted your time. Also, just to clarify, this is only an optimization when the register is not AX.

    Quote Originally Posted by mangis View Post
    Sometimes QB gets far enough before crashing to show a "String space corrupt" -error, so I think more testing with the runtime should be in order though.
    It's been a while since I did anything in QB but IIRC, this can also happen when you use a lot of memory (string space) and/or have very big strings. In other words, it can just as well be a bug in QB.
    Looking for a cache card for the "ICL ErgoPRO C4/66d V"

  6. #56

    Default

    Quote Originally Posted by Krille View Post
    It's been a while since I did anything in QB but IIRC, this can also happen when you use a lot of memory (string space) and/or have very big strings. In other words, it can just as well be a bug in QB.
    Probably not a bug in QB, the EXE-version got some random corrupted pixels in it's sprite memory (lucky, easy to spot) as well.

    Tried a simple thing today and it seemed to fix everything:

    Moving all variables (timerTick, timerCount, etc) from .DATA to .CODE in the assembly listing seemed to fix the problem. The game runs solid both from Qbasic and as EXE, even when restarted muliple times.

    I guess anything put in .DATA would get moved around to where ever LINK, LIB or BC would put data (from the whole program, not just the library) during library compiling. Maybe writing to a variable offset supposedly in CS could go in all kinds of places after that?

    Since variables seem to work so well now, my other routines could really benefit from them too... I wouldn't need to send obvious information like sprite bank memory offsets every frame through stack.

    Just to show how things are ordered in the assembly routines now:
    Code:
    .model medium,basic
    
    .data
    
    .code   
    ;==============================================================================
    ;
    ; Procedures
    ;
    ;============================================================================== 
    
    aTimerStart PROC
    aTimerStart ENDP
    
    aTimerEnd PROC
    aTimerEnd ENDP
    
    aTimerWait PROC
    aTimerWait ENDP
    
    aTimerReset PROC
    aTimerReset ENDP
    
    ;==============================================================================
    ;
    ; Timer ISR
    ;
    ;============================================================================== 
    
        timerISR:
            inc     timerTick
            dec     timerCount
            jz      callOldTimerISR
            push    ax
            mov     al, 20h
            out     20h, al
            pop     ax
            iret
                
    
        callOldTimerISR:
            mov  timerCount, 8
            db 234
            oldTimerISR dw 1234h, 5678h, 0000h, 0000h, 0000h
            ; Added some dummy data for safety(?)
    
    ;============================================================================== 
    ;
    ; Code segment variables
    ;
    ;============================================================================== 
        
        screenSeg       dw  0b800h
    
        timerTick       dw  0
        timerCount      db  8
        timerActive     db  0
    
    ;============================================================================== 
        
    
    public aTimerStart
    
    public aTimerEnd
    
    public aTimerReset
    
    public aTimerWait
    
    end

  7. #57

    Default

    I can't speak for QB, but I know "good old" GW-Basic played fast and loose with segments to the point integrating ASM was a chore at best. If it has any of the same mechanisms in place I'd not be at all surprised if half the time you went to call those routines you were getting a different value in DS than your .DATA declaration was allocating... hence why putting them in your code segment is running fine.

    It's part of why BASIC -- ANY form of BASIC -- would have been the LAST language I'd have gone to for building something like this excepting perhaps Turbo Basic -- IMHO that makes what you've accomplished all the more impressive; but also makes me wonder how much faster/more effficient/easier to develop it would have been to use a Borland Pascal or C compiler.
    From time to time the accessibility of a website must be refreshed with the blood of owners and designers. It is its natural manure.
    CUTCODEDOWN.COM

  8. #58
    Join Date
    Dec 2014
    Location
    The Netherlands
    Posts
    1,634

    Default

    Quote Originally Posted by mangis View Post
    Moving all variables (timerTick, timerCount, etc) from .DATA to .CODE in the assembly listing seemed to fix the problem. The game runs solid both from Qbasic and as EXE, even when restarted muliple times.
    This is obvious though...
    You are using an interrupt handler. Interrupts are basically far-calls, and you don't know what any segment other than cs is (cs being your int handler).
    So you either need to store all your data for your int handler in the same segment as the code of the int handler... Or you need to store a variable containing the segment for your data in the int handler segment, and load ds (and/or es) yourself (don't forget to restore it before exiting the handler).

    That isn't language-specific. It's just how the x86 works.

  9. #59

    Default

    Quote Originally Posted by Scali View Post
    This is obvious though...
    OH, yeah. I thought he was talking all his .data -- of course the ISR stuff HAS to be in CS as you can't rely on DS being static... and .DATA is DS based. That's why my code example had the segment override.
    From time to time the accessibility of a website must be refreshed with the blood of owners and designers. It is its natural manure.
    CUTCODEDOWN.COM

  10. #60

    Default

    Quote Originally Posted by deathshadow View Post
    It's part of why BASIC -- ANY form of BASIC -- would have been the LAST language I'd have gone to for building something like this excepting perhaps Turbo Basic -- IMHO that makes what you've accomplished all the more impressive; but also makes me wonder how much faster/more effficient/easier to develop it would have been to use a Borland Pascal or C compiler.
    Certainly can't disagree there. Almost every line of code is trying so hard not be BASIC at this point, it might as well not be.
    With C it might be possible to shave off 30kb from the executable size. Saving many of the variables as bytes instead of words would be nice as well... Using that memory and better speed to improve the game is pretty tempting.

    I tried playing around with Turbo C 2 last year, but this doesn't feel like the right time for a rewrite... I'm not really convinced the game is worth redoing 2500 lines of Assembly and 2000 lines of BASIC, while learning C nearly from scratch. At least yet. It might be easier when I've got the games features well in place to avoid useless work.

    Moving from Quickbasic editor to Notepad++ already boosted up my productivity slightly, I can make the code much more readable and don't have to worry about comments using precious memory. Everything feels much less cramped now.

    I also ditched my custom level editor and made a batch-conversion program to convert levels from Tiled. Creating and iterating on levels is much faster now.

    Quote Originally Posted by Scali View Post
    This is obvious though...
    Yup, it was pretty embrassing to realise how "un-assembly" that thinking was.
    Last edited by mangis; March 28th, 2015 at 04:44 AM. Reason: Removed a mistaken statement about using CS.

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •