From 80cf3ddb03dcf7ef093ed93ad0e82894c83bd4a3 Mon Sep 17 00:00:00 2001 From: Martin Haye Date: Fri, 15 May 2015 08:19:18 -0700 Subject: [PATCH] Got triggers working right on 3D map, including multiple triggers per location. --- .../src/org/demo/PackPartitions.groovy | 26 +++-- Platform/Apple/virtual/src/core/mem.s | 33 +++++-- Platform/Apple/virtual/src/include/mem.i | 20 ++-- .../Apple/virtual/src/plasma/gameloop.pla | 59 +++++++---- Platform/Apple/virtual/src/raycast/render.s | 97 +++++++------------ Platform/Apple/virtual/src/tile/tile.s | 17 ++-- 6 files changed, 133 insertions(+), 119 deletions(-) diff --git a/Platform/Apple/tools/PackPartitions/src/org/demo/PackPartitions.groovy b/Platform/Apple/tools/PackPartitions/src/org/demo/PackPartitions.groovy index cbffa429..13968d2c 100644 --- a/Platform/Apple/tools/PackPartitions/src/org/demo/PackPartitions.groovy +++ b/Platform/Apple/tools/PackPartitions/src/org/demo/PackPartitions.groovy @@ -470,9 +470,9 @@ class PackPartitions def tile = (row && x < width) ? row[x] : null def flags = 0 if ([colNum, rowNum] in locationsWithTriggers) - flags |= 0x20 - if (tile?.@obstruction == 'true') flags |= 0x40 + if (tile?.@obstruction == 'true') + flags |= 0x80 buf.put((byte)((tile ? tileMap[tile.@id] : 0) | flags)) } } @@ -727,7 +727,7 @@ class PackPartitions // See if the set we're considering has room for all our tiles def inCommon = it.tileIds.intersect(tileIds) def together = it.tileIds + tileIds - if (together.size() <= 32 && inCommon.size() > bestCommon) { + if (together.size() <= 64 && inCommon.size() > bestCommon) { tileSet = it bestCommon = inCommon.size() } @@ -762,7 +762,7 @@ class PackPartitions def id = tile?.@id if (tile && !tileMap.containsKey(id)) { def num = tileMap.size()+1 - assert num < 32 : "Error: Only 31 kinds of tiles are allowed on any given map." + assert num < 64 : "Error: Only 63 kinds of tiles are allowed on any given map." tileMap[id] = num tiles[id].flip() // crazy stuff to append one buffer to another buf.put(tiles[id]) @@ -1748,7 +1748,9 @@ class PackPartitions y -= yRange[0] if (!triggers[y]) triggers[y] = [:] as TreeMap - triggers[y][x] = (idx+1) * 5 // address of function + if (!triggers[y][x]) + triggers[y][x] = [] + triggers[y][x].add((idx+1) * 5) // address of function } } } @@ -1767,10 +1769,16 @@ class PackPartitions // The table itself goes in the data segment. triggers.each { y, xs -> emitDataByte(y) - emitDataByte(2 + (xs.size() * 3)) // 2 bytes for y+off, plus 3 bytes per trigger (x, adrlo, adrhi) - xs.each { x, funcAddr -> - emitDataByte(x) - emitDataFixup(funcAddr) + def size = 2 // 2 bytes for y+off + xs.each { x, funcAddrs -> + size += funcAddrs.size() * 3 // plus 3 bytes per trigger (x, adrlo, adrhi) + } + emitDataByte(size) + xs.each { x, funcAddrs -> + funcAddrs.each { funcAddr -> + emitDataByte(x) + emitDataFixup(funcAddr) + } // Record a list of trigger locations for the caller's reference locationsWithTriggers << [x, y] } diff --git a/Platform/Apple/virtual/src/core/mem.s b/Platform/Apple/virtual/src/core/mem.s index 912ef259..9bb6529a 100644 --- a/Platform/Apple/virtual/src/core/mem.s +++ b/Platform/Apple/virtual/src/core/mem.s @@ -1906,14 +1906,16 @@ doAllFixups: !zone ; Utility routine for convenient assembly routines in PLASMA code. ; Params: Y=number of parameters passed from PLASMA routine ; 1. Save PLASMA's X register index to evalStk -; 2. Switch to ROM -; 3. Load the last parameter into A=lo, Y=hi -; 4. Run the calling routine (X still points into evalStk for add'l params if needed) -; 5. Switch back to LC RAM -; 6. Restore PLASMA's X register, and advance it over the parameter(s) -; 7. Store A=lo/Y=hi into PLASMA return value -; 8. Return to PLASMA +; 2. Verify X register is in the range 0-$10 +; 3. Switch to ROM +; 4. Load the *last* parameter into A=lo, Y=hi +; 5. Run the calling routine (X still points into evalStk for add'l params if needed) +; 6. Switch back to LC RAM +; 7. Restore PLASMA's X register, and advance it over the parameter(s) +; 8. Store A=lo/Y=hi into PLASMA return value +; 9. Return to PLASMA __asmPlasm: !zone + bit setROM ; switch to ROM pla ; save address of calling routine, so we can call it clc adc #1 @@ -1925,9 +1927,12 @@ __asmPlasm: !zone dey sty tmp txa -.add adc tmp + cpx #$11 + bcs .badx ; X must be in range 0..$10 +.add adc tmp ; carry cleared by cpx above pha ; and save that - bit setROM ; switch to ROM + cmp #$11 ; again, X must be in range 0..$10 + bcs .badx lda evalStkL,x ; get last param to A=lo ldy evalStkH,x ; ...Y=hi .jsr jsr $1111 ; call the routine to do work @@ -1940,6 +1945,16 @@ __asmPlasm: !zone tya sta evalStkH,x rts ; and return to PLASMA interpreter +.badx jsr crout ; X reg ran outside valid range. Print and abort. + lda #'X' + jsr cout + txa + jsr prbyte + jsr crout + ldx #<+ + ldy #>+ + jmp fatalError ++ !text $8D, "PLASMA x-reg out of range", 0 ;------------------------------------------------------------------------------ ; Segment tables diff --git a/Platform/Apple/virtual/src/include/mem.i b/Platform/Apple/virtual/src/include/mem.i index 2c38afc4..e99f887b 100644 --- a/Platform/Apple/virtual/src/include/mem.i +++ b/Platform/Apple/virtual/src/include/mem.i @@ -277,16 +277,16 @@ FATAL_ERROR = $1F ;------------------------------------------------------------------------------ ; Convenience for writing assembly routines in PLASMA source -; Macro param: number of parameters passed from PLASMA routine -; 1. Save PLASMA's X register index -; 2. Switch to ROM -; 3. Load the last parameter (if any) into A=lo, Y=hi -; 4. Run the calling routine (X still points into evalStk for add'l params if needed) -; 5. Switch back to LC RAM -; 6. Restore PLASMA's X register, and advance it over the parameter(s), leaving -; space for the return value. -; 7. Store A=lo/Y=hi into PLASMA return value -; 8. Return to PLASMA +; Macro param: number of parameters passed from PLASMA to the asm routine +; 1. Save PLASMA's X register index to evalStk +; 2. Verify X register is in the range 0-$10 +; 3. Switch to ROM +; 4. Load the *last* parameter into A=lo, Y=hi +; 5. Run the calling routine (X still points into evalStk for add'l params if needed) +; 6. Switch back to LC RAM +; 7. Restore PLASMA's X register, and advance it over the parameter(s) +; 8. Store A=lo/Y=hi into PLASMA return value +; 9. Return to PLASMA !macro asmPlasm nArgs { ldy #nArgs jsr _asmPlasm diff --git a/Platform/Apple/virtual/src/plasma/gameloop.pla b/Platform/Apple/virtual/src/plasma/gameloop.pla index b064ebc9..14002504 100644 --- a/Platform/Apple/virtual/src/plasma/gameloop.pla +++ b/Platform/Apple/virtual/src/plasma/gameloop.pla @@ -91,6 +91,7 @@ word triggerTbl byte redraw byte frameLoaded = 0 byte textDrawn = FALSE +byte needRender = FALSE word skyNum = 9 word groundNum = 10 @@ -125,30 +126,39 @@ end /////////////////////////////////////////////////////////////////////////////////////////////////// // API to call rendering engine (same API for raycaster and tile engine) asm initDisplay // params: mapNum, pMapData, x, y, dir + +asmPlasm 5 jmp $6000 end asm flipToPage1 // no params + +asmPlasm 0 jmp $6003 end asm getPos // params: @x, @y + +asmPlasm 2 jmp $6006 end asm setPos // params: x, y + +asmPlasm 2 jmp $6009 end asm getDir // no params; returns: dir (0-15) + +asmPlasm 0 jmp $600C end asm setDir // params: dir (0-15) + +asmPlasm 1 jmp $600F end asm advance // no params; return: 0 if same pos, 1 if new pos, 2 if new pos and scripted + +asmPlasm 0 jmp $6012 end asm setColor // params: slot (0=sky/1=ground), color (0-15) + +asmPlasm 2 jmp $6015 end asm render // no params + +asmPlasm 0 jmp $6018 end @@ -156,11 +166,9 @@ end // Simply retrieve the X register. Used to double-check that we're not leaking PLASMA eval // stack entries. asm getXReg + +asmPlasm 0 txa - dex ; make room for return value - sta evalStkL,x - lda #0 - sta evalStkH,x + ldy #0 rts end @@ -628,6 +636,7 @@ def initMap(x, y, dir) puts("Calling initDisplay.\n") initDisplay(mapNum, pMap, x, y, dir) puts("Back from initDisplay.\n") + needRender = FALSE end /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -700,12 +709,20 @@ end def moveForward() byte val val = advance() - printf1("advance returned %d\n", val) - if val > 0 and textDrawn + + // If not blocked, render at the new position. + if val > 0 + needRender = TRUE + fin + + // If we're on a new map tile, clear text from script(s) on the old tile. + if val >= 2 and textDrawn clearWindow() textDrawn = FALSE fin - if val == 2 + + // If there are script(s) on the new tile, run them. + if val == 3 checkScripts() fin end @@ -728,16 +745,14 @@ end // Turn left (3D mode) def rotateLeft() adjustDir(-1) - render() + needRender = TRUE end /////////////////////////////////////////////////////////////////////////////////////////////////// // Rotate to the right (3D mode) def rotateRight() adjustDir(1) - puts("About to call render.\n") - render() - puts("Back from render.\n") + needRender = TRUE end /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -788,7 +803,7 @@ def setMap(is3D, num, x, y, dir) end /////////////////////////////////////////////////////////////////////////////////////////////////// -def teleport() +def kbdTeleport() word x, y byte dir @@ -815,9 +830,11 @@ def teleport() end /////////////////////////////////////////////////////////////////////////////////////////////////// -def oldTeleport(x, y, dir) - printf3("Old teleport: x=%d y=%d dir=%d\n", x, y, dir) - puts("Doing nothing for now.\n") +def teleport(x, y, dir) + printf3("Teleport: x=%d y=%d dir=%d\n", x, y, dir) + setPos(x, y) + setDir(dir) + needRender = TRUE end /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -838,6 +855,10 @@ def kbdLoop() func = cmdTbl[key] if func; func(); fin fin + if needRender + render() + needRender = FALSE + fin loop end @@ -855,10 +876,8 @@ def setScriptInfo(mapName, trigTbl) setWindow1() //displayStr(mapName) - // Set up for drawing other script text. + // Back to the main text window. setWindow2() - clearWindow() - textDrawn = FALSE end /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -897,7 +916,7 @@ def initCmds() next // Commands common to both 2D and 3D - initCmd('T', @teleport) + initCmd('T', @kbdTeleport) // Commands handled differently in 3D vs 2D if mapIs3D @@ -987,7 +1006,7 @@ def setCallbacks() // $312 callbacks.18 = $4c - callbacks:19 = @oldTeleport + callbacks:19 = @teleport end /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Platform/Apple/virtual/src/raycast/render.s b/Platform/Apple/virtual/src/raycast/render.s index 7a75a894..44fcca00 100644 --- a/Platform/Apple/virtual/src/raycast/render.s +++ b/Platform/Apple/virtual/src/raycast/render.s @@ -1668,13 +1668,11 @@ calcMapOrigin: !zone ;------------------------------------------------------------------------------- ; Advance in current direction if not blocked. ; Params: none -; Return: 0 if same map tile; -; 1 if pos is on a new map tile; -; 2 if that new tile is also scripted +; Return: 0 if blocked; +; 1 if advanced but still within same map tile; +; 2 if pos is on a new map tile; +; 3 if that new tile is also scripted pl_advance: !zone - txa - pha ; save PLASMA eval stk pos - bit setROM ; switch out PLASMA while we work lda playerDir asl asl ; shift twice: each dir is 4 bytes in table @@ -1699,7 +1697,6 @@ pl_advance: !zone sta playerY lda playerY+1 pha - clc adc walkDirs+3,x sta playerY+1 @@ -1728,9 +1725,7 @@ pl_advance: !zone sta playerX ldy #0 beq .done -.ok ; Not blocked. Render at the new position - jsr renderFrame - ; See if we're in a new map tile. +.ok ; Not blocked. See if we're in a new map tile. pla eor playerY+1 sta tmp @@ -1741,39 +1736,26 @@ pl_advance: !zone tay pla tya - beq .done ; if not a new map tile, return zero - ; It is a new position. Is script hint set? + bne + + iny ; not a new map tile, return 1 + bne .done ; always taken ++ ; It is a new map tile. Is script hint set? ldy playerX+1 lda (pMap),y - ldy #1 ; ret val 1 = new blk but no script + ldy #2 ; ret val 2 = new blk but no script and #$20 ; map flag $20 is the script hint beq .done ; if not scripted, return one - iny ; else return 2 = new blk and a script -.done pla - tax ; restore PLASMA eval stk pos - dex ; make room for return value - tya ; retrieve ret value - sta evalStkL,x ; and store it - lda #0 - sta evalStkH,x ; hi byte of return is zero - bit setLcRW+lcBank2 ; switch PLASMA runtime back in - rts ; and return to PLASMA + iny ; else return 3 = new blk and a script +.done tya ; retrieve ret value + ldy #0 ; hi byte of ret is always 0 + rts ; all done ;------------------------------------------------------------------------------- ; Render at the current position and direction. ; Params: none ; Return: none pl_render: !zone - txa - pha ; save PLASMA eval stk pos - bit setROM ; switch out PLASMA while we work - jsr renderFrame - pla - tax ; restore PLASMA eval stk pos - jsr prbyte - jsr crout - bit setLcRW+lcBank2 ; switch PLASMA runtime back in - rts ; and return to PLASMA + jmp renderFrame ;------------------------------------------------------------------------------- ; Cast all the rays from the current player coord @@ -1934,12 +1916,16 @@ copyScreen: !zone ;------------------------------------------------------------------------------- ; Called by PLASMA code to get the position on the map. ; Parameters: @x, @y -; Returns: Nothing +; Returns: Nothing (but stores into the addressed variables) pl_getPos: !zone { lda playerY+1 + sec + sbc #1 ; adjust for border guards jsr .sto inx lda playerX+1 + sec + sbc #1 ; adjust for border guards ; Now fall thru, and exit with X incremented once (2 params - 1 return slot = 1) .sto ldy evalStkL,x sty pTmp @@ -1958,14 +1944,16 @@ pl_getPos: !zone { ; Parameters: x, y ; Returns: Nothing pl_setPos: !zone { - lda evalStkL,x + clc + adc #1 ; adjust for border guards sta playerY+1 lda evalStkL+1,x + clc + adc #1 ; adjust for border guards sta playerX+1 lda #$80 sta playerY sta playerX - inx ; 2 params - 1 ret = +1 rts } @@ -1975,10 +1963,7 @@ pl_setPos: !zone { ; Returns: Nothing pl_getDir: !zone { lda playerDir - dex - sta evalStkL,x - lda #0 - sta evalStkH,x + ldy #0 rts } @@ -1987,35 +1972,28 @@ pl_getDir: !zone { ; Parameters: dir (0-15) ; Returns: Nothing pl_setDir: !zone { - lda evalStkL,x and #15 sta playerDir - dex ; 0 param - 1 ret = -1 rts } ;------------------------------------------------------------------------------- pl_setColor: !zone - lda evalStkL,x ; color number - tay - lda skyGndTbl2,y - pha - lda skyGndTbl1,y - pha - lda evalStkH,x ; slot + and #15 + tay ; color number + lda evalStkL+1,x and #1 - asl - tay - pla - sta skyColorEven,y - pla - sta skyColorOdd,y - inx ; toss unused stack slot (parms=2, ret=1, diff=1) + tax ; slot + lda skyGndTbl1,y + sta skyColorEven,x + lda skyGndTbl2,y + sta skyColorOdd,x rts ;------------------------------------------------------------------------------- ; The real action pl_initMap: !zone + ; Figure out PLASMA stack for calling script init txa clc adc #5 ; 5 params @@ -2030,7 +2008,6 @@ pl_initMap: !zone inx jsr pl_setPos ; Proceed with loading - bit setROM ; switch out PLASMA runtime while we work jsr loadTextures jsr copyScreen lda tablesInitted @@ -2045,11 +2022,7 @@ pl_initMap: !zone sta tablesInitted jsr setExpansionCaller jsr graphInit - jsr renderFrame - bit setLcRW+lcBank2 ; switch PLASMA runtime back in - ldx plasmaStk ; restore PLASMA's eval stk pos - dex ; make room for dummy return (inc'd over params earlier) - rts + jmp renderFrame ; Following are log/pow lookup tables. For speed, align them on a page boundary. !align 255,0 diff --git a/Platform/Apple/virtual/src/tile/tile.s b/Platform/Apple/virtual/src/tile/tile.s index 9f7df09d..d2549c5a 100644 --- a/Platform/Apple/virtual/src/tile/tile.s +++ b/Platform/Apple/virtual/src/tile/tile.s @@ -220,10 +220,9 @@ LOAD_TILESET ;---------------------------------------------------------------------- ; >> GET TILE IN CARDINAL DIRECTION AND FLAGS ; (Returns Tile # in Y, Flags in A) -; Each tile in memory can be 0-32, the flags are the upper 3 bits -; 0 0 0 -; | | `- Visible obstruction (Can not see behind it) -; | `--- Boundary (Can not walk on it) +; Each tile in memory can be 0-63, the flags are the upper 2 bits +; 0 0 +; | `--- Obstructed / Boundary (Can not walk on it) ; `----- Script assigned, triggers script lookup ;---------------------------------------------------------------------- ; >> SET X,Y COORDINATES FOR VIEWPORT CENTER @@ -841,15 +840,16 @@ ROW_OFFSET = 3 LDA #>emptyTile+1 BNE .store_src ; always taken .not_empty - ; Calculate location of tile data == tile_base + (((tile & 31) - 1) * 32) + ; Calculate location of tile data == tile_base + (((tile & 63) - 1) * 32) LDY #0 STY TILE_SOURCE+1 - AND #31 + AND #63 SEC SBC #1 ; tile map is 1-based, tile set indexes are 0-based ASL ASL ASL + ROL TILE_SOURCE+1 ASL ROL TILE_SOURCE+1 ASL @@ -1289,8 +1289,7 @@ ADVANCE: !zone { JSR CALC LDA AVATAR_TILE ; get tile flags - AND #$40 ; obstructed? - BEQ + + BPL + ; no hi bit = not obstructed ; Player moved to an obstructed place. Undo! LDA AVATAR_DIR @@ -1314,7 +1313,7 @@ ADVANCE: !zone { BEQ .ret INY ; moved LDA AVATAR_TILE - AND #$20 ; check script flag + AND #$40 ; check script flag BEQ .ret INY ; moved and also new place is scripted .ret RTS