; Anno Domini 4k. ; (c) 2004 Jonathan Cauldwell. ; An entry for the 2004 Minigame Competition, 4k category. ; Some bugs are known to exist, but are mostly invisible to the player. ; Throughout this listing x refers to the displacement, in character cells, ; from the top of the screen. Y refers to the displacement from the left ; edge. ; Project started 05.06.2004 @ 12:18. ; Project completed 18.07.2004 @ 19:24. ; Compile length: 4064 bytes. ; Definitions of constants. STYEAR equ 4000 ; starting year, 4000 BC. MAPSIZ equ 96*96 ; size of map. NUMCIV equ 5 ; number of civilisations. UNTSIZ equ 5 ; size of entries in unit table. CITSIZ equ 8 ; size of entries in city table. XORIG equ 3 ; origin of map window. UTYPES equ 63 ; bits d0 and d1 of unit type reserved for flags. ; Map block types. OCEAN equ 0 FISH equ 1 LAND equ 2 WHEAT equ 3 FOREST equ 4 HILL equ 5 TUNDRA equ 6 FIRS equ 7 MINE equ 8 CITY equ 9 ; Unit types. SETTLR equ 0 ; settler. TRIREM equ 1 ; trireme. WARIOR equ 2 ; warrior. SPEARM equ 3 ; spearman. ARCHER equ 4 ; archer. SWORDS equ 5 ; swordsman. MOVED equ 64 ; unit moved once in turn flag. LOADED equ 128 ; loaded flag. TRIREL equ TRIREM+LOADED ; loaded trireme. BUSY equ 64 ; settler unit busy flag. SETTLB equ SETTLR+BUSY ; busy settler. ; City improvement types. MILL equ 6 KILN equ 7 SMITHY equ 8 HARBOU equ 9 LIBRAR equ 10 MARKET equ 11 LBUILD equ 12 ; last city improvement. ; Start address to which we're compiling. org 23770 ; Set up map graphics in RAM. ld hl,mapgfx ; first few squares. ld de,blkgfx+8 ; RAM copy. ld bc,mapcol-mapgfx ; transfer all map blocks. ldir ; do the move. ld a,NUMCIV ; 1 set of city graphics per civilisation. ramcp ld hl,15752 ; ROM number chars 1-9. ld bc,72 ; 9 * 8 bytes to transfer to RAM. ldir ; copy to RAM. ld hl,c1016 ; city graphics 10-15. ld bc,mapgfx-c1016 ; 7 * 8 bytes to transfer to RAM. ldir ; copy to RAM. dec a ; this iteration done. jr nz,ramcp ; repeat for each civilisation. ; Transfer the block graphic colours. ld hl,mapcol ; first few squares. ld de,blcols ; RAM copy. ld bc,lbyte-mapcol ; transfer all map blocks. ldir ; do the move. ; Set up city colours for each civilisation. xor a ; first civilisation. ld h,d ; copy d to h. ld l,e ; copy e to l, hl=de. inc de ; next byte. ramcp0 push af ; count civilisations. cp 4 ; is this green? jr nz,ramcp1 ; no, so it won't clash with grass. inc a ; make it cyan instead. ramcp1 rlca ; make civilisation our paper colour. rlca ; 3 left shifts multiply by 8. rlca add a,7 ; ink colour = 7. ld (hl),a ; set colour. ld bc,16 ; number to transfer. ldir ; set all city blocks same colour. pop af ; restore count. inc a ; next civilisation. cp NUMCIV ; passed last one? jr nz,ramcp0 ; no, more colours needed. ; Starting from scratch - generate the landscape first. ld a,(23672) ; low byte of clock. ld (seed),a ; gives us a random seed of 0-255. ld hl,map ; start of map data. ld de,map+1 ; next byte. ld bc,9215 ; size of map. ld (hl),OCEAN ; ocean squares. ldir ; start with a world of ocean. ld a,LAND ; terrain type to fill is land. ex af,af' ; store it in alternate accumulator. defb 1,8,12 ; size and number of distinct land masses. defb 17,6,15 ; high row=6, size variation 15. gmap0 push bc ; loop counter. push de ; store parameters. call gmap ; generate land mass. pop de ; restore parameters. pop bc ; restore loop counter. djnz gmap0 ; repeat until all blocks drawn. ; Now we've drawn the larger land masses we can decide where to start ; our civilisations. After all, none of them will want to be stuck on ; some remote little island for the majority of the game so we need ; to look for patches of land before we generate the smaller islands. ld b,NUMCIV ; number of civilisations to start. gpos call ranmap ; set up random map position in hl. and a ; is it ocean? jr z,gpos ; yes, try again. ld c,SETTLR ; unit type = settler. call newun ; generate a new unit. djnz gpos ; repeat for all civilisations. ; So we've decided where everyone will start. We can now add some smaller ; land masses and islands to the map. ld hl,units+27 ld (hl),90 ld a,LAND ; terrain type to fill is land. ex af,af' ; store it in alternate accumulator. defb 1,2,120 ; minimum size=2, 120 land masses. defb 17,16,1 ; high row=16, size variation 1. gmap1 push bc ; loop counter. push de ; store parameters. ld c,2 ; minimum size=2. call gmap ; create a mass of land. pop de ; restore parameters. pop bc ; restore loop counter. djnz gmap1 ; repeat until all blocks drawn. ; Some icecaps would be nice too! defb 1,2,8 ; top edge and number of distinct land masses. gmap2 push bc ; loop counter. call gmap3 ; generate tundra. pop bc ; restore loop counter. djnz gmap2 ; repeat until all blocks drawn. defb 1,86,8 ; top edge and number of distinct land masses. gmap4 push bc ; loop counter. call gmap3 ; generate tundra. pop bc ; restore loop counter. djnz gmap4 ; repeat until all blocks drawn. ; Generate resources. ld bc,2 ; number of resources on map = 512. gres call ranmap ; set up random map position in hl. cp LAND ; is it ocean or fish? jr c,gres0 ; yes, put fish here. cp TUNDRA ; grassland? jr c,gres3 ; yes, establish ersource there. ; Icecaps - could only be forest. ld (hl),FIRS ; fir trees are only resource. jr gres1 ; So we're placing a land resource. gres3 ld a,b ; loop counter. cp 16 ; chance of special resource. jr c,gres2 ; special resource. ld a,c ; 0 or 1. add a,FOREST-1 ; want forest or hill. ld (hl),a ; create forest or hill. jr gres1 gres2 ld (hl),WHEAT ; make it wheat. jr gres1 ; Ocean resources consist of fish. gres0 ld a,c ; first or second iteration? rra ; is it the second? jr c,gres ; yes, only want land resources. ld (hl),FISH ; create forest. gres1 djnz gres ; repeat for all civilisations. dec c ; second pass. jr nz,gres ; draw trees etc. ; Set up the start values etc. ld hl,STYEAR ; set up the start year. ld (year),hl ; store year. ld hl,0 ; start with no gold in treasury. ld (money),hl ; gold. call 3503 ; clear screen. turn xor a ; zero in accumulator. ld (nosel),a ; units selected flag. ld ix,units-UNTSIZ ; table of units. mloopb ld b,1 ; player's civilisation is always 1. call lookun ; look for next unit for this civilisation. jr nz,mloop ; no player units left, turn is over. call cmapix ; centre and draw map. mloop call dmap ; show map. mloopu ld de,cityt3 ; clear panel. ld bc,cityt4-cityt3 ; length of string. call 8252 ; show it. ld de,cityt1 ; unit text. ld bc,cityt2-cityt1 ; length. call 8252 ; display it. call dyear ; display year. call dunits ; display all visible units. call dunitf ; display current unit. xor a ld (23560),a ; keypress buffer. mloop0 ld a,(23560) ; last key press. ; Scrolling map controls, always available. cp 11 ; cursor up. jr z,mapup ; scroll up. cp 10 ; cursor down. jr z,mapdn ; scroll screen down. cp 8 ; cursor left. jr z,maplf cp 9 ; cursor right. jr z,maprt cp '1' ; information key. jp z,menu ; general information screen. cp '0' ; city menu key. jp z,cmenu ; city menu screen. cp 13 ; Enter key. jp z,ai ; end of player turn, do CPU intelligence. ; Check if there are units to process. ex af,af' ; store keypress. ld a,(nosel) ; nothing selected flag. and a ; pointing to something? jr nz,mloop0 ; no. ex af,af' ; remember keypress. ; Unit movement keys. cp 'q' jp z,unup ; unit up. cp 'a' jp z,undn ; move the unit down. cp 'o' jp z,unlf ; move left. cp 'p' jp z,unrt ; Move unit right. cp 'b' ; action key. jr z,build ; build city. cp 'm' ; action - mine. jr z,bmine ; build a mine. cp 'c' ; action key. jr z,mapcnt ; centre map around unit. cp 32 ; Space key. jp z,unmov1 ; skip turn for this unit. jr mloop0 mapup ld hl,winx ; window x coordinate. ld a,(hl) ; what's its present value? and a ; not zero is it? jr z,mloop0 ; it is, can't go up. dec (hl) ; move up one. mloopa jr mloop ; rejoin main loop. mapdn ld hl,winx ; window x position. ld a,(hl) ; current value. cp 75 ; 96-21=75. jr z,mloop0 ; at bottom edge, don't scroll down. inc (hl) ; move x down the map. jr mloopa ; back to main loop. maplf ld hl,winy ; point to y coordinate. ld a,(hl) ; what's in there now? and a ; zero? jr z,mloop0 ; can't go any further. dec (hl) ; move left one block. jr mloopa ; main loop. maprt ld hl,winy ; y coordinate. ld a,(hl) ; present value. cp 64 ; 96-32=64. jr z,mloop0 ; that's the right edge, can go no further. inc (hl) ; scroll right. mloopc jr mloopa ; rejoin main loop. mapcnt call cmapix ; centre and draw map. jp mloopu ; display unit and continue. build call ctype ; check it's a settler. call checkb ; check we can build city here. jr nc,mloopa ; can't build a city here, too close to existing. call build0 ; build city. jp mloopb ; rejoin main loop looking for next unit. build0 ld c,(ix) ; civilisation number. push ix ; store unit pointer. call adjblk ; adjust city map block to reflect its size. ld c,(ix) ; put civilisation number in c register. ld (ix),0 ; remove settler from table. call settle ; create entry in settlement table. ld a,(ix) ; which civilisation? cp 1 ; is it a player city? jr nz,build1 ; no, it's CPU. ; Zoom straight to new city so player can decide what to build there. call decide ; set default item to build. call cmenu3 ; go to city selection bit. build2 pop ix ; restore unit. ret bmine call ctype ; only settlers can do this. call mapix ; get map block where settler is. cp HILL ; can't build mines where there are no hills. jr nz,mloopc ; no hills here. ld (hl),MINE ; build the mine. jp unmov1 ; finish move and find next unit. ; CPU civilisation has built a city - but what should it build there...? build1 call decide ; decide what to build there. jr build2 ; Check unit type is a settler. ctype ld a,(ix+1) ; get unit type. cp SETTLR ; is it a settler? ret z ; yes it is, it's okay. pop hl ; remove return address from stack (it's 4k, ok?) jr mloopc ; go back to main loop. decide ld a,(year+1) ; high byte of year. ld b,a ; in b register for now. call random ; random number. and 31 ; want a number 0-31. sub b ; subtract high byte of year. jr c,dec0 ; build settler. ; We don't default to settler units for the player so jump in here. decidp ld a,(ix+5) ; do we have a kiln? ld b,a ; store in b. and 2 ; second bit high indicates so. call z,dec2 ; don't have a kiln. decid1 rr b ; rightmost bit indicates mill in city. call nc,dec3 ; don't already have mill in settlement. ld a,b ; buildings shifted right. and 2 ; is there a blacksmiths? call z,dec4 ; no, let's try and build one. jr c,decid0 ; blacksmiths not allowed. ld a,SWORDS ; build swordsman. jr dec1 ; that's settled then. ; Nothing else is possible so let's have a warrior. decid0 ld a,WARIOR ; build warrior. jr dec1 dec4 ld a,SMITHY ; want a blacksmiths. jr decx ; check if allowed. dec3 ld a,MILL ; build a mill. jr decx ; check if allowed. dec2 ld a,KILN ; build a kiln. decx call notall ; not allowed? ret c ; no it isn't. pop hl ; pop return address from stack (saves memory!) jr dec1 ; set production. dec0 xor a ; settler is always zero. dec1 ld (ix+6),a ; set new production. ret ; Check to make sure we can build a city here. checkb call putxy ; put x and y coords into dispx. checb0 push ix ; store pointer to unit. call cityc ; check no cities already in vicinity. pop ix ; unit pointer back again. ret ; Create a settlement table entry for civilisation c. settle ld b,0 ; most cities we can have. ld ix,cities ; address of all settlement data. ld de,CITSIZ ; size of each entry. settl0 ld a,(ix) ; is this a city? and a ; zero means it's empty. jr z,settl1 ; it's empty. add ix,de ; next city in list. djnz settl0 ; repeat until all table is checked. ret settl1 ld (ix),c ; civilisation to whom city belongs. ld (ix+1),0 ; city starts with size of zero. ld hl,(dispx) ; fetch coords for city. ld (ix+2),l ; x coordinate. ld (ix+3),h ; y coordinate. and a ; remaining data is all zero. ld (ix+4),a ; food stored. ld (ix+5),a ; buildings in city. ld (ix+6),a ; building currently underway. ld (ix+7),a ; production. ret ; city now created. ; City menu selection. cmenu push ix ; store unit pointer. ld ix,cities ; city table. call ncity ; find player's next city. ld a,b ; how many attempts did we take? and a ; looped round table more than once? call nz,cmenu3 ; no, player has at least one city. pop ix ; restore unit pointer. jp mloop ; return to main loop. cmenu3 xor a ; clear accumulator. ld (23560),a ; remove last keypress. call cmapix ; centre map on this city. ld a,(ix+2) ; x coord. add a,XORIG ; map window starts 3 lines down. ld l,a ; result in low byte of hl pair. ld h,(ix+3) ; y coord. ld de,(winx) ; window coords. and a ; reset carry. sbc hl,de ; find x and y for city. ld (dispx),hl ; set up coords. call atadd set 7,(hl) ; make it flash. ld de,cityt0 ; city text. ld bc,cityt1-cityt0 ; length. call 8252 ; display it. ; ld a,(ix+1) ; city size. ; inc a ; increment it so it shows 1-16. ; call dispa ; show size. ld a,32 ; SPACE char. rst 16 ; display space. ld a,"(" ; open parenthesis. rst 16 ; display parenthesis. ld hl,unitt ; unit text descriptions. ld a,(ix+6) ; item in production. call getwrd ; get word from list. call pname ; display it. ld a,32 ; space character. rst 16 ; display space between unit and production. ld a,(ix+7) ; production spent. call dispa ; show it. ld a,'/' ; division symbol. rst 16 ; show separator. call gcost ; time to complete. cmen3a call dispa ; display remaining production. ld de,cityt2 ; next bit of text. ld bc,cityt3-cityt2 ; length. call 8252 ; display it. call fprod ; find production available. ; inc c ; always 1 less than displayed. call dispc ; display value on screen. ld a,32 ; ASCII space. rst 16 ; display on screen. ld a,"F" ; character to show. rst 16 ; display on screen. ld a,":" ; character to show. rst 16 ; display on screen. call ffood ; find food sources available. inc c ; always 1 less than displayed. call dispc ; display value on screen. ld a,6 ; delete to end of line. rst 16 ; tab across. call dyear ; display year. ; Now we need to list all buildings in this city. ld a,19 ; x coord, 25 - 6 = 19. ld (dispx),a ld a,(ix+5) ; buildings in city. and 127 ; mask out coast flag. jr z,cmenu0 ; nothing built in this city. push af ; store buildings. ld b,0 ; past last building. call listb ; text at top of list. pop af ; remember buildings. ld b,LBUILD-MILL ; number of buildings. listc push bc ; loop counter. rra ; rotate bit into carry flag. push af ; store buildings. call c,listb ; building exists in city, list it. pop af ; restore buildings byte. pop bc ; loop counter. djnz listc cmenu0 ld a,(23560) ; last keypress. cp 'o' ; O key. jr z,cmenu1 ; previous city in list. cp 'p' ; P key. jr z,cmenu2 ; next city in list. cp 'c' ; C key. jr z,cprd ; change item in production. cp 13 ; zero key. ret z ; menu done. jr cmenu0 ; continue until something pressed. cmenu1 call lcity ; previous settlement. cmenu4 jp cmenu3 ; show city details. cmenu2 ld de,CITSIZ ; size of city entry. add ix,de ; next in table. call ncity ; next city. jr cmenu4 ; show city details. cprd ld a,(ix+6) ; item in production. cprd0 inc a ; next in list. ld c,a ; put it in c for now. cp TRIREM ; trireme. jr z,cprd1 ; need to see if this is valid. cp HARBOU ; harbour. jr z,cprd3 ; make sure none already there and city on coast. cp MILL ; is it a unit? jr c,cprdl ; yes, can have any number within city. cp LBUILD ; reached last unit? jr nz,cprd2 ; no, make sure building not already there. cprdf xor a ; past end of list, get first item again. cprdl call notall ; is it allowed? jr c,cprd0 ; insufficient scientific research. ld (ix+6),a ; new item. jr cmenu4 ; redisplay city information panel. cprdno ld a,c ; restore unit type in production. jr cprd0 ; skip to next one. cprd1 equ $ cprdco ld a,(ix+5) ; coastal flag/city buildings byte. rla ; leftmost bit indicates a coastal city. jr nc,cprdno ; not coastal, can't build naval units. cprdys ld a,c ; restore production. jr cprdl ; this is valid. ; It's a building of some sort, need to check there isn't one already. cprd2 call bposs ; is building possible? jr nz,cprdno ; no, look for another. jr cprdys ; this improvement is fine to build. cprd3 call bposs ; is building possible? jr nz,cprdno ; no, look for another. jr cprdco ; make sure we're in a coastal city. bposs sub MILL-1 ; want improvement in range 1-7. call i2bit ; get bitmask in a. and (ix+5) ; check bit isn't already set. ret ; List a particular building. listb defb 17,13,30 ; 33-column and right edge. ld a,(ix+3) ; city's y coord. cp 81 ; is it at right edge of map, and therefore screen? jr c,listb0 ; no, list buildings down the right. defb 17,31,14 ; 33-column and right edge. listb0 push de ; remember left edge in d. ld a,LBUILD-MILL ; last building. sub b ; subtract loop counter to find building number. push af ; place on stack for later. ld hl,dispx ; x coord. ld a,(hl) ; get x coordinate for next item in list. dec (hl) ; post increment coordinate for next item. ld b,a ; put in b. ld c,e ; y coord. call 3545 ; set print position. ld a,32 ; ASCII space character. rst 16 ; display space at left of list. ld hl,imprt ; list of improvement types. pop af ; put building number in accumulator. call getwrd ; find name of this building. call pname ; display building name. ld a,23 ; TAB character. rst 16 ; tell ROM to tabulate. pop af ; remember left edge in a. rst 16 ; blank spaces to right edge of list. rst 16 ; need extra char due to bug in ROM. ret ; Given a city improvement number 1-7 we need to return the bitmask. i2bit ld b,a ; number of shifts. ld a,128 ; first shift rotates into rightmost bit. i2bit0 rlca ; do rotation. djnz i2bit0 ; repeat until we find relevant bit. ret ; Not allowed check. ; Item to build is passed in accumulator, then scientific research is ; checked to make sure item can be built. notall push bc ; store bc registers. ld c,a ; store in c register. ld e,a ; unit number in de. ld d,0 ; no high byte. ld hl,restab ; research table. add hl,de ; point to research entry for this item. add hl,de ; point to research entry for this item. add hl,de ; point to research entry for this item. call mul ; find amount required. push hl ; store pointer. ld hl,(scii) ; default to player's infrastructure. ld a,(ix) ; civilisation to check. dec a ; is it the player? jr z,notali ; yes, check his infrastructure will permit this. ld hl,(cpusci) ; CPU infrastructure. notali sbc hl,de ; subtract amount required from that spent. pop hl ; restore pointer. jr c,notal0 ; requirement is greater, not allowed. inc hl ; military requirement. call mul ; find amount required. push hl ; store pointer again. ld hl,(scim) ; military. ld a,(ix) ; civilisation to check. dec a ; is it the player? jr z,notalm ; yes, check his military can build it. ld hl,(cpuscm) ; CPU military. notalm sbc hl,de ; subtract amount required from that spent. pop hl ; restore pointer. jr c,notal0 ; requirement is greater, not allowed. inc hl ; cultural requirement. call mul ; find amount required. ld hl,(scic) ; culture. ld a,(ix) ; civilisation to check. dec a ; is it the player? jr z,notalc ; yes, check cultural research has discovered it. ld hl,(cpuscc) ; CPU cultural science. notalc sbc hl,de ; subtract amount required from that spent. jr c,notal0 ; requirement is greater, not allowed. notal0 ld a,c ; restore item number. pop bc ; restore bc register pair. ret mul ld a,(hl) ; science requirement. ld d,0 ; high byte of requirement. ld b,4 ; shift iterations, 2^4 = multiply by 16. mul0 rla ; double it. rl d ; rotate into high byte. djnz mul0 ; repeat 4 times. ld e,a ; what's left goes into low byte. ret ; Move units up/down/left/right. unup call putxy2 ; get coords in dispx. ld hl,dispx ; x coord. dec (hl) ; up 1 square. ; Check if another unit occupying square and start a fight if there is. unup0 call occsqa ; check for units occupying square. jr z,unup3 ; nothing there, move should be possible. cp (ix) ; make sure 2 civilisations are the same. jr z,unup3 ; they are, move is okay. ; Combat! ; A unit of one type is attempting to move into a square occupied by ; one of a rival culture. ; First we need to check that a civilian unit isn't attacking. ld a,(ix) ; is first unit a civilian one? and a ; settlers are always zero. jp z,mloopu ; civilian units cannot attack. ; So we're moving a military unit then. ; Attack the first unit in that square, regardless of defensive strength. call cinit ; start a fight. jp mloopb ; find next unit to move. unup3 ld a,(ix+1) ; find unit type. and UTYPES ; don't want flag bits. cp TRIREM ; is it a naval unit? jp z,unup1 ; yes it is, can only move through water. call mapadd ; what is there? cp LAND ; is it dry land? jr nc,unup2 ; yes, move is okay then. push ix ld ix,units-UNTSIZ ; table of units. unup4 call occsq ; any units occupying this square? jr z,unupu ; no, can't move there then. ld a,(ix+1) ; unit type. cp TRIREM ; is it an empty trireme? jr nz,unup4 ; no, look for another. ; Adjust trireme flag to say it's occupied. set 7,(ix+1) ; set type to loaded trireme. pop ix ; restore pointer to original unit. jr unup2 ; move is valid. unupu pop ix ; restore pointer to this unit. jp mloopu ; back to main loop. unup2 ld hl,(dispx) ; get new x coordinate. ld a,(ix+1) ; type of unit being moved. and UTYPES+LOADED ; check for unit types whether loaded or not. cp TRIREL ; is it a loaded trireme? jr z,uncar ; yes, move both units together. unup5 ld (ix+2),l ; new x. ld (ix+3),h ; new y. ld a,(ix+1) ; get unit type. ld b,a ; remember it. and UTYPES ; mask for unit types. cp TRIREM ; trireme? jp nz,disem ; no, only one move then. ld a,b ; restore type. and MOVED ; has unit moved? jr z,unmov0 ; yes, this is last move. unmov1 res 6,(ix+1) ; reset moved flag. disem call dechk ; disembark check. call mapix ; get map block where settler is. sub CITY ; is it a city? jr c,mlpb0 ; no, just move next unit. ; We're in a city. Does it belong to the player? rra ; divide by 16 to find civilisation. rra ; 4 right shifts rra ; will do this rra ; for us. and 7 ; remove bits shifted into left. ; inc a ; civilisation number now in accumulator. ; cp (ix) ; is it player's city? and a ; is it player's own city? jr z,mlpb0 ; yes, just move next unit. ; Conquered an enemy city. call switch ; switch city's allegiance. push ix ; store pointer to unit. ld ix,(temp) ; point to captured city. call cmenu3 ; ask player to select construction project. pop ix ; restore current unit. mlpb0 jp mloopb ; move next unit. unmov0 set 6,(ix+1) ; set moved once flag. ; call dechk ; disembark check. jp mloop ; still have second move left. unup1 call mapadd ; what terrain is there at new position? cp CITY ; is it a city? jr nc,unup2 ; cities are okay to move through. cp LAND ; is it a land square? jr c,unup2 ; no, can sail through. jp mloopu ; yes it's land, block move. ; One unit is carrying another. uncar ld (tempx),hl ; store new x and y coordinates. call putxy ; fetch current coords again. push ix ; push address of carrier onto stack. ld ix,units-UNTSIZ ; table of units. uncar0 call occsq ; any units occupying this square? jr z,uncar1 ; no, can't just move carrier then. ld a,(ix+1) ; unit type. and UTYPES ; ignore flags. cp TRIREM ; is it another trireme? jr z,uncar0 ; yes, look for another unit. ld hl,(tempx) ; restore new coords. ld (ix+2),l ; new x position. ld (ix+3),h ; new y position. uncar1 pop ix ; restore pointer to carrying unit. ld hl,(tempx) ; restore new coords. jp unup5 ; set new coordinates and find next unit. undn call putxy2 ; get coords in dispx. ld hl,dispx ; x coord. inc (hl) ; up 1 square. unuprj jp unup0 unlf call putxy2 ; get coords in dispx. ld hl,dispy ; y coord. dec (hl) ; left 1 square. jr unuprj unrt call putxy2 ; get coords in dispx. ld hl,dispy ; y coord. inc (hl) ; right 1 square. jr unuprj cinit1 push hl ; defender pointer. call cmapix ; centre map on conflict. call dunits ; show units on map. pop hl ; restore pointer. ld a,h ; accumulator must be non-zero. jr cinit0 ; set flag to indicate combat is shown. ; Combat - initialisation comes first. ; We add the attack strength to the defence strength to get the sum. cinit ld a,(hl) ; get defender civ. dec a ; does unit belong to player? jr z,cinit1 ; yes, contest must be seen then. ld a,(ix) ; attacker's civilisation. dec a ; does unit belong to player? jr z,cinit1 ; yes, contest must be seen then. xor a ; combat not shown. cinit0 ld (showc),a ; set flag. ld a,(ix+1) ; attacking unit type. call gatt ; get attack strength in c. inc hl ; defender type. ld a,(hl) ; put type in accumulator. inc hl ; defender x coord. ld a,(hl) ; get x in accumulator. ld (centx),a ; store it away. inc hl ; defender y coord. ld a,(hl) ; get y in accumulator. ld (centy),a ; store it away. inc hl ; defender strength. call gdef ; get defence in b. ld a,b ; defence. add a,c ; add attack for total strength. ld d,a ; store total in d for now. ; This is the combat loop. ; Choose a random number no higher than the sum of the 2 unit strengths. ; If the number is less than the defence strength the defence wins the ; round, otherwise the attacker does. Rounds repeat until one unit is ; completely destroyed by the other. combat push hl ; store pointer to defender. ld a,(showc) ; get flag. and a ; are we showing the fight? jr z,comba0 ; no, skip strength display. ; Show strength of unit on opposite side to unit with which it is engaged. push bc ; store combat points. push de ; combined points. ld de,(winx) ; window x and y coords in e and d respectively. ld a,(centx) ; defender x. ld b,a ; store in b register. sub (ix+2) ; attacker x. push af ; x difference. add a,b ; x is other side of defender. sub e ; subtract window x. add a,XORIG ; map starts at character cell (3,0). ld (dispx),a ; x coord of defender strength. ld a,(centy) ; defender y. ld b,a ; store in b register. sub (ix+3) ; attacker y. push af ; y difference. add a,b ; y is other side of defender. sub d ; subtract window y. ld (dispy),a ; y coord of defender strength. ld a,(hl) ; get strength. push de ; store window coords. call shocom ; show combat strength. pop de ; restore window coords. pop af ; restore y difference. neg ; flip the sign. add a,(ix+3) ; y coordinate of attacker. sub d ; subtract window y. ld (dispy),a ; store y coordinate of attacker strength. pop af ; x difference. neg ; flip the sign. add a,(ix+2) ; x coordinate of attacker. sub e ; subtract window x. add a,XORIG ; map starts at character cell (3,0). ld (dispx),a ; store x coordinate of attacker strength. ld a,(ix+4) ; attacker strength. call shocom ; show combat strength. call delay ; single second delay. pop de ; total points. pop bc ; unit attack/defence points. comba0 call random ; want a random number. cp d ; more than total strength? jr nc,comba0 ; yes, find another. pop hl ; restore pointer to defending unit. cp b ; has defence won this round? jr c,combd ; yes, weaken attacker. ; Attacker wins this round. dec (hl) ; no, weaken defender. jr nz,combat ; next round of combat. ; Attacker has won. dec hl ; defender y coord. dec hl ; defender x coord. dec hl ; defender type. dec hl ; civilisation. ld (hl),0 ; scrub unit. ret ; move completed after victory. ; Defender wins this round. combd dec (ix+4) ; weaken attacker. jr nz,combat ; next round of combat. ; Defender has won. ld (ix),0 ; kill attacking unit. ret ; City has been conquered by civilisation c. ; We need to find this city in the table, switch its allegiance, ; then update the map terrain type to reflect the new culture. switch push ix ; store unit pointer. ld a,(ix) ; unit's civilisation. push af ; store it. call cityc ; find city unit is in - this routine will do. ld (temp),ix ; store address of city in ix. ld a,(ix) ; city's current civilisation. cp 1 ; does it belong to player? jr z,switc0 ; city switching from player to CPU. pop af ; remember civilisation. ld (ix),a ; change allegiance to new side. call adjblk ; adjust city map block to reflect new owner. switc1 call decide ; default production type. ld (ix+7),0 ; start production from scratch. pop ix ; remember unit we just moved. ret switc0 call cmapix ; centre map on city. call delay ; short pause. pop af ; remember civilisation. ld (ix),a ; change allegiance to new side. call putxy ; coords of city in dispx. call adjblk ; adjust city map block to reflect new owner. call dmap ; show new ownership. call delay ; short pause. jr switc1 ; set up production and continue. ; Disembarking check. ; This code checks to see if unit is disembarking a naval unit. ; Original coordinates should be stored in origx, so look for a loaded ; naval unit with these coordinates - if we find one set it to unloaded. ; Another way to do this would have been to extend the unit table by ; another 2 bytes and store a pointer to the carrying/carried unit. ; This method was used because it was easy to use the existing occsq ; search routine, and efficient reuse of code in 4K takes priority. ; At the end of the day one trireme is much the same as another. dechk push ix ; pointer to unit that's just moved. ld hl,(origx) ; original coords of that unit. ld (dispx),hl ; put them in dispx for our search. ld ix,units-UNTSIZ ; table of units. dechk0 call occsq ; is any unit occupying this square? jr z,dechk1 ; nothing there, no boats to unload. ld a,(ix+1) ; check unit type. and UTYPES+LOADED ; remove movement bits. cp TRIREL ; is it a loaded trireme? jr nz,dechk0 ; no, look for another unit. ld (ix+1),TRIREM ; unload the boat. dechk1 pop ix ; restore pointer to original unit. ret ; job done. ; Get attack and defence strengths for unit type passed in accumulator. gatt cp ARCHER ; is it an archer? jr z,gatt2 ; yes, attack is 2. cp SWORDS ; is it a swordsman? jr z,gatt3 ; yes, attack is 3. ld c,1 ; default = attack strength 1. ret gatt2 ld c,2 ; strength 2. ret gatt3 ld c,3 ; attack points 3. ret gdef and a ; is defender a settler? ld b,a ; default b is zero. ret z ; yes, defence (b) is nothing. cp SPEARM ; is it a spearman? jr z,gdef2 ; yes, defence is worth 2. cp SWORDS ; is it a swordsman? jr z,gdef2 ; yes, defence is worth 2. ld b,1 ; default defence strength is 1. ret gdef2 ld b,2 ; strength 2. ret ; Get word number from a list. ; On entry: hl points to word list ; a contains word number. getwrd and a ; first word in list? ret z ; yep, don't search. ld b,a ; number of words to search in b register. getwd0 ld a,(hl) ; get ASCII character. inc hl ; next character of current word. rla ; found end of word? jr nc,getwd0 ; no, carry on. djnz getwd0 ; until we have right number. ret ; display characters until we encounter a byte with bit d7 set. pname ld a,(hl) ; get char. cp 128 ; shift leftmost bit into carry. jr nc,pname0 ; d7 is set so this is last char of word. rst 16 ; display it. inc hl ; next character of string. jr pname ; repeat until we hit the end. pname0 and 127 ; don't want bit d7. rst 16 ; show last letter. ret ; okay we're through. ; Text for unit types. unitt defb 'Settle','r'+128 defb 'Trirem','e'+128 defb 'Warrio','r'+128 defb 'Spearma','n'+128 defb 'Arche','r'+128 defb 'Swordsma','n'+128 ; Text for city improvement types. imprt defb 'Mil','l'+128 defb 'Kil','n'+128 defb 'Smith','y'+128 defb 'Harbou','r'+128 defb 'Librar','y'+128 defb 'Marke','t'+128 defb 'Buil','t'+128 ; Research table, science requirement before each unit may be built. ; Three bytes : Infra*16, Military*16, Culture*16. restab defb 0,0,0 ; settler. defb 5,2,0 ; trireme. defb 0,0,0 ; warrior. defb 0,30,0 ; spearman. defb 0,40,0 ; archer. defb 0,60,0 ; swordsman. defb 8,0,0 ; mill. defb 5,0,5 ; kiln. defb 0,60,0 ; smithy. defb 10,2,1 ; harbour. defb 5,0,50 ; library. defb 10,0,5 ; market. ; Return total production for city ix in c register. fprod call mapix ; get map address for city. ld de,65439 ; one char up and left = minus 97. add hl,de ; do the subtraction. ld c,0 ; production from city starts at zero. call gprodt ; get production from these 3 squares. call gprod ; square to left of settlement. inc hl ; square to right of settlement. call gprod ; find production there. ld de,93 ; last row = 93 chars on. add hl,de ; look down. call gprodt ; get production from these 3 squares. inc c ; 1 unit of production from city itself. ld a,(ix+5) ; city improvements. and 2 ; do we have a kiln here? ret z ; no. inc c ; kiln in city, increase production inside. ret ; Return total production for city ix in c register. ffood call mapix ; get map address for city. ld de,65439 ; one char up and left = minus 97. add hl,de ; do the subtraction. ld c,0 ; food starts at zero. call gfoodt ; get food from these 3 squares. call gfood ; square to left of settlement. inc hl ; square to right of settlement. call gfood ; find food sources there. ld de,93 ; last row = 93 chars on. add hl,de ; look down. call gfoodt ; get food from these 3 squares. inc c ; 1 unit of food from city itself. ld a,(ix+5) ; city improvements. rra ; do we have a mill here? ret nc ; no. inc c ; mill is present, so increase food from city. ret ; Put x and y coordinates into dispx and dispy prior to calling mapadd. putxy ld l,(ix+2) ; x position. ld h,(ix+3) ; y pos. ld (dispx),hl ; put coords in dispx for mapadd call later. ret ; Put x and y into dispx and origx, dispx will change but we'll keep origx. putxy2 call putxy ; put x+y coords into dispx and dispy. ld (origx),hl ; store original coords for disembark check. ret ; Establish what production a square gives based on its type. gprod ld a,(hl) ; what exactly is the type? cp FIRS ; fir trees? jr z,gprod1 ; yes, increment production. cp MINE ; a mine? jr z,gprod1 ; yes, increment production. cp FOREST ; is it forest? jr nz,gprod0 ; no, don't increment production. gprod1 inc c ; increment production count. gprod0 inc hl ; next square to the right. ld a,(ix+1) ; city's size. inc a ; 0 means 1, 1 means 2 etc. cp c ; have we reached the population limit? ret nc ; no, food is fine. ld c,a ; limit production to population size. ret gprodt ld b,3 ; want 3 iterations. gprodr call gprod ; what kind of territory is this? djnz gprodr ; repeat for top 3 squares. gprods ld de,93 ; next row = 93 chars on. add hl,de ; look down. ret ; Establish what food resource a square gives based on its type. gfood ld a,(hl) ; what exactly is the type? cp LAND ; is it sea of some sort? call c,setsea ; yes, set flag to say it's coastal. cp LAND ; green land? jr z,gfood1 ; yes, 1 unit of food. cp WHEAT ; wheat? jr z,gfood2 ; yes, 2 units of food. cp FISH ; is it fish? jr nz,gfood0 ; no, no more food squares. gfood3 inc c ; increment food production count. gfood2 inc c ; increment food count. gfood1 inc c ; more food to count. gfood0 inc hl ; next square to the right. ld a,(ix+1) ; city's size. cp c ; have we reached the population limit? ret nc ; not yet we haven't. gfoodl ld c,a ; limit production to population size. ret gfoodt ld b,3 ; want 3 iterations. gfoodr call gfood ; what kind of territory is this? djnz gfoodr ; repeat for top 3 squares. jr gprods ; next row = 93 chars down. ; While we're doing food calculation we can set flag for coastal cities. setsea ld a,(ix+5) ; buildings/coastal byte. or 128 ; set byte to say city is coastal. ld (ix+5),a ; put byte back again. and 8 ; bit 4 indicates harbour is present in city. jr z,setse0 ; no harbour. inc c ; increase food resource of sea square. setse0 ld a,(hl) ; restore terrain type. ret cityt0 defb 22,0,0 ; top of screen. defb 'City ' ; city selected. cityt1 defb 22,0,0 defb 'Unit ' ; unit selected. cityt2 defb ')',6 ; end of item in production. defb 'P:' ; production per turn. cityt3 defb 22,0,0,6,6,6,6 ; blank top lines. defb 6,6 cityt4 equ $ ; Use the BASIC line numbering routine to display a number. dispa ld c,a ; accumulator to c. dispc ld b,0 ; zeroise high byte. dispbc jp 6683 ; display number in bc pair. dispas call dispa ; display number in accumulator. ld a,32 ; ASCII code for a space. rst 16 ; display trailing space. ret dyear ld a,22 ; AT code. rst 16 ; display it. xor a ; top line. rst 16 ; display it. ld a,25 ; end of line. rst 16 ; display it. ld bc,(year) ; year in BC (how apt!) call 6683 ; show year. ld a,32 ; SPACE char. rst 16 ; display it. ld a,'B' ; character to show. rst 16 ; display it. ld a,'C' ; character to display. rst 16 ; display it. ret ; Find previous city owned by the player. lcity ld de,65536-CITSIZ ; city table entry size, negative. add ix,de ; find next in list. ld a,(ix) ; get civilisation of this city. cp 1 ; is city ours? ret z ; yes, return city. push ix ; copy ix onto stack. pop hl ; pop it into hl. ld de,cities ; start of cities. sbc hl,de ; do subtraction to see if we're at the beginning. jr nc,lcity ; no we aren't. ld ix,termin-CITSIZ ; point to end of city list again. jr lcity ; let's start again. ; Find next city owned by the player. ncity ld b,2 ; number of attempts. ncity0 ld a,(ix) ; get civilisation of this city. cp 1 ; is city ours? ret z ; yes, return city. ld de,CITSIZ ; city table entry size. add ix,de ; find next in list. push ix ; copy ix onto stack. pop hl ; pop it into hl. ld de,termin-1 ; end of cities. sbc hl,de ; do subtraction to see if we're at the end. jr c,ncity0 ; no we aren't. dec b ; keep count of number of times we've looped. ret z ; it's pointless continuing after > 1 pass. ld ix,cities ; point to start of city list again. jr ncity0 ; let's start again. ; City check. Put x in l and y in h, then call to see if city nearby. cityc ld ix,cities-CITSIZ ; address of all settlement data. cityc0 call fcity ; can we find a city? ret c ; no we can't. push ix ; copy ix onto stack. pop hl ; pop it into hl. ld de,termin-1 ; end of cities. sbc hl,de ; do subtraction to see if we're at the end. ret nc ; no we aren't. ld hl,(dispx) ; get coordinates of potential city in hl. ld a,(ix+2) ; x coordinate of city. add a,3 ; add 3. sub l ; x coordinate to check against. cp 7 ; is it within radius of 4 (8/2)? jr nc,cityc0 ; no, we're nowhere near it then. ld a,(ix+3) ; y coordinate of city. add a,3 ; add 3. sub h ; y coordinate to check against. cp 7 ; is it within radius of 4 (8/2)? jr nc,cityc0 ; no, we're nowhere near it. ld b,(ix) ; return civilization to whom it belongs. and a ; reset carry to say city found. ret ; Find next city. fcity ld de,CITSIZ ; size of each entry. add ix,de ; next city in list. push ix ; copy ix onto stack. pop hl ; pop it into hl. ld de,termin-1 ; end of cities. sbc hl,de ; do subtraction to see if we're at the end. jr nc,fcity1 ; yes we are - set carry and return. ld a,(ix) ; is this a city? and a ; zero means it's empty. ret nz ; it's a city. jr fcity ; loop round again. fcity1 scf ; set carry to indicate nothing found. ret ; Display all units. dunits push ix ; store pointer to current unit. ld hl,units ; start of units table. ld b,0 ; number of units in table. dunts0 push bc ; store unit counter. ld a,(hl) ; civilisation number of unit. and a ; does unit entry exist? jr nz,dunts1 ; yes, show it. dunts2 ld de,UNTSIZ ; size of unit entries. add hl,de ; try next unit. pop bc ; restore unit counter. djnz dunts0 ; repeat for all units. pop ix ; restore current unit pointer. ret dunts1 push hl ; copy unit address onto stack. pop ix ; pop it off into ix pair. push hl ; store unit address. call dunit ; display unit if we can. pop hl ; restore unit pointer. jr dunts2 ; return and process the rest. ; Flash selected unit. dunitf ld hl,0 ; default to ROM so we don't overwrite anything. ld a,(ix) ; unit flag. and a ; valid unit? ret z ; no, there's nothing to display. push ix ; copy ix onto stack. pop hl ; pop it into hl. ld de,cities ; start of cities. sbc hl,de ; do subtraction to see if we're past units. ret nc ; yes we are. call dunit ; display unit. or 128 ; want attribute flashing. ld (hl),a ; set new attribute. ld hl,unitt ; unit text descriptions. ld a,(ix+1) ; current item. and UTYPES ; mask off flags. call getwrd ; get word from list. call pname ; display name of this unit. ld a,32 ; space character. rst 16 ; display space. ld a,(ix+4) ; unit strength. jp dispa ; display strength and return. ; Display unit pointed to by ix registers. dunit ld a,(winx) ; window x. sub (ix+2) ; unit x position. neg ; result is negative, make it positive. cp 21 ; is it less than 21? ret nc ; no, so unit isn't on screen. add a,XORIG ; origin of window is (3,0). ld (dispx),a ; screen x coordinate. ld a,(winy) ; window x. sub (ix+3) ; unit x position. neg ; result is negative, make it positive. cp 32 ; is it less than 32? ret nc ; no, so unit isn't on screen. ld (dispy),a ; screen y coord. call findsc ; find screen address. ld hl,untgfx ; unit graphics. ld a,(ix+1) ; unit type. and UTYPES ; mask off bits reserved for flags. call addacc ; multipl accumulator by 8 and add to hl. call dchr ; display unit. call atadd ; address of screen attributes. ld a,(ix) ; civilization number. add a,55 ; values 56 onwards for attributes. cp 60 ; is it green? jr nz,dunit0 ; no. ld a,5 ; make it cyan on black. dunit0 ld (hl),a ; set attributes. ret addacc rlca ; multiply by 8. rlca rlca ld c,a ; put char address displacement in c. ld b,0 ; zero high byte of bc. add hl,bc ; add displacement to unit graphics address. ret ; Look for next unit belonging to civilisation b. ; On success returns with ix pointing to unit, if no more units are ; found it returns with zero flag unset. ; NB: Don't insert anything between units and cities or lookun won't work. lookun call getunt ; find next entry in unit table. jr nc,lokun0 ; we are at the end of the table. ld a,(ix) ; civilisation number of unit. cp b ; does it match the one we want? ret z ; yes, job done. jr lookun lokun0 ld a,b ; set a to non-zero. ld (nosel),a ; set no units selected flag. ret getunt ld de,UNTSIZ ; size of unit entries. add ix,de ; try next unit. push ix ; copy ix onto stack. pop hl ; pop it into hl. ld de,cities-1 ; end of units. sbc hl,de ; do subtraction to see if we're at the end. ret ; General CPU intelligence. ai ld a,2 ; start with civilisation 2. ai1 ld (tciv),a ; CPU civilisation stored in temp. ld ix,units-UNTSIZ ; table of units. ai0 ld a,(tciv) ; fetch CPU civilisation. ld b,a ; put it in b. call lookun ; look for next unit for this civilisation. jr nz,aiok ; no player units left, turn is over. ; So we've found a CPU unit. Establish its type so we can decide what to do. ld a,(ix+1) ; get type. cp WARIOR ; is it military? jp nc,mili ; yes, do military intelligence. ; It's a settler. If we can build here then do so. call checkb ; check we can build city here. jr nc,aim ; can't build a city here, need to move settler. call build0 ; build city here. jr ai0 ; loop until no more units for this civilisation. aiok ld a,(tciv) ; restore civilisation. inc a ; next one. cp NUMCIV+1 ; gone past last one? jp nc,eotp ; yes, do end of turn processing. jr ai1 ; start again. ; Can't build a city where we are, so need to move to where we can. aim ld a,255 ; set max distance. ld (mintrv),a ; minimum travel distance to potential city site. call random ; random direction. ld (direct),a ; default in case nowhere to go. push ix ; pointer to unit. pop hl ; copy to hl. ld a,l ; put low byte in a. ; rra ; ONLY WANT THIS IF UNTSIZ IS AN EVEN NUMBER! ld (temp),a ; direction. ld b,4 ; 4 directions to try out. aim0 push bc ; store loop counter for 4 directions. xor a ; zero accumulator. ld (dist),a ; zero distance for this direction. call putxy ; coords in tempx. ld a,(temp) ; get direction. and 3 ; direction, 0-3. jr z,aiu ; look up. dec a jr z,aid ; look down. dec a ; next direction. jr z,ail ; look left. ; Drop through into AI right. air ld hl,dispy ; y coord. inc (hl) ; right 1 square. call distup ; increment distance and get territory. cp LAND ; is it land? jr c,aind ; no, it's water. call checb0 ; could we build a city here? jr nc,air ; move again. ; Set this as distance. setd ld a,(mintrv) ; minimum distance to travel. ld b,a ; put minimum distance in b. ld a,(dist) ; this distance. ld c,a ; store in c for now. sub b ; is minimum greater? jr nc,aind ; no, try next direction. ld a,(temp) ; this direction. ld (direct),a ; store direction as closest yet. ld a,c ; get this distance back from c. ld (mintrv),a ; set new minimum travel distance. aind ld hl,temp ; direction. inc (hl) ; try next one. pop bc ; pop loop counter. djnz aim0 ; repeat for 4 directions. jp aimset ; set move. aiu ld hl,dispx ; x coord. dec (hl) ; up 1 square. call distup ; increment distance and get territory. cp LAND ; is it land? jr c,aind ; no, it's water. call checb0 ; could we build a city here? jr c,setd ; yes, set this as distance. jr aiu ; move up again. aid ld hl,dispx ; x coord. inc (hl) ; down 1 square. call distup ; increment distance and get territory. cp LAND ; is it land? jr c,aind ; no, it's water. call checb0 ; could we build a city here? jr c,setd ; yes, set this as distance. jr aid ; move up again. ail ld hl,dispy ; x coord. dec (hl) ; up 1 square. call distup ; increment distance and get territory. cp LAND ; is it land? jr c,aind ; no, it's water. call checb0 ; could we build a city here? jr c,setd ; yes, set this as distance. jr ail ; move up again. distup ld hl,dist ; distance travelled in this direction. inc (hl) ; increment it. jp mapadd ; get next territory square. ; AI to move settler. aimset call putxy ; coords in temp location. ld hl,dispx ; point hl at x coord. ld a,(direct) ; direction we're going in. and 3 ; up? jr z,aimu ; move up. dec a ; down? jr z,aimd ; move down. dec a ; down? jr z,aiml ; move left. inc hl ; point to y coord. inc (hl) ; move right 1 square. aimst0 call mapadd ; what's the terrain like? cp LAND ; double-check we're moving onto land. jr c,aiblok ; after all that we got a duff move! call occsqa ; anyone already there? jr z,aimst1 ; no, it's free. ld a,(ix) ; unit's civilisation. cp (hl) ; blocking unit's civilisation. jr z,aimst1 ; it's the same tribe so move is okay. aiblok jp ai0 ; can't move, get next unit. aimst1 ld hl,(dispx) ; get new coords. ld (ix+2),l ; unit's new x. ld (ix+3),h ; unit's new y. jp ai0 ; get next unit for this civilisation. aimu dec (hl) ; move up 1 block. jr aimst0 aimd inc (hl) ; move down 1 position. jr aimst0 aiml inc hl ; point to y. dec (hl) ; check left 1 square. jr aimst0 ; Look for next unit occupying a particular square. ; Returns with zero flag set if no unit present. occsq call getunt ; get next table entry. jr nc,occsq0 ; we are at the end of the table. ld hl,(dispx) ; get coords to check. ld a,(ix+2) ; get unit x coord. cp l ; compare with dispx. jr nz,occsq ; x coords don't match, find next unit. ld a,(ix+3) ; get unit y coord. cp h ; compare with dispy. jr nz,occsq ; x coords don't match, find next unit. ld a,(ix) ; civilisation of unit in that square. and a ; make sure unit is a valid one. jr z,occsq ; that's not a unit, coords are rubbish. push ix ; place pointer to this unit on the stack. pop hl ; copy it into hl. ret ; return civilisation in a, zero unset. occsq0 push ix ; place pointer to this unit on the stack. pop hl ; copy it into hl. and a ; zeroise accumulator, set zero flag. ret occsqa push ix ; store ix. ld ix,units-UNTSIZ ; table of units. call occsq ; any unit occupying this square? pop ix ; restore ix. ret ; Military 'intelligence' follows. ; First perform a search of all cities to find the closest potential target. mili push ix ; store pointer to unit. ld a,255 ; distance. ld (mintrv),a ; minimum travel distance to potential city site. call putxy ; store unit's coordinates for city check. ld (origx),hl ; second copy of coords in tempx. ld (tempx),hl ; default destination is to stay put. ld ix,cities-CITSIZ ; list of all settlements. milin0 call fcity ; find next city. jr c,miliv ; no more cities so seek out closest we found. ; Found a city, but is it of any interest to us? call putxy ; put city's coords in dispx for search. ld a,(tciv) ; to whom does the unit belong? cp (ix) ; same civilisation as the city? jr nz,militg ; no, potential target then. ; It's our own city. Does it have a unit to defend it? call occsqa ; is this city square occupied? jr z,militg ; city is empty, so potential target. ; It's possible that the present unit is the only one within the city. ld a,(origx) ; unit x coordinate. cp (ix+2) ; city x coord. jr nz,milin1 ; don't match, it's a different unit. ld a,(origx+1) ; unit y coordinate. cp (ix+3) ; city's y coord. jr nz,milin1 ; it's a different unit, city is defended. ; Need to look for a second unit within city. push ix ; store city pointer. push hl ; copy last unit we found to stack. pop ix ; copy into ix and continue search. call occsq ; find another unit in city. pop ix ; restore city pointer. jr z,militg ; no other unit is defending city. ; Search for the next city. milin1 ld hl,(origx) ; get unit coordinates. ld (dispx),hl ; reset search coordinates. jr milin0 ; search for next city. ; We have a potential target in mind, let's see how close it is. militg ld a,(origx) ; unit's current x position. ld hl,dispx ; city's x position. call fdiff ; find vertical difference. ld b,a ; put in b. inc hl ; point to city y coordinate. ld a,(origx+1) ; unit's y position. call fdiff ; find horizontal difference. add a,b ; add vertical difference to get distance. ld hl,mintrv ; minimum travel distance. cp (hl) ; is distance less than previous closest city? jr nc,milin1 ; no, try another city. ld (mintrv),a ; set this as new default position. ld hl,(dispx) ; city coordinates. ld (tempx),hl ; copy to destination coords. jr milin1 ; find next city. ; Okay, we've trawled through the city table and have a target. ; At this point we have a destination in tempx, let's go there. miliv pop ix ; restore pointer to unit. call putxy ; unit's coords in dispx again. ld hl,tempx ; vertical destination. ld a,(dispx) ; unit's vertical position. cp (hl) ; where is it in relation to the city? ld hl,dispx ; unit x. jr z,milih ; the same, move unit horizontally. jr nc,miliu ; it's higher so move military unit up. inc (hl) ; look down. militv call mapadd ; examine terrain. cp LAND ; is it land? jr c,milih ; no, move horizontally instead. ; Rival unit check. miliru call occsqa ; anyone there? jr z,militm ; nothing there, move should be possible. cp (ix) ; make sure 2 civilisations are the same. jr z,militm ; they are, move is okay. ; CPU is moving a military unit into a square occupied by another unit. ; Call the combat routine to establish who wins the square. call cinit ; initiate combat. jr miliok ; move next CPU unit. miliu dec (hl) ; look up. jr militv ; check terrain and rival units. militm ld hl,(dispx) ; new position. ld (ix+2),l ; new x coordinate of unit. ld (ix+3),h ; new y coordinate of unit. call mapadd ; get terrain type in accumulator. sub CITY ; is it a city? jr c,miliok ; no, just move next unit. call switch ; switch city's allegiance to player. miliok jp ai0 ; Vertical movement is no good, let's try horizontal. milih call putxy ; put unit coords in dispx again. ld hl,tempy ; horizontal destination. ld a,(dispy) ; unit's horizontal position. cp (hl) ; where is it in relation to the city? ld hl,dispy ; unit y. jr z,miliok ; the same, leave unit alone. jr nc,milil ; it's to the left so move unit that way. inc (hl) ; look right. milith call mapadd ; examine terrain. cp LAND ; is it land? jr c,miliok ; no, move impossible. jr miliru ; check for rival units and fight them. milil dec (hl) ; look left. jr milith ; check terrain and rival units. ; End of turn processing. eotp ld hl,(year) ; year. ld de,65526 ; progress in ten-year steps. add hl,de ; subtract ten years (it's BC, remember!) ld (year),hl ; new year. ld a,h ; high byte of year. or l ; mix with low byte. jr nz,pcity ; if not reached AD 1 we continue. call 3503 ; clear screen. call dpop ; display final population. rst 8 ; game over. defb 255 ; end run with 0:OK message. ; Process cities. pcity xor a ; default to no civilisation. ld (tciv),a ; CPU civilisation conducting research. ld ix,cities-CITSIZ ; list of all settlements. ld b,0 ; most cities we can have. pcity0 call fcity ; find next city to process. jp c,pcityr ; checked all table, none left. ; We have a city to process! ; First we put city size in de pair. ld e,(ix+1) ; city size. ld d,0 ; zeroise high byte of de. inc de ; need to add 1. ld a,(ix) ; to which civilisation does city belong? cp 1 ; is it the player? jp nz,cpucit ; it's the CPU, process accordingly. ; Now check for special buildings and process the effects they have. ld a,(ix+5) ; check buildings present. ld b,a ; store in b for now. and 16 ; is a library present? jr z,nolib ; no. ; Library is present in city so increase research in all three areas. ld hl,(scii) ; infrastructure research spent so far. add hl,de ; increase it. ld (scii),hl ; new total. ld hl,(scim) ; military research spent so far. add hl,de ; increase it. ld (scim),hl ; new total. ld hl,(scic) ; cultural research spent so far. add hl,de ; increase it. ld (scic),hl ; new total. nolib ld a,b ; fetch buildings flags again. and 32 ; has a market been built? jr z,nomkt ; no market. inc de ; increment money gained in taxes. nomkt ld hl,(money) ; treasury. add hl,de ; increase it. ld (money),hl ; new total. ; Find out food available and grow accordingly. pcity2 call ffood ; find food resources. inc c ; add 1. ld a,(ix+4) ; food stored. add a,c ; add food. ld b,(ix+1) ; find population size. inc b ; zero means population of 1. sub b ; subtract population size. jr c,starve ; oops, city suffering from starvation. ld (ix+4),a ; new food total. rl b ; multiply population by 16. rl b rl b rl b cp b ; has stored food exceeded limit? jr c,constr ; no, city hasn't grown so check construction. ; So the city has grown. Empty food store and increase city's size. ld (ix+4),0 ; empty the food store. ld a,(ix+1) ; city size. cp 15 ; reached maximum of 15? jr nc,constr ; yes, cannot grow any more. inc (ix+1) ; grow city. call putxy ; set up x and y to find address. call adjblk ; adjust map block to reflect new city size. ; Work out the new production total and see if we've finished construction. constr call fprod ; find production available. ld a,(ix+7) ; production spent. add a,c ; add production for this city. ld (ix+7),a ; new production total. ld b,a ; put in b for now. call gcost ; get cost of item in production. sub b ; subtract spent from that required. jr nc,pcity0 ; not reached amount yet, get next city. ld (ix+7),0 ; start production from scratch. ld a,(ix+6) ; what exactly was underway? and a ; was it a settler? jp z,newu0 ; generate new settler. sub SWORDS ; is it a military unit? jp c,newu1 ; set up the new naval unit then. jp z,newu1 ; set up the new naval unit then. ; Dropped through to here so must have built a building. call i2bit ; convert building to bitmask. or (ix+5) ; combine with buildings already in city. ld (ix+5),a ; new buildings. pcity1 call decide ; default new production. ld a,(ix) ; civilisation number. dec a ; is it the player's city? jr nz,pcity3 ; no, just process next city. push ix ; store pointer as player may change city. call cmenu3 ; ask player to select next project. pop ix ; restore current city. pcity3 jp pcity0 ; process next city. starve ld (ix+4),0 ; empty the food store. dec (ix+1) ; reduce population. call adjblk ; adjust map block to reflect new city size. jr constr ; now check construction project. ; All cities processed. Now process research. pcityr ld hl,(money) ; money in bank. ld de,(expi) ; infrastructure expenditure. and a ; reset carry flag. sbc hl,de ; subtract expenditure from treasury. jr c,pcitye ; can't afford it. ld (money),hl ; new treasury figure. ld hl,(scii) ; infrastructure research spent so far. add hl,de ; increase it. ld (scii),hl ; new total. ld hl,(money) ; money in bank. ld de,(expm) ; military expenditure. sbc hl,de ; subtract expenditure from treasury. jr c,pcitye ; can't afford it. ld (money),hl ; money remaining. ld hl,(scim) ; military research spent so far. add hl,de ; increase it. ld (scim),hl ; new total. ld hl,(money) ; money in bank. ld de,(expc) ; cultural expenditure. sbc hl,de ; subtract expenditure from treasury. jr c,pcitye ; can't afford it. ld (money),hl ; gold left after science. ld hl,(scic) ; cultural research spent so far. add hl,de ; increase it. ld (scic),hl ; new total. jr pcityd ; done. ; Too expensive, zeroise all expenditure. pcitye ld hl,0 ; no money. ld (expi),hl ; infrastructure spending. ld (expm),hl ; military spending. ld (expc),hl ; cultural expenditure. pcityd jp turn ; back to main loop. ; Make random decision as to how CPU spends its research income from ; each individual city. cpucit ld a,(tciv) ; find temp civilisation. and a ; has it been set up? jr z,cpuci1 ; no, this civilisation will do. cp (ix) ; is this the same civilisation? jr nz,cpuci2 ; no, don't bother. cpuci1 ld a,(ix) ; get civilisation to which city belongs. ld (tciv),a ; this is the one we'll be using. call random ; fetch a random number. ld hl,cpusci ; default to infrastructure. cp 85 ; one third chance. jr c,cpuci0 ; spend city's income on infrastructure. inc hl ; add 2 to point to inc hl ; military spending. cp 170 ; one third chance. jr c,cpuci0 ; spend city's income on military research. inc hl ; add 2 to point to inc hl ; cultural research. cpuci0 ld e,(ix+1) ; city's size. inc e ; add 1 as always below actual population. ld d,0 ; initialise high byte. ld c,(hl) ; low byte of address. inc hl ; point to high byte. ld b,(hl) ; high byte in bc. ex de,hl ; pointer in de, budget in hl. add hl,bc ; add to amount already spent. ex de,hl ; pointer in hl, budget in de. ld (hl),d ; high byte of new total. dec hl ; point to low byte. ld (hl),e ; low byte of new total. cpuci2 jp pcity2 ; process food etc. ; Get production cost of item currently under construction. gcost ld a,(ix+6) ; get item in production. ld e,a ; displacement. ld d,0 ; zero high byte. ld hl,pctab ; production cost table. add hl,de ; add displacement. ld a,(hl) ; return cost in accumulator. ret ; Table of production costs for units and city improvements. pctab defb 20 ; settler. defb 20 ; trireme. defb 15 ; warrior. defb 30 ; spearman. defb 30 ; archer. defb 50 ; swordsman. defb 40 ; mill. defb 40 ; kiln. defb 80 ; smithy. defb 40 ; harbour. defb 100 ; library. defb 60 ; market. ; Can't produce a unit for whatever reason so stop production for now. stprod call gcost ; get cost of production. ld (ix+7),a ; keep production until unit can be built. jp pcity3 ; process next city. ; Generate new settler. newu0 ld a,(ix+1) ; city size. and a ; less than 2? jr z,stprod ; can't build that unit yet. dec (ix+1) ; decrease population. call adjblk ; adjust city map block to reflect its size. newu1 ld c,(ix+6) ; unit type in c register. ld b,(ix) ; civilisation number in b. call putxy ; put x and y coords of city into dispx. call newun ; generate the new unit, doesn't corrupt ix. jp pcity1 ; job done, next city please. ; This routine places a city block on the map. ; Cities can be 1-16 in size and each civilisation has a set of its own. adjblk call mapadd ; get block here. ld a,(ix) ; civilisation number in accumulator. ld c,a ; leave a copy in c register. dec a ; start with black civilisation. rlca ; multiply by 16. rlca rlca rlca add a,CITY ; add on displacement for city. add a,(ix+1) ; add city size. ld (hl),a ; turn it into relevant city graphic. ret ; Map generation routines. ; gmap generates a block of grassland. gmap call random ; get random number in accumulator. and d ; no higher than this please. add a,c ; minimum size. ld (tempx),a ; that's our height then. call random ; random number. and d ; in range 0-15. add a,c ; minimum 8 chars, 8-23. ld (tempy),a ; block width. call random ; more randomness. and 63 ; block starts here. add a,e ; no higher than row 4. ld (dispx),a ; start of block. call random ; more randomness. and 63 ; block starts here. add a,e ; no further left than this column. ld (dispy),a ; start of block. ; Now fill a block of map with land. fland call mapadd ; get address of top left corner. ld a,(tempy) ; width. ld c,a ; put width in bc. ld b,0 ; no high byte needed as max is 96. dec bc ; subtract one. ld e,l ; copy hl to de. ld d,h inc de ; de is next byte. ex af,af' ; get terrain from alternate accumulator. ld (hl),a ; land square. ex af,af' ; store terrain again. ldir ; fill in a strip of land. ld hl,tempx ; height. dec (hl) ; decrement it. ret z ; job done. ld hl,dispx ; x coordinate. inc (hl) ; next strip down. jr fland ; repeat. ; set up coords and generate a block of arctic tundra. gmap3 call random ; get random number in accumulator. and 3 ; no higher than this please. add a,2 ; minimum size. ld (tempx),a ; that's our height then. call random ; random number. and 3 ; in range 0-15. add a,4 ; minimum 8 chars, 8-23. ld (tempy),a ; block width. call random ; more randomness. and 3 ; block starts here. add a,c ; no higher than row 2. ld (dispx),a ; start of block. call random ; more randomness. and 63 ; block starts here. add a,15 ; range 16-80. ld (dispy),a ; start of block. ld a,TUNDRA ; terrain type. ex af,af' ; set up parameter for fland routine. jr fland ; generate land mass. ; This routine centres the map on x and y coordinates of unit/city ix. cmapix ld hl,0 ; set coords as (0,0). ld a,(ix+2) ; unit x coord. sub 10 ; want unit half-way down if possible. jr c,cmapx0 ; that's past top of screen. cp 75 ; past bottom edge of screen? jr c,cmapx1 ; no, coord is valid. ld a,75 ; set x as low as we can. jr cmapx1 cmapx0 xor a ; set x as high up as we can. cmapx1 ld (winx),a ; set top of window. ld a,(ix+3) ; unit y coord. sub 15 ; want unit half-way across if possible. jr c,cmapy0 ; that's past left edge of screen. cp 64 ; past right edge of screen? jr c,cmapy1 ; no, coord is valid. ld a,64 ; set y furthest right we can. jr cmapy1 cmapy0 xor a ; set y as far left as we can. cmapy1 ld (winy),a ; set top of window. ; Display bit of map we're on. ; Screen is made up of 21 rows and 32 columns of character blocks, ; and map consists of a 96x96 grid. To find the address of the data ; for the bit we're showing we multiply the x displacement by 96 and ; add on the y coordinate. Normally we would achieve this with a few ; shifts and a couple of additions but for the sake of saving memory ; we'll have a simple addition loop. dmap ld hl,XORIG ; x and y at origin (3,0). ld (dispx),hl ; set cursor position. ld hl,map ; address of screens data. ld de,96 ; each line = 96 chars. ld a,(winx) ; x displacement. and a ; is it zero? jr z,dmap3 ; yes so we already have the correct address. dmap4 add hl,de ; next line. dec a ; one less line to skip. jr nz,dmap4 ; repeat. dmap3 ld a,(winy) ; y displacement. ld e,a ; put in de. add hl,de ; add to address. ; Right then, hl should now be pointing to our map block data. ld b,21 ; window is 21 rows high. dmap2 push bc ; push row counter. ld b,32 ; window is 32 columns wide. dmap1 push bc ; push column counter. push hl ; stack address of map data. call findsc ; find screen address at (dispx,dispy). ld a,(hl) ; get block number. push af ; store block number. rlca ; multiply by 8. rlca ; shift left 3 times rlca ; to achieve this. ld c,a ; remember result - we need it in a minute. and 7 ; 3 leftmost bits shifted into high byte. ld b,a ; want these in b register (high). ld a,c ; restore result of shifts. and 248 ; take the bits for the low byte this time. ld c,a ; put these in c, bc=a*8. ld hl,blkgfx ; address of block graphics. add hl,bc ; add bc to find address of block's graphic. call dchr ; display char. pop af ; restore block. ld hl,blcols ; block colours. ld e,a ; put block number in de. ld d,0 ; zero high byte. add hl,de ; address of block attributes. ex de,hl ; want it in de. call atadd ; address of character's attributes. ld a,(de) ; get block attributes. ld (hl),a ; place them on screen. ld hl,dispy ; current column. inc (hl) ; move display position 1 char right. pop hl ; restore address of room data. inc hl ; next byte of room data. pop bc ; pop column counter. djnz dmap1 ; next column. ld de,64 ; 96-32=64 columns to skip. add hl,de ; start of next row down. ld de,(dispx) ; row and column in de. inc e ; move 1 row down. ld d,0 ; start again at column 0. ld (dispx),de ; return new row and column positions. pop bc ; pop row counter. djnz dmap2 ; next row. ret ; Show combat strength. shocom ld hl,15744 ; address of ROM digit bitmaps 0-9. call addacc ; add a*8. call findsc ; return screen address in de. ; drop through into display char routine. ; Transfer char hl to screen position de. dchr ld b,8 ; 8 bytes per block. dchr0 ld a,(hl) ; block graphic data. ld (de),a ; transfer to screen. inc hl ; next byte to transfer. inc d ; next pixel line on screen. djnz dchr0 ; repeat for rest of character block. ret ; Map index. ; Get map address of block for unit/city in ix registers. mapix call putxy ; place the coordinates in dispx. jr mapadd ; find address and return block in accumulator. ; Look for a random point anywhere on map. ranmap call rand96 ; give us a random number in range 0-95. ld (dispx),a ; this is our x coord. call rand96 ; another random number 0-95. ld (dispy),a ; this is our y position. ; Now drop through to mapadd to find the character at this position. ; Calculate address of map position (dispx,dispy). ; Multiply x by 96 and add y. mapadd ld a,(dispx) ; x coordinate. rrca ; multiply by 32. rrca rrca ld d,a ; put result in d for now. and 224 ; mask bits for low byte. ld e,a ; low byte in e. ld a,d ; get result again. and 31 ; high byte mask. ld d,a ; one third of x displacement in de. ld hl,map ; address of map. add hl,de ; add 3 times as 3*32=96. add hl,de add hl,de ld a,(dispy) ; y coordinate. ld e,a ; want it in e. ld d,0 ; no high byte. add hl,de ; hl now points to map address. ld a,(hl) ; return map block in accumulator. ret ; Find screen address for character block at (dispx, dispy). findsc ld a,(dispx) ; x coordinate. ld e,a ; put it in e. and 24 ; which segment, 1 to 3? add a,64 ; 64*256=16384, start of Spectrum screen. ld d,a ; that's our high byte then. ld a,e ; get x again. and 7 ; which row within segment? rrca ; multiply row by 32. rrca rrca ld e,a ; low byte for x position. ld a,(dispy) ; y coordinate. add a,e ; add on y coordinate. ld e,a ; screen address in DE. ret ; Calculate address of attribute for character at (dispx, dispy). atadd ld a,(dispx) ; x position. rrca ; multiply by 32. rrca rrca ld l,a ; store away in l. and 3 ; mask bits for high byte. add a,88 ; 88*256=22528, start of attributes. ld h,a ; high byte done. ld a,l ; get x*32 again. and 224 ; mask low byte. ld l,a ; put in l. ld a,(dispy) ; get y displacement. add a,l ; add to low byte. ld l,a ; hl=address of attributes. ret ; Pseudo-random number generator. ; Steps a pointer through the ROM (held in seed), returning the contents ; of the byte at that location. random ld hl,(seed) ; Pointer ld a,h cp 58 ; Approaching end of "random" area? jr nc,rand0 ; Yes - reset pointer. ld a,(hl) ; Get "random" number from location. inc hl ; Increment pointer. ld (seed),hl ; remember new pointer. add a,l ; extra randomness. ret rand0 ld hl,0 ; Reset pointer. ld (seed),hl ret ; Give us a number from 0-95. rand96 call random ; random number generator. cp 96 ; is it too big? ret c ; no, it's below 96. jr rand96 ; find another one. ; Find difference between accumulator and byte at hl. fdiff sub (hl) ; do subtraction. ret nc ; result is positive so return. neg ; result negative, make it positive. ret ; Pause for one second. delay call 8015 ; blank keypress. ld bc,50 ; 50ths of a second. jp 7997 ; ROM routine to pause. ; Create a new unit of type C for civilisation B. newun xor a ; max number of units in play = 256. ld hl,units ; table of units. ld de,UNTSIZ ; size of unit table entry. newun0 ex af,af' ; store loop count. ld a,(hl) ; civilisation flag. and a ; is this unit on? jr z,newun1 ; no, create it. add hl,de ; get next unit entry in table. ex af,af' ; loop count. dec a ; decrement. jr nz,newun0 ; continue until space found in table. ; We won't bother error checking as it's unlikely we'll reach unit 256. ; If we drop through to here the unit will be generated but won't appear ; in the game. In practice this won't happen. newun1 ld (hl),b ; unit is for this civilisation. inc hl ; type flag. ld (hl),c ; set unit type. inc hl ; move on to x coordinate. ld a,(dispx) ; x axis where we generate unit. ld (hl),a ; set x position of unit. inc hl ; move on to y coordinate. ld a,(dispy) ; y axis where we generate unit. ld (hl),a ; set y position of unit. inc hl ; unit strength. ld (hl),5 ; start off at 5. ret ; Information and science screen. menu call 3503 ; ROM routine to clear the screen. ld de,mtxt0 ; text to display. ld bc,mtxt1-mtxt0 ; string length. call 8252 ; ask ROM to display string. ld bc,(money) ; get money in bc registers. call dispbc ; show number in bc. ; Display civilisation's total population. push ix ; store unit pointer. call dpop ; display population. pop ix ; restore unit pointer. ; Display zeroes after population and general menu text string. ld de,mtxt2 ; text to display. ld bc,mtxt3-mtxt2 ; string length. call 8252 ; ask ROM to display string. menu1 defb 1,8,16 call 3545 ; set print position. ld a,(expi) ; get infrastructure expenditure. call dispas ; show number in bc. defb 1,8,14 call 3545 ; set print position. ld a,(expm) ; get military research budget. call dispas ; show number in bc. defb 1,8,12 call 3545 ; set print position. ld a,(expc) ; get cultural advances budget. call dispas ; show number in bc. xor a ; zero accumulator. ld (23560),a ; clear last keypress. menu0 ld a,(23560) ; last key pressed. cp 13 ; was it the Enter key? jp z,mloop ; yes, go back to main game loop. cp 'o' ; O. jr z,menuo ; decrease infrastructure research. cp 'p' ; P. jr z,menup ; increase infrastructure research. cp 'k' ; K. jr z,menuk ; decrease military research. cp 'l' ; L. jr z,menul ; increase military research. cp 'n' ; N. jr z,menun ; decrease cultural research. cp 'm' ; M. jr z,menum ; increase cultural research. jr menu0 ; wait for input. ; Less/more research. menun ld hl,expc ; cultural research. jr menulr ; decrease wanted. menuk ld hl,expm ; military research. jr menulr ; decrease wanted. menuo ld hl,expi ; infrastructure research. menulr ld a,(hl) ; get amount. and a ; is it already at zero? jp z,menu0 ; reached minimum. dec (hl) ; the reduced R&D budget. jr menu1 ; redisplay all values. menum ld hl,expc ; cultural research. jr menumr ; increase wanted. menul ld hl,expm ; military research. jr menumr ; increase wanted. menup ld hl,expi ; infrastructure research. menumr ld a,(hl) ; amount currently paid. cp 99 ; already at 99? jp nc,menu0 ; reached maximum. inc (hl) ; new ticket price. jr menu1 ; redisplay all values. mtxt0 defb 22,1,1 defb 'Gold:' mtxt1 defb 22,1,13 defb 'Pop:' mtxt2 defb 22,8,1 defb ' Infra' defb 22,10,1 defb ' Military' defb 22,12,1 defb ' Culture' mtxt3 equ $ ; Display population. ; Find out size of cities belong to player and keep a running total of ; the population. This is shown on the science screen, then again as ; the final score at the end of the game. ; First, display the population text string. dpop ld de,mtxt1 ; text to display. ld bc,mtxt2-mtxt1 ; string length. call 8252 ; ask ROM to display string. ; Now work out the population and display it. ld bc,0 ; population in bc. ld ix,cities-CITSIZ ; address of all settlement data. dpop0 call fcity ; can we find a city? jr c,dpop1 ; no we can't. ld a,(ix) ; to which civilisation does this belong? cp 1 ; player's civilisation is always 1. jr nz,dpop0 ; doesn't belong to player, find another. ld l,(ix+1) ; size of city. inc l ; (ix+1) is always 1 less than actual city size. ld h,0 ; zero high byte. add hl,bc ; add to population so far. ld b,h ; copy h to b. ld c,l ; copy l to c, so bc = hl. jr dpop0 dpop1 call dispbc ; show number in bc. ld b,3 ; want three zeroes after. eotp0 ld a,48 ; ASCII zero char. rst 16 ; display it. djnz eotp0 ; repeat 3 times. ret ; Unit graphics. untgfx defb 88,152,252,154,154,152,152,188 ; settler. defb 32,96,96,96,96,32,255,126 ; trireme. defb 24,88,72,92,106,8,8,24 ; warrior. defb 152,216,72,88,40,40,24,24 ; spearman. defb 24,26,17,63,17,18,16,24 ; archer. defb 88,216,200,124,42,8,8,24 ; swordsman. ; Map block graphics. ; City blocks 10-16. c1016 defb 0,70,201,75,77,73,230,0,0,68,204,68,68,68,238,0 defb 0,78,209,65,78,80,255,0,0,78,209,70,65,81,238,0 defb 0,66,198,74,82,95,226,0,0,95,208,94,65,81,238,0 defb 0,78,208,94,81,81,238,0 ; General map graphics. mapgfx defb 0,16,122,254,122,16,0,0 ; fish. defb 0,0,0,0,0,0,0,0 ; land. defb 68,238,68,238,68,238,68,68 ; wheat. defb 8,42,28,107,28,8,8,8 ; forest. defb 0,0,0,28,34,65,0,0 ; hill. defb 0,0,0,0,0,0,0,0 ; tundra. defb 8,28,8,62,8,127,8,8 ; forest. defb 0,0,0,28,34,73,28,0 ; mine. mapcol defb 77 ; water. defb 78 ; fish. defb 32 ; grassland. defb 38 ; wheat. defb 32 ; forest. defb 33 ; hill. defb 120 ; tundra. defb 124 ; icy forest. defb 33 ; mine. lbyte equ $ ; Variables used in the game. blkgfx equ 32768 ; map block graphics. blcols equ blkgfx+(128*NUMCIV)+(mapcol-mapgfx) ; map block colours. expi equ blcols+((blcols-blkgfx)/8)+2 ; infrastructure expenditure. expm equ expi+2 ; military research expenditure. expc equ expm+2 ; cultural expenditure. scii equ expc+2 ; infrastructure science. scim equ scii+2 ; military science. scic equ scim+2 ; cultural science. money equ scic+2 ; money. dispx equ money+2 ; general purpose coordinates. dispy equ dispx+1 temp equ dispy+1 ; temporary store. tempx equ temp+2 ; temporary coordinates. tempy equ tempx+1 origx equ tempy+1 ; coordinates of original unit. winx equ origx+2 ; position of window on map. winy equ winx+1 seed equ winy+1 ; points to byte in ROM for random routine. year equ seed+2 ; current year. nosel equ year+2 mintrv equ nosel+1 ; distance to nearest city site. dist equ mintrv+1 ; distance to travel in current direction. direct equ dist+1 ; direction in which we are to move. tciv equ direct+1 ; temporary civilisation number. centx equ tciv+1 centy equ centx+1 showc equ centy+1 ; show combat flag, 0=yes. cpusci equ showc+1 ; science for CPU civilisations. cpuscm equ cpusci+2 cpuscc equ cpuscm+2 mapoff equ cpuscc+2 ; area above map. map equ mapoff+96 viewm equ map+MAPSIZ units equ viewm+MAPSIZ ; Unit data: ; ix+ 0 = civilisation 1-4, 0=no unit. ; ix+ 1 = unit type/flags. ; d0 = unit loaded (trireme). ; d2-d7 = unit type. ; ix+ 2 = x coordinate. ; ix+ 3 = y coordinate. ; ix+ 4 = strength. ; Now for the cities. cities equ units+(UNTSIZ*257) ; City data: ; ix+ 0 = civilisation 1-4, 0=no unit. ; ix+ 1 = city size. ; ix+ 2 = x coordinate. ; ix+ 3 = y coordinate. ; ix+ 4 = city food store. ; ix+ 5 = buildings. ; ix+ 6 = building underway. ; ix+ 7 = production spent so far. ; Last byte of RAM we're using. termin equ cities+(256*CITSIZ)