News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu

Recent posts

#1
avatar_lightforce6128
Games / Re: Turrican (128K)
Last post by lightforce6128 - Today at 22:49
Quote from: Jean-Marie on Yesterday at 20:06Only the end of the procedure remains mysterious to me (after the palette setting).

I tried to understand what is going on there, but also without success. The additional code somehow builds up an index (a table with addresses) for another, more complex data structure. Maybe this is somehow related to sprites, maybe it is something completely different.

ORG #1B39

    prepare_tiles:

        LD HL,#1B1F : CALL set_table_of_firmware_inks                ;; Set palette.
        LD BC,#002C : LD DE,#D7CC : LD HL,#D7CB : LD (HL),#04 : LDIR ;; Fill buffer with vertical stripes (blue-yellow). Why?
        LD BC,#0030 : LD DE,#6DC0 : LD HL,#6930 : LDIR               ;; Create copy of sprite. This overwrites font data "789".
        LD BC,#0040 : LD DE,#6D40 : LD HL,#6CB0 : LDIR               ;; Create copy of big flame. This overwrites font data "_012".

        LD B,#06                                                ;; Counter for outer loop.
        LD IX,#243E                                             ;; Target address. Table reaches below source address (length: 192, 96 entries).
        LD DE,#0006                                             ;; Source step size.
        LD HL,#24FE                                             ;; Source address.
        outer_loop:                                             ;;
            LD C,#10                                            ;; Counter for inner loop.
            inner_loop:                                         ;;
                LD (IX+#01),H : LD (IX+#00),L : INC IX : INC IX ;; Store source address in target entry.
                search_marker_loop:                             ;;
                    LD A,(HL) : INC HL                          ;;
                    CP #D3 : JP Z,marker_found                  ;;
                    ADD HL,DE                                   ;; Go to next source record.
                JP search_marker_loop                           ;;
                marker_found:                                   ;;
            DEC C : JP NZ,inner_loop                            ;;
        DJNZ outer_loop                                         ;;

        ;; Here:
        ;;     IX            - The target pointer has reached the begin of the source at #24FE.
        ;;     HL            - The source pointer has reached the begin of sprite data at #2BD2.
        ;;     (#243E)       - Target entry 0 points to a value #D3.
        ;;     (#243E+n*2)   - Other target entries point to a value behind #D3.
        ;;     ((#243E+n*2)) - a sequence like ( [type] [adr_low] [adr_high] [?] [?] [?] [?] )+

        RET



ORG #D600

    set_table_of_firmware_inks:

        ;; HL - Table of 17 firmware inks (for 16 pens and border).

        LD E,(HL)                           ;; E is loaded, but not used.
        LD D,#10                            ;; Pen counter, 16..1.
        pen_loop:                           ;;
            LD A,D : SUB #10 : NEG : LD C,A ;; Pen, 0..15.
            LD A,(HL)                       ;; Read firmware ink from table.
            CALL set_pen_to_firmware_ink    ;; Set pen to ink.
            INC HL                          ;; Go to next firmware ink.
        DEC D : JP NZ,pen_loop              ;;

        LD C,#10                            ;; Finally select border (pen 16).
        LD A,(HL)                           ;; Read final firmware ink.
        ;;                                  ;; Fall through to subroutine without CALL.

    set_pen_to_firmware_ink:

        ;; A - firmware ink
        ;; C - pen

        PUSH HL                          ;;
            ADD #85 : LD L,A             ;; Calculate low byte of address (+#85).
            ADC #DE : SUB L : LD H,A     ;; Calculate high byte of address (+#DE).
            LD A,(HL)                    ;; Read hardware ink.
        POP HL                           ;;
        AND #1F : OR #40                 ;; Mask ink and add command bit for Gate Array.
        LD B,#7F : OUT (C),C : OUT (C),A ;; Set ink.
        ;;                               ;;
        RET                              ;; Jump back to pen loop or to caller of 'set_table_of_firmware_inks'.
#2
avatar_lightforce6128
Games / Re: Turrican (128K)
Last post by lightforce6128 - Today at 22:39
After looking at the drawing of tiles, now I had a look at drawing of sprites. This is by far more complex and distributes over several longer routines. The following BASIC-like pseudo-code gives a coarse overview about what is happening there. The given addresses map to the begin of routines or code blocks.


0DA9: copyTilesToScreen()
0E28: FOR EACH sprite IN spriteList DO
0E3A:    IF sprite IS ExtrasSphere THEN
0E60:        copySmallerExtrasSphereSpriteToATemporaryNormalSprite()
----:    END IF
AEF0:    WITH sprite DO
A7C0:        mirrorHorizontally()
9F00:        mirrorVertically()
AF04:        clipHorizontally()
AF48:        clipVertically()
AFC3:        copyNonTransparentBytesToScreen()
----:    END WITH
0EA9: NEXT
0EB2: drawSpriteWithoutClipping(mine)
0EB9: drawSpriteWithoutClipping(player)
0EE8: drawSpriteWithoutClipping(shield)
DE00: FOR EACH explosion in explosionList
DE2A:    getAnimation()
DE11:    drawSpriteWithoutClipping(explosion)
DE14:    updateAnimation()
----: NEXT
0EEE: swapScreenBuffers()
----:
DF02: SUB drawSpriteWithoutClipping(sprite) : ... : END SUB

Also I would like to, I cannot provide a well commented disassembly. This would be by far too much work. But at least some discoveries I would like to share:

  • There is not any kind of caching or reuse.
  • In each frame, the extras spheres are converted to normal sprites again.
  • In each frame, each single sprite (that needs to) is mirrored again.
  • The converted sprites with the extras sphere are transparent at more than 50% of the bytes. Nevertheless each transparent byte is built up during the conversion and skipped later while drawing the sprite. In each frame, for each single extras sphere.
  • There are smaller and bigger explosions. It seems, the latter one is not used.
  • The smaller explosions skip their last animation step due to a programming error.

For the loop for drawing a sprite I can provide a disassembly. I think this can be optimized. Using this routine takes ~3000 NOPs to draw a single sprite. This is 15% of a frame. Drawing 6 sprites eats up a whole frame. Bad things will happen if an extras box is destroyed and releases a bunch of extras spheres.


ORG #AFC3

;; This routine draws a single sprite after mirroring and clipping have been applied.
;;
;; B  - clipped height (full height is 24)
;; C  - clipped width (full width is 6)
;; DE' - source address
;; HL' - target address
;; (source_skip-2)  - bytes to skip in source for each row
;; (target_skip-2)  - bytes to advance target for each row
;; (jump_condition) - set to #CA (JP Z) or #C2 (JP NZ)

draw_sprite:

    y_loop:                                                            ;;             ;;
        LD A,C                                                         ;;  1          ;;
        EXX                                                            ;;  1          ;;
            ;;                                                         ;;  |          ;;
            x_loop:                                                    ;;  |          ;; To write one byte, this inner loop takes 17 NOPs.
                EX AF,AF'                                              ;;  |----- 1   ;; Save A.
                    LD A,(DE) : INC DE                                 ;;  |    +-4-+ ;; Load sprite data and update source pointer.
                    OR A : JR Z,$+3                                    ;;  |    3  4  ;; Is byte opaque?
                        LD (HL),A                                      ;;  |    +---2 ;; Write byte.
                    INC HL                                             ;;  |      2   ;; Update target pointer.
                EX AF,AF'                                              ;;  |      1   ;; Restore A.
            DEC A : JP NZ,x_loop                                       ;;  |----- 4   ;;
            ;;                                                         ;;  |          ;;
            EX DE,HL                                                   ;;  1          ;; Swap registers to allow DE=DE+BC.
                LD BC,#0000 :source_skip                               ;;  3          ;; Skip bytes in source data.
                ADD HL,BC                                              ;;  3          ;;
            EX DE,HL                                                   ;;  1          ;;
            ;;                                                         ;;  |          ;;
            LD BC,#07FA :target_skip                                   ;;  3          ;; Go to next row and skip bytes on screen.
            ADD HL,BC                                                  ;;  3          ;;
            ;;                                                         ;;  |          ;;
            BIT 6,H                                                    ;;  2          ;; Was the screen memory left?
            jump_condition: JP Z,$+7                                   ;;  3          ;;
                LD BC,#C040 : ADD HL,BC                                ;; (6/8)       ;; Then correct target pointer.
            ;;                                                         ;;  |          ;;
        EXX                                                            ;;  1          ;;
    DJNZ y_loop                                                        ;;  4-1        ;;
    ;;                                                                 ;; ----  ----- ;;
    ;;                                                                 ;; 26-1  15|18 ;; (6*(15+18)/2+26+6/8)*24-1 = ~3017 NOPs per sprite.
#3
D
GFX + Tunes / Re: Amstrad music
Last post by dal - Today at 21:02
#4
avatar_iXien
Games / Re: Converted GX4000 .cpr - Th...
Last post by iXien - Today at 20:18
We have an update here, this weekend :P :

HARRIER ATTACK RELOADED (version 07/08/2025) from Chris Perver

Very nice new features and bugfixes, check it here: https://cp-soft.itch.io/harrier-attack-reloaded

Have a nice weekend ;)

#5
and now the real fun begins! Any other fans of Spindizzy?
 
#6
avatar_TMTLOGIC
Games / Re: 4 TMTNet multiplayer netwo...
Last post by TMTLOGIC - Today at 20:08
It's definitely worth trying Quigs programming.
It's similar to Visual Basic.
Tembmint has created this fantastically.

A big advantage is that the graphics part is done quite quickly.
And you can create software for more than four computer types: MSX, CPC, Enterprise, PCW...

We'll explain more on my Discord channel together with Edoz.

#7
avatar_Jean-Marie
Games / Re: Turrican (128K)
Last post by Jean-Marie - Today at 18:32
I got the first level working under its newly compressed form :) Many thanks to @lightforce6128 for the hints!
#8
A
Games / Re: Vespertino
Last post by andycadley - Today at 16:36
Still not as weird as the SNES art



But they were all produced at different times for different markets, probably by different marketing teams with whatever strategy they supposedly had.

I'm not sure why you'd single out any on version as being "not professional" regardless of your overall opinion of each.
#9
And finally success. I was able to desolder the older chips and replace them with sockets and fresh ram chips. I gotta thank each and every one of you who encouranged and helped me with this. I have learned so much! Thank you!!



#10
avatar_XeNoMoRPH
Games / Re: Mighty Street fighter - CP...
Last post by XeNoMoRPH - Today at 12:41
QuoteMSF version 1.2 Turbo is programmed to launch July 18 for the latest generation, the full version supports projects, together with a demo version with 3 playable characters that are also available for all of the world

Powered by SMFPacks Menu Editor Mod