Merge branch 'ecs'
This commit is contained in:
commit
fa09db6026
|
@ -1,13 +1,13 @@
|
|||
*~
|
||||
node_modules
|
||||
./local/
|
||||
./tests_output/
|
||||
./test/output/
|
||||
/local/
|
||||
/tests_output/
|
||||
/test/output/
|
||||
.DS_Store
|
||||
./tmp/
|
||||
./web/
|
||||
./release/
|
||||
./gen/
|
||||
/tmp/
|
||||
/web/
|
||||
/release/
|
||||
/gen/
|
||||
config.js
|
||||
chromedriver.log
|
||||
nightwatch.conf.js
|
||||
|
|
|
@ -25,6 +25,8 @@ npm i
|
|||
npm run build
|
||||
```
|
||||
|
||||
To use GitHub integration locally, download the Firebase config file, e.g. https://8bitworkshop.com/v[version]/config.js
|
||||
|
||||
### Start Server
|
||||
|
||||
Start a web server on http://localhost:8000/ while TypeScript compiles in the background:
|
||||
|
@ -108,3 +110,4 @@ The IDE uses custom forks for many of these, found at https://github.com/sehugg?
|
|||
* https://github.com/sehugg/8bitworkshop-compilers
|
||||
* https://github.com/sehugg/8bit-tools
|
||||
* https://github.com/sehugg/awesome-8bitgamedev
|
||||
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# Kernel
|
||||
# A Kernel draws a set of scanlines to the screen.
|
||||
|
||||
component Kernel
|
||||
lines: 0..255 "Height of region in scanlines"
|
||||
bgcolor: 0..255 "Background color"
|
||||
end
|
||||
|
||||
system SimpleKernel
|
||||
tempbytes 8
|
||||
on preframe do once [Kernel] ---
|
||||
lda #192 ; TODO: numlines
|
||||
sec
|
||||
sbc ypos_ypos_b0+ent
|
||||
sta {{$5}}+ofs
|
||||
|
||||
ldy hasbitmap_bitmap_b0+ent
|
||||
lda bitmap_bitmapdata_b0,y
|
||||
sec
|
||||
sbc {{$5}}+ofs
|
||||
sta {{$0}}+ofs
|
||||
lda bitmap_bitmapdata_b8,y
|
||||
sbc #0
|
||||
sta {{$1}}+ofs
|
||||
|
||||
ldy hascolormap_colormap_b0+ent
|
||||
lda colormap_colormapdata_b0,y
|
||||
sec
|
||||
sbc {{$5}}+ofs
|
||||
sta {{$2}}+ofs
|
||||
lda colormap_colormapdata_b8,y
|
||||
sbc #0
|
||||
sta {{$3}}+ofs
|
||||
|
||||
lda sprite_height_b0+ent
|
||||
sta {{$4}}+ofs
|
||||
lda ypos_ypos_b0+ent
|
||||
sta {{$5}}+ofs
|
||||
---
|
||||
on preframe do once [Sprite,HasBitmap,HasColormap,HasYpos] --
|
||||
{{@KernelSetup}} 0,0
|
||||
{{@KernelSetup}} 1,6
|
||||
--
|
||||
on kernel do once [Kernel]:
|
||||
lda %{<bgcolor}
|
||||
sta COLUBK
|
||||
ldy %{<lines}
|
||||
@LVScan:
|
||||
lda %{$4} ; height
|
||||
dcp %{$5}
|
||||
bcs @DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw1:
|
||||
lda (%{$0}),y
|
||||
sta WSYNC
|
||||
sta GRP0
|
||||
lda (%{$2}),y
|
||||
sta COLUP0
|
||||
|
||||
lda %{$10} ; height
|
||||
dcp %{$11}
|
||||
bcs @DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw2:
|
||||
lda (%{$6}),y
|
||||
sta GRP1
|
||||
lda (%{$8}),y
|
||||
sta COLUP1
|
||||
|
||||
dey ; decrement
|
||||
bne @LVScan ; repeat until 192 lines
|
||||
--
|
||||
end
|
||||
|
||||
scope Root
|
||||
|
||||
entity kernel [SimpleKernel]
|
||||
const lines = 100
|
||||
end
|
||||
|
||||
entity player1 [Sprite,HasBitmap,HasColormap,HasYpos]
|
||||
const plyrindex = 0
|
||||
init height = 8
|
||||
init xpos = 100
|
||||
init ypos = 100
|
||||
end
|
||||
|
||||
end scope
|
|
@ -542,6 +542,7 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
|
|||
<script src="src/codemirror/basic.js"></script>
|
||||
<script src="src/codemirror/wiz.js"></script>
|
||||
<script src="src/codemirror/vasm.js"></script>
|
||||
<script src="src/codemirror/ecs.js"></script>
|
||||
<link rel="stylesheet" href="css/codemirror.css">
|
||||
<script src="codemirror/addon/edit/matchbrackets.js"></script>
|
||||
<script src="codemirror/addon/search/search.js"></script>
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,6 +12,7 @@
|
|||
"dependencies": {
|
||||
"@types/chroma-js": "^2.1.3",
|
||||
"@types/emscripten": "^1.39.5",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"@wasmer/wasi": "^0.12.0",
|
||||
"@wasmer/wasmfs": "^0.12.0",
|
||||
"binaryen": "^101.0.0",
|
||||
|
@ -32,8 +33,10 @@
|
|||
"devDependencies": {
|
||||
"@types/bootbox": "^5.1.3",
|
||||
"@types/bootstrap": "^3.4.0",
|
||||
"@types/expect": "^24.3.0",
|
||||
"@types/file-saver": "^2.0.3",
|
||||
"@types/jquery": "^3.5.5",
|
||||
"@types/mocha": "^9.1.0",
|
||||
"@types/node": "^14.14.20",
|
||||
"atob": "^2.1.x",
|
||||
"bootstrap": "^3.4.1",
|
||||
|
@ -66,8 +69,8 @@
|
|||
"esbuild-worker": "esbuild src/worker/workermain.ts --bundle --sourcemap --target=es2017 --outfile=./gen/worker/bundle.js",
|
||||
"esbuild-ui": "esbuild src/ide/ui.ts src/ide/embedui.ts --splitting --format=esm --bundle --minify --sourcemap --target=es2017 --outdir=./gen/ --external:path --external:fs",
|
||||
"test-one": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000",
|
||||
"test-node": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 test/cli",
|
||||
"test-profile": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 --prof test/cli",
|
||||
"test-node": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 test/cli gen/test",
|
||||
"test-profile": "NODE_PATH=$(pwd) mocha --recursive --timeout 60000 --prof test/cli gen/test",
|
||||
"test-worker": "NODE_PATH=$(pwd) mocha --timeout 60000 test/cli/testworker.js",
|
||||
"test-platforms": "NODE_PATH=$(pwd) mocha --timeout 60000 test/cli/testplatforms.js",
|
||||
"test-verilog": "NODE_PATH=$(pwd) mocha --timeout 60000 --reporter mocha-simple-html-reporter --reporter-options output=test/output/verilog.html test/verilog/testverilog.js",
|
||||
|
|
|
@ -0,0 +1,687 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
import "score.ecs"
|
||||
import "sound.ecs"
|
||||
import "velocity.ecs"
|
||||
import "kernel2.ecs"
|
||||
import "random.ecs"
|
||||
import "versatile.ecs"
|
||||
import "music.ecs"
|
||||
|
||||
// TODO: not yet used
|
||||
component Activity
|
||||
activity: enum [Standing,Walking,Jumping]
|
||||
end
|
||||
|
||||
component Enemy
|
||||
end
|
||||
|
||||
component Gravity
|
||||
end
|
||||
|
||||
component Jumper
|
||||
end
|
||||
|
||||
system MoveJoyVel
|
||||
// dampen velocity
|
||||
on frame8 do with [HasXpos]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
lsr
|
||||
clc
|
||||
adc #4
|
||||
sta {{<xvel}}
|
||||
---
|
||||
// move left and right
|
||||
on joyleft do with [HasXpos]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
sec
|
||||
sbc #1
|
||||
cmp #2
|
||||
bcc @nomove
|
||||
sta {{<xvel}}
|
||||
@nomove:
|
||||
---
|
||||
on joyright do with [HasXpos]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #14
|
||||
bcs @nomove
|
||||
sta {{<xvel}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system Gravity
|
||||
on frame8 do foreach [Gravity]
|
||||
---
|
||||
lda {{get bitmap}}
|
||||
cmp #{{&DudeStanding1}}-{{&Blank}}+1
|
||||
bcc @skip
|
||||
lda {{<yvel}}
|
||||
cmp #14
|
||||
bcs @nofall
|
||||
clc
|
||||
adc #2
|
||||
bne @done
|
||||
@nofall:
|
||||
lda #15
|
||||
@done:
|
||||
sta {{<yvel}}
|
||||
@skip:
|
||||
---
|
||||
on xmoved do with [TinyVelY]
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #7
|
||||
bcc @nodown
|
||||
{{!checkplatform}}
|
||||
@nodown:
|
||||
---
|
||||
on ymoved do with [TinyVelY]
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #7
|
||||
bcc @nodown
|
||||
{{!checkplatform}}
|
||||
@nodown:
|
||||
---
|
||||
on joybutton do with [Player]
|
||||
---
|
||||
; TODO
|
||||
lda {{get bitmap}}
|
||||
cmp #{{&DudeStanding1}}-{{&Blank}}+1
|
||||
bcs @nojump
|
||||
lda #0
|
||||
sta {{get yvel}}
|
||||
lda #{{&DudeJumping1}}-{{&Blank}}
|
||||
sta {{set bitmap}}
|
||||
{{!playsound 0 1 5}}
|
||||
@nojump:
|
||||
---
|
||||
end
|
||||
|
||||
system PlatformJumper
|
||||
on platformstopped do with [Jumper]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
and #$fe
|
||||
sta {{<ypos}}
|
||||
---
|
||||
on platformstopped do if [Player]
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #8
|
||||
beq @skip
|
||||
lda #8
|
||||
sta {{<yvel}}
|
||||
lda #{{&DudeStanding1}}-{{&Blank}}
|
||||
sta {{set bitmap}}
|
||||
{{!playsound 0 2 5}}
|
||||
@skip:
|
||||
---
|
||||
on platformnotstopped do if [Player]
|
||||
---
|
||||
lda #{{&DudeJumping1}}-{{&Blank}}
|
||||
sta {{set bitmap}}
|
||||
---
|
||||
end
|
||||
|
||||
resource PFCollideMask ---
|
||||
.byte $10,$20,$40,$80 ; PF0
|
||||
.byte $80,$40,$20,$10,$08,$04,$02,$01 ; PF1
|
||||
.byte $01,$02,$04,$08,$10,$20,$40,$80 ; PF2
|
||||
.byte $80,$40,$20,$10,$08,$04,$02,$01 ; PF2
|
||||
.byte $01,$02,$04,$08,$10,$20,$40,$80 ; PF1
|
||||
.byte $80,$40,$20,$10 ; PF0
|
||||
---
|
||||
resource PFCollideReg ---
|
||||
.byte $d,$d,$d,$d
|
||||
.byte $e,$e,$e,$e,$e,$e,$e,$e
|
||||
.byte $f,$f,$f,$f,$f,$f,$f,$f
|
||||
.byte $f,$f,$f,$f,$f,$f,$f,$f
|
||||
.byte $e,$e,$e,$e,$e,$e,$e,$e
|
||||
.byte $d,$d,$d,$d
|
||||
---
|
||||
|
||||
|
||||
system EnemyMotion
|
||||
on stopped do if [Enemy]
|
||||
---
|
||||
lda #5
|
||||
sta {{<yvel}}
|
||||
---
|
||||
on frame16 do foreach [Enemy]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
adc {{<Les.xpos}}
|
||||
and #15
|
||||
sta {{<xvel}}
|
||||
---
|
||||
end
|
||||
|
||||
system EnemyCollider
|
||||
on preframe do once
|
||||
---
|
||||
sta CXCLR
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
lda CXPPMM
|
||||
bpl @nocollide
|
||||
{{!enemyspawn}}
|
||||
@nocollide:
|
||||
---
|
||||
on enemyspawn do once
|
||||
---
|
||||
{{!nextrand8}}
|
||||
and #$e0
|
||||
clc
|
||||
adc {{get Les.xpos}}
|
||||
and #$7f
|
||||
clc
|
||||
adc #10
|
||||
sta {{set Rock.xpos}}
|
||||
|
||||
{{!nextrand8}}
|
||||
and #$20
|
||||
clc
|
||||
adc {{get Les.ypos}}
|
||||
and #$7f
|
||||
clc
|
||||
adc #24
|
||||
sta {{set Rock.ypos}}
|
||||
|
||||
; TODO:
|
||||
;inc {{set Rock.bitmap}}
|
||||
---
|
||||
end
|
||||
|
||||
system EnemyDifficulty
|
||||
locals 1
|
||||
on preframe do foreach [Enemy]
|
||||
---
|
||||
{{!nextrand8}}
|
||||
lsr
|
||||
lsr
|
||||
cmp {{get PlayerScore.digits}}
|
||||
bcs @nomove
|
||||
; run away from player
|
||||
lda {{get xpos}}
|
||||
cmp #2
|
||||
bcc @nox
|
||||
cmp #140
|
||||
bcs @nox
|
||||
sec
|
||||
sbc {{get Les.xpos}}
|
||||
bcc @xdec
|
||||
inc {{set xpos}}
|
||||
inc {{set xpos}}
|
||||
@xdec:
|
||||
dec {{set xpos}}
|
||||
@nox:
|
||||
; move Y a bit
|
||||
lda {{get ypos}}
|
||||
cmp #40
|
||||
bcc @nomove
|
||||
cmp #170
|
||||
bcs @nomove
|
||||
sec
|
||||
sbc {{get Les.ypos}}
|
||||
bcc @ydec
|
||||
inc {{set ypos}}
|
||||
inc {{set ypos}}
|
||||
@ydec:
|
||||
dec {{set ypos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
//
|
||||
|
||||
scope Main
|
||||
|
||||
using FrameLoop, ResetConsole
|
||||
using Kernel2Digit, BCDMath
|
||||
using Kernel2Sprite
|
||||
using SetXPos, SetHorizPos
|
||||
using TinyMover
|
||||
using Gravity
|
||||
using VersatilePlayfield
|
||||
using PlatformJumper
|
||||
|
||||
using FrameCounter
|
||||
entity FrameCount [FrameCount]
|
||||
end
|
||||
|
||||
// TODO: this has to be after FrameCounter
|
||||
// for velocity damping to work correctly
|
||||
// but "after" keyword might be better
|
||||
using Joystick, JoyButton, MoveJoyVel with [Player]
|
||||
|
||||
using EnemyCollider
|
||||
using EnemyDifficulty
|
||||
|
||||
entity Level1 [VersatilePlayfield]
|
||||
decode vcs_versatile
|
||||
---
|
||||
.................... .. .. ..
|
||||
.................... .. .. 01
|
||||
.................... e8 .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
............xxx..... .. .. ..
|
||||
.............x...... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.........xxx........ .. .. ..
|
||||
..........xx........ .. .. ..
|
||||
...........x........ .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 18 .. ..
|
||||
.................... .. .. ..
|
||||
xxxx................ .. .. ..
|
||||
xxx................. .. .. ..
|
||||
xx.................. .. .. ..
|
||||
x................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 28 .. ..
|
||||
.................... .. .. ..
|
||||
....xxxxxx.......... .. .. ..
|
||||
......xxxx.......... .. .. ..
|
||||
........x........... .. .. ..
|
||||
.................... .. .. ..
|
||||
............xxx..... .. .. ..
|
||||
.............xx..xxx .. .. ..
|
||||
..............x...xx .. .. ..
|
||||
..................xx .. .. ..
|
||||
...................x .. .. ..
|
||||
...................x .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 38 .. ..
|
||||
.....xxxx........... .. .. ..
|
||||
......xxx........... .. .. ..
|
||||
.......xx........... .. .. ..
|
||||
........x........... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 48 .. ..
|
||||
............xxx..... .. .. ..
|
||||
.............xx..... .. .. ..
|
||||
..............x..... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 58 .. ..
|
||||
..................xx .. .. ..
|
||||
.................xxx .. .. ..
|
||||
................xxxx .. .. ..
|
||||
..................xx .. .. ..
|
||||
...................x .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. 82 ..
|
||||
.................... .. .. ..
|
||||
.................... .. 84 ..
|
||||
.................... .. .. ..
|
||||
.................... .. 86 ..
|
||||
.................... .. .. ..
|
||||
.................... 68 .. ..
|
||||
............xxxxxx.. .. .. ..
|
||||
............xxxxxx.. .. .. ..
|
||||
--- end
|
||||
|
||||
entity Blank [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
........ 00
|
||||
---
|
||||
end
|
||||
entity DudeStanding1 [Bitmap,Colormap,Activity]
|
||||
const activity = Standing
|
||||
decode vcs_sprite
|
||||
---
|
||||
..xxx... f8
|
||||
.xxxxx.. f8
|
||||
x.xxxx.. f8
|
||||
.xxx.x.. f8
|
||||
x.xxxxx. f8
|
||||
x.xxxx.. f8
|
||||
..xx.... f8
|
||||
..xxxx.. f8
|
||||
...xxx.. f8
|
||||
...xx... f8
|
||||
...xx... f8
|
||||
..xxx... 38
|
||||
..xxx... 48
|
||||
.x.xxx.. 58
|
||||
x..xxx.. 68
|
||||
x..xx.x. 78
|
||||
x..xx..x 88
|
||||
...xxx.. 98
|
||||
..xxxx.. 98
|
||||
..x..x.. 98
|
||||
..x..xx. 98
|
||||
.xx...x. 98
|
||||
.x....x. 98
|
||||
.x....x. f8
|
||||
xx....xx f8
|
||||
---
|
||||
end
|
||||
entity DudeJumping1 [Bitmap,Colormap,Activity]
|
||||
const activity = Jumping
|
||||
const colormapdata = DudeStanding1.colormapdata
|
||||
decode vcs_bitmap
|
||||
---
|
||||
x.xxx...
|
||||
.xxxxx..
|
||||
x.xxxx..
|
||||
.xxx.x..
|
||||
..xxxxx.
|
||||
..xxxx..
|
||||
..xx....
|
||||
..xxx...
|
||||
...xxx..
|
||||
...xx...
|
||||
x..xx...
|
||||
x.xxx..x
|
||||
x.xxx.x.
|
||||
.x.xxx..
|
||||
...xx...
|
||||
...xx...
|
||||
...xx...
|
||||
...xxx..
|
||||
..xxxx..
|
||||
.xx..xx.
|
||||
.x....x.
|
||||
.x....x.
|
||||
.x....x.
|
||||
.x....x.
|
||||
xx....xx
|
||||
---
|
||||
end
|
||||
|
||||
entity Coin1 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
00001000 ca
|
||||
01001001 dc
|
||||
00100010 ee
|
||||
00000000 0e
|
||||
00011110 0e
|
||||
00100011 ee
|
||||
01000101 ee
|
||||
10001001 ee
|
||||
11111001 ee
|
||||
11101001 ee
|
||||
11011001 ee
|
||||
11111001 dc
|
||||
11111001 ca
|
||||
11011010 ca
|
||||
10111100 ca
|
||||
01111000 ca
|
||||
---
|
||||
end
|
||||
entity Coin2 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
..xxxx.. ca
|
||||
.xxxxxx. dc
|
||||
xxxxxxxx ee
|
||||
x..xx..x 0e
|
||||
xx.xx.xx 0e
|
||||
xxxxxxxx ee
|
||||
xxxxxxxx ee
|
||||
.xx..xx. ee
|
||||
.xxxxxx. ee
|
||||
.xx..xx. ee
|
||||
..xxxx.. dc
|
||||
...xx... ca
|
||||
........ ca
|
||||
---
|
||||
end
|
||||
|
||||
entity Empty [Sprite,HasBitmap,HasColormap]
|
||||
const bitmap = #Blank
|
||||
const colormap = #Blank
|
||||
end
|
||||
|
||||
entity Les [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,TinyVelX,TinyVelY,Player,Jumper,Gravity]
|
||||
var xpos = 73
|
||||
var ypos = 90
|
||||
var bitmap = #DudeJumping1
|
||||
const colormap = #DudeStanding1
|
||||
var plyrflags = $00
|
||||
var xvel = 8
|
||||
var yvel = 7
|
||||
end
|
||||
|
||||
entity Rock [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Enemy]
|
||||
var bitmap = #Coin1
|
||||
const colormap = #Coin1
|
||||
var xpos = 73
|
||||
var ypos = 140
|
||||
end
|
||||
|
||||
entity PlayerScore [BCDScore2]
|
||||
var scorecolor = $ca
|
||||
end
|
||||
entity TimerScore [BCDScore2]
|
||||
var scorecolor = $0e
|
||||
var digits = $00
|
||||
end
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 174
|
||||
var bgcolor = $80
|
||||
end
|
||||
|
||||
entity Slot0 [SpriteSlot]
|
||||
var sprite = #Les
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
var sprite = #Rock
|
||||
end
|
||||
|
||||
// SOUNDS
|
||||
|
||||
using SoundEngine
|
||||
|
||||
entity SFXNull [SoundEffect]
|
||||
const duration = 0
|
||||
const sounddata = [0]
|
||||
end
|
||||
entity SFXJump [SoundEffect]
|
||||
const duration = 14
|
||||
const sounddata = [
|
||||
$81,$83,$85,
|
||||
$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,
|
||||
$a8]
|
||||
end
|
||||
entity SFXBounce [SoundEffect]
|
||||
const duration = 10
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$40,$20,$10,
|
||||
$a4]
|
||||
end
|
||||
entity SFXScore [SoundEffect]
|
||||
const duration = 11
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$10,$20,$10,$08,
|
||||
$a2]
|
||||
end
|
||||
entity SFXScore2 [SoundEffect]
|
||||
const duration = 11
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$10,$20,$10,$08,
|
||||
$a8]
|
||||
end
|
||||
|
||||
// TODO: make sfx have priority over music?
|
||||
entity SFX1 [SoundChannel] end
|
||||
entity SFX2 [SoundChannel] end
|
||||
|
||||
// MUSIC
|
||||
|
||||
using MusicPlayer
|
||||
entity MusicPlayer [MusicPlayer]
|
||||
const volume = 10
|
||||
const tempo = 31
|
||||
end
|
||||
entity Music1 [MusicChannel] end
|
||||
entity Music2 [MusicChannel] end
|
||||
|
||||
//
|
||||
|
||||
using Random
|
||||
system GameManager
|
||||
// start the game? set timer to 99
|
||||
// but only if timer = 0 and score = 0
|
||||
on joybutton do select [#TimerScore]
|
||||
---
|
||||
lda {{<digits}}
|
||||
bne @skip
|
||||
lda {{<PlayerScore.digits}}
|
||||
bne @skip
|
||||
lda #$99
|
||||
sta {{<digits}}
|
||||
@skip:
|
||||
---
|
||||
// decrease the timer every 16 frames
|
||||
on frame16 do foreach [#TimerScore]
|
||||
---
|
||||
lda {{<digits}}
|
||||
beq @done
|
||||
{{!SubBCD2 1}}
|
||||
lda {{<digits}}
|
||||
bne @done
|
||||
{{!timerexpired}}
|
||||
@done:
|
||||
---
|
||||
// add score for each new spawn
|
||||
on enemyspawn do begin
|
||||
foreach [#PlayerScore]
|
||||
---
|
||||
{{!AddBCD2 1}}
|
||||
{{!playsound 1 3 10}}
|
||||
---
|
||||
// add timer for each new spawn
|
||||
foreach [#TimerScore]
|
||||
---
|
||||
{{!AddBCD2 10}}
|
||||
---
|
||||
end
|
||||
// subtract one when player wraps around vertically
|
||||
on ymoved do begin
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #7
|
||||
bcc @nowrap
|
||||
lda {{<ypos}}
|
||||
cmp #2
|
||||
bcs @nowrap
|
||||
{{!playerwrapped}}
|
||||
inc {{set ypos}}
|
||||
@nowrap:
|
||||
---
|
||||
end
|
||||
// TODO: doesn't work yet
|
||||
on playerwrapped do with [#PlayerScore]
|
||||
---
|
||||
{{!SubBCD2 1}}
|
||||
---
|
||||
// each frame, game is either running or stopped
|
||||
on preframe do once
|
||||
---
|
||||
lda {{<TimerScore.digits}}
|
||||
bne @gameon
|
||||
{{!gamestopped}}
|
||||
jmp @done
|
||||
@gameon:
|
||||
{{!gamerunning}}
|
||||
@done:
|
||||
---
|
||||
// stop everything when game is stopped
|
||||
// TODO: if "Sprite" it overwrites array elements
|
||||
on gamestopped do foreach [TinyVelX,TinyVelY]
|
||||
// on gamestopped do foreach [Sprite]
|
||||
---
|
||||
lda #8
|
||||
sta {{set xvel}}
|
||||
sta {{set yvel}}
|
||||
---
|
||||
// set colors when game is stopped
|
||||
on gamestopped do once
|
||||
---
|
||||
lda #$4c
|
||||
sta {{set TimerScore.scorecolor}}
|
||||
lda #$02
|
||||
sta {{set Kernel.bgcolor}}
|
||||
---
|
||||
// set colors when game is running
|
||||
on gamerunning do once
|
||||
---
|
||||
lda #$0a
|
||||
sta {{set TimerScore.scorecolor}}
|
||||
lda #$80
|
||||
sta {{set Kernel.bgcolor}}
|
||||
; blink when timer is close to zero
|
||||
lda {{get TimerScore.digits}}
|
||||
cmp #$20
|
||||
bcs @nocolor
|
||||
lda {{get FrameCount:frame}}
|
||||
lsr
|
||||
lsr
|
||||
and #$07
|
||||
ora #$40
|
||||
sta {{set Kernel.bgcolor}}
|
||||
@nocolor:
|
||||
---
|
||||
// play music when timer expires
|
||||
on timerexpired do once
|
||||
---
|
||||
;{{^SampleMusic}}
|
||||
{{!playmusic SampleMusic}}
|
||||
---
|
||||
on xxx_preframeloop do once
|
||||
---
|
||||
;{{^IntroMusic}}
|
||||
{{!playmusic IntroMusic}}
|
||||
---
|
||||
end
|
||||
|
||||
entity [Random8] end
|
||||
end
|
||||
|
||||
// TODO: use byte array too?
|
||||
resource IntroMusic ---
|
||||
.byte $27,$90,$2c,$8f,$2f,$8f,$33,$8f,$38,$8f,$3b,$8f,$20,$23,$88,$3a,$83,$38,$82,$37,$83,$38,$20,$ff
|
||||
---
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
|
||||
system Kernel2Sprite
|
||||
locals 13
|
||||
on preframe do with [KernelSection]
|
||||
---
|
||||
; TODOO: can store KLINES in memory?
|
||||
.define KLINES {{<lines}}
|
||||
.define KPAD 32
|
||||
; set height to zero in case no sprites
|
||||
lda #0
|
||||
sta {{$8}}
|
||||
sta {{$9}}
|
||||
---
|
||||
on preframe do join
|
||||
[SpriteSlot] with
|
||||
[Sprite] limit 2
|
||||
---
|
||||
; set player object flags
|
||||
lda {{<plyrflags}}
|
||||
sta NUSIZ0,y
|
||||
sta REFP0,y
|
||||
; calculate screen height - ypos
|
||||
lda KLINES
|
||||
clc
|
||||
adc KPAD
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$11}}
|
||||
; calculate bitmap pointer
|
||||
stx {{$12}} ; save X (Sprite index)
|
||||
lda {{<bitmap}} ; deref bitmap
|
||||
tax
|
||||
lda {{<Bitmap:bitmapdata}},x
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$0}},y ; Y = sprite slot index
|
||||
lda {{>Bitmap:bitmapdata}},x
|
||||
sbc #0
|
||||
sta {{$2}},y
|
||||
; get bitmap height
|
||||
lda {{<Bitmap:height}},x
|
||||
sta {{$8}},y
|
||||
; calculate colormap pointer
|
||||
ldx {{$12}} ; restore X
|
||||
lda {{<colormap}} ; deref colormap
|
||||
tax
|
||||
lda {{<Colormap:colormapdata}},x
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$4}},y
|
||||
lda {{>Colormap:colormapdata}},x
|
||||
sbc #0
|
||||
sta {{$6}},y
|
||||
; save ypos
|
||||
ldx {{$12}} ; restore X
|
||||
lda {{<ypos}}
|
||||
sta {{$10}},y
|
||||
---
|
||||
on preframe do once
|
||||
---
|
||||
; shuffle pointers into (MSB, LSB) byte order
|
||||
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||
lda {{$1}}
|
||||
ldy {{$2}}
|
||||
sty {{$1}}
|
||||
sta {{$2}}
|
||||
lda {{$5}}
|
||||
ldy {{$6}}
|
||||
sty {{$5}}
|
||||
sta {{$6}}
|
||||
---
|
||||
on preframe do if [KernelSection,BGColor]
|
||||
---
|
||||
lda {{<bgcolor}}
|
||||
sta COLUBK
|
||||
---
|
||||
on preframe do if [Missile,HasYpos]
|
||||
---
|
||||
lda KLINES
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$12}}
|
||||
---
|
||||
on kernel do with [KernelSection]
|
||||
---
|
||||
ldy #0
|
||||
sty VDELP0
|
||||
iny
|
||||
sty VDELP1
|
||||
---
|
||||
on kernel do critical with [KernelSection]
|
||||
---
|
||||
ldy {{<lines}}
|
||||
@LVScan:
|
||||
{{!scanline 0}}
|
||||
dey ; next scanline
|
||||
{{!scanline 1}}
|
||||
dey ; next scanline
|
||||
bne @LVScan ; repeat until out of lines
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
; draw player 0
|
||||
lda {{$8}} ; height
|
||||
dcp {{$10}} ; ypos
|
||||
bcs @DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw1:
|
||||
lda ({{$0}}),y
|
||||
; .if {{#0}} = 0 ; TODO: configurable?
|
||||
sta WSYNC
|
||||
; .endif
|
||||
sta GRP0
|
||||
lda ({{$4}}),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda {{$9}} ; height
|
||||
dcp {{$11}} ; ypos
|
||||
bcs @DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw2:
|
||||
lda ({{$2}}),y
|
||||
sta GRP1
|
||||
lda ({{$6}}),y
|
||||
sta COLUP1
|
||||
---
|
||||
on kernel do once
|
||||
---
|
||||
lda #0
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
---
|
||||
on scanline do if [Missile,HasYpos]
|
||||
---
|
||||
cpy {{$12}}
|
||||
php
|
||||
pla
|
||||
sta ENAM0
|
||||
---
|
||||
end
|
||||
|
||||
///
|
||||
|
||||
demo Main
|
||||
|
||||
using FrameLoop, Kernel2Sprite
|
||||
using Joystick, MoveJoyX, MoveJoyY
|
||||
using SetXPos, SetHorizPos
|
||||
using SpriteShuffler, SpriteHider
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 192
|
||||
const bgcolor = 0xa2
|
||||
end
|
||||
|
||||
entity Bitmap1 [Bitmap]
|
||||
const bitmapdata = [1, 1, 3, 7, 15, 31, 63, 127, 0]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Bitmap2 [Bitmap]
|
||||
const bitmapdata = [$18,$3e,$ff,$ff,$ff,$ff,$3e,$18, 0]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Colormap1 [Colormap]
|
||||
const colormapdata = [2, 4, 6, 8, 10, 12, 14, 14, 14]
|
||||
end
|
||||
|
||||
entity Sprite0 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 50
|
||||
init ypos = 150
|
||||
init bitmap = #Bitmap2
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Sprite1 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 100
|
||||
init ypos = 60
|
||||
init bitmap = #Bitmap1
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 3
|
||||
end
|
||||
|
||||
entity Sprite2 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 80
|
||||
init ypos = 90
|
||||
init bitmap = #Bitmap2
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 2
|
||||
end
|
||||
|
||||
entity Sprite3 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 40
|
||||
init ypos = 150
|
||||
init bitmap = #Bitmap1
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 0
|
||||
end
|
||||
/*
|
||||
entity [Missile,HasXpos,HasYpos]
|
||||
init xpos = 70
|
||||
init ypos = 70
|
||||
end
|
||||
*/
|
||||
entity Slot0 [SpriteSlot]
|
||||
init sprite = #Sprite0
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
init sprite = #Sprite1
|
||||
end
|
||||
entity Slot2 [SpriteSlot]
|
||||
init sprite = #Sprite2
|
||||
end
|
||||
entity Slot3 [SpriteSlot]
|
||||
init sprite = #Sprite3
|
||||
end
|
||||
|
||||
end demo
|
||||
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component Song
|
||||
songdata: array of 0..255
|
||||
end
|
||||
|
||||
// TODO: merge with SoundChannel
|
||||
component MusicChannel
|
||||
duration: 0..255
|
||||
note: 0..255
|
||||
duty: 0..255
|
||||
end
|
||||
|
||||
component MusicPlayer
|
||||
timer: 0..255 default 255
|
||||
channel: [MusicChannel]
|
||||
songptr: 0..65535
|
||||
volume: 0..15 default 15
|
||||
tempo: 0..255 default 7
|
||||
end
|
||||
|
||||
|
||||
// Table of AUDF base values for each note
|
||||
resource FREQZ ---
|
||||
.byte 30, 30, 30, 30, 30, 28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 30, 29, 27, 25, 24, 22, 21, 20, 19, 18, 16, 15, 15, 14, 13, 12, 11, 11, 10, 31, 29, 27, 25, 24, 23, 21, 20, 19, 18, 16, 15, 15
|
||||
---
|
||||
// Table of duty-cycle bits for each note
|
||||
resource DUTYZ ---
|
||||
.byte 247, 247, 247, 247, 1, 73, 219, 1, 219, 73, 0, 219, 181, 85, 85, 85, 181, 219, 247, 1, 73, 181, 0, 73, 219, 17, 219, 17, 219, 73, 247, 85, 247, 1, 85, 247, 73, 247, 181, 17, 1, 0, 247, 247, 0, 1, 17, 73, 181, 0, 17, 0, 1, 85, 247, 73, 0, 181, 73, 1, 0, 247, 247, 0
|
||||
---
|
||||
// Table of AUDC values for each note
|
||||
resource TONEZ ---
|
||||
.byte 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||||
---
|
||||
|
||||
system MusicPlayer
|
||||
on preframe do once
|
||||
---
|
||||
{{!musicpulse}} ; update song
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
on prekernel do once
|
||||
---
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
on postkernel do once
|
||||
---
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
// TODO: unroll?
|
||||
on musicframe do foreach [MusicChannel]
|
||||
---
|
||||
; Update channel pitch in AUDF0
|
||||
; 8-bit rotation of duty cycle bits
|
||||
lda {{get duration}}
|
||||
beq :++
|
||||
lda {{set duty}}
|
||||
asl
|
||||
bcc :+
|
||||
ora #1
|
||||
: sta {{set duty}}
|
||||
lda {{get note}}
|
||||
beq :+
|
||||
; If next bit is set, add 1 to AUDF0
|
||||
adc #0
|
||||
sta AUDF0,x
|
||||
:
|
||||
---
|
||||
on musicpulse do foreach [MusicChannel]
|
||||
---
|
||||
; Decrement the volumes for each channel
|
||||
; Also decrement next-note timer, fetch next note
|
||||
lda {{get duration}}
|
||||
beq :+
|
||||
lsr
|
||||
sta AUDV0,x
|
||||
dec {{set duration}}
|
||||
:
|
||||
---
|
||||
on musicpulse do with [MusicPlayer]
|
||||
---
|
||||
lda {{get timer}}
|
||||
bmi @Done
|
||||
beq @NextData
|
||||
dec {{set timer}}
|
||||
jmp @Done
|
||||
; Timer ran out, so fetch next note
|
||||
@NextData:
|
||||
ldx #0
|
||||
lda ({{get songptr}},x)
|
||||
bmi @LoadDuration
|
||||
; < $80, play next note
|
||||
ldx {{get channel}} ; next channel
|
||||
tay
|
||||
{{!musicnote}}
|
||||
inx
|
||||
txa
|
||||
and #1
|
||||
sta {{set channel}} ; inc next channel
|
||||
jmp @IncDataPtr
|
||||
; >= $80, load next duration
|
||||
@LoadDuration:
|
||||
cmp #$ff ; $ff = end of song
|
||||
bne @NoResetTrack
|
||||
sta {{set timer}}
|
||||
{{!musicdone}}
|
||||
jmp @Done
|
||||
@NoResetTrack:
|
||||
and #$7f
|
||||
; asl
|
||||
sta {{set timer}} ; store duration * 2
|
||||
@IncDataPtr:
|
||||
; increment song pointer
|
||||
inc {{set songptr 0}}
|
||||
bne @Done
|
||||
inc {{set songptr 8}}
|
||||
@Done:
|
||||
---
|
||||
// TODO: should use "with"?
|
||||
on musicnote do select all [MusicChannel]
|
||||
---
|
||||
; Play a note
|
||||
; X = channel (0,1)
|
||||
; Y = note index (0-63)
|
||||
lda {{^FREQZ}},y
|
||||
sta {{base note}},x
|
||||
lda {{^DUTYZ}},y
|
||||
sta {{base duty}},x
|
||||
lda {{^TONEZ}},y
|
||||
sta AUDC0,x
|
||||
; TODO: consts?
|
||||
lda {{get MusicPlayer:tempo}}
|
||||
sta {{base duration}},x
|
||||
lda {{get MusicPlayer:volume}}
|
||||
sta AUDV0,x
|
||||
---
|
||||
on playmusic do foreach [MusicPlayer] limit 1
|
||||
---
|
||||
lda #<{{arg 0}}
|
||||
sta {{set songptr 0}}
|
||||
lda #>{{arg 0}}
|
||||
sta {{set songptr 8}}
|
||||
lda #0
|
||||
sta {{set timer}}
|
||||
---
|
||||
on stopmusic do foreach [MusicPlayer] limit 1
|
||||
---
|
||||
lda #$ff
|
||||
sta {{set timer}}
|
||||
---
|
||||
end
|
||||
|
||||
///
|
||||
|
||||
demo music
|
||||
using FrameLoop
|
||||
using MusicPlayer
|
||||
entity [MusicChannel] end
|
||||
entity [MusicChannel] end
|
||||
entity MusicPlayer [MusicPlayer]
|
||||
const volume = 10
|
||||
const tempo = 31
|
||||
end
|
||||
system music
|
||||
on musicdone do with [MusicPlayer]
|
||||
---
|
||||
; TODO: nested exprs
|
||||
; {{!playmusic ^SampleMusic}}
|
||||
;{{^SampleMusic}}
|
||||
{{!playmusic SampleMusic}}
|
||||
---
|
||||
on preframeloop do once
|
||||
---
|
||||
{{!musicdone}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
||||
resource SampleMusic ---
|
||||
.byte $35,$41,$8a,$37,$43,$8a,$33,$3f,$8a,$30,$3c,$94,$3e,$32,$8a,$3a,$2e,$94,$35,$29,$8a,$37,$2b,$8a,$33,$27,$8a,$30,$24,$94,$32,$26,$8a,$2e,$22,$94,$29,$1d,$8a,$2b,$1f,$8a,$27,$1b,$8a,$24,$18,$94,$1a,$26,$8a,$18,$24,$8a,$17,$23,$8a,$16,$22,$a8,$3a,$35,$ff
|
||||
---
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
component Random8
|
||||
seed: 0..255 default 1 // TODO: default = 1, or seed?
|
||||
end
|
||||
|
||||
system Random
|
||||
on nextrand8 do foreach [Random8]
|
||||
---
|
||||
lda {{<seed}}
|
||||
lsr
|
||||
bcc :+
|
||||
eor #$d4
|
||||
:
|
||||
sta {{<seed}}
|
||||
---
|
||||
on prevrand8 do foreach [Random8]
|
||||
---
|
||||
lda {{<seed}}
|
||||
asl
|
||||
bcc :+
|
||||
eor #$a9
|
||||
:
|
||||
sta {{<seed}}
|
||||
---
|
||||
/* add entropy via joystick inputs */
|
||||
on preframe do foreach [Random8]
|
||||
---
|
||||
lda {{<seed}}
|
||||
eor SWCHA
|
||||
beq :+
|
||||
sta {{<seed}}
|
||||
:
|
||||
---
|
||||
end
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component BCDScore2
|
||||
digits: 0..$ff
|
||||
scorecolor: 0..$ff
|
||||
end
|
||||
|
||||
component BCDScore4
|
||||
digits: 0..0xffff
|
||||
end
|
||||
|
||||
component BCDScore6
|
||||
digits: 0..0xffffff
|
||||
end
|
||||
|
||||
system Kernel6Digit
|
||||
locals 15
|
||||
on preframe do with [BCDScore6]
|
||||
---
|
||||
Digit0 = {{$0}}
|
||||
Digit1 = {{$2}}
|
||||
Digit2 = {{$4}}
|
||||
Digit3 = {{$6}}
|
||||
Digit4 = {{$8}}
|
||||
Digit5 = {{$10}}
|
||||
@BCD0 = {{$12}}
|
||||
@BCD1 = {{$13}}
|
||||
@BCD2 = {{$14}}
|
||||
|
||||
lda {{get digits 0}}
|
||||
sta @BCD0
|
||||
lda {{get digits 8}}
|
||||
sta @BCD1
|
||||
lda {{get digits 16}}
|
||||
sta @BCD2
|
||||
ldx #0 ; leftmost bitmap
|
||||
ldy #2 ; start from most-sigificant BCD value
|
||||
@Loop:
|
||||
lda @BCD0,y ; get BCD value
|
||||
and #$f0 ; isolate high nibble (* 16)
|
||||
lsr ; shift right 1 bit (* 8)
|
||||
clc
|
||||
adc #<{{^FontTable}}
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>{{^FontTable}}
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
lda @BCD0,y ; get BCD value (again)
|
||||
and #$f ; isolate low nibble
|
||||
asl
|
||||
asl
|
||||
asl ; * 8
|
||||
clc
|
||||
adc #<{{^FontTable}}
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>{{^FontTable}}
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
dey ; next BCD value
|
||||
bpl @Loop ; repeat until < 0
|
||||
---
|
||||
on kernel do with [BCDScore6,PFColor]
|
||||
---
|
||||
lda {{<pfcolor}}
|
||||
sta COLUP0
|
||||
sta COLUP1
|
||||
lda #3
|
||||
sta NUSIZ0
|
||||
sta NUSIZ1
|
||||
; set horizontal position of player objects
|
||||
sta WSYNC
|
||||
sta HMCLR
|
||||
SLEEPR 24
|
||||
sta RESP0
|
||||
sta RESP1
|
||||
lda #$10
|
||||
sta HMP1
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24 ; wait 24 cycles between write to HMOVE and HMxxx
|
||||
sta HMCLR
|
||||
lda #1
|
||||
sta VDELP0
|
||||
sta VDELP1
|
||||
---
|
||||
on kernel do
|
||||
critical fit 72
|
||||
with [BCDScore6,BGColor]
|
||||
---
|
||||
; Display the resulting 48x8 bitmap
|
||||
; using the Digit0-5 pointers.
|
||||
@LoopCount = {{$12}}
|
||||
@Temp = {{$13}}
|
||||
|
||||
lda {{<bgcolor}}
|
||||
sta WSYNC
|
||||
sta COLUBK
|
||||
lda #7
|
||||
sta @LoopCount
|
||||
SLEEPR 20 ; TODO?
|
||||
:
|
||||
ldy @LoopCount ; counts backwards
|
||||
lda (Digit0),y ; load B0 (1st sprite byte)
|
||||
sta GRP0 ; B0 -> [GRP0]
|
||||
lda (Digit1),y ; load B1 -> A
|
||||
sta GRP1 ; B1 -> [GRP1], B0 -> GRP0
|
||||
sta WSYNC ; sync to next scanline
|
||||
lda (Digit2),y ; load B2 -> A
|
||||
sta GRP0 ; B2 -> [GRP0], B1 -> GRP1
|
||||
lda (Digit5),y ; load B5 -> A
|
||||
sta @Temp ; B5 -> temp
|
||||
lda (Digit4),y ; load B4
|
||||
tax ; -> X
|
||||
lda (Digit3),y ; load B3 -> A
|
||||
ldy @Temp ; load B5 -> Y
|
||||
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
||||
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
||||
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
||||
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
||||
dec @LoopCount ; go to next line
|
||||
bpl :- ; repeat until < 0
|
||||
|
||||
lda #0 ; clear the sprite registers
|
||||
sta WSYNC
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta COLUBK
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
resource FontTable ---
|
||||
; Font table for digits 0-9 (8x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$3c,$66,$66,$76,$6e,$66,$3c,$00,$7e,$18,$18,$18,$38,$18,$18
|
||||
.byte $00,$7e,$60,$30,$0c,$06,$66,$3c,$00,$3c,$66,$06,$1c,$06,$66,$3c
|
||||
.byte $00,$06,$06,$7f,$66,$1e,$0e,$06,$00,$3c,$66,$06,$06,$7c,$60,$7e
|
||||
.byte $00,$3c,$66,$66,$7c,$60,$66,$3c,$00,$18,$18,$18,$18,$0c,$66,$7e
|
||||
.byte $00,$3c,$66,$66,$3c,$66,$66,$3c,$00,$3c,$66,$06,$3e,$66,$66,$3c
|
||||
---
|
||||
|
||||
system Kernel2Digit
|
||||
locals 3
|
||||
on preframe do once
|
||||
---
|
||||
lda #0
|
||||
sta {{$1}}
|
||||
sta {{$2}}
|
||||
---
|
||||
on kernel do select [BCDScore2]
|
||||
---
|
||||
lda #$02
|
||||
sta CTRLPF
|
||||
; TODO: should be constants
|
||||
; and it's wrong, too!
|
||||
lda {{<BCDScore2:scorecolor}}+0
|
||||
sta COLUP0
|
||||
lda {{<BCDScore2:scorecolor}}+1
|
||||
sta COLUP1
|
||||
---
|
||||
on kernel do
|
||||
critical fit 98
|
||||
select [BCDScore2]
|
||||
---
|
||||
lda #7
|
||||
sta {{$0}}
|
||||
@Loop:
|
||||
ldx #0
|
||||
sta WSYNC
|
||||
{{!compute2digit 0}}
|
||||
.if {{%ecount}}>1
|
||||
inx
|
||||
{{!compute2digit 1}}
|
||||
.else
|
||||
{{!compute2digit 0}}
|
||||
.endif
|
||||
; playfield
|
||||
dec {{$0}}
|
||||
jpl @Loop
|
||||
; dex
|
||||
; stx PF1
|
||||
---
|
||||
on compute2digit do once
|
||||
---
|
||||
lda {{$1}} ; load 1st pf
|
||||
sta PF1 ; store 1st pf
|
||||
; first digit
|
||||
lda {{<BCDScore2:digits}} + {{#0}}
|
||||
pha
|
||||
and #$0f
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
{{!fetchdigit}}
|
||||
and #$0f
|
||||
ldy {{$2}} ; load 2nd pf
|
||||
sta {{$1}} + {{#0}}
|
||||
; second digit
|
||||
pla
|
||||
and #$f0
|
||||
lsr
|
||||
sty PF1 ; store 2nd pf
|
||||
{{!fetchdigit}}
|
||||
and #$f0
|
||||
ora {{$1}} + {{#0}}
|
||||
sta {{$1}} + {{#0}}
|
||||
---
|
||||
on fetchdigit do once
|
||||
---
|
||||
adc {{$0}}
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda {{^FontTablePF}},y
|
||||
---
|
||||
end
|
||||
|
||||
resource FontTablePF ---
|
||||
; Font table for digits 0-9 (4x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$00,$EE,$AA,$AA,$AA,$EE,$00
|
||||
.byte $00,$00,$22,$22,$22,$22,$22,$00
|
||||
.byte $00,$00,$EE,$88,$EE,$22,$EE,$00
|
||||
.byte $00,$00,$EE,$22,$66,$22,$EE,$00
|
||||
.byte $00,$00,$22,$22,$EE,$AA,$AA,$00
|
||||
.byte $00,$00,$EE,$22,$EE,$88,$EE,$00
|
||||
.byte $00,$00,$EE,$AA,$EE,$88,$EE,$00
|
||||
.byte $00,$00,$22,$22,$22,$22,$EE,$00
|
||||
.byte $00,$00,$EE,$AA,$EE,$AA,$EE,$00
|
||||
.byte $00,$00,$EE,$22,$EE,$AA,$EE,$00
|
||||
;;
|
||||
---
|
||||
|
||||
resource FontTablePFFancy ---
|
||||
; Font table for digits 0-9 (4x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$44,$AA,$AA,$AA,$AA,$AA,$44
|
||||
.byte $00,$EE,$44,$44,$44,$44,$CC,$44
|
||||
.byte $00,$EE,$88,$88,$44,$22,$AA,$44
|
||||
.byte $00,$CC,$22,$22,$66,$22,$22,$CC
|
||||
.byte $00,$22,$22,$22,$EE,$AA,$AA,$88
|
||||
.byte $00,$44,$AA,$22,$44,$88,$88,$EE
|
||||
.byte $00,$44,$AA,$AA,$CC,$88,$AA,$44
|
||||
.byte $00,$22,$22,$22,$22,$22,$AA,$EE
|
||||
.byte $00,$44,$AA,$AA,$44,$AA,$AA,$44
|
||||
.byte $00,$44,$AA,$22,$66,$AA,$AA,$44
|
||||
;;
|
||||
---
|
||||
|
||||
system BCDMath
|
||||
locals 1
|
||||
on AddBCD4 do once
|
||||
---
|
||||
.ifnblank {{arg 0}}
|
||||
lda #<{{arg 0}}
|
||||
ldy #>{{arg 0}}
|
||||
.endif
|
||||
---
|
||||
on AddBCD4 do with [BCDScore6]
|
||||
---
|
||||
; Adds value to 6-BCD-digit score.
|
||||
; A = 1st BCD digit
|
||||
; Y = 2nd BCD digit
|
||||
sed ; enter BCD mode
|
||||
clc ; clear carry
|
||||
adc {{get digits}}
|
||||
sta {{set digits}}
|
||||
tya
|
||||
adc {{get digits 8}}
|
||||
sta {{set digits 8}}
|
||||
lda {{get digits 16}}
|
||||
adc #0
|
||||
sta {{set digits 16}}
|
||||
cld ; exit BCD mode
|
||||
---
|
||||
on AddBCD2 do once
|
||||
---
|
||||
.ifnblank {{arg 0}}
|
||||
lda #<{{arg 0}}
|
||||
.endif
|
||||
---
|
||||
on SubBCD2 do once
|
||||
---
|
||||
.ifnblank {{arg 0}}
|
||||
lda #<{{arg 0}}
|
||||
.endif
|
||||
---
|
||||
on AddBCD2 do with [BCDScore2]
|
||||
---
|
||||
sed ; enter BCD mode
|
||||
clc ; clear carry
|
||||
adc {{get digits}}
|
||||
sta {{set digits}}
|
||||
cld ; exit BCD mode
|
||||
bcc :+
|
||||
lda #$99
|
||||
sta {{set digits}}
|
||||
:
|
||||
---
|
||||
on SubBCD2 do with [BCDScore2]
|
||||
---
|
||||
; TODO?
|
||||
tay
|
||||
lda {{get digits}}
|
||||
sty {{set digits}}
|
||||
sed ; enter BCD mode
|
||||
sec ; set carry
|
||||
sbc {{get digits}}
|
||||
sta {{set digits}}
|
||||
cld ; exit BCD mode
|
||||
bcs :+
|
||||
lda #0
|
||||
sta {{set digits}}
|
||||
:
|
||||
---
|
||||
end
|
||||
|
||||
demo Main
|
||||
|
||||
using FrameLoop
|
||||
using Kernel6Digit
|
||||
using Kernel2Digit
|
||||
using JoyButton, BCDMath
|
||||
|
||||
entity [Player,BCDScore6,PFColor,BGColor]
|
||||
init digits = 0x123456
|
||||
init pfcolor = $3c
|
||||
init bgcolor = $02
|
||||
end
|
||||
|
||||
entity [BCDScore2]
|
||||
init digits = 0x24
|
||||
init scorecolor = $ce
|
||||
end
|
||||
entity [BCDScore2]
|
||||
init digits = 0x56
|
||||
init scorecolor = $3e
|
||||
end
|
||||
|
||||
system IncScore
|
||||
on joybutton do with [Player,BCDScore6]
|
||||
---
|
||||
{{!AddBCD4 $0210}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component SoundEffect
|
||||
duration: 0..255
|
||||
sounddata: array of 0..255
|
||||
end
|
||||
|
||||
component SoundChannel
|
||||
sfx: [SoundEffect]
|
||||
timer: 0..255
|
||||
end
|
||||
|
||||
// TODO
|
||||
component SoundPriority
|
||||
priority: 0..15
|
||||
end
|
||||
|
||||
system SoundEngine
|
||||
locals 3
|
||||
on preframe do
|
||||
join [SoundChannel]
|
||||
with [SoundEffect]
|
||||
---
|
||||
lda {{base timer}},y
|
||||
jeq @nosound
|
||||
sec
|
||||
sbc #1
|
||||
sta {{base timer}},y
|
||||
pha
|
||||
lda {{<sounddata}}
|
||||
sta {{$0}}
|
||||
lda {{>sounddata}}
|
||||
sta {{$1}} ; save pointer to sound data
|
||||
sty {{$2}} ; save Y (sound channel #)
|
||||
pla
|
||||
tay
|
||||
lda ({{$0}}),y ; get sound data
|
||||
bpl @setfreq ; hi bit clear = just freq
|
||||
ldy {{$2}}
|
||||
lsr ; right shift (/ 2)
|
||||
bcs @setvol ; lo bit set = volume
|
||||
sta AUDC0,y ; lo bit clear = control
|
||||
lsr ; also set freq (/ 2)
|
||||
@setfreq:
|
||||
ldy {{$2}}
|
||||
sta AUDF0,y ; set frequency
|
||||
jmp @done
|
||||
@nosound:
|
||||
lda #0
|
||||
@setvol:
|
||||
sta AUDV0,y ; set volume
|
||||
@done:
|
||||
---
|
||||
// TODO: need to pass sound entity as arg
|
||||
on playsound do select [SoundChannel]
|
||||
---
|
||||
; arg 0 = sound channel
|
||||
ldy #{{arg 0}}
|
||||
; arg 1 = sound effect #
|
||||
lda #{{arg 1}}
|
||||
sta {{base sfx}},y
|
||||
tax
|
||||
---
|
||||
// TODO: shouldn't need to split up like this...
|
||||
on playsound do select [SoundEffect]
|
||||
---
|
||||
lda {{base duration}},x
|
||||
---
|
||||
on playsound do select [SoundChannel]
|
||||
---
|
||||
sta {{base timer}},y
|
||||
; arg 2 = base volume
|
||||
lda #{{arg 2}}
|
||||
sta AUDV0,y
|
||||
---
|
||||
end
|
||||
|
||||
// TODO: default entities?
|
||||
|
||||
|
||||
demo SoundDemo
|
||||
using FrameLoop, SoundEngine
|
||||
|
||||
entity SFXScore [SoundEffect]
|
||||
const duration = 11
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$10,$20,$10,$08,
|
||||
$a8]
|
||||
end
|
||||
|
||||
// TODO: make sfx have priority?
|
||||
entity SFX1 [SoundChannel] end
|
||||
entity SFX2 [SoundChannel] end
|
||||
|
||||
system Test
|
||||
on preframeloop do once
|
||||
---
|
||||
{{!playsound 0 0 15}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component Bitmap
|
||||
bitmapdata: array of 0..255 baseoffset 31
|
||||
height: 0..255
|
||||
end
|
||||
|
||||
// TODO: remove?
|
||||
component HasBitmap
|
||||
end
|
||||
|
||||
component Colormap
|
||||
colormapdata: array of 0..255 baseoffset 31
|
||||
end
|
||||
|
||||
component HasColormap
|
||||
colormap: [Colormap]
|
||||
end
|
||||
|
||||
component Sprite
|
||||
bitmap: [Bitmap]
|
||||
plyrflags: 0..63
|
||||
end
|
||||
|
||||
component HasXpos
|
||||
xpos: 0..255
|
||||
end
|
||||
|
||||
component HasYpos
|
||||
ypos: 0..255
|
||||
end
|
||||
|
||||
component Missile
|
||||
index: 2..3
|
||||
end
|
||||
|
||||
component SpriteSlot
|
||||
sprite: [Sprite] // TODO: HasBitmap?
|
||||
end
|
||||
|
||||
system JoyFaceDirection
|
||||
on joyleft do with [Sprite]
|
||||
---
|
||||
lda {{<plyrflags}}
|
||||
ora #$08
|
||||
sta {{<plyrflags}}
|
||||
---
|
||||
on joyright do with [Sprite]
|
||||
---
|
||||
lda {{<plyrflags}}
|
||||
and #$f7
|
||||
sta {{<plyrflags}}
|
||||
---
|
||||
end
|
||||
|
||||
system MoveJoyX
|
||||
on joyleft do with [HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
sec
|
||||
sbc #1
|
||||
bcc @nomove
|
||||
sta {{<xpos}}
|
||||
@nomove:
|
||||
---
|
||||
on joyright do with [HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #150
|
||||
bcs @nomove
|
||||
sta {{<xpos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system MoveJoyY
|
||||
on joyup do with [HasYpos]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
sec
|
||||
sbc #1
|
||||
bcc @nomove
|
||||
sta {{<ypos}}
|
||||
@nomove:
|
||||
---
|
||||
on joydown do with [HasYpos]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #220
|
||||
bcs @nomove
|
||||
sta {{<ypos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system SetXPos
|
||||
on preframe do join [SpriteSlot] with [Sprite]
|
||||
limit 2
|
||||
---
|
||||
lda {{<xpos}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on preframe do foreach [Missile,HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
ldy {{<index}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on prekernel do once
|
||||
---
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24
|
||||
sta HMCLR
|
||||
---
|
||||
end
|
||||
|
||||
system SpriteShuffler
|
||||
locals 2
|
||||
on postframe do select [SpriteSlot]
|
||||
---
|
||||
; load two sprite slots at left side of array
|
||||
lda {{<SpriteSlot:sprite}}
|
||||
sta {{$0}}
|
||||
lda {{<SpriteSlot:sprite}}+1
|
||||
sta {{$1}}
|
||||
; move two slots to the left
|
||||
ldx #0
|
||||
@loop:
|
||||
lda {{<SpriteSlot:sprite}}+2,x
|
||||
sta {{<SpriteSlot:sprite}},x
|
||||
inx
|
||||
cpx #{{%ecount}}-2
|
||||
bne @loop
|
||||
; store two sprite slots at right side of array
|
||||
lda {{$0}}
|
||||
sta {{<SpriteSlot:sprite}}+{{%ecount}}-2
|
||||
lda {{$1}}
|
||||
sta {{<SpriteSlot:sprite}}+{{%ecount}}-1
|
||||
---
|
||||
end
|
||||
|
||||
system SpriteHider
|
||||
locals 1
|
||||
on postframe do select [SpriteSlot]
|
||||
---
|
||||
lda #{{%efullcount}}-1
|
||||
sta {{$0}}
|
||||
---
|
||||
on postframe do
|
||||
join [SpriteSlot]
|
||||
with [Sprite,HasYpos]
|
||||
limit 2
|
||||
---
|
||||
lda {{<ypos}}
|
||||
cmp #192
|
||||
bcc @skip
|
||||
; swap this sprite slot with slot at end of array
|
||||
lda {{<SpriteSlot:sprite}},y
|
||||
pha
|
||||
ldx {{$0}} ; clobbers X, but no longer used
|
||||
lda {{<SpriteSlot:sprite}},x
|
||||
sta {{<SpriteSlot:sprite}},y
|
||||
pla
|
||||
sta {{<SpriteSlot:sprite}},x
|
||||
dec {{$0}}
|
||||
@skip:
|
||||
---
|
||||
end
|
||||
|
|
@ -0,0 +1,286 @@
|
|||
.setcpu "6502X"
|
||||
|
||||
; TIA write registers
|
||||
|
||||
VSYNC := $00 ; ---- --1- This address controls vertical sync time by writing D1 into the VSYNC latch.
|
||||
VBLANK := $01 ; 76-- --1- 1=Start VBLANK, 6=Enable INPT4, INPT5 latches, 7=Dump INPT1,2,3,6 to ground
|
||||
WSYNC := $02 ; ---- ---- This address halts microprocessor by clearing RDY latch to zero. RDY is set true again by the leading edge of horizontal blank.
|
||||
RSYNC := $03 ; ---- ---- This address resets the horizontal sync counter to define the beginning of horizontal blank time, and is used in chip testing.
|
||||
NUSIZ0 := $04 ; --54 -210 \ 0,1,2: player copys'n'size, 4,5: missile size: 2^x pixels
|
||||
NUSIZ1 := $05 ; --54 -210 /
|
||||
COLUP0 := $06 ; 7654 321- color player 0
|
||||
COLUP1 := $07 ; 7654 321- color player 1
|
||||
COLUPF := $08 ; 7654 321- color playfield
|
||||
COLUBK := $09 ; 7654 321- color background
|
||||
CTRLPF := $0A ; --54 -210 0=reflect playfield, 1=pf uses player colors, 2=playfield over sprites 4,5=ballsize:2^x
|
||||
REFP0 := $0B ; ---- 3--- reflect player 0
|
||||
REFP1 := $0C ; ---- 3--- reflect player 1
|
||||
PF0 := $0D ; DCBA ---- \ Playfield bits: ABCDEFGHIJKLMNOPQRST
|
||||
PF1 := $0E ; EFGH IJKL > normal: ABCDEFGHIJKLMNOPQRSTABCDEFGHIJKLMNOPQRST
|
||||
PF2 := $0F ; TSRQ PONM / reflect: ABCDEFGHIJKLMNOPQRSTTSRQPONMLKJIHGFEDCBA
|
||||
RESP0 := $10 ; ---- ---- \
|
||||
RESP1 := $11 ; ---- ---- \
|
||||
RESM0 := $12 ; ---- ---- > reset players, missiles and the ball. The object will begin its serial graphics at the time of a horizontal line at which the reset address occurs.
|
||||
RESM1 := $13 ; ---- ---- /
|
||||
RESBL := $14 ; ---- ---- /
|
||||
AUDC0 := $15 ; ---- 3210 audio control voice 0
|
||||
AUDC1 := $16 ; ---- 3210 audio control voice 1
|
||||
AUDF0 := $17 ; ---4 3210 frequency divider voice 0
|
||||
AUDF1 := $18 ; ---4 3210 frequency divider voice 1
|
||||
AUDV0 := $19 ; ---- 3210 audio volume voice 0
|
||||
AUDV1 := $1A ; ---- 3210 audio volume voice 1
|
||||
GRP0 := $1B ; 7654 3210 graphics player 0
|
||||
GRP1 := $1C ; 7654 3210 graphics player 1
|
||||
ENAM0 := $1D ; ---- --1- enable missile 0
|
||||
ENAM1 := $1E ; ---- --1- enable missile 1
|
||||
ENABL := $1F ; ---- --1- enable ball
|
||||
HMP0 := $20 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers
|
||||
HMP1 := $21 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers
|
||||
HMM0 := $22 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers
|
||||
HMM1 := $23 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers
|
||||
HMBL := $24 ; 7654 ---- write data (horizontal motion values) into the horizontal motion registers
|
||||
VDELP0 := $25 ; ---- ---0 delay player 0 by one vertical line
|
||||
VDELP1 := $26 ; ---- ---0 delay player 1 by one vertical line
|
||||
VDELBL := $27 ; ---- ---0 delay ball by one vertical line
|
||||
RESMP0 := $28 ; ---- --1- keep missile 0 aligned with player 0
|
||||
RESMP1 := $29 ; ---- --1- keep missile 1 aligned with player 1
|
||||
HMOVE := $2A ; ---- ---- This address causes the horizontal motion register values to be acted upon during the horizontal blank time in which it occurs.
|
||||
HMCLR := $2B ; ---- ---- This address clears all horizontal motion registers to zero (no motion).
|
||||
CXCLR := $2C ; ---- ---- clears all collision latches
|
||||
|
||||
; TIA read registers
|
||||
|
||||
CXM0P := $00 ; xx00 0000 Read Collision M0-P1 M0-P0
|
||||
CXM1P := $01 ; xx00 0000 M1-P0 M1-P1
|
||||
CXP0FB := $02 ; xx00 0000 P0-PF P0-BL
|
||||
CXP1FB := $03 ; xx00 0000 P1-PF P1-BL
|
||||
CXM0FB := $04 ; xx00 0000 M0-PF M0-BL
|
||||
CXM1FB := $05 ; xx00 0000 M1-PF M1-BL
|
||||
CXBLPF := $06 ; x000 0000 BL-PF -----
|
||||
CXPPMM := $07 ; xx00 0000 P0-P1 M0-M1
|
||||
INPT0 := $08 ; x000 0000 Read Pot Port 0
|
||||
INPT1 := $09 ; x000 0000 Read Pot Port 1
|
||||
INPT2 := $0A ; x000 0000 Read Pot Port 2
|
||||
INPT3 := $0B ; x000 0000 Read Pot Port 3
|
||||
INPT4 := $0C ; x000 0000 Read Input (Trigger) 0
|
||||
INPT5 := $0D ; x000 0000 Read Input (Trigger) 1
|
||||
|
||||
; RIOT
|
||||
|
||||
SWCHA := $0280
|
||||
SWACNT := $0281
|
||||
SWCHB := $0282
|
||||
SWBCNT := $0283
|
||||
INTIM := $0284 ; Timer output
|
||||
TIMINT := $0285
|
||||
|
||||
TIM1T := $0294
|
||||
TIM8T := $0295
|
||||
TIM64T := $0296
|
||||
TIM1024T := $0297
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; SLEEP duration
|
||||
; Original author: Thomas Jentzsch
|
||||
; Inserts code which takes the specified number of cycles to execute. This is
|
||||
; useful for code where precise timing is required.
|
||||
; ILLEGAL-OPCODE VERSION DOES NOT AFFECT FLAGS OR REGISTERS.
|
||||
; LEGAL OPCODE VERSION MAY AFFECT FLAGS
|
||||
; Uses illegal opcode (DASM 2.20.01 onwards).
|
||||
|
||||
.macro SLEEP cycles
|
||||
.if cycles < 0 || cycles = 1
|
||||
.error "MACRO ERROR: 'SLEEP': Duration must be >= 2"
|
||||
.endif
|
||||
.if cycles & 1
|
||||
.ifndef NO_ILLEGAL_OPCODES
|
||||
nop 0
|
||||
.else
|
||||
bit VSYNC
|
||||
.endif
|
||||
.repeat (cycles-3)/2
|
||||
nop
|
||||
.endrep
|
||||
.else
|
||||
.repeat cycles/2
|
||||
nop
|
||||
.endrep
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; VERTICAL_SYNC
|
||||
; revised version by Edwin Blink -- saves bytes!
|
||||
; Inserts the code required for a proper 3 scanline vertical sync sequence
|
||||
; Note: Alters the accumulator
|
||||
|
||||
; OUT: A = 0
|
||||
|
||||
.macro VERTICAL_SYNC
|
||||
lda #%1110 ; each '1' bits generate a VSYNC ON line (bits 1..3)
|
||||
: sta WSYNC ; 1st '0' bit resets Vsync, 2nd '0' bit exit loop
|
||||
sta VSYNC
|
||||
.ifdef VERTICAL_SYNC_MACRO
|
||||
pha
|
||||
VERTICAL_SYNC_MACRO
|
||||
pla
|
||||
.endif
|
||||
lsr
|
||||
bne :- ; branch until VYSNC has been reset
|
||||
.endmacro
|
||||
|
||||
;-------------------------------------------------------
|
||||
; Usage: TIMER_SETUP lines
|
||||
; where lines is the number of scanlines to skip (> 2).
|
||||
; The timer will be set so that it expires before this number
|
||||
; of scanlines. A WSYNC will be done first.
|
||||
|
||||
.macro TIMER_SETUP lines
|
||||
.local cycles
|
||||
cycles = ((lines * 76) - 13)
|
||||
; special case for when we have two timer events in a line
|
||||
; and our 2nd event straddles the WSYNC boundary
|
||||
.if (cycles .mod 64) < 12
|
||||
lda #(cycles / 64) - 1
|
||||
sta WSYNC
|
||||
.else
|
||||
lda #(cycles / 64)
|
||||
sta WSYNC
|
||||
.endif
|
||||
sta TIM64T
|
||||
.endmacro
|
||||
|
||||
;-------------------------------------------------------
|
||||
; Use with TIMER_SETUP to wait for timer to complete.
|
||||
; Performs a WSYNC afterwards.
|
||||
|
||||
.macro TIMER_WAIT
|
||||
.local waittimer
|
||||
waittimer:
|
||||
lda INTIM
|
||||
bne waittimer
|
||||
sta WSYNC
|
||||
.endmacro
|
||||
|
||||
;-------------------------------------------------------------------------------
|
||||
; CLEAN_START
|
||||
; Original author: Andrew Davie
|
||||
; Standardised start-up code, clears stack, all TIA registers and RAM to 0
|
||||
; Sets stack pointer to $FF, and all registers to 0
|
||||
; Sets decimal mode off, sets interrupt flag (kind of un-necessary)
|
||||
; Use as very first section of code on boot (ie: at reset)
|
||||
; Code written to minimise total ROM usage - uses weird 6502 knowledge :)
|
||||
|
||||
.macro CLEAN_START
|
||||
.local CLEAR_STACK
|
||||
sei
|
||||
cld
|
||||
ldx #0
|
||||
txa
|
||||
tay
|
||||
CLEAR_STACK: dex
|
||||
txs
|
||||
pha
|
||||
bne CLEAR_STACK ; SP=$FF, X = A = Y = 0
|
||||
.endmacro
|
||||
|
||||
;-------------------------------------------------------
|
||||
; SET_POINTER
|
||||
; Original author: Manuel Rotschkar
|
||||
;
|
||||
; Sets a 2 byte RAM pointer to an absolute address.
|
||||
;
|
||||
; Usage: SET_POINTER pointer, address
|
||||
; Example: SET_POINTER SpritePTR, SpriteData
|
||||
;
|
||||
; Note: Alters the accumulator, NZ flags
|
||||
; IN 1: 2 byte RAM location reserved for pointer
|
||||
; IN 2: absolute address
|
||||
.macro SET_POINTER ptr, addr
|
||||
lda #<addr
|
||||
sta ptr
|
||||
lda #>addr
|
||||
sta ptr+1
|
||||
.endmacro
|
||||
|
||||
|
||||
; assume NTSC unless PAL defined
|
||||
.ifndef PAL
|
||||
PAL = 0
|
||||
.endif
|
||||
|
||||
; 192 visible scanlines for NTSC, 228 for PAL
|
||||
.if PAL
|
||||
SCANLINES = 228
|
||||
LINESD12 = 19
|
||||
.else
|
||||
SCANLINES = 192
|
||||
LINESD12 = 16
|
||||
.endif
|
||||
|
||||
; start of frame -- vsync and set back porch timer
|
||||
.macro FRAME_START
|
||||
VERTICAL_SYNC
|
||||
.if PAL
|
||||
TIMER_SETUP 44
|
||||
.else
|
||||
TIMER_SETUP 36
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
; end of back porch -- start kernel
|
||||
.macro KERNEL_START
|
||||
TIMER_WAIT
|
||||
lda #0
|
||||
sta VBLANK
|
||||
.if !PAL
|
||||
TIMER_SETUP 194
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
; end of kernel -- start front porch timer
|
||||
.macro KERNEL_END
|
||||
.if !PAL
|
||||
TIMER_WAIT
|
||||
.endif
|
||||
lda #2
|
||||
sta VBLANK
|
||||
.if PAL
|
||||
TIMER_SETUP 36
|
||||
.else
|
||||
TIMER_SETUP 28
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
; end of frame -- jump to frame start
|
||||
.macro FRAME_END
|
||||
TIMER_WAIT
|
||||
.endmacro
|
||||
|
||||
;-----------------------------------------------------------
|
||||
; SLEEPR - sleep macro that uses JSR/RTS for 12 cycle delays
|
||||
; Requires a lone RTS instruction with the label "Return"
|
||||
; (note: may fool 8bitworkshop's Anaylze CPU Timing feature)
|
||||
|
||||
.macro SLEEPR cycles
|
||||
.if cycles >= 14 || cycles = 12
|
||||
jsr Return
|
||||
SLEEPR (cycles-12)
|
||||
.else
|
||||
SLEEP cycles
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
;-----------------------------------------------------------
|
||||
; SLEEPH - sleep macro that uses PHA/PLA for 12 cycle delays
|
||||
|
||||
.macro SLEEPH cycles
|
||||
.if cycles >= 9 || cycles = 7
|
||||
pha
|
||||
pla
|
||||
SLEEPH (cycles-7)
|
||||
.else
|
||||
SLEEP cycles
|
||||
.endif
|
||||
.endmacro
|
||||
|
|
@ -0,0 +1,336 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
system Init
|
||||
on main_init do once
|
||||
---
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
{{!start}} ; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
---
|
||||
end
|
||||
|
||||
component Player
|
||||
end
|
||||
|
||||
component KernelSection
|
||||
lines: 1..255 default 1
|
||||
end
|
||||
|
||||
component BGColor
|
||||
bgcolor: 0..255
|
||||
end
|
||||
|
||||
component FGColor
|
||||
fgcolor: 0..255
|
||||
end
|
||||
|
||||
component PFColor
|
||||
pfcolor: 0..255
|
||||
end
|
||||
|
||||
component Playfield
|
||||
pf: 0..0xffffff
|
||||
end
|
||||
|
||||
component AsymPlayfield
|
||||
pfleft: 0..0xffffff
|
||||
pfright: 0..0xffffff
|
||||
end
|
||||
|
||||
system FrameLoop
|
||||
on start do once
|
||||
---
|
||||
{{emit preframeloop}}
|
||||
@NextFrame:
|
||||
FRAME_END
|
||||
{{emit prevsync}}
|
||||
FRAME_START
|
||||
{{emit preframe}}
|
||||
{{emit prekernel}}
|
||||
KERNEL_START
|
||||
{{emit kernel}}
|
||||
KERNEL_END
|
||||
{{emit postkernel}}
|
||||
{{emit postframe}}
|
||||
jmp @NextFrame ; loop to next frame
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs @NoStart
|
||||
{{emit resetswitch}}
|
||||
@NoStart:
|
||||
---
|
||||
end
|
||||
|
||||
system ResetConsole
|
||||
on resetswitch do once
|
||||
---
|
||||
jmp Main::__Reset ; jump to Reset handler
|
||||
---
|
||||
end
|
||||
|
||||
system JoyButton
|
||||
on postframe do foreach [Player]
|
||||
---
|
||||
lda {{index INPT4}} ;read button input
|
||||
bmi @NotPressed
|
||||
{{emit joybutton}}
|
||||
@NotPressed:
|
||||
---
|
||||
end
|
||||
|
||||
system Joystick
|
||||
locals 1
|
||||
on postframe do once
|
||||
---
|
||||
; 2 control inputs share a single byte, 4 bits each
|
||||
lda SWCHA
|
||||
sta {{$0}}
|
||||
---
|
||||
on postframe do foreach [Player] limit 2
|
||||
---
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joyright
|
||||
bcs @SkipMoveRight
|
||||
{{!joyright}}
|
||||
@SkipMoveRight:
|
||||
.endif
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joyleft
|
||||
bcs @SkipMoveLeft
|
||||
{{!joyleft}}
|
||||
@SkipMoveLeft:
|
||||
.endif
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joydown
|
||||
bcs @SkipMoveDown
|
||||
{{!joydown}}
|
||||
@SkipMoveDown:
|
||||
.endif
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joyup
|
||||
bcs @SkipMoveUp
|
||||
{{!joyup}}
|
||||
@SkipMoveUp:
|
||||
.endif
|
||||
---
|
||||
end
|
||||
|
||||
system SetHorizPos
|
||||
on SetHorizPos do critical fit 22 once
|
||||
---
|
||||
; SetHorizPos routine
|
||||
; A = X coordinate
|
||||
; Y = player number (0 or 1)
|
||||
sec ; set carry flag
|
||||
sta WSYNC ; start a new line
|
||||
:
|
||||
sbc #15 ; subtract 15
|
||||
bcs :- ; branch until negative
|
||||
eor #7 ; calculate fine offset
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta HMP0,y ; set fine offset
|
||||
sta RESP0,y ; fix coarse position
|
||||
sta WSYNC ; won't overrun if X < 150
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
system StandardKernel
|
||||
on wsync do once
|
||||
---
|
||||
sta WSYNC
|
||||
---
|
||||
on preframe do foreach [KernelSection] limit 1
|
||||
---
|
||||
{{!wsync}}
|
||||
{{!kernelsetup}}
|
||||
---
|
||||
on kernel do foreach [KernelSection]
|
||||
---
|
||||
{{!wsync}}
|
||||
{{!kernelsetup}}
|
||||
{{!kerneldraw}}
|
||||
{{!kerneldone}}
|
||||
---
|
||||
on kerneldraw do with [KernelSection]
|
||||
---
|
||||
ldy {{<lines}}
|
||||
@loop:
|
||||
{{!prescanline}}
|
||||
{{!wsync}}
|
||||
{{!scanline}}
|
||||
dey
|
||||
bne @loop
|
||||
---
|
||||
on kernelsetup do if [BGColor]
|
||||
---
|
||||
lda {{<bgcolor}}
|
||||
sta COLUBK
|
||||
---
|
||||
on kernelsetup do if [PFColor]
|
||||
---
|
||||
lda {{get pfcolor}}
|
||||
sta COLUPF
|
||||
---
|
||||
on kernelsetup do if [Playfield]
|
||||
---
|
||||
lda {{get pf 0}}
|
||||
sta PF0
|
||||
lda {{get pf 8}}
|
||||
sta PF1
|
||||
lda {{get pf 16}}
|
||||
sta PF2
|
||||
---
|
||||
end
|
||||
|
||||
component SimpleCollidable
|
||||
lastx: 0..255
|
||||
lasty: 0..255
|
||||
end
|
||||
|
||||
system SimpleCollision
|
||||
on postframe do with [SimpleCollidable]
|
||||
---
|
||||
lda CXP0FB
|
||||
bpl @nocollide
|
||||
lda {{<lastx}}
|
||||
sta {{<xpos}}
|
||||
lda {{<lasty}}
|
||||
sta {{<ypos}}
|
||||
@nocollide:
|
||||
---
|
||||
on ymoved do with [SimpleCollidable]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
sta {{<lastx}}
|
||||
lda {{<ypos}}
|
||||
sta {{<lasty}}
|
||||
---
|
||||
end
|
||||
|
||||
component FrameCount
|
||||
frame: 0..255
|
||||
end
|
||||
|
||||
system FrameCounter
|
||||
on postframe do with [FrameCount]
|
||||
---
|
||||
inc {{set frame}}
|
||||
.ifdef EVENT__frame256
|
||||
jne @noframe256
|
||||
{{emit frame256}}
|
||||
@noframe256:
|
||||
.endif
|
||||
---
|
||||
// TODO: only .if responds to events
|
||||
on postframe do with [FrameCount]
|
||||
---
|
||||
jmp @go
|
||||
.ifdef EVENT__frame4
|
||||
@frame4:
|
||||
{{emit frame4}}
|
||||
jmp @done
|
||||
.endif
|
||||
.ifdef EVENT__frame8
|
||||
@frame8:
|
||||
{{emit frame8}}
|
||||
jmp @done
|
||||
.endif
|
||||
.ifdef EVENT__frame16
|
||||
@frame16:
|
||||
{{emit frame16}}
|
||||
jmp @done
|
||||
.endif
|
||||
@go:
|
||||
lda {{get frame}}
|
||||
.ifdef EVENT__frame16
|
||||
and #15
|
||||
jeq @frame16
|
||||
.endif
|
||||
.ifdef EVENT__frame8
|
||||
and #7
|
||||
cmp #3
|
||||
jeq @frame8
|
||||
.endif
|
||||
.ifdef EVENT__frame4
|
||||
and #3
|
||||
cmp #1
|
||||
jeq @frame4
|
||||
.endif
|
||||
@done:
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
|
||||
///
|
||||
|
||||
demo Main
|
||||
using FrameLoop, ResetConsole
|
||||
using StandardKernel, JoyButton
|
||||
|
||||
entity [Player]
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $1a
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $16
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $14
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $12
|
||||
end
|
||||
entity [KernelSection,BGColor,Playfield]
|
||||
const lines = 10
|
||||
const bgcolor = $14
|
||||
const pf = 0x125244
|
||||
end
|
||||
entity Trees [KernelSection,BGColor,PFColor,Playfield]
|
||||
const lines = 50
|
||||
const bgcolor = $14
|
||||
const pf = 0x112244
|
||||
end
|
||||
entity Trees2 [KernelSection,BGColor,PFColor,Playfield]
|
||||
const lines = 50
|
||||
const bgcolor = $16
|
||||
const pf = 0x124
|
||||
end
|
||||
entity [KernelSection,BGColor,Playfield]
|
||||
const lines = 10
|
||||
const bgcolor = $18
|
||||
const pf = 0
|
||||
end
|
||||
|
||||
system Local
|
||||
on joybutton do with [#Trees] ---
|
||||
inc {{set pfcolor}}
|
||||
---
|
||||
end
|
||||
|
||||
end demo
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
|
||||
component TinyVelX
|
||||
// TODO: -8..7? packed?
|
||||
xvel: 0..15 default 8
|
||||
end
|
||||
component TinyVelY
|
||||
// TODO: -8..7? packed?
|
||||
yvel: 0..15 default 8
|
||||
end
|
||||
|
||||
system TinyMover
|
||||
locals 1
|
||||
on postframe do foreach [HasXpos,TinyVelX]
|
||||
---
|
||||
lda {{<FrameCount:frame}}
|
||||
and #7 ; reduce frame # to 0..7
|
||||
tay
|
||||
lda {{^VMaskTable}},y ; lookup frame bit mask
|
||||
ldy {{<xvel}} ; xvel from 0..15
|
||||
and {{^VAndTable}},y ; mask with velocity table
|
||||
jeq @nomove ; no bits set? no move
|
||||
lda {{^DeltaVTable}},y ; lookup position delta
|
||||
clc
|
||||
adc {{<xpos}} ; add to coordinate
|
||||
sta {{<xpos}} ; store to coordinate
|
||||
{{!xmoved}} ; maybe modify it?
|
||||
@nomove:
|
||||
---
|
||||
on postframe do foreach [HasXpos,TinyVelY]
|
||||
---
|
||||
lda {{<FrameCount:frame}}
|
||||
and #7 ; reduce frame # to 0..7
|
||||
tay
|
||||
lda {{^VMaskTable}},y ; lookup frame bit mask
|
||||
ldy {{<yvel}} ; xvel from 0..15
|
||||
and {{^VAndTable}},y ; mask with velocity table
|
||||
jeq @nomove ; no bits set? no move
|
||||
lda {{^DeltaVTable}},y ; lookup position delta
|
||||
clc
|
||||
adc {{<ypos}} ; add to coordinate
|
||||
sta {{<ypos}} ; store to coordinate
|
||||
{{!ymoved}} ; maybe modify it?
|
||||
@nomove:
|
||||
---// set player reflection bit
|
||||
on xmoved do with [Sprite]
|
||||
---
|
||||
pha
|
||||
lda {{<plyrflags}}
|
||||
and #255-8
|
||||
ora {{^VReflectTab}},y
|
||||
sta {{<plyrflags}}
|
||||
and #7
|
||||
tay
|
||||
lda {{^VXLimitTab}},y
|
||||
sta {{$0}}
|
||||
pla
|
||||
---
|
||||
// TODO: x/y limits should be properties
|
||||
on xmoved do with [HasXpos]
|
||||
---
|
||||
cmp #2
|
||||
jcc @left
|
||||
cmp {{$0}}
|
||||
jcc @skip
|
||||
@right:
|
||||
{{!xlimit_right}}
|
||||
jne @skip
|
||||
@left:
|
||||
{{!xlimit_left}}
|
||||
@skip:
|
||||
---
|
||||
on xlimit_right do with [HasXpos]
|
||||
---
|
||||
lda {{$0}}
|
||||
sta {{<xpos}}
|
||||
---
|
||||
on xlimit_left do with [HasXpos]
|
||||
---
|
||||
lda #2
|
||||
sta {{<xpos}}
|
||||
---
|
||||
|
||||
end
|
||||
|
||||
resource DeltaVTable ---
|
||||
; this table tells us which direction to move
|
||||
; for each of the 16 velocity values (-1, 0 or +1)
|
||||
.byte $fe,$fe,$ff,$ff,$ff,$ff,$ff,$00
|
||||
.byte $00,$01,$01,$01,$01,$01,$02,$02
|
||||
---
|
||||
|
||||
resource VAndTable ---
|
||||
; this table contains a bitmask for each of the 16
|
||||
; velocity values -- it's ANDed with a global shift
|
||||
; register that tells us which frames to update position
|
||||
|
||||
.byte %11111111 ;16/8
|
||||
.byte %01110111 ;12/8
|
||||
.byte %11111111 ;8/8
|
||||
.byte %01110111 ;6/8
|
||||
.byte %10101010 ;4/8
|
||||
.byte %01010010 ;3/8
|
||||
.byte %10001000 ;2/8
|
||||
.byte %00000000 ;0
|
||||
.byte %00000000 ;0
|
||||
.byte %10001000 ;2/8
|
||||
.byte %01010010 ;3/8
|
||||
.byte %10101010 ;4/8
|
||||
.byte %01110111 ;6/8
|
||||
.byte %11111111 ;8/8
|
||||
.byte %01110111 ;12/8
|
||||
.byte %11111111 ;16/8
|
||||
---
|
||||
|
||||
resource VMaskTable ---
|
||||
.byte %00000001
|
||||
.byte %00000010
|
||||
.byte %00000100
|
||||
.byte %00001000
|
||||
.byte %00010000
|
||||
.byte %00100000
|
||||
.byte %01000000
|
||||
.byte %10000000
|
||||
---
|
||||
|
||||
resource VReflectTab ---
|
||||
.byte 8,8,8,8,8,8,8,8
|
||||
.byte 0,0,0,0,0,0,0,0
|
||||
---
|
||||
|
||||
/*
|
||||
if 000, X one copy
|
||||
if 001, X X two copies, close
|
||||
if 010, X X two copies, medium
|
||||
if 011, X X X three copies, close
|
||||
if 100, X X Two copies, far
|
||||
if 101, XX one copy, double width
|
||||
if 110, X X X 3 copies, medium
|
||||
if 111, XXXX one copy, quad width
|
||||
*/
|
||||
resource VXLimitTab ---
|
||||
.byte 152-8*1
|
||||
.byte 152-8*3
|
||||
.byte 152-8*5
|
||||
.byte 152-8*5
|
||||
.byte 152-8*9
|
||||
.byte 152-8*2
|
||||
.byte 152-8*9
|
||||
.byte 152-8*4
|
||||
---
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
component VersatilePlayfield
|
||||
data: array of 0..255 baseoffset -1
|
||||
end
|
||||
|
||||
system VersatilePlayfield
|
||||
locals 2
|
||||
on preframe do with [VersatilePlayfield]
|
||||
---
|
||||
lda {{<data}}
|
||||
sta {{$0}}
|
||||
lda {{>data}}
|
||||
sta {{$1}}
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
.if {{arg 0}} = 0
|
||||
lda ({{local 0}}),y
|
||||
tax
|
||||
.endif
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
.if {{arg 0}} = 1
|
||||
lda ({{local 0}}),y
|
||||
sta $00,x
|
||||
.endif
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
lda #0
|
||||
sta PF0
|
||||
sta PF1
|
||||
sta PF2
|
||||
---
|
||||
on checkplatform do with [HasXpos,HasYpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
clc
|
||||
adc #6
|
||||
lsr
|
||||
lsr
|
||||
tay
|
||||
lda {{^PFCollideMask}},y
|
||||
pha
|
||||
lda {{^PFCollideReg}},y
|
||||
pha
|
||||
lda #176 ; TODO: adjust for kernel size
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
and #$fe
|
||||
tay
|
||||
; TODO: use system local pointer
|
||||
pla
|
||||
cmp ({{$0}}),y ; match register?
|
||||
bne @nostop1
|
||||
dey
|
||||
pla
|
||||
and ({{$0}}),y ; mask bitmap?
|
||||
beq @nostop
|
||||
{{!platformstopped}}
|
||||
jmp @done
|
||||
@nostop1:
|
||||
pla
|
||||
@nostop:
|
||||
{{!platformnotstopped}}
|
||||
@done:
|
||||
---
|
||||
end
|
|
@ -266,3 +266,16 @@ LINESD12 = 16
|
|||
SLEEP cycles
|
||||
.endif
|
||||
.endmacro
|
||||
|
||||
;-----------------------------------------------------------
|
||||
; SLEEPH - sleep macro that uses PHA/PLA for 12 cycle delays
|
||||
|
||||
.macro SLEEPH cycles
|
||||
.if cycles >= 9 || cycles = 7
|
||||
pha
|
||||
pla
|
||||
SLEEPH (cycles-7)
|
||||
.else
|
||||
SLEEP cycles
|
||||
.endif
|
||||
.endmacro
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function (mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function (CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
// 6502 DASM syntax
|
||||
|
||||
CodeMirror.defineMode('ecs', function (_config, parserConfig) {
|
||||
var keywords1, keywords2;
|
||||
|
||||
var directives_list = [
|
||||
'begin', 'end',
|
||||
'component', 'system', 'entity', 'scope', 'using', 'demo', 'decode', 'resource',
|
||||
'const', 'locals', 'var',
|
||||
'enum', 'default', 'array', 'baseoffset', 'critical', 'fit', 'asc', 'desc',
|
||||
'on', 'do', 'emit', 'limit',
|
||||
'once', 'foreach', 'with', 'join', 'if', 'select', 'unroll',
|
||||
];
|
||||
var keywords_list = [
|
||||
'processor',
|
||||
'byte', 'word', 'long',
|
||||
'include', 'seg', 'dc', 'ds', 'dv', 'hex', 'err', 'org', 'rorg', 'echo', 'rend',
|
||||
'align', 'subroutine', 'equ', 'eqm', 'set', 'mac', 'endm', 'mexit', 'ifconst',
|
||||
'ifnconst', 'else', 'endif', 'eif', 'repeat', 'repend'
|
||||
];
|
||||
|
||||
var directives = new Map();
|
||||
directives_list.forEach(function (s) { directives.set(s, 'keyword'); });
|
||||
keywords_list.forEach(function (s) { directives.set(s, 'def'); });
|
||||
|
||||
var opcodes = /^\s[a-z][a-z][a-z]\s/i;
|
||||
var numbers = /^(0x[\da-f]+|[$][\da-f]+|[\da-f]+h|[0-7]+o|[01]+b|\d+d?)\b/i;
|
||||
var tags = /^\{\{.*\}\}/;
|
||||
var comment = /^\/\/.*$/;
|
||||
var mlcomment = /^\/\*.*?\*\//s; // TODO
|
||||
var codedelim = /^---/;
|
||||
|
||||
return {
|
||||
startState: function () {
|
||||
return {
|
||||
context: 0
|
||||
};
|
||||
},
|
||||
token: function (stream, state) {
|
||||
if (stream.eatSpace())
|
||||
return null;
|
||||
|
||||
if (stream.match(tags)) {
|
||||
return 'meta';
|
||||
}
|
||||
if (stream.match(comment)) {
|
||||
return 'comment';
|
||||
}
|
||||
if (stream.match(mlcomment)) {
|
||||
return 'comment';
|
||||
}
|
||||
if (stream.match(codedelim)) {
|
||||
state.context = state.context ^ 1;
|
||||
return null;
|
||||
}
|
||||
|
||||
var w;
|
||||
if (stream.eatWhile(/\w/)) {
|
||||
w = stream.current();
|
||||
var cur = w.toLowerCase();
|
||||
var style = directives.get(cur);
|
||||
if (style)
|
||||
return style;
|
||||
|
||||
if (numbers.test(w)) {
|
||||
return 'number';
|
||||
} else if (w == 'comment') {
|
||||
stream.match(mlcomment);
|
||||
return 'comment';
|
||||
} else {
|
||||
return state.context ? 'variable-2' : null;
|
||||
}
|
||||
} else if (stream.eat(';')) {
|
||||
stream.skipToEnd();
|
||||
return 'comment';
|
||||
} else if (stream.eat('"')) {
|
||||
while (w = stream.next()) {
|
||||
if (w == '"')
|
||||
break;
|
||||
|
||||
if (w == '\\')
|
||||
stream.next();
|
||||
}
|
||||
return 'string';
|
||||
} else if (stream.eat('\'')) {
|
||||
if (stream.match(/\\?.'/))
|
||||
return 'number';
|
||||
} else if (stream.eat('$') || stream.eat('#')) {
|
||||
if (stream.eatWhile(/[^;]/i))
|
||||
return 'number';
|
||||
} else if (stream.eat('%')) {
|
||||
if (stream.eatWhile(/[01]/))
|
||||
return 'number';
|
||||
} else {
|
||||
stream.next();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/x-ecs", "ecs");
|
||||
|
||||
});
|
|
@ -223,7 +223,10 @@ export abstract class BasePlatform {
|
|||
return inspectSymbol((this as any) as Platform, sym);
|
||||
}
|
||||
getDebugTree() : {} {
|
||||
return this.saveState();
|
||||
var o : any = { };
|
||||
o.state = this.saveState();
|
||||
if (this.debugSymbols?.debuginfo) o.debuginfo = this.debugSymbols.debuginfo;
|
||||
return o;
|
||||
}
|
||||
readFile(path: string) : FileData {
|
||||
return this.internalFiles[path];
|
||||
|
@ -432,6 +435,7 @@ export function getToolForFilename_6502(fn:string) : string {
|
|||
if (fn.endsWith(".dasm")) return "dasm";
|
||||
if (fn.endsWith(".acme")) return "acme";
|
||||
if (fn.endsWith(".wiz")) return "wiz";
|
||||
if (fn.endsWith(".ecs")) return "ecs";
|
||||
return "dasm"; // .a
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { WorkerError, CodeListingMap, SourceLocation, SourceLine } from "../workertypes";
|
||||
import { WorkerError, CodeListingMap, SourceLocation, SourceLine, SourceLocated, SourceLineLocated } from "../workertypes";
|
||||
|
||||
export interface BASICOptions {
|
||||
dialectName : string; // use this to select the dialect
|
||||
|
@ -50,15 +50,6 @@ export interface BASICOptions {
|
|||
maxArrayElements? : number; // max array elements (all dimensions)
|
||||
}
|
||||
|
||||
// objects that have source code position info
|
||||
export interface SourceLocated {
|
||||
$loc?: SourceLocation;
|
||||
}
|
||||
// statements also have the 'offset' (pc) field from SourceLine
|
||||
export interface SourceLineLocated {
|
||||
$loc?: SourceLine;
|
||||
}
|
||||
|
||||
export class CompileError extends Error {
|
||||
$loc : SourceLocation;
|
||||
constructor(msg: string, loc: SourceLocation) {
|
||||
|
|
|
@ -0,0 +1,213 @@
|
|||
|
||||
# NOTES
|
||||
|
||||
entity scopes contain entities, and are nested
|
||||
also contain segments (code, bss, rodata)
|
||||
components and systems are global
|
||||
component fields are stored in arrays, range of entities, can be bit-packed
|
||||
some values can be constant, are stored in rodata (or loaded immediate)
|
||||
optional components? on or off
|
||||
union components? either X or Y or Z...
|
||||
|
||||
systems receive and send events, execute code on entities
|
||||
systems are generated on a per-scope basis
|
||||
system queries can only contain entities from self and parent scopes
|
||||
starting from the 'init' event walk the event tree
|
||||
include systems that have at least 1 entity in scope (except init?)
|
||||
|
||||
when entering scope, entities are initialized (zero or init w/ data)
|
||||
to change scope, fire event w/ scope name
|
||||
- how to handle bank-switching?
|
||||
|
||||
helps with:
|
||||
- rapid prototyping w/ reasonable defaults
|
||||
- deconstructing objects into arrays
|
||||
- packing/unpacking bitfields
|
||||
- initializing objects
|
||||
- building lookup tables
|
||||
- selecting and iterating objects
|
||||
- managing events
|
||||
- managing memory and scope
|
||||
- converting assets to native formats?
|
||||
- removing unused data
|
||||
|
||||
it's more convenient to have loops be zero-indexed
|
||||
for page cross, temp storage, etc
|
||||
should references be zero-indexed to a field, or global?
|
||||
should we limit # of entities passed to systems? min-max
|
||||
join thru a reference? load both x and y
|
||||
|
||||
code fragments can be parameterized like macros
|
||||
if two fragments are identical, do a JSR
|
||||
(do we have to look for labels?)
|
||||
should events have parameters? e.g. addscore X Y Z
|
||||
how are Z80 arrays working?
|
||||
https://forums.nesdev.org/viewtopic.php?f=20&t=14691
|
||||
https://www.cpcwiki.eu/forum/programming/trying-not-to-use-ix/msg133416/#msg133416
|
||||
|
||||
how to select two between two entities with once? like scoreboard
|
||||
maybe stack-based interpreter?
|
||||
|
||||
can you query specific entities? merge with existing queries?
|
||||
bigints?
|
||||
source/if query?
|
||||
|
||||
only worry about intersection when non-contiguous ranges?
|
||||
|
||||
crazy idea -- full expansion, then relooper
|
||||
|
||||
how to avoid cycle crossing for critical code and data? bin packing
|
||||
|
||||
system define order, action order, entity order, using order?
|
||||
what happens when a system must be nested inside another? like display kernels
|
||||
|
||||
constants? (NTSC vs PAL)
|
||||
|
||||
set operations:
|
||||
|
||||
E = select entities from scope
|
||||
A intersect B
|
||||
A join B
|
||||
loop over E limit N asc/desc
|
||||
select Nth from E
|
||||
run if A intersects B (if)
|
||||
|
||||
|
||||
virtual machine
|
||||
- entityset stack
|
||||
- register states
|
||||
|
||||
|
||||
entity Foo[Bar] { }
|
||||
|
||||
system FrameLoop
|
||||
|
||||
end
|
||||
|
||||
class StaticKernel
|
||||
locals 12
|
||||
func init ---
|
||||
lda {{$0}}
|
||||
sta {{$1}}
|
||||
---
|
||||
func display ---
|
||||
lda {{$0}}
|
||||
sta {{$1}}
|
||||
---
|
||||
end
|
||||
|
||||
Game {
|
||||
superman: [Sprite, ...] {
|
||||
var xpos=12
|
||||
}
|
||||
FrameLoop {
|
||||
a: StaticKernel(lines=30,bgcolor=$30)
|
||||
b: Kernel48(...)
|
||||
c: StaticKernel(...)
|
||||
|
||||
on preframe {
|
||||
}
|
||||
on display {
|
||||
}
|
||||
on postframe {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
systems and scope same thing?
|
||||
nested systems?
|
||||
systems allocated in blocks
|
||||
entities allocated in arrays, take up 1 or more blocks
|
||||
mid-level abstraction for scopes/macros/(banks?)
|
||||
|
||||
|
||||
|
||||
Init
|
||||
with FrameLoop do
|
||||
with StaticKernel do
|
||||
end
|
||||
ResetSwitch:
|
||||
on reset do ResetConsole
|
||||
end
|
||||
StaticKernel:
|
||||
end
|
||||
JoyButton:
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
scopes are banks!
|
||||
banks need to duplicate code and/or rodata
|
||||
- don't split critical code across banks
|
||||
need bank trampoline macro
|
||||
nested scopes for game modes? (title / demo / play)
|
||||
access parent data from child scope
|
||||
|
||||
critical data fields
|
||||
if accessed in critical section, make critical
|
||||
ignore arrays that aren't referenced
|
||||
|
||||
use DASM for multipass?
|
||||
|
||||
processes
|
||||
take up at least one byte if stateful
|
||||
might need free list
|
||||
need jump table?
|
||||
you'd like to change "mode" from any event
|
||||
|
||||
need constant folding, set arrays from other exprs
|
||||
|
||||
a = [Sprite,-Player]
|
||||
foreach a do begin
|
||||
xpos = ypos
|
||||
end
|
||||
|
||||
on gowest do with x:[Location]
|
||||
---
|
||||
ldy {{<room}}
|
||||
lda {{<Room:west}},y
|
||||
sta {{<room}}
|
||||
---
|
||||
on preframe do
|
||||
with y=[SpriteSlot] limit 2
|
||||
with x=y.sprite
|
||||
---
|
||||
lda {{<xpos}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on preframe do
|
||||
foreach x=[Missile,HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
ldy {{<index}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
|
||||
Slice PNGs into sprites
|
||||
Maybe output decoder text
|
||||
Action priorities - before, after
|
||||
Generate C symbols
|
||||
|
||||
|
||||
QUERIES
|
||||
- when to intersect / union / start over
|
||||
- with vs. foreach limit 1 (at top level)
|
||||
- once vs begin/end
|
||||
- mapping of regs vs working set
|
||||
- debug info into source code (and make listing work)
|
||||
|
||||
// subtract one when player wraps around vertically
|
||||
on ymoved do begin
|
||||
---
|
||||
lda {{<ypos}}
|
||||
bne @nowrap
|
||||
---
|
||||
select [#PlayerScore] ---
|
||||
{{!SubBCD2 1}}}
|
||||
---
|
||||
---
|
||||
@nowrap:
|
||||
---
|
||||
end
|
|
@ -0,0 +1,239 @@
|
|||
|
||||
var debug = false;
|
||||
|
||||
export interface BoxConstraints {
|
||||
left?: number;
|
||||
top?: number;
|
||||
width: number;
|
||||
height: number;
|
||||
box?: PlacedBox;
|
||||
label?: string;
|
||||
}
|
||||
|
||||
enum BoxPlacement {
|
||||
TopLeft=0, TopRight=1, BottomLeft=2, BottomRight=3
|
||||
}
|
||||
|
||||
export interface Box {
|
||||
left: number;
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
}
|
||||
|
||||
export interface PlacedBox extends Box {
|
||||
bin: Bin;
|
||||
parents: Box[];
|
||||
place: BoxPlacement;
|
||||
}
|
||||
|
||||
function boxesIntersect(a: Box, b: Box) : boolean {
|
||||
return !(b.left >= a.right || b.right <= a.left || b.top >= a.bottom || b.bottom <= a.top);
|
||||
}
|
||||
|
||||
function boxesContain(a: Box, b: Box) : boolean {
|
||||
return b.left >= a.left && b.top >= a.top && b.right <= a.right && b.bottom <= a.bottom;
|
||||
}
|
||||
|
||||
export class Bin {
|
||||
boxes: Box[] = [];
|
||||
free: Box[] = [];
|
||||
extents: Box = {left:0,top:0,right:0,bottom:0};
|
||||
|
||||
constructor(public readonly binbounds: Box) {
|
||||
this.free.push(binbounds);
|
||||
}
|
||||
getBoxes(bounds: Box, limit: number, boxes?: Box[]) : Box[] {
|
||||
let result = [];
|
||||
if (!boxes) boxes = this.boxes;
|
||||
for (let box of boxes) {
|
||||
//console.log(bounds, box, boxesIntersect(bounds, box))
|
||||
if (boxesIntersect(bounds, box)) {
|
||||
result.push(box);
|
||||
if (result.length >= limit) break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
fits(b: Box) {
|
||||
if (!boxesContain(this.binbounds, b)) {
|
||||
if (debug) console.log('out of bounds!', b.left,b.top,b.right,b.bottom);
|
||||
return false;
|
||||
}
|
||||
if (this.getBoxes(b, 1).length > 0) {
|
||||
if (debug) console.log('intersect!', b.left,b.top,b.right,b.bottom);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bestFit(b: BoxConstraints) : Box | null {
|
||||
let bestscore = 0;
|
||||
let best = null;
|
||||
for (let f of this.free) {
|
||||
if (b.left != null && b.left < f.left) continue;
|
||||
if (b.left != null && b.left + b.width > f.right) continue;
|
||||
if (b.top != null && b.top < f.top) continue;
|
||||
if (b.top != null && b.top + b.height > f.bottom) continue;
|
||||
let dx = (f.right - f.left) - b.width;
|
||||
let dy = (f.bottom - f.top) - b.height;
|
||||
if (dx >= 0 && dy >= 0) {
|
||||
let score = 1 / (1 + dx + dy + f.left * 0.001);
|
||||
if (score > bestscore) {
|
||||
best = f;
|
||||
bestscore = score;
|
||||
if (score == 1) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
anyFit(b: BoxConstraints) : Box | null {
|
||||
let bestscore = 0;
|
||||
let best = null;
|
||||
for (let f of this.free) {
|
||||
let box : Box = {
|
||||
left: b.left != null ? b.left : f.left,
|
||||
right: f.left + b.width,
|
||||
top: b.top != null ? b.top : f.top,
|
||||
bottom: f.top + b.height };
|
||||
if (this.fits(box)) {
|
||||
let score = 1 / (1 + box.left + box.top);
|
||||
if (score > bestscore) {
|
||||
best = f;
|
||||
if (score == 1) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
add(b: PlacedBox) {
|
||||
if (debug) console.log('add', b.left,b.top,b.right,b.bottom);
|
||||
if (!this.fits(b)) {
|
||||
//console.log('collided with', this.getBoxes(b, 1));
|
||||
throw new Error(`bad fit ${b.left} ${b.top} ${b.right} ${b.bottom}`)
|
||||
}
|
||||
// add box to list
|
||||
this.boxes.push(b);
|
||||
this.extents.right = Math.max(this.extents.right, b.right);
|
||||
this.extents.bottom = Math.max(this.extents.bottom, b.bottom);
|
||||
// delete bin
|
||||
for (let p of b.parents) {
|
||||
let i = this.free.indexOf(p);
|
||||
if (i < 0) throw new Error('cannot find parent');
|
||||
if (debug) console.log('removed',p.left,p.top,p.right,p.bottom);
|
||||
this.free.splice(i, 1);
|
||||
// split into new bins
|
||||
// make long columns
|
||||
this.addFree(p.left, p.top, b.left, p.bottom);
|
||||
this.addFree(b.right, p.top, p.right, p.bottom);
|
||||
// make top caps
|
||||
this.addFree(b.left, p.top, b.right, b.top);
|
||||
this.addFree(b.left, b.bottom, b.right, p.bottom);
|
||||
}
|
||||
}
|
||||
addFree(left: number, top: number, right: number, bottom: number) {
|
||||
if (bottom > top && right > left) {
|
||||
let b = { left, top, right, bottom };
|
||||
if (debug) console.log('free',b.left,b.top,b.right,b.bottom);
|
||||
this.free.push(b);
|
||||
}
|
||||
// TODO: merge free boxes?
|
||||
}
|
||||
}
|
||||
|
||||
export class Packer {
|
||||
bins : Bin[] = [];
|
||||
boxes : BoxConstraints[] = [];
|
||||
defaultPlacement : BoxPlacement = BoxPlacement.TopLeft; //TODO
|
||||
|
||||
pack() : boolean {
|
||||
for (let bc of this.boxes) {
|
||||
let box = this.bestPlacement(bc);
|
||||
if (!box) return false;
|
||||
box.bin.add(box);
|
||||
bc.box = box;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bestPlacement(b: BoxConstraints) : PlacedBox | null {
|
||||
for (let bin of this.bins) {
|
||||
let parent = bin.bestFit(b);
|
||||
let approx = false;
|
||||
if (!parent) {
|
||||
parent = bin.anyFit(b);
|
||||
approx = true;
|
||||
if (debug) console.log('anyfit',parent?.left,parent?.top);
|
||||
}
|
||||
if (parent) {
|
||||
let place = this.defaultPlacement;
|
||||
let box = {
|
||||
left: parent.left,
|
||||
top: parent.top,
|
||||
right: parent.left + b.width,
|
||||
bottom: parent.top + b.height
|
||||
};
|
||||
if (b.left != null) {
|
||||
box.left = b.left;
|
||||
box.right = b.left + b.width;
|
||||
}
|
||||
if (b.top != null) {
|
||||
box.top = b.top;
|
||||
box.bottom = b.top + b.height;
|
||||
}
|
||||
if (place == BoxPlacement.BottomLeft || place == BoxPlacement.BottomRight) {
|
||||
let h = box.bottom - box.top;
|
||||
box.top = parent.bottom - h;
|
||||
box.bottom = parent.bottom;
|
||||
}
|
||||
if (place == BoxPlacement.TopRight || place == BoxPlacement.BottomRight) {
|
||||
let w = box.right - box.left;
|
||||
box.left = parent.right - w;
|
||||
box.right = parent.right;
|
||||
}
|
||||
if (debug) console.log('place',b.label,box.left,box.top,box.right,box.bottom,parent?.left,parent?.top);
|
||||
let parents = [parent];
|
||||
// if approx match, might overlap multiple free boxes
|
||||
if (approx) parents = bin.getBoxes(box, 100, bin.free);
|
||||
return { parents, place, bin, ...box };
|
||||
}
|
||||
}
|
||||
if (debug) console.log('cannot place!', b.left,b.top,b.width,b.height);
|
||||
return null;
|
||||
}
|
||||
toSVG() {
|
||||
let s = '';
|
||||
let r = {width:100,height:70}
|
||||
for (let bin of this.bins) {
|
||||
r.width = Math.max(r.width, bin.binbounds.right);
|
||||
r.height = Math.max(r.height, bin.binbounds.bottom);
|
||||
}
|
||||
s += `<svg viewBox="0 0 ${r.width} ${r.height}" xmlns="http://www.w3.org/2000/svg"><style><![CDATA[text {font: 1px sans-serif;}]]></style>`;
|
||||
for (let bin of this.bins) {
|
||||
let be = bin.extents;
|
||||
s += '<g>'
|
||||
s += `<rect width="${be.right-be.left}" height="${be.bottom-be.top}" stroke="black" stroke-width="0.5" fill="none"/>`;
|
||||
let textx = be.right+1;
|
||||
let texty = 0;
|
||||
for (let box of this.boxes) {
|
||||
let b = box.box;
|
||||
if (b) {
|
||||
if (b.bin == bin) s += `<rect width="${b.right-b.left}" height="${b.bottom-b.top}" x="${b.left}" y="${b.top}" stroke="black" stroke-width="0.25" fill="#ccc"/>`;
|
||||
if (b.top == texty) textx += 10; else textx = be.right+1;
|
||||
texty = b.top;
|
||||
if (box.label) s += `<text x="${textx}" y="${texty}" height="1">${box.label}</text>`;
|
||||
}
|
||||
}
|
||||
/*
|
||||
for (let b of bin.free) {
|
||||
s += `<rect width="${b.right-b.left}" height="${b.bottom-b.top}" x="${b.left}" y="${b.top}" stroke="red" stroke-width="0.1" fill="none"/>`;
|
||||
}
|
||||
*/
|
||||
s += '</g>'
|
||||
}
|
||||
s += `</svg>`;
|
||||
return s;
|
||||
}
|
||||
toSVGUrl() {
|
||||
return `data:image/svg+xml;base64,${btoa(this.toSVG())}`;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,851 @@
|
|||
|
||||
import { mergeLocs, Token, Tokenizer, TokenType } from "../tokenizer";
|
||||
import { SourceLocated, SourceLocation } from "../workertypes";
|
||||
import { newDecoder } from "./decoder";
|
||||
import { Action, ActionContext, ArrayType, CodeLiteralNode, CodePlaceholderNode, ComponentType, DataField, DataType, DataValue, ECSError, Entity, EntityArchetype, EntityManager, EntityScope, IntType, Query, RefType, SelectType, SELECT_TYPE, SourceFileExport, System, SystemInstance, SystemInstanceParameters, ComponentFieldPair, Expr, ExprBase, ForwardRef, isLiteral, EntityFieldOp, LExpr, Statement, QueryExpr } from "./ecs";
|
||||
|
||||
export enum ECSTokenType {
|
||||
Ellipsis = 'ellipsis',
|
||||
Operator = 'operator',
|
||||
Relational = 'relational',
|
||||
QuotedString = 'quoted-string',
|
||||
Integer = 'integer',
|
||||
CodeFragment = 'code-fragment',
|
||||
Placeholder = 'placeholder',
|
||||
}
|
||||
|
||||
const OPERATORS = {
|
||||
'IMP': {f:'bimp',p:4},
|
||||
'EQV': {f:'beqv',p:5},
|
||||
'XOR': {f:'bxor',p:6},
|
||||
'OR': {f:'bor',p:7}, // or "lor" for logical
|
||||
'AND': {f:'band',p:8}, // or "land" for logical
|
||||
'||': {f:'lor',p:17}, // not used
|
||||
'&&': {f:'land',p:18}, // not used
|
||||
'=': {f:'eq',p:50},
|
||||
'==': {f:'eq',p:50},
|
||||
'<>': {f:'ne',p:50},
|
||||
'><': {f:'ne',p:50},
|
||||
'!=': {f:'ne',p:50},
|
||||
'#': {f:'ne',p:50},
|
||||
'<': {f:'lt',p:50},
|
||||
'>': {f:'gt',p:50},
|
||||
'<=': {f:'le',p:50},
|
||||
'>=': {f:'ge',p:50},
|
||||
'MIN': {f:'min',p:75},
|
||||
'MAX': {f:'max',p:75},
|
||||
'+': {f:'add',p:100},
|
||||
'-': {f:'sub',p:100},
|
||||
};
|
||||
|
||||
function getOperator(op: string) {
|
||||
return (OPERATORS as any)[op];
|
||||
}
|
||||
|
||||
function getPrecedence(tok: Token): number {
|
||||
switch (tok.type) {
|
||||
case ECSTokenType.Operator:
|
||||
case ECSTokenType.Relational:
|
||||
case TokenType.Ident:
|
||||
let op = getOperator(tok.str);
|
||||
if (op) return op.p;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// is token an end of statement marker? (":" or end of line)
|
||||
function isEOS(tok: Token) {
|
||||
return tok.type == TokenType.EOL || tok.type == TokenType.Comment
|
||||
|| tok.str == ':' || tok.str == 'ELSE'; // TODO: only ELSE if ifElse==true
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
export class ECSCompiler extends Tokenizer {
|
||||
|
||||
currentScope: EntityScope | null = null;
|
||||
currentContext: ActionContext | null = null;
|
||||
includeDebugInfo = false;
|
||||
|
||||
constructor(
|
||||
public readonly em: EntityManager,
|
||||
public readonly isMainFile: boolean) {
|
||||
super();
|
||||
//this.includeEOL = true;
|
||||
this.setTokenRules([
|
||||
{ type: ECSTokenType.Ellipsis, regex: /\.\./ },
|
||||
{ type: ECSTokenType.QuotedString, regex: /".*?"/ },
|
||||
{ type: ECSTokenType.CodeFragment, regex: /---.*?---/ },
|
||||
{ type: ECSTokenType.Integer, regex: /0[xX][A-Fa-f0-9]+/ },
|
||||
{ type: ECSTokenType.Integer, regex: /\$[A-Fa-f0-9]+/ },
|
||||
{ type: ECSTokenType.Integer, regex: /[%][01]+/ },
|
||||
{ type: ECSTokenType.Integer, regex: /\d+/ },
|
||||
{ type: ECSTokenType.Relational, regex: /[=<>][=<>]?/ },
|
||||
{ type: ECSTokenType.Operator, regex: /[.#,:(){}\[\]\-\+]/ },
|
||||
{ type: TokenType.Ident, regex: /[A-Za-z_][A-Za-z0-9_]*/ },
|
||||
{ type: TokenType.Ignore, regex: /\/\/.*?[\n\r]/ },
|
||||
{ type: TokenType.Ignore, regex: /\/\*.*?\*\// },
|
||||
{ type: TokenType.EOL, regex: /[\n\r]+/ },
|
||||
{ type: TokenType.Ignore, regex: /\s+/ },
|
||||
]);
|
||||
this.errorOnCatchAll = true;
|
||||
}
|
||||
|
||||
annotate<T extends SourceLocated>(fn: () => T) {
|
||||
let start = this.peekToken();
|
||||
let obj = fn();
|
||||
let end = this.lasttoken;
|
||||
let $loc = end ? mergeLocs(start.$loc, end.$loc) : start.$loc;
|
||||
if (obj) (obj as SourceLocated).$loc = $loc;
|
||||
return obj;
|
||||
}
|
||||
|
||||
parseFile(text: string, path: string) {
|
||||
this.tokenizeFile(text, path);
|
||||
while (!this.isEOF()) {
|
||||
let top = this.parseTopLevel();
|
||||
if (top) {
|
||||
let t = top;
|
||||
this.annotate(() => t); // TODO? typescript bug?
|
||||
}
|
||||
}
|
||||
this.runDeferred();
|
||||
}
|
||||
|
||||
getImportFile: (path: string) => string;
|
||||
|
||||
importFile(path: string) {
|
||||
if (!this.em.imported[path]) { // already imported?
|
||||
let text = this.getImportFile && this.getImportFile(path);
|
||||
if (!text) this.compileError(`I can't find the import file "${path}".`);
|
||||
this.em.imported[path] = true;
|
||||
let comp = new ECSCompiler(this.em, false);
|
||||
comp.includeDebugInfo = this.includeDebugInfo; // TODO: clone compiler
|
||||
try {
|
||||
comp.parseFile(text, path);
|
||||
} catch (e) {
|
||||
for (var err of comp.errors) this.errors.push(err);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseTopLevel() {
|
||||
//this.skipBlankLines();
|
||||
let tok = this.expectTokens(['component', 'system', 'scope', 'resource', 'import', 'demo', 'comment']);
|
||||
if (tok.str == 'component') {
|
||||
return this.em.defineComponent(this.parseComponentDefinition());
|
||||
}
|
||||
if (tok.str == 'system') {
|
||||
return this.em.defineSystem(this.parseSystem());
|
||||
}
|
||||
if (tok.str == 'scope') {
|
||||
return this.parseScope();
|
||||
}
|
||||
if (tok.str == 'resource') {
|
||||
return this.em.defineSystem(this.parseResource());
|
||||
}
|
||||
if (tok.str == 'import') {
|
||||
let tok = this.expectTokenTypes([ECSTokenType.QuotedString]);
|
||||
let path = tok.str.substring(1, tok.str.length - 1);
|
||||
return this.importFile(path);
|
||||
}
|
||||
if (tok.str == 'demo') {
|
||||
if (this.isMainFile) {
|
||||
let scope = this.parseScope();
|
||||
scope.isDemo = true;
|
||||
this.expectToken('demo');
|
||||
return scope;
|
||||
} else {
|
||||
this.skipDemo(); // don't even parse it, just skip it
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (tok.str == 'comment') {
|
||||
this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||
return;
|
||||
}
|
||||
this.compileError(`Unexpected top-level keyword: ${tok.str}`);
|
||||
}
|
||||
|
||||
skipDemo() {
|
||||
var tok;
|
||||
while ((tok = this.consumeToken()) && !this.isEOF()) {
|
||||
if (tok.str == 'end' && this.peekToken().str == 'demo') {
|
||||
this.consumeToken();
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new ECSError(`Expected "end demo" after a "demo" declaration.`);
|
||||
}
|
||||
|
||||
parseComponentDefinition(): ComponentType {
|
||||
let name = this.expectIdent().str;
|
||||
let fields = [];
|
||||
this.em.deferComponent(name);
|
||||
while (this.peekToken().str != 'end') {
|
||||
fields.push(this.parseComponentField());
|
||||
}
|
||||
this.expectToken('end');
|
||||
return { name, fields };
|
||||
}
|
||||
|
||||
parseComponentField(): DataField {
|
||||
let name = this.expectIdent();
|
||||
this.expectToken(':', 'I expected either a ":" or "end" here.'); // TODO
|
||||
let type = this.parseDataType();
|
||||
return { name: name.str, $loc: name.$loc, ...type };
|
||||
}
|
||||
|
||||
parseDataType(): DataType {
|
||||
if (this.peekToken().type == 'integer') {
|
||||
let lo = this.parseIntegerConstant();
|
||||
this.expectToken('..');
|
||||
let hi = this.parseIntegerConstant();
|
||||
this.checkLowerLimit(lo, -0x80000000, "lower int range");
|
||||
this.checkUpperLimit(hi, 0x7fffffff, "upper int range");
|
||||
this.checkUpperLimit(hi-lo, 0xffffffff, "int range");
|
||||
this.checkLowerLimit(hi, lo, "int range");
|
||||
// TODO: use default value?
|
||||
let defvalue;
|
||||
if (this.ifToken('default')) {
|
||||
defvalue = this.parseIntegerConstant();
|
||||
}
|
||||
// TODO: check types
|
||||
return { dtype: 'int', lo, hi, defvalue } as IntType;
|
||||
}
|
||||
if (this.peekToken().str == '[') {
|
||||
return { dtype: 'ref', query: this.parseQuery() } as RefType;
|
||||
}
|
||||
if (this.ifToken('array')) {
|
||||
let index: IntType | undefined = undefined;
|
||||
if (this.peekToken().type == ECSTokenType.Integer) {
|
||||
index = this.parseDataType() as IntType;
|
||||
}
|
||||
this.expectToken('of');
|
||||
let elem = this.parseDataType();
|
||||
let baseoffset;
|
||||
if (this.ifToken('baseoffset')) {
|
||||
baseoffset = this.parseIntegerConstant();
|
||||
this.checkLowerLimit(baseoffset, -32768, "base offset");
|
||||
this.checkUpperLimit(baseoffset, 32767, "base offset");
|
||||
}
|
||||
return { dtype: 'array', index, elem, baseoffset } as ArrayType;
|
||||
}
|
||||
if (this.ifToken('enum')) {
|
||||
this.expectToken('[');
|
||||
let enumtoks = this.parseList(this.parseEnumIdent, ',');
|
||||
this.expectToken(']');
|
||||
if (enumtoks.length == 0) this.compileError(`must define at least one enum`);
|
||||
let lo = 0;
|
||||
let hi = enumtoks.length-1;
|
||||
this.checkLowerLimit(hi, 0, "enum count");
|
||||
this.checkUpperLimit(hi, 255, "enum count");
|
||||
let enums : {[name:string]:number} = {};
|
||||
for (let i=0; i<=hi; i++)
|
||||
enums[enumtoks[i].str] = i;
|
||||
// TODO: use default value?
|
||||
let defvalue;
|
||||
if (this.ifToken('default')) {
|
||||
defvalue = this.parseIntegerConstant();
|
||||
}
|
||||
return { dtype: 'int', lo, hi, defvalue, enums } as IntType;
|
||||
}
|
||||
throw this.compileError(`I expected a data type here.`);
|
||||
}
|
||||
|
||||
parseEnumIdent() {
|
||||
let tok = this.expectTokenTypes([TokenType.Ident]);
|
||||
return tok;
|
||||
}
|
||||
parseEnumValue(tok: Token, field: IntType) {
|
||||
if (!field.enums) throw new ECSError(`field is not an enum`);
|
||||
let value = field.enums[tok.str];
|
||||
if (value == null) throw new ECSError(`unknown enum "${tok.str}"`);
|
||||
return value;
|
||||
}
|
||||
|
||||
parseDataValue(field: DataField): DataValue | ForwardRef {
|
||||
let tok = this.peekToken();
|
||||
// TODO: move to expr
|
||||
if (tok.type == TokenType.Ident && field.dtype == 'int') {
|
||||
return this.parseEnumValue(this.consumeToken(), field);
|
||||
}
|
||||
if (tok.type == TokenType.Ident) {
|
||||
let entity = this.currentScope?.getEntityByName(tok.str);
|
||||
if (!entity)
|
||||
this.compileError('no entity named "${tok.str}"');
|
||||
else {
|
||||
this.consumeToken();
|
||||
this.expectToken('.');
|
||||
let fieldName = this.expectIdent().str;
|
||||
let constValue = this.currentScope?.getConstValue(entity, fieldName);
|
||||
if (constValue == null)
|
||||
throw new ECSError(`"${fieldName}" is not defined as a constant`, entity);
|
||||
else
|
||||
return constValue;
|
||||
}
|
||||
}
|
||||
if (tok.str == '[') {
|
||||
// TODO: 16-bit?
|
||||
return new Uint8Array(this.parseDataArray());
|
||||
}
|
||||
if (tok.str == '#') {
|
||||
this.consumeToken();
|
||||
let reftype = field.dtype == 'ref' ? field as RefType : undefined;
|
||||
return this.parseEntityForwardRef(reftype);
|
||||
}
|
||||
// TODO?
|
||||
return this.parseIntegerConstant();
|
||||
// TODO: throw this.compileError(`I expected a ${field.dtype} here.`);
|
||||
}
|
||||
|
||||
parseEntityForwardRef(reftype?: RefType): ForwardRef {
|
||||
let token = this.expectIdent();
|
||||
return { reftype, token };
|
||||
}
|
||||
|
||||
parseDataArray() {
|
||||
this.expectToken('[');
|
||||
let arr = this.parseList(this.parseIntegerConstant, ',');
|
||||
this.expectToken(']');
|
||||
return arr;
|
||||
}
|
||||
|
||||
expectInteger(): number {
|
||||
let s = this.consumeToken().str;
|
||||
let i: number;
|
||||
if (s.startsWith('$'))
|
||||
i = parseInt(s.substring(1), 16); // hex $...
|
||||
else if (s.startsWith('%'))
|
||||
i = parseInt(s.substring(1), 2); // binary %...
|
||||
else
|
||||
i = parseInt(s); // default base 10 or 16 (0x...)
|
||||
if (isNaN(i)) this.compileError('There should be an integer here.');
|
||||
return i;
|
||||
}
|
||||
|
||||
parseSystem(): System {
|
||||
let name = this.expectIdent().str;
|
||||
let actions: Action[] = [];
|
||||
let system: System = { name, actions };
|
||||
let cmd;
|
||||
while ((cmd = this.expectTokens(['on', 'locals', 'end']).str) != 'end') {
|
||||
if (cmd == 'on') {
|
||||
let action = this.annotate(() => this.parseAction(system));
|
||||
actions.push(action);
|
||||
} else if (cmd == 'locals') {
|
||||
system.tempbytes = this.parseIntegerConstant();
|
||||
} else {
|
||||
this.compileError(`Unexpected system keyword: ${cmd}`);
|
||||
}
|
||||
}
|
||||
return system;
|
||||
}
|
||||
|
||||
parseResource(): System {
|
||||
let name = this.expectIdent().str;
|
||||
let tempbytes;
|
||||
if (this.peekToken().str == 'locals') {
|
||||
this.consumeToken();
|
||||
tempbytes = this.parseIntegerConstant();
|
||||
}
|
||||
let system: System = { name, tempbytes, actions: [] };
|
||||
let expr = this.annotate(() => this.parseBlockStatement());
|
||||
let action: Action = { expr, event: name };
|
||||
system.actions.push(action);
|
||||
return system;
|
||||
}
|
||||
|
||||
parseAction(system: System): Action {
|
||||
// TODO: unused events?
|
||||
const event = this.expectIdent().str;
|
||||
this.expectToken('do');
|
||||
let fitbytes = undefined;
|
||||
let critical = undefined;
|
||||
if (this.ifToken('critical')) critical = true;
|
||||
if (this.ifToken('fit')) fitbytes = this.parseIntegerConstant();
|
||||
let expr = this.annotate(() => this.parseBlockStatement());
|
||||
//query, join, select, direction,
|
||||
let action : Action = { expr, event, fitbytes, critical };
|
||||
return action as Action;
|
||||
}
|
||||
|
||||
parseQuery() {
|
||||
let q: Query = { include: [] };
|
||||
let start = this.expectToken('[');
|
||||
this.parseList(() => this.parseQueryItem(q), ',');
|
||||
this.expectToken(']');
|
||||
// TODO: other params
|
||||
q.$loc = mergeLocs(start.$loc, this.lasttoken.$loc);
|
||||
return q;
|
||||
}
|
||||
|
||||
parseQueryItem(q: Query) {
|
||||
let prefix = this.peekToken();
|
||||
if (prefix.type != TokenType.Ident) {
|
||||
this.consumeToken();
|
||||
}
|
||||
if (prefix.type == TokenType.Ident) {
|
||||
let cref = this.parseComponentRef();
|
||||
q.include.push(cref);
|
||||
} else if (prefix.str == '-') {
|
||||
let cref = this.parseComponentRef();
|
||||
if (!q.exclude) q.exclude = [];
|
||||
q.exclude.push(cref);
|
||||
} else if (prefix.str == '#') {
|
||||
const scope = this.currentScope;
|
||||
if (scope == null) {
|
||||
throw this.compileError('You can only reference specific entities inside of a scope.');
|
||||
}
|
||||
let eref = this.parseEntityForwardRef();
|
||||
this.deferred.push(() => {
|
||||
let refvalue = this.resolveEntityRef(scope, eref);
|
||||
if (!q.entities) q.entities = [];
|
||||
q.entities.push(scope.entities[refvalue]);
|
||||
});
|
||||
} else {
|
||||
this.compileError(`Query components may be preceded only by a '-'.`);
|
||||
}
|
||||
}
|
||||
|
||||
parseEventName() {
|
||||
return this.expectIdent().str;
|
||||
}
|
||||
|
||||
parseEventList() {
|
||||
return this.parseList(this.parseEventName, ",");
|
||||
}
|
||||
|
||||
parseCode(): string { // TODOActionNode[] {
|
||||
// TODO: add $loc
|
||||
let tok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||
let code = tok.str.substring(3, tok.str.length - 3);
|
||||
// TODO: add after parsing maybe?
|
||||
let lines = code.split('\n');
|
||||
if (this.includeDebugInfo) this.addDebugInfo(lines, tok.$loc.line);
|
||||
code = lines.join('\n');
|
||||
|
||||
//let acomp = new ECSActionCompiler(context);
|
||||
//let nodes = acomp.parseFile(code, this.path);
|
||||
// TODO: return nodes
|
||||
return code;
|
||||
}
|
||||
|
||||
addDebugInfo(lines: string[], startline: number) {
|
||||
const re = /^\s*(;|\/\/|$)/; // ignore comments and blank lines
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if (!lines[i].match(re))
|
||||
lines[i] = this.em.dialect.debug_line(this.path, startline + i) + '\n' + lines[i];
|
||||
}
|
||||
}
|
||||
|
||||
parseScope(): EntityScope {
|
||||
let name = this.expectIdent().str;
|
||||
let scope = this.em.newScope(name, this.currentScope || undefined);
|
||||
scope.filePath = this.path;
|
||||
this.currentScope = scope;
|
||||
let cmd;
|
||||
while ((cmd = this.expectTokens(['end', 'using', 'entity', 'scope', 'comment', 'system']).str) != 'end') {
|
||||
if (cmd == 'using') {
|
||||
this.parseScopeUsing();
|
||||
}
|
||||
if (cmd == 'entity') {
|
||||
this.annotate(() => this.parseEntity());
|
||||
}
|
||||
if (cmd == 'scope') {
|
||||
this.annotate(() => this.parseScope());
|
||||
}
|
||||
if (cmd == 'comment') {
|
||||
this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||
}
|
||||
// TODO: need to make these local names, otherwise we get "duplicate name"
|
||||
if (cmd == 'system') {
|
||||
let sys = this.annotate(() => this.parseSystem());
|
||||
this.em.defineSystem(sys);
|
||||
this.currentScope.newSystemInstanceWithDefaults(sys);
|
||||
}
|
||||
}
|
||||
this.currentScope = scope.parent || null;
|
||||
return scope;
|
||||
}
|
||||
|
||||
parseScopeUsing() {
|
||||
let instlist = this.parseList(this.parseSystemInstanceRef, ',');
|
||||
let params = {};
|
||||
if (this.peekToken().str == 'with') {
|
||||
this.consumeToken();
|
||||
params = this.parseSystemInstanceParameters();
|
||||
}
|
||||
for (let inst of instlist) {
|
||||
inst.params = params;
|
||||
this.currentScope?.newSystemInstance(inst);
|
||||
}
|
||||
}
|
||||
|
||||
parseEntity(): Entity {
|
||||
if (!this.currentScope) { throw this.internalError(); }
|
||||
const scope = this.currentScope;
|
||||
let entname = '';
|
||||
if (this.peekToken().type == TokenType.Ident) {
|
||||
entname = this.expectIdent().str;
|
||||
}
|
||||
let etype = this.parseEntityArchetype();
|
||||
let entity = this.currentScope.newEntity(etype, entname);
|
||||
let cmd2: string;
|
||||
// TODO: remove init?
|
||||
while ((cmd2 = this.expectTokens(['const', 'init', 'var', 'decode', 'end']).str) != 'end') {
|
||||
let cmd = cmd2; // put in scope
|
||||
if (cmd == 'var') cmd = 'init'; // TODO: remove?
|
||||
if (cmd == 'init' || cmd == 'const') {
|
||||
this.parseInitConst(cmd, scope, entity);
|
||||
} else if (cmd == 'decode') {
|
||||
this.parseDecode(scope, entity);
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
parseInitConst(cmd: string, scope: EntityScope, entity: Entity) {
|
||||
// TODO: check data types
|
||||
let name = this.expectIdent().str;
|
||||
let { c, f } = this.getEntityField(entity, name);
|
||||
let symtype = scope.isConstOrInit(c, name);
|
||||
if (symtype && symtype != cmd)
|
||||
this.compileError(`I can't mix const and init values for a given field in a scope.`);
|
||||
this.expectToken('=');
|
||||
let valueOrRef = this.parseDataValue(f);
|
||||
if ((valueOrRef as ForwardRef).token != null) {
|
||||
this.deferred.push(() => {
|
||||
this.lasttoken = (valueOrRef as ForwardRef).token; // for errors
|
||||
let refvalue = this.resolveEntityRef(scope, valueOrRef as ForwardRef);
|
||||
if (cmd == 'const') scope.setConstValue(entity, c, f, refvalue);
|
||||
if (cmd == 'init') scope.setInitValue(entity, c, f, refvalue);
|
||||
});
|
||||
} else {
|
||||
if (cmd == 'const') scope.setConstValue(entity, c, f, valueOrRef as DataValue);
|
||||
if (cmd == 'init') scope.setInitValue(entity, c, f, valueOrRef as DataValue);
|
||||
}
|
||||
}
|
||||
|
||||
parseDecode(scope: EntityScope, entity: Entity) {
|
||||
let decoderid = this.expectIdent().str;
|
||||
let codetok = this.expectTokenTypes([ECSTokenType.CodeFragment]);
|
||||
let code = codetok.str;
|
||||
code = code.substring(3, code.length - 3);
|
||||
let decoder = newDecoder(decoderid, code);
|
||||
if (!decoder) { throw this.compileError(`I can't find a "${decoderid}" decoder.`); }
|
||||
let result;
|
||||
try {
|
||||
result = decoder.parse();
|
||||
} catch (e) {
|
||||
throw new ECSError(e.message, decoder.getErrorLocation(codetok.$loc));
|
||||
}
|
||||
for (let entry of Object.entries(result.properties)) {
|
||||
let { c, f } = this.getEntityField(entity, entry[0]);
|
||||
scope.setConstValue(entity, c, f, entry[1] as DataValue);
|
||||
}
|
||||
}
|
||||
|
||||
getEntityField(e: Entity, name: string): ComponentFieldPair {
|
||||
if (!this.currentScope) { throw this.internalError(); }
|
||||
let comps = this.em.componentsWithFieldName([e.etype], name);
|
||||
if (comps.length == 0) this.compileError(`I couldn't find a field named "${name}" for this entity.`)
|
||||
if (comps.length > 1) this.compileError(`I found more than one field named "${name}" for this entity.`)
|
||||
let component = comps[0];
|
||||
let field = component.fields.find(f => f.name == name);
|
||||
if (!field) { throw this.internalError(); }
|
||||
return { c: component, f: field };
|
||||
}
|
||||
|
||||
parseEntityArchetype(): EntityArchetype {
|
||||
this.expectToken('[');
|
||||
let components = this.parseList(this.parseComponentRef, ',');
|
||||
this.expectToken(']');
|
||||
return { components };
|
||||
}
|
||||
|
||||
parseComponentRef(): ComponentType {
|
||||
let name = this.expectIdent().str;
|
||||
let cref = this.em.getComponentByName(name);
|
||||
if (!cref) this.compileError(`I couldn't find a component named "${name}".`)
|
||||
return cref;
|
||||
}
|
||||
|
||||
findEntityByName(scope: EntityScope, token: Token) {
|
||||
let name = token.str;
|
||||
let eref = scope.entities.find(e => e.name == name);
|
||||
if (!eref) {
|
||||
throw this.compileError(`I couldn't find an entity named "${name}" in this scope.`, token.$loc)
|
||||
}
|
||||
return eref;
|
||||
}
|
||||
|
||||
resolveEntityRef(scope: EntityScope, ref: ForwardRef): number {
|
||||
let id = this.findEntityByName(scope, ref.token).id;
|
||||
if (ref.reftype) {
|
||||
// TODO: make this a function? elo ehi etc?
|
||||
let atypes = this.em.archetypesMatching(ref.reftype.query);
|
||||
let entities = scope.entitiesMatching(atypes);
|
||||
if (entities.length == 0)
|
||||
throw this.compileError(`This entity doesn't seem to fit the reference type.`, ref.token.$loc);
|
||||
id -= entities[0].id;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
parseSystemInstanceRef(): SystemInstance {
|
||||
let name = this.expectIdent().str;
|
||||
let system = this.em.getSystemByName(name);
|
||||
if (!system) throw this.compileError(`I couldn't find a system named "${name}".`, this.lasttoken.$loc);
|
||||
let params = {};
|
||||
let inst = { system, params, id: 0 };
|
||||
return inst;
|
||||
}
|
||||
|
||||
parseSystemInstanceParameters(): SystemInstanceParameters {
|
||||
let scope = this.currentScope;
|
||||
if (scope == null) throw this.internalError();
|
||||
if (this.peekToken().str == '[') {
|
||||
return { query: this.parseQuery() };
|
||||
}
|
||||
this.expectToken('#');
|
||||
let entname = this.expectIdent();
|
||||
this.expectToken('.');
|
||||
let fieldname = this.expectIdent();
|
||||
let entity = this.findEntityByName(scope, entname);
|
||||
let cf = this.getEntityField(entity, fieldname.str);
|
||||
return { refEntity: entity, refField: cf };
|
||||
}
|
||||
|
||||
exportToFile(src: SourceFileExport) {
|
||||
this.em.exportToFile(src);
|
||||
}
|
||||
|
||||
export() {
|
||||
let src = new SourceFileExport();
|
||||
src.line(this.em.dialect.debug_file(this.path));
|
||||
for (let path of Object.keys(this.em.imported))
|
||||
src.line(this.em.dialect.debug_file(path));
|
||||
this.exportToFile(src);
|
||||
return src.toString();
|
||||
}
|
||||
|
||||
checkUpperLimit(value: number, upper: number, what: string) {
|
||||
if (value > upper) this.compileError(`This ${what} is too high; must be ${upper} or less`);
|
||||
}
|
||||
checkLowerLimit(value: number, lower: number, what: string) {
|
||||
if (value < lower) this.compileError(`This ${what} is too low; must be ${lower} or more`);
|
||||
}
|
||||
|
||||
// expression stuff
|
||||
|
||||
parseConstant(): DataValue {
|
||||
let expr = this.parseExpr();
|
||||
expr = this.em.evalExpr(expr, this.currentScope);
|
||||
if (isLiteral(expr)) return expr.value;
|
||||
throw this.compileError('This expression is not a constant.');
|
||||
}
|
||||
parseIntegerConstant(): number {
|
||||
let value = this.parseConstant();
|
||||
if (typeof value === 'number') return value;
|
||||
throw this.compileError('This expression is not an integer.');
|
||||
}
|
||||
parseExpr(): Expr {
|
||||
var startloc = this.peekToken().$loc;
|
||||
var expr = this.parseExpr1(this.parsePrimary(), 0);
|
||||
var endloc = this.lasttoken.$loc;
|
||||
expr.$loc = mergeLocs(startloc, endloc);
|
||||
return expr;
|
||||
}
|
||||
parseExpr1(left: Expr, minPred: number): Expr {
|
||||
let look = this.peekToken();
|
||||
while (getPrecedence(look) >= minPred) {
|
||||
let op = this.consumeToken();
|
||||
let right: Expr = this.parsePrimary();
|
||||
look = this.peekToken();
|
||||
while (getPrecedence(look) > getPrecedence(op)) {
|
||||
right = this.parseExpr1(right, getPrecedence(look));
|
||||
look = this.peekToken();
|
||||
}
|
||||
var opfn = getOperator(op.str).f;
|
||||
// use logical operators instead of bitwise?
|
||||
if (op.str == 'and') opfn = 'land';
|
||||
if (op.str == 'or') opfn = 'lor';
|
||||
var valtype = this.exprTypeForOp(opfn, left, right, op);
|
||||
left = { valtype:valtype, op:opfn, left: left, right: right };
|
||||
}
|
||||
return left;
|
||||
}
|
||||
parsePrimary(): Expr {
|
||||
let tok = this.consumeToken();
|
||||
switch (tok.type) {
|
||||
case ECSTokenType.Integer:
|
||||
this.pushbackToken(tok);
|
||||
let value = this.expectInteger();
|
||||
let valtype : IntType = { dtype: 'int', lo: value, hi: value };
|
||||
return { valtype, value };
|
||||
case TokenType.Ident:
|
||||
if (tok.str == 'not') {
|
||||
let expr = this.parsePrimary();
|
||||
let valtype : IntType = { dtype: 'int', lo: 0, hi: 1 };
|
||||
return { valtype, op: 'lnot', expr: expr };
|
||||
} else {
|
||||
this.pushbackToken(tok);
|
||||
return this.parseVarSubscriptOrFunc();
|
||||
}
|
||||
case ECSTokenType.Operator:
|
||||
if (tok.str == '(') {
|
||||
let expr = this.parseExpr();
|
||||
this.expectToken(')', `There should be another expression or a ")" here.`);
|
||||
return expr;
|
||||
} else if (tok.str == '-') {
|
||||
let expr = this.parsePrimary(); // TODO: -2^2=-4 and -2-2=-4
|
||||
let valtype = (expr as ExprBase).valtype;
|
||||
if (valtype?.dtype == 'int') {
|
||||
let hi = Math.abs(valtype.hi);
|
||||
let negtype : IntType = { dtype: 'int', lo: -hi, hi: hi };
|
||||
return { valtype: negtype, op: 'neg', expr: expr };
|
||||
}
|
||||
} else if (tok.str == '+') {
|
||||
return this.parsePrimary(); // ignore unary +
|
||||
}
|
||||
default:
|
||||
throw this.compileError(`The expression is incomplete.`);
|
||||
}
|
||||
}
|
||||
parseVarSubscriptOrFunc(): LExpr {
|
||||
var tok = this.consumeToken();
|
||||
switch (tok.type) {
|
||||
case TokenType.Ident:
|
||||
// component:field
|
||||
if (this.ifToken(':')) {
|
||||
let ftok = this.consumeToken();
|
||||
let component = this.em.getComponentByName(tok.str);
|
||||
if (!component) throw this.compileError(`A component named "${tok.str}" has not been defined.`);
|
||||
let field = component.fields.find(f => f.name == ftok.str);
|
||||
if (!field) throw this.compileError(`There is no "${ftok.str}" field in the ${tok.str} component.`);
|
||||
if (!this.currentScope) throw this.compileError(`This operation only works inside of a scope.`);
|
||||
let atypes = this.em.archetypesMatching({ include: [component] })
|
||||
let entities = this.currentScope.entitiesMatching(atypes);
|
||||
return { entities, field } as EntityFieldOp;
|
||||
}
|
||||
// entity.field
|
||||
if (this.ifToken('.')) {
|
||||
let ftok = this.consumeToken();
|
||||
if (!this.currentScope) throw this.compileError(`This operation only works inside of a scope.`);
|
||||
let entity = this.currentScope.getEntityByName(tok.str);
|
||||
if (!entity) throw this.compileError(`An entity named "${tok.str}" has not been defined.`);
|
||||
let component = this.em.singleComponentWithFieldName([entity.etype], ftok.str, ftok);
|
||||
let field = component.fields.find(f => f.name == ftok.str);
|
||||
if (!field) throw this.compileError(`There is no "${ftok.str}" field in this entity.`);
|
||||
let entities = [entity];
|
||||
return { entities, field } as EntityFieldOp;
|
||||
}
|
||||
let args : Expr[] = [];
|
||||
if (this.ifToken('(')) {
|
||||
args = this.parseExprList();
|
||||
this.expectToken(')', `There should be another expression or a ")" here.`);
|
||||
}
|
||||
var loc = mergeLocs(tok.$loc, this.lasttoken.$loc);
|
||||
var valtype = this.exprTypeForSubscript(tok.str, args, loc);
|
||||
return { valtype: valtype, name: tok.str, args: args, $loc:loc };
|
||||
default:
|
||||
throw this.compileError(`There should be a variable name here.`);
|
||||
}
|
||||
}
|
||||
parseLexpr(): LExpr {
|
||||
var lexpr = this.parseVarSubscriptOrFunc();
|
||||
//this.vardefs[lexpr.name] = lexpr;
|
||||
//this.validateVarName(lexpr);
|
||||
return lexpr;
|
||||
}
|
||||
exprTypeForOp(fnname: string, left: Expr, right: Expr, optok: Token) : DataType {
|
||||
return { dtype: 'int', lo:0, hi:255 }; // TODO?
|
||||
}
|
||||
exprTypeForSubscript(fnname: string, args: Expr[], loc: SourceLocation) : DataType {
|
||||
return { dtype: 'int', lo:0, hi:255 }; // TODO?
|
||||
}
|
||||
parseLexprList(): LExpr[] {
|
||||
return this.parseList(this.parseLexpr, ',');
|
||||
}
|
||||
parseExprList(): Expr[] {
|
||||
return this.parseList(this.parseExpr, ',');
|
||||
}
|
||||
// TODO: annotate with location
|
||||
parseBlockStatement(): Statement {
|
||||
let valtype : IntType = { dtype:'int', lo:0, hi: 0 } // TODO?
|
||||
if (this.peekToken().type == ECSTokenType.CodeFragment) {
|
||||
return { valtype, code: this.parseCode() };
|
||||
}
|
||||
if (this.ifToken('begin')) {
|
||||
let stmts = [];
|
||||
while (this.peekToken().str != 'end') {
|
||||
stmts.push(this.annotate(() => this.parseBlockStatement()));
|
||||
}
|
||||
this.expectToken('end');
|
||||
return { valtype, stmts };
|
||||
}
|
||||
let cmd = this.peekToken();
|
||||
if (SELECT_TYPE.includes(cmd.str as any)) {
|
||||
return this.parseQueryStatement();
|
||||
}
|
||||
throw this.compileError(`There should be a statement or "end" here.`, cmd.$loc);
|
||||
}
|
||||
parseQueryStatement() : QueryExpr {
|
||||
// TODO: include modifiers in error msg
|
||||
const select = this.expectTokens(SELECT_TYPE).str as SelectType; // TODO: type check?
|
||||
let all = this.ifToken('all') != null;
|
||||
let query = undefined;
|
||||
let join = undefined;
|
||||
if (select == 'once') {
|
||||
if (this.peekToken().str == '[') this.compileError(`A "${select}" action can't include a query.`)
|
||||
} else {
|
||||
query = this.parseQuery();
|
||||
}
|
||||
if (select == 'join') {
|
||||
this.expectToken('with');
|
||||
join = this.parseQuery();
|
||||
}
|
||||
if (this.ifToken('limit')) {
|
||||
if (!query) { this.compileError(`A "${select}" query can't include a limit.`); }
|
||||
else query.limit = this.parseIntegerConstant();
|
||||
}
|
||||
const all_modifiers = ['asc', 'desc']; // TODO
|
||||
const modifiers = this.parseModifiers(all_modifiers);
|
||||
let direction = undefined;
|
||||
if (modifiers['asc']) direction = 'asc';
|
||||
else if (modifiers['desc']) direction = 'desc';
|
||||
let body = this.annotate(() => this.parseBlockStatement());
|
||||
return { select, query, join, direction, all, stmts: [body], loop: select == 'foreach' } as QueryExpr;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
export class ECSActionCompiler extends Tokenizer {
|
||||
constructor(
|
||||
public readonly context: ActionContext) {
|
||||
super();
|
||||
this.setTokenRules([
|
||||
{ type: ECSTokenType.Placeholder, regex: /\{\{.*?\}\}/ },
|
||||
{ type: TokenType.CatchAll, regex: /[^{\n]+\n*/ },
|
||||
]);
|
||||
this.errorOnCatchAll = false;
|
||||
}
|
||||
|
||||
parseFile(text: string, path: string) {
|
||||
this.tokenizeFile(text, path);
|
||||
let nodes = [];
|
||||
while (!this.isEOF()) {
|
||||
let tok = this.consumeToken();
|
||||
if (tok.type == ECSTokenType.Placeholder) {
|
||||
let args = tok.str.substring(2, tok.str.length - 2).split(/\s+/);
|
||||
nodes.push(new CodePlaceholderNode(this.context, tok.$loc, args));
|
||||
} else if (tok.type == TokenType.CatchAll) {
|
||||
nodes.push(new CodeLiteralNode(this.context, tok.$loc, tok.str));
|
||||
}
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
|
||||
import { SourceLocation } from "../workertypes";
|
||||
import { DataValue, ECSError } from "./ecs";
|
||||
|
||||
export interface DecoderResult {
|
||||
properties: {[name: string] : DataValue}
|
||||
}
|
||||
|
||||
abstract class LineDecoder {
|
||||
curline: number = 0; // for debugging, zero-indexed
|
||||
lines : string[][]; // array of token arrays
|
||||
|
||||
constructor(
|
||||
text: string
|
||||
) {
|
||||
// split the text into lines and into tokens
|
||||
this.lines = text.split('\n').map(s => s.trim()).filter(s => !!s).map(s => s.split(/\s+/));
|
||||
}
|
||||
|
||||
decodeBits(s: string, n: number, msbfirst: boolean) {
|
||||
if (s.length != n) throw new ECSError(`Expected ${n} characters`);
|
||||
let b = 0;
|
||||
for (let i=0; i<n; i++) {
|
||||
let bit;
|
||||
let ch = s.charAt(i);
|
||||
if (ch == 'x' || ch == 'X' || ch == '1') bit = 1;
|
||||
else if (ch == '.' || ch == '0') bit = 0;
|
||||
else throw new ECSError('need x or . (or 0 or 1)');
|
||||
if (bit) {
|
||||
if (msbfirst) b |= 1 << (n-1-i);
|
||||
else b |= 1 << i;
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
assertTokens(toks: string[], count: number) {
|
||||
if (toks.length != count) throw new ECSError(`Expected ${count} tokens on line.`);
|
||||
}
|
||||
|
||||
hex(s: string) {
|
||||
let v = parseInt(s, 16);
|
||||
if (isNaN(v)) throw new ECSError(`Invalid hex value: ${s}`)
|
||||
return v;
|
||||
}
|
||||
|
||||
getErrorLocation($loc: SourceLocation): SourceLocation {
|
||||
// TODO: blank lines mess this up
|
||||
$loc.line += this.curline + 1;
|
||||
return $loc;
|
||||
}
|
||||
|
||||
abstract parse() : DecoderResult;
|
||||
}
|
||||
|
||||
export class VCSSpriteDecoder extends LineDecoder {
|
||||
parse() {
|
||||
let height = this.lines.length;
|
||||
let bitmapdata = new Uint8Array(height);
|
||||
let colormapdata = new Uint8Array(height);
|
||||
for (let i=0; i<height; i++) {
|
||||
this.curline = height - 1 - i;
|
||||
let toks = this.lines[this.curline];
|
||||
this.assertTokens(toks, 2);
|
||||
bitmapdata[i] = this.decodeBits(toks[0], 8, true);
|
||||
colormapdata[i] = this.hex(toks[1]);
|
||||
}
|
||||
return {
|
||||
properties: {
|
||||
bitmapdata, colormapdata, height: height-1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VCSBitmapDecoder extends LineDecoder {
|
||||
parse() {
|
||||
let height = this.lines.length;
|
||||
let bitmapdata = new Uint8Array(height);
|
||||
for (let i=0; i<height; i++) {
|
||||
this.curline = height - 1 - i;
|
||||
let toks = this.lines[this.curline];
|
||||
this.assertTokens(toks, 1);
|
||||
bitmapdata[i] = this.decodeBits(toks[0], 8, true);
|
||||
}
|
||||
return {
|
||||
properties: {
|
||||
bitmapdata, height: height-1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VCSPlayfieldDecoder extends LineDecoder {
|
||||
parse() {
|
||||
let height = this.lines.length;
|
||||
let pf = new Uint32Array(height);
|
||||
for (let i=0; i<height; i++) {
|
||||
this.curline = height - 1 - i;
|
||||
let toks = this.lines[this.curline];
|
||||
this.assertTokens(toks, 1);
|
||||
let pf0 = this.decodeBits(toks[0].substring(0,4), 4, false) << 4;
|
||||
let pf1 = this.decodeBits(toks[0].substring(4,12), 8, true);
|
||||
let pf2 = this.decodeBits(toks[0].substring(12,20), 8, false);
|
||||
pf[i] = (pf0 << 0) | (pf1 << 8) | (pf2 << 16);
|
||||
}
|
||||
return {
|
||||
properties: {
|
||||
pf
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class VCSVersatilePlayfieldDecoder extends LineDecoder {
|
||||
parse() {
|
||||
let height = this.lines.length;
|
||||
let data = new Uint8Array(height * 2);
|
||||
data.fill(0x3f);
|
||||
// pf0 pf1 pf2 colupf colubk ctrlpf trash
|
||||
const regs = [0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x3f];
|
||||
let prev = [0,0,0,0,0,0,0];
|
||||
let cur = [0,0,0,0,0,0,0];
|
||||
for (let i=0; i<height; i++) {
|
||||
let dataofs = height*2 - i*2;
|
||||
this.curline = i;
|
||||
let toks = this.lines[this.curline];
|
||||
if (toks.length == 2) {
|
||||
data[dataofs - 1] = this.hex(toks[0]);
|
||||
data[dataofs - 2] = this.hex(toks[1]);
|
||||
continue;
|
||||
}
|
||||
this.assertTokens(toks, 4);
|
||||
cur[0] = this.decodeBits(toks[0].substring(0,4), 4, false) << 4;
|
||||
cur[1] = this.decodeBits(toks[0].substring(4,12), 8, true);
|
||||
cur[2] = this.decodeBits(toks[0].substring(12,20), 8, false);
|
||||
if (toks[1] != '..') cur[3] = this.hex(toks[1]);
|
||||
if (toks[2] != '..') cur[4] = this.hex(toks[2]);
|
||||
if (toks[3] != '..') cur[5] = this.hex(toks[3]);
|
||||
let changed = [];
|
||||
for (let j=0; j<cur.length; j++) {
|
||||
if (cur[j] != prev[j])
|
||||
changed.push(j);
|
||||
}
|
||||
if (changed.length > 1) {
|
||||
console.log(changed, cur, prev);
|
||||
throw new ECSError(`More than one register change in line ${i+1}: [${changed}]`);
|
||||
}
|
||||
let chgidx = changed.length ? changed[0] : regs.length-1;
|
||||
data[dataofs - 1] = regs[chgidx];
|
||||
data[dataofs - 2] = cur[chgidx];
|
||||
prev[chgidx] = cur[chgidx];
|
||||
}
|
||||
return {
|
||||
properties: {
|
||||
data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VCSBitmap48Decoder extends LineDecoder {
|
||||
parse() {
|
||||
let height = this.lines.length;
|
||||
let bitmap0 = new Uint8Array(height);
|
||||
let bitmap1 = new Uint8Array(height);
|
||||
let bitmap2 = new Uint8Array(height);
|
||||
let bitmap3 = new Uint8Array(height);
|
||||
let bitmap4 = new Uint8Array(height);
|
||||
let bitmap5 = new Uint8Array(height);
|
||||
for (let i=0; i<height; i++) {
|
||||
this.curline = height - 1 - i;
|
||||
let toks = this.lines[this.curline];
|
||||
this.assertTokens(toks, 1);
|
||||
bitmap0[i] = this.decodeBits(toks[0].slice(0,8), 8, true);
|
||||
bitmap1[i] = this.decodeBits(toks[0].slice(8,16), 8, true);
|
||||
bitmap2[i] = this.decodeBits(toks[0].slice(16,24), 8, true);
|
||||
bitmap3[i] = this.decodeBits(toks[0].slice(24,32), 8, true);
|
||||
bitmap4[i] = this.decodeBits(toks[0].slice(32,40), 8, true);
|
||||
bitmap5[i] = this.decodeBits(toks[0].slice(40,48), 8, true);
|
||||
}
|
||||
return {
|
||||
properties: {
|
||||
bitmap0, bitmap1, bitmap2, bitmap3, bitmap4, bitmap5,
|
||||
height: height-1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function newDecoder(name: string, text: string) : LineDecoder | undefined {
|
||||
let cons = (DECODERS as any)[name];
|
||||
if (cons) return new cons(text);
|
||||
}
|
||||
|
||||
const DECODERS = {
|
||||
'vcs_sprite': VCSSpriteDecoder,
|
||||
'vcs_bitmap': VCSBitmapDecoder,
|
||||
'vcs_playfield': VCSPlayfieldDecoder,
|
||||
'vcs_versatile': VCSVersatilePlayfieldDecoder,
|
||||
'vcs_bitmap48': VCSBitmap48Decoder,
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
|||
import { readFileSync } from "fs";
|
||||
import { ECSCompiler } from "./compiler";
|
||||
import { Dialect_CA65, EntityManager, SourceFileExport } from "./ecs";
|
||||
|
||||
class ECSMain {
|
||||
|
||||
compiler = new ECSCompiler(new EntityManager(new Dialect_CA65()), true); // TODO
|
||||
|
||||
constructor(readonly args: string[]) {
|
||||
}
|
||||
|
||||
run() {
|
||||
for (let path of this.args) {
|
||||
let text = readFileSync(path, 'utf-8');
|
||||
try {
|
||||
this.compiler.parseFile(text, path);
|
||||
if (this.compiler.errors.length == 0) {
|
||||
let file = new SourceFileExport();
|
||||
this.compiler.exportToFile(file);
|
||||
console.log(file.toString());
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
for (let err of this.compiler.errors) {
|
||||
console.error(`${err.path}:${err.line}:${err.start}: ${err.msg}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new ECSMain(process.argv.slice(2)).run();
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"preserveConstEnums": true,
|
||||
"alwaysStrict": true,
|
||||
"strictNullChecks": true,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
|
||||
import type { SourceLocation, SourceLine, WorkerError, SourceLocated } from "./workertypes";
|
||||
|
||||
export class CompileError extends Error {
|
||||
$loc: SourceLocation;
|
||||
constructor(msg: string, loc: SourceLocation) {
|
||||
super(msg);
|
||||
Object.setPrototypeOf(this, CompileError.prototype);
|
||||
this.$loc = loc;
|
||||
}
|
||||
}
|
||||
|
||||
export function mergeLocs(a: SourceLocation, b: SourceLocation): SourceLocation {
|
||||
return {
|
||||
line: Math.min(a.line, b.line),
|
||||
start: Math.min(a.start, b.start),
|
||||
end: Math.max(a.end, b.end),
|
||||
label: a.label || b.label,
|
||||
path: a.path || b.path,
|
||||
}
|
||||
}
|
||||
|
||||
export enum TokenType {
|
||||
EOF = 'eof',
|
||||
EOL = 'eol',
|
||||
Ident = 'ident',
|
||||
Comment = 'comment',
|
||||
Ignore = 'ignore',
|
||||
CatchAll = 'catch-all',
|
||||
}
|
||||
|
||||
export class Token implements SourceLocated {
|
||||
str: string;
|
||||
type: string;
|
||||
eol: boolean; // end of line?
|
||||
$loc: SourceLocation;
|
||||
}
|
||||
|
||||
export class TokenRule {
|
||||
type: string;
|
||||
regex: RegExp;
|
||||
}
|
||||
|
||||
const CATCH_ALL_RULES: TokenRule[] = [
|
||||
{ type: TokenType.CatchAll, regex: /.+?/ }
|
||||
]
|
||||
|
||||
function re_escape(rule: TokenRule): string {
|
||||
return `(${rule.regex.source})`;
|
||||
}
|
||||
|
||||
export class TokenizerRuleSet {
|
||||
rules: TokenRule[];
|
||||
regex: RegExp;
|
||||
constructor(rules: TokenRule[]) {
|
||||
this.rules = rules.concat(CATCH_ALL_RULES);
|
||||
var pattern = this.rules.map(re_escape).join('|');
|
||||
this.regex = new RegExp(pattern, "gs"); // global, dotall
|
||||
}
|
||||
}
|
||||
|
||||
export class Tokenizer {
|
||||
ruleset: TokenizerRuleSet;
|
||||
lineindex: number[];
|
||||
path: string;
|
||||
lineno: number;
|
||||
tokens: Token[];
|
||||
lasttoken: Token;
|
||||
errors: WorkerError[];
|
||||
curlabel: string;
|
||||
eof: Token;
|
||||
errorOnCatchAll = false;
|
||||
deferred: (() => void)[] = [];
|
||||
|
||||
constructor() {
|
||||
this.errors = [];
|
||||
this.lineno = 0;
|
||||
this.lineindex = [];
|
||||
this.tokens = [];
|
||||
}
|
||||
setTokenRuleSet(ruleset: TokenizerRuleSet) {
|
||||
this.ruleset = ruleset;
|
||||
}
|
||||
setTokenRules(rules: TokenRule[]) {
|
||||
this.setTokenRuleSet(new TokenizerRuleSet(rules));
|
||||
}
|
||||
tokenizeFile(contents: string, path: string) {
|
||||
this.path = path;
|
||||
let m;
|
||||
let re = /\n|\r\n?/g;
|
||||
this.lineindex.push(0);
|
||||
while (m = re.exec(contents)) {
|
||||
this.lineindex.push(m.index);
|
||||
}
|
||||
this._tokenize(contents);
|
||||
this.eof = { type: TokenType.EOF, str: "", eol: true, $loc: { path: this.path, line: this.lineno } };
|
||||
this.pushToken(this.eof);
|
||||
}
|
||||
_tokenize(text: string): void {
|
||||
// iterate over each token via re_toks regex
|
||||
let m: RegExpMatchArray;
|
||||
this.lineno = 0;
|
||||
while (m = this.ruleset.regex.exec(text)) {
|
||||
let found = false;
|
||||
// find line #
|
||||
while (m.index >= this.lineindex[this.lineno]) {
|
||||
this.lineno++;
|
||||
}
|
||||
// find out which capture group was matched, and thus token type
|
||||
let rules = this.ruleset.rules;
|
||||
for (let i = 0; i < rules.length; i++) {
|
||||
let s: string = m[i + 1];
|
||||
if (s != null) {
|
||||
found = true;
|
||||
let col = m.index - (this.lineindex[this.lineno-1] || -1) - 1;
|
||||
let loc = { path: this.path, line: this.lineno, start: col, end: col + s.length };
|
||||
let rule = rules[i];
|
||||
// add token to list
|
||||
switch (rule.type) {
|
||||
case TokenType.CatchAll:
|
||||
if (this.errorOnCatchAll) {
|
||||
this.compileError(`I didn't expect the character "${m[0]}" here.`, loc);
|
||||
}
|
||||
default:
|
||||
this.pushToken({ str: s, type: rule.type, $loc: loc, eol: false });
|
||||
break;
|
||||
case TokenType.EOL:
|
||||
// set EOL for last token
|
||||
if (this.tokens.length)
|
||||
this.tokens[this.tokens.length-1].eol = true;
|
||||
case TokenType.Comment:
|
||||
case TokenType.Ignore:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
this.compileError(`Could not parse token: <<${m[0]}>>`)
|
||||
}
|
||||
}
|
||||
}
|
||||
pushToken(token: Token) {
|
||||
this.tokens.push(token);
|
||||
}
|
||||
addError(msg: string, loc?: SourceLocation) {
|
||||
let tok = this.lasttoken || this.peekToken();
|
||||
if (!loc) loc = tok.$loc;
|
||||
this.errors.push({ path: loc.path, line: loc.line, label: this.curlabel, start: loc.start, end: loc.end, msg: msg });
|
||||
}
|
||||
internalError() {
|
||||
return this.compileError("Internal error.");
|
||||
}
|
||||
notImplementedError() {
|
||||
return this.compileError("Not yet implemented.");
|
||||
}
|
||||
compileError(msg: string, loc?: SourceLocation, loc2?: SourceLocation) : CompileError {
|
||||
this.addError(msg, loc);
|
||||
//if (loc2 != null) this.addError(`...`, loc2);
|
||||
let e = new CompileError(msg, loc);
|
||||
throw e;
|
||||
return e;
|
||||
}
|
||||
peekToken(lookahead?: number): Token {
|
||||
let tok = this.tokens[lookahead || 0];
|
||||
return tok ? tok : this.eof;
|
||||
}
|
||||
consumeToken(): Token {
|
||||
let tok = this.lasttoken = (this.tokens.shift() || this.eof);
|
||||
return tok;
|
||||
}
|
||||
ifToken(match: string): Token | undefined {
|
||||
if (this.peekToken().str == match) return this.consumeToken();
|
||||
}
|
||||
expectToken(str: string, msg?: string): Token {
|
||||
let tok = this.consumeToken();
|
||||
let tokstr = tok.str;
|
||||
if (str != tokstr) {
|
||||
this.compileError(msg || `There should be a "${str}" here.`);
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
expectTokens(strlist: readonly string[], msg?: string): Token {
|
||||
let tok = this.consumeToken();
|
||||
let tokstr = tok.str;
|
||||
if (!strlist.includes(tokstr)) {
|
||||
this.compileError(msg || `These keywords are valid here: ${strlist.join(', ')}`);
|
||||
}
|
||||
return tok;
|
||||
}
|
||||
parseModifiers(modifiers: string[]): { [modifier: string]: boolean } {
|
||||
let result = {};
|
||||
do {
|
||||
var tok = this.peekToken();
|
||||
if (modifiers.indexOf(tok.str) < 0)
|
||||
return result;
|
||||
this.consumeToken();
|
||||
result[tok.str] = true;
|
||||
} while (tok != null);
|
||||
}
|
||||
expectIdent(msg?: string): Token {
|
||||
let tok = this.consumeToken();
|
||||
if (tok.type != TokenType.Ident)
|
||||
this.compileError(msg || `There should be an identifier here.`);
|
||||
return tok;
|
||||
}
|
||||
pushbackToken(tok: Token) {
|
||||
this.tokens.unshift(tok);
|
||||
}
|
||||
isEOF() {
|
||||
return this.tokens.length == 0 || this.peekToken().type == 'eof'; // TODO?
|
||||
}
|
||||
expectEOL(msg?: string) {
|
||||
let tok = this.consumeToken();
|
||||
if (tok.type != TokenType.EOL)
|
||||
this.compileError(msg || `There's too much stuff on this line.`);
|
||||
}
|
||||
skipBlankLines() {
|
||||
this.skipTokenTypes(['eol']);
|
||||
}
|
||||
skipTokenTypes(types: string[]) {
|
||||
while (types.includes(this.peekToken().type))
|
||||
this.consumeToken();
|
||||
}
|
||||
expectTokenTypes(types: string[], msg?: string) {
|
||||
let tok = this.consumeToken();
|
||||
if (!types.includes(tok.type))
|
||||
this.compileError(msg || `There should be a ${types.map((s) => `"${s}"`).join(' or ')} here. not a "${tok.type}".`);
|
||||
return tok;
|
||||
}
|
||||
parseList<T>(parseFunc:()=>T, delim:string): T[] {
|
||||
var sep;
|
||||
var list = [];
|
||||
do {
|
||||
var el = parseFunc.bind(this)(); // call parse function
|
||||
if (el != null) list.push(el); // add parsed element to list
|
||||
sep = this.consumeToken(); // consume seperator token
|
||||
} while (sep.str == delim);
|
||||
this.pushbackToken(sep);
|
||||
return list;
|
||||
}
|
||||
runDeferred() {
|
||||
while (this.deferred.length) {
|
||||
this.deferred.shift()();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -482,7 +482,7 @@ export function getBasePlatform(platform : string) : string {
|
|||
}
|
||||
|
||||
// get platform ID without - specialization
|
||||
export function getRootPlatform(platform : string) : string {
|
||||
function getRootPlatform(platform : string) : string {
|
||||
return platform.split('-')[0];
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,15 @@ export interface SourceLine extends SourceLocation {
|
|||
cycles?:number;
|
||||
}
|
||||
|
||||
// objects that have source code position info
|
||||
export interface SourceLocated {
|
||||
$loc?: SourceLocation;
|
||||
}
|
||||
// statements also have the 'offset' (pc) field from SourceLine
|
||||
export interface SourceLineLocated {
|
||||
$loc?: SourceLine;
|
||||
}
|
||||
|
||||
export class SourceFile {
|
||||
lines: SourceLine[];
|
||||
text: string;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
import { FileData, Dependency, SourceLine, SourceFile, CodeListing, CodeListingMap, WorkerError, Segment, WorkerResult, WorkerOutputResult, isUnchanged, isOutputResult, WorkerMessage, WorkerItemUpdate } from "../common/workertypes";
|
||||
import { FileData, Dependency, SourceLine, SourceFile, CodeListing, CodeListingMap, WorkerError, Segment, WorkerResult, WorkerOutputResult, isUnchanged, isOutputResult, WorkerMessage, WorkerItemUpdate, WorkerErrorResult, isErrorResult } from "../common/workertypes";
|
||||
import { getFilenamePrefix, getFolderForPath, isProbablyBinary, getBasePlatform, getWithBinary } from "../common/util";
|
||||
import { Platform } from "../common/baseplatform";
|
||||
import localforage from "localforage";
|
||||
|
@ -129,6 +129,8 @@ export class CodeProject {
|
|||
}
|
||||
if (data && isOutputResult(data)) {
|
||||
this.processBuildResult(data);
|
||||
} else if (isErrorResult(data)) {
|
||||
this.processBuildListings(data);
|
||||
}
|
||||
this.callbackBuildResult(data);
|
||||
}
|
||||
|
@ -150,6 +152,7 @@ export class CodeProject {
|
|||
files.push(dir + '/' + fn);
|
||||
}
|
||||
|
||||
// TODO: use tool id to parse files, not platform
|
||||
parseIncludeDependencies(text:string):string[] {
|
||||
let files = [];
|
||||
let m;
|
||||
|
@ -199,13 +202,18 @@ export class CodeProject {
|
|||
this.pushAllFiles(files, m[2]);
|
||||
}
|
||||
// for wiz
|
||||
let re5 = /^\s*(import|embed)\s+"(.+?)";/gmi;
|
||||
let re5 = /^\s*(import|embed)\s*"(.+?)";/gmi;
|
||||
while (m = re5.exec(text)) {
|
||||
if (m[1] == 'import')
|
||||
this.pushAllFiles(files, m[2] + ".wiz");
|
||||
else
|
||||
this.pushAllFiles(files, m[2]);
|
||||
}
|
||||
// for ecs
|
||||
let re6 = /^\s*(import)\s*"(.+?)"/gmi;
|
||||
while (m = re6.exec(text)) {
|
||||
this.pushAllFiles(files, m[2]);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
@ -370,7 +378,7 @@ export class CodeProject {
|
|||
this.sendBuild();
|
||||
}
|
||||
|
||||
processBuildResult(data: WorkerOutputResult<any>) {
|
||||
processBuildListings(data: WorkerOutputResult<any> | WorkerErrorResult) {
|
||||
// TODO: link listings with source files
|
||||
if (data.listings) {
|
||||
this.listings = data.listings;
|
||||
|
@ -382,6 +390,14 @@ export class CodeProject {
|
|||
lst.assemblyfile = new SourceFile(lst.asmlines, lst.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processBuildResult(data: WorkerOutputResult<any>) {
|
||||
this.processBuildListings(data);
|
||||
this.processBuildSegments(data);
|
||||
}
|
||||
|
||||
processBuildSegments(data: WorkerOutputResult<any>) {
|
||||
// save and sort segment list
|
||||
var segs = (this.platform.getMemoryMap && this.platform.getMemoryMap()["main"]) || [];
|
||||
if (data.segments) { segs = segs.concat(data.segments || []); }
|
||||
|
@ -401,6 +417,10 @@ export class CodeProject {
|
|||
var fnprefix = getFilenamePrefix(this.stripLocalPath(path));
|
||||
var listings = this.getListings();
|
||||
var onlyfile = null;
|
||||
for (var lstfn in listings) {
|
||||
if (lstfn == path)
|
||||
return listings[lstfn];
|
||||
}
|
||||
for (var lstfn in listings) {
|
||||
onlyfile = lstfn;
|
||||
if (getFilenamePrefix(lstfn) == fnprefix) {
|
||||
|
|
|
@ -115,7 +115,8 @@ const TOOL_TO_SOURCE_STYLE = {
|
|||
'silice': 'verilog',
|
||||
'wiz': 'text/x-wiz',
|
||||
'vasmarm': 'vasm',
|
||||
'armips': 'vasm'
|
||||
'armips': 'vasm',
|
||||
'ecs': 'ecs',
|
||||
}
|
||||
|
||||
const TOOL_TO_HELPURL = {
|
||||
|
@ -323,7 +324,7 @@ function refreshWindowList() {
|
|||
for (var lstfn in listings) {
|
||||
var lst = listings[lstfn];
|
||||
// add listing if source/assembly file exists and has text
|
||||
if ((lst.assemblyfile && lst.assemblyfile.text) || (lst.sourcefile && lst.sourcefile.text)) {
|
||||
if ((lst.assemblyfile && lst.assemblyfile.text) || (lst.sourcefile && lst.sourcefile.text) || lst.text) {
|
||||
addWindowItem(lstfn, getFilenameForPath(lstfn), (path) => {
|
||||
return new ListingView(path);
|
||||
});
|
||||
|
@ -1829,8 +1830,10 @@ function _addIncludeFile() {
|
|||
addFileToProject("Include", ".inc", (s) => { return '\t.include "'+s+'"' });
|
||||
else if (tool == 'verilator')
|
||||
addFileToProject("Verilog", ".v", (s) => { return '`include "'+s+'"' });
|
||||
else if (tool == 'wiz')
|
||||
else if (tool == 'wiz')
|
||||
addFileToProject("Include", ".wiz", (s) => { return 'import "'+s+'";' });
|
||||
else if (tool == 'ecs')
|
||||
addFileToProject("Include", ".ecs", (s) => { return 'import "'+s+'"' });
|
||||
else
|
||||
alertError("Can't add include file to this project type (" + tool + ")");
|
||||
}
|
||||
|
|
|
@ -175,6 +175,12 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
|||
var meta = {defs:metadefs,width:width*8,height:height*8};
|
||||
result.push({fileid:id,label:ident,meta:meta});
|
||||
}
|
||||
// TODO: look for decode <ident> --- ... ---
|
||||
/*
|
||||
var re3 = /\bdecode\s+(\w+)\s*---(.+?)---/gims;
|
||||
while (m = re3.exec(data)) {
|
||||
}
|
||||
*/
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ const MODEDEFS = {
|
|||
markdown: { lineWrap: true },
|
||||
fastbasic: { noGutters: true },
|
||||
basic: { noLineNumbers: true, noGutters: true }, // TODO: not used?
|
||||
ecs: { theme: 'mbo', isAsm: true },
|
||||
}
|
||||
|
||||
export var textMapFunctions = {
|
||||
|
@ -213,7 +214,7 @@ export class SourceEditor implements ProjectView {
|
|||
if (!info.path || this.path.endsWith(info.path)) {
|
||||
var numLines = this.editor.lineCount();
|
||||
var line = info.line-1;
|
||||
if (line < 0 || line >= numLines) line = 0;
|
||||
if (isNaN(line) || line < 0 || line >= numLines) line = 0;
|
||||
this.addErrorMarker(line, info.msg);
|
||||
if (info.start != null) {
|
||||
var markOpts = {className:"mark-error", inclusiveLeft:true};
|
||||
|
@ -278,6 +279,7 @@ export class SourceEditor implements ProjectView {
|
|||
this.editor.clearGutter("gutter-clock");
|
||||
var lstlines = this.sourcefile.lines || [];
|
||||
for (var info of lstlines) {
|
||||
//if (info.path && info.path != this.path) continue;
|
||||
if (info.offset >= 0) {
|
||||
this.setGutter("gutter-offset", info.line-1, hex(info.offset&0xffff,4));
|
||||
}
|
||||
|
@ -579,7 +581,7 @@ export class ListingView extends DisassemblerView implements ProjectView {
|
|||
refreshListing() {
|
||||
// lookup corresponding assemblyfile for this file, using listing
|
||||
var lst = current_project.getListingForFile(this.path);
|
||||
// TODO?
|
||||
// TODO?
|
||||
this.assemblyfile = lst && (lst.assemblyfile || lst.sourcefile);
|
||||
}
|
||||
|
||||
|
@ -589,6 +591,7 @@ export class ListingView extends DisassemblerView implements ProjectView {
|
|||
if (!this.assemblyfile) return;
|
||||
var asmtext = this.assemblyfile.text;
|
||||
var disasmview = this.getDisasmView();
|
||||
// TODO: sometimes it picks one without a text file
|
||||
disasmview.setValue(asmtext);
|
||||
// go to PC
|
||||
if (!platform.saveState) return;
|
||||
|
|
|
@ -475,11 +475,12 @@ class JSNESPlatform extends Base6502Platform implements Platform, Probeable {
|
|||
}
|
||||
|
||||
getMemoryMap = function() { return { main:[
|
||||
//{name:'Work RAM',start:0x0,size:0x800,type:'ram'},
|
||||
{name:'Zero Page RAM',start:0x0,size:0x100,type:'ram'},
|
||||
{name:'OAM Buffer',start:0x200,size:0x100,type:'ram'},
|
||||
{name:'Work RAM',start:0x300,size:0x1000-0x300,type:'ram'},
|
||||
{name:'PPU Registers',start:0x2000,last:0x2008,size:0x2000,type:'io'},
|
||||
{name:'APU Registers',start:0x4000,last:0x4020,size:0x2000,type:'io'},
|
||||
{name:'Cartridge RAM',start:0x6000,size:0x2000,type:'ram'},
|
||||
{name:'Optional Cartridge RAM',start:0x6000,size:0x2000,type:'ram'},
|
||||
] } };
|
||||
|
||||
showHelp(tool:string, ident:string) {
|
||||
|
|
|
@ -60,6 +60,7 @@ function getToolForFilename_vcs(fn: string) {
|
|||
if (fn.endsWith(".wiz")) return "wiz";
|
||||
if (fn.endsWith(".bb") || fn.endsWith(".bas")) return "bataribasic";
|
||||
if (fn.endsWith(".ca65")) return "ca65";
|
||||
if (fn.endsWith(".ecs")) return "ecs";
|
||||
return "dasm";
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ var WilliamsPlatform = function(mainElement, proto, options) {
|
|||
this.__proto__ = new (proto ? proto : Base6809Platform)();
|
||||
|
||||
options = options || {};
|
||||
var isDefender = options.isDefender;
|
||||
var isDefender = options?.isDefender;
|
||||
var SCREEN_HEIGHT = 304;
|
||||
var SCREEN_WIDTH = 256;
|
||||
|
||||
|
@ -304,7 +304,7 @@ var WilliamsPlatform = function(mainElement, proto, options) {
|
|||
workerchannel = new WorkerSoundChannel(worker);
|
||||
audio.master.addChannel(workerchannel);
|
||||
|
||||
let rotate = options.rotate == null ? -90 : parseFloat(options.rotate);
|
||||
let rotate = options?.rotate == null ? -90 : parseFloat(options.rotate);
|
||||
video = new RasterVideo(mainElement, SCREEN_WIDTH, SCREEN_HEIGHT, { rotate });
|
||||
video.create();
|
||||
$(video.canvas).click(function(e) {
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
|
||||
import { spawnSync } from "child_process";
|
||||
import { existsSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
||||
import { describe } from "mocha";
|
||||
import { Bin, BoxConstraints, Packer } from "../common/ecs/binpack";
|
||||
import { ECSCompiler } from "../common/ecs/compiler";
|
||||
import { Dialect_CA65, EntityManager, SourceFileExport } from "../common/ecs/ecs";
|
||||
|
||||
function testCompiler() {
|
||||
let em = new EntityManager(new Dialect_CA65()); // TODO
|
||||
let c = new ECSCompiler(em, true);
|
||||
try {
|
||||
c.parseFile(`
|
||||
// comment
|
||||
/*
|
||||
mju,fjeqowfjqewiofjqe
|
||||
*/
|
||||
component Kernel
|
||||
lines: 0..255
|
||||
bgcolor: 0..255
|
||||
end
|
||||
component Bitmap
|
||||
data: array of 0..255
|
||||
end
|
||||
component HasBitmap
|
||||
bitmap: [Bitmap]
|
||||
end
|
||||
|
||||
system SimpleKernel
|
||||
locals 8
|
||||
on preframe do with [Kernel] --- JUNK_AT_END
|
||||
lda #5
|
||||
sta #6
|
||||
Label:
|
||||
---
|
||||
end
|
||||
|
||||
comment ---
|
||||
|
||||
---
|
||||
|
||||
scope Root
|
||||
entity kernel [Kernel]
|
||||
const lines = 0xc0
|
||||
//const lines = $c0
|
||||
end
|
||||
entity nobmp [Bitmap]
|
||||
const data = [4]
|
||||
end
|
||||
entity bmp [Bitmap]
|
||||
const data = [1,2,3]
|
||||
end
|
||||
entity player1 [HasBitmap]
|
||||
init bitmap = #bmp
|
||||
end
|
||||
end
|
||||
|
||||
`, 'foo.txt');
|
||||
//console.log('json', c.em.toJSON());
|
||||
let src = new SourceFileExport();
|
||||
c.exportToFile(src);
|
||||
// TODO: test?
|
||||
console.log(src.toString());
|
||||
return em;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
for (let err of c.errors) {
|
||||
console.log(err);
|
||||
}
|
||||
console.log(c.tokens);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: files in markdown?
|
||||
// TODO: jsr OperModeExecutionTree?
|
||||
|
||||
describe('Tokenizer', function() {
|
||||
it('Should use Compiler', function() {
|
||||
testCompiler();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Compiler', function() {
|
||||
let testdir = './test/ecs/';
|
||||
let files = readdirSync(testdir).filter(f => f.endsWith('.ecs'));
|
||||
files.forEach((ecsfn) => {
|
||||
it('Should compile ' + ecsfn, function() {
|
||||
let asmfn = ecsfn.replace('.ecs','.asm');
|
||||
let goodfn = ecsfn.replace('.ecs','.txt');
|
||||
let ecspath = testdir + ecsfn;
|
||||
let goodpath = testdir + goodfn;
|
||||
let dialect = new Dialect_CA65();
|
||||
let em = new EntityManager(dialect);
|
||||
em.mainPath = ecspath;
|
||||
let compiler = new ECSCompiler(em, true);
|
||||
compiler.getImportFile = (path: string) => {
|
||||
return readFileSync(testdir + path, 'utf-8');
|
||||
}
|
||||
let code = readFileSync(ecspath, 'utf-8');
|
||||
var outtxt = '';
|
||||
try {
|
||||
compiler.parseFile(code, ecspath);
|
||||
// TODO: errors
|
||||
let out = new SourceFileExport();
|
||||
em.exportToFile(out);
|
||||
outtxt = out.toString();
|
||||
} catch (e) {
|
||||
outtxt = e.toString();
|
||||
console.log(e);
|
||||
}
|
||||
if (compiler.errors.length)
|
||||
outtxt = compiler.errors.map(e => `${e.line}:${e.msg}`).join('\n');
|
||||
let goodtxt = existsSync(goodpath) ? readFileSync(goodpath, 'utf-8') : '';
|
||||
if (outtxt.trim() != goodtxt.trim()) {
|
||||
let asmpath = '/tmp/' + asmfn;
|
||||
writeFileSync(asmpath, outtxt, 'utf-8');
|
||||
console.log(spawnSync('/usr/bin/diff', [goodpath, asmpath], {encoding:'utf-8'}).stdout);
|
||||
throw new Error(`files different; to fix: cp ${asmpath} ${goodpath}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function testPack(bins: Bin[], boxes: BoxConstraints[]) {
|
||||
let packer = new Packer();
|
||||
for (let bin of bins) packer.bins.push(bin);
|
||||
for (let bc of boxes) packer.boxes.push(bc);
|
||||
if (!packer.pack()) throw new Error('cannot pack')
|
||||
//console.log(packer.boxes);
|
||||
//console.log(packer.bins[0].free)
|
||||
}
|
||||
|
||||
describe('Box Packer', function() {
|
||||
it('Should pack boxes', function() {
|
||||
testPack(
|
||||
[
|
||||
new Bin({ left:0, top:0, right:10, bottom:10 })
|
||||
], [
|
||||
{ width: 5, height: 5 },
|
||||
{ width: 5, height: 5 },
|
||||
{ width: 5, height: 5 },
|
||||
{ width: 5, height: 5 },
|
||||
]
|
||||
);
|
||||
});
|
||||
it('Should pack top-aligned boxes', function() {
|
||||
testPack(
|
||||
[
|
||||
new Bin({ left:0, top:0, right:10, bottom:10 })
|
||||
], [
|
||||
{ width: 5, height: 7, top: 0 },
|
||||
{ width: 5, height: 7, top: 1 },
|
||||
{ width: 5, height: 1 },
|
||||
{ width: 5, height: 1 },
|
||||
{ width: 5, height: 3 },
|
||||
{ width: 5, height: 1 },
|
||||
]
|
||||
);
|
||||
});
|
||||
it('Should pack unaligned boxes', function() {
|
||||
testPack(
|
||||
[
|
||||
new Bin({ left:0, top:0, right:10, bottom:10 })
|
||||
], [
|
||||
{ width: 3, height: 7, top: 0 },
|
||||
{ width: 3, height: 7, top: 1 },
|
||||
{ width: 3, height: 7, top: 2 },
|
||||
{ width: 5, height: 1 },
|
||||
{ width: 3, height: 1 },
|
||||
]
|
||||
);
|
||||
});
|
||||
it('Should pack multiple bins', function() {
|
||||
testPack(
|
||||
[
|
||||
new Bin({ left:0, top:0, right:10, bottom:10 }),
|
||||
new Bin({ left:0, top:0, right:10, bottom:10 })
|
||||
], [
|
||||
|
||||
{ width: 5, height: 10 },
|
||||
{ width: 5, height: 10 },
|
||||
{ width: 5, height: 5 },
|
||||
{ width: 5, height: 10 },
|
||||
{ width: 5, height: 5 },
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
import assert from "assert";
|
||||
import { describe } from "mocha";
|
||||
import { EmuHalt } from "../common/emu"
|
||||
import { lzgmini, isProbablyBinary } from "../common/util";
|
||||
import { Tokenizer, TokenType } from "../common/tokenizer";
|
||||
|
||||
var NES_CONIO_ROM_LZG = [
|
||||
76, 90, 71, 0, 0, 160, 16, 0, 0, 11, 158, 107, 131, 223, 83, 1, 9, 17, 21, 22, 78, 69, 83, 26, 2, 1, 3, 0, 22, 6, 120, 216,
|
||||
162, 0, 134, 112, 134, 114, 134, 113, 134, 115, 154, 169, 32, 157, 0, 2, 157, 0, 3, 157, 0, 4, 232, 208, 244, 32, 134, 130, 32, 85, 129, 169,
|
||||
0, 162, 8, 133, 2, 134, 3, 32, 93, 128, 32, 50, 129, 32, 73, 129, 76, 0, 128, 72, 152, 72, 138, 72, 169, 1, 133, 112, 230, 107, 208, 2,
|
||||
230, 108, 32, 232, 129, 169, 32, 141, 6, 32, 169, 0, 22, 129, 141, 5, 22, 66, 104, 170, 104, 168, 104, 64, 160, 0, 240, 7, 169, 105, 162, 128,
|
||||
76, 4, 96, 96, 162, 0, 21, 23, 0, 32, 22, 195, 1, 22, 194, 63, 21, 37, 21, 134, 22, 197, 41, 21, 27, 173, 41, 96, 201, 4, 32, 169,
|
||||
129, 240, 3, 76, 158, 128, 76, 188, 128, 169, 184, 162, 130, 24, 109, 41, 96, 144, 1, 232, 160, 0, 32, 130, 129, 141, 7, 21, 36, 238, 41, 96,
|
||||
21, 32, 76, 140, 128, 21, 47, 33, 21, 246, 201, 17, 14, 61, 15, 21, 253, 227, 128, 76, 1, 129, 169, 169, 17, 24, 61, 209, 21, 125, 17, 2,
|
||||
180, 17, 10, 130, 5, 22, 201, 128, 17, 4, 172, 30, 141, 1, 32, 76, 46, 129, 22, 65, 96, 173, 0, 96, 174, 1, 96, 32, 112, 130, 173, 2,
|
||||
96, 174, 3, 21, 65, 160, 4, 76, 105, 128, 17, 3, 228, 188, 162, 130, 17, 2, 228, 169, 188, 133, 10, 169, 130, 133, 11, 169, 0, 133, 12, 169,
|
||||
96, 133, 13, 162, 214, 169, 255, 133, 18, 160, 0, 232, 240, 13, 177, 10, 145, 12, 200, 208, 246, 230, 11, 230, 13, 208, 240, 230, 18, 208, 239, 96,
|
||||
133, 10, 134, 11, 162, 0, 177, 10, 96, 208, 42, 162, 0, 138, 96, 240, 36, 22, 163, 30, 48, 28, 22, 227, 2, 16, 20, 22, 227, 14, 144, 12,
|
||||
21, 200, 176, 4, 22, 226, 162, 0, 169, 1, 96, 165, 115, 208, 252, 96, 169, 255, 197, 115, 240, 252, 96, 133, 118, 132, 116, 134, 117, 32, 193, 129,
|
||||
164, 113, 165, 116, 153, 0, 2, 165, 117, 153, 0, 3, 165, 118, 153, 0, 4, 200, 132, 113, 230, 115, 96, 164, 115, 208, 1, 96, 166, 114, 169, 14,
|
||||
141, 42, 96, 189, 0, 2, 141, 6, 32, 189, 0, 3, 22, 163, 4, 141, 7, 32, 232, 136, 240, 93, 17, 19, 14, 71, 17, 19, 14, 49, 17, 19,
|
||||
14, 27, 17, 19, 14, 5, 206, 42, 96, 208, 141, 134, 114, 132, 115, 96, 169, 0, 162, 0, 72, 165, 2, 56, 233, 2, 133, 2, 176, 2, 198, 3,
|
||||
160, 1, 138, 145, 2, 104, 136, 145, 2, 96, 169, 41, 133, 10, 169, 96, 17, 34, 41, 168, 162, 0, 240, 10, 145, 10, 200, 208, 251, 230, 11, 202,
|
||||
208, 246, 192, 2, 240, 5, 21, 70, 247, 96, 78, 111, 32, 99, 97, 114, 116, 32, 108, 111, 97, 100, 101, 100, 0, 1, 0, 16, 32, 17, 66, 184,
|
||||
141, 18, 96, 142, 19, 96, 141, 25, 96, 142, 26, 96, 136, 185, 255, 255, 141, 35, 22, 196, 34, 96, 140, 37, 96, 32, 255, 255, 160, 255, 208, 232,
|
||||
96, 17, 71, 230, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 10, 53, 128, 0, 128, 92, 128,
|
||||
17, 14, 14, 204, 204, 51, 51, 22, 106, 0, 24, 60, 126, 24, 22, 1, 22, 231, 16, 48, 127, 127, 48, 16, 0, 22, 230, 12, 18, 48, 124, 48,
|
||||
98, 252, 22, 231, 0, 0, 3, 62, 118, 54, 54, 22, 231, 127, 127, 17, 4, 80, 22, 230, 224, 224, 96, 22, 3, 22, 230, 24, 24, 24, 248, 248,
|
||||
21, 16, 22, 230, 204, 153, 51, 102, 22, 106, 51, 153, 204, 22, 107, 21, 27, 255, 255, 17, 4, 67, 22, 227, 3, 22, 13, 17, 6, 188, 22, 230,
|
||||
17, 2, 172, 22, 13, 31, 31, 22, 236, 255, 255, 22, 236, 31, 31, 17, 4, 136, 22, 227, 22, 1, 248, 248, 21, 5, 22, 233, 17, 14, 123, 17,
|
||||
3, 64, 22, 230, 17, 3, 64, 21, 248, 17, 8, 29, 21, 216, 17, 6, 88, 17, 3, 64, 22, 230, 240, 22, 13, 21, 233, 21, 243, 22, 230, 17,
|
||||
6, 16, 22, 226, 192, 192, 48, 48, 22, 106, 15, 22, 1, 21, 84, 22, 230, 17, 10, 4, 22, 226, 17, 10, 52, 22, 230, 17, 6, 16, 17, 10,
|
||||
44, 22, 6, 17, 35, 220, 0, 24, 22, 231, 102, 102, 17, 34, 107, 0, 22, 233, 255, 22, 33, 102, 22, 231, 24, 62, 96, 60, 6, 124, 21, 40,
|
||||
22, 229, 0, 102, 12, 24, 48, 102, 70, 22, 231, 60, 102, 60, 56, 103, 102, 63, 22, 231, 6, 12, 17, 36, 59, 22, 230, 21, 30, 48, 48, 24,
|
||||
12, 22, 231, 22, 97, 12, 21, 4, 22, 231, 0, 102, 60, 255, 60, 17, 2, 115, 22, 230, 24, 24, 126, 17, 35, 70, 22, 230, 17, 4, 173, 21,
|
||||
33, 22, 231, 126, 21, 205, 22, 231, 21, 80, 22, 232, 3, 6, 12, 24, 48, 96, 22, 231, 60, 102, 110, 118, 102, 102, 60, 22, 231, 24, 24, 56,
|
||||
24, 24, 24, 126, 22, 231, 60, 102, 6, 12, 48, 96, 22, 235, 28, 6, 21, 168, 22, 228, 6, 14, 30, 102, 127, 6, 6, 22, 231, 126, 96, 124,
|
||||
6, 21, 80, 22, 230, 60, 102, 96, 124, 17, 4, 88, 22, 228, 126, 102, 12, 17, 35, 83, 22, 230, 60, 21, 13, 21, 216, 22, 231, 62, 21, 240,
|
||||
22, 228, 17, 34, 124, 22, 66, 22, 236, 17, 2, 224, 22, 228, 14, 24, 48, 96, 48, 24, 14, 0, 22, 230, 17, 2, 239, 17, 4, 241, 22, 228,
|
||||
112, 24, 12, 6, 12, 24, 112, 22, 231, 17, 2, 192, 24, 21, 52, 22, 232, 110, 110, 96, 98, 17, 3, 248, 22, 227, 24, 60, 102, 126, 17, 34,
|
||||
228, 22, 230, 124, 102, 102, 22, 66, 22, 231, 60, 102, 96, 96, 96, 17, 4, 200, 22, 227, 120, 108, 21, 30, 108, 120, 22, 231, 126, 96, 96, 120,
|
||||
96, 96, 126, 22, 237, 96, 22, 231, 21, 48, 110, 17, 37, 8, 22, 227, 21, 46, 17, 3, 96, 22, 230, 60, 17, 99, 19, 21, 24, 22, 229, 30,
|
||||
12, 22, 1, 108, 56, 22, 231, 102, 108, 120, 112, 120, 108, 21, 40, 22, 229, 17, 132, 62, 126, 22, 231, 99, 119, 127, 107, 99, 99, 99, 22, 231,
|
||||
102, 118, 126, 126, 110, 17, 2, 88, 22, 229, 60, 102, 22, 2, 17, 35, 88, 22, 227, 17, 2, 205, 21, 49, 22, 231, 21, 144, 60, 14, 22, 231,
|
||||
21, 80, 17, 2, 96, 22, 230, 60, 102, 96, 60, 17, 37, 208, 22, 227, 17, 163, 13, 17, 34, 200, 22, 229, 21, 111, 17, 5, 208, 22, 232, 60,
|
||||
17, 5, 16, 22, 225, 99, 99, 99, 107, 127, 119, 99, 22, 231, 21, 77, 60, 17, 3, 248, 22, 230, 21, 1, 17, 4, 64, 22, 227, 126, 17, 67,
|
||||
159, 126, 22, 231, 60, 48, 22, 2, 60, 22, 231, 96, 48, 24, 12, 6, 3, 0, 22, 231, 60, 17, 34, 32, 12, 21, 24, 22, 229, 17, 34, 193,
|
||||
17, 68, 244, 22, 229, 22, 3, 17, 165, 133, 22, 225, 17, 134, 203, 22, 230, 21, 58, 6, 62, 102, 62, 22, 232, 96, 17, 66, 176, 124, 22, 232,
|
||||
0, 60, 96, 96, 96, 17, 66, 144, 22, 229, 6, 21, 31, 21, 96, 22, 230, 0, 60, 102, 126, 21, 216, 22, 228, 14, 24, 62, 17, 3, 84, 22,
|
||||
230, 0, 21, 95, 6, 124, 22, 231, 17, 3, 80, 102, 17, 5, 88, 22, 225, 24, 0, 56, 17, 34, 240, 22, 231, 6, 0, 6, 22, 1, 60, 22,
|
||||
231, 96, 96, 108, 17, 34, 128, 22, 231, 21, 30, 21, 160, 22, 230, 0, 102, 127, 127, 107, 99, 22, 233, 17, 2, 79, 21, 32, 22, 231, 17, 34,
|
||||
210, 17, 4, 152, 22, 228, 17, 36, 242, 22, 232, 17, 3, 144, 6, 22, 232, 124, 17, 66, 226, 21, 160, 22, 228, 17, 131, 225, 22, 232, 17, 130,
|
||||
127, 17, 98, 112, 22, 230, 17, 35, 226, 17, 34, 0, 22, 233, 60, 17, 2, 240, 22, 230, 99, 107, 127, 62, 17, 226, 24, 22, 230, 17, 35, 241,
|
||||
22, 234, 21, 47, 12, 120, 22, 232, 126, 12, 24, 48, 17, 98, 194, 22, 228, 28, 48, 24, 112, 24, 48, 28, 22, 231, 17, 164, 159, 22, 3, 22,
|
||||
227, 56, 12, 24, 14, 24, 12, 56, 0, 22, 230, 51, 255, 204, 17, 35, 206, 22, 230, 22, 14, 17, 194, 92, 22, 10, 17, 236, 246, 204, 204, 255,
|
||||
231, 195, 129, 231, 22, 1, 22, 231, 239, 207, 128, 128, 207, 239, 255, 22, 230, 243, 237, 207, 131, 207, 157, 3, 22, 231, 255, 255, 252, 193, 137, 201,
|
||||
201, 22, 231, 128, 128, 17, 4, 80, 22, 230, 31, 31, 159, 22, 3, 22, 230, 231, 231, 231, 7, 7, 21, 16, 22, 230, 17, 236, 246, 204, 17, 237,
|
||||
246, 51, 153, 17, 227, 11, 17, 4, 67, 22, 227, 252, 22, 13, 17, 6, 188, 22, 230, 17, 2, 172, 22, 13, 224, 224, 22, 236, 0, 0, 22, 236,
|
||||
224, 224, 17, 4, 136, 22, 227, 22, 1, 7, 7, 21, 5, 22, 233, 17, 14, 123, 17, 3, 64, 22, 230, 17, 3, 64, 21, 248, 17, 8, 29, 21,
|
||||
216, 17, 6, 88, 17, 3, 64, 22, 230, 17, 226, 124, 22, 10, 17, 238, 244, 22, 226, 17, 6, 16, 22, 226, 63, 63, 207, 207, 22, 106, 17, 226,
|
||||
192, 21, 84, 22, 230, 17, 10, 4, 17, 230, 220, 17, 14, 60, 17, 234, 252, 17, 6, 44, 22, 6, 17, 35, 220, 255, 231, 22, 231, 153, 153, 17,
|
||||
34, 107, 255, 22, 233, 0, 22, 33, 153, 22, 231, 231, 193, 159, 195, 249, 131, 21, 40, 22, 229, 255, 153, 243, 231, 207, 153, 185, 22, 231, 195, 153,
|
||||
195, 199, 152, 153, 192, 22, 231, 249, 243, 17, 36, 59, 22, 230, 21, 30, 207, 207, 231, 243, 22, 231, 22, 97, 243, 21, 4, 22, 231, 255, 153, 195,
|
||||
0, 195, 17, 2, 115, 22, 230, 231, 231, 129, 17, 35, 70, 22, 230, 17, 4, 173, 21, 33, 22, 231, 129, 21, 205, 22, 231, 21, 80, 22, 232, 252,
|
||||
249, 243, 231, 207, 159, 22, 231, 195, 153, 145, 137, 153, 153, 195, 22, 231, 231, 231, 199, 231, 231, 231, 129, 22, 231, 195, 153, 249, 243, 207, 159, 22,
|
||||
235, 227, 249, 21, 168, 22, 228, 249, 241, 225, 153, 128, 249, 249, 22, 231, 129, 159, 131, 249, 21, 80, 22, 230, 195, 153, 159, 131, 17, 4, 88, 22,
|
||||
228, 129, 153, 243, 17, 35, 83, 22, 230, 195, 21, 13, 21, 216, 22, 231, 193, 21, 240, 22, 228, 17, 34, 124, 22, 66, 22, 236, 17, 2, 224, 22,
|
||||
228, 241, 231, 207, 159, 207, 231, 241, 255, 22, 230, 17, 2, 239, 17, 4, 241, 22, 228, 143, 231, 243, 249, 243, 231, 143, 22, 231, 17, 2, 192, 231,
|
||||
21, 52, 22, 232, 145, 145, 159, 157, 17, 3, 248, 22, 227, 231, 195, 153, 129, 17, 34, 228, 22, 230, 131, 153, 153, 22, 66, 22, 231, 195, 153, 159,
|
||||
159, 159, 17, 4, 200, 22, 227, 135, 147, 21, 30, 147, 135, 22, 231, 129, 159, 159, 135, 159, 159, 129, 22, 237, 159, 22, 231, 21, 48, 145, 17, 37,
|
||||
8, 22, 227, 21, 46, 17, 3, 96, 22, 230, 195, 17, 99, 19, 21, 24, 22, 229, 225, 243, 22, 1, 147, 199, 22, 231, 153, 147, 135, 143, 135, 147,
|
||||
21, 40, 22, 229, 17, 132, 62, 129, 22, 231, 156, 136, 128, 148, 156, 156, 156, 22, 231, 153, 137, 129, 129, 145, 17, 2, 88, 22, 229, 195, 153, 22,
|
||||
2, 17, 35, 88, 22, 227, 17, 2, 205, 21, 49, 22, 231, 21, 144, 195, 241, 22, 231, 21, 80, 17, 2, 96, 22, 230, 195, 153, 159, 195, 17, 37,
|
||||
208, 22, 227, 17, 163, 13, 17, 34, 200, 22, 229, 21, 111, 17, 5, 208, 22, 232, 195, 17, 5, 16, 22, 225, 156, 156, 156, 148, 128, 136, 156, 22,
|
||||
231, 21, 77, 195, 17, 3, 248, 22, 230, 21, 1, 17, 4, 64, 22, 227, 129, 17, 67, 159, 129, 22, 231, 195, 207, 22, 2, 195, 22, 231, 159, 207,
|
||||
231, 243, 249, 252, 255, 22, 231, 195, 17, 34, 32, 243, 21, 24, 22, 229, 17, 34, 193, 17, 68, 244, 22, 229, 22, 3, 17, 165, 133, 22, 225, 17,
|
||||
134, 203, 22, 230, 21, 58, 249, 193, 153, 193, 22, 232, 159, 17, 66, 176, 131, 22, 232, 255, 195, 159, 159, 159, 17, 66, 144, 22, 229, 249, 21, 31,
|
||||
21, 96, 22, 230, 255, 195, 153, 129, 21, 216, 22, 228, 241, 231, 193, 17, 3, 84, 22, 230, 255, 21, 95, 249, 131, 22, 231, 17, 3, 80, 153, 17,
|
||||
5, 88, 22, 225, 231, 255, 199, 17, 34, 240, 22, 231, 249, 255, 249, 22, 1, 195, 22, 231, 159, 159, 147, 17, 34, 128, 22, 231, 21, 30, 21, 160,
|
||||
22, 230, 255, 153, 128, 128, 148, 156, 22, 233, 17, 2, 79, 21, 32, 22, 231, 17, 34, 210, 17, 4, 152, 22, 228, 17, 36, 242, 22, 232, 17, 3,
|
||||
144, 249, 22, 232, 131, 17, 66, 226, 21, 160, 22, 228, 17, 131, 225, 22, 232, 17, 130, 127, 17, 98, 112, 22, 230, 17, 35, 226, 17, 34, 0, 22,
|
||||
233, 195, 17, 2, 240, 22, 230, 156, 148, 128, 193, 17, 226, 24, 22, 230, 17, 35, 241, 22, 234, 21, 47, 243, 135, 22, 232, 129, 243, 231, 207, 17,
|
||||
98, 194, 22, 228, 227, 207, 231, 143, 231, 207, 227, 22, 231, 17, 164, 159, 22, 3, 22, 227, 199, 243, 231, 241, 231, 243, 199, 255, 22, 230, 204, 0,
|
||||
51, 17, 35, 206, 22, 230, 22, 14, 9, 19, 0, 13, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 31,
|
||||
22, 31, 22, 31, 22, 31, 22, 31, 22, 31, 22, 30, 22, 28
|
||||
];
|
||||
|
||||
describe('LZG', function () {
|
||||
it('Should decode LZG', function () {
|
||||
var rom = new Uint8Array(new lzgmini().decode(NES_CONIO_ROM_LZG));
|
||||
assert.equal(40976, rom.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('string functions', function () {
|
||||
it('Should detect binary', function () {
|
||||
assert.ok(!isProbablyBinary(null, [32, 32, 10, 13, 9, 32, 32, 10, 13]));
|
||||
assert.ok(isProbablyBinary(null, [32, 32, 0x80]));
|
||||
assert.ok(!isProbablyBinary(null, [32, 32, 0xc1, 0x81, 32, 32, 10, 13]));
|
||||
assert.ok(isProbablyBinary(null, NES_CONIO_ROM_LZG));
|
||||
assert.ok(isProbablyBinary('test.bin'));
|
||||
assert.ok(isProbablyBinary('test.chr'));
|
||||
assert.ok(!isProbablyBinary('test.txt'));
|
||||
assert.ok(isProbablyBinary('test.dat'));
|
||||
assert.ok(!isProbablyBinary(null, [0x20, 0xa9, 0x20, 0x31, 0x39, 0x38, 0x32]));
|
||||
assert.ok(isProbablyBinary(null, [0x00, 0x00])); // 00 is binary
|
||||
assert.ok(isProbablyBinary(null, [0x9f])); // 9f is binary
|
||||
assert.ok(isProbablyBinary(null, [0xff])); // FF is binary
|
||||
assert.ok(isProbablyBinary(null, [0xf0, 0x12])); // ran out of data
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmuHalt', function () {
|
||||
it('Should detect emuhalt', function () {
|
||||
var e = new EmuHalt("?");
|
||||
assert.ok(e instanceof EmuHalt);
|
||||
assert.ok(e.hasOwnProperty('$loc'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('Tokenizer', function () {
|
||||
it('Should tokenize', function () {
|
||||
var t = new Tokenizer();
|
||||
t.setTokenRules([
|
||||
{ type: 'ident', regex: /[$A-Za-z_][A-Za-z0-9_-]*/ },
|
||||
{ type: 'delim', regex: /[\(\)\{\}\[\]]/ },
|
||||
{ type: 'qstring', regex: /".*?"/ },
|
||||
{ type: 'integer', regex: /[-]?\d+/ },
|
||||
{ type: 'eol', regex: /\n+/ },
|
||||
{ type: 'ignore', regex: /\s+/ },
|
||||
]);
|
||||
t.tokenizeFile("a\n{\"key\" value\n \"number\" 531\n\n \"f\" (fn [x] (+ x 2))}\n", "test.file");
|
||||
assert.strictEqual(t.tokens.map(t => t.type).join(' '),
|
||||
'ident delim qstring ident qstring integer qstring delim ident delim ident delim delim catch-all ident integer delim delim delim eof');
|
||||
assert.strictEqual(t.tokens.map(t => t.str).join(' '),
|
||||
'a { "key" value "number" 531 "f" ( fn [ x ] ( + x 2 ) ) } ');
|
||||
assert.strictEqual(t.tokens.filter(t => t.eol).map(t => t.str).join(' '),
|
||||
'a value 531 } ');
|
||||
assert.strictEqual(t.tokens.map(t => t.$loc.line).join(' '),
|
||||
'1 2 2 2 3 3 5 5 5 5 5 5 5 5 5 5 5 5 5 6');
|
||||
assert.strictEqual(20, t.tokens.length);
|
||||
assert.strictEqual('a', t.peekToken().str);
|
||||
assert.strictEqual('a', t.expectToken('a').str);
|
||||
t.expectTokens(['foo', '{']);
|
||||
t.pushbackToken(t.consumeToken());
|
||||
assert.strictEqual('"key"', t.consumeToken().str);
|
||||
assert.deepStrictEqual({ 'value': true }, t.parseModifiers(['foo', 'value', 'bar']));
|
||||
assert.deepStrictEqual([], t.errors);
|
||||
t = new Tokenizer();
|
||||
t.setTokenRules([
|
||||
{ type: 'ident', regex: /[$A-Za-z_][A-Za-z0-9_-]*/ },
|
||||
{ type: 'delim', regex: /[\(\)\{\}\[\]]/ },
|
||||
{ type: 'code-fragment', regex: /---[^-]*---/ },
|
||||
{ type: 'ignore', regex: /\s+/ },
|
||||
]);
|
||||
t.tokenizeFile("key value ---\nthis is\na fragment\n--- foo", "test.file");
|
||||
assert.strictEqual(t.tokens.map(t => t.type).join(' '),
|
||||
'ident ident code-fragment ident eof');
|
||||
});
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
import { getRootBasePlatform } from "../../common/util";
|
||||
import { getFilenamePrefix, getRootBasePlatform } from "../../common/util";
|
||||
import { CodeListingMap, WorkerError } from "../../common/workertypes";
|
||||
import { re_crlf, BuildStepResult, anyTargetChanged, execMain, gatherFiles, msvcErrorMatcher, populateEntry, populateExtraFiles, populateFiles, print_fn, putWorkFile, setupFS, staleFiles, BuildStep, emglobal, loadNative, moduleInstFn, fixParamsWithDefines, store, makeErrorMatcher } from "../workermain";
|
||||
import { re_crlf, BuildStepResult, anyTargetChanged, execMain, gatherFiles, msvcErrorMatcher, populateEntry, populateExtraFiles, populateFiles, print_fn, putWorkFile, setupFS, staleFiles, BuildStep, emglobal, loadNative, moduleInstFn, fixParamsWithDefines, store, makeErrorMatcher, getWorkFileAsString } from "../workermain";
|
||||
import { EmscriptenModule } from "../workermain"
|
||||
|
||||
|
||||
|
@ -18,21 +18,30 @@ import { EmscriptenModule } from "../workermain"
|
|||
00B726 1 xx xx IBSECSZ: .res 2
|
||||
00BA2F 1 2A 2B E8 2C HEX "2A2BE82C2D2E2F303132F0F133343536"
|
||||
*/
|
||||
function parseCA65Listing(code: string, symbols, params, dbg: boolean) {
|
||||
function parseCA65Listing(code: string, symbols, params, dbg: boolean, listings?: CodeListingMap) {
|
||||
var segofs = 0;
|
||||
var offset = 0;
|
||||
var dbgLineMatch = /^([0-9A-F]+)([r]?)\s+(\d+)\s+[.]dbg\s+(\w+), "([^"]+)", (.+)/;
|
||||
var funcLineMatch = /"(\w+)", (\w+), "(\w+)"/;
|
||||
var insnLineMatch = /^([0-9A-F]+)([r]?)\s{1,2}(\d+)\s{1,2}([0-9A-Frx ]{11})\s+(.*)/;
|
||||
var segMatch = /[.]segment\s+"(\w+)"/i;
|
||||
var lines = [];
|
||||
var origlines = [];
|
||||
var lines = origlines;
|
||||
var linenum = 0;
|
||||
let curpath = '';
|
||||
// TODO: only does .c functions, not all .s files
|
||||
for (var line of code.split(re_crlf)) {
|
||||
var dbgm = dbgLineMatch.exec(line);
|
||||
if (dbgm && dbgm[1]) {
|
||||
var dbgtype = dbgm[4];
|
||||
offset = parseInt(dbgm[1], 16);
|
||||
curpath = dbgm[5];
|
||||
// new file?
|
||||
if (curpath && listings) {
|
||||
let l = listings[curpath];
|
||||
if (!l) l = listings[curpath] = {lines:[]};
|
||||
lines = l.lines;
|
||||
}
|
||||
if (dbgtype == 'func') {
|
||||
var funcm = funcLineMatch.exec(dbgm[6]);
|
||||
if (funcm) {
|
||||
|
@ -45,9 +54,9 @@ function parseCA65Listing(code: string, symbols, params, dbg: boolean) {
|
|||
}
|
||||
}
|
||||
if (dbg && dbgm && dbgtype == 'line') {
|
||||
//console.log(dbgm[6], offset, segofs);
|
||||
//console.log(dbgm[5], dbgm[6], offset, segofs);
|
||||
lines.push({
|
||||
// TODO: sourcefile
|
||||
path: dbgm[5],
|
||||
line: parseInt(dbgm[6]),
|
||||
offset: offset + segofs,
|
||||
insns: null
|
||||
|
@ -65,6 +74,7 @@ function parseCA65Listing(code: string, symbols, params, dbg: boolean) {
|
|||
linenum--;
|
||||
} else if (!dbg) {
|
||||
lines.push({
|
||||
path: curpath,
|
||||
line: linenum,
|
||||
offset: offset + segofs,
|
||||
insns: insns,
|
||||
|
@ -90,7 +100,7 @@ function parseCA65Listing(code: string, symbols, params, dbg: boolean) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
return origlines;
|
||||
}
|
||||
|
||||
export function assembleCA65(step: BuildStep): BuildStepResult {
|
||||
|
@ -118,8 +128,12 @@ export function assembleCA65(step: BuildStep): BuildStepResult {
|
|||
args.unshift.apply(args, ["-D", "__MAIN__=1"]);
|
||||
}
|
||||
execMain(step, CA65, args);
|
||||
if (errors.length)
|
||||
return { errors: errors };
|
||||
if (errors.length) {
|
||||
// TODO?
|
||||
let listings : CodeListingMap = {};
|
||||
listings[step.path] = { lines:[], text:getWorkFileAsString(step.path) };
|
||||
return { errors, listings };
|
||||
}
|
||||
objout = FS.readFile(objpath, { encoding: 'binary' });
|
||||
lstout = FS.readFile(lstpath, { encoding: 'utf8' });
|
||||
putWorkFile(objpath, objout);
|
||||
|
@ -216,15 +230,25 @@ export function linkLD65(step: BuildStep): BuildStepResult {
|
|||
if (fn.endsWith('.lst')) {
|
||||
var lstout = FS.readFile(fn, { encoding: 'utf8' });
|
||||
lstout = lstout.split('\n\n')[1] || lstout; // remove header
|
||||
var asmlines = parseCA65Listing(lstout, symbolmap, params, false);
|
||||
var srclines = parseCA65Listing(lstout, symbolmap, params, true);
|
||||
putWorkFile(fn, lstout);
|
||||
// TODO: you have to get rid of all source lines to get asm listing
|
||||
listings[fn] = {
|
||||
asmlines: srclines.length ? asmlines : null,
|
||||
lines: srclines.length ? srclines : asmlines,
|
||||
text: lstout
|
||||
};
|
||||
console.log(step);
|
||||
let isECS = step.debuginfo?.entities != null; // TODO
|
||||
if (isECS) {
|
||||
var asmlines = [];
|
||||
var srclines = parseCA65Listing(lstout, symbolmap, params, true, listings);
|
||||
listings[fn] = {
|
||||
lines: [],
|
||||
text: lstout
|
||||
}
|
||||
} else {
|
||||
var asmlines = parseCA65Listing(lstout, symbolmap, params, false);
|
||||
var srclines = parseCA65Listing(lstout, symbolmap, params, true); // TODO: listings param for ecs
|
||||
listings[fn] = {
|
||||
asmlines: srclines.length ? asmlines : null,
|
||||
lines: srclines.length ? srclines : asmlines,
|
||||
text: lstout
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import { ECSCompiler } from "../../common/ecs/compiler";
|
||||
import { Dialect_CA65, ECSError, EntityManager } from "../../common/ecs/ecs";
|
||||
import { CompileError } from "../../common/tokenizer";
|
||||
import { CodeListingMap } from "../../common/workertypes";
|
||||
import { BuildStep, BuildStepResult, fixParamsWithDefines, gatherFiles, getWorkFileAsString, putWorkFile, staleFiles } from "../workermain";
|
||||
|
||||
export function assembleECS(step: BuildStep): BuildStepResult {
|
||||
let em = new EntityManager(new Dialect_CA65()); // TODO
|
||||
let compiler = new ECSCompiler(em, true);
|
||||
compiler.getImportFile = (path: string) => {
|
||||
return getWorkFileAsString(path);
|
||||
}
|
||||
gatherFiles(step, { mainFilePath: "main.ecs" });
|
||||
if (step.mainfile) em.mainPath = step.path;
|
||||
var destpath = step.prefix + '.ca65';
|
||||
if (staleFiles(step, [destpath])) {
|
||||
let code = getWorkFileAsString(step.path);
|
||||
fixParamsWithDefines(step.path, step.params);
|
||||
try {
|
||||
compiler.includeDebugInfo = true;
|
||||
compiler.parseFile(code, step.path);
|
||||
let outtext = compiler.export().toString();
|
||||
putWorkFile(destpath, outtext);
|
||||
var listings: CodeListingMap = {};
|
||||
listings[destpath] = {lines:[], text:outtext} // TODO
|
||||
var debuginfo = compiler.em.getDebugTree();
|
||||
} catch (e) {
|
||||
if (e instanceof ECSError) {
|
||||
compiler.addError(e.message, e.$loc);
|
||||
for (let obj of e.$sources) {
|
||||
let name = (obj as any).event;
|
||||
if (name == 'start') break;
|
||||
compiler.addError(`... ${name}`, obj.$loc); // TODO?
|
||||
}
|
||||
return { errors: compiler.errors };
|
||||
} else if (e instanceof CompileError) {
|
||||
return { errors: compiler.errors };
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return {
|
||||
nexttool: "ca65",
|
||||
path: destpath,
|
||||
args: [destpath],
|
||||
files: [destpath].concat(step.files),
|
||||
listings,
|
||||
debuginfo
|
||||
};
|
||||
}
|
||||
}
|
|
@ -431,6 +431,7 @@ export interface BuildStep extends WorkerBuildStep {
|
|||
code?
|
||||
prefix?
|
||||
maxts?
|
||||
debuginfo?
|
||||
};
|
||||
|
||||
///
|
||||
|
@ -518,6 +519,11 @@ class Builder {
|
|||
}
|
||||
if (step.result) {
|
||||
(step.result as any).params = step.params; // TODO: type check
|
||||
if (step.debuginfo) {
|
||||
let r = step.result as any; // TODO
|
||||
if (!r.debuginfo) r.debuginfo = {};
|
||||
Object.assign(r.debuginfo, step.debuginfo);
|
||||
}
|
||||
// errors? return them
|
||||
if ('errors' in step.result && step.result.errors.length) {
|
||||
applyDefaultErrorPath(step.result.errors, step.path);
|
||||
|
@ -529,6 +535,7 @@ class Builder {
|
|||
}
|
||||
// combine files with a link tool?
|
||||
if ('linktool' in step.result) {
|
||||
// add to existing link step
|
||||
if (linkstep) {
|
||||
linkstep.files = linkstep.files.concat(step.result.files);
|
||||
linkstep.args = linkstep.args.concat(step.result.args);
|
||||
|
@ -540,6 +547,7 @@ class Builder {
|
|||
args:step.result.args
|
||||
};
|
||||
}
|
||||
linkstep.debuginfo = step.debuginfo; // TODO: multiple debuginfos
|
||||
}
|
||||
// process with another tool?
|
||||
if ('nexttool' in step.result) {
|
||||
|
@ -1102,6 +1110,7 @@ import * as z80 from './tools/z80'
|
|||
import * as x86 from './tools/x86'
|
||||
import * as arm from './tools/arm'
|
||||
import * as script from './tools/script'
|
||||
import * as ecs from './tools/ecs'
|
||||
|
||||
var TOOLS = {
|
||||
'dasm': dasm.assembleDASM,
|
||||
|
@ -1137,7 +1146,8 @@ var TOOLS = {
|
|||
'wiz': misc.compileWiz,
|
||||
'armips': arm.assembleARMIPS,
|
||||
'vasmarm': arm.assembleVASMARM,
|
||||
'js': script.runJavascript,
|
||||
//'js': script.runJavascript,
|
||||
'ecs': ecs.assembleECS,
|
||||
}
|
||||
|
||||
var TOOL_PRELOADFS = {
|
||||
|
@ -1166,6 +1176,8 @@ var TOOL_PRELOADFS = {
|
|||
'fastbasic': '65-atari8',
|
||||
'silice': 'Silice',
|
||||
'wiz': 'wiz',
|
||||
'ecs-vcs': '65-none', // TODO: support multiple platforms
|
||||
'ecs-nes': '65-nes', // TODO: support multiple platforms
|
||||
}
|
||||
|
||||
//const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay)); // for testing
|
||||
|
|
|
@ -196,9 +196,9 @@ async function testPlatform(platid, romname, maxframes, callback) {
|
|||
assert.equal(clks, proberec.countClocks());
|
||||
}
|
||||
// debug tree
|
||||
if (platform.getDebugTree) {
|
||||
if (platform.getDebugTree != null) {
|
||||
var dbgtree = platform.getDebugTree();
|
||||
JSON.stringify(dbgtree);
|
||||
if (dbgtree != null) JSON.stringify(dbgtree);
|
||||
}
|
||||
// misc
|
||||
assert.ok(platform.getDefaultExtension().startsWith('.'));
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
|
||||
var vm = require('vm');
|
||||
var fs = require('fs');
|
||||
var assert = require('assert');
|
||||
|
||||
var emu = require("gen/common/emu.js");
|
||||
var util = require("gen/common/util.js");
|
||||
var nes = require("gen/platform/nes.js");
|
||||
|
||||
var NES_CONIO_ROM_LZG = [
|
||||
76,90,71,0,0,160,16,0,0,11,158,107,131,223,83,1,9,17,21,22,78,69,83,26,2,1,3,0,22,6,120,216,
|
||||
162,0,134,112,134,114,134,113,134,115,154,169,32,157,0,2,157,0,3,157,0,4,232,208,244,32,134,130,32,85,129,169,
|
||||
0,162,8,133,2,134,3,32,93,128,32,50,129,32,73,129,76,0,128,72,152,72,138,72,169,1,133,112,230,107,208,2,
|
||||
230,108,32,232,129,169,32,141,6,32,169,0,22,129,141,5,22,66,104,170,104,168,104,64,160,0,240,7,169,105,162,128,
|
||||
76,4,96,96,162,0,21,23,0,32,22,195,1,22,194,63,21,37,21,134,22,197,41,21,27,173,41,96,201,4,32,169,
|
||||
129,240,3,76,158,128,76,188,128,169,184,162,130,24,109,41,96,144,1,232,160,0,32,130,129,141,7,21,36,238,41,96,
|
||||
21,32,76,140,128,21,47,33,21,246,201,17,14,61,15,21,253,227,128,76,1,129,169,169,17,24,61,209,21,125,17,2,
|
||||
180,17,10,130,5,22,201,128,17,4,172,30,141,1,32,76,46,129,22,65,96,173,0,96,174,1,96,32,112,130,173,2,
|
||||
96,174,3,21,65,160,4,76,105,128,17,3,228,188,162,130,17,2,228,169,188,133,10,169,130,133,11,169,0,133,12,169,
|
||||
96,133,13,162,214,169,255,133,18,160,0,232,240,13,177,10,145,12,200,208,246,230,11,230,13,208,240,230,18,208,239,96,
|
||||
133,10,134,11,162,0,177,10,96,208,42,162,0,138,96,240,36,22,163,30,48,28,22,227,2,16,20,22,227,14,144,12,
|
||||
21,200,176,4,22,226,162,0,169,1,96,165,115,208,252,96,169,255,197,115,240,252,96,133,118,132,116,134,117,32,193,129,
|
||||
164,113,165,116,153,0,2,165,117,153,0,3,165,118,153,0,4,200,132,113,230,115,96,164,115,208,1,96,166,114,169,14,
|
||||
141,42,96,189,0,2,141,6,32,189,0,3,22,163,4,141,7,32,232,136,240,93,17,19,14,71,17,19,14,49,17,19,
|
||||
14,27,17,19,14,5,206,42,96,208,141,134,114,132,115,96,169,0,162,0,72,165,2,56,233,2,133,2,176,2,198,3,
|
||||
160,1,138,145,2,104,136,145,2,96,169,41,133,10,169,96,17,34,41,168,162,0,240,10,145,10,200,208,251,230,11,202,
|
||||
208,246,192,2,240,5,21,70,247,96,78,111,32,99,97,114,116,32,108,111,97,100,101,100,0,1,0,16,32,17,66,184,
|
||||
141,18,96,142,19,96,141,25,96,142,26,96,136,185,255,255,141,35,22,196,34,96,140,37,96,32,255,255,160,255,208,232,
|
||||
96,17,71,230,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,10,53,128,0,128,92,128,
|
||||
17,14,14,204,204,51,51,22,106,0,24,60,126,24,22,1,22,231,16,48,127,127,48,16,0,22,230,12,18,48,124,48,
|
||||
98,252,22,231,0,0,3,62,118,54,54,22,231,127,127,17,4,80,22,230,224,224,96,22,3,22,230,24,24,24,248,248,
|
||||
21,16,22,230,204,153,51,102,22,106,51,153,204,22,107,21,27,255,255,17,4,67,22,227,3,22,13,17,6,188,22,230,
|
||||
17,2,172,22,13,31,31,22,236,255,255,22,236,31,31,17,4,136,22,227,22,1,248,248,21,5,22,233,17,14,123,17,
|
||||
3,64,22,230,17,3,64,21,248,17,8,29,21,216,17,6,88,17,3,64,22,230,240,22,13,21,233,21,243,22,230,17,
|
||||
6,16,22,226,192,192,48,48,22,106,15,22,1,21,84,22,230,17,10,4,22,226,17,10,52,22,230,17,6,16,17,10,
|
||||
44,22,6,17,35,220,0,24,22,231,102,102,17,34,107,0,22,233,255,22,33,102,22,231,24,62,96,60,6,124,21,40,
|
||||
22,229,0,102,12,24,48,102,70,22,231,60,102,60,56,103,102,63,22,231,6,12,17,36,59,22,230,21,30,48,48,24,
|
||||
12,22,231,22,97,12,21,4,22,231,0,102,60,255,60,17,2,115,22,230,24,24,126,17,35,70,22,230,17,4,173,21,
|
||||
33,22,231,126,21,205,22,231,21,80,22,232,3,6,12,24,48,96,22,231,60,102,110,118,102,102,60,22,231,24,24,56,
|
||||
24,24,24,126,22,231,60,102,6,12,48,96,22,235,28,6,21,168,22,228,6,14,30,102,127,6,6,22,231,126,96,124,
|
||||
6,21,80,22,230,60,102,96,124,17,4,88,22,228,126,102,12,17,35,83,22,230,60,21,13,21,216,22,231,62,21,240,
|
||||
22,228,17,34,124,22,66,22,236,17,2,224,22,228,14,24,48,96,48,24,14,0,22,230,17,2,239,17,4,241,22,228,
|
||||
112,24,12,6,12,24,112,22,231,17,2,192,24,21,52,22,232,110,110,96,98,17,3,248,22,227,24,60,102,126,17,34,
|
||||
228,22,230,124,102,102,22,66,22,231,60,102,96,96,96,17,4,200,22,227,120,108,21,30,108,120,22,231,126,96,96,120,
|
||||
96,96,126,22,237,96,22,231,21,48,110,17,37,8,22,227,21,46,17,3,96,22,230,60,17,99,19,21,24,22,229,30,
|
||||
12,22,1,108,56,22,231,102,108,120,112,120,108,21,40,22,229,17,132,62,126,22,231,99,119,127,107,99,99,99,22,231,
|
||||
102,118,126,126,110,17,2,88,22,229,60,102,22,2,17,35,88,22,227,17,2,205,21,49,22,231,21,144,60,14,22,231,
|
||||
21,80,17,2,96,22,230,60,102,96,60,17,37,208,22,227,17,163,13,17,34,200,22,229,21,111,17,5,208,22,232,60,
|
||||
17,5,16,22,225,99,99,99,107,127,119,99,22,231,21,77,60,17,3,248,22,230,21,1,17,4,64,22,227,126,17,67,
|
||||
159,126,22,231,60,48,22,2,60,22,231,96,48,24,12,6,3,0,22,231,60,17,34,32,12,21,24,22,229,17,34,193,
|
||||
17,68,244,22,229,22,3,17,165,133,22,225,17,134,203,22,230,21,58,6,62,102,62,22,232,96,17,66,176,124,22,232,
|
||||
0,60,96,96,96,17,66,144,22,229,6,21,31,21,96,22,230,0,60,102,126,21,216,22,228,14,24,62,17,3,84,22,
|
||||
230,0,21,95,6,124,22,231,17,3,80,102,17,5,88,22,225,24,0,56,17,34,240,22,231,6,0,6,22,1,60,22,
|
||||
231,96,96,108,17,34,128,22,231,21,30,21,160,22,230,0,102,127,127,107,99,22,233,17,2,79,21,32,22,231,17,34,
|
||||
210,17,4,152,22,228,17,36,242,22,232,17,3,144,6,22,232,124,17,66,226,21,160,22,228,17,131,225,22,232,17,130,
|
||||
127,17,98,112,22,230,17,35,226,17,34,0,22,233,60,17,2,240,22,230,99,107,127,62,17,226,24,22,230,17,35,241,
|
||||
22,234,21,47,12,120,22,232,126,12,24,48,17,98,194,22,228,28,48,24,112,24,48,28,22,231,17,164,159,22,3,22,
|
||||
227,56,12,24,14,24,12,56,0,22,230,51,255,204,17,35,206,22,230,22,14,17,194,92,22,10,17,236,246,204,204,255,
|
||||
231,195,129,231,22,1,22,231,239,207,128,128,207,239,255,22,230,243,237,207,131,207,157,3,22,231,255,255,252,193,137,201,
|
||||
201,22,231,128,128,17,4,80,22,230,31,31,159,22,3,22,230,231,231,231,7,7,21,16,22,230,17,236,246,204,17,237,
|
||||
246,51,153,17,227,11,17,4,67,22,227,252,22,13,17,6,188,22,230,17,2,172,22,13,224,224,22,236,0,0,22,236,
|
||||
224,224,17,4,136,22,227,22,1,7,7,21,5,22,233,17,14,123,17,3,64,22,230,17,3,64,21,248,17,8,29,21,
|
||||
216,17,6,88,17,3,64,22,230,17,226,124,22,10,17,238,244,22,226,17,6,16,22,226,63,63,207,207,22,106,17,226,
|
||||
192,21,84,22,230,17,10,4,17,230,220,17,14,60,17,234,252,17,6,44,22,6,17,35,220,255,231,22,231,153,153,17,
|
||||
34,107,255,22,233,0,22,33,153,22,231,231,193,159,195,249,131,21,40,22,229,255,153,243,231,207,153,185,22,231,195,153,
|
||||
195,199,152,153,192,22,231,249,243,17,36,59,22,230,21,30,207,207,231,243,22,231,22,97,243,21,4,22,231,255,153,195,
|
||||
0,195,17,2,115,22,230,231,231,129,17,35,70,22,230,17,4,173,21,33,22,231,129,21,205,22,231,21,80,22,232,252,
|
||||
249,243,231,207,159,22,231,195,153,145,137,153,153,195,22,231,231,231,199,231,231,231,129,22,231,195,153,249,243,207,159,22,
|
||||
235,227,249,21,168,22,228,249,241,225,153,128,249,249,22,231,129,159,131,249,21,80,22,230,195,153,159,131,17,4,88,22,
|
||||
228,129,153,243,17,35,83,22,230,195,21,13,21,216,22,231,193,21,240,22,228,17,34,124,22,66,22,236,17,2,224,22,
|
||||
228,241,231,207,159,207,231,241,255,22,230,17,2,239,17,4,241,22,228,143,231,243,249,243,231,143,22,231,17,2,192,231,
|
||||
21,52,22,232,145,145,159,157,17,3,248,22,227,231,195,153,129,17,34,228,22,230,131,153,153,22,66,22,231,195,153,159,
|
||||
159,159,17,4,200,22,227,135,147,21,30,147,135,22,231,129,159,159,135,159,159,129,22,237,159,22,231,21,48,145,17,37,
|
||||
8,22,227,21,46,17,3,96,22,230,195,17,99,19,21,24,22,229,225,243,22,1,147,199,22,231,153,147,135,143,135,147,
|
||||
21,40,22,229,17,132,62,129,22,231,156,136,128,148,156,156,156,22,231,153,137,129,129,145,17,2,88,22,229,195,153,22,
|
||||
2,17,35,88,22,227,17,2,205,21,49,22,231,21,144,195,241,22,231,21,80,17,2,96,22,230,195,153,159,195,17,37,
|
||||
208,22,227,17,163,13,17,34,200,22,229,21,111,17,5,208,22,232,195,17,5,16,22,225,156,156,156,148,128,136,156,22,
|
||||
231,21,77,195,17,3,248,22,230,21,1,17,4,64,22,227,129,17,67,159,129,22,231,195,207,22,2,195,22,231,159,207,
|
||||
231,243,249,252,255,22,231,195,17,34,32,243,21,24,22,229,17,34,193,17,68,244,22,229,22,3,17,165,133,22,225,17,
|
||||
134,203,22,230,21,58,249,193,153,193,22,232,159,17,66,176,131,22,232,255,195,159,159,159,17,66,144,22,229,249,21,31,
|
||||
21,96,22,230,255,195,153,129,21,216,22,228,241,231,193,17,3,84,22,230,255,21,95,249,131,22,231,17,3,80,153,17,
|
||||
5,88,22,225,231,255,199,17,34,240,22,231,249,255,249,22,1,195,22,231,159,159,147,17,34,128,22,231,21,30,21,160,
|
||||
22,230,255,153,128,128,148,156,22,233,17,2,79,21,32,22,231,17,34,210,17,4,152,22,228,17,36,242,22,232,17,3,
|
||||
144,249,22,232,131,17,66,226,21,160,22,228,17,131,225,22,232,17,130,127,17,98,112,22,230,17,35,226,17,34,0,22,
|
||||
233,195,17,2,240,22,230,156,148,128,193,17,226,24,22,230,17,35,241,22,234,21,47,243,135,22,232,129,243,231,207,17,
|
||||
98,194,22,228,227,207,231,143,231,207,227,22,231,17,164,159,22,3,22,227,199,243,231,241,231,243,199,255,22,230,204,0,
|
||||
51,17,35,206,22,230,22,14,9,19,0,13,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,22,31,
|
||||
22,31,22,31,22,31,22,31,22,31,22,30,22,28
|
||||
];
|
||||
|
||||
describe('LZG', function() {
|
||||
it('Should decode LZG', function() {
|
||||
var rom = new Uint8Array(new util.lzgmini().decode(NES_CONIO_ROM_LZG));
|
||||
assert.equal(40976, rom.length);
|
||||
});
|
||||
});
|
||||
|
||||
describe('string functions', function() {
|
||||
it('Should detect binary', function() {
|
||||
assert.ok(!util.isProbablyBinary(null, [32,32,10,13,9,32,32,10,13]));
|
||||
assert.ok(util.isProbablyBinary(null, [32,32,0x80]));
|
||||
assert.ok(!util.isProbablyBinary(null, [32,32,0xc1,0x81,32,32,10,13]));
|
||||
assert.ok(util.isProbablyBinary(null, NES_CONIO_ROM_LZG));
|
||||
assert.ok(util.isProbablyBinary('test.bin'));
|
||||
assert.ok(util.isProbablyBinary('test.chr'));
|
||||
assert.ok(!util.isProbablyBinary('test.txt'));
|
||||
assert.ok(util.isProbablyBinary('test.dat'));
|
||||
assert.ok(!util.isProbablyBinary(null, [0x20,0xa9,0x20,0x31,0x39,0x38,0x32]));
|
||||
assert.ok(util.isProbablyBinary(null, [0x00,0x00])); // 00 is binary
|
||||
assert.ok(util.isProbablyBinary(null, [0x9f])); // 9f is binary
|
||||
assert.ok(util.isProbablyBinary(null, [0xff])); // FF is binary
|
||||
assert.ok(util.isProbablyBinary(null, [0xf0,0x12])); // ran out of data
|
||||
});
|
||||
});
|
||||
|
||||
describe('EmuHalt', function() {
|
||||
it('Should detect emuhalt', function() {
|
||||
var e = new emu.EmuHalt();
|
||||
assert.ok(e instanceof emu.EmuHalt);
|
||||
assert.ok(e.hasOwnProperty('$loc'));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
// comment
|
||||
/*
|
||||
mju,fjeqowfjqewiofjqe
|
||||
*/
|
||||
component Kernel
|
||||
lines: 0..255
|
||||
bgcolor: 0..255
|
||||
end
|
||||
|
||||
component Bitmap
|
||||
data: array of 0..255
|
||||
end
|
||||
|
||||
component HasBitmap
|
||||
bitmap: [Bitmap]
|
||||
end
|
|
@ -0,0 +1,148 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
import "kernel2.ecs"
|
||||
import "score.ecs"
|
||||
|
||||
demo Main
|
||||
|
||||
using FrameLoop, Kernel2Sprite
|
||||
using Joystick, MoveJoyX, MoveJoyY
|
||||
using SetXPos, SetHorizPos
|
||||
using SpriteShuffler, SpriteHider
|
||||
|
||||
using Kernel6Digit
|
||||
using JoyButton, BCDMath
|
||||
|
||||
entity Score [BCDScore6, PFColor, BGColor]
|
||||
const pfcolor = $3c
|
||||
const bgcolor = $02
|
||||
end
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 168
|
||||
const bgcolor = 0xa0
|
||||
end
|
||||
|
||||
entity Weird [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
.x...... 12
|
||||
.xx..... 14
|
||||
.xxx.... 16
|
||||
.xxxx... 18
|
||||
.xxxxx.. 1a
|
||||
.xxxxxx. 1c
|
||||
.xxx.xxx 1e
|
||||
.x.x.x.x 18
|
||||
---
|
||||
end
|
||||
|
||||
entity Cool [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
...xx... 48
|
||||
..xxxx.. 4a
|
||||
.xxxxxx. 4c
|
||||
xxxxxxxx 4e
|
||||
x..xx..x 4e
|
||||
x.xxx.xx 4e
|
||||
xxxxxxxx 4e
|
||||
xxxxxxxx 4e
|
||||
xxxxxxxx 4e
|
||||
xx....xx 4e
|
||||
xxxxxxxx 4e
|
||||
.xxxxxx. 4c
|
||||
..xxxx.. 4a
|
||||
---
|
||||
end
|
||||
|
||||
entity Cool2 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
...xx... 48
|
||||
..xxxx.. 4a
|
||||
.xxxxxx. 4c
|
||||
xxxxxxxx 8e
|
||||
x..xx..x ce
|
||||
x..xx..x ce
|
||||
xxxxxxxx ce
|
||||
xxxxxxxx 4e
|
||||
xxxxxxxx 4e
|
||||
xx.xx.xx 4e
|
||||
xxx..xxx 4e
|
||||
.xxxxxx. 4c
|
||||
..xxxx.. 4a
|
||||
---
|
||||
end
|
||||
|
||||
entity Bitmap1 [Bitmap]
|
||||
const bitmapdata = [1, 1, 3, 7, 15, 31, 63, 255]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Bitmap2 [Bitmap]
|
||||
const bitmapdata = [$18,$3e,$ff,$ff,$ff,$ff,$3e,$18]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Colormap1 [Colormap]
|
||||
const colormapdata = [6, 3, 6, 9, 12, 14, 31, 63]
|
||||
end
|
||||
|
||||
entity Sprite0 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
var xpos = 50
|
||||
var ypos = 150
|
||||
var bitmap = #Cool
|
||||
var colormap = #Cool
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Sprite1 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
var xpos = 100
|
||||
var ypos = 60
|
||||
var bitmap = #Cool2
|
||||
var colormap = #Cool2
|
||||
const plyrflags = 3
|
||||
end
|
||||
|
||||
entity Sprite2 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos]
|
||||
var xpos = 80
|
||||
var ypos = 90
|
||||
var bitmap = #Weird
|
||||
var colormap = #Weird
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Sprite3 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos]
|
||||
var xpos = 40
|
||||
var ypos = 150
|
||||
var bitmap = #Weird
|
||||
var colormap = #Weird
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Slot0 [SpriteSlot]
|
||||
var sprite = #Sprite0
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
var sprite = #Sprite1
|
||||
end
|
||||
entity Slot2 [SpriteSlot]
|
||||
var sprite = #Sprite2
|
||||
end
|
||||
entity Slot3 [SpriteSlot]
|
||||
var sprite = #Sprite3
|
||||
end
|
||||
|
||||
system Enemies
|
||||
on postframe do foreach [Sprite,HasYpos,-Player]
|
||||
---
|
||||
inc {{set ypos}}
|
||||
; inc {{set ypos}}
|
||||
---
|
||||
end
|
||||
|
||||
end demo
|
|
@ -0,0 +1,885 @@
|
|||
EVENT__start = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__kernel = 1
|
||||
EVENT__scanline = 1
|
||||
EVENT__joyleft = 1
|
||||
EVENT__joyright = 1
|
||||
EVENT__joyup = 1
|
||||
EVENT__joydown = 1
|
||||
EVENT__prekernel = 1
|
||||
EVENT__SetHorizPos = 1
|
||||
EVENT__AddBCD4 = 1
|
||||
EVENT__AddBCD2 = 1
|
||||
EVENT__SubBCD2 = 1
|
||||
.scope Main
|
||||
.zeropage
|
||||
Sprite_bitmap_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
HasColormap_colormap_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
HasXpos_xpos_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
HasYpos_ypos_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
SpriteSlot_sprite_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
BCDScore6_digits_b0:
|
||||
.res 1
|
||||
BCDScore6_digits_b8:
|
||||
.res 1
|
||||
BCDScore6_digits_b16:
|
||||
.res 1
|
||||
TEMP:
|
||||
Kernel2Sprite__2__tmp:
|
||||
Joystick__3__tmp:
|
||||
SpriteHider__9__tmp:
|
||||
.res 1
|
||||
SpriteShuffler__8__tmp:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
Kernel6Digit__10__tmp:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.code
|
||||
PFColor_pfcolor_b0:
|
||||
.byte 60
|
||||
BGColor_bgcolor_b0:
|
||||
.byte 2
|
||||
.byte 160
|
||||
KernelSection_lines_b0:
|
||||
.byte 168
|
||||
Bitmap_bitmapdata_b0:
|
||||
.byte <(Bitmap_bitmapdata_e2_b0+31)
|
||||
.byte <(Bitmap_bitmapdata_e3_b0+31)
|
||||
.byte <(Bitmap_bitmapdata_e4_b0+31)
|
||||
.byte <(Bitmap_bitmapdata_e5_b0+31)
|
||||
.byte <(Bitmap_bitmapdata_e6_b0+31)
|
||||
Bitmap_bitmapdata_b8:
|
||||
.byte >(Bitmap_bitmapdata_e2_b0+31)
|
||||
.byte >(Bitmap_bitmapdata_e3_b0+31)
|
||||
.byte >(Bitmap_bitmapdata_e4_b0+31)
|
||||
.byte >(Bitmap_bitmapdata_e5_b0+31)
|
||||
.byte >(Bitmap_bitmapdata_e6_b0+31)
|
||||
Bitmap_bitmapdata_e2_b0:
|
||||
.byte 85
|
||||
.byte 119
|
||||
.byte 126
|
||||
.byte 124
|
||||
.byte 120
|
||||
.byte 112
|
||||
.byte 96
|
||||
.byte 64
|
||||
Bitmap_height_b0:
|
||||
.byte 7
|
||||
.byte 12
|
||||
.byte 12
|
||||
.byte 8
|
||||
.byte 8
|
||||
Colormap_colormapdata_b0:
|
||||
.byte <(Colormap_colormapdata_e2_b0+31)
|
||||
.byte <(Colormap_colormapdata_e3_b0+31)
|
||||
.byte <(Colormap_colormapdata_e4_b0+31)
|
||||
.res 1
|
||||
.res 1
|
||||
.byte <(Colormap_colormapdata_e7_b0+31)
|
||||
Colormap_colormapdata_b8:
|
||||
.byte >(Colormap_colormapdata_e2_b0+31)
|
||||
.byte >(Colormap_colormapdata_e3_b0+31)
|
||||
.byte >(Colormap_colormapdata_e4_b0+31)
|
||||
.res 1
|
||||
.res 1
|
||||
.byte >(Colormap_colormapdata_e7_b0+31)
|
||||
Colormap_colormapdata_e2_b0:
|
||||
.byte 24
|
||||
.byte 30
|
||||
.byte 28
|
||||
.byte 26
|
||||
.byte 24
|
||||
.byte 22
|
||||
.byte 20
|
||||
.byte 18
|
||||
Bitmap_bitmapdata_e3_b0:
|
||||
.byte 60
|
||||
.byte 126
|
||||
.byte 255
|
||||
.byte 195
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 187
|
||||
.byte 153
|
||||
.byte 255
|
||||
.byte 126
|
||||
.byte 60
|
||||
.byte 24
|
||||
Colormap_colormapdata_e3_b0:
|
||||
.byte 74
|
||||
.byte 76
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 76
|
||||
.byte 74
|
||||
.byte 72
|
||||
Bitmap_bitmapdata_e4_b0:
|
||||
.byte 60
|
||||
.byte 126
|
||||
.byte 231
|
||||
.byte 219
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 153
|
||||
.byte 153
|
||||
.byte 255
|
||||
.byte 126
|
||||
.byte 60
|
||||
.byte 24
|
||||
Colormap_colormapdata_e4_b0:
|
||||
.byte 74
|
||||
.byte 76
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 78
|
||||
.byte 206
|
||||
.byte 206
|
||||
.byte 206
|
||||
.byte 142
|
||||
.byte 76
|
||||
.byte 74
|
||||
.byte 72
|
||||
Bitmap_bitmapdata_e5_b0:
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 3
|
||||
.byte 7
|
||||
.byte 15
|
||||
.byte 31
|
||||
.byte 63
|
||||
.byte 255
|
||||
Bitmap_bitmapdata_e6_b0:
|
||||
.byte 24
|
||||
.byte 62
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 62
|
||||
.byte 24
|
||||
Colormap_colormapdata_e7_b0:
|
||||
.byte 6
|
||||
.byte 3
|
||||
.byte 6
|
||||
.byte 9
|
||||
.byte 12
|
||||
.byte 14
|
||||
.byte 31
|
||||
.byte 63
|
||||
Sprite_plyrflags_b0:
|
||||
.byte 0
|
||||
.byte 3
|
||||
.byte 0
|
||||
.byte 0
|
||||
Main__INITDATA:
|
||||
.byte 1
|
||||
.byte 2
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 1
|
||||
.byte 2
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 50
|
||||
.byte 100
|
||||
.byte 80
|
||||
.byte 40
|
||||
.byte 150
|
||||
.byte 60
|
||||
.byte 90
|
||||
.byte 150
|
||||
.byte 0
|
||||
.byte 1
|
||||
.byte 2
|
||||
.byte 3
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #23
|
||||
: lda Main__INITDATA-1,y
|
||||
sta Sprite_bitmap_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_END
|
||||
|
||||
FRAME_START
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__5
|
||||
|
||||
; TODOO: can store KLINES in memory?
|
||||
.define KLINES #168
|
||||
.define KPAD 32
|
||||
; set height to zero in case no sprites
|
||||
lda #0
|
||||
sta Kernel2Sprite__2__tmp+8
|
||||
sta Kernel2Sprite__2__tmp+9
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__5
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__8
|
||||
|
||||
ldy #0
|
||||
Kernel2Sprite__preframe__9____each:
|
||||
ldx SpriteSlot_sprite_b0,y
|
||||
|
||||
; set player object flags
|
||||
lda Sprite_plyrflags_b0,x
|
||||
sta NUSIZ0,y
|
||||
sta REFP0,y
|
||||
; calculate screen height - ypos
|
||||
lda KLINES
|
||||
clc
|
||||
adc KPAD
|
||||
sec
|
||||
sbc HasYpos_ypos_b0,x
|
||||
sta Kernel2Sprite__2__tmp+11
|
||||
; calculate bitmap pointer
|
||||
stx Kernel2Sprite__2__tmp+12 ; save X (Sprite index)
|
||||
lda Sprite_bitmap_b0,x ; deref bitmap
|
||||
tax
|
||||
lda Bitmap_bitmapdata_b0,x
|
||||
sec
|
||||
sbc Kernel2Sprite__2__tmp+11
|
||||
sta Kernel2Sprite__2__tmp+0,y ; Y = sprite slot index
|
||||
lda Bitmap_bitmapdata_b8,x
|
||||
sbc #0
|
||||
sta Kernel2Sprite__2__tmp+2,y
|
||||
; get bitmap height
|
||||
lda Bitmap_height_b0,x
|
||||
sta Kernel2Sprite__2__tmp+8,y
|
||||
; calculate colormap pointer
|
||||
ldx Kernel2Sprite__2__tmp+12 ; restore X
|
||||
lda HasColormap_colormap_b0,x ; deref colormap
|
||||
tax
|
||||
lda Colormap_colormapdata_b0,x
|
||||
sec
|
||||
sbc Kernel2Sprite__2__tmp+11
|
||||
sta Kernel2Sprite__2__tmp+4,y
|
||||
lda Colormap_colormapdata_b8,x
|
||||
sbc #0
|
||||
sta Kernel2Sprite__2__tmp+6,y
|
||||
; save ypos
|
||||
ldx Kernel2Sprite__2__tmp+12 ; restore X
|
||||
lda HasYpos_ypos_b0,x
|
||||
sta Kernel2Sprite__2__tmp+10,y
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne Kernel2Sprite__preframe__9____each
|
||||
Kernel2Sprite__preframe__9____exit:
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__8
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__11
|
||||
|
||||
; shuffle pointers into (MSB, LSB) byte order
|
||||
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||
lda Kernel2Sprite__2__tmp+1
|
||||
ldy Kernel2Sprite__2__tmp+2
|
||||
sty Kernel2Sprite__2__tmp+1
|
||||
sta Kernel2Sprite__2__tmp+2
|
||||
lda Kernel2Sprite__2__tmp+5
|
||||
ldy Kernel2Sprite__2__tmp+6
|
||||
sty Kernel2Sprite__2__tmp+5
|
||||
sta Kernel2Sprite__2__tmp+6
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__11
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__13
|
||||
|
||||
lda #160
|
||||
sta COLUBK
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__13
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__16
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__16
|
||||
|
||||
;;; start action SetXPos__preframe__17
|
||||
|
||||
ldy #0
|
||||
SetXPos__preframe__18____each:
|
||||
ldx SpriteSlot_sprite_b0,y
|
||||
|
||||
lda HasXpos_xpos_b0,x
|
||||
|
||||
jsr SetHorizPos__SetHorizPos__20
|
||||
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne SetXPos__preframe__18____each
|
||||
SetXPos__preframe__18____exit:
|
||||
|
||||
;;; end action SetXPos__preframe__17
|
||||
|
||||
;;; start action SetXPos__preframe__22
|
||||
|
||||
;;; end action SetXPos__preframe__22
|
||||
|
||||
;;; start action Kernel6Digit__preframe__23
|
||||
|
||||
Digit0 = Kernel6Digit__10__tmp+0
|
||||
Digit1 = Kernel6Digit__10__tmp+2
|
||||
Digit2 = Kernel6Digit__10__tmp+4
|
||||
Digit3 = Kernel6Digit__10__tmp+6
|
||||
Digit4 = Kernel6Digit__10__tmp+8
|
||||
Digit5 = Kernel6Digit__10__tmp+10
|
||||
Kernel6Digit__preframe__25__BCD0 = Kernel6Digit__10__tmp+12
|
||||
Kernel6Digit__preframe__25__BCD1 = Kernel6Digit__10__tmp+13
|
||||
Kernel6Digit__preframe__25__BCD2 = Kernel6Digit__10__tmp+14
|
||||
|
||||
lda BCDScore6_digits_b0
|
||||
sta Kernel6Digit__preframe__25__BCD0
|
||||
lda BCDScore6_digits_b8
|
||||
sta Kernel6Digit__preframe__25__BCD1
|
||||
lda BCDScore6_digits_b16
|
||||
sta Kernel6Digit__preframe__25__BCD2
|
||||
ldx #0 ; leftmost bitmap
|
||||
ldy #2 ; start from most-sigificant BCD value
|
||||
Kernel6Digit__preframe__25__Loop:
|
||||
lda Kernel6Digit__preframe__25__BCD0,y ; get BCD value
|
||||
and #$f0 ; isolate high nibble (* 16)
|
||||
lsr ; shift right 1 bit (* 8)
|
||||
clc
|
||||
adc #<FontTable
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>FontTable
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
lda Kernel6Digit__preframe__25__BCD0,y ; get BCD value (again)
|
||||
and #$f ; isolate low nibble
|
||||
asl
|
||||
asl
|
||||
asl ; * 8
|
||||
clc
|
||||
adc #<FontTable
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>FontTable
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
dey ; next BCD value
|
||||
bpl Kernel6Digit__preframe__25__Loop ; repeat until < 0
|
||||
|
||||
;;; end action Kernel6Digit__preframe__23
|
||||
|
||||
|
||||
;;; start action SetXPos__prekernel__26
|
||||
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24
|
||||
sta HMCLR
|
||||
|
||||
;;; end action SetXPos__prekernel__26
|
||||
|
||||
KERNEL_START
|
||||
|
||||
;;; start action Kernel2Sprite__kernel__28
|
||||
|
||||
ldy #0
|
||||
sty VDELP0
|
||||
iny
|
||||
sty VDELP1
|
||||
|
||||
;;; end action Kernel2Sprite__kernel__28
|
||||
|
||||
jsr Kernel2Sprite__kernel__31
|
||||
|
||||
;;; start action Kernel2Sprite__kernel__40
|
||||
|
||||
lda #0
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
|
||||
;;; end action Kernel2Sprite__kernel__40
|
||||
|
||||
;;; start action Kernel6Digit__kernel__42
|
||||
|
||||
lda #60
|
||||
sta COLUP0
|
||||
sta COLUP1
|
||||
lda #3
|
||||
sta NUSIZ0
|
||||
sta NUSIZ1
|
||||
; set horizontal position of player objects
|
||||
sta WSYNC
|
||||
sta HMCLR
|
||||
SLEEPR 24
|
||||
sta RESP0
|
||||
sta RESP1
|
||||
lda #$10
|
||||
sta HMP1
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24 ; wait 24 cycles between write to HMOVE and HMxxx
|
||||
sta HMCLR
|
||||
lda #1
|
||||
sta VDELP0
|
||||
sta VDELP1
|
||||
|
||||
;;; end action Kernel6Digit__kernel__42
|
||||
|
||||
jsr Kernel6Digit__kernel__45
|
||||
|
||||
KERNEL_END
|
||||
|
||||
|
||||
;;; start action FrameLoop__postframe__48
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs FrameLoop__postframe__49__NoStart
|
||||
|
||||
FrameLoop__postframe__49__NoStart:
|
||||
|
||||
;;; end action FrameLoop__postframe__48
|
||||
|
||||
;;; start action Joystick__postframe__50
|
||||
|
||||
; 2 control inputs share a single byte, 4 bits each
|
||||
lda SWCHA
|
||||
sta Joystick__3__tmp+0
|
||||
|
||||
;;; end action Joystick__postframe__50
|
||||
|
||||
;;; start action Joystick__postframe__52
|
||||
|
||||
ldx #0
|
||||
Joystick__postframe__53____each:
|
||||
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joyright
|
||||
bcs Joystick__postframe__54__SkipMoveRight
|
||||
|
||||
;;; start action MoveJoyX__joyright__55
|
||||
|
||||
lda HasXpos_xpos_b0,x
|
||||
clc
|
||||
adc #1
|
||||
cmp #150
|
||||
bcs MoveJoyX__joyright__57__nomove
|
||||
sta HasXpos_xpos_b0,x
|
||||
MoveJoyX__joyright__57__nomove:
|
||||
|
||||
;;; end action MoveJoyX__joyright__55
|
||||
|
||||
Joystick__postframe__54__SkipMoveRight:
|
||||
.endif
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joyleft
|
||||
bcs Joystick__postframe__54__SkipMoveLeft
|
||||
|
||||
;;; start action MoveJoyX__joyleft__58
|
||||
|
||||
lda HasXpos_xpos_b0,x
|
||||
sec
|
||||
sbc #1
|
||||
bcc MoveJoyX__joyleft__60__nomove
|
||||
sta HasXpos_xpos_b0,x
|
||||
MoveJoyX__joyleft__60__nomove:
|
||||
|
||||
;;; end action MoveJoyX__joyleft__58
|
||||
|
||||
Joystick__postframe__54__SkipMoveLeft:
|
||||
.endif
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joydown
|
||||
bcs Joystick__postframe__54__SkipMoveDown
|
||||
|
||||
;;; start action MoveJoyY__joydown__61
|
||||
|
||||
lda HasYpos_ypos_b0,x
|
||||
clc
|
||||
adc #1
|
||||
cmp #220
|
||||
bcs MoveJoyY__joydown__63__nomove
|
||||
sta HasYpos_ypos_b0,x
|
||||
MoveJoyY__joydown__63__nomove:
|
||||
|
||||
;;; end action MoveJoyY__joydown__61
|
||||
|
||||
Joystick__postframe__54__SkipMoveDown:
|
||||
.endif
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joyup
|
||||
bcs Joystick__postframe__54__SkipMoveUp
|
||||
|
||||
;;; start action MoveJoyY__joyup__64
|
||||
|
||||
lda HasYpos_ypos_b0,x
|
||||
sec
|
||||
sbc #1
|
||||
bcc MoveJoyY__joyup__66__nomove
|
||||
sta HasYpos_ypos_b0,x
|
||||
MoveJoyY__joyup__66__nomove:
|
||||
|
||||
;;; end action MoveJoyY__joyup__64
|
||||
|
||||
Joystick__postframe__54__SkipMoveUp:
|
||||
.endif
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne Joystick__postframe__53____each
|
||||
Joystick__postframe__53____exit:
|
||||
|
||||
;;; end action Joystick__postframe__52
|
||||
|
||||
;;; start action SpriteShuffler__postframe__67
|
||||
|
||||
; load two sprite slots at left side of array
|
||||
lda SpriteSlot_sprite_b0
|
||||
sta SpriteShuffler__8__tmp+0
|
||||
lda SpriteSlot_sprite_b0+1
|
||||
sta SpriteShuffler__8__tmp+1
|
||||
; move two slots to the left
|
||||
ldx #0
|
||||
SpriteShuffler__postframe__69__loop:
|
||||
lda SpriteSlot_sprite_b0+2,x
|
||||
sta SpriteSlot_sprite_b0,x
|
||||
inx
|
||||
cpx #4-2
|
||||
bne SpriteShuffler__postframe__69__loop
|
||||
; store two sprite slots at right side of array
|
||||
lda SpriteShuffler__8__tmp+0
|
||||
sta SpriteSlot_sprite_b0+4-2
|
||||
lda SpriteShuffler__8__tmp+1
|
||||
sta SpriteSlot_sprite_b0+4-1
|
||||
|
||||
;;; end action SpriteShuffler__postframe__67
|
||||
|
||||
;;; start action SpriteHider__postframe__70
|
||||
|
||||
lda #4-1
|
||||
sta SpriteHider__9__tmp+0
|
||||
|
||||
;;; end action SpriteHider__postframe__70
|
||||
|
||||
;;; start action SpriteHider__postframe__73
|
||||
|
||||
ldy #0
|
||||
SpriteHider__postframe__74____each:
|
||||
ldx SpriteSlot_sprite_b0,y
|
||||
|
||||
lda HasYpos_ypos_b0,x
|
||||
cmp #192
|
||||
bcc SpriteHider__postframe__75__skip
|
||||
; swap this sprite slot with slot at end of array
|
||||
lda SpriteSlot_sprite_b0,y
|
||||
pha
|
||||
ldx SpriteHider__9__tmp+0 ; clobbers X, but no longer used
|
||||
lda SpriteSlot_sprite_b0,x
|
||||
sta SpriteSlot_sprite_b0,y
|
||||
pla
|
||||
sta SpriteSlot_sprite_b0,x
|
||||
dec SpriteHider__9__tmp+0
|
||||
SpriteHider__postframe__75__skip:
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne SpriteHider__postframe__74____each
|
||||
SpriteHider__postframe__74____exit:
|
||||
|
||||
;;; end action SpriteHider__postframe__73
|
||||
|
||||
;;; start action JoyButton__postframe__76
|
||||
|
||||
ldx #0
|
||||
JoyButton__postframe__77____each:
|
||||
|
||||
lda INPT4,x ;read button input
|
||||
bmi JoyButton__postframe__78__NotPressed
|
||||
|
||||
JoyButton__postframe__78__NotPressed:
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne JoyButton__postframe__77____each
|
||||
JoyButton__postframe__77____exit:
|
||||
|
||||
;;; end action JoyButton__postframe__76
|
||||
|
||||
;;; start action Enemies__postframe__79
|
||||
|
||||
ldx #0
|
||||
Enemies__postframe__80____each:
|
||||
|
||||
inc HasYpos_ypos_b0+2,x
|
||||
; inc HasYpos_ypos_b0+2,x
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne Enemies__postframe__80____each
|
||||
Enemies__postframe__80____exit:
|
||||
|
||||
;;; end action Enemies__postframe__79
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
.rodata
|
||||
__ALIGNORIGIN:
|
||||
.rodata
|
||||
SetHorizPos__SetHorizPos__20:
|
||||
|
||||
; SetHorizPos routine
|
||||
; A = X coordinate
|
||||
; Y = player number (0 or 1)
|
||||
sec ; set carry flag
|
||||
sta WSYNC ; start a new line
|
||||
:
|
||||
sbc #15 ; subtract 15
|
||||
bcs :- ; branch until negative
|
||||
eor #7 ; calculate fine offset
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta HMP0,y ; set fine offset
|
||||
sta RESP0,y ; fix coarse position
|
||||
sta WSYNC ; won't overrun if X < 150
|
||||
|
||||
rts
|
||||
|
||||
.assert >(SetHorizPos__SetHorizPos__20) = >(*), error, "SetHorizPos__SetHorizPos__20 crosses a page boundary!"
|
||||
|
||||
.assert (* - SetHorizPos__SetHorizPos__20) <= 22, error, .sprintf("SetHorizPos__SetHorizPos__20 does not fit in 22 bytes, it took %d!", (* - SetHorizPos__SetHorizPos__20))
|
||||
.rodata
|
||||
Kernel2Sprite__kernel__31:
|
||||
|
||||
ldy #168
|
||||
Kernel2Sprite__kernel__33__LVScan:
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__34
|
||||
|
||||
; draw player 0
|
||||
lda Kernel2Sprite__2__tmp+8 ; height
|
||||
dcp Kernel2Sprite__2__tmp+10 ; ypos
|
||||
bcs Kernel2Sprite__scanline__35__DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__35__DoDraw1:
|
||||
lda (Kernel2Sprite__2__tmp+0),y
|
||||
; .if 0 = 0 ; TODO: configurable?
|
||||
sta WSYNC
|
||||
; .endif
|
||||
sta GRP0
|
||||
lda (Kernel2Sprite__2__tmp+4),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda Kernel2Sprite__2__tmp+9 ; height
|
||||
dcp Kernel2Sprite__2__tmp+11 ; ypos
|
||||
bcs Kernel2Sprite__scanline__35__DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__35__DoDraw2:
|
||||
lda (Kernel2Sprite__2__tmp+2),y
|
||||
sta GRP1
|
||||
lda (Kernel2Sprite__2__tmp+6),y
|
||||
sta COLUP1
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__34
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__36
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__36
|
||||
|
||||
dey ; next scanline
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__37
|
||||
|
||||
; draw player 0
|
||||
lda Kernel2Sprite__2__tmp+8 ; height
|
||||
dcp Kernel2Sprite__2__tmp+10 ; ypos
|
||||
bcs Kernel2Sprite__scanline__38__DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__38__DoDraw1:
|
||||
lda (Kernel2Sprite__2__tmp+0),y
|
||||
; .if 1 = 0 ; TODO: configurable?
|
||||
sta WSYNC
|
||||
; .endif
|
||||
sta GRP0
|
||||
lda (Kernel2Sprite__2__tmp+4),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda Kernel2Sprite__2__tmp+9 ; height
|
||||
dcp Kernel2Sprite__2__tmp+11 ; ypos
|
||||
bcs Kernel2Sprite__scanline__38__DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__38__DoDraw2:
|
||||
lda (Kernel2Sprite__2__tmp+2),y
|
||||
sta GRP1
|
||||
lda (Kernel2Sprite__2__tmp+6),y
|
||||
sta COLUP1
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__37
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__39
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__39
|
||||
|
||||
dey ; next scanline
|
||||
bne Kernel2Sprite__kernel__33__LVScan ; repeat until out of lines
|
||||
|
||||
rts
|
||||
|
||||
.assert >(Kernel2Sprite__kernel__31) = >(*), error, "Kernel2Sprite__kernel__31 crosses a page boundary!"
|
||||
|
||||
.if <(* - __ALIGNORIGIN) > 256-72
|
||||
.align $100
|
||||
.endif
|
||||
.rodata
|
||||
Kernel6Digit__kernel__45:
|
||||
|
||||
; Display the resulting 48x8 bitmap
|
||||
; using the Digit0-5 pointers.
|
||||
Kernel6Digit__kernel__47__LoopCount = Kernel6Digit__10__tmp+12
|
||||
Kernel6Digit__kernel__47__Temp = Kernel6Digit__10__tmp+13
|
||||
|
||||
lda #2
|
||||
sta WSYNC
|
||||
sta COLUBK
|
||||
lda #7
|
||||
sta Kernel6Digit__kernel__47__LoopCount
|
||||
SLEEPR 20 ; TODO?
|
||||
:
|
||||
ldy Kernel6Digit__kernel__47__LoopCount ; counts backwards
|
||||
lda (Digit0),y ; load B0 (1st sprite byte)
|
||||
sta GRP0 ; B0 -> [GRP0]
|
||||
lda (Digit1),y ; load B1 -> A
|
||||
sta GRP1 ; B1 -> [GRP1], B0 -> GRP0
|
||||
sta WSYNC ; sync to next scanline
|
||||
lda (Digit2),y ; load B2 -> A
|
||||
sta GRP0 ; B2 -> [GRP0], B1 -> GRP1
|
||||
lda (Digit5),y ; load B5 -> A
|
||||
sta Kernel6Digit__kernel__47__Temp ; B5 -> temp
|
||||
lda (Digit4),y ; load B4
|
||||
tax ; -> X
|
||||
lda (Digit3),y ; load B3 -> A
|
||||
ldy Kernel6Digit__kernel__47__Temp ; load B5 -> Y
|
||||
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
||||
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
||||
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
||||
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
||||
dec Kernel6Digit__kernel__47__LoopCount ; go to next line
|
||||
bpl :- ; repeat until < 0
|
||||
|
||||
lda #0 ; clear the sprite registers
|
||||
sta WSYNC
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta COLUBK
|
||||
|
||||
rts
|
||||
|
||||
.assert >(Kernel6Digit__kernel__45) = >(*), error, "Kernel6Digit__kernel__45 crosses a page boundary!"
|
||||
|
||||
.assert (* - Kernel6Digit__kernel__45) <= 72, error, .sprintf("Kernel6Digit__kernel__45 does not fit in 72 bytes, it took %d!", (* - Kernel6Digit__kernel__45))
|
||||
FontTable:
|
||||
|
||||
;;; start action FontTable__FontTable__82
|
||||
|
||||
; Font table for digits 0-9 (8x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$3c,$66,$66,$76,$6e,$66,$3c,$00,$7e,$18,$18,$18,$38,$18,$18
|
||||
.byte $00,$7e,$60,$30,$0c,$06,$66,$3c,$00,$3c,$66,$06,$1c,$06,$66,$3c
|
||||
.byte $00,$06,$06,$7f,$66,$1e,$0e,$06,$00,$3c,$66,$06,$06,$7c,$60,$7e
|
||||
.byte $00,$3c,$66,$66,$7c,$60,$66,$3c,$00,$18,$18,$18,$18,$0c,$66,$7e
|
||||
.byte $00,$3c,$66,$66,$3c,$66,$66,$3c,$00,$3c,$66,$06,$3e,$66,$66,$3c
|
||||
|
||||
;;; end action FontTable__FontTable__82
|
||||
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
component KernelSection
|
||||
lines: 1..255
|
||||
end
|
||||
|
||||
component BGColor
|
||||
color: 0..255
|
||||
end
|
||||
|
||||
component FGColor
|
||||
color: 0..255
|
||||
end
|
||||
|
||||
demo Main
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const color = $18
|
||||
end
|
||||
entity [KernelSection,BGColor,FGColor]
|
||||
const lines = 2
|
||||
const color = $16
|
||||
end
|
||||
entity [KernelSection,FGColor]
|
||||
const lines = 2
|
||||
const color = $16
|
||||
end
|
||||
entity [KernelSection,FGColor]
|
||||
const lines = 2
|
||||
const color = $16
|
||||
end
|
||||
end demo
|
|
@ -0,0 +1 @@
|
|||
21:I found more than one field named "color" for this entity.
|
|
@ -0,0 +1,685 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
import "score.ecs"
|
||||
import "sound.ecs"
|
||||
import "velocity.ecs"
|
||||
import "kernel2.ecs"
|
||||
import "random.ecs"
|
||||
import "versatile.ecs"
|
||||
import "music.ecs"
|
||||
|
||||
// TODO: not yet used
|
||||
component Activity
|
||||
activity: enum [Standing,Walking,Jumping]
|
||||
end
|
||||
|
||||
component Enemy
|
||||
end
|
||||
|
||||
component Gravity
|
||||
end
|
||||
|
||||
component Jumper
|
||||
end
|
||||
|
||||
system MoveJoyVel
|
||||
// dampen velocity
|
||||
on frame8 do with [HasXpos]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
lsr
|
||||
clc
|
||||
adc #4
|
||||
sta {{<xvel}}
|
||||
---
|
||||
// move left and right
|
||||
on joyleft do with [HasXpos]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
sec
|
||||
sbc #1
|
||||
cmp #2
|
||||
bcc @nomove
|
||||
sta {{<xvel}}
|
||||
@nomove:
|
||||
---
|
||||
on joyright do with [HasXpos]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #14
|
||||
bcs @nomove
|
||||
sta {{<xvel}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system Gravity
|
||||
on frame8 do foreach [Gravity]
|
||||
---
|
||||
lda {{get bitmap}}
|
||||
cmp #{{&DudeStanding1}}-{{&Blank}}+1
|
||||
bcc @skip
|
||||
lda {{<yvel}}
|
||||
cmp #14
|
||||
bcs @nofall
|
||||
clc
|
||||
adc #2
|
||||
bne @done
|
||||
@nofall:
|
||||
lda #15
|
||||
@done:
|
||||
sta {{<yvel}}
|
||||
@skip:
|
||||
---
|
||||
on xmoved do with [TinyVelY]
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #7
|
||||
bcc @nodown
|
||||
{{!checkplatform}}
|
||||
@nodown:
|
||||
---
|
||||
on ymoved do with [TinyVelY]
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #7
|
||||
bcc @nodown
|
||||
{{!checkplatform}}
|
||||
@nodown:
|
||||
---
|
||||
on joybutton do with [Player]
|
||||
---
|
||||
; TODO
|
||||
lda {{get bitmap}}
|
||||
cmp #{{&DudeStanding1}}-{{&Blank}}+1
|
||||
bcs @nojump
|
||||
lda #0
|
||||
sta {{get yvel}}
|
||||
lda #{{&DudeJumping1}}-{{&Blank}}
|
||||
sta {{set bitmap}}
|
||||
{{!playsound 0 1 5}}
|
||||
@nojump:
|
||||
---
|
||||
end
|
||||
|
||||
system PlatformJumper
|
||||
on platformstopped do with [Jumper]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
and #$fe
|
||||
sta {{<ypos}}
|
||||
---
|
||||
on platformstopped do if [Player]
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #8
|
||||
beq @skip
|
||||
lda #8
|
||||
sta {{<yvel}}
|
||||
lda #{{&DudeStanding1}}-{{&Blank}}
|
||||
sta {{set bitmap}}
|
||||
{{!playsound 0 2 5}}
|
||||
@skip:
|
||||
---
|
||||
on platformnotstopped do if [Player]
|
||||
---
|
||||
lda #{{&DudeJumping1}}-{{&Blank}}
|
||||
sta {{set bitmap}}
|
||||
---
|
||||
end
|
||||
|
||||
resource PFCollideMask ---
|
||||
.byte $10,$20,$40,$80 ; PF0
|
||||
.byte $80,$40,$20,$10,$08,$04,$02,$01 ; PF1
|
||||
.byte $01,$02,$04,$08,$10,$20,$40,$80 ; PF2
|
||||
.byte $80,$40,$20,$10,$08,$04,$02,$01 ; PF2
|
||||
.byte $01,$02,$04,$08,$10,$20,$40,$80 ; PF1
|
||||
.byte $80,$40,$20,$10 ; PF0
|
||||
---
|
||||
resource PFCollideReg ---
|
||||
.byte $d,$d,$d,$d
|
||||
.byte $e,$e,$e,$e,$e,$e,$e,$e
|
||||
.byte $f,$f,$f,$f,$f,$f,$f,$f
|
||||
.byte $f,$f,$f,$f,$f,$f,$f,$f
|
||||
.byte $e,$e,$e,$e,$e,$e,$e,$e
|
||||
.byte $d,$d,$d,$d
|
||||
---
|
||||
|
||||
|
||||
system EnemyMotion
|
||||
on stopped do if [Enemy]
|
||||
---
|
||||
lda #5
|
||||
sta {{<yvel}}
|
||||
---
|
||||
on frame16 do foreach [Enemy]
|
||||
---
|
||||
lda {{<xvel}}
|
||||
adc {{<Les.xpos}}
|
||||
and #15
|
||||
sta {{<xvel}}
|
||||
---
|
||||
end
|
||||
|
||||
system EnemyCollider
|
||||
on preframe do once
|
||||
---
|
||||
sta CXCLR
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
lda CXPPMM
|
||||
bpl @nocollide
|
||||
{{!enemyspawn}}
|
||||
@nocollide:
|
||||
---
|
||||
on enemyspawn do once
|
||||
---
|
||||
{{!nextrand8}}
|
||||
and #$e0
|
||||
clc
|
||||
adc {{get Les.xpos}}
|
||||
and #$7f
|
||||
clc
|
||||
adc #10
|
||||
sta {{set Rock.xpos}}
|
||||
|
||||
{{!nextrand8}}
|
||||
and #$20
|
||||
clc
|
||||
adc {{get Les.ypos}}
|
||||
and #$7f
|
||||
clc
|
||||
adc #24
|
||||
sta {{set Rock.ypos}}
|
||||
|
||||
; TODO:
|
||||
;inc {{set Rock.bitmap}}
|
||||
---
|
||||
end
|
||||
|
||||
system EnemyDifficulty
|
||||
locals 1
|
||||
on preframe do foreach [Enemy]
|
||||
---
|
||||
{{!nextrand8}}
|
||||
lsr
|
||||
lsr
|
||||
cmp {{get PlayerScore.digits}}
|
||||
bcs @nomove
|
||||
; run away from player
|
||||
lda {{get xpos}}
|
||||
cmp #2
|
||||
bcc @nox
|
||||
cmp #140
|
||||
bcs @nox
|
||||
sec
|
||||
sbc {{get Les.xpos}}
|
||||
bcc @xdec
|
||||
inc {{set xpos}}
|
||||
inc {{set xpos}}
|
||||
@xdec:
|
||||
dec {{set xpos}}
|
||||
@nox:
|
||||
; move Y a bit
|
||||
lda {{get ypos}}
|
||||
cmp #40
|
||||
bcc @nomove
|
||||
cmp #170
|
||||
bcs @nomove
|
||||
sec
|
||||
sbc {{get Les.ypos}}
|
||||
bcc @ydec
|
||||
inc {{set ypos}}
|
||||
inc {{set ypos}}
|
||||
@ydec:
|
||||
dec {{set ypos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
//
|
||||
|
||||
scope Main
|
||||
|
||||
using FrameLoop, ResetConsole
|
||||
using Kernel2Digit, BCDMath
|
||||
using Kernel2Sprite
|
||||
using SetXPos, SetHorizPos
|
||||
using TinyMover
|
||||
using Gravity
|
||||
using VersatilePlayfield
|
||||
using PlatformJumper
|
||||
|
||||
using FrameCounter
|
||||
entity FrameCount [FrameCount]
|
||||
end
|
||||
|
||||
// TODO: this has to be after FrameCounter
|
||||
// for velocity damping to work correctly
|
||||
// but "after" keyword might be better
|
||||
using Joystick, JoyButton, MoveJoyVel with [Player]
|
||||
|
||||
using EnemyCollider
|
||||
using EnemyDifficulty
|
||||
|
||||
entity Level1 [VersatilePlayfield]
|
||||
decode vcs_versatile
|
||||
---
|
||||
.................... .. .. ..
|
||||
.................... .. .. 01
|
||||
.................... e8 .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
............xxx..... .. .. ..
|
||||
.............x...... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.........xxx........ .. .. ..
|
||||
..........xx........ .. .. ..
|
||||
...........x........ .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 18 .. ..
|
||||
.................... .. .. ..
|
||||
xxxx................ .. .. ..
|
||||
xxx................. .. .. ..
|
||||
xx.................. .. .. ..
|
||||
x................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 28 .. ..
|
||||
.................... .. .. ..
|
||||
....xxxxxx.......... .. .. ..
|
||||
......xxxx.......... .. .. ..
|
||||
........x........... .. .. ..
|
||||
.................... .. .. ..
|
||||
............xxx..... .. .. ..
|
||||
.............xx..xxx .. .. ..
|
||||
..............x...xx .. .. ..
|
||||
..................xx .. .. ..
|
||||
...................x .. .. ..
|
||||
...................x .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 38 .. ..
|
||||
.....xxxx........... .. .. ..
|
||||
......xxx........... .. .. ..
|
||||
.......xx........... .. .. ..
|
||||
........x........... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 48 .. ..
|
||||
............xxx..... .. .. ..
|
||||
.............xx..... .. .. ..
|
||||
..............x..... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... 58 .. ..
|
||||
..................xx .. .. ..
|
||||
.................xxx .. .. ..
|
||||
................xxxx .. .. ..
|
||||
..................xx .. .. ..
|
||||
...................x .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. 82 ..
|
||||
.................... .. .. ..
|
||||
.................... .. 84 ..
|
||||
.................... .. .. ..
|
||||
.................... .. 86 ..
|
||||
.................... .. .. ..
|
||||
.................... 68 .. ..
|
||||
............xxxxxx.. .. .. ..
|
||||
............xxxxxx.. .. .. ..
|
||||
--- end
|
||||
|
||||
entity Blank [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
........ 00
|
||||
---
|
||||
end
|
||||
entity DudeStanding1 [Bitmap,Colormap,Activity]
|
||||
const activity = Standing
|
||||
decode vcs_sprite
|
||||
---
|
||||
..xxx... f8
|
||||
.xxxxx.. f8
|
||||
x.xxxx.. f8
|
||||
.xxx.x.. f8
|
||||
x.xxxxx. f8
|
||||
x.xxxx.. f8
|
||||
..xx.... f8
|
||||
..xxxx.. f8
|
||||
...xxx.. f8
|
||||
...xx... f8
|
||||
...xx... f8
|
||||
..xxx... 38
|
||||
..xxx... 48
|
||||
.x.xxx.. 58
|
||||
x..xxx.. 68
|
||||
x..xx.x. 78
|
||||
x..xx..x 88
|
||||
...xxx.. 98
|
||||
..xxxx.. 98
|
||||
..x..x.. 98
|
||||
..x..xx. 98
|
||||
.xx...x. 98
|
||||
.x....x. 98
|
||||
.x....x. f8
|
||||
xx....xx f8
|
||||
---
|
||||
end
|
||||
entity DudeJumping1 [Bitmap,Colormap,Activity]
|
||||
const activity = Jumping
|
||||
const colormapdata = DudeStanding1.colormapdata
|
||||
decode vcs_bitmap
|
||||
---
|
||||
x.xxx...
|
||||
.xxxxx..
|
||||
x.xxxx..
|
||||
.xxx.x..
|
||||
..xxxxx.
|
||||
..xxxx..
|
||||
..xx....
|
||||
..xxx...
|
||||
...xxx..
|
||||
...xx...
|
||||
x..xx...
|
||||
x.xxx..x
|
||||
x.xxx.x.
|
||||
.x.xxx..
|
||||
...xx...
|
||||
...xx...
|
||||
...xx...
|
||||
...xxx..
|
||||
..xxxx..
|
||||
.xx..xx.
|
||||
.x....x.
|
||||
.x....x.
|
||||
.x....x.
|
||||
.x....x.
|
||||
xx....xx
|
||||
---
|
||||
end
|
||||
|
||||
entity Coin1 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
00001000 ca
|
||||
01001001 dc
|
||||
00100010 ee
|
||||
00000000 0e
|
||||
00011110 0e
|
||||
00100011 ee
|
||||
01000101 ee
|
||||
10001001 ee
|
||||
11111001 ee
|
||||
11101001 ee
|
||||
11011001 ee
|
||||
11111001 dc
|
||||
11111001 ca
|
||||
11011010 ca
|
||||
10111100 ca
|
||||
01111000 ca
|
||||
---
|
||||
end
|
||||
entity Coin2 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
..xxxx.. ca
|
||||
.xxxxxx. dc
|
||||
xxxxxxxx ee
|
||||
x..xx..x 0e
|
||||
xx.xx.xx 0e
|
||||
xxxxxxxx ee
|
||||
xxxxxxxx ee
|
||||
.xx..xx. ee
|
||||
.xxxxxx. ee
|
||||
.xx..xx. ee
|
||||
..xxxx.. dc
|
||||
...xx... ca
|
||||
........ ca
|
||||
---
|
||||
end
|
||||
|
||||
entity Empty [Sprite,HasBitmap,HasColormap]
|
||||
const bitmap = #Blank
|
||||
const colormap = #Blank
|
||||
end
|
||||
|
||||
entity Les [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,TinyVelX,TinyVelY,Player,Jumper,Gravity]
|
||||
var xpos = 73
|
||||
var ypos = 90
|
||||
var bitmap = #DudeJumping1
|
||||
const colormap = #DudeStanding1
|
||||
var plyrflags = $00
|
||||
var xvel = 8
|
||||
var yvel = 7
|
||||
end
|
||||
|
||||
entity Rock [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Enemy]
|
||||
var bitmap = #Coin1
|
||||
const colormap = #Coin1
|
||||
var xpos = 73
|
||||
var ypos = 140
|
||||
end
|
||||
|
||||
entity PlayerScore [BCDScore2]
|
||||
var scorecolor = $ca
|
||||
end
|
||||
entity TimerScore [BCDScore2]
|
||||
var scorecolor = $0e
|
||||
var digits = $00
|
||||
end
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 174
|
||||
var bgcolor = $80
|
||||
end
|
||||
|
||||
entity Slot0 [SpriteSlot]
|
||||
var sprite = #Les
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
var sprite = #Rock
|
||||
end
|
||||
|
||||
// SOUNDS
|
||||
|
||||
using SoundEngine
|
||||
|
||||
entity SFXNull [SoundEffect]
|
||||
const duration = 0
|
||||
const sounddata = [0]
|
||||
end
|
||||
entity SFXJump [SoundEffect]
|
||||
const duration = 14
|
||||
const sounddata = [
|
||||
$81,$83,$85,
|
||||
$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,
|
||||
$a8]
|
||||
end
|
||||
entity SFXBounce [SoundEffect]
|
||||
const duration = 10
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$40,$20,$10,
|
||||
$a4]
|
||||
end
|
||||
entity SFXScore [SoundEffect]
|
||||
const duration = 11
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$10,$20,$10,$08,
|
||||
$a2]
|
||||
end
|
||||
entity SFXScore2 [SoundEffect]
|
||||
const duration = 11
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$10,$20,$10,$08,
|
||||
$a8]
|
||||
end
|
||||
|
||||
// TODO: make sfx have priority over music?
|
||||
entity SFX1 [SoundChannel] end
|
||||
entity SFX2 [SoundChannel] end
|
||||
|
||||
// MUSIC
|
||||
|
||||
using MusicPlayer
|
||||
entity MusicPlayer [MusicPlayer]
|
||||
const volume = 10
|
||||
const tempo = 31
|
||||
end
|
||||
entity Music1 [MusicChannel] end
|
||||
entity Music2 [MusicChannel] end
|
||||
|
||||
//
|
||||
|
||||
using Random
|
||||
system GameManager
|
||||
// start the game? set timer to 99
|
||||
on joybutton do select [#TimerScore]
|
||||
---
|
||||
lda {{<digits}}
|
||||
bne @skip
|
||||
lda #$99
|
||||
sta {{<digits}}
|
||||
@skip:
|
||||
---
|
||||
// decrease the timer every 16 frames
|
||||
on frame16 do foreach [#TimerScore]
|
||||
---
|
||||
lda {{<digits}}
|
||||
beq @done
|
||||
{{!SubBCD2 1}}
|
||||
lda {{<digits}}
|
||||
bne @done
|
||||
{{!timerexpired}}
|
||||
@done:
|
||||
---
|
||||
// add score for each new spawn
|
||||
on enemyspawn do begin
|
||||
foreach [#PlayerScore]
|
||||
---
|
||||
{{!AddBCD2 1}}
|
||||
{{!playsound 1 3 10}}
|
||||
---
|
||||
// add timer for each new spawn
|
||||
foreach [#TimerScore]
|
||||
---
|
||||
{{!AddBCD2 10}}
|
||||
---
|
||||
end
|
||||
// subtract one when player wraps around vertically
|
||||
on ymoved do begin
|
||||
---
|
||||
lda {{<yvel}}
|
||||
cmp #7
|
||||
bcc @nowrap
|
||||
lda {{<ypos}}
|
||||
cmp #2
|
||||
bcs @nowrap
|
||||
{{!playerwrapped}}
|
||||
inc {{set ypos}}
|
||||
@nowrap:
|
||||
---
|
||||
end
|
||||
// TODO: doesn't work yet
|
||||
on playerwrapped do with [#PlayerScore]
|
||||
---
|
||||
{{!SubBCD2 1}}
|
||||
---
|
||||
// each frame, game is either running or stopped
|
||||
on preframe do once
|
||||
---
|
||||
lda {{<TimerScore.digits}}
|
||||
bne @gameon
|
||||
{{!gamestopped}}
|
||||
jmp @done
|
||||
@gameon:
|
||||
{{!gamerunning}}
|
||||
@done:
|
||||
---
|
||||
// stop everything when game is stopped
|
||||
// TODO: if "Sprite" it overwrites array elements
|
||||
on gamestopped do foreach [TinyVelX,TinyVelY]
|
||||
// on gamestopped do foreach [Sprite]
|
||||
---
|
||||
lda #8
|
||||
sta {{set xvel}}
|
||||
sta {{set yvel}}
|
||||
---
|
||||
// set colors when game is stopped
|
||||
on gamestopped do once
|
||||
---
|
||||
lda #$4c
|
||||
sta {{set TimerScore.scorecolor}}
|
||||
lda #$02
|
||||
sta {{set Kernel.bgcolor}}
|
||||
---
|
||||
// set colors when game is running
|
||||
on gamerunning do once
|
||||
---
|
||||
lda #$0a
|
||||
sta {{set TimerScore.scorecolor}}
|
||||
lda #$80
|
||||
sta {{set Kernel.bgcolor}}
|
||||
; blink when timer is close to zero
|
||||
lda {{get TimerScore.digits}}
|
||||
cmp #$20
|
||||
bcs @nocolor
|
||||
lda {{get FrameCount:frame}}
|
||||
lsr
|
||||
lsr
|
||||
and #$07
|
||||
ora #$40
|
||||
sta {{set Kernel.bgcolor}}
|
||||
@nocolor:
|
||||
---
|
||||
// play music when timer expires
|
||||
on timerexpired do once
|
||||
---
|
||||
;{{^SampleMusic}}
|
||||
{{!playmusic SampleMusic}}
|
||||
---
|
||||
on xxx_preframeloop do once
|
||||
---
|
||||
;{{^IntroMusic}}
|
||||
{{!playmusic IntroMusic}}
|
||||
---
|
||||
end
|
||||
|
||||
entity [Random8]
|
||||
end
|
||||
end
|
||||
|
||||
// TODO: use byte array too?
|
||||
resource IntroMusic ---
|
||||
.byte $27,$90,$2c,$8f,$2f,$8f,$33,$8f,$38,$8f,$3b,$8f,$20,$23,$88,$3a,$83,$38,$82,$37,$83,$38,$20,$ff
|
||||
---
|
|
@ -0,0 +1 @@
|
|||
Error: ENOENT: no such file or directory, open './test/ecs/velocity.ecs'
|
|
@ -0,0 +1,147 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
|
||||
system Kernel1Sprite
|
||||
locals 7
|
||||
|
||||
on kernelsetup do with [Sprite]
|
||||
---
|
||||
; set player object flags
|
||||
lda {{<plyrflags}}
|
||||
sta NUSIZ0
|
||||
sta REFP0
|
||||
---
|
||||
|
||||
on kernelsetup do with
|
||||
[Sprite,HasBitmap,HasColormap,HasYpos]
|
||||
---
|
||||
; calculate screen height - ypos
|
||||
lda {{<lines}}
|
||||
clc
|
||||
adc #32
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$5}}
|
||||
; calculate bitmap pointer
|
||||
stx {{$6}} ; save X (Sprite index)
|
||||
lda {{<bitmap}} ; deref bitmap
|
||||
tax
|
||||
lda {{<Bitmap:bitmapdata}},x
|
||||
sec
|
||||
sbc {{$5}}
|
||||
sta {{$0}} ; Y = sprite slot index
|
||||
lda {{>Bitmap:bitmapdata}},x
|
||||
sbc #0
|
||||
sta {{$1}}
|
||||
; get bitmap height
|
||||
lda {{<Bitmap:height}},x
|
||||
sta {{$4}}
|
||||
; calculate colormap pointer
|
||||
ldx {{$6}} ; restore X
|
||||
lda {{<colormap}} ; deref colormap
|
||||
tax
|
||||
lda {{<Colormap:colormapdata}},x
|
||||
sec
|
||||
sbc {{$5}}
|
||||
sta {{$2}}
|
||||
lda {{>Colormap:colormapdata}},x
|
||||
sbc #0
|
||||
sta {{$3}}
|
||||
; save ypos
|
||||
ldx {{$6}} ; restore X
|
||||
lda {{<ypos}}
|
||||
sta {{$5}}
|
||||
@nosprite:
|
||||
---
|
||||
|
||||
// TODO: what if > 1 player? or missile?
|
||||
on kernelsetup do with [Sprite,HasXpos]
|
||||
---
|
||||
ldy #0
|
||||
lda {{<xpos}}
|
||||
{{!SetHorizPos}}
|
||||
sta HMOVE
|
||||
---
|
||||
on prescanline do once
|
||||
---
|
||||
; draw player 0
|
||||
lda {{$4}} ; height
|
||||
dcp {{$5}} ; ypos
|
||||
bcs @DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw1:
|
||||
lda ({{$0}}),y
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
sta GRP0
|
||||
lda ({{$2}}),y
|
||||
sta COLUP0
|
||||
---
|
||||
on kerneldone do once
|
||||
---
|
||||
lda #0
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
---
|
||||
end
|
||||
|
||||
system KernelMissile
|
||||
locals 1
|
||||
// TODO: unroll loops
|
||||
on preframe do foreach [Missile,HasYpos] limit 1
|
||||
---
|
||||
lda {{<ypos}}
|
||||
sta {{$0}}
|
||||
---
|
||||
on scanline do foreach [Missile,HasYpos] limit 1
|
||||
---
|
||||
dec {{$0}}
|
||||
php
|
||||
pla
|
||||
sta ENAM0+{{const index}}-2
|
||||
---
|
||||
on kerneldone do foreach [Missile,HasYpos] limit 1
|
||||
---
|
||||
; skip 3 lines each kernel section
|
||||
lda #0
|
||||
sta ENAM0+{{const index}}-2
|
||||
dec {{$0}}
|
||||
dec {{$0}}
|
||||
dec {{$0}}
|
||||
---
|
||||
end
|
||||
|
||||
system KernelCollide
|
||||
locals 1
|
||||
on preframe do once
|
||||
---
|
||||
lda #$ff
|
||||
sta {{$0}} ; object index if collision
|
||||
---
|
||||
on kernelsetup do once
|
||||
---
|
||||
sta CXCLR ; clear collision flags
|
||||
---
|
||||
on kerneldone do with [Sprite]
|
||||
---
|
||||
lda CXM1P
|
||||
bpl @nocollide ; missile 1 <-> player 0?
|
||||
stx {{$0}} ; save object index
|
||||
@nocollide:
|
||||
---
|
||||
// TODO: somehow avoid select? pass arg to explode?
|
||||
on postframe do select [Sprite]
|
||||
---
|
||||
ldx {{$0}} ; get object index
|
||||
bmi @noexplode ; was there collision?
|
||||
{{!explode}}
|
||||
@noexplode:
|
||||
---
|
||||
end
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
|
||||
system Kernel2Sprite
|
||||
locals 13
|
||||
on preframe do with [KernelSection]
|
||||
---
|
||||
; TODOO: can store KLINES in memory?
|
||||
.define KLINES {{<lines}}
|
||||
.define KPAD 32
|
||||
; set height to zero in case no sprites
|
||||
lda #0
|
||||
sta {{$8}}
|
||||
sta {{$9}}
|
||||
---
|
||||
on preframe do join
|
||||
[SpriteSlot] with
|
||||
[Sprite] limit 2
|
||||
---
|
||||
; set player object flags
|
||||
lda {{<plyrflags}}
|
||||
sta NUSIZ0,y
|
||||
sta REFP0,y
|
||||
; calculate screen height - ypos
|
||||
lda KLINES
|
||||
clc
|
||||
adc KPAD
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$11}}
|
||||
; calculate bitmap pointer
|
||||
stx {{$12}} ; save X (Sprite index)
|
||||
lda {{<bitmap}} ; deref bitmap
|
||||
tax
|
||||
lda {{<Bitmap:bitmapdata}},x
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$0}},y ; Y = sprite slot index
|
||||
lda {{>Bitmap:bitmapdata}},x
|
||||
sbc #0
|
||||
sta {{$2}},y
|
||||
; get bitmap height
|
||||
lda {{<Bitmap:height}},x
|
||||
sta {{$8}},y
|
||||
; calculate colormap pointer
|
||||
ldx {{$12}} ; restore X
|
||||
lda {{<colormap}} ; deref colormap
|
||||
tax
|
||||
lda {{<Colormap:colormapdata}},x
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$4}},y
|
||||
lda {{>Colormap:colormapdata}},x
|
||||
sbc #0
|
||||
sta {{$6}},y
|
||||
; save ypos
|
||||
ldx {{$12}} ; restore X
|
||||
lda {{<ypos}}
|
||||
sta {{$10}},y
|
||||
---
|
||||
on preframe do once
|
||||
---
|
||||
; shuffle pointers into (MSB, LSB) byte order
|
||||
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||
lda {{$1}}
|
||||
ldy {{$2}}
|
||||
sty {{$1}}
|
||||
sta {{$2}}
|
||||
lda {{$5}}
|
||||
ldy {{$6}}
|
||||
sty {{$5}}
|
||||
sta {{$6}}
|
||||
---
|
||||
on preframe do if [KernelSection,BGColor]
|
||||
---
|
||||
lda {{<bgcolor}}
|
||||
sta COLUBK
|
||||
---
|
||||
on preframe do if [Missile,HasYpos]
|
||||
---
|
||||
lda KLINES
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$12}}
|
||||
---
|
||||
on kernel do with [KernelSection]
|
||||
---
|
||||
ldy #0
|
||||
sty VDELP0
|
||||
iny
|
||||
sty VDELP1
|
||||
---
|
||||
on kernel do critical with [KernelSection]
|
||||
---
|
||||
ldy {{<lines}}
|
||||
@LVScan:
|
||||
{{!scanline 0}}
|
||||
dey ; next scanline
|
||||
{{!scanline 1}}
|
||||
dey ; next scanline
|
||||
bne @LVScan ; repeat until out of lines
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
; draw player 0
|
||||
lda {{$8}} ; height
|
||||
dcp {{$10}} ; ypos
|
||||
bcs @DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw1:
|
||||
lda ({{$0}}),y
|
||||
; .if {{#0}} = 0 ; TODO: configurable?
|
||||
sta WSYNC
|
||||
; .endif
|
||||
sta GRP0
|
||||
lda ({{$4}}),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda {{$9}} ; height
|
||||
dcp {{$11}} ; ypos
|
||||
bcs @DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
@DoDraw2:
|
||||
lda ({{$2}}),y
|
||||
sta GRP1
|
||||
lda ({{$6}}),y
|
||||
sta COLUP1
|
||||
---
|
||||
on kernel do once
|
||||
---
|
||||
lda #0
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
---
|
||||
on scanline do if [Missile,HasYpos]
|
||||
---
|
||||
cpy {{$12}}
|
||||
php
|
||||
pla
|
||||
sta ENAM0
|
||||
---
|
||||
end
|
||||
|
||||
///
|
||||
|
||||
demo Main
|
||||
|
||||
using FrameLoop, Kernel2Sprite
|
||||
using Joystick, MoveJoyX, MoveJoyY
|
||||
using SetXPos, SetHorizPos
|
||||
using SpriteShuffler, SpriteHider
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 192
|
||||
const bgcolor = 0xa2
|
||||
end
|
||||
|
||||
entity Bitmap1 [Bitmap]
|
||||
const bitmapdata = [1, 1, 3, 7, 15, 31, 63, 127, 0]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Bitmap2 [Bitmap]
|
||||
const bitmapdata = [$18,$3e,$ff,$ff,$ff,$ff,$3e,$18, 0]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Colormap1 [Colormap]
|
||||
const colormapdata = [2, 4, 6, 8, 10, 12, 14, 14, 14]
|
||||
end
|
||||
|
||||
entity Sprite0 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 50
|
||||
init ypos = 150
|
||||
init bitmap = #Bitmap2
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Sprite1 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 100
|
||||
init ypos = 60
|
||||
init bitmap = #Bitmap1
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 3
|
||||
end
|
||||
|
||||
entity Sprite2 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 80
|
||||
init ypos = 90
|
||||
init bitmap = #Bitmap2
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 2
|
||||
end
|
||||
|
||||
entity Sprite3 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 40
|
||||
init ypos = 150
|
||||
init bitmap = #Bitmap1
|
||||
init colormap = #Colormap1
|
||||
const plyrflags = 0
|
||||
end
|
||||
/*
|
||||
entity [Missile,HasXpos,HasYpos]
|
||||
init xpos = 70
|
||||
init ypos = 70
|
||||
end
|
||||
*/
|
||||
entity Slot0 [SpriteSlot]
|
||||
init sprite = #Sprite0
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
init sprite = #Sprite1
|
||||
end
|
||||
entity Slot2 [SpriteSlot]
|
||||
init sprite = #Sprite2
|
||||
end
|
||||
entity Slot3 [SpriteSlot]
|
||||
init sprite = #Sprite3
|
||||
end
|
||||
|
||||
end demo
|
||||
|
||||
|
|
@ -0,0 +1,587 @@
|
|||
EVENT__start = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__kernel = 1
|
||||
EVENT__scanline = 1
|
||||
EVENT__joyleft = 1
|
||||
EVENT__joyright = 1
|
||||
EVENT__joyup = 1
|
||||
EVENT__joydown = 1
|
||||
EVENT__prekernel = 1
|
||||
EVENT__SetHorizPos = 1
|
||||
.scope Main
|
||||
.zeropage
|
||||
Sprite_bitmap_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
HasColormap_colormap_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
HasXpos_xpos_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
HasYpos_ypos_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
SpriteSlot_sprite_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
TEMP:
|
||||
Kernel2Sprite__2__tmp:
|
||||
Joystick__3__tmp:
|
||||
SpriteHider__9__tmp:
|
||||
.res 1
|
||||
SpriteShuffler__8__tmp:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.code
|
||||
KernelSection_lines_b0:
|
||||
.byte 192
|
||||
BGColor_bgcolor_b0:
|
||||
.byte 162
|
||||
Bitmap_bitmapdata_b0:
|
||||
.byte <(Bitmap_bitmapdata_e1_b0+31)
|
||||
.byte <(Bitmap_bitmapdata_e2_b0+31)
|
||||
Bitmap_bitmapdata_b8:
|
||||
.byte >(Bitmap_bitmapdata_e1_b0+31)
|
||||
.byte >(Bitmap_bitmapdata_e2_b0+31)
|
||||
Bitmap_bitmapdata_e1_b0:
|
||||
.byte 1
|
||||
.byte 1
|
||||
.byte 3
|
||||
.byte 7
|
||||
.byte 15
|
||||
.byte 31
|
||||
.byte 63
|
||||
.byte 127
|
||||
.byte 0
|
||||
Bitmap_height_b0:
|
||||
.byte 8
|
||||
.byte 8
|
||||
Bitmap_bitmapdata_e2_b0:
|
||||
.byte 24
|
||||
.byte 62
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 255
|
||||
.byte 62
|
||||
.byte 24
|
||||
.byte 0
|
||||
Colormap_colormapdata_b0:
|
||||
.byte <(Colormap_colormapdata_e3_b0+31)
|
||||
Colormap_colormapdata_b8:
|
||||
.byte >(Colormap_colormapdata_e3_b0+31)
|
||||
Colormap_colormapdata_e3_b0:
|
||||
.byte 2
|
||||
.byte 4
|
||||
.byte 6
|
||||
.byte 8
|
||||
.byte 10
|
||||
.byte 12
|
||||
.byte 14
|
||||
.byte 14
|
||||
.byte 14
|
||||
Sprite_plyrflags_b0:
|
||||
.byte 0
|
||||
.byte 3
|
||||
.byte 2
|
||||
.byte 0
|
||||
Main__INITDATA:
|
||||
.byte 1
|
||||
.byte 0
|
||||
.byte 1
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 50
|
||||
.byte 100
|
||||
.byte 80
|
||||
.byte 40
|
||||
.byte 150
|
||||
.byte 60
|
||||
.byte 90
|
||||
.byte 150
|
||||
.byte 0
|
||||
.byte 1
|
||||
.byte 2
|
||||
.byte 3
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #20
|
||||
: lda Main__INITDATA-1,y
|
||||
sta Sprite_bitmap_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_END
|
||||
|
||||
FRAME_START
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__5
|
||||
|
||||
; TODOO: can store KLINES in memory?
|
||||
.define KLINES #192
|
||||
.define KPAD 32
|
||||
; set height to zero in case no sprites
|
||||
lda #0
|
||||
sta Kernel2Sprite__2__tmp+8
|
||||
sta Kernel2Sprite__2__tmp+9
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__5
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__8
|
||||
|
||||
ldy #0
|
||||
Kernel2Sprite__preframe__9____each:
|
||||
ldx SpriteSlot_sprite_b0,y
|
||||
|
||||
; set player object flags
|
||||
lda Sprite_plyrflags_b0,x
|
||||
sta NUSIZ0,y
|
||||
sta REFP0,y
|
||||
; calculate screen height - ypos
|
||||
lda KLINES
|
||||
clc
|
||||
adc KPAD
|
||||
sec
|
||||
sbc HasYpos_ypos_b0,x
|
||||
sta Kernel2Sprite__2__tmp+11
|
||||
; calculate bitmap pointer
|
||||
stx Kernel2Sprite__2__tmp+12 ; save X (Sprite index)
|
||||
lda Sprite_bitmap_b0,x ; deref bitmap
|
||||
tax
|
||||
lda Bitmap_bitmapdata_b0,x
|
||||
sec
|
||||
sbc Kernel2Sprite__2__tmp+11
|
||||
sta Kernel2Sprite__2__tmp+0,y ; Y = sprite slot index
|
||||
lda Bitmap_bitmapdata_b8,x
|
||||
sbc #0
|
||||
sta Kernel2Sprite__2__tmp+2,y
|
||||
; get bitmap height
|
||||
lda Bitmap_height_b0,x
|
||||
sta Kernel2Sprite__2__tmp+8,y
|
||||
; calculate colormap pointer
|
||||
ldx Kernel2Sprite__2__tmp+12 ; restore X
|
||||
lda HasColormap_colormap_b0,x ; deref colormap
|
||||
tax
|
||||
lda Colormap_colormapdata_b0,x
|
||||
sec
|
||||
sbc Kernel2Sprite__2__tmp+11
|
||||
sta Kernel2Sprite__2__tmp+4,y
|
||||
lda Colormap_colormapdata_b8,x
|
||||
sbc #0
|
||||
sta Kernel2Sprite__2__tmp+6,y
|
||||
; save ypos
|
||||
ldx Kernel2Sprite__2__tmp+12 ; restore X
|
||||
lda HasYpos_ypos_b0,x
|
||||
sta Kernel2Sprite__2__tmp+10,y
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne Kernel2Sprite__preframe__9____each
|
||||
Kernel2Sprite__preframe__9____exit:
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__8
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__11
|
||||
|
||||
; shuffle pointers into (MSB, LSB) byte order
|
||||
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||
lda Kernel2Sprite__2__tmp+1
|
||||
ldy Kernel2Sprite__2__tmp+2
|
||||
sty Kernel2Sprite__2__tmp+1
|
||||
sta Kernel2Sprite__2__tmp+2
|
||||
lda Kernel2Sprite__2__tmp+5
|
||||
ldy Kernel2Sprite__2__tmp+6
|
||||
sty Kernel2Sprite__2__tmp+5
|
||||
sta Kernel2Sprite__2__tmp+6
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__11
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__13
|
||||
|
||||
lda #162
|
||||
sta COLUBK
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__13
|
||||
|
||||
;;; start action Kernel2Sprite__preframe__16
|
||||
|
||||
;;; end action Kernel2Sprite__preframe__16
|
||||
|
||||
;;; start action SetXPos__preframe__17
|
||||
|
||||
ldy #0
|
||||
SetXPos__preframe__18____each:
|
||||
ldx SpriteSlot_sprite_b0,y
|
||||
|
||||
lda HasXpos_xpos_b0,x
|
||||
|
||||
jsr SetHorizPos__SetHorizPos__20
|
||||
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne SetXPos__preframe__18____each
|
||||
SetXPos__preframe__18____exit:
|
||||
|
||||
;;; end action SetXPos__preframe__17
|
||||
|
||||
;;; start action SetXPos__preframe__22
|
||||
|
||||
;;; end action SetXPos__preframe__22
|
||||
|
||||
|
||||
;;; start action SetXPos__prekernel__23
|
||||
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24
|
||||
sta HMCLR
|
||||
|
||||
;;; end action SetXPos__prekernel__23
|
||||
|
||||
KERNEL_START
|
||||
|
||||
;;; start action Kernel2Sprite__kernel__25
|
||||
|
||||
ldy #0
|
||||
sty VDELP0
|
||||
iny
|
||||
sty VDELP1
|
||||
|
||||
;;; end action Kernel2Sprite__kernel__25
|
||||
|
||||
jsr Kernel2Sprite__kernel__28
|
||||
|
||||
;;; start action Kernel2Sprite__kernel__37
|
||||
|
||||
lda #0
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
|
||||
;;; end action Kernel2Sprite__kernel__37
|
||||
|
||||
KERNEL_END
|
||||
|
||||
|
||||
;;; start action FrameLoop__postframe__39
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs FrameLoop__postframe__40__NoStart
|
||||
|
||||
FrameLoop__postframe__40__NoStart:
|
||||
|
||||
;;; end action FrameLoop__postframe__39
|
||||
|
||||
;;; start action Joystick__postframe__41
|
||||
|
||||
; 2 control inputs share a single byte, 4 bits each
|
||||
lda SWCHA
|
||||
sta Joystick__3__tmp+0
|
||||
|
||||
;;; end action Joystick__postframe__41
|
||||
|
||||
;;; start action Joystick__postframe__43
|
||||
|
||||
ldx #0
|
||||
Joystick__postframe__44____each:
|
||||
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joyright
|
||||
bcs Joystick__postframe__45__SkipMoveRight
|
||||
|
||||
;;; start action MoveJoyX__joyright__46
|
||||
|
||||
lda HasXpos_xpos_b0,x
|
||||
clc
|
||||
adc #1
|
||||
cmp #150
|
||||
bcs MoveJoyX__joyright__48__nomove
|
||||
sta HasXpos_xpos_b0,x
|
||||
MoveJoyX__joyright__48__nomove:
|
||||
|
||||
;;; end action MoveJoyX__joyright__46
|
||||
|
||||
Joystick__postframe__45__SkipMoveRight:
|
||||
.endif
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joyleft
|
||||
bcs Joystick__postframe__45__SkipMoveLeft
|
||||
|
||||
;;; start action MoveJoyX__joyleft__49
|
||||
|
||||
lda HasXpos_xpos_b0,x
|
||||
sec
|
||||
sbc #1
|
||||
bcc MoveJoyX__joyleft__51__nomove
|
||||
sta HasXpos_xpos_b0,x
|
||||
MoveJoyX__joyleft__51__nomove:
|
||||
|
||||
;;; end action MoveJoyX__joyleft__49
|
||||
|
||||
Joystick__postframe__45__SkipMoveLeft:
|
||||
.endif
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joydown
|
||||
bcs Joystick__postframe__45__SkipMoveDown
|
||||
|
||||
;;; start action MoveJoyY__joydown__52
|
||||
|
||||
lda HasYpos_ypos_b0,x
|
||||
clc
|
||||
adc #1
|
||||
cmp #220
|
||||
bcs MoveJoyY__joydown__54__nomove
|
||||
sta HasYpos_ypos_b0,x
|
||||
MoveJoyY__joydown__54__nomove:
|
||||
|
||||
;;; end action MoveJoyY__joydown__52
|
||||
|
||||
Joystick__postframe__45__SkipMoveDown:
|
||||
.endif
|
||||
asl Joystick__3__tmp+0
|
||||
.ifdef EVENT__joyup
|
||||
bcs Joystick__postframe__45__SkipMoveUp
|
||||
|
||||
;;; start action MoveJoyY__joyup__55
|
||||
|
||||
lda HasYpos_ypos_b0,x
|
||||
sec
|
||||
sbc #1
|
||||
bcc MoveJoyY__joyup__57__nomove
|
||||
sta HasYpos_ypos_b0,x
|
||||
MoveJoyY__joyup__57__nomove:
|
||||
|
||||
;;; end action MoveJoyY__joyup__55
|
||||
|
||||
Joystick__postframe__45__SkipMoveUp:
|
||||
.endif
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne Joystick__postframe__44____each
|
||||
Joystick__postframe__44____exit:
|
||||
|
||||
;;; end action Joystick__postframe__43
|
||||
|
||||
;;; start action SpriteShuffler__postframe__58
|
||||
|
||||
; load two sprite slots at left side of array
|
||||
lda SpriteSlot_sprite_b0
|
||||
sta SpriteShuffler__8__tmp+0
|
||||
lda SpriteSlot_sprite_b0+1
|
||||
sta SpriteShuffler__8__tmp+1
|
||||
; move two slots to the left
|
||||
ldx #0
|
||||
SpriteShuffler__postframe__60__loop:
|
||||
lda SpriteSlot_sprite_b0+2,x
|
||||
sta SpriteSlot_sprite_b0,x
|
||||
inx
|
||||
cpx #4-2
|
||||
bne SpriteShuffler__postframe__60__loop
|
||||
; store two sprite slots at right side of array
|
||||
lda SpriteShuffler__8__tmp+0
|
||||
sta SpriteSlot_sprite_b0+4-2
|
||||
lda SpriteShuffler__8__tmp+1
|
||||
sta SpriteSlot_sprite_b0+4-1
|
||||
|
||||
;;; end action SpriteShuffler__postframe__58
|
||||
|
||||
;;; start action SpriteHider__postframe__61
|
||||
|
||||
lda #4-1
|
||||
sta SpriteHider__9__tmp+0
|
||||
|
||||
;;; end action SpriteHider__postframe__61
|
||||
|
||||
;;; start action SpriteHider__postframe__64
|
||||
|
||||
ldy #0
|
||||
SpriteHider__postframe__65____each:
|
||||
ldx SpriteSlot_sprite_b0,y
|
||||
|
||||
lda HasYpos_ypos_b0,x
|
||||
cmp #192
|
||||
bcc SpriteHider__postframe__66__skip
|
||||
; swap this sprite slot with slot at end of array
|
||||
lda SpriteSlot_sprite_b0,y
|
||||
pha
|
||||
ldx SpriteHider__9__tmp+0 ; clobbers X, but no longer used
|
||||
lda SpriteSlot_sprite_b0,x
|
||||
sta SpriteSlot_sprite_b0,y
|
||||
pla
|
||||
sta SpriteSlot_sprite_b0,x
|
||||
dec SpriteHider__9__tmp+0
|
||||
SpriteHider__postframe__66__skip:
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne SpriteHider__postframe__65____each
|
||||
SpriteHider__postframe__65____exit:
|
||||
|
||||
;;; end action SpriteHider__postframe__64
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
.rodata
|
||||
__ALIGNORIGIN:
|
||||
.rodata
|
||||
SetHorizPos__SetHorizPos__20:
|
||||
|
||||
; SetHorizPos routine
|
||||
; A = X coordinate
|
||||
; Y = player number (0 or 1)
|
||||
sec ; set carry flag
|
||||
sta WSYNC ; start a new line
|
||||
:
|
||||
sbc #15 ; subtract 15
|
||||
bcs :- ; branch until negative
|
||||
eor #7 ; calculate fine offset
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta HMP0,y ; set fine offset
|
||||
sta RESP0,y ; fix coarse position
|
||||
sta WSYNC ; won't overrun if X < 150
|
||||
|
||||
rts
|
||||
|
||||
.assert >(SetHorizPos__SetHorizPos__20) = >(*), error, "SetHorizPos__SetHorizPos__20 crosses a page boundary!"
|
||||
|
||||
.assert (* - SetHorizPos__SetHorizPos__20) <= 22, error, .sprintf("SetHorizPos__SetHorizPos__20 does not fit in 22 bytes, it took %d!", (* - SetHorizPos__SetHorizPos__20))
|
||||
.rodata
|
||||
Kernel2Sprite__kernel__28:
|
||||
|
||||
ldy #192
|
||||
Kernel2Sprite__kernel__30__LVScan:
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__31
|
||||
|
||||
; draw player 0
|
||||
lda Kernel2Sprite__2__tmp+8 ; height
|
||||
dcp Kernel2Sprite__2__tmp+10 ; ypos
|
||||
bcs Kernel2Sprite__scanline__32__DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__32__DoDraw1:
|
||||
lda (Kernel2Sprite__2__tmp+0),y
|
||||
; .if 0 = 0 ; TODO: configurable?
|
||||
sta WSYNC
|
||||
; .endif
|
||||
sta GRP0
|
||||
lda (Kernel2Sprite__2__tmp+4),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda Kernel2Sprite__2__tmp+9 ; height
|
||||
dcp Kernel2Sprite__2__tmp+11 ; ypos
|
||||
bcs Kernel2Sprite__scanline__32__DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__32__DoDraw2:
|
||||
lda (Kernel2Sprite__2__tmp+2),y
|
||||
sta GRP1
|
||||
lda (Kernel2Sprite__2__tmp+6),y
|
||||
sta COLUP1
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__31
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__33
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__33
|
||||
|
||||
dey ; next scanline
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__34
|
||||
|
||||
; draw player 0
|
||||
lda Kernel2Sprite__2__tmp+8 ; height
|
||||
dcp Kernel2Sprite__2__tmp+10 ; ypos
|
||||
bcs Kernel2Sprite__scanline__35__DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__35__DoDraw1:
|
||||
lda (Kernel2Sprite__2__tmp+0),y
|
||||
; .if 1 = 0 ; TODO: configurable?
|
||||
sta WSYNC
|
||||
; .endif
|
||||
sta GRP0
|
||||
lda (Kernel2Sprite__2__tmp+4),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda Kernel2Sprite__2__tmp+9 ; height
|
||||
dcp Kernel2Sprite__2__tmp+11 ; ypos
|
||||
bcs Kernel2Sprite__scanline__35__DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
Kernel2Sprite__scanline__35__DoDraw2:
|
||||
lda (Kernel2Sprite__2__tmp+2),y
|
||||
sta GRP1
|
||||
lda (Kernel2Sprite__2__tmp+6),y
|
||||
sta COLUP1
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__34
|
||||
|
||||
;;; start action Kernel2Sprite__scanline__36
|
||||
|
||||
;;; end action Kernel2Sprite__scanline__36
|
||||
|
||||
dey ; next scanline
|
||||
bne Kernel2Sprite__kernel__30__LVScan ; repeat until out of lines
|
||||
|
||||
rts
|
||||
|
||||
.assert >(Kernel2Sprite__kernel__28) = >(*), error, "Kernel2Sprite__kernel__28 crosses a page boundary!"
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,189 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component Song
|
||||
songdata: array of 0..255
|
||||
end
|
||||
|
||||
// TODO: merge with SoundChannel
|
||||
component MusicChannel
|
||||
duration: 0..255
|
||||
note: 0..255
|
||||
duty: 0..255
|
||||
end
|
||||
|
||||
component MusicPlayer
|
||||
timer: 0..255 default 255
|
||||
channel: [MusicChannel]
|
||||
songptr: 0..65535
|
||||
volume: 0..15 default 15
|
||||
tempo: 0..255 default 7
|
||||
end
|
||||
|
||||
|
||||
// Table of AUDF base values for each note
|
||||
resource FREQZ ---
|
||||
.byte 30, 30, 30, 30, 30, 28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 30, 29, 27, 25, 24, 22, 21, 20, 19, 18, 16, 15, 15, 14, 13, 12, 11, 11, 10, 31, 29, 27, 25, 24, 23, 21, 20, 19, 18, 16, 15, 15
|
||||
---
|
||||
// Table of duty-cycle bits for each note
|
||||
resource DUTYZ ---
|
||||
.byte 247, 247, 247, 247, 1, 73, 219, 1, 219, 73, 0, 219, 181, 85, 85, 85, 181, 219, 247, 1, 73, 181, 0, 73, 219, 17, 219, 17, 219, 73, 247, 85, 247, 1, 85, 247, 73, 247, 181, 17, 1, 0, 247, 247, 0, 1, 17, 73, 181, 0, 17, 0, 1, 85, 247, 73, 0, 181, 73, 1, 0, 247, 247, 0
|
||||
---
|
||||
// Table of AUDC values for each note
|
||||
resource TONEZ ---
|
||||
.byte 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||||
---
|
||||
|
||||
system MusicPlayer
|
||||
on preframe do once
|
||||
---
|
||||
{{!musicpulse}} ; update song
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
on prekernel do once
|
||||
---
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
on postkernel do once
|
||||
---
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
{{!musicframe}} ; update registers
|
||||
---
|
||||
// TODO: unroll?
|
||||
on musicframe do foreach [MusicChannel]
|
||||
---
|
||||
; Update channel pitch in AUDF0
|
||||
; 8-bit rotation of duty cycle bits
|
||||
lda {{get duration}}
|
||||
beq :++
|
||||
lda {{set duty}}
|
||||
asl
|
||||
bcc :+
|
||||
ora #1
|
||||
: sta {{set duty}}
|
||||
lda {{get note}}
|
||||
beq :+
|
||||
; If next bit is set, add 1 to AUDF0
|
||||
adc #0
|
||||
sta AUDF0,x
|
||||
:
|
||||
---
|
||||
on musicpulse do foreach [MusicChannel]
|
||||
---
|
||||
; Decrement the volumes for each channel
|
||||
; Also decrement next-note timer, fetch next note
|
||||
lda {{get duration}}
|
||||
beq :+
|
||||
lsr
|
||||
sta AUDV0,x
|
||||
dec {{set duration}}
|
||||
:
|
||||
---
|
||||
on musicpulse do with [MusicPlayer]
|
||||
---
|
||||
lda {{get timer}}
|
||||
bmi @Done
|
||||
beq @NextData
|
||||
dec {{set timer}}
|
||||
jmp @Done
|
||||
; Timer ran out, so fetch next note
|
||||
@NextData:
|
||||
ldx #0
|
||||
lda ({{get songptr}},x)
|
||||
bmi @LoadDuration
|
||||
; < $80, play next note
|
||||
ldx {{get channel}} ; next channel
|
||||
tay
|
||||
{{!musicnote}}
|
||||
inx
|
||||
txa
|
||||
and #1
|
||||
sta {{set channel}} ; inc next channel
|
||||
jmp @IncDataPtr
|
||||
; >= $80, load next duration
|
||||
@LoadDuration:
|
||||
cmp #$ff ; $ff = end of song
|
||||
bne @NoResetTrack
|
||||
sta {{set timer}}
|
||||
{{!musicdone}}
|
||||
jmp @Done
|
||||
@NoResetTrack:
|
||||
and #$7f
|
||||
; asl
|
||||
sta {{set timer}} ; store duration * 2
|
||||
@IncDataPtr:
|
||||
; increment song pointer
|
||||
inc {{set songptr 0}}
|
||||
bne @Done
|
||||
inc {{set songptr 8}}
|
||||
@Done:
|
||||
---
|
||||
// TODO: should use "with"?
|
||||
on musicnote do select all [MusicChannel]
|
||||
---
|
||||
; Play a note
|
||||
; X = channel (0,1)
|
||||
; Y = note index (0-63)
|
||||
lda {{^FREQZ}},y
|
||||
sta {{base note}},x
|
||||
lda {{^DUTYZ}},y
|
||||
sta {{base duty}},x
|
||||
lda {{^TONEZ}},y
|
||||
sta AUDC0,x
|
||||
; TODO: consts?
|
||||
lda {{get MusicPlayer:tempo}}
|
||||
sta {{base duration}},x
|
||||
lda {{get MusicPlayer:volume}}
|
||||
sta AUDV0,x
|
||||
---
|
||||
on playmusic do foreach [MusicPlayer] limit 1
|
||||
---
|
||||
lda #<{{arg 0}}
|
||||
sta {{set songptr 0}}
|
||||
lda #>{{arg 0}}
|
||||
sta {{set songptr 8}}
|
||||
lda #0
|
||||
sta {{set timer}}
|
||||
---
|
||||
on stopmusic do foreach [MusicPlayer] limit 1
|
||||
---
|
||||
lda #$ff
|
||||
sta {{set timer}}
|
||||
---
|
||||
end
|
||||
|
||||
///
|
||||
|
||||
demo music
|
||||
using FrameLoop
|
||||
using MusicPlayer
|
||||
entity [MusicChannel] end
|
||||
entity [MusicChannel] end
|
||||
entity MusicPlayer [MusicPlayer]
|
||||
const volume = 10
|
||||
const tempo = 31
|
||||
end
|
||||
system music
|
||||
on musicdone do with [MusicPlayer]
|
||||
---
|
||||
; TODO: nested exprs
|
||||
; {{!playmusic ^SampleMusic}}
|
||||
;{{^SampleMusic}}
|
||||
{{!playmusic SampleMusic}}
|
||||
---
|
||||
on preframeloop do once
|
||||
---
|
||||
{{!musicdone}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
||||
resource SampleMusic ---
|
||||
.byte $35,$41,$8a,$37,$43,$8a,$33,$3f,$8a,$30,$3c,$94,$3e,$32,$8a,$3a,$2e,$94,$35,$29,$8a,$37,$2b,$8a,$33,$27,$8a,$30,$24,$94,$32,$26,$8a,$2e,$22,$94,$29,$1d,$8a,$2b,$1f,$8a,$27,$1b,$8a,$24,$18,$94,$1a,$26,$8a,$18,$24,$8a,$17,$23,$8a,$16,$22,$a8,$3a,$35,$ff
|
||||
---
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
EVENT__start = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__prekernel = 1
|
||||
EVENT__postkernel = 1
|
||||
EVENT__musicframe = 1
|
||||
EVENT__musicpulse = 1
|
||||
EVENT__musicnote = 1
|
||||
EVENT__playmusic = 1
|
||||
EVENT__stopmusic = 1
|
||||
EVENT__musicdone = 1
|
||||
EVENT__preframeloop = 1
|
||||
.scope music
|
||||
.zeropage
|
||||
MusicPlayer_timer_b0:
|
||||
.res 1
|
||||
MusicChannel_duration_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
MusicChannel_note_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
MusicChannel_duty_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
MusicPlayer_channel_b0:
|
||||
.res 1
|
||||
MusicPlayer_songptr_b0:
|
||||
.res 1
|
||||
MusicPlayer_songptr_b8:
|
||||
.res 1
|
||||
.code
|
||||
MusicPlayer_volume_b0:
|
||||
.byte 10
|
||||
MusicPlayer_tempo_b0:
|
||||
.byte 31
|
||||
music__INITDATA:
|
||||
.byte 255
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #10
|
||||
: lda music__INITDATA-1,y
|
||||
sta MusicPlayer_timer_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
|
||||
;;; start action music__preframeloop__5
|
||||
|
||||
|
||||
;;; start action music__musicdone__7
|
||||
|
||||
; TODO: nested exprs
|
||||
;
|
||||
jsr MusicPlayer__playmusic__10
|
||||
|
||||
;SampleMusic
|
||||
|
||||
jsr MusicPlayer__playmusic__13
|
||||
|
||||
|
||||
;;; end action music__musicdone__7
|
||||
|
||||
|
||||
;;; end action music__preframeloop__5
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_END
|
||||
|
||||
FRAME_START
|
||||
|
||||
;;; start action MusicPlayer__preframe__16
|
||||
|
||||
|
||||
;;; start action MusicPlayer__musicpulse__18
|
||||
|
||||
ldx #0
|
||||
MusicPlayer__musicpulse__19____each:
|
||||
|
||||
; Decrement the volumes for each channel
|
||||
; Also decrement next-note timer, fetch next note
|
||||
lda MusicChannel_duration_b0,x
|
||||
beq :+
|
||||
lsr
|
||||
sta AUDV0,x
|
||||
dec MusicChannel_duration_b0,x
|
||||
:
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne MusicPlayer__musicpulse__19____each
|
||||
MusicPlayer__musicpulse__19____exit:
|
||||
|
||||
;;; end action MusicPlayer__musicpulse__18
|
||||
|
||||
;;; start action MusicPlayer__musicpulse__21
|
||||
|
||||
lda MusicPlayer_timer_b0
|
||||
bmi MusicPlayer__musicpulse__23__Done
|
||||
beq MusicPlayer__musicpulse__23__NextData
|
||||
dec MusicPlayer_timer_b0
|
||||
jmp MusicPlayer__musicpulse__23__Done
|
||||
; Timer ran out, so fetch next note
|
||||
MusicPlayer__musicpulse__23__NextData:
|
||||
ldx #0
|
||||
lda (MusicPlayer_songptr_b0,x)
|
||||
bmi MusicPlayer__musicpulse__23__LoadDuration
|
||||
; < $80, play next note
|
||||
ldx MusicPlayer_channel_b0 ; next channel
|
||||
tay
|
||||
|
||||
;;; start action MusicPlayer__musicnote__24
|
||||
|
||||
; Play a note
|
||||
; X = channel (0,1)
|
||||
; Y = note index (0-63)
|
||||
lda FREQZ,y
|
||||
sta MusicChannel_note_b0,x
|
||||
lda DUTYZ,y
|
||||
sta MusicChannel_duty_b0,x
|
||||
lda TONEZ,y
|
||||
sta AUDC0,x
|
||||
; TODO: consts?
|
||||
lda MusicPlayer_tempo_b0
|
||||
sta MusicChannel_duration_b0,x
|
||||
lda MusicPlayer_volume_b0
|
||||
sta AUDV0,x
|
||||
|
||||
;;; end action MusicPlayer__musicnote__24
|
||||
|
||||
inx
|
||||
txa
|
||||
and #1
|
||||
sta MusicPlayer_channel_b0 ; inc next channel
|
||||
jmp MusicPlayer__musicpulse__23__IncDataPtr
|
||||
; >= $80, load next duration
|
||||
MusicPlayer__musicpulse__23__LoadDuration:
|
||||
cmp #$ff ; $ff = end of song
|
||||
bne MusicPlayer__musicpulse__23__NoResetTrack
|
||||
sta MusicPlayer_timer_b0
|
||||
|
||||
;;; start action music__musicdone__27
|
||||
|
||||
; TODO: nested exprs
|
||||
;
|
||||
jsr MusicPlayer__playmusic__10
|
||||
|
||||
;SampleMusic
|
||||
|
||||
jsr MusicPlayer__playmusic__13
|
||||
|
||||
|
||||
;;; end action music__musicdone__27
|
||||
|
||||
jmp MusicPlayer__musicpulse__23__Done
|
||||
MusicPlayer__musicpulse__23__NoResetTrack:
|
||||
and #$7f
|
||||
; asl
|
||||
sta MusicPlayer_timer_b0 ; store duration * 2
|
||||
MusicPlayer__musicpulse__23__IncDataPtr:
|
||||
; increment song pointer
|
||||
inc MusicPlayer_songptr_b0
|
||||
bne MusicPlayer__musicpulse__23__Done
|
||||
inc MusicPlayer_songptr_b8
|
||||
MusicPlayer__musicpulse__23__Done:
|
||||
|
||||
;;; end action MusicPlayer__musicpulse__21
|
||||
; update song
|
||||
|
||||
jsr MusicPlayer__musicframe__36
|
||||
; update registers
|
||||
|
||||
;;; end action MusicPlayer__preframe__16
|
||||
|
||||
|
||||
;;; start action MusicPlayer__prekernel__39
|
||||
|
||||
|
||||
jsr MusicPlayer__musicframe__36
|
||||
; update registers
|
||||
|
||||
;;; end action MusicPlayer__prekernel__39
|
||||
|
||||
KERNEL_START
|
||||
|
||||
KERNEL_END
|
||||
|
||||
;;; start action MusicPlayer__postkernel__44
|
||||
|
||||
|
||||
jsr MusicPlayer__musicframe__36
|
||||
; update registers
|
||||
|
||||
;;; end action MusicPlayer__postkernel__44
|
||||
|
||||
|
||||
;;; start action FrameLoop__postframe__49
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs FrameLoop__postframe__50__NoStart
|
||||
|
||||
FrameLoop__postframe__50__NoStart:
|
||||
|
||||
;;; end action FrameLoop__postframe__49
|
||||
|
||||
;;; start action MusicPlayer__postframe__51
|
||||
|
||||
|
||||
jsr MusicPlayer__musicframe__36
|
||||
; update registers
|
||||
|
||||
;;; end action MusicPlayer__postframe__51
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
.rodata
|
||||
__ALIGNORIGIN:
|
||||
.rodata
|
||||
MusicPlayer__playmusic__10:
|
||||
|
||||
lda #<^SampleMusic
|
||||
sta MusicPlayer_songptr_b0
|
||||
lda #>^SampleMusic
|
||||
sta MusicPlayer_songptr_b8
|
||||
lda #0
|
||||
sta MusicPlayer_timer_b0
|
||||
|
||||
rts
|
||||
.rodata
|
||||
MusicPlayer__playmusic__13:
|
||||
|
||||
lda #<SampleMusic
|
||||
sta MusicPlayer_songptr_b0
|
||||
lda #>SampleMusic
|
||||
sta MusicPlayer_songptr_b8
|
||||
lda #0
|
||||
sta MusicPlayer_timer_b0
|
||||
|
||||
rts
|
||||
.rodata
|
||||
MusicPlayer__musicframe__36:
|
||||
|
||||
ldx #0
|
||||
MusicPlayer__musicframe__37____each:
|
||||
|
||||
; Update channel pitch in AUDF0
|
||||
; 8-bit rotation of duty cycle bits
|
||||
lda MusicChannel_duration_b0,x
|
||||
beq :++
|
||||
lda MusicChannel_duty_b0,x
|
||||
asl
|
||||
bcc :+
|
||||
ora #1
|
||||
: sta MusicChannel_duty_b0,x
|
||||
lda MusicChannel_note_b0,x
|
||||
beq :+
|
||||
; If next bit is set, add 1 to AUDF0
|
||||
adc #0
|
||||
sta AUDF0,x
|
||||
:
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne MusicPlayer__musicframe__37____each
|
||||
MusicPlayer__musicframe__37____exit:
|
||||
|
||||
rts
|
||||
SampleMusic:
|
||||
|
||||
;;; start action SampleMusic__SampleMusic__56
|
||||
|
||||
.byte $35,$41,$8a,$37,$43,$8a,$33,$3f,$8a,$30,$3c,$94,$3e,$32,$8a,$3a,$2e,$94,$35,$29,$8a,$37,$2b,$8a,$33,$27,$8a,$30,$24,$94,$32,$26,$8a,$2e,$22,$94,$29,$1d,$8a,$2b,$1f,$8a,$27,$1b,$8a,$24,$18,$94,$1a,$26,$8a,$18,$24,$8a,$17,$23,$8a,$16,$22,$a8,$3a,$35,$ff
|
||||
|
||||
;;; end action SampleMusic__SampleMusic__56
|
||||
|
||||
FREQZ:
|
||||
|
||||
;;; start action FREQZ__FREQZ__58
|
||||
|
||||
.byte 30, 30, 30, 30, 30, 28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 13, 12, 12, 11, 10, 10, 9, 8, 8, 7, 7, 6, 6, 5, 5, 30, 29, 27, 25, 24, 22, 21, 20, 19, 18, 16, 15, 15, 14, 13, 12, 11, 11, 10, 31, 29, 27, 25, 24, 23, 21, 20, 19, 18, 16, 15, 15
|
||||
|
||||
;;; end action FREQZ__FREQZ__58
|
||||
|
||||
DUTYZ:
|
||||
|
||||
;;; start action DUTYZ__DUTYZ__60
|
||||
|
||||
.byte 247, 247, 247, 247, 1, 73, 219, 1, 219, 73, 0, 219, 181, 85, 85, 85, 181, 219, 247, 1, 73, 181, 0, 73, 219, 17, 219, 17, 219, 73, 247, 85, 247, 1, 85, 247, 73, 247, 181, 17, 1, 0, 247, 247, 0, 1, 17, 73, 181, 0, 17, 0, 1, 85, 247, 73, 0, 181, 73, 1, 0, 247, 247, 0
|
||||
|
||||
;;; end action DUTYZ__DUTYZ__60
|
||||
|
||||
TONEZ:
|
||||
|
||||
;;; start action TONEZ__TONEZ__62
|
||||
|
||||
.byte 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
|
||||
|
||||
;;; end action TONEZ__TONEZ__62
|
||||
|
||||
.endscope
|
||||
music__Start = music::__Start
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
component Xpos
|
||||
x: 0..255
|
||||
end
|
||||
component Player
|
||||
end
|
||||
component Enemy
|
||||
end
|
||||
|
||||
scope Main
|
||||
entity foo [Xpos]
|
||||
end
|
||||
entity p [Xpos,Player]
|
||||
init x = 50
|
||||
end
|
||||
entity e1 [Xpos,Enemy]
|
||||
init x = 100
|
||||
end
|
||||
entity e2 [Xpos,Enemy]
|
||||
init x = 150
|
||||
end
|
||||
system move
|
||||
on start do foreach [Enemy]
|
||||
---
|
||||
lda {{<x}}
|
||||
---
|
||||
end
|
||||
end
|
|
@ -0,0 +1,38 @@
|
|||
EVENT__start = 1
|
||||
.scope Main
|
||||
.zeropage
|
||||
Xpos_x_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.code
|
||||
Main__INITDATA:
|
||||
.byte 0
|
||||
.byte 50
|
||||
.byte 100
|
||||
.byte 150
|
||||
__Start:
|
||||
|
||||
ldy #4
|
||||
: lda Main__INITDATA-1,y
|
||||
sta Xpos_x_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action move__start__1
|
||||
|
||||
ldx #0
|
||||
move__start__2____each:
|
||||
|
||||
lda Xpos_x_b0+2,x
|
||||
|
||||
inx
|
||||
cpx #2
|
||||
jne move__start__2____each
|
||||
move__start__2____exit:
|
||||
|
||||
;;; end action move__start__1
|
||||
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,42 @@
|
|||
|
||||
component RoomGraphics
|
||||
graphics: array 0..8 of 0..255
|
||||
end
|
||||
|
||||
component Room
|
||||
fgcolor: 0..255
|
||||
bgcolor: 0..255
|
||||
north: [Room]
|
||||
east: [Room]
|
||||
south: [Room]
|
||||
west: [Room]
|
||||
end
|
||||
|
||||
component Location
|
||||
room: [Room]
|
||||
end
|
||||
|
||||
scope Main
|
||||
/*
|
||||
entity NullRoom [Room]
|
||||
end
|
||||
*/
|
||||
entity InsideDailyPlanet [Room]
|
||||
const fgcolor = $0c
|
||||
const bgcolor = $12
|
||||
const north = #InsideDailyPlanet
|
||||
const south = #InsideDailyPlanet
|
||||
const east = #OutsideDailyPlanet
|
||||
const west = #InsideDailyPlanet
|
||||
end
|
||||
|
||||
entity OutsideDailyPlanet [Room]
|
||||
const fgcolor = $0c
|
||||
const bgcolor = $12
|
||||
const north = #InsideDailyPlanet
|
||||
const south = #InsideDailyPlanet
|
||||
const east = #InsideDailyPlanet
|
||||
const west = #OutsideDailyPlanet
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
.scope Main
|
||||
.zeropage
|
||||
.code
|
||||
Room_fgcolor_b0:
|
||||
.byte 12
|
||||
.byte 12
|
||||
Room_bgcolor_b0:
|
||||
.byte 18
|
||||
.byte 18
|
||||
Room_north_b0:
|
||||
.byte 0
|
||||
.byte 0
|
||||
Room_east_b0:
|
||||
.byte 1
|
||||
.byte 0
|
||||
Room_south_b0:
|
||||
.byte 0
|
||||
.byte 0
|
||||
Room_west_b0:
|
||||
.byte 0
|
||||
.byte 1
|
||||
__Start:
|
||||
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
component Random8
|
||||
seed: 0..255 default 1 // TODO: default = 1, or seed?
|
||||
end
|
||||
|
||||
system Random
|
||||
on nextrand8 do foreach [Random8]
|
||||
---
|
||||
lda {{<seed}}
|
||||
lsr
|
||||
bcc :+
|
||||
eor #$d4
|
||||
:
|
||||
sta {{<seed}}
|
||||
---
|
||||
on prevrand8 do foreach [Random8]
|
||||
---
|
||||
lda {{<seed}}
|
||||
asl
|
||||
bcc :+
|
||||
eor #$a9
|
||||
:
|
||||
sta {{<seed}}
|
||||
---
|
||||
/* add entropy via joystick inputs */
|
||||
on preframe do foreach [Random8]
|
||||
---
|
||||
lda {{<seed}}
|
||||
eor SWCHA
|
||||
beq :+
|
||||
sta {{<seed}}
|
||||
:
|
||||
---
|
||||
end
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component BCDScore2
|
||||
digits: 0..$ff
|
||||
scorecolor: 0..$ff
|
||||
end
|
||||
|
||||
component BCDScore4
|
||||
digits: 0..0xffff
|
||||
end
|
||||
|
||||
component BCDScore6
|
||||
digits: 0..0xffffff
|
||||
end
|
||||
|
||||
system Kernel6Digit
|
||||
locals 15
|
||||
on preframe do with [BCDScore6]
|
||||
---
|
||||
Digit0 = {{$0}}
|
||||
Digit1 = {{$2}}
|
||||
Digit2 = {{$4}}
|
||||
Digit3 = {{$6}}
|
||||
Digit4 = {{$8}}
|
||||
Digit5 = {{$10}}
|
||||
@BCD0 = {{$12}}
|
||||
@BCD1 = {{$13}}
|
||||
@BCD2 = {{$14}}
|
||||
|
||||
lda {{get digits 0}}
|
||||
sta @BCD0
|
||||
lda {{get digits 8}}
|
||||
sta @BCD1
|
||||
lda {{get digits 16}}
|
||||
sta @BCD2
|
||||
ldx #0 ; leftmost bitmap
|
||||
ldy #2 ; start from most-sigificant BCD value
|
||||
@Loop:
|
||||
lda @BCD0,y ; get BCD value
|
||||
and #$f0 ; isolate high nibble (* 16)
|
||||
lsr ; shift right 1 bit (* 8)
|
||||
clc
|
||||
adc #<{{^FontTable}}
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>{{^FontTable}}
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
lda @BCD0,y ; get BCD value (again)
|
||||
and #$f ; isolate low nibble
|
||||
asl
|
||||
asl
|
||||
asl ; * 8
|
||||
clc
|
||||
adc #<{{^FontTable}}
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>{{^FontTable}}
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
dey ; next BCD value
|
||||
bpl @Loop ; repeat until < 0
|
||||
---
|
||||
on kernel do with [BCDScore6,PFColor]
|
||||
---
|
||||
lda {{<pfcolor}}
|
||||
sta COLUP0
|
||||
sta COLUP1
|
||||
lda #3
|
||||
sta NUSIZ0
|
||||
sta NUSIZ1
|
||||
; set horizontal position of player objects
|
||||
sta WSYNC
|
||||
sta HMCLR
|
||||
SLEEPR 24
|
||||
sta RESP0
|
||||
sta RESP1
|
||||
lda #$10
|
||||
sta HMP1
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24 ; wait 24 cycles between write to HMOVE and HMxxx
|
||||
sta HMCLR
|
||||
lda #1
|
||||
sta VDELP0
|
||||
sta VDELP1
|
||||
---
|
||||
on kernel do
|
||||
critical fit 72
|
||||
with [BCDScore6,BGColor]
|
||||
---
|
||||
; Display the resulting 48x8 bitmap
|
||||
; using the Digit0-5 pointers.
|
||||
@LoopCount = {{$12}}
|
||||
@Temp = {{$13}}
|
||||
|
||||
lda {{<bgcolor}}
|
||||
sta WSYNC
|
||||
sta COLUBK
|
||||
lda #7
|
||||
sta @LoopCount
|
||||
SLEEPR 20 ; TODO?
|
||||
:
|
||||
ldy @LoopCount ; counts backwards
|
||||
lda (Digit0),y ; load B0 (1st sprite byte)
|
||||
sta GRP0 ; B0 -> [GRP0]
|
||||
lda (Digit1),y ; load B1 -> A
|
||||
sta GRP1 ; B1 -> [GRP1], B0 -> GRP0
|
||||
sta WSYNC ; sync to next scanline
|
||||
lda (Digit2),y ; load B2 -> A
|
||||
sta GRP0 ; B2 -> [GRP0], B1 -> GRP1
|
||||
lda (Digit5),y ; load B5 -> A
|
||||
sta @Temp ; B5 -> temp
|
||||
lda (Digit4),y ; load B4
|
||||
tax ; -> X
|
||||
lda (Digit3),y ; load B3 -> A
|
||||
ldy @Temp ; load B5 -> Y
|
||||
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
||||
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
||||
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
||||
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
||||
dec @LoopCount ; go to next line
|
||||
bpl :- ; repeat until < 0
|
||||
|
||||
lda #0 ; clear the sprite registers
|
||||
sta WSYNC
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta COLUBK
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
resource FontTable ---
|
||||
; Font table for digits 0-9 (8x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$3c,$66,$66,$76,$6e,$66,$3c,$00,$7e,$18,$18,$18,$38,$18,$18
|
||||
.byte $00,$7e,$60,$30,$0c,$06,$66,$3c,$00,$3c,$66,$06,$1c,$06,$66,$3c
|
||||
.byte $00,$06,$06,$7f,$66,$1e,$0e,$06,$00,$3c,$66,$06,$06,$7c,$60,$7e
|
||||
.byte $00,$3c,$66,$66,$7c,$60,$66,$3c,$00,$18,$18,$18,$18,$0c,$66,$7e
|
||||
.byte $00,$3c,$66,$66,$3c,$66,$66,$3c,$00,$3c,$66,$06,$3e,$66,$66,$3c
|
||||
---
|
||||
|
||||
system Kernel2Digit
|
||||
locals 3
|
||||
on preframe do once
|
||||
---
|
||||
lda #0
|
||||
sta {{$1}}
|
||||
sta {{$2}}
|
||||
---
|
||||
on kernel do select [BCDScore2]
|
||||
---
|
||||
lda #$02
|
||||
sta CTRLPF
|
||||
; TODO: should be constants
|
||||
; and it's wrong, too!
|
||||
lda {{<BCDScore2:scorecolor}}+0
|
||||
sta COLUP0
|
||||
lda {{<BCDScore2:scorecolor}}+1
|
||||
sta COLUP1
|
||||
---
|
||||
on kernel do
|
||||
critical fit 98
|
||||
select [BCDScore2]
|
||||
---
|
||||
lda #7
|
||||
sta {{$0}}
|
||||
@Loop:
|
||||
ldx #0
|
||||
sta WSYNC
|
||||
{{!compute2digit 0}}
|
||||
.if {{%ecount}}>1
|
||||
inx
|
||||
{{!compute2digit 1}}
|
||||
.else
|
||||
{{!compute2digit 0}}
|
||||
.endif
|
||||
; playfield
|
||||
dec {{$0}}
|
||||
jpl @Loop
|
||||
; dex
|
||||
; stx PF1
|
||||
---
|
||||
on compute2digit do once
|
||||
---
|
||||
lda {{$1}} ; load 1st pf
|
||||
sta PF1 ; store 1st pf
|
||||
; first digit
|
||||
lda {{<BCDScore2:digits}} + {{#0}}
|
||||
pha
|
||||
and #$0f
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
{{!fetchdigit}}
|
||||
and #$0f
|
||||
ldy {{$2}} ; load 2nd pf
|
||||
sta {{$1}} + {{#0}}
|
||||
; second digit
|
||||
pla
|
||||
and #$f0
|
||||
lsr
|
||||
sty PF1 ; store 2nd pf
|
||||
{{!fetchdigit}}
|
||||
and #$f0
|
||||
ora {{$1}} + {{#0}}
|
||||
sta {{$1}} + {{#0}}
|
||||
---
|
||||
on fetchdigit do once
|
||||
---
|
||||
adc {{$0}}
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda {{^FontTablePF}},y
|
||||
---
|
||||
end
|
||||
|
||||
resource FontTablePF ---
|
||||
; Font table for digits 0-9 (4x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$00,$EE,$AA,$AA,$AA,$EE,$00
|
||||
.byte $00,$00,$22,$22,$22,$22,$22,$00
|
||||
.byte $00,$00,$EE,$88,$EE,$22,$EE,$00
|
||||
.byte $00,$00,$EE,$22,$66,$22,$EE,$00
|
||||
.byte $00,$00,$22,$22,$EE,$AA,$AA,$00
|
||||
.byte $00,$00,$EE,$22,$EE,$88,$EE,$00
|
||||
.byte $00,$00,$EE,$AA,$EE,$88,$EE,$00
|
||||
.byte $00,$00,$22,$22,$22,$22,$EE,$00
|
||||
.byte $00,$00,$EE,$AA,$EE,$AA,$EE,$00
|
||||
.byte $00,$00,$EE,$22,$EE,$AA,$EE,$00
|
||||
;;
|
||||
---
|
||||
|
||||
resource FontTablePFFancy ---
|
||||
; Font table for digits 0-9 (4x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$44,$AA,$AA,$AA,$AA,$AA,$44
|
||||
.byte $00,$EE,$44,$44,$44,$44,$CC,$44
|
||||
.byte $00,$EE,$88,$88,$44,$22,$AA,$44
|
||||
.byte $00,$CC,$22,$22,$66,$22,$22,$CC
|
||||
.byte $00,$22,$22,$22,$EE,$AA,$AA,$88
|
||||
.byte $00,$44,$AA,$22,$44,$88,$88,$EE
|
||||
.byte $00,$44,$AA,$AA,$CC,$88,$AA,$44
|
||||
.byte $00,$22,$22,$22,$22,$22,$AA,$EE
|
||||
.byte $00,$44,$AA,$AA,$44,$AA,$AA,$44
|
||||
.byte $00,$44,$AA,$22,$66,$AA,$AA,$44
|
||||
;;
|
||||
---
|
||||
|
||||
system BCDMath
|
||||
locals 1
|
||||
on AddBCD4 do once
|
||||
---
|
||||
.ifnblank {{arg 0}}
|
||||
lda #<{{arg 0}}
|
||||
ldy #>{{arg 0}}
|
||||
.endif
|
||||
---
|
||||
on AddBCD4 do with [BCDScore6]
|
||||
---
|
||||
; Adds value to 6-BCD-digit score.
|
||||
; A = 1st BCD digit
|
||||
; Y = 2nd BCD digit
|
||||
sed ; enter BCD mode
|
||||
clc ; clear carry
|
||||
adc {{get digits}}
|
||||
sta {{set digits}}
|
||||
tya
|
||||
adc {{get digits 8}}
|
||||
sta {{set digits 8}}
|
||||
lda {{get digits 16}}
|
||||
adc #0
|
||||
sta {{set digits 16}}
|
||||
cld ; exit BCD mode
|
||||
---
|
||||
on AddBCD2 do once
|
||||
---
|
||||
.ifnblank {{arg 0}}
|
||||
lda #<{{arg 0}}
|
||||
.endif
|
||||
---
|
||||
on SubBCD2 do once
|
||||
---
|
||||
.ifnblank {{arg 0}}
|
||||
lda #<{{arg 0}}
|
||||
.endif
|
||||
---
|
||||
on AddBCD2 do with [BCDScore2]
|
||||
---
|
||||
sed ; enter BCD mode
|
||||
clc ; clear carry
|
||||
adc {{get digits}}
|
||||
sta {{set digits}}
|
||||
cld ; exit BCD mode
|
||||
bcc :+
|
||||
lda #$99
|
||||
sta {{set digits}}
|
||||
:
|
||||
---
|
||||
on SubBCD2 do with [BCDScore2]
|
||||
---
|
||||
; TODO?
|
||||
tay
|
||||
lda {{get digits}}
|
||||
sty {{set digits}}
|
||||
sed ; enter BCD mode
|
||||
sec ; set carry
|
||||
sbc {{get digits}}
|
||||
sta {{set digits}}
|
||||
cld ; exit BCD mode
|
||||
bcs :+
|
||||
lda #0
|
||||
sta {{set digits}}
|
||||
:
|
||||
---
|
||||
end
|
||||
|
||||
demo Main
|
||||
|
||||
using FrameLoop
|
||||
using Kernel6Digit
|
||||
using Kernel2Digit
|
||||
using JoyButton, BCDMath
|
||||
|
||||
entity [Player,BCDScore6,PFColor,BGColor]
|
||||
init digits = 0x123456
|
||||
init pfcolor = $3c
|
||||
init bgcolor = $02
|
||||
end
|
||||
|
||||
entity [BCDScore2]
|
||||
init digits = 0x24
|
||||
init scorecolor = $ce
|
||||
end
|
||||
entity [BCDScore2]
|
||||
init digits = 0x56
|
||||
init scorecolor = $3e
|
||||
end
|
||||
|
||||
system IncScore
|
||||
on joybutton do with [Player,BCDScore6]
|
||||
---
|
||||
{{!AddBCD4 $0210}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
|
@ -0,0 +1,510 @@
|
|||
EVENT__start = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__kernel = 1
|
||||
EVENT__compute2digit = 1
|
||||
EVENT__fetchdigit = 1
|
||||
EVENT__AddBCD4 = 1
|
||||
EVENT__AddBCD2 = 1
|
||||
EVENT__SubBCD2 = 1
|
||||
EVENT__joybutton = 1
|
||||
.scope Main
|
||||
.zeropage
|
||||
BCDScore6_digits_b0:
|
||||
.res 1
|
||||
BCDScore6_digits_b8:
|
||||
.res 1
|
||||
BCDScore6_digits_b16:
|
||||
.res 1
|
||||
PFColor_pfcolor_b0:
|
||||
.res 1
|
||||
BGColor_bgcolor_b0:
|
||||
.res 1
|
||||
BCDScore2_digits_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
BCDScore2_scorecolor_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
TEMP:
|
||||
Kernel6Digit__2__tmp:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
Kernel2Digit__3__tmp:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.code
|
||||
Main__INITDATA:
|
||||
.byte 86
|
||||
.byte 52
|
||||
.byte 18
|
||||
.byte 60
|
||||
.byte 2
|
||||
.byte 36
|
||||
.byte 86
|
||||
.byte 206
|
||||
.byte 62
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #9
|
||||
: lda Main__INITDATA-1,y
|
||||
sta BCDScore6_digits_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_END
|
||||
|
||||
FRAME_START
|
||||
|
||||
;;; start action Kernel6Digit__preframe__5
|
||||
|
||||
Digit0 = Kernel6Digit__2__tmp+0
|
||||
Digit1 = Kernel6Digit__2__tmp+2
|
||||
Digit2 = Kernel6Digit__2__tmp+4
|
||||
Digit3 = Kernel6Digit__2__tmp+6
|
||||
Digit4 = Kernel6Digit__2__tmp+8
|
||||
Digit5 = Kernel6Digit__2__tmp+10
|
||||
Kernel6Digit__preframe__7__BCD0 = Kernel6Digit__2__tmp+12
|
||||
Kernel6Digit__preframe__7__BCD1 = Kernel6Digit__2__tmp+13
|
||||
Kernel6Digit__preframe__7__BCD2 = Kernel6Digit__2__tmp+14
|
||||
|
||||
lda BCDScore6_digits_b0
|
||||
sta Kernel6Digit__preframe__7__BCD0
|
||||
lda BCDScore6_digits_b8
|
||||
sta Kernel6Digit__preframe__7__BCD1
|
||||
lda BCDScore6_digits_b16
|
||||
sta Kernel6Digit__preframe__7__BCD2
|
||||
ldx #0 ; leftmost bitmap
|
||||
ldy #2 ; start from most-sigificant BCD value
|
||||
Kernel6Digit__preframe__7__Loop:
|
||||
lda Kernel6Digit__preframe__7__BCD0,y ; get BCD value
|
||||
and #$f0 ; isolate high nibble (* 16)
|
||||
lsr ; shift right 1 bit (* 8)
|
||||
clc
|
||||
adc #<FontTable
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>FontTable
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
lda Kernel6Digit__preframe__7__BCD0,y ; get BCD value (again)
|
||||
and #$f ; isolate low nibble
|
||||
asl
|
||||
asl
|
||||
asl ; * 8
|
||||
clc
|
||||
adc #<FontTable
|
||||
sta Digit0,x ; store pointer lo byte
|
||||
lda #>FontTable
|
||||
adc #0
|
||||
sta Digit0+1,x ; store pointer hi byte
|
||||
inx
|
||||
inx ; next bitmap pointer
|
||||
dey ; next BCD value
|
||||
bpl Kernel6Digit__preframe__7__Loop ; repeat until < 0
|
||||
|
||||
;;; end action Kernel6Digit__preframe__5
|
||||
|
||||
;;; start action Kernel2Digit__preframe__8
|
||||
|
||||
lda #0
|
||||
sta Kernel2Digit__3__tmp+1
|
||||
sta Kernel2Digit__3__tmp+2
|
||||
|
||||
;;; end action Kernel2Digit__preframe__8
|
||||
|
||||
|
||||
KERNEL_START
|
||||
|
||||
;;; start action Kernel6Digit__kernel__10
|
||||
|
||||
lda PFColor_pfcolor_b0
|
||||
sta COLUP0
|
||||
sta COLUP1
|
||||
lda #3
|
||||
sta NUSIZ0
|
||||
sta NUSIZ1
|
||||
; set horizontal position of player objects
|
||||
sta WSYNC
|
||||
sta HMCLR
|
||||
SLEEPR 24
|
||||
sta RESP0
|
||||
sta RESP1
|
||||
lda #$10
|
||||
sta HMP1
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24 ; wait 24 cycles between write to HMOVE and HMxxx
|
||||
sta HMCLR
|
||||
lda #1
|
||||
sta VDELP0
|
||||
sta VDELP1
|
||||
|
||||
;;; end action Kernel6Digit__kernel__10
|
||||
|
||||
jsr Kernel6Digit__kernel__13
|
||||
|
||||
;;; start action Kernel2Digit__kernel__16
|
||||
|
||||
lda #$02
|
||||
sta CTRLPF
|
||||
; TODO: should be constants
|
||||
; and it's wrong, too!
|
||||
lda BCDScore2_scorecolor_b0+0
|
||||
sta COLUP0
|
||||
lda BCDScore2_scorecolor_b0+1
|
||||
sta COLUP1
|
||||
|
||||
;;; end action Kernel2Digit__kernel__16
|
||||
|
||||
jsr Kernel2Digit__kernel__19
|
||||
|
||||
KERNEL_END
|
||||
|
||||
|
||||
;;; start action FrameLoop__postframe__40
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs FrameLoop__postframe__41__NoStart
|
||||
|
||||
FrameLoop__postframe__41__NoStart:
|
||||
|
||||
;;; end action FrameLoop__postframe__40
|
||||
|
||||
;;; start action JoyButton__postframe__42
|
||||
|
||||
lda INPT4 ;read button input
|
||||
bmi JoyButton__postframe__44__NotPressed
|
||||
|
||||
;;; start action IncScore__joybutton__45
|
||||
|
||||
|
||||
;;; start action BCDMath__AddBCD4__48
|
||||
|
||||
.ifnblank $0210
|
||||
lda #<$0210
|
||||
ldy #>$0210
|
||||
.endif
|
||||
|
||||
;;; end action BCDMath__AddBCD4__48
|
||||
|
||||
;;; start action BCDMath__AddBCD4__50
|
||||
|
||||
; Adds value to 6-BCD-digit score.
|
||||
; A = 1st BCD digit
|
||||
; Y = 2nd BCD digit
|
||||
sed ; enter BCD mode
|
||||
clc ; clear carry
|
||||
adc BCDScore6_digits_b0
|
||||
sta BCDScore6_digits_b0
|
||||
tya
|
||||
adc BCDScore6_digits_b8
|
||||
sta BCDScore6_digits_b8
|
||||
lda BCDScore6_digits_b16
|
||||
adc #0
|
||||
sta BCDScore6_digits_b16
|
||||
cld ; exit BCD mode
|
||||
|
||||
;;; end action BCDMath__AddBCD4__50
|
||||
|
||||
|
||||
;;; end action IncScore__joybutton__45
|
||||
|
||||
JoyButton__postframe__44__NotPressed:
|
||||
|
||||
;;; end action JoyButton__postframe__42
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
.rodata
|
||||
__ALIGNORIGIN:
|
||||
.rodata
|
||||
Kernel6Digit__kernel__13:
|
||||
|
||||
; Display the resulting 48x8 bitmap
|
||||
; using the Digit0-5 pointers.
|
||||
Kernel6Digit__kernel__15__LoopCount = Kernel6Digit__2__tmp+12
|
||||
Kernel6Digit__kernel__15__Temp = Kernel6Digit__2__tmp+13
|
||||
|
||||
lda BGColor_bgcolor_b0
|
||||
sta WSYNC
|
||||
sta COLUBK
|
||||
lda #7
|
||||
sta Kernel6Digit__kernel__15__LoopCount
|
||||
SLEEPR 20 ; TODO?
|
||||
:
|
||||
ldy Kernel6Digit__kernel__15__LoopCount ; counts backwards
|
||||
lda (Digit0),y ; load B0 (1st sprite byte)
|
||||
sta GRP0 ; B0 -> [GRP0]
|
||||
lda (Digit1),y ; load B1 -> A
|
||||
sta GRP1 ; B1 -> [GRP1], B0 -> GRP0
|
||||
sta WSYNC ; sync to next scanline
|
||||
lda (Digit2),y ; load B2 -> A
|
||||
sta GRP0 ; B2 -> [GRP0], B1 -> GRP1
|
||||
lda (Digit5),y ; load B5 -> A
|
||||
sta Kernel6Digit__kernel__15__Temp ; B5 -> temp
|
||||
lda (Digit4),y ; load B4
|
||||
tax ; -> X
|
||||
lda (Digit3),y ; load B3 -> A
|
||||
ldy Kernel6Digit__kernel__15__Temp ; load B5 -> Y
|
||||
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
||||
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
||||
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
||||
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
||||
dec Kernel6Digit__kernel__15__LoopCount ; go to next line
|
||||
bpl :- ; repeat until < 0
|
||||
|
||||
lda #0 ; clear the sprite registers
|
||||
sta WSYNC
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta COLUBK
|
||||
|
||||
rts
|
||||
|
||||
.assert >(Kernel6Digit__kernel__13) = >(*), error, "Kernel6Digit__kernel__13 crosses a page boundary!"
|
||||
|
||||
.assert (* - Kernel6Digit__kernel__13) <= 72, error, .sprintf("Kernel6Digit__kernel__13 does not fit in 72 bytes, it took %d!", (* - Kernel6Digit__kernel__13))
|
||||
|
||||
.if <(* - __ALIGNORIGIN) > 256-98
|
||||
.align $100
|
||||
.endif
|
||||
.rodata
|
||||
Kernel2Digit__kernel__19:
|
||||
|
||||
lda #7
|
||||
sta Kernel2Digit__3__tmp+0
|
||||
Kernel2Digit__kernel__21__Loop:
|
||||
ldx #0
|
||||
sta WSYNC
|
||||
|
||||
;;; start action Kernel2Digit__compute2digit__22
|
||||
|
||||
lda Kernel2Digit__3__tmp+1 ; load 1st pf
|
||||
sta PF1 ; store 1st pf
|
||||
; first digit
|
||||
lda BCDScore2_digits_b0 + 0
|
||||
pha
|
||||
and #$0f
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
|
||||
;;; start action Kernel2Digit__fetchdigit__24
|
||||
|
||||
adc Kernel2Digit__3__tmp+0
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda FontTablePF,y
|
||||
|
||||
;;; end action Kernel2Digit__fetchdigit__24
|
||||
|
||||
and #$0f
|
||||
ldy Kernel2Digit__3__tmp+2 ; load 2nd pf
|
||||
sta Kernel2Digit__3__tmp+1 + 0
|
||||
; second digit
|
||||
pla
|
||||
and #$f0
|
||||
lsr
|
||||
sty PF1 ; store 2nd pf
|
||||
|
||||
;;; start action Kernel2Digit__fetchdigit__26
|
||||
|
||||
adc Kernel2Digit__3__tmp+0
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda FontTablePF,y
|
||||
|
||||
;;; end action Kernel2Digit__fetchdigit__26
|
||||
|
||||
and #$f0
|
||||
ora Kernel2Digit__3__tmp+1 + 0
|
||||
sta Kernel2Digit__3__tmp+1 + 0
|
||||
|
||||
;;; end action Kernel2Digit__compute2digit__22
|
||||
|
||||
.if 2>1
|
||||
inx
|
||||
|
||||
;;; start action Kernel2Digit__compute2digit__28
|
||||
|
||||
lda Kernel2Digit__3__tmp+1 ; load 1st pf
|
||||
sta PF1 ; store 1st pf
|
||||
; first digit
|
||||
lda BCDScore2_digits_b0 + 1
|
||||
pha
|
||||
and #$0f
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
|
||||
;;; start action Kernel2Digit__fetchdigit__30
|
||||
|
||||
adc Kernel2Digit__3__tmp+0
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda FontTablePF,y
|
||||
|
||||
;;; end action Kernel2Digit__fetchdigit__30
|
||||
|
||||
and #$0f
|
||||
ldy Kernel2Digit__3__tmp+2 ; load 2nd pf
|
||||
sta Kernel2Digit__3__tmp+1 + 1
|
||||
; second digit
|
||||
pla
|
||||
and #$f0
|
||||
lsr
|
||||
sty PF1 ; store 2nd pf
|
||||
|
||||
;;; start action Kernel2Digit__fetchdigit__32
|
||||
|
||||
adc Kernel2Digit__3__tmp+0
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda FontTablePF,y
|
||||
|
||||
;;; end action Kernel2Digit__fetchdigit__32
|
||||
|
||||
and #$f0
|
||||
ora Kernel2Digit__3__tmp+1 + 1
|
||||
sta Kernel2Digit__3__tmp+1 + 1
|
||||
|
||||
;;; end action Kernel2Digit__compute2digit__28
|
||||
|
||||
.else
|
||||
|
||||
;;; start action Kernel2Digit__compute2digit__34
|
||||
|
||||
lda Kernel2Digit__3__tmp+1 ; load 1st pf
|
||||
sta PF1 ; store 1st pf
|
||||
; first digit
|
||||
lda BCDScore2_digits_b0 + 0
|
||||
pha
|
||||
and #$0f
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
|
||||
;;; start action Kernel2Digit__fetchdigit__36
|
||||
|
||||
adc Kernel2Digit__3__tmp+0
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda FontTablePF,y
|
||||
|
||||
;;; end action Kernel2Digit__fetchdigit__36
|
||||
|
||||
and #$0f
|
||||
ldy Kernel2Digit__3__tmp+2 ; load 2nd pf
|
||||
sta Kernel2Digit__3__tmp+1 + 0
|
||||
; second digit
|
||||
pla
|
||||
and #$f0
|
||||
lsr
|
||||
sty PF1 ; store 2nd pf
|
||||
|
||||
;;; start action Kernel2Digit__fetchdigit__38
|
||||
|
||||
adc Kernel2Digit__3__tmp+0
|
||||
tay
|
||||
; TODO: select your own?
|
||||
lda FontTablePF,y
|
||||
|
||||
;;; end action Kernel2Digit__fetchdigit__38
|
||||
|
||||
and #$f0
|
||||
ora Kernel2Digit__3__tmp+1 + 0
|
||||
sta Kernel2Digit__3__tmp+1 + 0
|
||||
|
||||
;;; end action Kernel2Digit__compute2digit__34
|
||||
|
||||
.endif
|
||||
; playfield
|
||||
dec Kernel2Digit__3__tmp+0
|
||||
jpl Kernel2Digit__kernel__21__Loop
|
||||
; dex
|
||||
; stx PF1
|
||||
|
||||
rts
|
||||
|
||||
.assert >(Kernel2Digit__kernel__19) = >(*), error, "Kernel2Digit__kernel__19 crosses a page boundary!"
|
||||
|
||||
.assert (* - Kernel2Digit__kernel__19) <= 98, error, .sprintf("Kernel2Digit__kernel__19 does not fit in 98 bytes, it took %d!", (* - Kernel2Digit__kernel__19))
|
||||
FontTable:
|
||||
|
||||
;;; start action FontTable__FontTable__53
|
||||
|
||||
; Font table for digits 0-9 (8x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$3c,$66,$66,$76,$6e,$66,$3c,$00,$7e,$18,$18,$18,$38,$18,$18
|
||||
.byte $00,$7e,$60,$30,$0c,$06,$66,$3c,$00,$3c,$66,$06,$1c,$06,$66,$3c
|
||||
.byte $00,$06,$06,$7f,$66,$1e,$0e,$06,$00,$3c,$66,$06,$06,$7c,$60,$7e
|
||||
.byte $00,$3c,$66,$66,$7c,$60,$66,$3c,$00,$18,$18,$18,$18,$0c,$66,$7e
|
||||
.byte $00,$3c,$66,$66,$3c,$66,$66,$3c,$00,$3c,$66,$06,$3e,$66,$66,$3c
|
||||
|
||||
;;; end action FontTable__FontTable__53
|
||||
|
||||
FontTablePF:
|
||||
|
||||
;;; start action FontTablePF__FontTablePF__55
|
||||
|
||||
; Font table for digits 0-9 (4x8 pixels)
|
||||
;;{w:8,h:8,count:10,brev:1,flip:1};;
|
||||
.byte $00,$00,$EE,$AA,$AA,$AA,$EE,$00
|
||||
.byte $00,$00,$22,$22,$22,$22,$22,$00
|
||||
.byte $00,$00,$EE,$88,$EE,$22,$EE,$00
|
||||
.byte $00,$00,$EE,$22,$66,$22,$EE,$00
|
||||
.byte $00,$00,$22,$22,$EE,$AA,$AA,$00
|
||||
.byte $00,$00,$EE,$22,$EE,$88,$EE,$00
|
||||
.byte $00,$00,$EE,$AA,$EE,$88,$EE,$00
|
||||
.byte $00,$00,$22,$22,$22,$22,$EE,$00
|
||||
.byte $00,$00,$EE,$AA,$EE,$AA,$EE,$00
|
||||
.byte $00,$00,$EE,$22,$EE,$AA,$EE,$00
|
||||
;;
|
||||
|
||||
;;; end action FontTablePF__FontTablePF__55
|
||||
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,105 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component SoundEffect
|
||||
duration: 0..255
|
||||
sounddata: array of 0..255
|
||||
end
|
||||
|
||||
component SoundChannel
|
||||
sfx: [SoundEffect]
|
||||
timer: 0..255
|
||||
end
|
||||
|
||||
// TODO
|
||||
component SoundPriority
|
||||
priority: 0..15
|
||||
end
|
||||
|
||||
system SoundEngine
|
||||
locals 3
|
||||
on preframe do
|
||||
join [SoundChannel]
|
||||
with [SoundEffect]
|
||||
---
|
||||
lda {{base timer}},y
|
||||
jeq @nosound
|
||||
sec
|
||||
sbc #1
|
||||
sta {{base timer}},y
|
||||
pha
|
||||
lda {{<sounddata}}
|
||||
sta {{$0}}
|
||||
lda {{>sounddata}}
|
||||
sta {{$1}} ; save pointer to sound data
|
||||
sty {{$2}} ; save Y (sound channel #)
|
||||
pla
|
||||
tay
|
||||
lda ({{$0}}),y ; get sound data
|
||||
bpl @setfreq ; hi bit clear = just freq
|
||||
ldy {{$2}}
|
||||
lsr ; right shift (/ 2)
|
||||
bcs @setvol ; lo bit set = volume
|
||||
sta AUDC0,y ; lo bit clear = control
|
||||
lsr ; also set freq (/ 2)
|
||||
@setfreq:
|
||||
ldy {{$2}}
|
||||
sta AUDF0,y ; set frequency
|
||||
jmp @done
|
||||
@nosound:
|
||||
lda #0
|
||||
@setvol:
|
||||
sta AUDV0,y ; set volume
|
||||
@done:
|
||||
---
|
||||
// TODO: need to pass sound entity as arg
|
||||
on playsound do select [SoundChannel]
|
||||
---
|
||||
; arg 0 = sound channel
|
||||
ldy #{{arg 0}}
|
||||
; arg 1 = sound effect #
|
||||
lda #{{arg 1}}
|
||||
sta {{base sfx}},y
|
||||
tax
|
||||
---
|
||||
// TODO: shouldn't need to split up like this...
|
||||
on playsound do select [SoundEffect]
|
||||
---
|
||||
lda {{base duration}},x
|
||||
---
|
||||
on playsound do select [SoundChannel]
|
||||
---
|
||||
sta {{base timer}},y
|
||||
; arg 2 = base volume
|
||||
lda #{{arg 2}}
|
||||
sta AUDV0,y
|
||||
---
|
||||
end
|
||||
|
||||
// TODO: default entities?
|
||||
|
||||
|
||||
demo SoundDemo
|
||||
using FrameLoop, SoundEngine
|
||||
|
||||
entity SFXScore [SoundEffect]
|
||||
const duration = 11
|
||||
const sounddata = [
|
||||
$02,$03,$04,$08,$10,$20,$10,$20,$10,$08,
|
||||
$a8]
|
||||
end
|
||||
|
||||
// TODO: make sfx have priority?
|
||||
entity SFX1 [SoundChannel] end
|
||||
entity SFX2 [SoundChannel] end
|
||||
|
||||
system Test
|
||||
on preframeloop do once
|
||||
---
|
||||
{{!playsound 0 0 15}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
EVENT__start = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__playsound = 1
|
||||
EVENT__preframeloop = 1
|
||||
.scope SoundDemo
|
||||
.zeropage
|
||||
SoundChannel_sfx_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
SoundChannel_timer_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
TEMP:
|
||||
SoundEngine__2__tmp:
|
||||
.res 1
|
||||
.res 1
|
||||
.res 1
|
||||
.code
|
||||
SoundEffect_duration_b0:
|
||||
.byte 11
|
||||
SoundEffect_sounddata_b0:
|
||||
.byte <SoundEffect_sounddata_e0_b0
|
||||
SoundEffect_sounddata_b8:
|
||||
.byte >SoundEffect_sounddata_e0_b0
|
||||
SoundEffect_sounddata_e0_b0:
|
||||
.byte 2
|
||||
.byte 3
|
||||
.byte 4
|
||||
.byte 8
|
||||
.byte 16
|
||||
.byte 32
|
||||
.byte 16
|
||||
.byte 32
|
||||
.byte 16
|
||||
.byte 8
|
||||
.byte 168
|
||||
SoundDemo__INITDATA:
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
.byte 0
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #4
|
||||
: lda SoundDemo__INITDATA-1,y
|
||||
sta SoundChannel_sfx_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
|
||||
;;; start action Test__preframeloop__5
|
||||
|
||||
|
||||
;;; start action SoundEngine__playsound__7
|
||||
|
||||
; arg 0 = sound channel
|
||||
ldy #0
|
||||
; arg 1 = sound effect #
|
||||
lda #0
|
||||
sta SoundChannel_sfx_b0,y
|
||||
tax
|
||||
|
||||
;;; end action SoundEngine__playsound__7
|
||||
|
||||
;;; start action SoundEngine__playsound__10
|
||||
|
||||
lda SoundEffect_duration_b0,x
|
||||
|
||||
;;; end action SoundEngine__playsound__10
|
||||
|
||||
;;; start action SoundEngine__playsound__13
|
||||
|
||||
sta SoundChannel_timer_b0,y
|
||||
; arg 2 = base volume
|
||||
lda #15
|
||||
sta AUDV0,y
|
||||
|
||||
;;; end action SoundEngine__playsound__13
|
||||
|
||||
|
||||
;;; end action Test__preframeloop__5
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_END
|
||||
|
||||
FRAME_START
|
||||
|
||||
;;; start action SoundEngine__preframe__16
|
||||
|
||||
ldy #0
|
||||
SoundEngine__preframe__17____each:
|
||||
ldx SoundChannel_sfx_b0,y
|
||||
|
||||
lda SoundChannel_timer_b0,y
|
||||
jeq SoundEngine__preframe__18__nosound
|
||||
sec
|
||||
sbc #1
|
||||
sta SoundChannel_timer_b0,y
|
||||
pha
|
||||
lda SoundEffect_sounddata_b0,x
|
||||
sta SoundEngine__2__tmp+0
|
||||
lda SoundEffect_sounddata_b8,x
|
||||
sta SoundEngine__2__tmp+1 ; save pointer to sound data
|
||||
sty SoundEngine__2__tmp+2 ; save Y (sound channel #)
|
||||
pla
|
||||
tay
|
||||
lda (SoundEngine__2__tmp+0),y ; get sound data
|
||||
bpl SoundEngine__preframe__18__setfreq ; hi bit clear = just freq
|
||||
ldy SoundEngine__2__tmp+2
|
||||
lsr ; right shift (/ 2)
|
||||
bcs SoundEngine__preframe__18__setvol ; lo bit set = volume
|
||||
sta AUDC0,y ; lo bit clear = control
|
||||
lsr ; also set freq (/ 2)
|
||||
SoundEngine__preframe__18__setfreq:
|
||||
ldy SoundEngine__2__tmp+2
|
||||
sta AUDF0,y ; set frequency
|
||||
jmp SoundEngine__preframe__18__done
|
||||
SoundEngine__preframe__18__nosound:
|
||||
lda #0
|
||||
SoundEngine__preframe__18__setvol:
|
||||
sta AUDV0,y ; set volume
|
||||
SoundEngine__preframe__18__done:
|
||||
|
||||
iny
|
||||
cpy #2
|
||||
jne SoundEngine__preframe__17____each
|
||||
SoundEngine__preframe__17____exit:
|
||||
|
||||
;;; end action SoundEngine__preframe__16
|
||||
|
||||
|
||||
KERNEL_START
|
||||
|
||||
KERNEL_END
|
||||
|
||||
|
||||
;;; start action FrameLoop__postframe__19
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs FrameLoop__postframe__20__NoStart
|
||||
|
||||
FrameLoop__postframe__20__NoStart:
|
||||
|
||||
;;; end action FrameLoop__postframe__19
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
|
||||
.endscope
|
||||
SoundDemo__Start = SoundDemo::__Start
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component Bitmap
|
||||
bitmapdata: array of 0..255 baseoffset 31
|
||||
height: 0..255
|
||||
end
|
||||
|
||||
// TODO: remove?
|
||||
component HasBitmap
|
||||
end
|
||||
|
||||
component Colormap
|
||||
colormapdata: array of 0..255 baseoffset 31
|
||||
end
|
||||
|
||||
component HasColormap
|
||||
colormap: [Colormap]
|
||||
end
|
||||
|
||||
component Sprite
|
||||
bitmap: [Bitmap]
|
||||
plyrflags: 0..63
|
||||
end
|
||||
|
||||
component HasXpos
|
||||
xpos: 0..255
|
||||
end
|
||||
|
||||
component HasYpos
|
||||
ypos: 0..255
|
||||
end
|
||||
|
||||
component Missile
|
||||
index: 2..3
|
||||
end
|
||||
|
||||
component SpriteSlot
|
||||
sprite: [Sprite] // TODO: HasBitmap?
|
||||
end
|
||||
|
||||
system JoyFaceDirection
|
||||
on joyleft do with [Sprite]
|
||||
---
|
||||
lda {{<plyrflags}}
|
||||
ora #$08
|
||||
sta {{<plyrflags}}
|
||||
---
|
||||
on joyright do with [Sprite]
|
||||
---
|
||||
lda {{<plyrflags}}
|
||||
and #$f7
|
||||
sta {{<plyrflags}}
|
||||
---
|
||||
end
|
||||
|
||||
system MoveJoyX
|
||||
on joyleft do with [HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
sec
|
||||
sbc #1
|
||||
bcc @nomove
|
||||
sta {{<xpos}}
|
||||
@nomove:
|
||||
---
|
||||
on joyright do with [HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #150
|
||||
bcs @nomove
|
||||
sta {{<xpos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system MoveJoyY
|
||||
on joyup do with [HasYpos]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
sec
|
||||
sbc #1
|
||||
bcc @nomove
|
||||
sta {{<ypos}}
|
||||
@nomove:
|
||||
---
|
||||
on joydown do with [HasYpos]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #220
|
||||
bcs @nomove
|
||||
sta {{<ypos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system SetXPos
|
||||
on preframe do join [SpriteSlot] with [Sprite]
|
||||
limit 2
|
||||
---
|
||||
lda {{<xpos}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on preframe do foreach [Missile,HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
ldy {{<index}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on prekernel do once
|
||||
---
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
SLEEPR 24
|
||||
sta HMCLR
|
||||
---
|
||||
end
|
||||
|
||||
system SpriteShuffler
|
||||
locals 2
|
||||
on postframe do select [SpriteSlot]
|
||||
---
|
||||
; load two sprite slots at left side of array
|
||||
lda {{<SpriteSlot:sprite}}
|
||||
sta {{$0}}
|
||||
lda {{<SpriteSlot:sprite}}+1
|
||||
sta {{$1}}
|
||||
; move two slots to the left
|
||||
ldx #0
|
||||
@loop:
|
||||
lda {{<SpriteSlot:sprite}}+2,x
|
||||
sta {{<SpriteSlot:sprite}},x
|
||||
inx
|
||||
cpx #{{%ecount}}-2
|
||||
bne @loop
|
||||
; store two sprite slots at right side of array
|
||||
lda {{$0}}
|
||||
sta {{<SpriteSlot:sprite}}+{{%ecount}}-2
|
||||
lda {{$1}}
|
||||
sta {{<SpriteSlot:sprite}}+{{%ecount}}-1
|
||||
---
|
||||
end
|
||||
|
||||
system SpriteHider
|
||||
locals 1
|
||||
on postframe do select [SpriteSlot]
|
||||
---
|
||||
lda #{{%efullcount}}-1
|
||||
sta {{$0}}
|
||||
---
|
||||
on postframe do
|
||||
join [SpriteSlot]
|
||||
with [Sprite,HasYpos]
|
||||
limit 2
|
||||
---
|
||||
lda {{<ypos}}
|
||||
cmp #192
|
||||
bcc @skip
|
||||
; swap this sprite slot with slot at end of array
|
||||
lda {{<SpriteSlot:sprite}},y
|
||||
pha
|
||||
ldx {{$0}} ; clobbers X, but no longer used
|
||||
lda {{<SpriteSlot:sprite}},x
|
||||
sta {{<SpriteSlot:sprite}},y
|
||||
pla
|
||||
sta {{<SpriteSlot:sprite}},x
|
||||
dec {{$0}}
|
||||
@skip:
|
||||
---
|
||||
end
|
||||
|
|
@ -0,0 +1,401 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component Bitmap
|
||||
bitmapdata: array of 0..255 baseoffset 31
|
||||
height: 0..255
|
||||
end
|
||||
|
||||
component HasBitmap
|
||||
bitmap: [Bitmap]
|
||||
end
|
||||
|
||||
component Colormap
|
||||
colormapdata: array of 0..255 baseoffset 31
|
||||
end
|
||||
|
||||
component HasColormap
|
||||
colormap: [Colormap]
|
||||
end
|
||||
|
||||
component Sprite
|
||||
plyrflags: 0..63
|
||||
end
|
||||
|
||||
component HasXpos
|
||||
xpos: 0..255
|
||||
end
|
||||
|
||||
component HasYpos
|
||||
ypos: 0..255
|
||||
end
|
||||
|
||||
component SpriteSlot
|
||||
sprite: [Sprite,HasBitmap,HasColormap,HasYpos]
|
||||
end
|
||||
|
||||
component Missile
|
||||
end
|
||||
|
||||
system Kernel2Sprite
|
||||
locals 13
|
||||
on preframe do with [KernelSection]
|
||||
---
|
||||
.define KLINES {{<lines}}
|
||||
.define KPAD 32
|
||||
---
|
||||
on preframe do join
|
||||
[SpriteSlot] with
|
||||
[Sprite,HasBitmap,HasColormap,HasYpos] limit 2
|
||||
---
|
||||
; set player object flags
|
||||
lda {{<plyrflags}}
|
||||
sta NUSIZ0,y
|
||||
sta REFP0,y
|
||||
; calculate screen height - ypos
|
||||
lda KLINES+KPAD
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$11}}
|
||||
; calculate bitmap pointer
|
||||
stx {{$12}} ; save X (Sprite index)
|
||||
lda {{<bitmap}} ; deref bitmap
|
||||
tax
|
||||
lda {{<Bitmap:bitmapdata}},x
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$0}},y ; Y = sprite slot index
|
||||
lda {{>Bitmap:bitmapdata}},x
|
||||
sbc #0
|
||||
sta {{$2}},y
|
||||
; get bitmap height
|
||||
lda {{<Bitmap:height}},x
|
||||
sta {{$8}},y
|
||||
; calculate colormap pointer
|
||||
ldx {{$12}} ; restore X
|
||||
lda {{<colormap}} ; deref colormap
|
||||
tax
|
||||
lda {{<Colormap:colormapdata}},x
|
||||
sec
|
||||
sbc {{$11}}
|
||||
sta {{$4}},y
|
||||
lda {{>Colormap:colormapdata}},x
|
||||
sbc #0
|
||||
sta {{$6}},y
|
||||
; save ypos
|
||||
ldx {{$12}} ; restore X
|
||||
lda {{<ypos}}
|
||||
sta {{$10}},y
|
||||
---
|
||||
on preframe do once
|
||||
---
|
||||
; L0 L1 H0 H1 -> L0 H0 L1 H1
|
||||
lda {{$1}}
|
||||
ldy {{$2}}
|
||||
sty {{$1}}
|
||||
sta {{$2}}
|
||||
lda {{$5}}
|
||||
ldy {{$6}}
|
||||
sty {{$5}}
|
||||
sta {{$6}}
|
||||
---
|
||||
on preframe do if [BGColor]
|
||||
---
|
||||
lda {{<bgcolor}}
|
||||
sta COLUBK
|
||||
---
|
||||
on preframe do if [Missile,HasYpos]
|
||||
---
|
||||
lda KLINES
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
sta {{$12}}
|
||||
---
|
||||
on kernel do with [KernelSection]
|
||||
---
|
||||
ldy #0
|
||||
sty VDELP0
|
||||
iny
|
||||
sta VDELP1
|
||||
---
|
||||
on kernel do with [KernelSection]
|
||||
---
|
||||
; define macro for each line
|
||||
.macro @DrawLine do_wsync
|
||||
.local DoDraw1
|
||||
.local DoDraw2
|
||||
; draw player 0
|
||||
lda {{$8}} ; height
|
||||
dcp {{$10}} ; ypos
|
||||
bcs DoDraw1
|
||||
lda #0
|
||||
.byte $2C
|
||||
DoDraw1:
|
||||
lda ({{$0}}),y
|
||||
.if do_wsync
|
||||
sta WSYNC
|
||||
.endif
|
||||
sta GRP0
|
||||
lda ({{$4}}),y
|
||||
sta COLUP0
|
||||
; draw player 1
|
||||
lda {{$9}} ; height
|
||||
dcp {{$11}} ; ypos
|
||||
bcs DoDraw2
|
||||
lda #0
|
||||
.byte $2C
|
||||
DoDraw2:
|
||||
lda ({{$2}}),y
|
||||
sta GRP1
|
||||
lda ({{$6}}),y
|
||||
sta COLUP1
|
||||
.endmacro
|
||||
|
||||
ldy {{<lines}}
|
||||
@LVScan:
|
||||
{{!scanline1}}
|
||||
@DrawLine 1 ; macro: draw scanline w/ WSYNC
|
||||
dey ; next scanline
|
||||
{{!scanline2}}
|
||||
@DrawLine 0 ; macro: draw scanline no WSYNC
|
||||
dey ; next scanline
|
||||
bne @LVScan ; repeat until out of lines
|
||||
---
|
||||
on kernel do with [KernelSection]
|
||||
---
|
||||
lda #0
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
sta GRP0
|
||||
sta GRP1
|
||||
---
|
||||
on scanline1 do if [Missile,HasYpos]
|
||||
---
|
||||
cpy {{$12}}
|
||||
php
|
||||
pla
|
||||
sta ENAM0
|
||||
---
|
||||
end
|
||||
|
||||
system VersatilePlayfield
|
||||
locals 2
|
||||
on preframe do with [VersatilePlayfield]
|
||||
---
|
||||
lda {{<data}}
|
||||
sta {{$0}}
|
||||
lda {{>data}}
|
||||
sta {{$1}}
|
||||
---
|
||||
on scanline1 do with [VersatilePlayfield]
|
||||
---
|
||||
lda ({{local 0}}),y
|
||||
tax
|
||||
---
|
||||
on scanline2 do with [VersatilePlayfield]
|
||||
---
|
||||
lda ({{local 0}}),y
|
||||
sta $00,x
|
||||
---
|
||||
end
|
||||
|
||||
system SetXPos
|
||||
on preframe do once
|
||||
---
|
||||
sta HMCLR
|
||||
---
|
||||
on preframe do join [SpriteSlot] with [HasXpos]
|
||||
limit 2
|
||||
---
|
||||
lda {{<xpos}}
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on preframe do if [Missile,HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
ldx #2
|
||||
{{!SetHorizPos}}
|
||||
---
|
||||
on preframe do once
|
||||
---
|
||||
sta WSYNC
|
||||
sta HMOVE
|
||||
---
|
||||
end
|
||||
|
||||
system MoveJoyX
|
||||
on joyleft do with [HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
sec
|
||||
sbc #1
|
||||
bcc @nomove
|
||||
sta {{<xpos}}
|
||||
@nomove:
|
||||
---
|
||||
on joyright do with [HasXpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #152
|
||||
bcs @nomove
|
||||
sta {{<xpos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system MoveJoyY
|
||||
on joyup do with [HasYpos]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
sec
|
||||
sbc #1
|
||||
bcc @nomove
|
||||
sta {{<ypos}}
|
||||
@nomove:
|
||||
---
|
||||
on joydown do with [HasYpos]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
clc
|
||||
adc #1
|
||||
cmp #220
|
||||
bcs @nomove
|
||||
sta {{<ypos}}
|
||||
@nomove:
|
||||
---
|
||||
end
|
||||
|
||||
system SpriteShuffler
|
||||
locals 2
|
||||
on postframe do select [SpriteSlot]
|
||||
---
|
||||
; load two sprite slots at left side of array
|
||||
lda {{<SpriteSlot:sprite}}
|
||||
sta {{$0}}
|
||||
lda {{<SpriteSlot:sprite}}+1
|
||||
sta {{$1}}
|
||||
; move two slots to the left
|
||||
ldx #0
|
||||
@loop:
|
||||
lda {{<SpriteSlot:sprite}}+2,x
|
||||
sta {{<SpriteSlot:sprite}},x
|
||||
inx
|
||||
cpx #{{%ecount}}-2
|
||||
bne @loop
|
||||
; store two sprite slots at right side of array
|
||||
lda {{$0}}
|
||||
sta {{<SpriteSlot:sprite}}+{{%ecount}}-2
|
||||
lda {{$1}}
|
||||
sta {{<SpriteSlot:sprite}}+{{%ecount}}-1
|
||||
---
|
||||
end
|
||||
|
||||
system SpriteHider
|
||||
locals 1
|
||||
on postframe do select [SpriteSlot]
|
||||
---
|
||||
lda #{{%efullcount}}-1
|
||||
sta {{$0}}
|
||||
---
|
||||
on postframe do
|
||||
join [SpriteSlot]
|
||||
with [Sprite,HasYpos]
|
||||
limit 2
|
||||
---
|
||||
lda {{<ypos}}
|
||||
cmp #192
|
||||
bcc @skip
|
||||
; swap this sprite slot with slot at end of array
|
||||
lda {{<SpriteSlot:sprite}},y
|
||||
pha
|
||||
ldx {{$0}} ; clobbers X, but no longer used
|
||||
lda {{<SpriteSlot:sprite}},x
|
||||
sta {{<SpriteSlot:sprite}},y
|
||||
pla
|
||||
sta {{<SpriteSlot:sprite}},x
|
||||
dec {{$0}}
|
||||
@skip:
|
||||
---
|
||||
end
|
||||
|
||||
///
|
||||
|
||||
demo Main
|
||||
|
||||
using FrameLoop, Kernel2Sprite
|
||||
using Joystick, MoveJoyX, MoveJoyY
|
||||
using SetXPos, SetHorizPos
|
||||
using SpriteShuffler, SpriteHider
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 192
|
||||
const bgcolor = 0xa2
|
||||
end
|
||||
|
||||
entity Bitmap1 [Bitmap]
|
||||
const bitmapdata = [1, 1, 3, 7, 15, 31, 63, 127]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Bitmap2 [Bitmap]
|
||||
const bitmapdata = [$18,$3e,$ff,$ff,$ff,$ff,$3e,$18]
|
||||
const height = 8
|
||||
end
|
||||
|
||||
entity Colormap1 [Colormap]
|
||||
const colormapdata = [6, 3, 6, 9, 12, 14, 31, 63]
|
||||
end
|
||||
|
||||
entity Sprite0 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 50
|
||||
init ypos = 150
|
||||
init bitmap = #Bitmap2
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Sprite1 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 100
|
||||
init ypos = 60
|
||||
init bitmap = #Bitmap1
|
||||
const plyrflags = 3
|
||||
end
|
||||
|
||||
entity Sprite2 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 80
|
||||
init ypos = 90
|
||||
init bitmap = #Bitmap2
|
||||
const plyrflags = 0
|
||||
end
|
||||
|
||||
entity Sprite3 [Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player]
|
||||
init xpos = 40
|
||||
init ypos = 150
|
||||
init bitmap = #Bitmap1
|
||||
const plyrflags = 0
|
||||
end
|
||||
/*
|
||||
entity [Missile,HasXpos,HasYpos]
|
||||
init xpos = 70
|
||||
init ypos = 70
|
||||
end
|
||||
*/
|
||||
entity Slot0 [SpriteSlot]
|
||||
init sprite = #Sprite0
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
init sprite = #Sprite1
|
||||
end
|
||||
entity Slot2 [SpriteSlot]
|
||||
init sprite = #Sprite2
|
||||
end
|
||||
entity Slot3 [SpriteSlot]
|
||||
init sprite = #Sprite3
|
||||
end
|
||||
|
||||
end demo
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
185:I couldn't find a component named "VersatilePlayfield".
|
|
@ -0,0 +1,514 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
import "sprites.ecs"
|
||||
import "kernel2.ecs"
|
||||
import "versatile.ecs"
|
||||
|
||||
// https://csanyk.com/2014/02/topology-metropolis-superman-atari-2600/
|
||||
|
||||
component RoomGraphics
|
||||
graphics: array 0..8 of 0..255
|
||||
end
|
||||
|
||||
component Room
|
||||
fgcolor: 0..255
|
||||
bgcolor: 0..255
|
||||
gfx: [VersatilePlayfield]
|
||||
north: [Room]
|
||||
east: [Room]
|
||||
south: [Room]
|
||||
west: [Room]
|
||||
end
|
||||
|
||||
component Location
|
||||
room: [Room]
|
||||
end
|
||||
|
||||
component Enemy
|
||||
end
|
||||
|
||||
component Moving
|
||||
speed: 1..15
|
||||
end
|
||||
|
||||
|
||||
system SuperFly
|
||||
on gowest do with [Location]
|
||||
---
|
||||
ldy {{<room}}
|
||||
lda {{<Room:west}},y
|
||||
sta {{<room}}
|
||||
---
|
||||
on goeast do with [Location]
|
||||
---
|
||||
ldy {{<room}}
|
||||
lda {{<Room:east}},y
|
||||
sta {{<room}}
|
||||
---
|
||||
on gonorth do with [Location]
|
||||
---
|
||||
ldy {{<room}}
|
||||
lda {{<Room:north}},y
|
||||
sta {{<room}}
|
||||
---
|
||||
on gosouth do with [Location]
|
||||
---
|
||||
ldy {{<room}}
|
||||
lda {{<Room:south}},y
|
||||
sta {{<room}}
|
||||
---
|
||||
on joyleft do with [Location,HasXpos,Moving]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
sec
|
||||
sbc {{<speed}}
|
||||
jcs @nomove
|
||||
{{!gowest}}
|
||||
lda #142
|
||||
@nomove:
|
||||
sta {{<xpos}}
|
||||
---
|
||||
on joyright do with [Location,HasXpos,Moving]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
clc
|
||||
adc {{<speed}}
|
||||
cmp #142
|
||||
jcc @nomove
|
||||
{{!goeast}}
|
||||
lda #2
|
||||
@nomove:
|
||||
sta {{<xpos}}
|
||||
---
|
||||
on joyup do with [Location,HasYpos,Moving]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
sec
|
||||
sbc {{<speed}}
|
||||
jcs @nomove
|
||||
{{!gonorth}}
|
||||
lda #200
|
||||
@nomove:
|
||||
sta {{<ypos}}
|
||||
---
|
||||
on joydown do with [Location,HasYpos,Moving]
|
||||
---
|
||||
lda {{<ypos}}
|
||||
clc
|
||||
adc {{<speed}}
|
||||
cmp #220
|
||||
jcc @nomove
|
||||
{{!gosouth}}
|
||||
lda #2
|
||||
@nomove:
|
||||
sta {{<ypos}}
|
||||
---
|
||||
end
|
||||
|
||||
system BadMove
|
||||
on postframe do foreach [Enemy]
|
||||
---
|
||||
{{!joyright}}
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
system RoomShuffle
|
||||
on postframe do select [Location,Sprite]
|
||||
---
|
||||
ldy #{{%ecount}}-1
|
||||
ldx {{<Slot1.sprite}}
|
||||
beq @empty ; empty slot, load 1st entry
|
||||
@loop:
|
||||
inx
|
||||
cpx #{{%ecount}}+1
|
||||
bcc @norecycle
|
||||
; TODO: need to get index of specific entity
|
||||
@empty:
|
||||
ldx #2 ; skip null sprite and player
|
||||
@norecycle:
|
||||
; TODO: should automatically index
|
||||
lda {{<Location:room}}-1,x
|
||||
cmp {{<Superdude.room}}
|
||||
beq @exit
|
||||
dey
|
||||
bne @loop
|
||||
ldx #0 ; null sprite
|
||||
@exit:
|
||||
stx {{<Slot1.sprite}}
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
|
||||
scope Main
|
||||
|
||||
using FrameLoop, Kernel2Sprite
|
||||
using Joystick, JoyFaceDirection
|
||||
using SuperFly
|
||||
using BadMove
|
||||
using RoomShuffle
|
||||
//using MoveJoyX, MoveJoyY
|
||||
using SetXPos, SetHorizPos
|
||||
//using SpriteShuffler, SpriteHider
|
||||
|
||||
entity Kernel [KernelSection, BGColor]
|
||||
const lines = 190
|
||||
const bgcolor = 0xa2
|
||||
end
|
||||
|
||||
entity Blank [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
........ 00
|
||||
---
|
||||
end
|
||||
|
||||
entity Superdude1 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
......xx 52
|
||||
.....xx. 54
|
||||
x....xx. 48
|
||||
.x...xx. 48
|
||||
..x..xxx 48
|
||||
...x.xx. 48
|
||||
....xx.. 46
|
||||
...xxx.. 88
|
||||
...xxx.. 86
|
||||
..xxxx.x 86
|
||||
..xxxxx. 86
|
||||
.xxx.x.. 86
|
||||
.xxx.... 88
|
||||
xxx..... 86
|
||||
xxx..... 86
|
||||
xx...... 86
|
||||
xx...... 46
|
||||
x....... 46
|
||||
---
|
||||
end
|
||||
|
||||
entity BexButhor1 [Bitmap,Colormap]
|
||||
decode vcs_sprite
|
||||
---
|
||||
x....... 04
|
||||
.xx..... 04
|
||||
..xx.... 04
|
||||
..x.x... 04
|
||||
..x..... 04
|
||||
..x..xx. 46
|
||||
..x.xxx. 48
|
||||
..x.xxx. 48
|
||||
..x.xxxx 48
|
||||
..x.xxx. 48
|
||||
..x.xxx. 48
|
||||
..x.xx.. 46
|
||||
..xxxxx. 2a
|
||||
..xxxxx. 2a
|
||||
..xxxxxx 28
|
||||
..xxxxxx 28
|
||||
..xxxxxx 28
|
||||
...xxxxx 28
|
||||
...xxxx. 28
|
||||
....xxx. 26
|
||||
....xx.. c8
|
||||
....xx.. c8
|
||||
....xx.. c8
|
||||
....xx.. c6
|
||||
....xx.. c6
|
||||
....xx.. c6
|
||||
....xxx. 04
|
||||
....xxx. 04
|
||||
---
|
||||
end
|
||||
|
||||
entity NullRoom [Room,VersatilePlayfield]
|
||||
const fgcolor = $0
|
||||
const bgcolor = $0
|
||||
const north = #NullRoom
|
||||
const south = #NullRoom
|
||||
const east = #NullRoom
|
||||
const west = #NullRoom
|
||||
const data = [0]
|
||||
end
|
||||
|
||||
entity InsideDailyPlanet [Room,VersatilePlayfield]
|
||||
const fgcolor = $0c
|
||||
const bgcolor = $12
|
||||
const north = #InsideDailyPlanet
|
||||
const south = #InsideDailyPlanet
|
||||
const east = #OutsideDailyPlanet
|
||||
const west = #OutsideDailyPlanet
|
||||
decode vcs_versatile
|
||||
---
|
||||
.................... .. c0 ..
|
||||
.................... .. .. 01
|
||||
.................... 08 .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
..................xx .. .. ..
|
||||
.....xxxx.........xx .. .. ..
|
||||
.....xxxx........xxx .. .. ..
|
||||
.....xxxx.......xxxx .. .. ..
|
||||
.....xxxx.......xxxx .. .. ..
|
||||
.....xxxx.......xxxx .. .. ..
|
||||
.....xxxx.......xxx. .. .. ..
|
||||
.....xxxx.......xx.. .. .. ..
|
||||
.....xxxx.......x... .. .. ..
|
||||
.....xxxx.......x..x .. .. ..
|
||||
.....xxxx.......x.xx .. .. ..
|
||||
.....xxxx.......x.xx .. .. ..
|
||||
.....xxxx.......x.xx .. 60 ..
|
||||
.....xxxxxxx....x.xx .. .. ..
|
||||
.xx..xxxxxxx....x.xx .. .. ..
|
||||
.xx..xxxxxxx....x..x .. .. ..
|
||||
.xx..xxxxxxx....x... .. .. ..
|
||||
.xx..xxxxxxx....xx.. .. .. ..
|
||||
.xx..xxxxxxx....xxx. .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. 50 ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. 44 ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. 46 ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. 38 ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
xxxx.xxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. 00
|
||||
xxxxxxxxxxxxxxxxxxxx .. c8 ..
|
||||
xxxxxxxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxx...xxx .. .. ..
|
||||
xxxxxxxxxxxxx.....xx .. .. ..
|
||||
xxxxxxxxxxxxx.....xx .. .. ..
|
||||
xxxxxxxxxxxx.......x .. .. ..
|
||||
xxxxxxxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx 08 .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx 06 .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. 18 ..
|
||||
xxxx.x.x.x.xxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
---
|
||||
end
|
||||
|
||||
// xxxxxxx....xxxxxx...
|
||||
// xxx...x.x...xxxx..xx
|
||||
// xxx.x....x....xx....
|
||||
|
||||
entity OutsideDailyPlanet [Room,VersatilePlayfield]
|
||||
const fgcolor = $0c
|
||||
const bgcolor = $12
|
||||
const north = #InsideDailyPlanet
|
||||
const south = #InsideDailyPlanet
|
||||
const east = #InsideDailyPlanet
|
||||
const west = #InsideDailyPlanet
|
||||
//9f9f 9f 0c fc 3e 38 46 44 506070a0000000
|
||||
decode vcs_versatile
|
||||
---
|
||||
.................... .. 70 ..
|
||||
.................... .. .. 01
|
||||
.................... a8 .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
.................... .. .. ..
|
||||
..................xx .. .. ..
|
||||
.....xxxx.........xx .. .. ..
|
||||
.....xxxx........xxx .. .. ..
|
||||
.....xxxx.......xxxx .. .. ..
|
||||
.....xxxx.......xxxx .. .. ..
|
||||
.....xxxx.......xxxx .. .. ..
|
||||
.....xxxx.......xxx. .. .. ..
|
||||
.....xxxx.......xx.. .. .. ..
|
||||
.....xxxx.......x... .. .. ..
|
||||
.....xxxx.......x..x .. .. ..
|
||||
.....xxxx.......x.xx .. .. ..
|
||||
.....xxxx.......x.xx .. .. ..
|
||||
.....xxxx.......x.xx .. 60 ..
|
||||
.....xxxxxxx....x.xx .. .. ..
|
||||
.xx..xxxxxxx....x.xx .. .. ..
|
||||
.xx..xxxxxxx....x..x .. .. ..
|
||||
.xx..xxxxxxx....x... .. .. ..
|
||||
.xx..xxxxxxx....xx.. .. .. ..
|
||||
.xx..xxxxxxx....xxx. .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. 50 ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. 44 ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xx.x.xx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xx.x .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx....xxxx .. 46 ..
|
||||
.xx..xxxxxxx....xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxx.xx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. 38 ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
.xx..xxxxxxxxxx.xxxx .. .. ..
|
||||
xxxx.xxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxxx.xxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. 00
|
||||
xxxxxxxxxxxxxxxxxxxx .. c8 ..
|
||||
xxxxxxxx.xxxxxxxxxxx .. .. ..
|
||||
xxxxxxxx.xxxxxxxxxxx .. .. ..
|
||||
xxxxxxx...xxxxxxxxxx .. .. ..
|
||||
xxxxxx.....xxxxxxxxx .. .. ..
|
||||
xxxxxx.....xxxxxxxxx .. .. ..
|
||||
xxxxx.......xxxxxxxx .. .. ..
|
||||
xxxxxxxx.xxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx 08 .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx 06 .. ..
|
||||
xxxxxxxxxxxxxxxxxxxx .. 06 ..
|
||||
x.x.xxxxxxxxxxxxxxxx .. .. ..
|
||||
x.x.x.x.x.x.xxxxxxxx .. .. ..
|
||||
x.x.x.x.x.x.x.x.x.x. .. .. ..
|
||||
x.x.x.x.x.x.x.x.x.x. .. .. ..
|
||||
x.x.x.x.x.x.x.x.x.x. .. 18 ..
|
||||
x.x.x.x.x.x.x.x.x.x. .. 06 ..
|
||||
3f 3f
|
||||
3f 3f
|
||||
3f 3f
|
||||
3f 3f
|
||||
3f 3f
|
||||
3f 3f
|
||||
3f 3f
|
||||
3f 3f
|
||||
---
|
||||
end
|
||||
|
||||
entity NullSprite [Sprite]
|
||||
const bitmap = #Blank
|
||||
//var plyrflags = $00
|
||||
end
|
||||
|
||||
entity Superdude [Location,Sprite,HasBitmap,HasColormap,HasXpos,HasYpos,Player,Moving]
|
||||
var room = #OutsideDailyPlanet
|
||||
var xpos = 40
|
||||
var ypos = 30
|
||||
const bitmap = #Superdude1
|
||||
const colormap = #Superdude1
|
||||
var plyrflags = $05
|
||||
const speed = 2
|
||||
end
|
||||
|
||||
entity BexButhor [Location,Sprite,HasXpos,HasYpos,HasBitmap,HasColormap,Enemy,Moving]
|
||||
var room = #OutsideDailyPlanet
|
||||
var xpos = 70
|
||||
var ypos = 70
|
||||
const bitmap = #BexButhor1
|
||||
const colormap = #BexButhor1
|
||||
var plyrflags = $00
|
||||
const speed = 1
|
||||
end
|
||||
|
||||
entity JBexButhor [Location,Sprite,HasXpos,HasYpos,HasBitmap,HasColormap,Enemy,Moving]
|
||||
var room = #OutsideDailyPlanet
|
||||
var xpos = 100
|
||||
var ypos = 60
|
||||
const bitmap = #BexButhor1
|
||||
const colormap = #BexButhor1
|
||||
var plyrflags = $00
|
||||
const speed = 1
|
||||
end
|
||||
|
||||
/*
|
||||
entity KBexButhor [Location,Sprite,HasXpos,HasYpos,HasBitmap,HasColormap,Enemy,Moving]
|
||||
var room = #InsideDailyPlanet
|
||||
var xpos = 50
|
||||
var ypos = 90
|
||||
const bitmap = #BexButhor1
|
||||
const colormap = #BexButhor1
|
||||
var plyrflags = $00
|
||||
const speed = 1
|
||||
end*/
|
||||
|
||||
entity Slot0 [SpriteSlot]
|
||||
var sprite = #Superdude
|
||||
end
|
||||
entity Slot1 [SpriteSlot]
|
||||
var sprite = #NullSprite
|
||||
end
|
||||
|
||||
using VersatilePlayfield with #Superdude.room
|
||||
|
||||
end
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,305 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
import "vcslib.ecs"
|
||||
|
||||
component Bitmap48
|
||||
bitmap0: array of 0..0xff
|
||||
bitmap1: array of 0..0xff
|
||||
bitmap2: array of 0..0xff
|
||||
bitmap3: array of 0..0xff
|
||||
bitmap4: array of 0..0xff
|
||||
bitmap5: array of 0..0xff
|
||||
height: 0..255
|
||||
end
|
||||
|
||||
system Kernel48Pixel
|
||||
locals 2
|
||||
on kernelsetup do if [Bitmap48] ---
|
||||
lda {{<height}}
|
||||
sta {{$0}} ; scanline counter
|
||||
---
|
||||
// TODO: should factor out this code, but doesnt
|
||||
on kernelsetup do if [Bitmap48] ---
|
||||
lda #$22
|
||||
sta COLUP0 ; show how players alternate
|
||||
lda #$12
|
||||
sta COLUP1 ; by having different colors
|
||||
lda #3
|
||||
sta NUSIZ0
|
||||
sta NUSIZ1 ; both players have 3 copies
|
||||
sta WSYNC
|
||||
SLEEPH 35
|
||||
sta RESP0 ; position 1st player
|
||||
sta RESP1 ; ...and 2nd player
|
||||
lda #$10
|
||||
sta HMP1 ; 1 pixel to the left
|
||||
sta WSYNC
|
||||
sta HMOVE ; apply HMOVE
|
||||
lda #1
|
||||
sta VDELP0 ; we need the VDEL registers
|
||||
sta VDELP1 ; so we can do our 4-store trick
|
||||
SLEEPH 24-8 ; sleep 24 cycles
|
||||
sta HMCLR ; clear HMOVE registers
|
||||
---
|
||||
on kernelsetup do if [PFColor] ---
|
||||
lda {{<pfcolor}}
|
||||
sta COLUP0
|
||||
sta COLUP1
|
||||
---
|
||||
on kerneldraw do critical fit 63
|
||||
if [Bitmap48]
|
||||
---
|
||||
txa
|
||||
pha
|
||||
:
|
||||
ldy {{$0}} ; counts backwards
|
||||
{{!wsync}} ; sync to next scanline
|
||||
lda {{data bitmap0}},y ; load B0 (1st sprite byte)
|
||||
sta GRP0 ; B0 -> [GRP0]
|
||||
lda {{data bitmap1}},y ; load B1 -> A
|
||||
sta GRP1 ; B1 -> [GRP1], B0 -> GRP0
|
||||
lda {{data bitmap2}},y ; load B2 -> A
|
||||
sta GRP0 ; B2 -> [GRP0], B1 -> GRP1
|
||||
lda {{data bitmap5}},y ; load B5 -> A
|
||||
sta {{$1}} ; B5 -> temp
|
||||
ldx {{data bitmap4}},y ; load B4 -> X
|
||||
lda {{data bitmap3}},y ; load B3 -> A
|
||||
ldy {{$1}} ; load B5 -> Y
|
||||
sta GRP1 ; B3 -> [GRP1]; B2 -> GRP0
|
||||
stx GRP0 ; B4 -> [GRP0]; B3 -> GRP1
|
||||
sty GRP1 ; B5 -> [GRP1]; B4 -> GRP0
|
||||
sta GRP0 ; ?? -> [GRP0]; B5 -> GRP1
|
||||
dec {{$0}} ; go to next line
|
||||
bpl :- ; repeat until < 0
|
||||
pla
|
||||
tax
|
||||
---
|
||||
end
|
||||
|
||||
demo TitleDemo
|
||||
|
||||
scope Title
|
||||
|
||||
using FrameLoop, StandardKernel
|
||||
using Kernel48Pixel with [#Name]
|
||||
using Kernel48Pixel with [#Copyright]
|
||||
using JoyButton
|
||||
|
||||
entity [Player]
|
||||
end
|
||||
|
||||
system Advance
|
||||
on joybutton do once
|
||||
---
|
||||
jmp Title2__Start
|
||||
---
|
||||
end
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
const lines = 30
|
||||
const bgcolor = $a0
|
||||
end
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
const lines = 10
|
||||
const bgcolor = $a2
|
||||
end
|
||||
|
||||
// convert -size 48x -gravity center label:"6502\nECS" pbm: | pnmtopnm -plain
|
||||
entity Name [KernelSection, BGColor, PFColor, Bitmap48]
|
||||
const lines = 2
|
||||
const bgcolor = 0xa4
|
||||
const pfcolor = 0xfc
|
||||
decode vcs_bitmap48 ---
|
||||
000000111100000111111110000011110000001111100000
|
||||
000011111110000111111110001111111000011111110000
|
||||
000011000011000110000000001100011000111000011000
|
||||
000110000011000110000000011000001100110000011000
|
||||
000110000000000110000000011000001100000000011000
|
||||
000110111100000111111000011000001100000000011000
|
||||
000111111110000111111100011000001100000000110000
|
||||
000111000111000000001110011000001100000001110000
|
||||
000110000011000000000110011000001100000011100000
|
||||
000110000011000000000110011000001100000111000000
|
||||
000110000011000000000110011000001100001110000000
|
||||
000110000011001100000110011000001100011100000000
|
||||
000011000011001100001110001100011000111000000000
|
||||
000011111110000111111100001111111000111111111000
|
||||
000000111100000011111000000111110000111111111000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000111111111100000011111000000001111100000000
|
||||
000000111111111100001111111110000111111111000000
|
||||
000000110000000000011100000111000110000011100000
|
||||
000000110000000000011000000011001100000001100000
|
||||
000000110000000000111000000001001100000000000000
|
||||
000000110000000000110000000000000111000000000000
|
||||
000000111111111000110000000000000011111000000000
|
||||
000000111111111000110000000000000001111111000000
|
||||
000000110000000000110000000000000000000111100000
|
||||
000000110000000000110000000000000000000001100000
|
||||
000000110000000000111000000011101100000001100000
|
||||
000000110000000000011000000011001100000001100000
|
||||
000000110000000000011100000111000110000011100000
|
||||
000000111111111100001111111110000111111111000000
|
||||
000000111111111100000011111000000001111110000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
|
||||
---
|
||||
end
|
||||
|
||||
entity Copyright [KernelSection, BGColor, PFColor, Bitmap48]
|
||||
const lines = 2
|
||||
const bgcolor = 0xa4
|
||||
const pfcolor = 0x8c
|
||||
decode vcs_bitmap48 ---
|
||||
000000000000000000000000000000100000000100000100
|
||||
000000000000000000000000000000000000000100000100
|
||||
000111000111001111010001101110100011010111101110
|
||||
001001001001001101111001001100100100110110100100
|
||||
001001001000101000101001001000100100110100010100
|
||||
011000011000101000101001001000101100010100010100
|
||||
011000011000101000101010001000101100010100010100
|
||||
011001001000101000100110001000100100110100010100
|
||||
001001001001001001000110001000100100110100010110
|
||||
000110000111001111000110001000100011110100010000
|
||||
000000000000001000000100000000000000010000000000
|
||||
000000000000001000000100000000000100100000000000
|
||||
000000000000001000001000000000000111100000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000001110001110001110001110000000000000
|
||||
000000000000010011011010010011010011000000000000
|
||||
000000000000010001010011010011010001000000000000
|
||||
000000000000000001110001000001000001000000000000
|
||||
000000000000000011110001000011000011000000000000
|
||||
000000000000000110110001000110000110000000000000
|
||||
000000000000001100110001001100001000000000000000
|
||||
000000000000010000010001010000010000000000000000
|
||||
000000000000010000010010010000010000000000000000
|
||||
000000000000111111001110111111111111000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
---
|
||||
end
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
const lines = 10
|
||||
const bgcolor = $a2
|
||||
end
|
||||
entity [KernelSection, BGColor]
|
||||
const lines = 10
|
||||
const bgcolor = $a0
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
scope Title2
|
||||
|
||||
using FrameLoop, Kernel48Pixel, StandardKernel
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
var lines = 60
|
||||
var bgcolor = 0x10
|
||||
end
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
var lines = 30
|
||||
var bgcolor = 0x30
|
||||
end
|
||||
|
||||
// convert -size 48x -gravity center label:"6502\nECS" pbm: | pnmtopnm -plain
|
||||
entity [KernelSection, BGColor, PFColor, Bitmap48]
|
||||
var lines = 2
|
||||
var pfcolor = 0xec
|
||||
var bgcolor = 0x30
|
||||
decode vcs_bitmap48 ---
|
||||
000000000000000000000000000000000000000000011000
|
||||
000000000000000000000000000000000000000000011000
|
||||
000000000000000000000000000000000000000000011000
|
||||
000000000000000000000000000000000000000000011000
|
||||
000001111011000011111000000111110000001111011000
|
||||
000011111111000111111100001111111000011111111000
|
||||
000110000111001100001110011000001100110000111000
|
||||
000110000011001100000110011000001100110000011000
|
||||
000110000011001100000110011000001100110000011000
|
||||
000110000011001100000110011000001100110000011000
|
||||
000110000011001100000110011000001100110000011000
|
||||
000110000011001100000110011000001100110000011000
|
||||
000110000111001100000110011000001100110000111000
|
||||
000011111111000111111100001111111000011111111000
|
||||
000001111011000011111000000111110000001111011000
|
||||
000000000011000000000000000000000000000000000000
|
||||
000110000110000000000000000000000000000000000000
|
||||
000111111110000000000000000000000000000000000000
|
||||
000001111100000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
000000000110000000000000110000000000110000000000
|
||||
000000000110000000000000110000000000110000000000
|
||||
000000000000000000000000110000000000110000000000
|
||||
000000000000000000000000110000000000110000000000
|
||||
000000000110000111110000110111100000110000000000
|
||||
000000000110001111111000111111110000110000000000
|
||||
000000000110011100001100111000011000110000000000
|
||||
000000000110011000001100110000011000110000000000
|
||||
000000000110011000001100110000011000110000000000
|
||||
000000000110011000001100110000011000110000000000
|
||||
000000000110011000001100110000011000110000000000
|
||||
000000000110011000001100110000011000000000000000
|
||||
000000000110011000001100111000011000000000000000
|
||||
000000000110001111111000111100110000110000000000
|
||||
000000000110000111110000110111100000110000000000
|
||||
000000000110000000000000000000000000000000000000
|
||||
000000000110000000000000000000000000000000000000
|
||||
000000011110000000000000000000000000000000000000
|
||||
000000011100000000000000000000000000000000000000
|
||||
000000000000000000000000000000000000000000000000
|
||||
---
|
||||
end
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
var lines = 20
|
||||
var bgcolor = 0x30
|
||||
end
|
||||
|
||||
entity [KernelSection, BGColor]
|
||||
var lines = 20
|
||||
var bgcolor = 0x50
|
||||
end
|
||||
|
||||
system Colors
|
||||
on postframe do foreach [PFColor]
|
||||
---
|
||||
inc {{set pfcolor}}
|
||||
bne :+
|
||||
inc {{set bgcolor}}
|
||||
:
|
||||
---
|
||||
on postframe do foreach [KernelSection]
|
||||
---
|
||||
dec {{set lines}}
|
||||
bne :+
|
||||
lda #1
|
||||
sta {{set lines}}
|
||||
:
|
||||
---
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
system Demo
|
||||
on start do once
|
||||
---
|
||||
{{start Title}}
|
||||
---
|
||||
end
|
||||
|
||||
end demo
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,235 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
system Init
|
||||
on main_init do once
|
||||
---
|
||||
.include "vcs-ca65.h"
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
{{!start}} ; start main routine
|
||||
.segment "VECTORS"
|
||||
Return: .word $6060
|
||||
VecNMI:
|
||||
VecReset: .word Main::__Reset
|
||||
VecBRK: .word Main::__BRK
|
||||
---
|
||||
end
|
||||
|
||||
component Player
|
||||
end
|
||||
|
||||
component KernelSection
|
||||
lines: 1..255
|
||||
end
|
||||
|
||||
component BGColor
|
||||
bgcolor: 0..255
|
||||
end
|
||||
|
||||
component PFColor
|
||||
pfcolor: 0..255
|
||||
end
|
||||
|
||||
component Playfield
|
||||
pf: 0..0xffffff
|
||||
end
|
||||
|
||||
component AsymPlayfield
|
||||
pfleft: 0..0xffffff
|
||||
pfright: 0..0xffffff
|
||||
end
|
||||
|
||||
component VersatilePlayfield
|
||||
data: array of 0..255 baseoffset -1
|
||||
end
|
||||
|
||||
system FrameLoop
|
||||
on start do once
|
||||
---
|
||||
@NextFrame:
|
||||
FRAME_START
|
||||
{{emit preframe}}
|
||||
KERNEL_START
|
||||
{{emit kernel}}
|
||||
KERNEL_END
|
||||
{{emit postframe}}
|
||||
FRAME_END
|
||||
{{emit nextframe}}
|
||||
jmp @NextFrame ; loop to next frame
|
||||
---
|
||||
end
|
||||
|
||||
system ResetSwitch
|
||||
on nextframe do once
|
||||
---
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs @NoStart
|
||||
{{!resetswitch}}
|
||||
@NoStart:
|
||||
---
|
||||
end
|
||||
|
||||
system ResetConsole
|
||||
on resetswitch do once
|
||||
---
|
||||
jmp Main::__Reset ; jump to Reset handler
|
||||
---
|
||||
end
|
||||
|
||||
system JoyButton
|
||||
on postframe do foreach [Player]
|
||||
---
|
||||
lda {{index INPT4}} ;read button input
|
||||
bmi @NotPressed
|
||||
{{emit joybutton}}
|
||||
@NotPressed:
|
||||
---
|
||||
end
|
||||
|
||||
system Joystick
|
||||
locals 1
|
||||
on postframe do once
|
||||
---
|
||||
; 2 control inputs share a single byte, 4 bits each
|
||||
lda SWCHA
|
||||
sta {{$0}}
|
||||
---
|
||||
on postframe do foreach [Player]
|
||||
---
|
||||
asl {{$0}}
|
||||
bcs @SkipMoveRight
|
||||
{{!joyright}}
|
||||
@SkipMoveRight:
|
||||
asl {{$0}}
|
||||
bcs @SkipMoveLeft
|
||||
{{!joyleft}}
|
||||
@SkipMoveLeft:
|
||||
asl {{$0}}
|
||||
bcs @SkipMoveDown
|
||||
{{!joydown}}
|
||||
@SkipMoveDown:
|
||||
asl {{$0}}
|
||||
bcs @SkipMoveUp
|
||||
{{!joyup}}
|
||||
@SkipMoveUp:
|
||||
---
|
||||
end
|
||||
|
||||
system SetHorizPos
|
||||
on SetHorizPos do once
|
||||
---
|
||||
; SetHorizPos routine
|
||||
; A = X coordinate
|
||||
; Y = player number (0 or 1)
|
||||
sta WSYNC ; start a new line
|
||||
sec ; set carry flag
|
||||
nop
|
||||
@DivideLoop:
|
||||
sbc #15 ; subtract 15
|
||||
bcs @DivideLoop ; branch until negative
|
||||
eor #7 ; calculate fine offset
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta RESP0,y ; fix coarse position
|
||||
sta HMP0,y ; set fine offset
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
system StaticKernel
|
||||
on preframe do foreach [KernelSection] limit 1
|
||||
---
|
||||
{{!kernelsetup}}
|
||||
---
|
||||
on kernel do foreach [KernelSection]
|
||||
---
|
||||
sta WSYNC
|
||||
{{!kernelsetup}}
|
||||
ldy {{<lines}}
|
||||
@loop:
|
||||
sta WSYNC
|
||||
{{!scanline}}
|
||||
dey
|
||||
bne @loop
|
||||
{{!kerneldone}}
|
||||
---
|
||||
on kernelsetup do if [BGColor]
|
||||
---
|
||||
lda {{<bgcolor}}
|
||||
sta COLUBK
|
||||
---
|
||||
on kernelsetup do if [PFColor]
|
||||
---
|
||||
lda {{get pfcolor}}
|
||||
sta COLUPF
|
||||
---
|
||||
on kernelsetup do if [Playfield]
|
||||
---
|
||||
lda {{get pf 0}}
|
||||
sta PF0
|
||||
lda {{get pf 8}}
|
||||
sta PF1
|
||||
lda {{get pf 16}}
|
||||
sta PF2
|
||||
---
|
||||
end
|
||||
|
||||
///
|
||||
|
||||
demo Main
|
||||
using FrameLoop, ResetSwitch, ResetConsole
|
||||
using StaticKernel, JoyButton
|
||||
entity [Player]
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $18
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $16
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $14
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $12
|
||||
end
|
||||
entity [KernelSection,BGColor,Playfield]
|
||||
const lines = 10
|
||||
const bgcolor = $14
|
||||
const pf = 0x125244
|
||||
end
|
||||
entity Trees [KernelSection,BGColor,PFColor,Playfield]
|
||||
const lines = 50
|
||||
const bgcolor = $14
|
||||
const pf = 0x112244
|
||||
end
|
||||
entity [KernelSection,BGColor,PFColor,Playfield]
|
||||
const lines = 50
|
||||
const bgcolor = $16
|
||||
const pf = 0x124
|
||||
end
|
||||
entity [KernelSection,BGColor,Playfield]
|
||||
const lines = 10
|
||||
const bgcolor = $18
|
||||
const pf = 0
|
||||
end
|
||||
|
||||
system Local
|
||||
locals 1
|
||||
on joybutton do foreach [PFColor] limit 1 ---
|
||||
inc {{$0}}
|
||||
inc {{set Trees.pfcolor}}
|
||||
---
|
||||
end
|
||||
end demo
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
EVENT__start = 1
|
||||
EVENT__nextframe = 1
|
||||
EVENT__resetswitch = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__kernel = 1
|
||||
EVENT__kernelsetup = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__joybutton = 1
|
||||
.scope Main
|
||||
.zeropage
|
||||
PFColor_pfcolor_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
TEMP:
|
||||
Local__6__tmp:
|
||||
.res 1
|
||||
.code
|
||||
KernelSection_lines_b0:
|
||||
.byte 2
|
||||
.byte 2
|
||||
.byte 2
|
||||
.byte 2
|
||||
.byte 10
|
||||
.byte 50
|
||||
.byte 50
|
||||
.byte 10
|
||||
BGColor_bgcolor_b0:
|
||||
.byte 24
|
||||
.byte 22
|
||||
.byte 20
|
||||
.byte 18
|
||||
.byte 20
|
||||
.byte 20
|
||||
.byte 22
|
||||
.byte 24
|
||||
Playfield_pf_b0:
|
||||
.byte 68
|
||||
.byte 68
|
||||
.byte 36
|
||||
.byte 0
|
||||
Playfield_pf_b8:
|
||||
.byte 82
|
||||
.byte 34
|
||||
.byte 1
|
||||
.byte 0
|
||||
Playfield_pf_b16:
|
||||
.byte 18
|
||||
.byte 17
|
||||
.byte 0
|
||||
.byte 0
|
||||
Main__INITDATA:
|
||||
.byte 0
|
||||
.byte 0
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #2
|
||||
: lda Main__INITDATA-1,y
|
||||
sta PFColor_pfcolor_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_START
|
||||
|
||||
;;; start action StaticKernel__preframe__5
|
||||
|
||||
|
||||
;;; start action StaticKernel__kernelsetup__8
|
||||
|
||||
lda #24
|
||||
sta COLUBK
|
||||
|
||||
;;; end action StaticKernel__kernelsetup__8
|
||||
|
||||
;;; start action StaticKernel__kernelsetup__11
|
||||
|
||||
;;; end action StaticKernel__kernelsetup__11
|
||||
|
||||
;;; start action StaticKernel__kernelsetup__12
|
||||
|
||||
;;; end action StaticKernel__kernelsetup__12
|
||||
|
||||
|
||||
;;; end action StaticKernel__preframe__5
|
||||
|
||||
KERNEL_START
|
||||
|
||||
;;; start action StaticKernel__kernel__13
|
||||
|
||||
ldx #0
|
||||
StaticKernel__kernel__14____each:
|
||||
|
||||
sta WSYNC
|
||||
|
||||
;;; start action StaticKernel__kernelsetup__16
|
||||
|
||||
lda BGColor_bgcolor_b0,x
|
||||
sta COLUBK
|
||||
|
||||
;;; end action StaticKernel__kernelsetup__16
|
||||
|
||||
;;; start action StaticKernel__kernelsetup__19
|
||||
|
||||
cpx #5+2
|
||||
jcs StaticKernel__kernelsetup__20____skipxhi
|
||||
|
||||
cpx #5
|
||||
jcc StaticKernel__kernelsetup__20____skipxlo
|
||||
|
||||
lda PFColor_pfcolor_b0-5,x
|
||||
sta COLUPF
|
||||
|
||||
StaticKernel__kernelsetup__20____skipxlo:
|
||||
|
||||
StaticKernel__kernelsetup__20____skipxhi:
|
||||
|
||||
;;; end action StaticKernel__kernelsetup__19
|
||||
|
||||
;;; start action StaticKernel__kernelsetup__22
|
||||
|
||||
cpx #4
|
||||
jcc StaticKernel__kernelsetup__23____skipxlo
|
||||
|
||||
lda Playfield_pf_b0-4,x
|
||||
sta PF0
|
||||
lda Playfield_pf_b8-4,x
|
||||
sta PF1
|
||||
lda Playfield_pf_b16-4,x
|
||||
sta PF2
|
||||
|
||||
StaticKernel__kernelsetup__23____skipxlo:
|
||||
|
||||
;;; end action StaticKernel__kernelsetup__22
|
||||
|
||||
ldy KernelSection_lines_b0,x
|
||||
StaticKernel__kernel__15__loop:
|
||||
sta WSYNC
|
||||
|
||||
dey
|
||||
bne StaticKernel__kernel__15__loop
|
||||
|
||||
|
||||
inx
|
||||
cpx #8
|
||||
jne StaticKernel__kernel__14____each
|
||||
StaticKernel__kernel__14____exit:
|
||||
|
||||
;;; end action StaticKernel__kernel__13
|
||||
|
||||
KERNEL_END
|
||||
|
||||
;;; start action JoyButton__postframe__25
|
||||
|
||||
lda INPT4 ;read button input
|
||||
bmi JoyButton__postframe__27__NotPressed
|
||||
|
||||
;;; start action Local__joybutton__28
|
||||
|
||||
inc Local__6__tmp+0
|
||||
inc PFColor_pfcolor_b0
|
||||
|
||||
;;; end action Local__joybutton__28
|
||||
|
||||
JoyButton__postframe__27__NotPressed:
|
||||
|
||||
;;; end action JoyButton__postframe__25
|
||||
|
||||
FRAME_END
|
||||
|
||||
;;; start action ResetSwitch__nextframe__31
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs ResetSwitch__nextframe__32__NoStart
|
||||
|
||||
;;; start action ResetConsole__resetswitch__33
|
||||
|
||||
jmp Main::__Reset ; jump to Reset handler
|
||||
|
||||
;;; end action ResetConsole__resetswitch__33
|
||||
|
||||
ResetSwitch__nextframe__32__NoStart:
|
||||
|
||||
;;; end action ResetSwitch__nextframe__31
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
Return: .word $6060
|
||||
VecNMI:
|
||||
VecReset: .word Main::__Reset
|
||||
VecBRK: .word Main::__BRK
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,338 @@
|
|||
|
||||
//#resource "vcs-ca65.h"
|
||||
|
||||
system Init
|
||||
on main_init do once
|
||||
---
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
{{!start}} ; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
---
|
||||
end
|
||||
|
||||
component Player
|
||||
end
|
||||
|
||||
component KernelSection
|
||||
lines: 1..255 default 1
|
||||
end
|
||||
|
||||
component BGColor
|
||||
bgcolor: 0..255
|
||||
end
|
||||
|
||||
component FGColor
|
||||
fgcolor: 0..255
|
||||
end
|
||||
|
||||
component PFColor
|
||||
pfcolor: 0..255
|
||||
end
|
||||
|
||||
component Playfield
|
||||
pf: 0..0xffffff
|
||||
end
|
||||
|
||||
component AsymPlayfield
|
||||
pfleft: 0..0xffffff
|
||||
pfright: 0..0xffffff
|
||||
end
|
||||
|
||||
system FrameLoop
|
||||
on start do once
|
||||
---
|
||||
{{emit preframeloop}}
|
||||
@NextFrame:
|
||||
FRAME_END
|
||||
{{emit prevsync}}
|
||||
FRAME_START
|
||||
{{emit preframe}}
|
||||
{{emit prekernel}}
|
||||
KERNEL_START
|
||||
{{emit kernel}}
|
||||
KERNEL_END
|
||||
{{emit postkernel}}
|
||||
{{emit postframe}}
|
||||
jmp @NextFrame ; loop to next frame
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs @NoStart
|
||||
{{emit resetswitch}}
|
||||
@NoStart:
|
||||
---
|
||||
end
|
||||
|
||||
system ResetConsole
|
||||
on resetswitch do once
|
||||
---
|
||||
jmp Main::__Reset ; jump to Reset handler
|
||||
---
|
||||
end
|
||||
|
||||
system JoyButton
|
||||
on postframe do foreach [Player]
|
||||
---
|
||||
lda {{index INPT4}} ;read button input
|
||||
bmi @NotPressed
|
||||
{{emit joybutton}}
|
||||
@NotPressed:
|
||||
---
|
||||
end
|
||||
|
||||
system Joystick
|
||||
locals 1
|
||||
on postframe do once
|
||||
---
|
||||
; 2 control inputs share a single byte, 4 bits each
|
||||
lda SWCHA
|
||||
sta {{$0}}
|
||||
---
|
||||
on postframe do foreach [Player] limit 2
|
||||
---
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joyright
|
||||
bcs @SkipMoveRight
|
||||
{{!joyright}}
|
||||
@SkipMoveRight:
|
||||
.endif
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joyleft
|
||||
bcs @SkipMoveLeft
|
||||
{{!joyleft}}
|
||||
@SkipMoveLeft:
|
||||
.endif
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joydown
|
||||
bcs @SkipMoveDown
|
||||
{{!joydown}}
|
||||
@SkipMoveDown:
|
||||
.endif
|
||||
asl {{$0}}
|
||||
.ifdef EVENT__joyup
|
||||
bcs @SkipMoveUp
|
||||
{{!joyup}}
|
||||
@SkipMoveUp:
|
||||
.endif
|
||||
---
|
||||
end
|
||||
|
||||
system SetHorizPos
|
||||
on SetHorizPos do critical fit 22 once
|
||||
---
|
||||
; SetHorizPos routine
|
||||
; A = X coordinate
|
||||
; Y = player number (0 or 1)
|
||||
sec ; set carry flag
|
||||
sta WSYNC ; start a new line
|
||||
:
|
||||
sbc #15 ; subtract 15
|
||||
bcs :- ; branch until negative
|
||||
eor #7 ; calculate fine offset
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
asl
|
||||
sta HMP0,y ; set fine offset
|
||||
sta RESP0,y ; fix coarse position
|
||||
sta WSYNC ; won't overrun if X < 150
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
system StandardKernel
|
||||
on wsync do once
|
||||
---
|
||||
sta WSYNC
|
||||
---
|
||||
on preframe do foreach [KernelSection] limit 1
|
||||
---
|
||||
{{!wsync}}
|
||||
{{!kernelsetup}}
|
||||
---
|
||||
on kernel do foreach [KernelSection]
|
||||
---
|
||||
{{!wsync}}
|
||||
{{!kernelsetup}}
|
||||
{{!kerneldraw}}
|
||||
{{!kerneldone}}
|
||||
---
|
||||
on kerneldraw do with [KernelSection]
|
||||
---
|
||||
ldy {{<lines}}
|
||||
@loop:
|
||||
{{!prescanline}}
|
||||
{{!wsync}}
|
||||
{{!scanline}}
|
||||
dey
|
||||
bne @loop
|
||||
---
|
||||
on kernelsetup do if [BGColor]
|
||||
---
|
||||
lda {{<bgcolor}}
|
||||
sta COLUBK
|
||||
---
|
||||
on kernelsetup do if [PFColor]
|
||||
---
|
||||
lda {{get pfcolor}}
|
||||
sta COLUPF
|
||||
---
|
||||
on kernelsetup do if [Playfield]
|
||||
---
|
||||
lda {{get pf 0}}
|
||||
sta PF0
|
||||
lda {{get pf 8}}
|
||||
sta PF1
|
||||
lda {{get pf 16}}
|
||||
sta PF2
|
||||
---
|
||||
end
|
||||
|
||||
component SimpleCollidable
|
||||
lastx: 0..255
|
||||
lasty: 0..255
|
||||
end
|
||||
|
||||
system SimpleCollision
|
||||
on postframe do with [SimpleCollidable]
|
||||
---
|
||||
lda CXP0FB
|
||||
bpl @nocollide
|
||||
lda {{<lastx}}
|
||||
sta {{<xpos}}
|
||||
lda {{<lasty}}
|
||||
sta {{<ypos}}
|
||||
@nocollide:
|
||||
---
|
||||
on ymoved do with [SimpleCollidable]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
sta {{<lastx}}
|
||||
lda {{<ypos}}
|
||||
sta {{<lasty}}
|
||||
---
|
||||
end
|
||||
|
||||
component FrameCount
|
||||
frame: 0..255
|
||||
end
|
||||
|
||||
system FrameCounter
|
||||
on postframe do with [FrameCount]
|
||||
---
|
||||
inc {{set frame}}
|
||||
.ifdef EVENT__frame256
|
||||
jne @noframe256
|
||||
{{emit frame256}}
|
||||
@noframe256:
|
||||
.endif
|
||||
---
|
||||
// TODO: only .if responds to events
|
||||
on postframe do with [FrameCount]
|
||||
---
|
||||
jmp @go
|
||||
.ifdef EVENT__frame4
|
||||
@frame4:
|
||||
{{emit frame4}}
|
||||
jmp @done
|
||||
.endif
|
||||
.ifdef EVENT__frame8
|
||||
@frame8:
|
||||
{{emit frame8}}
|
||||
jmp @done
|
||||
.endif
|
||||
.ifdef EVENT__frame16
|
||||
@frame16:
|
||||
{{emit frame16}}
|
||||
jmp @done
|
||||
.endif
|
||||
@go:
|
||||
lda {{get frame}}
|
||||
.ifdef EVENT__frame16
|
||||
and #15
|
||||
jeq @frame16
|
||||
.endif
|
||||
.ifdef EVENT__frame8
|
||||
and #7
|
||||
cmp #3
|
||||
jeq @frame8
|
||||
.endif
|
||||
.ifdef EVENT__frame4
|
||||
and #3
|
||||
cmp #1
|
||||
jeq @frame4
|
||||
.endif
|
||||
@done:
|
||||
---
|
||||
end
|
||||
|
||||
|
||||
|
||||
///
|
||||
|
||||
demo Main
|
||||
using FrameLoop, ResetConsole
|
||||
using StandardKernel, JoyButton
|
||||
|
||||
entity [Player]
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $18
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $16
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $14
|
||||
end
|
||||
entity [KernelSection,BGColor]
|
||||
const lines = 2
|
||||
const bgcolor = $12
|
||||
end
|
||||
entity [KernelSection,BGColor,Playfield]
|
||||
const lines = 10
|
||||
const bgcolor = $14
|
||||
const pf = 0x125244
|
||||
end
|
||||
entity Trees [KernelSection,BGColor,PFColor,Playfield]
|
||||
const lines = 50
|
||||
const bgcolor = $14
|
||||
const pf = 0x112244
|
||||
end
|
||||
entity Trees2 [KernelSection,BGColor,PFColor,Playfield]
|
||||
const lines = 50
|
||||
const bgcolor = $16
|
||||
const pf = 0x124
|
||||
end
|
||||
entity [KernelSection,BGColor,Playfield]
|
||||
const lines = 10
|
||||
const bgcolor = $18
|
||||
const pf = 0
|
||||
end
|
||||
|
||||
system Local
|
||||
locals 1
|
||||
on joybutton do foreach [PFColor] limit 1 ---
|
||||
inc {{$0}}
|
||||
inc {{set Trees.pfcolor}}
|
||||
---
|
||||
end
|
||||
|
||||
end demo
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
EVENT__start = 1
|
||||
EVENT__postframe = 1
|
||||
EVENT__resetswitch = 1
|
||||
EVENT__wsync = 1
|
||||
EVENT__preframe = 1
|
||||
EVENT__kernel = 1
|
||||
EVENT__kerneldraw = 1
|
||||
EVENT__kernelsetup = 1
|
||||
EVENT__joybutton = 1
|
||||
.scope Main
|
||||
.zeropage
|
||||
PFColor_pfcolor_b0:
|
||||
.res 1
|
||||
.res 1
|
||||
TEMP:
|
||||
Local__5__tmp:
|
||||
.res 1
|
||||
.code
|
||||
KernelSection_lines_b0:
|
||||
.byte 2
|
||||
.byte 2
|
||||
.byte 2
|
||||
.byte 2
|
||||
.byte 10
|
||||
.byte 50
|
||||
.byte 50
|
||||
.byte 10
|
||||
BGColor_bgcolor_b0:
|
||||
.byte 24
|
||||
.byte 22
|
||||
.byte 20
|
||||
.byte 18
|
||||
.byte 20
|
||||
.byte 20
|
||||
.byte 22
|
||||
.byte 24
|
||||
Playfield_pf_b0:
|
||||
.byte 68
|
||||
.byte 68
|
||||
.byte 36
|
||||
.byte 0
|
||||
Playfield_pf_b8:
|
||||
.byte 82
|
||||
.byte 34
|
||||
.byte 1
|
||||
.byte 0
|
||||
Playfield_pf_b16:
|
||||
.byte 18
|
||||
.byte 17
|
||||
.byte 0
|
||||
.byte 0
|
||||
Main__INITDATA:
|
||||
.byte 0
|
||||
.byte 0
|
||||
__Start:
|
||||
|
||||
;;; start action Init__main_init__1
|
||||
|
||||
.include "vcs-ca65.h"
|
||||
.macpack longbranch
|
||||
.define PAL 0
|
||||
__NMI:
|
||||
__Reset:
|
||||
__BRK:
|
||||
CLEAN_START
|
||||
|
||||
ldy #2
|
||||
: lda Main__INITDATA-1,y
|
||||
sta PFColor_pfcolor_b0-1,y
|
||||
dey
|
||||
bne :-
|
||||
|
||||
;;; start action FrameLoop__start__3
|
||||
|
||||
|
||||
FrameLoop__start__4__NextFrame:
|
||||
FRAME_END
|
||||
|
||||
FRAME_START
|
||||
|
||||
;;; start action StandardKernel__preframe__5
|
||||
|
||||
|
||||
;;; start action StandardKernel__wsync__8
|
||||
|
||||
sta WSYNC
|
||||
|
||||
;;; end action StandardKernel__wsync__8
|
||||
|
||||
|
||||
;;; start action StandardKernel__kernelsetup__10
|
||||
|
||||
lda #24
|
||||
sta COLUBK
|
||||
|
||||
;;; end action StandardKernel__kernelsetup__10
|
||||
|
||||
;;; start action StandardKernel__kernelsetup__13
|
||||
|
||||
;;; end action StandardKernel__kernelsetup__13
|
||||
|
||||
;;; start action StandardKernel__kernelsetup__14
|
||||
|
||||
;;; end action StandardKernel__kernelsetup__14
|
||||
|
||||
|
||||
;;; end action StandardKernel__preframe__5
|
||||
|
||||
|
||||
KERNEL_START
|
||||
|
||||
;;; start action StandardKernel__kernel__15
|
||||
|
||||
ldx #0
|
||||
StandardKernel__kernel__16____each:
|
||||
|
||||
|
||||
;;; start action StandardKernel__wsync__18
|
||||
|
||||
sta WSYNC
|
||||
|
||||
;;; end action StandardKernel__wsync__18
|
||||
|
||||
|
||||
;;; start action StandardKernel__kernelsetup__20
|
||||
|
||||
lda BGColor_bgcolor_b0,x
|
||||
sta COLUBK
|
||||
|
||||
;;; end action StandardKernel__kernelsetup__20
|
||||
|
||||
;;; start action StandardKernel__kernelsetup__23
|
||||
|
||||
cpx #5+2
|
||||
jcs StandardKernel__kernelsetup__24____skipxhi
|
||||
|
||||
cpx #5
|
||||
jcc StandardKernel__kernelsetup__24____skipxlo
|
||||
|
||||
lda PFColor_pfcolor_b0-5,x
|
||||
sta COLUPF
|
||||
|
||||
StandardKernel__kernelsetup__24____skipxlo:
|
||||
|
||||
StandardKernel__kernelsetup__24____skipxhi:
|
||||
|
||||
;;; end action StandardKernel__kernelsetup__23
|
||||
|
||||
;;; start action StandardKernel__kernelsetup__26
|
||||
|
||||
cpx #4
|
||||
jcc StandardKernel__kernelsetup__27____skipxlo
|
||||
|
||||
lda Playfield_pf_b0-4,x
|
||||
sta PF0
|
||||
lda Playfield_pf_b8-4,x
|
||||
sta PF1
|
||||
lda Playfield_pf_b16-4,x
|
||||
sta PF2
|
||||
|
||||
StandardKernel__kernelsetup__27____skipxlo:
|
||||
|
||||
;;; end action StandardKernel__kernelsetup__26
|
||||
|
||||
|
||||
;;; start action StandardKernel__kerneldraw__29
|
||||
|
||||
ldy KernelSection_lines_b0,x
|
||||
StandardKernel__kerneldraw__31__loop:
|
||||
|
||||
|
||||
;;; start action StandardKernel__wsync__32
|
||||
|
||||
sta WSYNC
|
||||
|
||||
;;; end action StandardKernel__wsync__32
|
||||
|
||||
|
||||
dey
|
||||
bne StandardKernel__kerneldraw__31__loop
|
||||
|
||||
;;; end action StandardKernel__kerneldraw__29
|
||||
|
||||
|
||||
|
||||
inx
|
||||
cpx #8
|
||||
jne StandardKernel__kernel__16____each
|
||||
StandardKernel__kernel__16____exit:
|
||||
|
||||
;;; end action StandardKernel__kernel__15
|
||||
|
||||
KERNEL_END
|
||||
|
||||
|
||||
;;; start action FrameLoop__postframe__34
|
||||
|
||||
lsr SWCHB ; test Game Reset switch
|
||||
bcs FrameLoop__postframe__35__NoStart
|
||||
|
||||
;;; start action ResetConsole__resetswitch__36
|
||||
|
||||
jmp Main::__Reset ; jump to Reset handler
|
||||
|
||||
;;; end action ResetConsole__resetswitch__36
|
||||
|
||||
FrameLoop__postframe__35__NoStart:
|
||||
|
||||
;;; end action FrameLoop__postframe__34
|
||||
|
||||
;;; start action JoyButton__postframe__38
|
||||
|
||||
lda INPT4 ;read button input
|
||||
bmi JoyButton__postframe__40__NotPressed
|
||||
|
||||
;;; start action Local__joybutton__41
|
||||
|
||||
inc Local__5__tmp+0
|
||||
inc PFColor_pfcolor_b0
|
||||
|
||||
;;; end action Local__joybutton__41
|
||||
|
||||
JoyButton__postframe__40__NotPressed:
|
||||
|
||||
;;; end action JoyButton__postframe__38
|
||||
|
||||
jmp FrameLoop__start__4__NextFrame ; loop to next frame
|
||||
|
||||
;;; end action FrameLoop__start__3
|
||||
; start main routine
|
||||
.segment "VECTORS"
|
||||
ZeroByte: .byte $00
|
||||
Return: .byte $60
|
||||
VecNMI:
|
||||
VecReset: .word __Reset
|
||||
VecBRK: .word __BRK
|
||||
.code
|
||||
|
||||
;;; end action Init__main_init__1
|
||||
|
||||
.endscope
|
||||
Main__Start = Main::__Start
|
|
@ -0,0 +1,69 @@
|
|||
|
||||
component VersatilePlayfield
|
||||
data: array of 0..255 baseoffset -1
|
||||
end
|
||||
|
||||
system VersatilePlayfield
|
||||
locals 2
|
||||
on preframe do with [VersatilePlayfield]
|
||||
---
|
||||
lda {{<data}}
|
||||
sta {{$0}}
|
||||
lda {{>data}}
|
||||
sta {{$1}}
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
.if {{arg 0}} = 0
|
||||
lda ({{local 0}}),y
|
||||
tax
|
||||
.endif
|
||||
---
|
||||
on scanline do once
|
||||
---
|
||||
.if {{arg 0}} = 1
|
||||
lda ({{local 0}}),y
|
||||
sta $00,x
|
||||
.endif
|
||||
---
|
||||
on postframe do once
|
||||
---
|
||||
lda #0
|
||||
sta PF0
|
||||
sta PF1
|
||||
sta PF2
|
||||
---
|
||||
on checkplatform do with [HasXpos,HasYpos]
|
||||
---
|
||||
lda {{<xpos}}
|
||||
clc
|
||||
adc #6
|
||||
lsr
|
||||
lsr
|
||||
tay
|
||||
lda {{^PFCollideMask}},y
|
||||
pha
|
||||
lda {{^PFCollideReg}},y
|
||||
pha
|
||||
lda #176 ; TODO: adjust for kernel size
|
||||
sec
|
||||
sbc {{<ypos}}
|
||||
and #$fe
|
||||
tay
|
||||
; TODO: use system local pointer
|
||||
pla
|
||||
cmp ({{$0}}),y ; match register?
|
||||
bne @nostop1
|
||||
dey
|
||||
pla
|
||||
and ({{$0}}),y ; mask bitmap?
|
||||
beq @nostop
|
||||
{{!platformstopped}}
|
||||
jmp @done
|
||||
@nostop1:
|
||||
pla
|
||||
@nostop:
|
||||
{{!platformnotstopped}}
|
||||
@done:
|
||||
---
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
36:I couldn't find a component named "HasXpos".
|
Loading…
Reference in New Issue