/*
* 2023-12-30 - Trying to cram in a splash screen as well!
* --- Last update 2023-12-29. Now pretty finished, send it to breadboard testing ---
*
* NOTE: This is unoptimised, horrible code. Unsavoury things are done
* in order to keep the memory footprint low for the ATTiny85.
*
* Do not use any of it. Except maybe the display settings/functions.
*
* Those are pretty sweet.
*/
#include <TinyWireM.h>
//#include <EEPROM.h>
#include "cave_64x56.h"
//#include "pitches.h" // ToDo: Reduce these to minimum (if needed). NOTE: It was needed.
//#define constexpr const // Huh, looks like this place uses C++11 or above
constexpr byte BTN1 PROGMEM = 6;
constexpr byte BTN2 PROGMEM = 4;
constexpr byte BTN3 PROGMEM = 3;
constexpr byte SPEAKER_PIN PROGMEM = 1;
constexpr byte BTN_1_VAL PROGMEM = 100;
constexpr byte BTN_2_VAL PROGMEM = 20;
constexpr byte BTN_3_VAL PROGMEM = 3;
constexpr byte BTN_1_2_VAL PROGMEM = 120;
constexpr byte BTN_1_3_VAL PROGMEM = 103;
constexpr byte BMP_WIDTH PROGMEM = 64;
constexpr byte DISPLAY_HEIGTH PROGMEM = 64;
constexpr byte DISPLAY_WIDTH PROGMEM = 128;
constexpr byte SHIP_HEIGHT PROGMEM = 4;
constexpr byte FUEL_CONSUMTION PROGMEM = 60;
constexpr byte TIME_UNIT PROGMEM = 250;
constexpr byte THRUST PROGMEM = 80;
constexpr byte GRAVITY PROGMEM = 30 ;
constexpr byte AIR_RESISTANCE PROGMEM = 40;
constexpr byte START_POS_X PROGMEM = 12;
constexpr byte START_POS_Y PROGMEM = 44;
//#define START_POS_X 4
//#define START_POS_Y 43
//#define START_POS_X 12
//#define START_POS_Y 35
//#define START_POS_X 31
//#define START_POS_Y 13
// To the left of Mesa. Single page.
//#define START_POS_X 31
//#define START_POS_Y 21
// Adjusted for c64 resolution. Use this. <-------------------------------
//#define START_POS_X 12
//#define START_POS_Y 44
// Above Mesa landing
//#define START_POS_X 44
//#define START_POS_Y 10
// Above east landing
//#define START_POS_X 109
//#define START_POS_Y 12
// TIME_LIMIT 59000
//#define TIME_LIMIT 59000
// Hmm, testing
// WOHA! 50 bytes!
const unsigned int PROGMEM TIME_LIMIT=59000; // 59000
//const byte MAX_X = BMP_WIDTH - 1;
//const byte MAX_Y = DISPLAY_HEIGTH - SHIP_HEIGHT - 1;
// Globals
byte ship_x, ship_y;
int dx, dy;
// ToDo: Work that int magic on these floats as well. Saves 64 bytes initially.
// Edit: That'll cause more problems than it's worth. The Wobble returns.
float move_x;
float move_y;
bool takeoff = false;
unsigned int time = TIME_LIMIT;
unsigned int old_time = TIME_LIMIT;
byte landings = 0b00000000; // 0b00000110; // Last 3 bits tell which pads we've landed on.
//unsigned int count;
//int heartBeat = 100;
//const byte notes_intro PROGMEM =
/*
beep(262, 17);
delay(50);
beep(262, 17);
delay(30);
beep(294, 15);
delay(30);
beep(262, 22);
beep(294, 20);
beep(523, 60);
*/
/*
const unsigned char digits[10][4] PROGMEM
{
{ 0x7e, 0x81, 0x81, 0x7e },
{ 0x82, 0xff, 0x80, 0x00 },
{ 0xc2, 0xa1, 0x91, 0x8f },
{ 0x42, 0x91, 0x91, 0x6e },
{ 0x1f, 0x10, 0x10, 0xff },
{ 0x4f, 0x91, 0x91, 0x61 },
{ 0x7c, 0x92, 0x91, 0x61 },
{ 0x01, 0xf1, 0x09, 0x07 },
{ 0x6e, 0x91, 0x91, 0x6e },
{ 0x0e, 0x91, 0x51, 0x3e }
};
*/
const char initializeCmds[] PROGMEM ={
// -------------- Basic settings
0xAE, // Screen Off
0x81, // Set contrast control
0x7F, // 0-FF ... default half way
0xA6, // Set normal display
//0xA7, // Inverted display
// -------------- Scrolling Commands
0x2E, // Deactivate scroll
// -------------- Addressing Commands
0x20, // Set memory addressing mode
0x00, // 0x00 Horizontal, 0x01 Vertical, 0x02 Page
// -------------- Hardware Configuration Commands
0xA1, // Set segment re-map
0xA8, // Set multiplex ratio
0x3F, // Vertical Size-1: 0x3F=63=128x64, 0x1F=31=128x32
0xC8, // Vertical scan direction: 0xC8 = TopDown, 0xC0 = DownTop
0xD3, 0x00, // Set Display Offset (default 0x00)
0xDA, // Set COM pins hardware configuration
0x12, // Alternate com config & disable com left/right
// -------------- Select screen work area
0x22, // Command, set page address range
0, // From top
7, // ..to bottom page (128x32 has, of course, 3)
0x21, // Command, set column range
0, // From col
127, // To col
// -------------- Timing and Driving Settings
0xD5, // Set display oscillator frequency 0-0xF /clock divide ratio 0-0xF
0x80, // Default value
0xD9, // Set pre-changed period
0x22, // Default 0x22
0xDB, // Set VCOMH Deselected level
0x20, // Default
// -------------- Charge pump regulator
0x8D, // Set charge pump
0x14, // VCC generated by internal DC/DC circuit
// -------------- Turn the screen back on
0xA4, // 0xA4, //Set entire display on/off
0xAF // Set display on
};
void setup() {
TinyWireM.begin();
// 0 = Pin 8, 4 = Pin 3
pinMode(BTN1, INPUT);
pinMode(BTN2, INPUT);
pinMode(BTN3, INPUT);
pinMode(SPEAKER_PIN, OUTPUT);
// Init display
config_display();
displayLogo();
// Init background/ship
ship_x = START_POS_X;
ship_y = START_POS_Y;
move_x = START_POS_X;
move_y = START_POS_Y;
drawCave();
//drawCollisionCave();
//drawShip(ship_x, ship_y);
appearShip(ship_x, ship_y);
playEventSound(0);
// Wait for user input
while(!digitalRead(BTN1)){}
}
// ToDo: Try doing this in one for-loop, otherwise it gets costly.
void displayLogo() {
//cursorToPage(63,2);
//send_data(0xFF);
//cursorToPage(65,2);
//send_data(0xFF);
for (int i=0; i<16; i++) {
// Top left
cursorToPage(32+(order[i]*2),3);
send_data(logo[order[i]] );
send_data(logo[order[i]] );
// Bottom left
cursorToPage(32+(order[i]*2),4);
send_data(reverse(logo[order[i]]));
send_data(reverse(logo[order[i]]));
// Top right
cursorToPage(78+(16-order[i]*2),3);
send_data(logo[order[i]]);
send_data(logo[order[i]]);
// Bottom left
cursorToPage(78+(16-order[i]*2),4);
send_data(reverse(logo[order[i]]));
send_data(reverse(logo[order[i]]));
delay(200);
}
/*
for (int i=0; i<20000; i++) {
beep(40, 5);
beep(60, 5);
}
*/
delay(2000);
}
byte reverse(byte b) {
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
return b;
}
void loop() {
byte state = 0;
bool play_sound = false;
// If this looks weird (the arbitrary button values) it's because the hardware version
// uses scaled resistors on all buttons to get them to fit on one analog pin.
//
if (digitalRead(BTN1) == HIGH)
state += 100;
if (digitalRead(BTN2) == HIGH)
state += 20;
if (digitalRead(BTN3) == HIGH)
state += 3;
// Gravity
if (dy < 20000)
dy += GRAVITY;
// Air resistance (can probably up this a bit)
if (dx < 0)
dx += AIR_RESISTANCE;
if (dx > 0)
dx -= AIR_RESISTANCE;
// ---------------------------------------------
// Button presses
if (state > 0) {
time -= FUEL_CONSUMTION;
play_sound = true;
switch(state) {
case BTN_1_VAL:
if (dy > -20000)
dy -= THRUST;
break;
case BTN_2_VAL:
if (dx < 20000)
dx += (THRUST*2);
break;
case BTN_3_VAL:
if (dx > -20000)
dx -= (THRUST*2);
break;
case BTN_1_2_VAL:
if (dy > -20000)
dy -= THRUST;
if (dx < 20000)
dx += (THRUST*2);
break;
case BTN_1_3_VAL:
if (dy > -20000)
dy -= THRUST;
if (dx > -20000)
dx -= (THRUST*2);
break;
}
}
// ---------------------------------------------------------
// Ship movement part
// Ugly hack to prevent global floats.
move_x += ((float)dx)/10000;
move_y += ((float)dy)/1000;
//byte x = round(move_x + ship_x);
//byte y = round(move_y + ship_y);
//byte x = round((ship_x += dx));
//byte y = round((ship_y += dy));
//byte x = round(move_x);
//byte y = round(move_y);
// ...seems obvious in hindsight. round() is evil.
// UNCOMMENT THIS
byte x = (int)move_x;
byte y = (int)move_y;
// Move ship if the coordinates changed. Do not move out of bounds.
// ToDo: The boundary checks can probably be removed, background collision takes care of that.
if ((ship_x != x || ship_y != y) && y < (DISPLAY_HEIGTH - SHIP_HEIGHT - 1) && x > 0 && y >= 0 && x < 127)
moveShip(x, y);
// Update time/fuel status bar. Alternatively, crash ship.
time -= 50;
if ((time < 100) || (time > TIME_LIMIT)) // Also check for int overflow (underflow?)
crashShip();
if ((time/1000) != (old_time/1000))
updateBars();
//clearDisplay();
//count = count>64000 ? 0 : count+1;
if (play_sound) {
beep(55, 10);
delay(20);
}
else
delay(100);
}
void appearShip(byte x, byte y) {
for (byte i=0; i<3; i++) {
unDrawShip(x, y);
delay(100);
drawShip(x, y);
beep(784, 15);
delay(170);
}
}
bool getCavePixelAt(byte x, byte y) {
byte slice = getSlice(x, y);
return (slice >> (y % 8)) & 1;
}
// ---------------------------------------------------------
// Time/Fuel status bars
//
void updateBars() {
// Time bar
//if (time > 0) {
// 7 - 124 (117/2 = 58)
//byte xpos = ((time / 1000) + 6);
//if (xpos > 7) {
// cursorToPage(xpos, 7);
// send_data(0b10000000);
//}
byte xpos = ((time / 500) + 3);
cursorToPage(xpos, 7);
send_data(0b10000000);
old_time = time;
}
// ---------------------------------------------------------
// A winner is you!
//
void winGame() {
playEventSound(3);
unsigned int tmp = time;
while(time >= 2000) {
//while(time > 100 && time <= TIME_LIMIT) {
//while ((time < 100) || (time > TIME_LIMIT))
time -= 2000;
updateBars();
beep(1100-((time/1000)*6), 15);
}
// Display score
cursorToPage(37,1);
for (int i=0; i<5; i++) {
send_data(0b00111100);
if (i <= tmp/10000) {
send_data(0b01111110);
send_data(0b01111110);
} else {
send_data(0b01000010);
send_data(0b01000010);
}
send_data(0b00111100);
send_data(0b00000000);
beep(447 + (i*60), 50);
delay(500);
}
while(!digitalRead(BTN1)){}
resetGame();
}
void moveShip(byte x, byte y) {
// Sprite emulation!
unDrawShip(ship_x, ship_y);
drawShip(x, y);
ship_x = x;
ship_y = y;
takeoff = true;
// Check collision with background
//if (x & 0x00000001)
// x -= 1;
if (x & 0x00000001)
x -= 1;
x = (int)(x/2);
if (
getCavePixelAt((x)+1, ship_y+3) || // Bottom right
getCavePixelAt(x, ship_y) || // Top
getCavePixelAt((x)-1, ship_y+3) // Bottom left
)
crashShip();
// For testing:
//if (getCavePixelAt(x, ship_y))
// crashShip();
// ---------------------------------------------
// Check for landing
//
// Prevent landing jingle to play at start.
// UNCOMMENT THIS
if (!takeoff)
return;
if (ship_y == 44) { // check
if (ship_x < 18 && ship_x > 7) //if (ship_x < 9 && ship_x > 3)
landShip(0);
}
else if (ship_y == 14) {
if (ship_x > 43 && ship_x < 51) //if (ship_x > 18 && ship_x < 25)
landShip(1);
}
else if (ship_y == 19) {
if (ship_x > 109 && ship_x < 123)
landShip(2);
}
}
void drawShip(byte x, byte y) {
byte mask = 0x00;
byte page = (int)y/8;
byte pageY = y % 8;
byte slices[6] = { 0 };
bool overlap = false;
//int index = (page * BMP_WIDTH) + (x/2);
//byte adj_x;
// Wobble fix. Add one to x if on an odd coordinate.
byte xx = x;
if (xx & 0x00000001)
xx -= 1;
byte adj_x = (int)(xx/2);
// --------------------------------------------------------------------
// Check if the "sprite" overlaps two pages vertically.
// ToDo: Put in a check for when we're at the last page. if (pageY > 4 && pageY !=7) {
int index = (page * BMP_WIDTH) + adj_x;
slices[0] = pgm_read_byte(cave + index - 1);
slices[1] = pgm_read_byte(cave + index);
slices[2] = pgm_read_byte(cave + index + 1);
// We have page overlap, add slices from a page below.
if (pageY > 4) {
index = (page * BMP_WIDTH) + adj_x + BMP_WIDTH;
slices[3] = pgm_read_byte(cave + index - 1);
slices[4] = pgm_read_byte(cave + index);
slices[5] = pgm_read_byte(cave + index + 1);
overlap = true;
}
// Mask for Col 1a of sprite.
mask = mask | (1 << (pageY+2));
mask = mask | (1 << (pageY+3));
slices[0] = slices[0] | mask;
// Mask for Col 2a of sprite.
mask = 0x00;
mask = mask | (1 << (pageY));
mask = mask | (1 << (pageY+1));
mask = mask | (1 << (pageY+2));
slices[1] = slices[1] | mask;
// Mask for Col 3a of sprite.
mask = 0x00;
mask = mask | (1 << (pageY+2));
mask = mask | (1 << (pageY+3));
slices[2] = slices[2] | mask;
if (overlap) {
// Mask for Col 1b of sprite.
mask = 0x00;
mask = mask | (1 << (pageY-6));
mask = mask | (1 << (pageY-5));
slices[3] = slices[3] | mask;
// Mask for Col 2b of sprite.
// Ok, this is a hack. Couldn't get dynamic indexing to work here.
mask = 0x00;
if (pageY == 6) {
mask = 0b00000001;
}
else if (pageY == 7) {
mask = 0b00000011;
}
slices[4] = slices[4] | mask;
// Mask for Col 3b of sprite.
mask = 0x00;
mask = mask | (1 << (pageY-6));
mask = mask | (1 << (pageY-5));
slices[5] = slices[5] | mask;
}
// Draw all slices.
//
//cursorToPage(x-1, page);
cursorToPage(xx-2, page); // c64
send_data(slices[0]);
send_data(slices[0]);
send_data(slices[1]);
send_data(slices[1]);
send_data(slices[2]);
send_data(slices[2]);
if (overlap) {
cursorToPage(xx-2, page+1);
send_data(slices[3]);
send_data(slices[3]);
send_data(slices[4]);
send_data(slices[4]);
send_data(slices[5]);
send_data(slices[5]);
}
}
void cursorToPage(byte x, byte page) {
send_command(0x22);
send_command(page);
send_command(7);
send_command(0x21);
send_command(x);
send_command(127);
}
void unDrawShip(byte x, byte y) {
byte page = (int)y/8;
byte subY = y % 8;
byte slices[6] = { 0 };
// Wobble fix. Add one to x if odd.
if (x & 0x00000001)
x -= 1;
byte adj_x = (int)(x/2);
int index = (page * BMP_WIDTH) + adj_x;
// The whole sprite fits into one page
//if (subY < 5) {
slices[0] = pgm_read_byte(cave + (index-1));
slices[1] = pgm_read_byte(cave + index);
slices[2] = pgm_read_byte(cave + (index+1));
// We'll always be displaying the first slice set.
//cursorToPage(xx-2, page);
cursorToPage(x-2, page);
send_data(slices[0]);
send_data(slices[0]);
send_data(slices[1]);
send_data(slices[1]);
send_data(slices[2]);
send_data(slices[2]);
// Sprite overlaps two pages, draw the bottom part.
if (subY > 4) {
slices[3] = pgm_read_byte(cave + (index-1)+BMP_WIDTH);
slices[4] = pgm_read_byte(cave + index+BMP_WIDTH);
slices[5] = pgm_read_byte(cave + (index+1)+BMP_WIDTH);
//cursorToPage(xx-2, page+1);
cursorToPage(x-2, page+1);
send_data(slices[3]);
send_data(slices[3]);
send_data(slices[4]);
send_data(slices[4]);
send_data(slices[5]);
send_data(slices[5]);
}
}
byte getSlice(byte x, byte y) {
int page = (int)y/8; // Get Page index
int index = (page * BMP_WIDTH) + x; // Width * number of pages (plus x-index)
byte slice = pgm_read_byte(cave+index);
return slice;
}
/* This actually takes up more memory than including delayMicro()! (Works though)
void pause(int val) {
unsigned long currentTime = micros(); // or micros()
while(micros() < (currentTime + val)){}
}
*/
// Overloading this, hope it doesn't eat memory
// It did! 14 bytes.
/*
void beep (byte frequencyInHertz, byte timeInMilliseconds) {
beep(frequencyInHertz, timeInMilliseconds, 0);
}
*/
// Send octave as argument, make frequencyInHertz a byte and add extra as needed. Saves 14 bytes.
// Just need to get it to work..
//void beep (byte frequencyInHertz, byte timeInMilliseconds, byte octave)
void beep (int frequencyInHertz, byte timeInMilliseconds)
{
//beep(184, 15, 6);
//if (octave > 0)
// frequencyInHertz + (100 * octave);
//int delayAmount PROGMEM = (long)(1000000 / frequencyInHertz);
//int delayAmount PROGMEM = (long)(1000000 / (frequencyInHertz < 10 ? frequencyInHertz+256 : frequencyInHertz));
int delayAmount PROGMEM = (long)(1000000 / frequencyInHertz); // <-- Use this with int if all else fails.
//int delayAmount PROGMEM = (long)(1000000 / ( (octave > 0) ? (frequencyInHertz + (100 * octave)) : frequencyInHertz) );
//long loopTime PROGMEM = (long)((timeInMilliseconds * 1000) / (delayAmount * 2));
int loopTime PROGMEM = (int)((timeInMilliseconds*10) / (delayAmount * 0.002));
for (int x = 0; x < loopTime; x++) {
digitalWrite(SPEAKER_PIN, HIGH);
delayMicroseconds(delayAmount);
//pause(delayAmount);
digitalWrite(SPEAKER_PIN, LOW);
delayMicroseconds(delayAmount);
//pause(delayAmount);
}
}
// ToDo: We could probably shorten the init sequence a bit. Check the 'Debugging SSD1306' page.
void config_display() {
//int len = sizeof(initializeCmds);
for(int i=0; i<sizeof(initializeCmds); i++) {
send_command(pgm_read_byte(initializeCmds+i));
}
}
/*
void cursorTo( unsigned char col, unsigned char row ){
send_command(0x00 | (0x0F & col) ); // low col = 0
send_command(0x10 | (0x0F & (col >> 4)) ); // hi col = 0
send_command(0xb0 | (0x03 & row) ); // hi col = 0
}
*/
/* With the drawCave() function, we don't need this! Saved 30 bytes.
void clearDisplay() {
cursorToPage(0, 0);
for (uint16_t i=0; i<448; i++) {
send_data(0x00);
}
}
*/
// Rightfully appropiated from StackOverflow (because mine sucked and didn't work right)
//
/*
void writeDigits(uint8_t x, uint8_t y, int number) {
// count number of digits
int c = 0; // digit position
int n = number;
while (n != 0) {
n /= 10;
c++;
}
int numberArray[c];
c = 0;
n = number;
// extract each digit
while (n != 0) {
numberArray[c] = n % 10;
n /= 10;
c++;
}
for (uint8_t i=0; i<c; i++) {
TinyWireM.beginTransmission(0x3C);
TinyWireM.write(0x40); // data mode
TinyWireM.write( digits[numberArray[c-i-1]][0] );
TinyWireM.write( digits[numberArray[c-i-1]][1] );
TinyWireM.write( digits[numberArray[c-i-1]][2] );
TinyWireM.write( digits[numberArray[c-i-1]][3] );
TinyWireM.write( 0x00 );
TinyWireM.endTransmission();
}
}
*/
void landShip(byte location) {
// Litho breaking on landing pad
if (dy > 500) {
crashShip();
return;
}
// Check if we haven't landed on this pad before.
if (!((1 << location) & landings)) {
playEventSound(1);
landings = landings | 1 << location;
}
// Landed on all three pads. Win game.
if (landings == 0b00000111)
winGame();
// Reset delta speed
dx = 0;
dy = 0;
// Wait for user input
while(!digitalRead(BTN1)){}
}
void crashShip() {
send_command(0xA7); // Inverted display
delay(100);
send_command(0xA6); // Set normal display
delay(100);
send_command(0xA7); // Inverted display
delay(100);
send_command(0xA6); // Set normal display
playEventSound(2);
delay(2000);
resetGame();
}
void resetGame() {
ship_x = START_POS_X;
ship_y = START_POS_Y;
move_x = ship_x;
move_y = ship_y;
dx = 0;
dy = 0;
time = TIME_LIMIT;
old_time = TIME_LIMIT;
takeoff = false;
//clearDisplay(); // Won't need this when drawing the whole background.
drawCave();
//drawShip(ship_x, ship_y);
appearShip(ship_x, ship_y);
playEventSound(0); // Intro
// Wait for user input
while(!digitalRead(BTN1)){}
}
void drawCave() {
//byte index = 0;
//byte space = 0b10000000;
cursorToPage(0, 0);
// Brute force method. Slow but reliable.
for (int x=0; x<448; x++) {
send_data(pgm_read_byte(cave + x));
send_data(pgm_read_byte(cave + x));
}
// Draw status bar
//
// First part
cursorToPage(0,7);
send_data(0b11111111);
send_data(0b10000000);
// The time bar
for (byte x=3; x<127; x++)
send_data(0b10011100);
// Ending
send_data(0b10000000);
send_data(0b11111111);
}
void send_data(byte slice) {
TinyWireM.beginTransmission(0x3C);
TinyWireM.write(0x40);
TinyWireM.write(slice);
TinyWireM.endTransmission();
}
void send_command(unsigned char cmd) {
TinyWireM.beginTransmission(0x3c);
TinyWireM.write(0x00);
TinyWireM.write(cmd);
TinyWireM.endTransmission();
}
void playEventSound(byte type) {
// This looks strange, but it saves memory.
byte n131 = 131;
byte n165 = 165;
int n262 = 262;
byte d15 = 15;
byte d12 = 12;
if (type == 0) {
// Intro
/*
beep(n262, 17, 1);
delay(50);
beep(n262, 17, 1);
delay(30);
beep(194, d15, 1);
delay(30);
beep(n262, 20, 1);
beep(194, 20, 1);
beep(223, 60, 3);
*/
beep(n262, 17);
delay(50);
beep(n262, 17);
delay(30);
beep(294, d15);
delay(30);
beep(n262, 20);
beep(294, 20);
beep(523, 60);
} else if (type == 1) {
// Landing
beep(523, d15);
beep(784, d15);
beep(1047, d15);
} else if (type == 2) {
// Crash
beep(n131, 30);
beep(n165, 30);
beep(147, 60);
beep(n131, 20);
} else if (type == 3) {
// Win game
beep(n131, d12);
beep(n165, d12);
beep(196, d12);
delay(200);
beep(n165, d12);
beep(196, d12);
beep(247, d12);
delay(500);
beep(262, 100);
//beep(6, 300);
}
}
// ToDo: Put all these into one function whith variables/constants for commmon notes.
/*
void playIntro() {
//return;
beep(262, 17);
delay(50);
beep(262, 17);
delay(30);
beep(294, 15);
delay(30);
beep(262, 22);
beep(294, 20);
beep(523, 60);
}
void playLanding() {
//byte d = 10;
//beep(131, d);
//beep(262, d);
//beep(131, d);
//beep(262, d);
//beep(131, d);
//beep(262, d);
beep(523, 15);
beep(784, 15);
beep(1047, 15);
}
void playWinGame() {
//byte mainDelay = 120;
beep(131, 12);
beep(165, 12);
beep(196, 12);
delay(200);
beep(165, 12);
beep(196, 12);
beep(247, 12);
delay(500);
beep(262, 100);
}
void playCrash() {
beep(131, 30);
beep(165, 30);
beep(147, 60);
beep(131, 20);
}
*/
/*
void playLanding() {
byte mainDelay = 120;
beep(NOTE_C3, mainDelay);
beep(NOTE_E3, mainDelay);
beep(NOTE_G3, mainDelay);
delay(200);
beep(NOTE_E3, mainDelay);
beep(NOTE_G3, mainDelay);
beep(NOTE_B3, mainDelay);
delay(500);
beep(NOTE_C4, 100);
//Old playLanding();
//beep(NOTE_C3, 200);
//beep(NOTE_F3, 200);
//beep(NOTE_A3, 200);
//beep(NOTE_F3, 200);
//beep(NOTE_C4, 100);
}
*/
/*
// Test function. Draw entire BMP using getCavePixelAt()
void drawCollisionCave() {
cursorToPage(0,0);
byte slice;
for(byte y=0; y<56; y+=8) {
for(byte x=0; x<64; x++) {
slice = 0x00;
for (byte b=0; b<8; b++) {
if (getCavePixelAt(x, y+b))
slice = slice | 1 << b;
}
TinyWireM.beginTransmission(0x3C);
TinyWireM.write(0x40);
TinyWireM.write(slice);
TinyWireM.write(slice);
TinyWireM.endTransmission();
}
}
}
*/
// Fancy multi-write to buffer. Something goes wrong here with more than 8 data bytes sent. Isn't the write buffer 32B? 16B?
//
/*
TinyWireM.beginTransmission(0x3C);
TinyWireM.write(0x40);
for (int x=0; x<448; x++) {
TinyWireM.write(pgm_read_byte(cave + x));
TinyWireM.write(pgm_read_byte(cave + x)); // c64
if (++index > 8) {
TinyWireM.endTransmission();
delay(10);
index = 0;
TinyWireM.beginTransmission(0x3C);
TinyWireM.write(0x40);
}
}
TinyWireM.endTransmission();
*/