Crap 0.1 first assembly project

Show us what you're working on, (preferably with screenshots).
Post Reply
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Crap 0.1 first assembly project

Post by RMartins »

Joefish wrote: Thu Jan 11, 2018 2:11 pm ...
If I've got a bit of code I want to repeat between REPT / ENDM markers, and I put a label in it, it throws up an error as the label counts as a redefinition the second time it's repeated. But every way I can think of for trying to define the label as local to the REPT macro fails.
I believe this is where the problem lays.

You are confusing two concepts, understandbly, because they seem similar, but they are not.

One is a local LABEL, that is limited to the context where it is inserted within.
This is were you use the LOCAL or "_" prefix situations

Another is how to generate DISTINCT labels when using a MACRO.
Here, what you need is to understand how a MACRO works and what the ## operator is for.

A MACRO is just a way to inform the compiler to make Copy&Paste actions (with some optional replace in between), for you.

The manual refers in the Macros Generalities section, the following
Identifier pasting: inside a MACRO the operator ## can be used to join two idenfiers resulting in another identifier. This is intended to allow the creation of identifiers dependent of macro arguments.
This should help you to generate unique and distinct labels when using MACROS.

NOTE: you can also use LOCALs on MACROS, if done correctly.
REPT is just a special MACRO. Check the manual.

WARNING: There is a CAVEAT, when using MACROS, basically a MACRO is referenced by it's name, which can be confused by the compiler to be a label, if you have not included the MACRO before using it.
So take that into account.
User avatar
Joefish
Rick Dangerous
Posts: 2042
Joined: Tue Nov 14, 2017 10:26 am

Re: Crap 0.1 first assembly project

Post by Joefish »

I'm not confusing any of that - I can concatenate names and labels just fine.
What the manual lacks is the syntax for how to use the LOCAL command.

What it seems you need to do is declare your label as local by inserting "LOCAL my_label" on a line within the loop/macro/whatever context, but completely separately from the line where you actually implement the label, e.g "my_label PUSH AF" at the start of your loop or whatever.
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

Yep, exactly. That’s how the parser is coded, for whatever reason.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
RMartins
Manic Miner
Posts: 776
Joined: Thu Nov 16, 2017 3:26 pm

Re: Crap 0.1 first assembly project

Post by RMartins »

Joefish wrote: Mon Jan 15, 2018 2:17 pm I'm not confusing any of that - I can concatenate names and labels just fine.
What the manual lacks is the syntax for how to use the LOCAL command.

What it seems you need to do is declare your label as local by inserting "LOCAL my_label" on a line within the loop/macro/whatever context, but completely separately from the line where you actually implement the label, e.g "my_label PUSH AF" at the start of your loop or whatever.
OK, but if you can concatenate names and labels, you can create unique labels everytime you call a MACRO, and this prevents the need for LOCAL labels.

We only need LOCAL labels, if somehow we want to use the EXACT same label elsewhere, in a different context.
Because that is the only use case for LOCAL labels.

And if you start to use MACROS that call MACROS you can get into trouble again easily, with either duplicated definitions or unknown labels, when inside a MACRO within another MACRO.

I usualy favor global Labels, parameterized (PREFIX or POSTFIX) to be unique.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Day 24: 341 days left..

Bet ya thought I had abandoned the project :P No, just my internet connection hates me. In the intervening 11 days went about things old school hitting the books while I was unable to access
the 'world wide web'.

It's surprising what a push that gave things actually, I got all of the graphics finished for crap chess, re-factored the code, created an animated intro screen and played around with a tech demo for copying board layouts from memory. (that was for something completely different but then it struck me this was exactly what I needed for crapchess and controlling the screen!)

Well despite this progress things have been slow, with a combination of no internet and the cat sabotaging my laptop any chance he gets. Its at times like these it shows just how dependent we all have become on the net for a research tool. There were tons of times I was catching myself trying to go onto google to solve a pickle I was in.

In the end I just had to hit the books (usually pointless for specifics) or just brute force a solution by trying every variation of a routine I could to try and get it to work. That is how the board copier 'spawned'. The code is not the prettiest, having used all of the registers already and not really understanding enough to get me out of trouble and the books giving woolly ivory tower explanations like 'manage your stack' :lol: I just used memory locations to store variables.

It was at this point I discovered what was worst than spaghetti goto code... tons of magic numbers for memory locations with values sprinkled willy nilly. Somehow it worked. but I shudder thinking about it...

Music was something that brought a little sanity into the mix. I composed a few little ditties on beepola but the issue was first getting it to load in the program. For very short music its ok. But when things got long or complicated the size of the file was ballooning to 12-15k. When I tried to add it to crap chess I suspect there is not enough room.

I can get the simple tracks to play continuously at the start of the program, but trying the NEXTNOTE code my potato brain seems to not be able to get it to work right.

For crapchess I want to get the background ditty down to a more manageable level so I can have it playing in the background during the game. But I guess its not the end of the world if there is no music.

Image

The other way around this is to radically redactor the code, take out my potato beginners memory mistakes and get the space i need that way.. I am getting to the point where I did everything I can by myself. A little bit of polish I think I can learn a lot from seeing how someone would fix my mess of a program :lol:

A big part of the problem is routines that I have just copy pasta'ed into the project that I don't really understand that use/affect registers. This stops basic stuff like DJNZ working as expected and making me having to resort to non-loopy methods to get things to work. If I could figure out how to preserve the registers, do my loops and replace them I could go on a re-factoring rampage :lol:

Still while its been frustrating and many times I felt like I was making little progress, at the end of the 11 days I am much further along than when I started. The dragon warrior tile loader was something I couldn't have done at the start of this project. I think its the first time I really sat down and thought 'ooh I did that, damn' :roll:

Whole reason behind the tech demo was I was getting cheesed off looking at the same damn green and white board and ugly chessmen every day. Needed something new to fire my braincells. So I figured why not do a tile loader for one of my fav games, dragon quest.

As a project its totally beyond my ability to code, but for stuff like proof of concept and tech demos to teach myself its ok. One day I will make it. :mrgreen:

OUTCOMES:

All sprites are done and in the bag, have a number of new routines to handle screen stuff like timers, player indicator, the animated screens, some music. And of course loading the tiles from a list of values in a memory location that can be updated in real time.

Other things that got completed - pause functions, these were used in the animation sequence for the start screen. I wanted to avoid fitting in the viewers so needed to slow down the rate that the attribute data was switched. Sadly this took almost a day of fiddling to get right, all the time I was cursing my internet thinking how easy it would have been to have gotten a solution with google. Still watching the little animation wiggle on the screen was satisfaction at the end of the day.

The animation is just two attribute pages, I got the idea from a spectrum book - that in turn was exposing a 'trade secret' from 1984 :lol: I thought 'ooh 768x2 bytes' that sure beats 12.2k.. I want some of that action.

That was a great learning tool. Its a very simple technique but looks nice. I am no artist anyway so attribute blocks are more my speed.

Still to do..

I need to figure out what is going on with the input routine, it must be some problem with the way the project is set up but I can't get the multi input routines to work in the program from how to write spectrum games. As a sanity check I wrote out the example game that the code was used in and it works ok. So it must be my project and not a book that has been used by thousands of people to code spectrum games :lol: (but at 3am when nothing is working, these dark thoughts enter the mind none-the-less..)

Will implement the routine from the dragon quest tile loader into crap-chess. It should be easier as its only 8x8 locations compared to 16x12.. (famous last words).


Image

Image

Image

Image

Image

Image

Image

Image

Image

One thing I wanted to master was how to have menus appear on the screen. I have achieved this in a simplistic potato way, but I need to learn masking so the ugly edges can be hidden and it blends better into the scene. At the moment I am just replacing the tiles with blanks. But that is not an elegent solution I think. And still suffering from a lack of loops in my life.

the code for the tech demo is bellow, you can see its hot mess of non-optimised stuff. I would like to learn how to make it better and more efficient. Figure out how to really master this looping business and taking care of my registers instead of praying that I don't negatively impact the rest of the program every time I make a change haha.

I have been trying to get the graphic tile printer (ROLF) to also adjust the attribute memory at the same time but not been having any luck. I remember one of the spectrum books had a routine to determine the attr location of any point on screen so It would be a matter of trying to get the attr from the tile printing function..

Code: Select all

ORG 33000
    
MAIN:
 
    ; SETS MEMORY LOCATION 50000 TO 0 AND 50001 TO 0, USED IN PRINT TILE. B C

    LD A,1
    LD (60000),A
    LD A,120
    LD (23693),A
    CALL 3503
    LD A,0
    CALL 8859

GAMELOOP:
    LD A,0
    LD HL,40000
    LD (HL),0
    INC HL
    LD (HL),0
    INC HL
    LD (HL),32000
    CALL SETMAP
    ;CALL MENUS
    CALL DRAWMAP
    JP GAMELOOP

MENUS:
; 20 IS LEFT TOP CORNER, 21 IS RIGHT TOP CORNER
; 22 IS LEFT BOTTOM CORNER, 23 IS RIGHT BOTTOM CORNER
; 24 IS VERTICAL, 25 HORIZONTAL
        LD A,25
        LD (32017),A
        LD A,25
        LD (32018),A
        LD A,25
        LD (32019),A
        LD A,25
        LD (32020),A
        LD A,21
        LD (32021),A        
        LD A,20
        LD (32016),A
        LD A,24
        LD (32032),A
        LD A,26
        LD (32033),A
        LD A,26
        LD (32034),A
        LD A,26
        LD (32035),A
        LD A,26
        LD (32036),A
        LD A,24
        LD (32048),A
        LD A,26
        LD (32049),A
        LD A,26
        LD (32050),A
        LD A,26
        LD (32051),A
        LD A,26
        LD (32052),A
        LD A,24
        LD (32064),A
        LD A,26
        LD (32065),A
        LD A,26
        LD (32066),A
        LD A,26
        LD (32067),A
        LD A,26
        LD (32068),A
        LD A,24
        LD (32080),A
        LD A,26
        LD (32081),A
        LD A,26
        LD (32082),A
        LD A,26
        LD (32083),A
        LD A,26
        LD (32084),A
        LD A,24
        LD (32096),A
        LD A,26
        LD (32097),A
        LD A,26
        LD (32098),A
        LD A,26
        LD (32099),A
        LD A,26
        LD (32100),A
        LD A,22
        LD (32112),A
        LD A,25
        LD (32113),A
        LD A,25
        LD (32114),A
        LD A,25
        LD (32115),A
        LD A,25
        LD (32116),A
        LD A,23
        LD (32117),A
        LD A,24
        LD (32101),A
        LD A,24
        LD (32085),A
        LD A,24
        LD (32069),A
        LD A,24
        LD (32053),A
        LD A,24
        LD (32037),A
        LD A,21
        LD (32021),A
        RET

DRAWTILE:   ;ARRIVE HL POINTING AT TILE GRAPHIC, DE AT SCREEN MEMORY
    LD B,16     ;LOOP COUNTER FOR 16 PX HIGH TILE
DRAWTILELOOP:
    LD A,(HL)   ;GET BYTE OF GRAPHIC
    LD (DE),A   ;PLONK IT IN SCREEN MEMORY
    INC HL      ;NEXT BYTE OF GRAPHIC
    INC E       ;NEXT COLUMN OF SCREEN
    LD A,(HL)   ;RIGHT HAND SIDE OF TILE
    LD (DE),A
    INC HL      ;NEXT BYTE OF GRAPHIC
    DEC E       ;BACK TO LEFT HAND SIDE OF TILE
    CALL NEXTLINEDOWN   ;MOVE DE DOWN ONE SCREEN LINE
    DJNZ DRAWTILELOOP
    RET
    ;
NEXTLINEDOWN:   ;ARRIVE DE AT SCREEN ADDRESS, MOVE IT DOWN ONE PIXEL LINE
    INC D
    LD A,D
    AND 7
    RET NZ
    LD A,E
    ADD A,32
    LD E,A
    RET C
    LD A,D
    SUB 8
    LD D,A
    RET

YX2CELL:    ;arrive with b=y column 0-23, c=x column 0-31, point DE at corresponding screen address
    LD A,B
    RRCA
    RRCA
    RRCA
    AND 224
    OR C
    LD E,A
    LD A,B
    AND 24
    OR 64
    LD D,A
    RET

FOREST:
        CALL YX2CELL
        LD HL,TILE_FORREST
        CALL DRAWTILE
        RET

SEA:
        CALL YX2CELL
        LD HL,TILE_SEA
        CALL DRAWTILE
        RET

GRASS:
        CALL YX2CELL
        LD HL,TILE_GRASS
        CALL DRAWTILE
        RET

VLINE:
        CALL YX2CELL
        LD HL,TILE_VLINE
        CALL DRAWTILE
        RET

HLINE:
        CALL YX2CELL
        LD HL,TILE_HLINE
        CALL DRAWTILE
        RET

TLCOR:
        CALL YX2CELL
        LD HL,TILE_TLCOR
        CALL DRAWTILE
        RET

TRCOR:
        CALL YX2CELL
        LD HL,TILE_TRCOR
        CALL DRAWTILE
        RET

BLCOR:
        CALL YX2CELL
        LD HL,TILE_BLCOR
        CALL DRAWTILE
        RET

BRCOR:
        CALL YX2CELL
        LD HL,TILE_BRCOR
        CALL DRAWTILE
        RET

WALL:
        CALL YX2CELL
        LD HL,TILE_WALL
        CALL DRAWTILE
        RET

BRICKFLOOR:
        CALL YX2CELL
        LD HL,TILE_FLOOR
        CALL DRAWTILE
        RET

STAIRSU:
        CALL YX2CELL
        LD HL,TILE_STAIRSU
        CALL DRAWTILE
        RET    

STAIRSD:
        CALL YX2CELL
        LD HL,TILE_STAIRSD
        CALL DRAWTILE
        RET    


TABLE:
        CALL YX2CELL
        LD HL,TILE_TABLE
        CALL DRAWTILE
        RET

DOOR:
        CALL YX2CELL
        LD HL,TILE_DOOR
        CALL DRAWTILE
        RET

MOUNTAIN:
        CALL YX2CELL
        LD HL,TILE_MOUNTAIN
        CALL DRAWTILE
        RET
HILLS:
        CALL YX2CELL
        LD HL,TILE_HILLS
        CALL DRAWTILE
        RET
STRIPES:
        CALL YX2CELL
        LD HL,TILE_STRIPES
        CALL DRAWTILE
        RET

SWAMP:
        CALL YX2CELL
        LD HL,TILE_SWAMP
        CALL DRAWTILE
        RET

CHEST:
        CALL YX2CELL
        LD HL,TILE_CHEST
        CALL DRAWTILE
        RET

INN:
        CALL YX2CELL
        LD HL,TILE_INN
        CALL DRAWTILE
        RET   

ARMOURER:
        CALL YX2CELL
        LD HL,TILE_ARMOURER
        CALL DRAWTILE
        RET

OLDMAN:
        CALL YX2CELL
        LD HL,TILE_OLDMAN
        CALL DRAWTILE
        RET   

GUARD:
        CALL YX2CELL
        LD HL,TILE_GUARD
        CALL DRAWTILE
        RET

KING:
        CALL YX2CELL
        LD HL,TILE_KING
        CALL DRAWTILE
        RET

TOWNSPEOPLE:
        CALL YX2CELL
        LD HL,TILE_TOWNSPEOPLE
        CALL DRAWTILE
        RET

TBLANK:
        CALL YX2CELL
        LD HL,TILE_BLANK
        CALL DRAWTILE
        RET   

PLAYER:
        CALL YX2CELL
        LD HL,TILE_PLAYER
        CALL DRAWTILE
        RET   



SETMAP:              ; sets the main screen background
       LD BC,192             ; length of block to copy
       LD HL,ROOM_TANTEGEL_1_2           ; source address
       LD DE,32000             ; destination address
       LDIR                    ; copy BC bytes from HL to DE

       RET

ROLF:

       CP 0
       JP Z,BRICKFLOOR
       CP 1
       JP Z,WALL
       CP 2
       JP Z,STAIRSU
       CP 3
       JP Z,GRASS
       CP 4
       JP Z,SEA
       CP 5
       JP Z,FOREST
       CP 6
       JP Z,TABLE
       CP 7
       JP Z,DOOR
       CP 8
       JP Z,STAIRSD
       CP 9
       JP Z,MOUNTAIN
       CP 10
       JP Z,HILLS
       CP 11
       JP Z,STRIPES
       CP 12
       JP Z,SWAMP
       CP 13
       JP Z,INN
       CP 14
       JP Z,OLDMAN
       CP 15
       JP Z,GUARD
       CP 16
       JP Z,KING
       CP 17
       JP Z,TOWNSPEOPLE 
       CP 18
       JP Z,CHEST
       CP 19
       JP Z,ARMOURER
       CP 20
       JP Z,TLCOR
       CP 21
       JP Z,TRCOR
       CP 22
       JP Z,BLCOR
       CP 23
       JP Z,BRCOR
       CP 24
       JP Z,VLINE
       CP 25
       JP Z,HLINE
       CP 26
       JP Z,TBLANK
       CP 99
       JP Z,PLAYER
       RET                     ; return

ROO16:
        LD IX,16
NMFR:
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        CALL ROO
        DEC (IX)
        LD e,(IX)
        CP 0
        JP Z,NMFR
        RET

DRAWMAP:

        LD IY,32000
        LD A,0
        LD (50000),A
        LD A,0
        LD (50002),A

        CALL ROO16

        LD A,2
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16
 
        LD A,4
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16
 
        LD A,6
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16
 
        LD A,8
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16
 
        LD A,10
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16

        LD A,12
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16

        LD A,14
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16

        LD A,16
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16

        LD A,18
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16

        LD A,20
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16

        LD A,22
        LD (50000),A
        LD A,0
        LD (50002),A
        CALL ROO16
        RET

ROO:
        LD A,(50000)
        LD B,A
        LD (50000),A
        LD A,(50002)
        LD C,A
        ADD A,2
        LD (50002),A
        LD A,(IY)
        CALL ROLF 
        INC IY                   
        RET

;Tantegel castle Top left. (1 of 6)

ROOM_TANTEGEL_2_1:
    DEFB    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    DEFB    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    DEFB    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    DEFB    1,1,1,1,0,0,0,0,0,18,0,0,1,1,1,1
    DEFB    1,1,1,1,0,6,6,6,6,6,6,0,1,1,1,1
    DEFB    1,1,1,1,0,6,16,6,6,0,6,0,1,1,1,1
    DEFB    1,1,1,1,0,0,0,18,18,0,0,0,1,1,1,1
    DEFB    1,1,1,1,0,0,0,0,0,0,0,15,1,1,1,1
    DEFB    1,1,1,1,0,0,15,0,15,0,0,0,1,1,1,1
    DEFB    1,1,1,1,1,1,1,7,1,1,1,1,1,1,1,1
    DEFB    1,1,1,1,0,0,0,0,0,0,0,8,1,1,1,1
    DEFB    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
ROOM_TANTEGEL_1_1:
    DEFB    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
    DEFB    3,1,1,1,1,1,1,1,3,3,3,3,3,3,3,3
    DEFB    3,1,0,0,0,0,0,1,3,5,3,5,5,3,5,3
    DEFB    3,1,0,0,0,0,0,1,3,3,3,3,3,3,3,3
    DEFB    3,1,0,0,1,0,0,1,1,1,1,0,0,1,1,1
    DEFB    3,1,0,0,0,0,0,15,0,0,0,0,0,0,0,0
    DEFB    3,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1
    DEFB    3,1,1,1,1,1,0,1,15,0,0,0,0,0,0,0
    DEFB    3,1,0,0,0,1,0,1,2,0,0,0,0,0,1,0
    DEFB    3,1,0,17,0,0,0,1,15,0,0,0,0,0,0,0
    DEFB    3,1,0,0,0,1,0,1,1,1,0,0,0,0,1,1
    DEFB    3,1,1,1,1,1,0,1,5,5,0,0,0,0,5,5

ROOM_TANTEGEL_1_2:
    DEFB    3,1,0,0,0,1,0,1,5,5,0,0,0,0,5,5
    DEFB    3,1,0,0,15,1,0,1,5,3,0,0,0,0,3,5
    DEFB    3,1,18,0,0,7,17,1,3,3,0,0,0,0,3,3
    DEFB    3,1,0,18,0,1,0,1,3,3,0,0,0,0,3,3
    DEFB    3,1,18,0,18,1,0,1,3,0,0,0,0,0,0,3
    DEFB    3,1,1,1,1,1,0,1,3,0,4,4,4,4,0,3
    DEFB    3,1,0,0,0,0,0,0,0,0,4,11,11,4,0,0
    DEFB    3,1,0,0,0,0,0,0,0,0,4,11,11,4,0,0
    DEFB    3,1,1,1,0,0,1,1,1,0,4,4,4,4,0,1
    DEFB    3,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1
    DEFB    3,1,0,0,0,0,0,0,1,1,0,0,0,0,1,1
    DEFB    3,1,0,0,1,0,0,0,0,1,0,0,0,0,1,0

TILE_FLOOR:
    DEFB      8,  8,  8,  8,255,255,128,128
    DEFB    128,128,128,128,255,255,  8,  8
    DEFB      8,  8,  8,  8,255,255,128,128
    DEFB    128,128,128,128,255,255,  8,  8
    DEFB     16, 16, 16, 16 

TILE_WALL:
    DEFB    252, 63,200, 19,128,  1,144,  1
    DEFB    224,  1,184,  1,204,  5,166,  3
    DEFB    192,  1,160,  1,176,  1,209, 83
    DEFB    194, 37,230, 17,200, 11,255,255
    DEFB     56, 56, 56, 56

TILE_CHEST:
    DEFB      0,  0,  0,  0,115,156,127,252
    DEFB    241,140,216,198,140, 99,140, 99
    DEFB    255,255,140, 99,141,251,141, 11
    DEFB    141,251,204, 99,236, 99,255,255
    DEFB     16, 16, 16, 16

TILE_SWAMP:
    DEFB    189,219,218,107,167, 53, 52,134
    DEFB    219,181,169, 85,118,203,101,106
    DEFB    139, 21,108,237,149, 52,209,163
    DEFB    237,157, 21,110,182,181,185,219
    DEFB      4,  4,  4,  4

TILE_FORREST:
    DEFB     24, 24, 62, 52,117,122,254,255
    DEFB    250,253,255,251,254,253,247,253
    DEFB    253,123,251,254,255,247,110,126
    DEFB     60, 56, 24, 24,126,126,  0,  0
    DEFB     32, 32, 32, 32

TILE_INN:
    DEFB    255,255,  0,  0,255,255,247,239
    DEFB    128,  1,128,  1,172,165,172,165
    DEFB    170,181,170,181,169,173,169,173
    DEFB    168,165,168,165,128,  1,255,255
    DEFB     56, 56, 56, 56

TILE_ARMOURER:
    DEFB    255,255,248, 57,243,145,228, 99
    DEFB    204, 71,158,139,175, 29,166, 53
    DEFB    164,101,232,245,153,253,207, 57
    DEFB    198, 19,147,231, 58, 15,127,255
    DEFB     56, 56, 56, 56   

TILE_STAIRSU:
    DEFB    244,  4, 20,  4, 31,  4, 17,244
    DEFB     17, 31, 17, 17, 17, 17, 17, 17
    DEFB     17, 17, 17, 17, 17, 17, 17, 17
    DEFB    241, 17,255, 17,255,241,255,255
    DEFB     56, 56, 56, 56

TILE_STAIRSD:
    DEFB    255,255, 31,255, 31,255, 31,255
    DEFB     17,255, 17,255, 17,255, 17, 31
    DEFB     17, 31, 17, 31, 17, 19, 17, 19
    DEFB     17, 19, 17, 18, 17, 18, 17, 18
    DEFB     56, 56, 56, 56

TILE_SEA:
    DEFB      0,  0,  0,  0, 60, 56, 30, 28
    DEFB      0,  0,  7,192,  3,248,  0,192
    DEFB      0,  0,  0,  0, 96,  0, 49,192
    DEFB      0,248,  0,  0,  0,  0,  0,  0
    DEFB     15, 15, 15, 15

TILE_MOUNTAIN:
    DEFB      6,  0,  5,  0,  4,176, 12,232
    DEFB      9,136, 24,196, 16,132, 35,148
    DEFB     33,212, 47, 54,103,146,110,218
    DEFB    100,138, 76,218, 56, 78, 31,248
    DEFB     56, 56, 56, 56

TILE_HILLS:
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,224,  3,208,  6,136,  8,196
    DEFB     49, 98, 68, 49, 74,153,114,158
    DEFB     62, 48,  3, 32,  1,192,  0,  0
    DEFB     32, 32, 32, 32

TILE_GRASS:
    DEFB      0,  2, 40, 32, 72, 68,  0,  4
    DEFB     16,129, 33,  8,  0, 18,100, 16
    DEFB     68,  2,  8,  2,  0, 64,  8,132
    DEFB     32,  8, 65,  1, 18, 24, 32, 32
    DEFB     48, 48, 48, 48

TILE_STRIPES:
    DEFB    227,142,199, 28,142, 56, 28,113
    DEFB     56,227,113,199,227,142,199, 28
    DEFB    142, 56, 28,113, 56,227,113,199
    DEFB    227,142,199, 28,142, 56, 28,113
    DEFB     49, 49, 49, 49

TILE_TABLE:
    DEFB    255,255,128,  1,191,253,160,  5
    DEFB    160,  5,160,  5,160,  5,160,  5
    DEFB    160,  5,160,  5,160,  5,160,  5
    DEFB    160,  5,191,253,128,  1,255,255
    DEFB     48, 48, 48, 48

TILE_DOOR:
    DEFB      0,  0, 31,248, 51,204, 97,134
    DEFB     65,130,193,131,129,129,145,137
    DEFB    145,137,185,157,255,255,129,129
    DEFB    129,129,129,129,129,129,255,255
    DEFB     56, 56, 56, 56

TILE_VLINE:
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB     56, 56, 56, 5
    
TILE_HLINE:
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,255,255
    DEFB    255,255,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB     56, 56, 56, 56

TILE_TLCOR:
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,255
    DEFB      1,255,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB     56, 56, 56, 56

TILE_TRCOR:
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,255,  0
    DEFB    255,128,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB     56, 56, 56, 56

TILE_BRCOR:
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,255,128
    DEFB    255,  0,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB     56, 56, 56, 56

TILE_BLCOR:
    DEFB      1,128,  1,128,  1,128,  1,128
    DEFB      1,128,  1,128,  1,128,  1,255
    DEFB      0,255,  0,  0,  0,  0,  0,  0
    DEFB      0,  0,  0,  0,  0,  0,  0,  0
    DEFB     56, 56, 56, 56

TILE_PLAYER:
    DEFB    255,255,248, 31,240, 15,224,  7
    DEFB    238,119,224,  7,206,115,202, 83
    DEFB    206,115,192,  3,162, 69, 96,  6
    DEFB    243,207,249,159,252, 63,255,255
    DEFB     56, 56, 56, 56

TILE_OLDMAN:
    DEFB      1,224,  2, 56,  6, 14, 12,  2
    DEFB      8, 51, 63,253, 20, 31, 52, 48
    DEFB     24,112, 17,216, 31,  8, 48, 12
    DEFB     35,  4, 46,  4, 56, 12, 16,  8
    DEFB     56, 56, 56, 56

TILE_GUARD:
    DEFB      3,240,  6, 20, 12, 20,  8, 20
    DEFB      8, 20, 31, 22, 21, 20, 53, 20
    DEFB     25,244, 17, 28, 31,  4,112,228
    DEFB     32,164, 40,228, 56,140, 18,  8
    DEFB     56, 56, 56, 56

TILE_KING:
    DEFB      0,  0,  2,168,  5, 84,  8,  2
    DEFB      8,  2, 30,  4, 53,  4, 33,  4
    DEFB     23,  4, 61,252, 34,  4,124,164
    DEFB     96,164, 40,196, 56,172, 18,  8
    DEFB     56, 56, 56, 56

TILE_TOWNSPEOPLE:
    DEFB      0,  0, 15,240,  8, 92,  8,212
    DEFB      8, 20, 30, 52, 53,  4, 39,  4
    DEFB     23,  4, 61,252, 34,  4, 61,250
    DEFB     17, 18,  9, 20,  8,172, 18, 72
    DEFB     56, 56, 56, 56

TILE_BLANK:
    DEFB     0,0,0,0,0,0,0,0
    DEFB     0,0,0,0,0,0,0,0
    DEFB     0,0,0,0,0,0,0,0
    DEFB     0,0,0,0,0,0,0,0
    DEFB     0,0,0,0   

END MAIN
What I have been trying and failing to do is read the memory locations starting from 32000 -> 32192 that contain all of the tiles on the screen at the time. The idea is I just poke values into these locations when I want to update the screen and as the code can read the locations and print to the screen it should update whenever the memory is changed. This all works.

But What I can't get to work is a simple nestled loop so that the outer loop handles the rows (12) and the inner loop handles the columns (16). to print the tiles on the screen. At the moment I am having to use the manual method of a kind of half way house between a loop and a mess.

The other thing I cannot get to work is a attribute 'diddler', what I want it to do as its reading the value of the memory location, it at the same time as printing the tile, also updates that locations attribute value from a CP ladder. I have tried and I can't seem to figure out a way to get it to work.

So for example, the brick floor, chest should be red paper, black ink, the walls should be white, the sea blue, the grass, trees, green, well you get the idea.

While this is a perfect project for a NIRVANA program, I just want to get the basics down first before jumping off the deep end. :lol:
User avatar
R-Tape
Site Admin
Posts: 6353
Joined: Thu Nov 09, 2017 11:46 am

Re: Crap 0.1 first assembly project

Post by R-Tape »

I confess I thought you had given up. Your Dragon Quest tile engine looks good but now mission creep is on the cards!

Looks like you've made good progress, maybe 2 weeks without the net would do us all some good.

Your code has this:
LD (HL),32000

What is it supposed to be? Are you trying to load a word into that memory location? In which case it should be LD (HL),0 INC HL, LD (HL),125 for 32000.

If I understand how it works properly, the CP ladder, 'ROLF', would be better if you multiply the tile number by 32 then use that number to find the graphic, and you can use it to find the colour in a table too (if one colour for chess use the tile number directly, if 4 colours per tile as per Dragon Quest then multiply by 4).
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

I guess its all about balance, there are some advantages to no internet, being able to totally focus all of ones leisure time on a 80s programming project does seem to increase productivity. But I lost many hours because I couldn't verify stuff I was doing/could have avoided a bunch of blind alleys. That said overall it was a good experience. Well it was that or watch the first season of Space 1999 again.

The (HL),32000 Is supposed to be loading the value of the first memory location that holds the tilemap data in memory. As you said I have screwed it up :lol: It should be peeking the value in 32000 and loading it into HL.
What I wanted it to do was loop through the range of 192 memory locations and print them on the screen. That is what the HL inc is supposed to be doing. I was wondering why it wouldn't work right lol. I will have a crack at the attribute analyser tomorrow. Once that is done I can apply it to crap chess and that is almost the program done. (with the exception of the input loop.)

Will get crapchess squared away in the next week or so I think, if progress continues at this pace. The plan after that is to take a step backwards as far as technical challenge goes and tackle what really should have been my first project (noughts and crosses ... in assembly with fancy music and graphics lol.) With the routines from crap chess and the dragonquest tile routine I think it would look pretty swish.

That way my first 'game' is crapchess, but I would predict that noughts and crosses would take a matter of days compared to the weeks that crapchess has taken. But its all good experience. To be able to get something out so quickly using the routines/tools is a challenge in it self in discipline. The plan with that is to learn all about custom fonts. That seems to be a logical step in more professional looking programs.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

I am probably missing something obvious here, but my print routine for the noughts and crosses is not behaving properly.

All its got to do is display first the grid with the numbers, then after you hit a key.. it will load the grid without numbers.

But for reasons that escape me its not working.

depending on what way the boards are arranged in the file, determines if the grid will show numbers or blank spaces when the program is run.

Image

Image

Here is the source code.

Code: Select all

ORG 33000

HELP:  DEFB 16,0,22,1,6,17,9,'*',17,3,' ',17,2,'N',17,3,'o',17,4,'u',17,5,'g',17,6,'h',17,7,'t',17,2,'s',17,5,' ',17,3,'&',17,3,' ',17,4,'C',17,5,'r',17,6,'o',17,7,'s',17,2,'s',17,5,'e',17,7,'s',17,3,' ',17,4,'*'
       DEFB 16,7,22,4,15,17,1,'This is noughts',13
       DEFB 22,5,15,'and crosses, for',13 
       DEFB 22,6,15,'two players.',13 
       DEFB 22,8,15,'I will tell you',13
       DEFB 22,9,15,'when either of',13 
       DEFB 22,10,15,'you has won.',13
       DEFB 22,12,15,'The board is',13
       DEFB 22,13,15,'numbered as on',13 
       DEFB 22,14,15,'the left side',13
       DEFB 22,15,15,'of the screen.',13
       DEFB 22,21,2,'PRESS ',18,1,16,2,'<RETURN>',18,0,16,7,' TO CONTINUE...'

BOARD: DEFB 16,2,17,0,22,4,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,13
       DEFB 22,5,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,6,1,$8A,' ',16,0,$80,16,2,' ',$8A,' ',16,0,$80,16,2,' ',$85,' ',16,0,$80,16,2,' ',$85,13
       DEFB 22,7,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,8,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,13
       DEFB 22,9,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,10,1,$8A,' ',16,0,$80,16,2,' ',$8A,' ',16,0,$80,16,2,' ',$85,' ',16,0,$80,16,2,' ',$85,13
       DEFB 22,11,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,12,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,13
       DEFB 22,13,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,14,1,$8A,' ',16,0,$80,16,2,' ',$8A,' ',16,0,$80,16,2,' ',$85,' ',16,0,$80,16,2,' ',$85,13
       DEFB 22,15,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,16,1,$8E,$8C,$8C,$8C,$8E,$8C,$8C,$8C,$8D,$8C,$8C,$8C,$8D,13,17,1,16,8


HELPBOARD:
       DEFB 16,2,17,0,22,4,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,13
       DEFB 22,5,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,6,1,$8A,' ',16,3,'1',16,2,' ',$8A,' ',16,3,'2',16,2,' ',$85,' ',16,3,'3',16,2,' ',$85,13
       DEFB 22,7,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,8,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,13
       DEFB 22,9,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,10,1,$8A,' ',16,3,'4',16,2,' ',$8A,' ',16,3,'5',16,2,' ',$85,' ',16,3,'6',16,2,' ',$85,13
       DEFB 22,11,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,12,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,13
       DEFB 22,13,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,14,1,$8A,' ',16,3,'7',16,2,' ',$8A,' ',16,3,'8',16,2,' ',$85,' ',16,3,'9',16,2,' ',$85,13
       DEFB 22,15,1,$8A,'   ',$8A,'   ',$85,'   ',$85,13
       DEFB 22,16,1,$8E,$8C,$8C,$8C,$8E,$8C,$8C,$8C,$8D,$8C,$8C,$8C,$8D,13,17,1,16,8

EOSTR: equ $
EOHELP: EQU $

EOBOARD: EQU $

MAIN:
       CALL FATFONT
       LD A,14              ; BLUE PAPER (1*8)+WHITE INK 8 = 16
       LD (23693),A         
       LD A,1
       CALL 8859           ; SET BORDER
       CALL 3503           ; CLEAR SCREEN & SET PAPER N INK.
       CALL HELPSCREEN
       CALL KEYBOARDINPUT
       ;CALL GAMELOOP
       ;CALL KEYBOARDINPUT
       JP MAIN

HELPSCREEN:
       ld a,2              ; upper screen
       call 5633           ; open channel
       ld de,HELP        ; address of string
       ld bc,EOHELP-HELP  ; length of string to print
       call 8252         ; print our string
       LD DE,HELPBOARD
       LD BC,EOBOARD-HELPBOARD
       CALL 8252
       RET

FATFONT:
       ld hl,15616         ; ROM font.
       ld de,60000         ; address of our font.
       ld bc,768           ; 96 chars * 8 rows to alter.
font1  ld a,(hl)           ; get bitmap.
       rlca                ; rotate it left.
       or (hl)             ; combine 2 images.
       ld (de),a           ; write to new font.
       inc hl              ; next byte of old.
       inc de              ; next byte of new.
       dec bc              ; decrement counter.
       ld a,b              ; high byte.
       or c                ; combine with low byte.
       jr nz,font1         ; repeat until bc=zero.
       ld hl,60000-256     ; font minus 32*8.
       ld (23606),hl       ; point to new font.
       ret

KEYBOARDINPUT:
       ld hl,23560         ; LAST K system variable.
       ld (hl),0           ; put null value there.
_loop   ld a,(hl)           ; new value of LAST K.
       cp 0                ; is it still zero?
       jr z,_loop           ; yes, so no key pressed.
       RET                          ; key was pressed.

GAMELOOP:
       LD DE,BOARD
       LD BC,EOBOARD-BOARD
       CALL 8252
       RET

END MAIN
What is supposed to happen after this is I will scan the keyboard for inputs 1-9, depending on what's pressed, will poke a memory location (the equivalent of variables as used in the basic listing for noughts and crosses games.) then I will just compare the 9 locations for win states (either player getting 3 in a row in some combination).

But until I get this input/print business I can't really progress. It has to be something obvious I am missing, but after a time you keep looking at a problem and can't see the forest for the trees (to paraphrase huey lewis.)
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

EOSTR: equ $
EOHELP: EQU $
EOBOARD: EQU $

All have to be at the end of the respective thing?
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Seven.FFF wrote: Wed Jan 24, 2018 5:20 pm EOSTR: equ $
EOHELP: EQU $
EOBOARD: EQU $

All have to be at the end of the respective thing?
I don't understand, I tried them in different places, at the ends of the defbs, I renamed them all the same then it got an error, then i erased all but one and it still didn't work.

What do they actually do anyway? I just want to show the grid with the numbers, the player hits the key, then i clear the grid and will add some extra text later.

Is there a more obvious way to do this? it seems to me to be very confusing way to get information on the screen.

I tried switching the attributes on the grid, using special characters to try and blank the numbers lol. Nothing seems to be working.

Sometimes I think I am going nowhere with this stuff as all of the books and tutorials seem to just progress to much more advance topics - but for me I seem to be stuck at the first hurdle with this stuff lol.

I still don't understand why these input routines, why the print routines are going wrong.
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

EOBOARD: EQU $ needs to be after the board data, and before the HELPBOARD: label.

At the end of your main loop, you're jumping back to the help printing text every time. Instead:

Code: Select all

MAINLOOP:
       CALL GAMELOOP
       ;CALL KEYBOARDINPUT
       JP MAINLOOP
Last edited by Seven.FFF on Wed Jan 24, 2018 6:01 pm, edited 1 time in total.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

Nomad wrote: Wed Jan 24, 2018 5:34 pmWhat do they actually do anyway?
The ROM print routine at 8252 takes the address of the first byte of the data in de, and the number of bytes to print (length) in bc.

You're using the assembler to do the maths heavy lifting by calculating the length, in such a way that there aren't any magic address numbers in the code. The code could be relocated by changing ORG, at any time, without breaking anything (all other things being equal).

$ will be the address of the byte after the last piece of data, at the time EOHELP etc is defined. Think of a simple example:

org 40000
TEST:
40000 db 'A'
40001 db 'B'
40002 db 'C'
EOTEST equ $
40003 [...]

TEST is 40000
EOTEST is 40003

EOTEST-TEST = 40003-40000 = 3 = the number of data bytes.

All more perils of copying examples by rote :D You'd usually do this deliberately, because you wanted to do the address and calculations. But getting the cart before the horse, you're doing calculations you don't understand the purpose of, and your confusion is even worse than if you'd used magic numbers and got them mixed up.
Last edited by Seven.FFF on Wed Jan 24, 2018 6:02 pm, edited 1 time in total.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

Another step towards eliminating magic numbers and confusion would be to do:

PR_STRING equ 8252

And use that constant everywhere instead of 8252. It's a) the official name of the routine in the ROM, so other people reading the code have a common reference point, and b) reasonably self-descriptive in itself. :)
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

More constants I use a lot, which would help make the print data more readable:

Code: Select all

; Screen
PixelAddress            equ $4000
AttributeAddress        equ $5800                       ; Start of the attributes in the Spectrum display file
AttributeLength         equ $300                        ; There are 768 bytes of attributes
BS                      equ 8
CR                      equ 13
Ink                     equ 16
Paper                   equ 17
Flash                   equ 18
Dim                     equ %00000000                   ; These two constants are the
Bright                  equ %01000000                   ;   attribute mask for the bright flag
PrBright                equ 19                          ; This is the print code for BRIGHT for ROM routines
Inverse                 equ 20
Over                    equ 21
At                      equ 22                          ; FZX understands this one as well as the ROM routines
Tab                     equ 23
Black                   equ 0
Blue                    equ 1
Red                     equ 2
Magenta                 equ 3
Green                   equ 4
Cyan                    equ 5
Yellow                  equ 6
White                   equ 7
BlackP                  equ 8*Black
BlueP                   equ 8*Blue
RedP                    equ 8*Red
MagentaP                equ 8*Magenta
GreenP                  equ 8*Green
CyanP                   equ 8*Cyan
YellowP                 equ 8*Yellow
WhiteP                  equ 8*White
DimBlack                equ Black
DimBlue                 equ Blue
DimRed                  equ Red
DimMagenta              equ Magenta
DimGreen                equ Green
DimCyan                 equ Cyan
DimYellow               equ Yellow
DimWhite                equ White
BrightBlack             equ Black+Bright
BrightBlue              equ Blue+Bright
BrightRed               equ Red+Bright
BrightMagenta           equ Magenta+Bright
BrightGreen             equ Green+Bright
BrightCyan              equ Cyan+Bright
BrightYellow            equ Yellow+Bright
BrightWhite             equ White+Bright
DimBlackBlackP          equ DimBlack+BlackP
DimBlueBlackP           equ DimBlue+BlackP
DimRedBlackP            equ DimRed+BlackP
DimMagentaBlackP        equ DimMagenta+BlackP
DimGreenBlackP          equ DimGreen+BlackP
DimCyanBlackP           equ DimCyan+BlackP
DimYellowBlackP         equ DimYellow+BlackP
DimWhiteBlackP          equ DimWhite+BlackP
BrightBlackBlackP       equ BrightBlack+BlackP
BrightBlueBlackP        equ BrightBlue+BlackP
BrightRedBlackP         equ BrightRed+BlackP
BrightMagentaBlackP     equ BrightMagenta+BlackP
BrightGreenBlackP       equ BrightGreen+BlackP
BrightCyanBlackP        equ BrightCyan+BlackP
BrightYellowBlackP      equ BrightYellow+BlackP
BrightWhiteBlackP       equ BrightWhite+BlackP
DimBlackBlueP           equ DimBlack+BlueP
DimBlueBlueP            equ DimBlue+BlueP
DimRedBlueP             equ DimRed+BlueP
DimMagentaBlueP         equ DimMagenta+BlueP
DimGreenBlueP           equ DimGreen+BlueP
DimCyanBlueP            equ DimCyan+BlueP
DimYellowBlueP          equ DimYellow+BlueP
DimWhiteBlueP           equ DimWhite+BlueP
BrightBlackBlueP        equ BrightBlack+BlueP
BrightBlueBlueP         equ BrightBlue+BlueP
BrightRedBlueP          equ BrightRed+BlueP
BrightMagentaBlueP      equ BrightMagenta+BlueP
BrightGreenBlueP        equ BrightGreen+BlueP
BrightCyanBlueP         equ BrightCyan+BlueP
BrightYellowBlueP       equ BrightYellow+BlueP
BrightWhiteBlueP        equ BrightWhite+BlueP
DimBlackRedP            equ DimBlack+RedP
DimBlueRedP             equ DimBlue+RedP
DimRedRedP              equ DimRed+RedP
DimMagentaRedP          equ DimMagenta+RedP
DimGreenRedP            equ DimGreen+RedP
DimCyanRedP             equ DimCyan+RedP
DimYellowRedP           equ DimYellow+RedP
DimWhiteRedP            equ DimWhite+RedP
BrightBlackRedP         equ BrightBlack+RedP
BrightBlueRedP          equ BrightBlue+RedP
BrightRedRedP           equ BrightRed+RedP
BrightMagentaRedP       equ BrightMagenta+RedP
BrightGreenRedP         equ BrightGreen+RedP
BrightCyanRedP          equ BrightCyan+RedP
BrightYellowRedP        equ BrightYellow+RedP
BrightWhiteRedP         equ BrightWhite+RedP
DimBlackMagentaP        equ DimBlack+MagentaP
DimBlueMagentaP         equ DimBlue+MagentaP
DimRedMagentaP          equ DimRed+MagentaP
DimMagentaMagentaP      equ DimMagenta+MagentaP
DimGreenMagentaP        equ DimGreen+MagentaP
DimCyanMagentaP         equ DimCyan+MagentaP
DimYellowMagentaP       equ DimYellow+MagentaP
DimWhiteMagentaP        equ DimWhite+MagentaP
BrightBlackMagentaP     equ BrightBlack+MagentaP
BrightBlueMagentaP      equ BrightBlue+MagentaP
BrightRedMagentaP       equ BrightRed+MagentaP
BrightMagentaMagentaP   equ BrightMagenta+MagentaP
BrightGreenMagentaP     equ BrightGreen+MagentaP
BrightCyanMagentaP      equ BrightCyan+MagentaP
BrightYellowMagentaP    equ BrightYellow+MagentaP
BrightWhiteMagentaP     equ BrightWhite+MagentaP
DimBlackGreenP          equ DimBlack+GreenP
DimBlueGreenP           equ DimBlue+GreenP
DimRedGreenP            equ DimRed+GreenP
DimMagentaGreenP        equ DimMagenta+GreenP
DimGreenGreenP          equ DimGreen+GreenP
DimCyanGreenP           equ DimCyan+GreenP
DimYellowGreenP         equ DimYellow+GreenP
DimWhiteGreenP          equ DimWhite+GreenP
BrightBlackGreenP       equ BrightBlack+GreenP
BrightBlueGreenP        equ BrightBlue+GreenP
BrightRedGreenP         equ BrightRed+GreenP
BrightMagentaGreenP     equ BrightMagenta+GreenP
BrightGreenGreenP       equ BrightGreen+GreenP
BrightCyanGreenP        equ BrightCyan+GreenP
BrightYellowGreenP      equ BrightYellow+GreenP
BrightWhiteGreenP       equ BrightWhite+GreenP
DimBlackCyanP           equ DimBlack+CyanP
DimBlueCyanP            equ DimBlue+CyanP
DimRedCyanP             equ DimRed+CyanP
DimMagentaCyanP         equ DimMagenta+CyanP
DimGreenCyanP           equ DimGreen+CyanP
DimCyanCyanP            equ DimCyan+CyanP
DimYellowCyanP          equ DimYellow+CyanP
DimWhiteCyanP           equ DimWhite+CyanP
BrightBlackCyanP        equ BrightBlack+CyanP
BrightBlueCyanP         equ BrightBlue+CyanP
BrightRedCyanP          equ BrightRed+CyanP
BrightMagentaCyanP      equ BrightMagenta+CyanP
BrightGreenCyanP        equ BrightGreen+CyanP
BrightCyanCyanP         equ BrightCyan+CyanP
BrightYellowCyanP       equ BrightYellow+CyanP
BrightWhiteCyanP        equ BrightWhite+CyanP
DimBlackYellowP         equ DimBlack+YellowP
DimBlueYellowP          equ DimBlue+YellowP
DimRedYellowP           equ DimRed+YellowP
DimMagentaYellowP       equ DimMagenta+YellowP
DimGreenYellowP         equ DimGreen+YellowP
DimCyanYellowP          equ DimCyan+YellowP
DimYellowYellowP        equ DimYellow+YellowP
DimWhiteYellowP         equ DimWhite+YellowP
BrightBlackYellowP      equ BrightBlack+YellowP
BrightBlueYellowP       equ BrightBlue+YellowP
BrightRedYellowP        equ BrightRed+YellowP
BrightMagentaYellowP    equ BrightMagenta+YellowP
BrightGreenYellowP      equ BrightGreen+YellowP
BrightCyanYellowP       equ BrightCyan+YellowP
BrightYellowYellowP     equ BrightYellow+YellowP
BrightWhiteYellowP      equ BrightWhite+YellowP
DimBlackWhiteP          equ DimBlack+WhiteP
DimBlueWhiteP           equ DimBlue+WhiteP
DimRedWhiteP            equ DimRed+WhiteP
DimMagentaWhiteP        equ DimMagenta+WhiteP
DimGreenWhiteP          equ DimGreen+WhiteP
DimCyanWhiteP           equ DimCyan+WhiteP
DimYellowWhiteP         equ DimYellow+WhiteP
DimWhiteWhiteP          equ DimWhite+WhiteP
BrightBlackWhiteP       equ BrightBlack+WhiteP
BrightBlueWhiteP        equ BrightBlue+WhiteP
BrightRedWhiteP         equ BrightRed+WhiteP
BrightMagentaWhiteP     equ BrightMagenta+WhiteP
BrightGreenWhiteP       equ BrightGreen+WhiteP
BrightCyanWhiteP        equ BrightCyan+WhiteP
BrightYellowWhiteP      equ BrightYellow+WhiteP
BrightWhiteWhiteP       equ BrightWhite+WhiteP
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Thanks for your constants list :) your right it does make it more readable.. Not sure about the camel case haha. Will have a think about that next time.

Yes I know FATFONT and FAT_FONT are not the most readable of labels lol..

Still its looking better than it did, now .. the grid dissipaters. hmmm interesting.

Going to put my potato brain to bed for the day, lol you never know what might happen with a little bit of zzzz.

Code: Select all

ORG 33000
; Screen
PixelAddress            equ $4000
AttributeAddress        equ $5800                       ; Start of the attributes in the Spectrum display file
AttributeLength         equ $300                        ; There are 768 bytes of attributes
BS                      equ 8
CR                      equ 13
Ink                     equ 16
Paper                   equ 17
Flash                   equ 18
Dim                     equ %00000000                   ; These two constants are the
Bright                  equ %01000000                   ;   attribute mask for the bright flag
PrBright                equ 19                          ; This is the print code for BRIGHT for ROM routines
Inverse                 equ 20
Over                    equ 21
At                      equ 22                          ; FZX understands this one as well as the ROM routines
Tab                     equ 23
Black                   equ 0
Blue                    equ 1
Red                     equ 2
Magenta                 equ 3
Green                   equ 4
Cyan                    equ 5
Yellow                  equ 6
White                   equ 7
BlackP                  equ 8*Black
BlueP                   equ 8*Blue
RedP                    equ 8*Red
MagentaP                equ 8*Magenta
GreenP                  equ 8*Green
CyanP                   equ 8*Cyan
YellowP                 equ 8*Yellow
WhiteP                  equ 8*White
DimBlack                equ Black
DimBlue                 equ Blue
DimRed                  equ Red
DimMagenta              equ Magenta
DimGreen                equ Green
DimCyan                 equ Cyan
DimYellow               equ Yellow
DimWhite                equ White
BrightBlack             equ Black+Bright
BrightBlue              equ Blue+Bright
BrightRed               equ Red+Bright
BrightMagenta           equ Magenta+Bright
BrightGreen             equ Green+Bright
BrightCyan              equ Cyan+Bright
BrightYellow            equ Yellow+Bright
BrightWhite             equ White+Bright
DimBlackBlackP          equ DimBlack+BlackP
DimBlueBlackP           equ DimBlue+BlackP
DimRedBlackP            equ DimRed+BlackP
DimMagentaBlackP        equ DimMagenta+BlackP
DimGreenBlackP          equ DimGreen+BlackP
DimCyanBlackP           equ DimCyan+BlackP
DimYellowBlackP         equ DimYellow+BlackP
DimWhiteBlackP          equ DimWhite+BlackP
BrightBlackBlackP       equ BrightBlack+BlackP
BrightBlueBlackP        equ BrightBlue+BlackP
BrightRedBlackP         equ BrightRed+BlackP
BrightMagentaBlackP     equ BrightMagenta+BlackP
BrightGreenBlackP       equ BrightGreen+BlackP
BrightCyanBlackP        equ BrightCyan+BlackP
BrightYellowBlackP      equ BrightYellow+BlackP
BrightWhiteBlackP       equ BrightWhite+BlackP
DimBlackBlueP           equ DimBlack+BlueP
DimBlueBlueP            equ DimBlue+BlueP
DimRedBlueP             equ DimRed+BlueP
DimMagentaBlueP         equ DimMagenta+BlueP
DimGreenBlueP           equ DimGreen+BlueP
DimCyanBlueP            equ DimCyan+BlueP
DimYellowBlueP          equ DimYellow+BlueP
DimWhiteBlueP           equ DimWhite+BlueP
BrightBlackBlueP        equ BrightBlack+BlueP
BrightBlueBlueP         equ BrightBlue+BlueP
BrightRedBlueP          equ BrightRed+BlueP
BrightMagentaBlueP      equ BrightMagenta+BlueP
BrightGreenBlueP        equ BrightGreen+BlueP
BrightCyanBlueP         equ BrightCyan+BlueP
BrightYellowBlueP       equ BrightYellow+BlueP
BrightWhiteBlueP        equ BrightWhite+BlueP
DimBlackRedP            equ DimBlack+RedP
DimBlueRedP             equ DimBlue+RedP
DimRedRedP              equ DimRed+RedP
DimMagentaRedP          equ DimMagenta+RedP
DimGreenRedP            equ DimGreen+RedP
DimCyanRedP             equ DimCyan+RedP
DimYellowRedP           equ DimYellow+RedP
DimWhiteRedP            equ DimWhite+RedP
BrightBlackRedP         equ BrightBlack+RedP
BrightBlueRedP          equ BrightBlue+RedP
BrightRedRedP           equ BrightRed+RedP
BrightMagentaRedP       equ BrightMagenta+RedP
BrightGreenRedP         equ BrightGreen+RedP
BrightCyanRedP          equ BrightCyan+RedP
BrightYellowRedP        equ BrightYellow+RedP
BrightWhiteRedP         equ BrightWhite+RedP
DimBlackMagentaP        equ DimBlack+MagentaP
DimBlueMagentaP         equ DimBlue+MagentaP
DimRedMagentaP          equ DimRed+MagentaP
DimMagentaMagentaP      equ DimMagenta+MagentaP
DimGreenMagentaP        equ DimGreen+MagentaP
DimCyanMagentaP         equ DimCyan+MagentaP
DimYellowMagentaP       equ DimYellow+MagentaP
DimWhiteMagentaP        equ DimWhite+MagentaP
BrightBlackMagentaP     equ BrightBlack+MagentaP
BrightBlueMagentaP      equ BrightBlue+MagentaP
BrightRedMagentaP       equ BrightRed+MagentaP
BrightMagentaMagentaP   equ BrightMagenta+MagentaP
BrightGreenMagentaP     equ BrightGreen+MagentaP
BrightCyanMagentaP      equ BrightCyan+MagentaP
BrightYellowMagentaP    equ BrightYellow+MagentaP
BrightWhiteMagentaP     equ BrightWhite+MagentaP
DimBlackGreenP          equ DimBlack+GreenP
DimBlueGreenP           equ DimBlue+GreenP
DimRedGreenP            equ DimRed+GreenP
DimMagentaGreenP        equ DimMagenta+GreenP
DimGreenGreenP          equ DimGreen+GreenP
DimCyanGreenP           equ DimCyan+GreenP
DimYellowGreenP         equ DimYellow+GreenP
DimWhiteGreenP          equ DimWhite+GreenP
BrightBlackGreenP       equ BrightBlack+GreenP
BrightBlueGreenP        equ BrightBlue+GreenP
BrightRedGreenP         equ BrightRed+GreenP
BrightMagentaGreenP     equ BrightMagenta+GreenP
BrightGreenGreenP       equ BrightGreen+GreenP
BrightCyanGreenP        equ BrightCyan+GreenP
BrightYellowGreenP      equ BrightYellow+GreenP
BrightWhiteGreenP       equ BrightWhite+GreenP
DimBlackCyanP           equ DimBlack+CyanP
DimBlueCyanP            equ DimBlue+CyanP
DimRedCyanP             equ DimRed+CyanP
DimMagentaCyanP         equ DimMagenta+CyanP
DimGreenCyanP           equ DimGreen+CyanP
DimCyanCyanP            equ DimCyan+CyanP
DimYellowCyanP          equ DimYellow+CyanP
DimWhiteCyanP           equ DimWhite+CyanP
BrightBlackCyanP        equ BrightBlack+CyanP
BrightBlueCyanP         equ BrightBlue+CyanP
BrightRedCyanP          equ BrightRed+CyanP
BrightMagentaCyanP      equ BrightMagenta+CyanP
BrightGreenCyanP        equ BrightGreen+CyanP
BrightCyanCyanP         equ BrightCyan+CyanP
BrightYellowCyanP       equ BrightYellow+CyanP
BrightWhiteCyanP        equ BrightWhite+CyanP
DimBlackYellowP         equ DimBlack+YellowP
DimBlueYellowP          equ DimBlue+YellowP
DimRedYellowP           equ DimRed+YellowP
DimMagentaYellowP       equ DimMagenta+YellowP
DimGreenYellowP         equ DimGreen+YellowP
DimCyanYellowP          equ DimCyan+YellowP
DimYellowYellowP        equ DimYellow+YellowP
DimWhiteYellowP         equ DimWhite+YellowP
BrightBlackYellowP      equ BrightBlack+YellowP
BrightBlueYellowP       equ BrightBlue+YellowP
BrightRedYellowP        equ BrightRed+YellowP
BrightMagentaYellowP    equ BrightMagenta+YellowP
BrightGreenYellowP      equ BrightGreen+YellowP
BrightCyanYellowP       equ BrightCyan+YellowP
BrightYellowYellowP     equ BrightYellow+YellowP
BrightWhiteYellowP      equ BrightWhite+YellowP
DimBlackWhiteP          equ DimBlack+WhiteP
DimBlueWhiteP           equ DimBlue+WhiteP
DimRedWhiteP            equ DimRed+WhiteP
DimMagentaWhiteP        equ DimMagenta+WhiteP
DimGreenWhiteP          equ DimGreen+WhiteP
DimCyanWhiteP           equ DimCyan+WhiteP
DimYellowWhiteP         equ DimYellow+WhiteP
DimWhiteWhiteP          equ DimWhite+WhiteP
BrightBlackWhiteP       equ BrightBlack+WhiteP
BrightBlueWhiteP        equ BrightBlue+WhiteP
BrightRedWhiteP         equ BrightRed+WhiteP
BrightMagentaWhiteP     equ BrightMagenta+WhiteP
BrightGreenWhiteP       equ BrightGreen+WhiteP
BrightCyanWhiteP        equ BrightCyan+WhiteP
BrightYellowWhiteP      equ BrightYellow+WhiteP
BrightWhiteWhiteP       equ BrightWhite+WhiteP

PR_STRING equ 8252
LAST_K    equ 23560
ROM_FONT  equ 15616
FAT_FONT  equ 60000
SET_BORDER equ 8859
CLEAR_SCR equ 3503       

MAIN:
       CALL FATFONT
       LD A,DimWhiteBlueP     ; 
       LD (23693),A         
       LD A,1
       CALL SET_BORDER     ; SET BORDER
       CALL CLEAR_SCR      ; CLEAR SCREEN & SET PAPER N INK.
       CALL HELPSCREEN
 MGL:  CALL KEYBOARDINPUT
       CALL GAMELOOP
       CALL KEYBOARDINPUT
       JP MGL

HELPSCREEN:
       ld a,2              ; upper screen
       call 5633           ; open channel
       ld de,HELP        ; address of string
       ld bc,EOSTR1-HELP  ; length of string to print
       call PR_STRING       ; print our string
       LD DE,HELPBOARD
       LD BC,EOSTR2-HELPBOARD
       CALL PR_STRING
       RET

FATFONT:
       ld hl,ROM_FONT      ; ROM font.
       ld de,FAT_FONT      ; address of our font.
       ld bc,768           ; 96 chars * 8 rows to alter.
font1  ld a,(hl)           ; get bitmap.
       rlca                ; rotate it left.
       or (hl)             ; combine 2 images.
       ld (de),a           ; write to new font.
       inc hl              ; next byte of old.
       inc de              ; next byte of new.
       dec bc              ; decrement counter.
       ld a,b              ; high byte.
       or c                ; combine with low byte.
       jr nz,font1         ; repeat until bc=zero.
       ld hl,FAT_FONT-256  ; font minus 32*8.
       ld (23606),hl       ; point to new font.
       ret

KEYBOARDINPUT:
       ld hl,LAST_K         ; LAST K system variable.
       ld (hl),0           ; put null value there.
_loop   ld a,(hl)           ; new value of LAST K.
       cp 0                ; is it still zero?
       jr z,_loop           ; yes, so no key pressed.
       RET                          ; key was pressed.

GAMELOOP:
       ld a,2              ; upper screen
       call 5633           ; open channel
       ld de,HELP        ; address of string
       ld bc,EOSTR1-HELP  ; length of string to print
       call PR_STRING 
       LD DE,BOARD
       LD BC,EOSTR3-BOARD
       CALL PR_STRING
       RET

HELP:  DEFB Ink,Black,At,1,6,Paper,9,'*',Paper,Magenta,' ',Paper,Red,'N',Paper,Magenta,'o',Paper,Green,'u',Paper,5,'g',Paper,6,'h',Paper,White,'t',Paper,Red,'s',Paper,5,' ',Paper,Magenta,'&',Paper,Magenta,' ',Paper,Green,'C',Paper,5,'r',Paper,6,'o',Paper,White,'s',Paper,Red,'s',Paper,5,'e',Paper,White,'s',Paper,Magenta,' ',Paper,Green,'*'
       DEFB Ink,White,At,4,15,Paper,1,'This is noughts',CR
       DEFB At,5,15,'and crosses, for',CR 
       DEFB At,6,15,'two players.',CR 
       DEFB At,8,15,'I will tell you',CR
       DEFB At,9,15,'when either of',CR 
       DEFB At,10,15,'you has won.',CR
       DEFB At,12,15,'The board is',CR
       DEFB At,13,15,'numbered as on',CR
       DEFB At,14,15,'the left side',CR
       DEFB At,15,15,'of the screen.',CR
       DEFB At,21,2,'PRESS ',Flash,1,Ink,Red,'<RETURN>',Flash,0,Ink,White,' TO CONTINUE...'
EOSTR1: equ $

BOARD: DEFB Ink,Red,Paper,Black,At,4,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,CR
       DEFB At,5,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,6,1,$8A,' ',Ink,Black,$80,Ink,Red,' ',$8A,' ',Ink,Black,$80,Ink,Red,' ',$85,' ',Ink,Black,$80,Ink,Red,' ',$85,CR
       DEFB At,7,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,8,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,CR
       DEFB At,9,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,10,1,$8A,' ',Ink,Black,$80,Ink,Red,' ',$8A,' ',Ink,Black,$80,Ink,Red,' ',$85,' ',Ink,Black,$80,Ink,Red,' ',$85,CR
       DEFB At,11,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,12,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,CR
       DEFB At,13,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,14,1,$8A,' ',Ink,Black,$80,Ink,Red,' ',$8A,' ',Ink,Black,$80,Ink,Red,' ',$85,' ',Ink,Black,$80,Ink,Red,' ',$85,CR
       DEFB At,15,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,16,1,$8E,$8C,$8C,$8C,$8E,$8C,$8C,$8C,$8D,$8C,$8C,$8C,$8D,CR,Paper,Blue,Ink,White
EOSTR2: equ $

HELPBOARD:
       DEFB Ink,Red,Paper,Black,At,4,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,CR
       DEFB At,5,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,6,1,$8A,' ',Ink,Magenta,'1',Ink,Red,' ',$8A,' ',Ink,Magenta,'2',Ink,Red,' ',$85,' ',Ink,Magenta,'3',Ink,Red,' ',$85,CR
       DEFB At,7,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,8,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,CR
       DEFB At,9,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,10,1,$8A,' ',Ink,Magenta,'4',Ink,Red,' ',$8A,' ',Ink,Magenta,'5',Ink,Red,' ',$85,' ',Ink,Magenta,'6',Ink,Red,' ',$85,CR
       DEFB At,11,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,12,1,$8B,$83,$83,$83,$8B,$83,$83,$83,$87,$83,$83,$83,$87,CR
       DEFB At,13,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,14,1,$8A,' ',Ink,Magenta,'7',Ink,Red,' ',$8A,' ',Ink,Magenta,'8',Ink,Red,' ',$85,' ',Ink,Magenta,'9',Ink,Red,' ',$85,CR
       DEFB At,15,1,$8A,'   ',$8A,'   ',$85,'   ',$85,CR
       DEFB At,16,1,$8E,$8C,$8C,$8C,$8E,$8C,$8C,$8C,$8D,$8C,$8C,$8C,$8D,13,Paper,Blue,Ink,White
EOSTR3: equ $

END MAIN
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Having slept on the problem, looking at the code afresh and re factoring it. I discovered I was being a dummy. :lol: I had zigged when I should have zagged. As was pointed out. I had jumbled up my fancy string length calculations. Assuming anything else equally potato does not crop up (highly likely unfortunately...) Predicting that end of the day will see the noughts and crosses program finished.

These keyboard input routines are getting on my nips lol. The multikey input routine is so flakey sometimes it works, sometimes it does not. there is no predictability other than it wont function reliably.

Then there is the test key, it seems a bit more reliable but then its useless for my task because I need to test 1-9 key at the same time.

is there a reliable, responsive way to do this?

Code: Select all

KEYBOARDINPUT:
       LD HL,LAST_K         ; LAST K SYSTEM VARIABLE.
       LD (HL),0           ; PUT NULL VALUE THERE.
_LOOP   LD A,(HL)           ; NEW VALUE OF LAST K.
       CP 0                ; IS IT STILL ZERO?
       JR Z,_LOOP           ; YES, SO NO KEY PRESSED.
       RET                          ; KEY WAS PRESSED.

MULTIKEY:
; WE WANT TO SCAN KEY 1-9, SO THE FOLLOWING WILL BE USED.

;61438 6, 7, 8, 9, 0
;63486 5, 4, 3, 2, 1
	LD A,0
	LD BC,63438         ; KEYBOARD ROW 6-0/JOYSTICK PORT 2.
       	IN A,(C)            ; SEE WHAT KEYS ARE PRESSED.
	RRA                 ; NEXT BIT ALONG (VALUE 2) = KEY 9.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP9         ; BEING PRESSED, SO PUT COUNTER IN MP9.
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT (VALUE 4) = KEY 8.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP8         ; BEING PRESSED,  SO PUT COUNTER IN MP8.
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT (VALUE 8) READS KEY 7.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP7         ; IT'S BEING PRESSED,  SO PUT COUNTER IN MP7.
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT (VALUE 16) READS KEY 6.
	CALL NC,MP6         ; IT'S BEING PRESSED,  SO PUT COUNTER IN MP6.
	LD A,0
	LD BC,63486         ; KEYBOARD ROW 1-5/JOYSTICK PORT 2.
       	IN A,(C)            ; SEE WHAT KEYS ARE PRESSED.
	RRA                 ; OUTERMOST BIT = KEY 1.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP1         ; IT'S BEING PRESSED,  SO PUT COUNTER IN MP1.
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT ALONG (VALUE 2) = KEY 2.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP2         ; BEING PRESSED, SO  SO PUT COUNTER IN MP2.
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT (VALUE 4) = KEY 3.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP3         ; BEING PRESSED,  SO PUT COUNTER IN MP3
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT (VALUE 8) READS KEY 4.
	PUSH AF             ; REMEMBER THE VALUE.
	CALL NC,MP4         ; IT'S BEING PRESSED,  SO PUT COUNTER IN MP4
	POP AF              ; RESTORE ACCUMULATOR.
	RRA                 ; NEXT BIT (VALUE 16) READS KEY 5.
	CALL NC,MP5         ; IT'S BEING PRESSED,  SO PUT COUNTER IN MP5
	JP Z,MULTIKEY
	RET

KEYTEST:
; MR. JONES' KEYBOARD TEST ROUTINE.

KTEST  LD C,A              ; KEY TO TEST IN C.
       AND 7               ; MASK BITS D0-D2 FOR ROW.
       INC A               ; IN RANGE 1-8.
       LD B,A              ; PLACE IN B.
       SRL C               ; DIVIDE C BY 8,
       SRL C               ; TO FIND POSITION WITHIN ROW.
       SRL C
       LD A,5              ; ONLY 5 KEYS PER ROW.
       SUB C               ; SUBTRACT POSITION.
       LD C,A              ; PUT IN C.
       LD A,254            ; HIGH BYTE OF PORT TO READ.
KTEST0 RRCA                ; ROTATE INTO POSITION.
       DJNZ KTEST0         ; REPEAT UNTIL WE'VE FOUND RELEVANT ROW.
       IN A,(254)          ; READ PORT (A=HIGH, 254=LOW).
KTEST1 RRA                 ; ROTATE BIT OUT OF RESULT.
       DEC C               ; LOOP COUNTER.
       JP NZ,KTEST1        ; REPEAT UNTIL BIT FOR POSITION IN CARRY.
       CCF
       RET
With MULTIKEY I tried resetting the accumulator between port scans, but that does not seem to help much. This is the main keyboard input i was trying to get working.

KEYBOARDINPUT works just fine, always responds and behaves in a predictable way. But then its not performing a particularly demanding task.. It's the one you would expect to work fine.

KEYTEST seems not to be so reliable.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Figured when the copy pasta failed me it was time to actually use my own coconut and 'roll my own' keyboard input comparator.

Code: Select all

POTATOK:
	LD A,0
	LD A,(LAST_K)
	CP $31		; IS 1?
	JP Z,MP1	; JUMP TO MP1
	CP $32		; IS 2?
	JP Z,MP2	; JUMP TO MP2
	CP $33		; IS 3?
	JP Z,MP3	; JUMP TO MP3
	CP $34		; IS 4?
	JP Z,MP4	; JUMP TO MP4
	CP $35		; IS 5?
	JP Z,MP5	; JUMP TO MP5
	CP $36		; IS 6?
	JP Z,MP6	; JUMP TO MP6
	CP $37		; IS 7?
	JP Z,MP7	; JUMP TO MP7
	CP $38		; IS 8?
	JP Z,MP8	; JUMP TO MP8
	CP $39		; IS 9?
	JP Z,MP9	; JUMP TO MP9
	RET
This works much more predictably than the copy and pasted subroutines. However the only pain in the butt is its not like INKEY$ in that I have to hit the key twice to get a response.

But for now its ok, at least it has limited predictable functionality. Will figure out what is wrong later.


Found out what the problem was, I was calling the KEYBOARDINPUT subroutine directly after the POTATOK subrouitne. (thus accounting for why I was having to hit everything twice..)
Having removed this from the main loop keyboard input responds as expected and is reliable.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Day 25: 340 days left.

As can be seen by my earlier comments today, POTATOK is working just fine and I can get information from the keyboard. I had been trying for days to get the tutorial keyboard routines to work without much success. I don't know what I was doing wrong there or if it was a case of them being non-portable. (lol wouldn't be the first tutorial that used a non-general routine example and stayed quiet about the fact...)

Anyway all that time wasted when I should have just trusted myself and wrote out my own routine. The funny thing was it worked first time (I just didn't realise it), another keyboard routine was causing the problem. I was using the general key test subroutine as a sanity check earlier in the day and had forgotten to take it out.

Still I think that the CP ladders are not the best solution, I think there is a more elegant approach but this was the simple one.

Once the keyboard input was done, I figured just cheeze this and use UGL characters for the noughts and crosses, its still better than the MSX basic listing at this point meh.. the idea was just to get something working then make it 'beautiful'. So I resisted the urge to break out SevenUP and get sprite happy for the moment.

From this point it was trivial to use the SOUNDFX.ASM file I had from crapchess in the project. I like this part about having the multi-file project. Now it's much more like a real program and it literally took me 1 min to include the file and call the routines. I think in the future this approach will greatly increase my productivity as I can be sure that the routines in the libraries work I just have to call them correctly.

Thus the keyboard input routines that were working all now live in KEYBOARD.ASM. Happily I can now use this in the crapchess with a little bit of work (just add in A,B,C,D,E,F,G,H and the arrow keys and were cooking on gas!)

As far as work flow goes, I tend to do the prototyping of ideas in MSX basic as I find it easer to use than spectrum basic. being able to something working straight off the bat (abet slow). Is good. From there I think about if I can feasibly do this on the spectrum in assembly. Then start figuring out the equivalent subroutines needed and if I already have written or have swiped from others or I will need to find/write them.

With the noughts and crosses the listing was 90 lines of basic, no graphics and just text characters to show the board. Speed wise its got the flicker issue that you find with most basic programs that update the screen.

I thought that with assembly code this could be fast enough to be fixed. and with fancy (er) graphics and some sounds, intro screen to tart it up a bit.

The program logic is an array, when a player selects a position on the board to place the X or the O the computer checks if that location is already occupied. If its already taken, an error is raised and the user is asked to input another choice. This continues in a loop till the program gets a board location that is vacant. It then places the O or X on the screen and records the players value in the array location (1-9).

There can be a maximum of 9 possible moves in noughts and crosses, there are three possible outcomes assuming that the players do not abandon the game.

1. Player A wins, Player B looses. No draw.
2. Player A looses, Player B wins. No draw.
3. Player A looses, Player B looses. Draw. (really this should be a case where A and B cant win..)

The basic listing looks at the array locations and sums them, if a certain magic number is reached it will tell you that a win state has happened (3 in a row). Based upon who has taken the last move tells the program who has won.

e.g

if CURRENTPLAYER = A then if any of the array lines sum to the winning total (3) goto winner section of the code.

This is fairly straight forward to do in assembly, my solution was to just have a series of nine memory locations that can be peeked by the program during run time. every time player A or B puts down a O or X a value is entered into these memory locations (in my program they live at 60001 -> 60009. with 2 being player B and 1 being player 1.

my solution to checking if there was already a value in the memory location is simple I just load the memory location into the accumulator compare it if its not zero then branch to an error state. tell the player they can't place a O or X in that location (1-9) and try again. This can be achieved in the form of a CP block of code with a JP to a error subroutine., then finally just a jp back to the start of the input loop.

The valid location selection is simple, assuming that the memory location that the player selected via keyboard (1-9) is 0, then either a 1 or a 2 is placed into the memory location. This is important as I use the 1,0,2 to determine what to print on the screen during the screen update portion of the program.

1 being an X and 2 being the O. blank space is 0. This is just another CP ladder that checks the memory location 60001 -> 60009 and prints to the screen.

The logic is fairly similar to the basic for checking win states, the memory locations are summed then logic is used (a series of AND and ORs should do the trick). if any of these logic states prove true then the program ends in one of the three ways I described earlier and depending on what state the program is in at the end determines how the screen looks to the user (Player A win screen, Player B win screen, Draw)

At the end of the game - there is a key input if players want to play again they can hit Y or if they want to continue on with their lives without more Noughts and Crosses action they can hit N. This is just another keyboard input routine. Would just be a variation of my POTATO routine (POTATOK3) that only checks for Y or N and berates you if you pick another key outside the range.

The last part is interesting, I plan to crash the machine on exit if user selects N.

There - a design outline for a assembly language noughts and crosses game. The reasons for creating such a think dubious at best but sometimes its best to get something done even if its crap and build up the skills haha. And what was obvious was I needed some more work before I can get crap chess working. But now that the noughts and crosses is nearly complete it makes me more confident in tackling crapchess and being able to complete it also.

Its the subroutines that I can use on the other projects that are the important thing, routines I can use again and again that are guaranteed to work out of the box. My prediction is soon this will enable me to increase my output. I figure there is a tipping point where you have enough subroutines in the bag to create any similar game you want then its just a matter of a graphics swap and some minor adjustment of game logic and you are good to go. With the board games I am only really limited by my lack of ability in scrolling the screen at the moment. If I just focus on non scrolling board games then that presents many hundreds of possible games that can be coded.

Snakes and ladders was one I thought about doing but unless I was going to make the squares very small its not fees able without scrolling the screen. So that is something for later. But boardgame geek has hundreds of games just waiting to a chance in the 'product lineup' lol. I always wanted to see how quickly I could bang out a line of games like this. If someone had a library of routines I think a great many could be created. Its just limited by your time in graphics for the different games. But then once you have a few graphics done its not hard to adapt for a new game. And then its just title screens and the help text.

The board games have been played by generations of people so its already play tested and a big part of the work is done then. While not technically impressive at least its a playable game. Lol.

Card games were something I thought about that are a logical progression from this, but actually they are more tricky with the game logic and you have to keep a larger array of data for each game (52 cards to anything up to something crazy like canasta). That is probably the next step after I have had enough of creating board games. Build more skills in developing game logic and do the card games. Eventually I can use these in creating the games I really want anyway (rpgs lol).

Next target after noughts and crosses to develop skill is ... Battleships. This is a logical progression to the skills developed in noughts and crosses in that we go from a 3x3 array to a 2 x 10x10 arrays. It can be written so that a series of menus control the action and graphics will be fine on the spectrum screen. The input routines can be handled and the game logic is pretty similar to what was used in noughts and crosses.

There is more scope for adding in some ship sinking animations when either player gets hit. This will help develop skills and help polish my handling of various game states/menus.
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

For those playing along at home, here is the original MSX basic listing I used as the template for the game.

This is crap game gold, taking a two player game that could have easily been played on scrap paper with better graphics and a more intuitive interface and putting it onto a computer. I love these programs. There is something heroic about the lack of analysis that goes into such a folly. As a testament to that - I took it further and made an assembly language version. :lol:

Anyway you can take a look at the base program. The book its from is full of games like this, so its a real treasure of crap games begging to be given the assembly graphics and sound overhaul.


Image

Image

Image
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

Which MSX emulator do you recommend? Ideally one that does MSX2 as well.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

Seven.FFF wrote: Thu Jan 25, 2018 2:22 pm Which MSX emulator do you recommend? Ideally one that does MSX2 as well.
openMSX is what I use but I don't really know enough about it to form an opinion there are a bunch of others that you could use.

fmsx is also referenced a lot, but there was a lot of technical documentation with the MSX so the emulation standard seems to be very good. With openMSX you can create your own configurations of MSX machine even ones that did not exist. It handles MSX2 and the MSX2+.

The main thing with openMSX is making sure that you have a manufacturer rom otherwise using the graphics launcher is just a pain because the generic rom does not allow you to use disk images. That sucks as the majority of MSX software is going to be on disk. But its fairly trivial to track down hundreds of manufacturer roms for MSX.

What I did was downloaded openMSX, then catapult (the graphic front end), then went to archive.org and got the TOSEC for MSX and MSX2. Then I realised I needed the manufacturer roms to actually run anything but the cartridges and spent about 30 mins googling. One you have that there are a few books on the net but nothing like the amount that there are for say atari/commodore or spectrum.

But where you loose with the books, you gain with the software - there is a lot available and tons of quality releases.

That said if I was an adult back in the 80s for sure I would have bought MSX, they are so nice to use and it was a common standard so there were lots of peripherals available (especially in Japan). It's a shame they were not more popular in the UK or US. With it being a common standard a lot of the compatibility issues that held up progress with microcomputers would have been avoided.

There are C compilers, Pascal, Forth, Logo, (think there is a Fortran and Cobol version available..). Plus a bunch of assemblers.I have not looked too deeply into it but Zen seems to be ok if you don't mind using a Merlin style program to develop on the platform. I got pasmo to compile roms for MSX. You have hardware sprite support and a bunch of other bios routines that help with making applications, plus openMSX has a nice monitor you can generate stuff like floppy disks on the fly I really only scratched the surface with what it can do.

There are tons of resources if you can read Japanese, there is still more that has never been scanned/loaded up onto the net but its all sat rotting on bookshelves in Japanese thirft stores and book warehouses. I remember seing junk shops when I was over there and they were filled floor the ceiling with crap for the MSX, peripherals, magazines, books, softs. One of the heart breakers was I saw a documentary on MSX over there they were interviewing a programmer and he had the source code listings all printed and in his little office for all these games that has never been preserved or studied. A guys whole store of programs and he didn't think anyone would want to look at it. I'll see if the documentary is on youtube it was pretty good.
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

Cheers, that sounds good. I'm looking at porting Metal Gear 1 from MSX2, so at some point I really should get round to running it(!). I appreciate the detailed tips :)
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

no worries, nothing worse than sitting in front of openMSX and wonder why nothing will load.

Image

That was me the first time I tried to run a game on openMSX lol.

That said its not a good day without one programming rage quit :lol:

Metal gear is a quality game - would be awesome to see how you got that to run on the Spectrum.

My guess is with the MSX once you nail the memory map and figure out how to talk to the rom its all pretty peachy but the tricky part is trying to overcome the limitations of the spectrum. The MSX gives you a lot of support to do great stuff. I think that is why there is some justifiable distaste for a lot of the spectrum titles that got ported to MSX, they didn't take advantage of the MSX hardware support that would make the games run much faster.

But going the other way, haha well the crap basic games are fine but my god trying to get even close to what it could do with some of the professional titles would be outstanding to even get close on the spectrum.
User avatar
Seven.FFF
Manic Miner
Posts: 736
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Crap 0.1 first assembly project

Post by Seven.FFF »

I had a FUUUUUUUUU- ragequit with openMSX too. Finally got it running with blueMSX, found an English translation patch, and managed to patch it.

I reaaally wanna use C.Born's wav2ay method to have it say "SNAAAAAAAAKE!!!" :D

Haven't got very far with it yet, but it'll be a radastan mode game that'll run on the Uno and ZEsarUX (and maybe the Next with some tweaking). I'm still playing around with a game screen graphics conversion workflow, but I got a title screen going.

Image
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Nomad
Manic Miner
Posts: 600
Joined: Thu Dec 28, 2017 12:38 pm

Re: Crap 0.1 first assembly project

Post by Nomad »

That looks sweet, its amazing what can be done with the new libraries. I have been itching to getting round to using the NIRVANA libraries but gotta get the basics down first.

Mind was blown today when I finally figured out I could compress more than screens with zx7 :lol: I was like 'if its all data.. then why not level data...' :mrgreen: depending on the compression ratios its making a game the size of dragonquest look at least remotely possible with multiloading of location data using the compression. I had been scratching my head for a while trying to figure out how to squeeze a open world into 30k with everything else up until now.

Helped keep crapchess's size down also, the background screen now weighs in at 320 bytes compressed. Might even have enough space for a continuous music track now.

But sure blueMSX is the one you tend to see in the youtube videos talking about msx. I think openMSX has a bit of a steep learning curve but once stuff starts to work its nice.

As a way to save the sanity of people trying to follow along with the various projects I waffle about here in the showcase I decided it was high time to get on the github bandwagon and put all the crap online for everyone to see the hot garbage that is my projects.

With all the source code your be able to have a chuckle at my potato antics and experience first hand the bizarre bugs and blind alley ways my projects inevitably take. any bug fixes or general sanity checks are most appreciated. It's also a good way to guard against my decrepit laptop finally giving up the ghost and taking all my data with it. Should be all set up by tomorrow.
Post Reply