new neslib2.lib (from clbr/neslib) using extrafiles parameter, local .h, disasm uses symbols

This commit is contained in:
Steven Hugg 2018-08-14 16:28:29 -04:00
parent 4a82d341bc
commit b29f11a1cc
18 changed files with 1540 additions and 86 deletions

View File

@ -60,6 +60,7 @@ $("#deleteitem").click(function(e) {
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-54497476-9', 'auto');
ga('set', 'anonymizeIp', true);
ga('send', 'pageview');
</script>
</html>

View File

@ -1,6 +1,9 @@

#include "neslib.h"
#pragma data-name (push,"CHARS")
#pragma data-name (pop)
//#define DEBUG
#define HAS_DEBUGGER
@ -34,6 +37,8 @@ static const unsigned char paused_palette[]={
#pragma bss-name(push,"ZEROPAGE")
#pragma data-name(push,"ZEROPAGE")
unsigned char oam_off;
static unsigned char i, j;
static unsigned char player_dir[2];
@ -2632,14 +2637,20 @@ void __fastcall__ init(void){
bank_spr(0);
bank_bg(1);
unrle_vram(bg_top_left, NAMETABLE_A);
unrle_vram(bg_top_right, NAMETABLE_B);
unrle_vram(bg_bottom_left, NAMETABLE_C);
unrle_vram(bg_bottom_right, NAMETABLE_D);
vram_adr(NAMETABLE_A);
vram_unrle(bg_top_left);
vram_adr(NAMETABLE_B);
vram_unrle(bg_top_right);
vram_adr(NAMETABLE_C);
vram_unrle(bg_bottom_left);
vram_adr(NAMETABLE_D);
vram_unrle(bg_bottom_right);
// copy tilesets
vram_write((unsigned char*)0x0000, 0x0, 0x2000);
vram_write((unsigned char*)0x2000, 0x0, 0x2000);
vram_adr(0x0);
vram_write((unsigned char*)0x0000, 0x2000);
vram_adr(0x2000);
vram_write((unsigned char*)0x2000, 0x2000);
ppu_on_all();
@ -2823,20 +2834,21 @@ void main(void){
while(1){
pal_all(paused_palette);
scroll(0, 0);
ppu_waitnmi();
ppu_wait_nmi();
ppu_off();
unrle_vram(bg_menu, NAMETABLE_A);
vram_adr(NAMETABLE_A);
vram_unrle(bg_menu);
ppu_on_all();
pal_all(palette);
ppu_waitnmi();
ppu_wait_nmi();
ppu_waitnmi();
ppu_wait_nmi();
while(1){
ppu_waitnmi();
ppu_wait_nmi();
spr=0;
oam_clear();
frame++;
@ -2894,20 +2906,21 @@ void main(void){
oam_clear();
pal_all(paused_palette);
ppu_waitnmi();
ppu_wait_nmi();
ppu_off();
unrle_vram(bg_top_left, NAMETABLE_A);
vram_adr(NAMETABLE_A);
vram_unrle(bg_top_left);
ppu_on_all();
ppu_waitnmi();
ppu_wait_nmi();
difficulty = 0;
next_level = 1;
while(1){
ppu_waitnmi();
ppu_wait_nmi();
spr=0;
oam_clear();
@ -2941,7 +2954,7 @@ void main(void){
frame = 0;
while(1)
{
ppu_waitnmi();
ppu_wait_nmi();
frame++;
if((frame > 100) && (frame == 255 || ((pad_trigger(0)|pad_trigger(1))&(PAD_A|PAD_B|PAD_START))))
{
@ -2981,7 +2994,7 @@ void main(void){
frame = 0;
while(1)
{
ppu_waitnmi();
ppu_wait_nmi();
frame++;
if(frame == 255)
{
@ -3014,7 +3027,7 @@ void main(void){
while(!(pad_trigger(0) & PAD_START))
{
ppu_waitnmi();
ppu_wait_nmi();
}
pal_all(palette);

292
presets/nes/neslib.h Normal file
View File

@ -0,0 +1,292 @@
/*
(C) 2015 Alex Semenov (Shiru)
(C) 2016 Lauri Kasanen
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
// NES hardware-dependent functions by Shiru (shiru@mail.ru)
// Feel free to do anything you want with this code, consider it Public Domain
// Versions history:
// 280215 - fixed palette glitch caused with the active DMC DMA glitch
// 030914 - minor fixes in the vram update system
// 310814 - added vram_flush_update
// 120414 - removed adr argument from vram_write and vram_read,
// unrle_vram renamed to vram_unrle, with adr argument removed
// 060414 - many fixes and improvements, including sequental VRAM updates
// previous versions were created since mid-2011, there were many updates
// set bg and spr palettes, data is 32 bytes array
void __fastcall__ pal_all(const char *data);
// set bg palette only, data is 16 bytes array
void __fastcall__ pal_bg(const char *data);
// set spr palette only, data is 16 bytes array
void __fastcall__ pal_spr(const char *data);
// set a palette entry, index is 0..31
void __fastcall__ pal_col(unsigned char index, unsigned char color);
// reset palette to $0f
void __fastcall__ pal_clear(void);
// set virtual bright both for sprites and background, 0 is black, 4 is normal, 8 is white
void __fastcall__ pal_bright(unsigned char bright);
// set virtual bright for sprites only
void __fastcall__ pal_spr_bright(unsigned char bright);
// set virtual bright for sprites background only
void __fastcall__ pal_bg_bright(unsigned char bright);
// wait actual TV frame, 50hz for PAL, 60hz for NTSC
void __fastcall__ ppu_wait_nmi(void);
// wait virtual frame, it is always 50hz, frame-to-frame in PAL, frameskip in NTSC
void __fastcall__ ppu_wait_frame(void);
// turn off rendering, nmi still enabled when rendering is disabled
void __fastcall__ ppu_off(void);
// turn on bg, spr
void __fastcall__ ppu_on_all(void);
// turn on bg only
void __fastcall__ ppu_on_bg(void);
// turn on spr only
void __fastcall__ ppu_on_spr(void);
// set PPU_MASK directly
void __fastcall__ ppu_mask(unsigned char mask);
// get current video system, 0 for PAL, not 0 for NTSC
unsigned char __fastcall__ ppu_system(void);
// Return an 8-bit counter incremented at each vblank
unsigned char __fastcall__ nesclock(void);
// get/set the internal ppu ctrl cache var for manual writing
unsigned char __fastcall__ get_ppu_ctrl_var(void);
void __fastcall__ set_ppu_ctrl_var(unsigned char var);
// clear OAM buffer, all the sprites are hidden
void __fastcall__ oam_clear(void);
// set sprite display mode, 0 for 8x8 sprites, 1 for 8x16 sprites
void __fastcall__ oam_size(unsigned char size);
// set sprite in OAM buffer, chrnum is tile, attr is attribute, sprid is offset in OAM in bytes
// returns sprid+4, which is offset for a next sprite
unsigned char __fastcall__ oam_spr(unsigned char x, unsigned char y,
unsigned char chrnum, unsigned char attr,
unsigned char sprid);
// set metasprite in OAM buffer
// meta sprite is a const unsigned char array, it contains four bytes per sprite
// in order x offset, y offset, tile, attribute
// x=128 is end of a meta sprite
// returns sprid+4, which is offset for a next sprite
unsigned char __fastcall__ oam_meta_spr(unsigned char x, unsigned char y,
unsigned char sprid, const unsigned char *data);
// hide all remaining sprites from given offset
void __fastcall__ oam_hide_rest(unsigned char sprid);
// play a music in FamiTone format
void __fastcall__ music_play(unsigned char song);
// stop music
void __fastcall__ music_stop(void);
// pause and unpause music
void __fastcall__ music_pause(unsigned char pause);
// play FamiTone sound effect on channel 0..3
void __fastcall__ sfx_play(unsigned char sound, unsigned char channel);
// play a DPCM sample, 1..63
void __fastcall__ sample_play(unsigned char sample);
// poll controller and return flags like PAD_LEFT etc, input is pad number (0 or 1)
unsigned char __fastcall__ pad_poll(unsigned char pad);
// poll controller in trigger mode, a flag is set only on button down, not hold
// if you need to poll the pad in both normal and trigger mode, poll it in the
// trigger mode for first, then use pad_state
unsigned char __fastcall__ pad_trigger(unsigned char pad);
// get previous pad state without polling ports
unsigned char __fastcall__ pad_state(unsigned char pad);
// set scroll, including rhe top bits
// it is always applied at beginning of a TV frame, not at the function call
void __fastcall__ scroll(unsigned int x, unsigned int y);
// set scroll after screen split invoked by the sprite 0 hit
// warning: all CPU time between the function call and the actual split point will be wasted!
// warning: the program loop has to fit into the frame time, ppu_wait_frame should not be used
// otherwise empty frames without split will be inserted, resulting in jumpy screen
// warning: only X scroll could be changed in this version
void __fastcall__ split(unsigned int x, unsigned int y);
// select current chr bank for sprites, 0..1
void __fastcall__ bank_spr(unsigned char n);
// select current chr bank for background, 0..1
void __fastcall__ bank_bg(unsigned char n);
// get random number 0..255 or 0..65535
unsigned char __fastcall__ rand8(void);
unsigned int __fastcall__ rand16(void);
// set random seed
void __fastcall__ set_rand(unsigned int seed);
// when display is enabled, vram access could only be done with this vram update system
// the function sets a pointer to the update buffer that contains data and addresses
// in a special format. It allows to write non-sequental bytes, as well as horizontal or
// vertical nametable sequences.
// buffer pointer could be changed during rendering, but it only takes effect on a new frame
// number of transferred bytes is limited by vblank time
// to disable updates, call this function with NULL pointer
// the update data format:
// MSB, LSB, byte for a non-sequental write
// MSB|NT_UPD_HORZ, LSB, LEN, [bytes] for a horizontal sequence
// MSB|NT_UPD_VERT, LSB, LEN, [bytes] for a vertical sequence
// NT_UPD_EOF to mark end of the buffer
// length of this data should be under 256 bytes
void __fastcall__ set_vram_update(unsigned char *buf);
// all following vram functions only work when display is disabled
// do a series of VRAM writes, the same format as for set_vram_update, but writes done right away
void __fastcall__ flush_vram_update(unsigned char *buf);
// set vram pointer to write operations if you need to write some data to vram
void __fastcall__ vram_adr(unsigned int adr);
// put a byte at current vram address, works only when rendering is turned off
void __fastcall__ vram_put(unsigned char n);
// fill a block with a byte at current vram address, works only when rendering is turned off
void __fastcall__ vram_fill(unsigned char n, unsigned int len);
// set vram autoincrement, 0 for +1 and not 0 for +32
void __fastcall__ vram_inc(unsigned char n);
// read a block from current address of vram, works only when rendering is turned off
void __fastcall__ vram_read(unsigned char *dst, unsigned int size);
// write a block to current address of vram, works only when rendering is turned off
void __fastcall__ vram_write(const unsigned char *src, unsigned int size);
// unpack RLE data to current address of vram, mostly used for nametables
void __fastcall__ vram_unrle(const unsigned char *data);
// unpack LZ4 data to this address
void __fastcall__ vram_unlz4(const unsigned char *in, unsigned char *out,
const unsigned uncompressed_size);
/*
Rough speeds for a full 1024 nametable:
- rle takes 0.5 frames
- uncompressed takes 1.3 frames
- lz4 takes 2.8 frames
*/
// like memset, but does not return anything
void __fastcall__ memfill(void *dst, unsigned char value, unsigned int len);
// delay for N frames
void __fastcall__ delay(unsigned char frames);
// display.sinc functions
void __fastcall__ oam_clear_fast(void);
void __fastcall__ oam_meta_spr_pal(unsigned char x,unsigned char y,unsigned char pal,const unsigned char *metasprite);
void __fastcall__ oam_meta_spr_clip(signed int x,unsigned char y,const unsigned char *metasprite);
#define PAD_A 0x01
#define PAD_B 0x02
#define PAD_SELECT 0x04
#define PAD_START 0x08
#define PAD_UP 0x10
#define PAD_DOWN 0x20
#define PAD_LEFT 0x40
#define PAD_RIGHT 0x80
#define OAM_FLIP_V 0x80
#define OAM_FLIP_H 0x40
#define OAM_BEHIND 0x20
#define MAX(x1,x2) ((x1)<(x2)?(x2):(x1))
#define MIN(x1,x2) ((x1)<(x2)?(x1):(x2))
#define MASK_SPR 0x10
#define MASK_BG 0x08
#define MASK_EDGE_SPR 0x04
#define MASK_EDGE_BG 0x02
#define NAMETABLE_A 0x2000
#define NAMETABLE_B 0x2400
#define NAMETABLE_C 0x2800
#define NAMETABLE_D 0x2c00
#define NULL 0
#define TRUE 1
#define FALSE 0
#define NT_UPD_HORZ 0x40
#define NT_UPD_VERT 0x80
#define NT_UPD_EOF 0xff
// macro to calculate nametable address from X,Y in compile time
#define NTADR_A(x,y) (NAMETABLE_A|(((y)<<5)|(x)))
#define NTADR_B(x,y) (NAMETABLE_B|(((y)<<5)|(x)))
#define NTADR_C(x,y) (NAMETABLE_C|(((y)<<5)|(x)))
#define NTADR_D(x,y) (NAMETABLE_D|(((y)<<5)|(x)))
// macro to get MSB and LSB
#define MSB(x) (((x)>>8))
#define LSB(x) (((x)&0xff))

View File

@ -3,7 +3,11 @@
#include "neslib.h"
// tileset data
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
const unsigned char TILESET[8*128] = {/*{w:8,h:8,bpp:1,count:128,brev:1}*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x7c,0x7c,0x7c,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x6c,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0xfe,0x6c,0xfe,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xfe,0xd0,0xfe,0x16,0xfe,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xce,0xdc,0x38,0x76,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x6c,0x7c,0xec,0xee,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x70,0x70,0x70,0x70,0x70,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x38,0x38,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x38,0x6c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0xfe,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0e,0x1e,0x3c,0x78,0xf0,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
@ -12,6 +16,8 @@ const unsigned char TILESET[8*128] = {/*{w:8,h:8,bpp:1,count:128,brev:1}*/
0x00,0xfc,0xee,0xee,0xee,0xfc,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xee,0xee,0xee,0xec,0x7e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfc,0xee,0xee,0xee,0xfc,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7c,0xe0,0x7c,0x0e,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x38,0x38,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xee,0xee,0xee,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xee,0x6c,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xfe,0xfe,0xee,0xc6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0x7c,0x38,0x7c,0xee,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xee,0xee,0xee,0x7c,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x1c,0x38,0x70,0xe0,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
#pragma data-name(pop)
//this macro is used remove need of calculation of the nametable address in runtime
#define NTADR(x,y) ((0x2000|((y)<<5)|x))
@ -32,7 +38,8 @@ void put_str(unsigned int adr,const char *str)
void main(void)
{
//copy tileset to RAM
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
//rendering is disabled at the startup, and palette is all black
pal_col(1,0x30);//set while color

View File

@ -4,6 +4,13 @@
#include "neslib.h"
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
#pragma data-name(pop)
//#link "tileset1.c"
// palette for balls, there are four sets for different ball colors
@ -35,7 +42,8 @@ static unsigned char ball_dy[BALLS_MAX];
void main(void)
{
//copy tileset to RAM
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
pal_spr(palSprites);//set palette for sprites
oam_size(1);
@ -69,7 +77,7 @@ void main(void)
while(1)
{
ppu_waitnmi();//wait for next TV frame
ppu_wait_nmi();//wait for next TV frame
spr=0;

View File

@ -2,8 +2,17 @@
//this example shows how to set up a palette and use 8x8 HW sprites
//also shows how fast (or slow) C code is
#include <string.h>
#include "neslib.h"
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
#pragma data-name(pop)
//#link "tileset1.c"
// tile set, two planes for 4 colors
@ -13,9 +22,6 @@ extern unsigned char TILESET[8*256];
//and how to use nametable update system that allows to modify nametable
//while rendering is enabled
#include "neslib.h"
//these macro are needed to simplify defining update list constants
#define NTADR(x,y) ((0x2000|((y)<<5)|x))
@ -35,27 +41,27 @@ static unsigned char list[6*3];
//init data for the update list, it contains MSB and LSB of a tile address
//in the nametable, then the tile number
const unsigned char list_init[6*3]={
MSB(NTADR(2,2)),LSB(NTADR(2,2)),0,
MSB(NTADR(3,2)),LSB(NTADR(3,2)),0,
MSB(NTADR(4,2)),LSB(NTADR(4,2)),0,
MSB(NTADR(6,2)),LSB(NTADR(6,2)),0,
MSB(NTADR(7,2)),LSB(NTADR(7,2)),0,
MSB(NTADR(8,2)),LSB(NTADR(8,2)),0
const unsigned char list_init[6*3+1]={
MSB(NTADR(2,2)),LSB(NTADR(2,2)),0,
MSB(NTADR(3,2)),LSB(NTADR(3,2)),0,
MSB(NTADR(4,2)),LSB(NTADR(4,2)),0,
MSB(NTADR(6,2)),LSB(NTADR(6,2)),0,
MSB(NTADR(7,2)),LSB(NTADR(7,2)),0,
MSB(NTADR(8,2)),LSB(NTADR(8,2)),0,
NT_UPD_EOF
};
void main(void)
{
//copy tileset to RAM
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
pal_col(1,0x21);//blue color for text
pal_col(17,0x30);//white color for sprite
memcpy(list,list_init,sizeof(list_init));
set_vram_update(6,list);
set_vram_update(list);
ppu_on_all();//enable rendering
@ -66,7 +72,7 @@ void main(void)
while(1)
{
ppu_waitnmi();//wait for next TV frame
ppu_wait_nmi();//wait for next TV frame
oam_spr(x,y,0x41,0,0);//put sprite

View File

@ -1,6 +1,13 @@
#include "neslib.h"
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
#pragma data-name(pop)
//#link "tileset1.c"
// tile set, two planes for 4 colors
@ -54,7 +61,8 @@ const unsigned char metaCat2[]={
void main(void)
{
//copy tileset to RAM
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
ppu_on_all();//enable rendering
@ -74,7 +82,7 @@ void main(void)
while(1)
{
ppu_waitnmi();//wait for next TV frame
ppu_wait_nmi();//wait for next TV frame
//flashing color for touch

View File

@ -4,6 +4,13 @@
#include "neslib.h"
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
#pragma data-name(pop)
const unsigned char test[308]={
0x01,0x00,0x01,0xa3,0x10,0x01,0x04,0x00,0x10,0x01,0x04,0x00,0x10,0x01,0x04,0x00,
0x10,0x01,0x04,0x00,0x01,0x0a,0x10,0x00,0x01,0x02,0x10,0x00,0x01,0x04,0x10,0x00,
@ -41,10 +48,12 @@ void main(void)
pal_bg(palette);//set background palette from an array
//copy tileset to RAM
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
//unpack nametable into the VRAM
unrle_vram(test,0x2000);
vram_adr(0x2000);
vram_unrle(test);
//enable rendering
ppu_on_all();

808
presets/nes/shoot2.c Normal file
View File

@ -0,0 +1,808 @@

#include <stdlib.h>
#include <string.h>
#include <nes.h>
#include <joystick.h>
#include "neslib.h"
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
#pragma data-name(pop)
#pragma static-locals (1);
#define COLS 32
#define ROWS 28
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
///
const char PALETTE[32] = {
0x0f,
0x11,0x24,0x3c, 0,
0x01,0x15,0x25, 0,
0x01,0x10,0x20, 0,
0x06,0x16,0x26, 0,
0x11,0x24,0x3c, 0,
0x01,0x15,0x25, 0,
0x31,0x35,0x3c, 0,
0x01,0x17,0x30
};
#define COLOR_PLAYER 3
#define COLOR_FORMATION 1
#define COLOR_ATTACKER 1
#define COLOR_MISSILE 3
#define COLOR_BOMB 2
#define COLOR_SCORE 2
#define COLOR_EXPLOSION 3
const char TILESET[128*8*2] = {/*{w:8,h:8,bpp:1,count:128,brev:1,np:2,pofs:8,remap:[0,1,2,4,5,6,7,8,9,10,11,12]}*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x7C,0x7C,0x7C,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x6C,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0x6C,0xFE,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xFE,0xD0,0xFE,0x16,0xFE,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCE,0xDC,0x38,0x76,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x6C,0x7C,0xEC,0xEE,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x70,0x70,0x70,0x70,0x70,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x38,0x38,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x38,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0xFE,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x1E,0x3C,0x78,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x7C,0xEE,0xEE,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x78,0x38,0x38,0x38,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x0E,0x7C,0xE0,0xEE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x0E,0x3C,0x0E,0x0E,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x7E,0xEE,0xEE,0xFE,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xE0,0xFC,0x0E,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xE0,0xFC,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xEE,0x1C,0x1C,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0x7C,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0xEE,0x7E,0x0E,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x38,0x70,0x70,0x38,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x1C,0x1C,0x38,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0x1C,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x7C,0xEE,0xEE,0xEE,0xE0,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0xEE,0xEE,0xFE,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xEE,0xFC,0xEE,0xEE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0xE0,0xE0,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0xEC,0xEE,0xEE,0xEE,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xE0,0xF0,0xE0,0xE0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xE0,0xF8,0xE0,0xE0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xE0,0xEE,0xEE,0xEE,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0xEE,0xFE,0xEE,0xEE,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x38,0x38,0x38,0x38,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x0E,0x0E,0x0E,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0xFC,0xF8,0xEC,0xEE,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0xE0,0xE0,0xE0,0xEE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xEE,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCE,0xEE,0xFE,0xFE,0xEE,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0xEE,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xFC,0xEE,0xEE,0xEE,0xFC,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0xEE,0xEE,0xEC,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xEE,0xEE,0xEE,0xFC,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xE0,0x7C,0x0E,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x38,0x38,0x38,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0x6C,0x38,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0xEE,0xFE,0xFE,0xEE,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0x7C,0x38,0x7C,0xEE,0xEE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0x7C,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x1C,0x38,0x70,0xE0,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// formation enemy (66)
0x0C,0x13,0x03,0x03,0x03,0x01,0x01,0x00,0x0C,0x10,0x01,0x0C,0x30,0x02,0x04,0x18,
0x18,0x64,0xE0,0xE0,0xE0,0xC0,0xC0,0x80,0x18,0x04,0x40,0x18,0x06,0x20,0x10,0x0C,
// attackers (68)
0x00,0x00,0x04,0x08,0x04,0x00,0x01,0x0C,0x00,0x00,0x04,0x08,0x04,0x03,0x03,0x03,
0x03,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x30,0x02,0x04,0x18,0x00,0x00,0x00,0x00,
0x00,0x00,0x10,0x08,0x10,0x60,0xE0,0xE0,0x00,0x00,0x10,0x08,0x10,0x00,0x40,0x18,
0xE0,0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x06,0x20,0x10,0x0C,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x04,0x04,0x03,0x03,0x03,0x00,0x00,0x02,0x04,0x04,0x20,0x11,0x0C,
0x03,0x07,0x03,0x03,0x02,0x00,0x00,0x00,0x00,0x20,0x1C,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x08,0x08,0x10,0xE0,0xE0,0x00,0x00,0x00,0x08,0x08,0x10,0x00,0x40,
0xE0,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x10,0x0C,0x02,0x20,0x10,0x0C,0x00,0x00,
0x00,0x00,0x0C,0x04,0x02,0x03,0x07,0x27,0x00,0x00,0x0C,0x04,0x00,0x00,0x01,0x20,
0x3F,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x32,0x00,0x04,0x08,0x10,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE0,0x00,0x00,0x00,0x20,0x40,0x84,0x08,0x10,
0xE0,0xF0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x07,0x03,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0x21,0x44,0x08,0x08,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0x00,0x00,0x20,0x40,0x80,0x98,0x20,0x00,
0xE0,0xFC,0xC4,0x80,0x80,0x80,0xC0,0x00,0x40,0x0C,0x04,0x00,0x00,0x80,0xC0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x04,0x02,0x11,0x08,0x04,
0x03,0x03,0x07,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x20,0x60,0xF0,0xFC,0x00,0x00,0x00,0x30,0x20,0x00,0x40,0x04,
0xFC,0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0x2C,0x00,0x20,0x18,0x80,0x40,0x60,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x07,0x00,0x00,0x00,0x10,0x10,0x08,0x04,0x00,
0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x00,0x00,
0x00,0x00,0x00,0x08,0x34,0xE0,0xE0,0xF0,0x00,0x80,0x80,0x88,0x94,0x00,0x40,0x00,
0xFA,0xE4,0x00,0x00,0x00,0x00,0x00,0x00,0x2A,0x04,0x80,0x40,0x20,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x07,0x00,0x00,0x01,0x09,0x08,0x04,0x02,0x00,
0x0F,0x07,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x04,0x08,0x09,0x01,0x00,
0x00,0x00,0x00,0x00,0x08,0x14,0xE0,0xE0,0x00,0x00,0x00,0x00,0x88,0x94,0x00,0x40,
0xC0,0xE0,0xE0,0x14,0x08,0x00,0x00,0x00,0x00,0x40,0x00,0x94,0x88,0x00,0x00,0x00,
0x01,0x01,0x01,0x00,0x00,0x01,0x11,0x11,0x01,0x01,0x02,0x07,0x01,0x21,0x21,0x2B,
0x11,0x16,0x1E,0x15,0x10,0x10,0x10,0x10,0x3F,0x3F,0x3F,0x3D,0x3B,0x3C,0x28,0x28,
0x40,0x40,0xC0,0x00,0x00,0x40,0x44,0x44,0xC0,0xC0,0x20,0xF0,0xC0,0xC2,0xC2,0xEA,
0x44,0x34,0x3C,0x54,0x04,0x04,0x04,0x04,0xFE,0xFE,0xFE,0xDE,0xEE,0x1E,0x0A,0x0A,
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x08,0x18,0x08,0x18,0x08,0x18,0x18,0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
// explosions
0x00,0x00,0x00,0x08,0x04,0x03,0x06,0x05,0x00,0x00,0x00,0x0C,0x06,0x04,0x00,0x18,
0x05,0x06,0x07,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x08,0x09,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x08,0x90,0xE0,0x90,0xD0,0x00,0x00,0x00,0x18,0x30,0x10,0x00,0x0C,
0xF0,0x20,0xE0,0x80,0x00,0x00,0x00,0x00,0x0C,0x10,0x18,0xC8,0x00,0x00,0x00,0x00,
0x00,0x04,0x12,0x0C,0x42,0x30,0x00,0x19,0x00,0x00,0x00,0x0A,0x00,0x06,0x08,0x00,
0x11,0x04,0x0C,0x00,0x21,0x46,0x00,0x00,0x04,0x10,0x02,0x0C,0x00,0x00,0x00,0x00,
0x00,0x40,0x08,0x91,0xA2,0x04,0x80,0xCC,0x00,0x00,0x00,0x20,0x00,0x30,0x08,0x00,
0xC4,0x10,0x1A,0x80,0x20,0x10,0x00,0x00,0x10,0x04,0xA0,0x98,0x80,0x00,0x00,0x00,
0x61,0x20,0x00,0x04,0x00,0xC4,0x08,0x10,0x00,0x00,0x04,0x06,0x09,0x02,0x10,0x14,
0x10,0x00,0x42,0xC8,0x80,0x00,0x10,0x30,0x34,0x10,0x11,0x02,0x00,0x00,0x00,0x00,
0x86,0xC4,0x00,0x10,0x01,0x10,0x08,0x04,0x00,0x00,0x10,0x30,0x48,0x20,0x04,0x14,
0x04,0x00,0x20,0x89,0x00,0x84,0xC6,0x43,0x16,0x04,0x44,0xA0,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x08,0x00,0x06,0x02,0x00,0x00,0x00,0x08,0x01,0x11,0x15,0x00,0x38,
0x30,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x10,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x20,0x08,0x00,0x30,0x20,0x00,0x00,0x00,0x08,0x40,0x44,0x54,0x00,0x0E,
0x06,0x20,0x80,0x80,0x00,0x00,0x00,0x00,0x0C,0x80,0x04,0x80,0x00,0x00,0x00,0x00,
};
#define CHAR(x) ((x)-' ')
#define BLANK 0
// VRAM UPDATE BUFFER
#define VBUFSIZE 64
byte updbuf[VBUFSIZE];
byte updptr = 0;
void cendbuf() {
updbuf[updptr] = NT_UPD_EOF;
}
void cflushnow() {
cendbuf();
ppu_wait_nmi();
flush_vram_update(updbuf);
updptr = 0;
cendbuf();
vram_adr(0x0);
}
void vdelay(byte count) {
while (count--) cflushnow();
}
void putchar(byte x, byte y, char ch) {
word addr = NTADR_A(x,y);
if (updptr >= VBUFSIZE-4) cflushnow();
updbuf[updptr++] = addr >> 8;
updbuf[updptr++] = addr & 0xff;
updbuf[updptr++] = ch;
cendbuf();
}
void putbytes(byte x, byte y, char* str, byte len) {
word addr = NTADR_A(x,y);
if (updptr >= VBUFSIZE-4-len) cflushnow();
updbuf[updptr++] = (addr >> 8) | NT_UPD_HORZ;
updbuf[updptr++] = addr & 0xff;
updbuf[updptr++] = len;
while (len--) {
updbuf[updptr++] = *str++;
}
cendbuf();
}
void putstring(byte x, byte y, char* str) {
putbytes(x, y, str, strlen(str));
}
void clrscr() {
updptr = 0;
cendbuf();
ppu_off();
vram_adr(0x2000);
vram_fill(BLANK, 32*28);
vram_adr(0x0);
ppu_on_all();
}
/////
char in_rect(byte x, byte y, byte x0, byte y0, byte w, byte h) {
return ((byte)(x-x0) < w && (byte)(y-y0) < h); // unsigned
}
void draw_bcd_word(byte col, byte row, word bcd) {
byte j;
static char buf[5];
buf[4] = CHAR('0');
for (j=3; j<0x80; j--) {
buf[j] = CHAR('0'+(bcd&0xf));
bcd >>= 4;
}
putbytes(col, row, buf, 5);
}
word bcd_add(word a, word b) {
word result = 0;
byte c = 0;
byte shift = 0;
while (shift < 16) {
byte d = (a & 0xf) + (b & 0xf) + c;
c = 0;
while (d >= 10) {
c++;
d -= 10;
}
result |= d << shift;
shift += 4;
a >>= 4;
b >>= 4;
}
return result;
}
// GAME CODE
#define NSPRITES 16
#define NMISSILES 8
#define YOFFSCREEN 239
#define SPRI_SHIP 96
#define SPRI_MISSILE 100
#define SPRI_BOMB 104
#define SPRI_EXPLODE 112
#define SPRI_ENEMY 68
#define SSRC_FORM1 66
#define SDST_FORM1 128
typedef struct {
byte shape;
} FormationEnemy;
// should be power of 2 length
typedef struct {
byte findex;
byte shape;
word x;
word y;
byte dir;
byte returning;
} AttackingEnemy;
typedef struct {
signed char dx;
byte xpos;
signed char dy;
byte ypos;
} Missile;
typedef struct {
byte name;
byte tag;
byte x;
byte y;
} Sprite;
#define ENEMIES_PER_ROW 8
#define ENEMY_ROWS 4
#define MAX_IN_FORMATION (ENEMIES_PER_ROW*ENEMY_ROWS)
#define MAX_ATTACKERS 6
FormationEnemy formation[MAX_IN_FORMATION];
AttackingEnemy attackers[MAX_ATTACKERS];
Missile missiles[NMISSILES];
Sprite vsprites[NSPRITES];
byte formation_offset_x;
signed char formation_direction;
byte current_row;
byte player_x;
const byte player_y = 190;
byte player_exploding;
byte enemy_exploding;
byte enemies_left;
word player_score;
byte framecount;
void copy_sprites() {
byte i;
byte oamid = 0;
for (i=0; i<NSPRITES; i++) {
Sprite* spr = &vsprites[i];
if (spr->y != YOFFSCREEN) {
byte y = spr->y;
byte x = spr->x;
byte chr = spr->name;
byte attr = spr->tag;
if (attr & 0x40) chr += 2; // horiz flip, swap tiles
oamid = oam_spr(x, y, chr, attr, oamid);
oamid = oam_spr(x+8, y, chr^2, attr, oamid);
}
}
// copy all "shadow missiles" to video memory
for (i=0; i<NMISSILES; i++) {
Missile* mis = &missiles[i];
if (mis->ypos != YOFFSCREEN) {
oamid = oam_spr(mis->xpos, mis->ypos, SPRI_MISSILE,
(i==7)?COLOR_MISSILE:COLOR_BOMB,
oamid);
}
}
oam_hide_rest(oamid);
}
void add_score(word bcd) {
player_score = bcd_add(player_score, bcd);
draw_bcd_word(1, 1, player_score);
}
void clrobjs() {
byte i;
memset(vsprites, 0, sizeof(vsprites));
for (i=0; i<NSPRITES; i++) {
vsprites[i].y = YOFFSCREEN;
}
for (i=0; i<NMISSILES; i++) {
missiles[i].ypos = YOFFSCREEN;
}
}
void setup_formation() {
byte i;
memset(formation, 0, sizeof(formation));
memset(attackers, 0, sizeof(attackers));
for (i=0; i<MAX_IN_FORMATION; i++) {
byte flagship = i < ENEMIES_PER_ROW;
formation[i].shape = flagship ? SDST_FORM1 : SDST_FORM1;
}
enemies_left = MAX_IN_FORMATION;
formation_offset_x = 8;
}
void draw_row(byte row) {
static char buf[32];
byte i;
byte x = formation_offset_x / 8;
byte xd = (formation_offset_x & 7) * 3;
byte y = 3 + row * 2;
for (i=0; i<x; i++)
buf[i] = BLANK;
for (i=0; i<ENEMIES_PER_ROW; i++) {
byte shape = formation[i + row*ENEMIES_PER_ROW].shape;
if (shape) {
shape += xd;
buf[x] = shape;
buf[x+1] = shape+1;
buf[x+2] = shape+2;
} else {
buf[x] = buf[x+1] = buf[x+2] = BLANK;
}
x += 3;
}
for (; x<COLS; x++)
buf[x] = BLANK;
putbytes(0, y, buf, sizeof(buf));
}
void draw_next_row() {
draw_row(current_row);
if (++current_row == ENEMY_ROWS) {
current_row = 0;
formation_offset_x += formation_direction;
if (formation_offset_x == 63) {
formation_direction = -1;
}
else if (formation_offset_x == 8) {
formation_direction = 1;
}
}
}
#define FLIPX 0x40
#define FLIPY 0x80
#define FLIPXY 0xc0
const byte DIR_TO_CODE[32] = {
0, 1, 2, 3, 4, 5, 6, 6,
6|FLIPXY, 6|FLIPXY, 5|FLIPXY, 4|FLIPXY, 3|FLIPXY, 2|FLIPXY, 1|FLIPXY, 0|FLIPXY,
0|FLIPX, 1|FLIPX, 2|FLIPX, 3|FLIPX, 4|FLIPX, 5|FLIPX, 6|FLIPX, 6|FLIPX,
6|FLIPY, 6|FLIPY, 5|FLIPY, 4|FLIPY, 3|FLIPY, 2|FLIPY, 1|FLIPY, 0|FLIPY,
};
const byte SINTBL[32] = {
0, 25, 49, 71, 90, 106, 117, 125,
127, 125, 117, 106, 90, 71, 49, 25,
0, -25, -49, -71, -90, -106, -117, -125,
-127, -125, -117, -106, -90, -71, -49, -25,
};
signed char isin(byte dir) {
return SINTBL[dir & 31];
}
signed char icos(byte dir) {
return isin(dir+8);
}
#define FORMATION_X0 0
#define FORMATION_Y0 19
#define FORMATION_XSPACE 24
#define FORMATION_YSPACE 16
byte get_attacker_x(byte formation_index) {
byte column = (formation_index % ENEMIES_PER_ROW);
return FORMATION_XSPACE*column + FORMATION_X0 + formation_offset_x;
}
byte get_attacker_y(byte formation_index) {
byte row = formation_index / ENEMIES_PER_ROW;
return FORMATION_YSPACE*row + FORMATION_Y0;
}
void draw_attacker(byte i) {
AttackingEnemy* a = &attackers[i];
if (a->findex) {
byte code = DIR_TO_CODE[(a->dir)&31];
vsprites[i].name = SPRI_ENEMY + (code&7)*4; // tile
vsprites[i].tag = code & 0xc0; // flip h/v
vsprites[i].x = a->x >> 8;
vsprites[i].y = a->y >> 8;
} else {
vsprites[i].y = YOFFSCREEN;
}
}
void draw_attackers() {
byte i;
for (i=0; i<MAX_ATTACKERS; i++) {
draw_attacker(i);
}
}
void return_attacker(AttackingEnemy* a) {
byte fi = a->findex-1;
byte destx = get_attacker_x(fi);
byte desty = get_attacker_y(fi);
byte ydist = desty - (a->y >> 8);
// are we close to our formation slot?
if (ydist == 0) {
// convert back to formation enemy
formation[fi].shape = a->shape;
a->findex = 0;
} else {
a->dir = (ydist + 16) & 31;
a->x = destx << 8;
a->y += 128;
}
}
void fly_attacker(AttackingEnemy* a) {
a->x += isin(a->dir) * 2;
a->y += icos(a->dir) * 2;
if ((a->y >> 8) == 0) {
a->returning = 1;
}
}
void move_attackers() {
byte i;
for (i=0; i<MAX_ATTACKERS; i++) {
AttackingEnemy* a = &attackers[i];
if (a->findex) {
if (a->returning)
return_attacker(a);
else
fly_attacker(a);
}
}
}
void think_attackers() {
byte i;
for (i=0; i<MAX_ATTACKERS; i++) {
AttackingEnemy* a = &attackers[i];
if (a->findex) {
// rotate?
byte x = a->x >> 8;
byte y = a->y >> 8;
// don't shoot missiles after player exploded
if (y < 112 || player_exploding) {
if (x < 128) {
a->dir++;
} else {
a->dir--;
}
} else {
// lower half of screen
// shoot a missile?
if (missiles[i].ypos == YOFFSCREEN) {
missiles[i].ypos = y+16;
missiles[i].xpos = x;
missiles[i].dy = 2;
}
}
}
}
}
void formation_to_attacker(byte formation_index) {
byte i;
// out of bounds? return
if (formation_index >= MAX_IN_FORMATION)
return;
// nobody in formation? return
if (!formation[formation_index].shape)
return;
// find an empty attacker slot
for (i=0; i<MAX_ATTACKERS; i++) {
AttackingEnemy* a = &attackers[i];
if (a->findex == 0) {
a->x = get_attacker_x(formation_index) << 8;
a->y = get_attacker_y(formation_index) << 8;
a->shape = formation[formation_index].shape;
a->findex = formation_index+1;
a->dir = 0;
a->returning = 0;
formation[formation_index].shape = 0;
break;
}
}
}
void draw_player() {
vsprites[7].x = player_x;
vsprites[7].y = player_y;
vsprites[7].name = SPRI_SHIP;
vsprites[7].tag = COLOR_PLAYER;
}
void move_player() {
byte joy = joy_read(JOY_1);
// move left/right?
if ((joy & JOY_LEFT_MASK) && player_x > 16) player_x--;
if ((joy & JOY_RIGHT_MASK) && player_x < 224) player_x++;
// shoot missile?
if ((joy & JOY_BTN_A_MASK) && missiles[7].ypos == YOFFSCREEN) {
missiles[7].ypos = player_y-8; // must be multiple of missile speed
missiles[7].xpos = player_x; // player X position
missiles[7].dy = -4; // player missile speed
}
vsprites[7].x = player_x;
}
void move_missiles() {
byte i;
for (i=0; i<8; i++) {
if (missiles[i].ypos != YOFFSCREEN) {
// hit the bottom or top?
if ((byte)(missiles[i].ypos += missiles[i].dy) > YOFFSCREEN) {
missiles[i].ypos = YOFFSCREEN;
}
}
}
}
void blowup_at(byte x, byte y) {
vsprites[6].tag = COLOR_EXPLOSION;
vsprites[6].name = SPRI_EXPLODE; // TODO
vsprites[6].x = x;
vsprites[6].y = y;
enemy_exploding = 1;
}
void animate_enemy_explosion() {
if (enemy_exploding) {
// animate next frame
if (enemy_exploding >= 8) {
enemy_exploding = 0; // hide explosion after 4 frames
vsprites[6].y = YOFFSCREEN;
} else {
vsprites[6].name = SPRI_EXPLODE + (enemy_exploding += 4); // TODO
}
}
}
void animate_player_explosion() {
byte z = player_exploding;
if (z <= 3) {
if (z == 3) {
vsprites[7].y = YOFFSCREEN;
} else {
vsprites[7].name = SPRI_EXPLODE + z*4;
}
}
}
void hide_player_missile() {
missiles[7].ypos = YOFFSCREEN;
}
void does_player_shoot_formation() {
byte mx = missiles[7].xpos + 8;
byte my = missiles[7].ypos;
signed char row = (my - FORMATION_Y0) / FORMATION_YSPACE;
if (row >= 0 && row < ENEMY_ROWS) {
// ok if unsigned (in fact, must be due to range)
byte xoffset = mx - FORMATION_X0 - formation_offset_x;
byte column = xoffset / FORMATION_XSPACE;
byte localx = xoffset - column * FORMATION_XSPACE;
if (column < ENEMIES_PER_ROW && localx < 16) {
char index = column + row * ENEMIES_PER_ROW;
if (formation[index].shape) {
formation[index].shape = 0;
enemies_left--;
blowup_at(get_attacker_x(index), get_attacker_y(index));
hide_player_missile();
add_score(2);
}
}
}
}
void does_player_shoot_attacker() {
byte mx = missiles[7].xpos + 8;
byte my = missiles[7].ypos;
byte i;
for (i=0; i<MAX_ATTACKERS; i++) {
AttackingEnemy* a = &attackers[i];
if (a->findex && in_rect(mx, my, a->x >> 8, a->y >> 8, 16, 16)) {
blowup_at(a->x >> 8, a->y >> 8);
a->findex = 0;
enemies_left--;
hide_player_missile();
add_score(5);
break;
}
}
}
void does_missile_hit_player() {
byte i;
if (player_exploding)
return;
for (i=0; i<MAX_ATTACKERS; i++) {
if (missiles[i].ypos != YOFFSCREEN &&
in_rect(missiles[i].xpos + 8, missiles[i].ypos + 16,
player_x, player_y, 16, 16)) {
player_exploding = 1;
break;
}
}
}
void new_attack_wave() {
byte i = rand();
byte j;
// find a random slot that has an enemy
for (j=0; j<MAX_IN_FORMATION; j++) {
i = (i+1) & (MAX_IN_FORMATION-1);
// anyone there?
if (formation[i].shape) {
formation_to_attacker(i);
formation_to_attacker(i+1);
formation_to_attacker(i+ENEMIES_PER_ROW);
formation_to_attacker(i+ENEMIES_PER_ROW+1);
break;
}
}
}
void new_player_ship() {
player_exploding = 0;
player_x = 120;
draw_player();
}
void set_sounds() {
/*
byte i;
// missile fire sound
if (missiles[7].ypos != YOFFSCREEN) {
cv_set_frequency(CV_SOUNDCHANNEL_0, 2000-missiles[7].ypos*4);
cv_set_attenuation(CV_SOUNDCHANNEL_0, 18);
} else {
cv_set_attenuation(CV_SOUNDCHANNEL_0, 32);
}
// enemy explosion sound
if (enemy_exploding) {
cv_set_frequency(CV_SOUNDCHANNEL_1, 500+enemy_exploding*64);
cv_set_attenuation(CV_SOUNDCHANNEL_1, 14);
} else {
cv_set_attenuation(CV_SOUNDCHANNEL_1, 32);
}
cv_set_attenuation(CV_SOUNDCHANNEL_2, 32);
// player explosion
if (player_exploding && player_exploding < 15) {
cv_set_frequency(CV_SOUNDCHANNEL_2, player_exploding*256);
cv_set_attenuation(CV_SOUNDCHANNEL_NOISE, 4+player_exploding);
cv_set_noise(true, 3);
} else {
// set diving sounds for spaceships
cv_set_attenuation(CV_SOUNDCHANNEL_NOISE, 32);
for (i=0; i<3; i++) {
byte y = attackers[i].y >> 8;
if (y >= 0x80) {
cv_set_frequency(CV_SOUNDCHANNEL_2, 4000+y*8);
cv_set_attenuation(CV_SOUNDCHANNEL_2, 28);
break;
}
}
}
*/
}
void wait_for_frame() {
ppu_wait_nmi();
}
void play_round() {
byte end_timer = 255;
player_score = 0;
add_score(0);
putstring(0, 0, "PLAYER 1");
setup_formation();
clrobjs();
formation_direction = 1;
framecount = 0;
new_player_ship();
while (end_timer) {
if (player_exploding) {
if ((framecount & 7) == 1) {
animate_player_explosion();
if (++player_exploding > 32 && enemies_left) {
new_player_ship();
}
}
} else {
if ((framecount & 0x7f) == 0 || enemies_left < 8) {
new_attack_wave();
}
move_player();
does_missile_hit_player();
}
if ((framecount & 3) == 2) animate_enemy_explosion();
move_attackers();
move_missiles();
if (framecount & 1)
does_player_shoot_formation();
else
does_player_shoot_attacker();
draw_next_row();
draw_attackers();
if ((framecount & 0xf) == 0) think_attackers();
set_sounds();
framecount++;
if (!enemies_left) end_timer--;
cflushnow();
copy_sprites();
}
}
void set_shifted_pattern(const byte* src, word dest, byte shift) {
static byte buf[16*3];
byte y;
for (y=0; y<16; y++) {
byte a = src[y];
byte b = src[y+16];
buf[y] = a>>shift;
buf[y+16] = b>>shift | a<<(8-shift);
buf[y+32] = b<<(8-shift);
}
vram_adr(dest);
vram_write(buf, sizeof(buf));
}
void setup_tileset() {
byte i;
word src;
word dest;
// copy background
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
// copy sprites
vram_adr(0x1000);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
// write shifted versions of formation ships
src = SSRC_FORM1*16;
dest = SDST_FORM1*16;
for (i=0; i<8; i++) {
set_shifted_pattern(&TILESET[src], dest, i);
dest += 3*16;
}
}
void main() {
joy_install (joy_static_stddrv);
setup_tileset();
pal_all(PALETTE);
oam_clear();
oam_size(1); // 8x16 sprites
clrscr();
play_round();
main();
}

View File

@ -1,21 +1,28 @@
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <nes.h>
#include <joystick.h>
#include "neslib.h"
#pragma bss-name (push,"ZEROPAGE")
unsigned char oam_off;
#pragma bss-name (pop)
#pragma data-name (push,"CHARS")
#pragma data-name(pop)
//#link "tileset1.c"
extern unsigned char palSprites[16];
extern unsigned char TILESET[8*256];
#define COLS 32
#define ROWS 28
#define NTADR(x,y) ((0x2000|((y)<<5)|(x)))
typedef unsigned char byte;
typedef signed char sbyte;
typedef unsigned short word;
@ -27,25 +34,68 @@ typedef unsigned short word;
// back to the start of the frame.
byte getchar(byte x, byte y) {
// compute VRAM read address
word addr = 0x2020+x+y*32;
word addr = NTADR(x,y);
byte rd;
// wait for VBLANK to start
waitvsync();
// set VRAM read address in PPU
PPU.vram.address = addr>>8;
PPU.vram.address = addr&0xff;
// read the char from PPUDATA
rd = PPU.vram.data; // discard
rd = PPU.vram.data; // keep this one
// reset the VRAM address to start of frame
PPU.vram.address = 0x00;
PPU.vram.address = 0x00;
// return result
return rd;
vram_adr(addr);
vram_read(&rd, 1);
vram_adr(0x0);
return rd + 0x20;
}
// VRAM UPDATE BUFFER
byte updbuf[64];
byte updptr = 0;
void cendbuf() {
updbuf[updptr] = NT_UPD_EOF;
}
void cflushnow() {
cendbuf();
waitvsync();
flush_vram_update(updbuf);
updptr = 0;
cendbuf();
vram_adr(0x0);
}
void vdelay(byte count) {
while (count--) waitvsync();
while (count--) cflushnow();
}
void cputcxy(byte x, byte y, char ch) {
word addr = NTADR(x,y);
if (updptr >= 60) cflushnow();
updbuf[updptr++] = addr >> 8;
updbuf[updptr++] = addr & 0xff;
updbuf[updptr++] = ch - 0x20;
cendbuf();
}
void cputsxy(byte x, byte y, char* str) {
word addr = NTADR(x,y);
byte len = strlen(str);
if (updptr >= 60 - len) cflushnow();
updbuf[updptr++] = (addr >> 8) | NT_UPD_HORZ;
updbuf[updptr++] = addr & 0xff;
updbuf[updptr++] = len;
while (len--) {
updbuf[updptr++] = *str++ - 0x20;
}
cendbuf();
}
void clrscr() {
updptr = 0;
cendbuf();
ppu_off();
vram_adr(0x2000);
vram_fill(0, 32*28);
vram_adr(0x0);
ppu_on_bg();
}
////////// GAME DATA
@ -63,7 +113,8 @@ typedef struct {
Player players[2];
byte credits = 0;
byte attract;
byte gameover;
byte frames_per_move;
#define START_SPEED 12
@ -72,7 +123,7 @@ byte frames_per_move;
///////////
const char BOX_CHARS[8] = { 17, 8, 20, 18, 11, 11, 14, 14 };
const char BOX_CHARS[8] = { '+','+','+','+','-','-','!','!' };
void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) {
byte x1 = x;
@ -91,11 +142,15 @@ void draw_box(byte x, byte y, byte x2, byte y2, const char* chars) {
}
void draw_playfield() {
draw_box(0,1,COLS-1,ROWS-1,BOX_CHARS);
cputsxy(0,0,"Plyr1:");
cputsxy(20,0,"Plyr2:");
cputcxy(7,0,players[0].score+'0');
cputcxy(27,0,players[1].score+'0');
draw_box(1,2,COLS-2,ROWS-1,BOX_CHARS);
cputcxy(9,1,players[0].score+'0');
cputcxy(28,1,players[1].score+'0');
if (attract) {
cputsxy(5,ROWS-1,"ATTRACT MODE - PRESS 1");
} else {
cputsxy(1,1,"PLYR1:");
cputsxy(20,1,"PLYR2:");
}
}
typedef enum { D_RIGHT, D_DOWN, D_LEFT, D_UP } dir_t;
@ -106,8 +161,8 @@ void init_game() {
memset(players, 0, sizeof(players));
players[0].head_attr = '1';
players[1].head_attr = '2';
players[0].tail_attr = 1;
players[1].tail_attr = 9;
players[0].tail_attr = '#';
players[1].tail_attr = '*';
frames_per_move = START_SPEED;
}
@ -136,8 +191,12 @@ void move_player(Player* p) {
void human_control(Player* p) {
byte dir = 0xff;
byte joy;
if (!p->human) return;
joy = joy_read (JOY_1);
// start game if attract mode
if (attract && (joy & JOY_START_MASK))
gameover = 1;
// do not allow movement unless human player
if (!p->human) return;
if (joy & JOY_LEFT_MASK) dir = D_LEFT;
if (joy & JOY_RIGHT_MASK) dir = D_RIGHT;
if (joy & JOY_UP_MASK) dir = D_UP;
@ -175,8 +234,6 @@ void ai_control(Player* p) {
}
}
byte gameover;
void flash_colliders() {
byte i;
// flash players that collided
@ -219,13 +276,13 @@ void declare_winner(byte winner) {
gameover = 1;
}
#define AE(a,b,c,d) (((a)<<0)|((b)<<2)|((c)<<4)|((d)<<6))
#define AE(tl,tr,bl,br) (((tl)<<0)|((tr)<<2)|((bl)<<4)|((br)<<6))
// this is attribute table data,
// each 2 bits defines a color palette
// for a 16x16 box
const unsigned char Attrib_Table[0x40]={
AE(3,3,1,1),AE(3,3,1,1),AE(3,3,1,1),AE(3,3,1,1), AE(2,2,1,1),AE(2,2,1,1),AE(2,2,1,1),AE(2,2,1,1),
AE(3,3,1,0),AE(3,3,0,0),AE(3,3,0,0),AE(3,3,0,0), AE(2,2,0,0),AE(2,2,0,0),AE(2,2,0,0),AE(2,2,0,1),
AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,1,0,1),
AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,1,0,1),
AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,1,0,1),
@ -235,24 +292,37 @@ AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,
AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1), AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),
};
// this is palette data
const unsigned char Palette_Table[16]={
0x02,
0x31,0x31,0x31,0x00,
0x34,0x34,0x34,0x00,
0x39,0x39,0x39,0x00,
};
// put 8x8 grid of palette entries into the PPU
void setup_attrib_table() {
byte index;
waitvsync(); // wait for VBLANK
PPU.vram.address = 0x23;
PPU.vram.address = 0xc0;
for( index = 0; index < 0x40; ++index ){
PPU.vram.data = Attrib_Table[index];
}
vram_adr(0x23c0);
vram_write(Attrib_Table, 0x40);
}
void setup_palette() {
int i;
// only set palette entries 0-15 (background only)
for (i=0; i<15; i++)
pal_col(i, Palette_Table[i] ^ attract);
}
void play_round() {
reset_players();
clrscr();
ppu_off();
setup_attrib_table();
setup_palette();
clrscr();
draw_playfield();
reset_players();
while (1) {
make_move();
if (gameover) return; // attract mode -> start
if (players[0].collided || players[1].collided) break;
}
flash_colliders();
@ -273,14 +343,21 @@ void play_round() {
void play_game() {
gameover = 0;
init_game();
players[0].human = 1;
if (!attract)
players[0].human = 1;
while (!gameover) {
play_round();
}
}
void main() {
vram_write((unsigned char*)TILESET, 0x0, sizeof(TILESET));
vram_adr(0x0);
vram_write((unsigned char*)TILESET, sizeof(TILESET));
joy_install (joy_static_stddrv);
play_game();
while (1) {
attract = 1;
play_game();
attract = 0;
play_game();
}
}

46
presets/nes/skeleton.dasm Normal file
View File

@ -0,0 +1,46 @@
include "nesdefs.asm"
;;;;; VARIABLES
seg.u RAM
org $0
;;;;; NES CARTRIDGE HEADER
NES_HEADER 0,2,1,0 ; mapper 0, 2 PRGs, 1 CHR, vertical
;;;;; START OF CODE
Start:
NES_INIT ; set up stack pointer, turn off PPU
jsr WaitSync ; wait for VSYNC
jsr ClearRAM ; clear RAM
jsr WaitSync ; wait for VSYNC (and PPU warmup)
lda #$3f ; $3F -> A register
ldy #$00 ; $00 -> Y register
sta PPU_ADDR ; write high byte first
sty PPU_ADDR ; $3F00 -> PPU address
lda #$1c ; $1C = light blue color
sta PPU_DATA ; $1C -> PPU data
lda #CTRL_NMI
sta PPU_CTRL ; enable NMI
lda #MASK_COLOR
sta PPU_MASK ; enable rendering
.endless
jmp .endless ; endless loop
;;;;; COMMON SUBROUTINES
include "nesppu.asm"
;;;;; INTERRUPT HANDLERS
NMIHandler:
rti
;;;;; CPU VECTORS
NES_VECTORS

135
presets/vicdual/asmtest.s Normal file
View File

@ -0,0 +1,135 @@
.area _HOME
.area _CODE
.area _INITIALIZER
.area _DATA
.area _INITIALIZED
.area _BSEG
.area _BSS
.area _HEAP
;--------------------------------------------------------
; File Created by SDCC : free open source ANSI-C Compiler
; Version 3.6.5 # (UNIX)
;--------------------------------------------------------
.module minimal
.optsdcc -mz80
;--------------------------------------------------------
; Public variables in this module
;--------------------------------------------------------
.globl _start
.globl _tileram
.globl _cellram
.globl _main
;--------------------------------------------------------
; special function registers
;--------------------------------------------------------
_palette = 0x0040
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
.area _DATA
_cellram = 0xe000
_tileram = 0xe800
;--------------------------------------------------------
; ram data
;--------------------------------------------------------
.area _INITIALIZED
;--------------------------------------------------------
; absolute external ram data
;--------------------------------------------------------
.area _DABS (ABS)
;--------------------------------------------------------
; global & static initialisations
;--------------------------------------------------------
.area _HOME
.area _GSINIT
.area _GSFINAL
.area _GSINIT
;--------------------------------------------------------
; Home
;--------------------------------------------------------
.area _HOME
.area _HOME
;--------------------------------------------------------
; code
;--------------------------------------------------------
.area _CODE
;<stdin>:15:
; ---------------------------------
; Function start
; ---------------------------------
_start::
;<stdin>:19:
LD SP,#0xE800 ; set up stack pointer
DI ; disable interrupts
;<stdin>:20:
jp _main
;<stdin>:23:
; ---------------------------------
; Function main
; ---------------------------------
_main::
;<stdin>:26:
ld a,#0x01
out (_palette),a
;<stdin>:27:
ld hl,#_tileram
ld (hl), #0xfe
ld e, l
ld d, h
inc de
ld bc, #0x07ff
ldir
;<stdin>:28:
ld hl,#_cellram
ld (hl), #0x00
ld e, l
ld d, h
inc de
ld bc, #0x07ff
ldir
;<stdin>:29:
ld c,#0x00
;<stdin>:30:
00112$:
ld a,c
rlca
rlca
rlca
and a,#0xf8
ld e,a
ld d,#0x00
00106$:
;<stdin>:31:
ld l,d
ld h,#0x00
add hl, hl
add hl, hl
add hl, hl
add hl, hl
add hl, hl
ld a,#<(_cellram)
add a, l
ld l,a
ld a,#>(_cellram)
adc a, h
ld h,a
ld b,#0x00
add hl, bc
ld (hl),e
;<stdin>:30:
inc d
ld a,d
sub a, #0x20
jr C,00106$
;<stdin>:29:
inc c
ld a,c
sub a, #0x20
jr C,00112$
;<stdin>:34:
00104$:
jr 00104$
.area _CODE
.area _INITIALIZER
.area _CABS (ABS)

View File

@ -332,6 +332,7 @@ function convertBytesToImages(bytes, fmt) {
}
function convertImagesToBytes(images, fmt) {
if (fmt.destfmt) fmt = fmt.destfmt;
var width = fmt.w;
var height = fmt.h;
var count = fmt.count || 1;

View File

@ -12,6 +12,7 @@ var JSNES_PRESETS = [
{id:'neslib4.c', name:'Metasprites'},
{id:'neslib5.c', name:'RLE Unpack'},
{id:'siegegame.c', name:'Siege Game'},
{id:'shoot2.c', name:'Solarian Game'},
];
var NES_NESLIB_PRESETS = [

View File

@ -92,9 +92,10 @@ export class CodeProject {
var linkfiles = this.parseLinkDependencies(text);
var allfiles = includes.concat(linkfiles);
this.loadFiles(allfiles, (err:string, result?:Dependency[]) => {
// set 'link' property on files that are link dependencies (must match filename)
if (result)
for (var dep of result)
dep.link = linkfiles.indexOf(dep.filename) >= 0;
dep.link = linkfiles.indexOf(dep.filename) >= 0 || linkfiles.indexOf('local/'+dep.filename) >= 0; //TODO!!!
callback(err, result);
});
}

View File

@ -184,6 +184,7 @@ export class SourceEditor implements ProjectView {
var insnstr = info.insns.length > 9 ? ("...") : info.insns;
this.setGutter("gutter-bytes", info.line-1, insnstr);
if (info.iscode) {
// TODO: labels trick this part?
var opcode = parseInt(info.insns.split(" ")[0], 16);
if (platform.getOpcodeMetadata) {
var meta = platform.getOpcodeMetadata(opcode, info.offset);
@ -415,7 +416,18 @@ export class DisassemblerView implements ProjectView {
bytes += hex(platform.readAddress(a+i));
while (bytes.length < 14)
bytes += ' ';
var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + disasm.line + "\n";
var dstr = disasm.line;
if (addr2symbol) {
dstr = dstr.replace(/([^#])[$]([0-9A-F]+)/, (substr:string, ...args:any[]):string => {
var addr = parseInt(args[1], 16);
var sym = addr2symbol[addr];
if (sym) return (args[0] + sym);
sym = addr2symbol[addr+1];
if (sym) return (args[0] + sym + "+1");
return substr;
});
}
var dline = hex(parseInt(a)) + "\t" + bytes + "\t" + dstr + "\n";
s += dline;
if (a == pc) selline = curline;
curline++;

BIN
src/worker/lib/nes/crt0.o Normal file

Binary file not shown.

View File

@ -105,7 +105,13 @@ var PLATFORM_PARAMS = {
'nes': { //TODO
define: '__NES__',
cfgfile: 'neslib.cfg',
libargs: ['neslib.lib', 'nes.lib'],
libargs: ['crt0.o', 'nes.lib',
'-D', 'NES_MAPPER=0',
'-D', 'NES_PRG_BANKS=2',
'-D', 'NES_CHR_BANKS=0', // TODO: >0 doesn't seem to work
'-D', 'NES_MIRRORING=0',
],
extrafiles: ['crt0.o'],
},
'nes-conio': {
cfgfile: 'nes.cfg',
@ -247,6 +253,28 @@ function populateFiles(step, fs, options) {
}
}
function populateExtraFiles(step, fs) {
// TODO: cache extra files
var extrafiles = step.params.extrafiles;
if (extrafiles) {
for (var i=0; i<extrafiles.length; i++) {
var xfn = extrafiles[i];
var xpath = "lib/" + step.platform + "/" + xfn;
var xhr = new XMLHttpRequest();
xhr.responseType = 'arraybuffer';
xhr.open("GET", xpath, false); // synchronous request
xhr.send(null);
if (xhr.response && xhr.status == 200) {
var data = new Uint8Array(xhr.response);
fs.writeFile(xfn, data, {encoding:'binary'});
console.log(":::",xfn);
} else {
throw Error("Could not load extra file " + xpath);
}
}
}
}
function staleFiles(step, targets) {
if (!step.maxts) throw "call populateFiles() first";
// see if any target files are more recent than inputs
@ -698,6 +726,7 @@ function linkLD65(step) {
var cfgfile = '/' + platform + '.cfg';
setupFS(FS, '65-'+platform.split('-')[0]);
populateFiles(step, FS);
populateExtraFiles(step, FS);
var libargs = params.libargs;
var args = ['--cfg-path', '/share/cfg',
'--lib-path', '/share/lib',