6 Commits

Author SHA1 Message Date
376c15c272 v0.5.4
[FEAT] Border
[FEAT] Color accepts a third optional parameter for border
2021-12-10 19:32:05 +01:00
f21f199917 [FEAT] Brackets enabled in console 2021-12-10 19:26:46 +01:00
12383f9309 [FEAT] Pong & Breakout included 2021-12-10 08:18:02 +01:00
d101da4a43 [BUG] volume, octave & tempo not reseting 2021-12-09 17:12:32 +01:00
d811790f66 [BUG] Versión not updated 2021-12-08 13:15:42 +01:00
77f31587f6 v0.5.2:
[FEAT] play(str)
[FEAT] Chime on boot
[FEAT] simple song example on 'game.lua'
2021-12-08 12:39:15 +01:00
9 changed files with 391 additions and 31 deletions

View File

@@ -3,9 +3,14 @@
#include <string.h>
#include "lua.h"
#include "rom.c"
#include "play.h"
#define swap(a, b) {auto tmp=a;a=b;b=tmp;}
#define AUDIO_NONE 0
#define AUDIO_SOUND 1
#define AUDIO_PLAY 2
char lua_filename[1024];
char window_title[256];
uint8_t mem[8192]; //2400
@@ -14,10 +19,11 @@ uint8_t *color_screen = NULL;
uint8_t screen_width = 40;
uint8_t screen_height = 30;
uint8_t current_color = 0x1e;
uint8_t current_border = 0;
uint8_t current_mode = 1;
uint8_t cursor_x = 0;
uint8_t cursor_y = 0;
bool sounding = false;
uint8_t audio_state = AUDIO_NONE;
int audio_freq = 0;
uint32_t audio_len = 0;
@@ -60,6 +66,7 @@ void reinit() {
screen_width = 80;
screen_height = 30;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
@@ -71,6 +78,7 @@ void reinit() {
screen_width = 40;
screen_height = 30;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
@@ -82,6 +90,7 @@ void reinit() {
screen_width = 20;
screen_height = 15;
current_color = 0x07;
current_border = 0;
cursor_x = 0;
cursor_y = 0;
char_screen = &mem[0];
@@ -92,16 +101,41 @@ void reinit() {
}
}
static Uint8* play_pos;
static Uint32 play_len;
static Uint8 play_buffer[132300];
void audioCallback(void * userdata, uint8_t * stream, int len) {
//if (audio_len <= 0) nosound();
static int period=0;
static int v = 16;
SDL_memset(stream, 0, len);
const int flen = min(audio_len, len);
audio_len -= flen;
for (int i=0; i<flen; ++i) {
stream[i] = v;
period++; if (period>=audio_freq) {period = 0; v=-v;}
if (audio_state == AUDIO_SOUND) {
if (audio_len <= 0) audio_state = AUDIO_NONE;
static int period=0;
static int v = 16;
SDL_memset(stream, 0, len);
const int flen = min(audio_len, len);
audio_len -= flen;
for (int i=0; i<flen; ++i) {
stream[i] = v;
period++; if (period>=audio_freq) {period = 0; v=-v;}
}
} else if (audio_state == AUDIO_PLAY) {
while( len > 0 ) {
while( play_len == 0 ) {
play_len = interpret_next_token(play_buffer);
if (play_len == -1) { audio_state=AUDIO_NONE; SDL_memset( stream, 0, len ); return; }
play_pos = play_buffer;
}
const int actual_len = ( len > play_len ? play_len : len );
//SDL_memset( stream, 0, actual_len );
//SDL_MixAudio( stream, audio_pos, actual_len, SDL_MIX_MAXVOLUME );
SDL_memcpy(stream, play_pos, actual_len);
stream += actual_len;
play_pos += actual_len;
play_len -= actual_len;
len -= actual_len;
}
} else {
SDL_memset(stream, 0, len);
}
}
@@ -126,7 +160,7 @@ int main(int argc,char*argv[]) {
bool exit = false;
SDL_Event mini_eve;
SDL_AudioSpec audioSpec = {44100, AUDIO_S8, 1, 0, 512, 0, 0, audioCallback, NULL};
SDL_AudioSpec audioSpec = {22050, AUDIO_S8, 1, 0, 512, 0, 0, audioCallback, NULL};
mini_audio_device = SDL_OpenAudioDevice(NULL, 0, &audioSpec, NULL, 0);
SDL_PauseAudioDevice(mini_audio_device, 0);
@@ -238,7 +272,7 @@ int main(int argc,char*argv[]) {
//for (int i=0;i<screen_surface->size;++i) pixels[i] = palette[screen_surface->p[i]];
SDL_UnlockTexture(mini_bak);
SDL_SetRenderDrawColor(mini_ren, (palette[0] >> 16)&0xff, (palette[0] >> 8)&0xff, palette[0]&0xff, 0);
SDL_SetRenderDrawColor(mini_ren, (palette[current_border] >> 16)&0xff, (palette[current_border] >> 8)&0xff, palette[current_border]&0xff, 0);
//SDL_SetRenderDrawColor(mini_ren, 255, 0, 0, 0);
SDL_RenderClear(mini_ren);
SDL_Rect rect = {40, 40, 640, 480};
@@ -270,8 +304,13 @@ void paper(uint8_t value) {
current_color = (current_color & 0x0f) + (value << 4);
}
void color(uint8_t ink, uint8_t paper) {
void border(uint8_t value) {
current_border = value & 0xf;
}
void color(uint8_t ink, uint8_t paper, int8_t border) {
current_color = (ink & 0x0f) + (paper << 4);
if (border >= 0) current_border = border & 0xf;
}
void locate(uint8_t x, uint8_t y) {
@@ -480,14 +519,21 @@ void memcpy(uint16_t dst, uint16_t src, uint16_t size) {
void sound(float freq, uint32_t len) {
// [TODO]
audio_len = len*44.1f;
audio_freq = 44100.0f/freq/2.0f;
sounding = true;
audio_freq = 22050.0f/freq/2.0f;
audio_state = AUDIO_SOUND;
}
void nosound() {
//SDL_PauseAudioDevice(mini_audio_device, 1);
audio_len = 0;
sounding = false;
audio_state = AUDIO_NONE;
}
void play(const char* str) {
play_pos = play_buffer;
play_len = 0;
play_init(str);
audio_state = AUDIO_PLAY;
}
void setmode(const uint8_t mode) {

View File

@@ -115,7 +115,8 @@ void loop();
void cls(uint8_t value=32);
void ink(uint8_t value); // global::ink
void paper(uint8_t value); // global::paper
void color(uint8_t ink, uint8_t paper);
void border(uint8_t value);
void color(uint8_t ink, uint8_t paper, int8_t border=-1);
void locate(uint8_t x, uint8_t y); // global::cursorx, global::cursory
void print(const char *str, int x = -1, int y = -1);
@@ -170,8 +171,9 @@ void memcpy(uint16_t dst, uint16_t src, uint16_t size);
void sound(float freq, uint32_t len);
void nosound();
void setmode(const uint8_t mode);
void play(const char* str);
void setmode(const uint8_t mode);
void load(const char* str);
void fileout(const char* str, uint16_t addr, uint16_t size);

94
breakout.lua Normal file
View File

@@ -0,0 +1,94 @@
function init()
setmode(1)
reset()
end
function reset()
bx,by=20,28
dx,dy=-1+rnd(1)*2,-1
px=18
wait=1
speed=6
bricks = {}
for i=0,35 do bricks[i]=COLOR_RED end
for i=36,71 do bricks[i]=COLOR_BROWN end
for i=72,107 do bricks[i]=COLOR_GREEN end
for i=108,143 do bricks[i]=COLOR_YELLOW end
end
function update()
-- move ball
wait=wait-1
if wait==0 then
wait=speed
bx=bx+dx
by=by+dy
if speed<6 then
if bx==2 or bx==37 then dx=-dx play("o3l0c") end
if by<9 then
local index=flr(bx/2)-1+(by-1)*18
if bricks[index]~=COLOR_BLACK then
play("o5l0c")
bricks[index]=COLOR_BLACK
dy=-dy
else
if by==1 then dy=-dy play("o3l0c") end
end
end
if by==28 and bx>=px and bx<=px+4 then
play("o4l0c")
dy=-dy
end
if by==29 then
play("l0o3bagfedc")
reset()
end
else
if bx==2 or bx==37 then dx=-dx end
if by==9 or by==29 then dy=-dy end
end
end
-- move paddle
if btn(KEY_LEFT) and px>2 then px=px-1 end
if btn(KEY_RIGHT) and px<34 then px=px+1 end
-- clear screen
paper(COLOR_BLACK)
cls()
-- draw white border
ink(COLOR_WHITE)
print("\150\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\154\156",1,0)
for i=1,29 do
print("\149",1,i)
print("\149",38,i)
end
-- draw bricks
for i=0,143 do
color(0,bricks[i])
print("\095\003",2+2*(i%18),1+flr(i/18))
end
--draw ball
color(COLOR_WHITE,COLOR_BLACK)
print("\233",bx,by)
-- draw paddle
ink(COLOR_LIGHT_BLUE)
for i=0,3 do print("\131",px+i,29) end
if speed==6 then
ink(rnd(16))
print("BREAKOUT",16,13)
ink(COLOR_WHITE)
print("Press '1' to play EASY",9,18)
print("Press '2' to play NORMAL",8,20)
print("Press '3' to play HARD",9,22)
if btn(KEY_1) then reset() speed=4 end
if btn(KEY_2) then reset() speed=3 end
if btn(KEY_3) then reset() speed=2 end
end
end

View File

@@ -1,17 +1,9 @@
function init()
setmode(0)
cls()
play("o4v5l1crcl4dcferl1crcl4dcgfr")
end
function update()
cls()
locate(0,0)
if mousebutton(1) then
print("Has pulsat el boto esquerre")
elseif mousebutton(2) then
print("Has pulsat el boto del mig")
elseif mousebutton(3) then
print("Has pulsat el boto dret")
else
print("No has pulsat cap boto")
end
end

23
lua.cpp
View File

@@ -21,10 +21,21 @@ extern "C" {
return 0;
}
static int cpp_border(lua_State *L) {
uint8_t val = luaL_checkinteger(L, 1);
border(val);
return 0;
}
static int cpp_color(lua_State *L) {
uint8_t ink = luaL_checkinteger(L, 1);
uint8_t paper = luaL_checkinteger(L, 2);
color(ink, paper);
if (lua_gettop(L) > 2) {
uint8_t border = luaL_checkinteger(L, 3);
color(ink, paper, border);
} else {
color(ink, paper);
}
return 0;
}
@@ -220,6 +231,12 @@ extern "C" {
return 0;
}
static int cpp_play(lua_State *L) {
const char* str = luaL_optstring(L, 1, NULL);
play(str);
return 0;
}
static int cpp_setmode(lua_State *L) {
int val = luaL_checkinteger(L, 1);
setmode(val);
@@ -268,7 +285,7 @@ bool lua_is_playing() {
return lua_state == STATE_PLAYING;
}
const char boot[] = "function init()setmode(1)cls()memcpy(360,4608,240)memcpy(1560,4848,240)ink(1)print('G A M E',8,16)ink(4)print('S Y S T E M',20,16)ink(8)print('v0.5.1',26,8)w=0 end function update()w=w+1 if w>90 then cls()load()end end";
const char boot[] = "function init()setmode(1)cls()play('o5l0v5cegv4cegv3cegv2cegv1ceg')memcpy(360,4608,240)memcpy(1560,4848,240)ink(1)print('G A M E',8,16)ink(4)print('S Y S T E M',20,16)ink(7)print('mini',9,8)ink(8)print('v0.5.4',34,29)w=0 end function update()w=w+1 if w>90 then cls()load()end end";
void lua_init(const char* filename, const bool start_playing) {
if (lua_state != STATE_STOPPED) lua_quit();
@@ -297,6 +314,7 @@ void lua_init(const char* filename, const bool start_playing) {
lua_pushcfunction(L,cpp_cls); lua_setglobal(L, "cls");
lua_pushcfunction(L,cpp_ink); lua_setglobal(L, "ink");
lua_pushcfunction(L,cpp_paper); lua_setglobal(L, "paper");
lua_pushcfunction(L,cpp_border); lua_setglobal(L, "border");
lua_pushcfunction(L,cpp_color); lua_setglobal(L, "color");
lua_pushcfunction(L,cpp_locate); lua_setglobal(L, "locate");
@@ -335,6 +353,7 @@ void lua_init(const char* filename, const bool start_playing) {
lua_pushcfunction(L,cpp_memcpy); lua_setglobal(L, "memcpy");
lua_pushcfunction(L,cpp_sound); lua_setglobal(L, "sound");
lua_pushcfunction(L,cpp_nosound); lua_setglobal(L, "nosound");
lua_pushcfunction(L,cpp_play); lua_setglobal(L, "play");
lua_pushcfunction(L,cpp_setmode); lua_setglobal(L, "setmode");
lua_pushcfunction(L,cpp_load); lua_setglobal(L, "load");
lua_pushcfunction(L,cpp_log); lua_setglobal(L, "log");

View File

@@ -32,6 +32,8 @@ void do_terminal() {
else if (key == KEY_COMMA) { if (mods & KMOD_SHIFT) { debugchr(';'); } else { debugchr(','); } }
else if (key == KEY_PERIOD) { if (mods & KMOD_SHIFT) { debugchr(':'); } else { debugchr('.'); } }
else if (key == KEY_SLASH) { if (mods & KMOD_SHIFT) { debugchr('_'); } else { debugchr('-'); } }
else if (key == KEY_LEFTBRACKET) { if (mods & KMOD_SHIFT) { debugchr(160); } else if (mods & KMOD_RALT) { debugchr('['); } else { debugchr(96); } }
else if (key == KEY_RIGHTBRACKET) { if (mods & KMOD_SHIFT) { debugchr('*'); } else if (mods & KMOD_RALT) { debugchr(']'); } else { debugchr('+'); } }
}
//cls(0);
pdebug();

84
play.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "play.h"
#include <stdlib.h>
#include <string.h>
const static uint16_t lengths[10] = { 313, 625, 938, 1250, 1875, 2500, 3750, 5000, 7500, 10000 };
const static uint16_t tempos[10] = { 13230, 8820, 6615, 5292, 4410, 3780, 3308, 2940, 2646, 2406 };
const float periods[108] = { 1348.49207, 1272.80688, 1201.37, 1133.94214, 1070.29871, 1010.22772, 953.527893, 900.010376, 849.496887, 801.818176, 756.815613, 714.338745, 674.246033, 636.403564, 600.684875, 566.971069, 535.149475, 505.11377, 476.763947, 450.005249, 424.748352, 400.909088, 378.407806, 357.169373, 337.123016, 318.201782, 300.342438, 283.485535, 267.574738, 252.556885, 238.381973, 225.002625, 212.374176, 200.454544, 189.203888, 178.584702, 168.561508, 159.100876, 150.171234, 141.742767, 133.787354, 126.278458, 119.190987, 112.501305, 106.187096, 100.227272, 94.6019516, 89.2923508, 84.2807541, 79.5504379, 75.0856171, 70.8713837, 66.8936768, 63.139225, 59.5954933, 56.2506561, 53.0935478, 50.113636, 47.3009758, 44.6461754, 42.140377, 39.775219, 37.5428085, 35.4356918, 33.4468384, 31.5696125, 29.7977467, 28.1253281, 26.5467739, 25.056818, 23.650486, 22.3230877, 21.0701885, 19.8876095, 18.7714043, 17.7178459, 16.7234192, 15.7848072, 14.8988733, 14.0626631, 13.273387, 12.528409, 11.8252439, 11.1615429, 10.5350943, 9.94380569, 9.38570118, 8.85892296, 8.36171055, 7.89240265, 7.44943666, 7.03133202, 6.636693, 6.2642045, 5.91262197, 5.58077145, 5.26754713, 4.97190285, 4.69285059, 4.42946148, 4.18085527, 3.94620132, 3.72471833, 3.51566601, 3.3183465, 3.13210225, 2.95631051, 2.7903862 };
static float default_length = 0.25f;
static uint8_t volume = 64;
static uint8_t octave = 4;
static uint32_t tempo = 44100;
static char* song_ptr = NULL;
static char* song = NULL;
uint32_t interpret_note(uint8_t* buffer, const char note, const char param ) {
const uint32_t length = ( param == -1 ? default_length : ((float)lengths[param])/10000.0f ) * tempo;
if( note == 100 ) { memset( buffer, 0, length ); return length; }
const uint16_t period = periods[note + octave*12];
for( int i = 0; i < length; i++ ) buffer[i] = ( (i % period) < (period >> 1) ? volume : -volume );
return length;
}
void play_init(const char* new_song) {
volume=64;
octave=4;
tempo=44100;
if (song != NULL) free(song);
song = (char*)malloc( strlen( new_song ) + 1 );
strcpy( song, new_song );
song_ptr = song;
}
int32_t interpret_next_token(uint8_t* buffer) {
char** token = &song_ptr;
char note = 0;
char param = -1;
switch( **token ) {
case 'b': note += 2;
case 'a': note += 2;
case 'g': note += 2;
case 'f': note += 1;
case 'e': note += 2;
case 'd': note += 2;
case 'c':
param = *++*token;
if( param == '#' || param == '+' ) { note++; param = *++*token; } else if( param == '-' ) { note--; param = *++*token; }
if( param >= 48 && param <= 57 ) { param -= 48; ++*token; } else { param = -1; }
return interpret_note( buffer, note, param );
case 'r':
param = *++*token;
if( param >= 48 && param <= 57 ) { param -= 48; ++*token; } else { param = -1; }
return interpret_note( buffer, 100, param );
case 'o':
param = *++*token;
if( param >= 48 && param <= 57 ) { octave = (param - 48) % 8; ++*token; }
return 0;
case '>':
octave = (octave+1) % 8; ++*token;
return 0;
case '<':
octave = (octave-1) % 8; ++*token;
return 0;
case 'l':
param = *++*token;
if( param >= 48 && param <= 57 ) { default_length = ((float)lengths[param - 48])/10000.0f; ++*token; }
return 0;
case 'v':
param = *++*token;
if( param >= 48 && param <= 57 ) { volume = (param - 48) << 4; ++*token; }
return 0;
case 't':
param = *++*token;
if( param >= 48 && param <= 57 ) { tempo = tempos[param - 48] * 10; ++*token; }
return 0;
case '\0':
return -1;
default:
++*token;
return 0;
};
}

6
play.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include <stdint.h>
void play_init(const char* new_song);
int32_t interpret_next_token(uint8_t* buffer);

115
pong.lua Normal file
View File

@@ -0,0 +1,115 @@
function init()
-- mode 1: 40x30 characters
setmode(1)
-- prepare everything for the match
reset_match()
p1,p2=0,0 -- reset scores
end
function update()
cls()
-- ball movement
-- 'wait' is a counter to skip some cycles before moving the ball, so it starts slower
-- 'speed' defines how many cycles to skip. Every 5 hits to the paddles 'speed' goes down by 1, effectively increasing the ball's speed
-- 'speed' is reset every point
wait=wait-1
if wait==0 then
wait=speed
-- move ball
bx=bx+dx
by=by+dy
-- if ball hits top or down walls, bounce
if by==0 or by==29 then
dy=-dy
if playing then play("a") end -- if we are not playing, be quiet
end
-- during a match, paddles bounce the ball and left and right walls award points
-- but before or after a match the ball just bounces around
if playing then
-- if ball hits left or right ball, reset the ball and award a point to the opposing paddle
if bx==0 then p2=p2+1 reset_ball() end
if bx==39 then p1=p1+1 reset_ball() end
-- if ball hits paddle, bounce
if (bx==1 and by>=y1 and by<=y1+4) or (bx==38 and by>=y2 and by<=y2+4) then
play("c")
dx=-dx
-- also, increase hits. Every 5 hits the ball will speed up (only if it's not already as fast as possible)
hits=hits+1
if (hits%5 == 0) and (speed>0) then speed=speed-1 end
end
else
-- when not playing, just bounce freely
if bx==0 or bx==39 then dx=-dx end
end
end
-- player 1 controls
if btn(KEY_Q) and y1>0 then y1=y1-1 end
if btn(KEY_A) and y1<25 then y1=y1+1 end
-- player 2 controls
if btn(KEY_UP) and y2>0 then y2=y2-1 end
if btn(KEY_DOWN) and y2<25 then y2=y2+1 end
-- draw net
if playing then for i=0,29 do print("\145",20,i) end end
-- draw score
print(p1,18,3)
print(p2,22,3)
-- draw ball
print("\143",flr(bx),flr(by))
-- draw paddles
for i=0,4 do
print("\143",1,y1+i)
print("\143",38,y2+i)
end
if not playing then
-- while not playing show the messages
if p1==10 then print("PLAYER 1 WINS!", 14, 8)
elseif p2==10 then print("PLAYER 2 WINS!", 14, 8)
else print("PONG!", 18, 10) end
print("Press SPACE to play", 11, 20)
if btn(KEY_SPACE) then
start_match()
end
end
end
function start_match()
playing=true
p1,p2=0,0 -- reset scores
end
function reset_match()
play("l2drl2d#l4e>l2crr<e>crr<l4e>crrrl2r cl4dl2d#l4el2cl4del2r<b>l4dl2rl4crrrl2r< drl2d#l4e>l2crr<e>crr<l4e>crrrl2r< l2argl4f#l2a>l4cl2errdl4cl2<al4>drrrl2r< l2drl2d#l4e>l2crr<e>crr<l4e>crrrl2r cl4dl2d#l4el2cl4del2r<b>l4dl2rl4crrrl2r<")
playing=false
bx,by=20,15 -- init ball's position
dx,dy=1,1 -- init ball's direction
y1,y2=14,14 -- init paddle's y coordinate
wait=1 -- reset wait counter
speed=4 -- reset speed
hits=0 -- reset hits counter
end
function reset_ball()
play("l0o3bagfedc") -- play sad tune
bx,by=20,15 -- reset ball's position
speed=4 -- reset speed
hits=0 -- reset hits counter
dx=-dx -- invert x direction
-- si algu arriba a 10, la partida acaba
if p1==10 or p2==10 then
playing=false
play("o5l1crl0ergrl4o6c")
end
end