mirror of
https://github.com/lefticus/6502-cpp.git
synced 2024-12-22 01:30:03 +00:00
Game map actions starting to work
This commit is contained in:
parent
bb51249b4c
commit
949e118ef7
@ -2,21 +2,17 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string_view>
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
#include <string_view>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
#include "chargen.hpp"
|
#include "chargen.hpp"
|
||||||
|
|
||||||
enum Colors : uint8_t { WHITE = 0x01 };
|
enum Colors : uint8_t { WHITE = 0x01 };
|
||||||
|
|
||||||
static volatile uint8_t &memory_loc(const uint16_t loc) {
|
static volatile uint8_t &memory_loc(const uint16_t loc) { return *reinterpret_cast<volatile uint8_t *>(loc); }
|
||||||
return *reinterpret_cast<volatile uint8_t *>(loc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void poke(const uint16_t loc, const uint8_t value) {
|
static void poke(const uint16_t loc, const uint8_t value) { memory_loc(loc) = value; }
|
||||||
memory_loc(loc) = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::uint8_t peek(const std::uint16_t loc) { return memory_loc(loc); }
|
static std::uint8_t peek(const std::uint16_t loc) { return memory_loc(loc); }
|
||||||
|
|
||||||
@ -29,64 +25,46 @@ struct Joystick
|
|||||||
{
|
{
|
||||||
std::uint8_t state{};
|
std::uint8_t state{};
|
||||||
|
|
||||||
constexpr bool up() const noexcept {
|
constexpr bool up() const noexcept { return (state & 1) == 0; }
|
||||||
return (state & 1) == 0;
|
constexpr bool left() const noexcept { return (state & 4) == 0; }
|
||||||
}
|
constexpr bool fire() const noexcept { return (state & 16) == 0; }
|
||||||
constexpr bool left() const noexcept {
|
constexpr bool right() const noexcept { return (state & 8) == 0; }
|
||||||
return (state & 4) == 0;
|
constexpr bool down() const noexcept { return (state & 2) == 0; }
|
||||||
}
|
|
||||||
constexpr bool fire() const noexcept {
|
|
||||||
return (state & 16) == 0;
|
|
||||||
}
|
|
||||||
constexpr bool right() const noexcept {
|
|
||||||
return (state & 8) == 0;
|
|
||||||
}
|
|
||||||
constexpr bool down() const noexcept {
|
|
||||||
return (state & 2) == 0;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool joystick_down() {
|
static bool joystick_down()
|
||||||
|
{
|
||||||
uint8_t joystick_state = peek(0xDC00);
|
uint8_t joystick_state = peek(0xDC00);
|
||||||
return (joystick_state & 2) == 0;
|
return (joystick_state & 2) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void use_data(std::array<char, 1024> &data);
|
void use_data(std::array<char, 1024> &data);
|
||||||
|
|
||||||
static void puts(uint8_t x, uint8_t y, std::string_view str) {
|
static void puts(uint8_t x, uint8_t y, std::string_view str)
|
||||||
|
{
|
||||||
const auto start = 0x400 + (y * 40 + x);
|
const auto start = 0x400 + (y * 40 + x);
|
||||||
|
|
||||||
std::memcpy(const_cast<uint8_t *>(&memory_loc(start)), str.data(),
|
std::memcpy(const_cast<uint8_t *>(&memory_loc(start)), str.data(), str.size());
|
||||||
str.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<std::uint8_t Width, std::uint8_t Height> struct Graphic
|
||||||
template<std::uint8_t Width, std::uint8_t Height>
|
|
||||||
struct Graphic
|
|
||||||
{
|
{
|
||||||
std::array<std::uint8_t, Width * Height> data{};
|
std::array<std::uint8_t, Width * Height> data{};
|
||||||
|
|
||||||
static constexpr auto width() noexcept {
|
static constexpr auto width() noexcept { return Width; }
|
||||||
return Width;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr auto height() noexcept {
|
static constexpr auto height() noexcept { return Height; }
|
||||||
return Height;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Graphic() = default;
|
constexpr Graphic() = default;
|
||||||
|
|
||||||
constexpr Graphic(std::array<uint8_t, Width * Height> data_) noexcept : data(data_) {}
|
constexpr Graphic(std::array<uint8_t, Width * Height> data_) noexcept : data(data_) {}
|
||||||
constexpr Graphic(std::initializer_list<uint8_t> data_) noexcept {
|
constexpr Graphic(std::initializer_list<uint8_t> data_) noexcept { std::copy(begin(data_), end(data_), begin(data)); }
|
||||||
std::copy(begin(data_), end(data_), begin(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr auto &operator()(const std::uint8_t x, const std::uint8_t y) noexcept {
|
constexpr auto &operator()(const std::uint8_t x, const std::uint8_t y) noexcept { return data[y * Width + x]; }
|
||||||
return data[y * Width + x];
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr const auto &operator()(const std::uint8_t x, const std::uint8_t y) const noexcept {
|
constexpr const auto &operator()(const std::uint8_t x, const std::uint8_t y) const noexcept
|
||||||
|
{
|
||||||
return data[y * Width + x];
|
return data[y * Width + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,9 +73,7 @@ struct Graphic
|
|||||||
std::size_t count = 0;
|
std::size_t count = 0;
|
||||||
for (std::uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) {
|
for (std::uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) {
|
||||||
for (std::uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) {
|
for (std::uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) {
|
||||||
if (graphic(cur_x, cur_y) == (*this)(cur_x + x, cur_y + y)) {
|
if (graphic(cur_x, cur_y) == (*this)(cur_x + x, cur_y + y)) { ++count; }
|
||||||
++count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,19 +85,18 @@ struct Graphic
|
|||||||
{
|
{
|
||||||
return match_count(graphic, x, y) == (graphic.width() * graphic.height());
|
return match_count(graphic, x, y) == (graphic.width() * graphic.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static constexpr auto load_charset(const std::span<const std::uint8_t, 256*8> &bits) {
|
static constexpr auto load_charset(const std::span<const std::uint8_t, 256 * 8> &bits)
|
||||||
std::array<Graphic<8,8>, 256> results{};
|
{
|
||||||
|
std::array<Graphic<8, 8>, 256> results{};
|
||||||
|
|
||||||
for (std::size_t idx = 0; idx < 256; ++idx) {
|
for (std::size_t idx = 0; idx < 256; ++idx) {
|
||||||
Graphic<8,8> glyph{};
|
Graphic<8, 8> glyph{};
|
||||||
|
|
||||||
for (std::uint8_t row = 0; row < 8; ++row) {
|
for (std::uint8_t row = 0; row < 8; ++row) {
|
||||||
const auto input_row = bits[idx*8+row];
|
const auto input_row = bits[idx * 8 + row];
|
||||||
glyph(0, row) = (0b1000'0000 & input_row) == 0 ? 0 : 1;
|
glyph(0, row) = (0b1000'0000 & input_row) == 0 ? 0 : 1;
|
||||||
glyph(1, row) = (0b0100'0000 & input_row) == 0 ? 0 : 1;
|
glyph(1, row) = (0b0100'0000 & input_row) == 0 ? 0 : 1;
|
||||||
glyph(2, row) = (0b0010'0000 & input_row) == 0 ? 0 : 1;
|
glyph(2, row) = (0b0010'0000 & input_row) == 0 ? 0 : 1;
|
||||||
@ -138,8 +113,9 @@ static constexpr auto load_charset(const std::span<const std::uint8_t, 256*8> &b
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::uint8_t InWidth, std::uint8_t InHeight>
|
template<std::uint8_t InWidth, std::uint8_t InHeight>
|
||||||
static constexpr auto from_pixels_to_petscii(const Graphic<InWidth, InHeight> &pixels) {
|
static constexpr auto from_pixels_to_petscii(const Graphic<InWidth, InHeight> &pixels)
|
||||||
|
{
|
||||||
Graphic<InWidth / 8, InHeight / 8> result{};
|
Graphic<InWidth / 8, InHeight / 8> result{};
|
||||||
|
|
||||||
constexpr auto charset = load_charset(uppercase);
|
constexpr auto charset = load_charset(uppercase);
|
||||||
@ -161,81 +137,67 @@ static constexpr auto load_charset(const std::span<const std::uint8_t, 256*8> &b
|
|||||||
++cur_char;
|
++cur_char;
|
||||||
}
|
}
|
||||||
|
|
||||||
result(x/8, y/8) = best_match;
|
result(x / 8, y / 8) = best_match;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<std::uint8_t InWidth, std::uint8_t InHeight>
|
template<std::uint8_t InWidth, std::uint8_t InHeight>
|
||||||
static constexpr auto from_pixels_to_2x2(const Graphic<InWidth, InHeight> &pixels) {
|
static constexpr auto from_pixels_to_2x2(const Graphic<InWidth, InHeight> &pixels)
|
||||||
|
{
|
||||||
Graphic<InWidth / 2, InHeight / 2> result{};
|
Graphic<InWidth / 2, InHeight / 2> result{};
|
||||||
|
|
||||||
using GlyphType = std::pair<Graphic<2,2>, std::uint8_t>;
|
using GlyphType = std::pair<Graphic<2, 2>, std::uint8_t>;
|
||||||
constexpr std::array<GlyphType, 17> lookup_map {
|
constexpr std::array<GlyphType, 17> lookup_map{ GlyphType{ { 0, 0, 0, 0 }, 32 },
|
||||||
GlyphType{ {0,0,
|
GlyphType{ { 1, 0, 0, 0 }, 126 },
|
||||||
0,0}, 32 },
|
GlyphType{ { 0, 1, 0, 0 }, 124 },
|
||||||
GlyphType{ {1,0,
|
GlyphType{ { 1, 1, 0, 0 }, 226 },
|
||||||
0,0}, 126 },
|
GlyphType{ { 0, 0, 1, 0 }, 123 },
|
||||||
GlyphType{ {0,1,
|
GlyphType{ { 1, 0, 1, 0 }, 97 },
|
||||||
0,0}, 124 },
|
GlyphType{ { 0, 1, 1, 0 }, 255 },
|
||||||
GlyphType{ {1,1,
|
GlyphType{ { 1, 1, 1, 0 }, 236 },
|
||||||
0,0}, 226 },
|
GlyphType{ { 0, 0, 0, 1 }, 108 },
|
||||||
GlyphType{ {0,0,
|
GlyphType{ { 1, 0, 0, 1 }, 127 },
|
||||||
1,0}, 123 },
|
GlyphType{ { 0, 1, 0, 1 }, 225 },
|
||||||
GlyphType{ {1,0,
|
GlyphType{ { 1, 1, 0, 1 }, 251 },
|
||||||
1,0}, 97 },
|
GlyphType{ { 0, 0, 1, 1 }, 98 },
|
||||||
GlyphType{ {0,1,
|
GlyphType{ { 1, 0, 1, 1 }, 252 },
|
||||||
1,0}, 255 },
|
GlyphType{ { 0, 1, 1, 1 }, 254 },
|
||||||
GlyphType{ {1,1,
|
GlyphType{ { 1, 1, 1, 1 }, 160 } };
|
||||||
1,0}, 236 },
|
|
||||||
GlyphType{ {0,0,
|
|
||||||
0,1}, 108 },
|
|
||||||
GlyphType{ {1,0,
|
|
||||||
0,1}, 127 },
|
|
||||||
GlyphType{ {0,1,
|
|
||||||
0,1}, 225 },
|
|
||||||
GlyphType{ {1,1,
|
|
||||||
0,1}, 251 },
|
|
||||||
GlyphType{ {0,0,
|
|
||||||
1,1}, 98 },
|
|
||||||
GlyphType{ {1,0,
|
|
||||||
1,1}, 252 },
|
|
||||||
GlyphType{ {0,1,
|
|
||||||
1,1}, 254 },
|
|
||||||
GlyphType{ {1,1,
|
|
||||||
1,1}, 160 }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
for (uint8_t x = 0; x < pixels.width(); x += 2) {
|
for (uint8_t x = 0; x < pixels.width(); x += 2) {
|
||||||
for (uint8_t y = 0; y < pixels.height(); y += 2) {
|
for (uint8_t y = 0; y < pixels.height(); y += 2) {
|
||||||
for (const auto &glyph : lookup_map) {
|
for (const auto &glyph : lookup_map) {
|
||||||
if (pixels.match(glyph.first, x, y)) {
|
if (pixels.match(glyph.first, x, y)) {
|
||||||
result(x/2, y/2) = glyph.second;
|
result(x / 2, y / 2) = glyph.second;
|
||||||
break; // go to next Y, we found our match
|
break;// go to next Y, we found our match
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void putc(uint8_t x, uint8_t y, uint8_t c) {
|
static void putc(uint8_t x, uint8_t y, uint8_t c)
|
||||||
|
{
|
||||||
const auto start = 0x400 + (y * 40 + x);
|
const auto start = 0x400 + (y * 40 + x);
|
||||||
poke(start, c);
|
poke(start, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::uint8_t loadc(uint8_t x, uint8_t y) {
|
static std::uint8_t loadc(uint8_t x, uint8_t y)
|
||||||
|
{
|
||||||
const auto start = 0x400 + (y * 40 + x);
|
const auto start = 0x400 + (y * 40 + x);
|
||||||
return peek(start);
|
return peek(start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void put_hex(uint8_t x, uint8_t y, uint8_t value) {
|
static void put_hex(uint8_t x, uint8_t y, uint8_t value)
|
||||||
|
{
|
||||||
const auto put_nibble = [](auto x, auto y, uint8_t nibble) {
|
const auto put_nibble = [](auto x, auto y, uint8_t nibble) {
|
||||||
if (nibble <= 9) {
|
if (nibble <= 9) {
|
||||||
putc(x, y, nibble + 48);
|
putc(x, y, nibble + 48);
|
||||||
@ -248,31 +210,31 @@ static void put_hex(uint8_t x, uint8_t y, uint8_t value) {
|
|||||||
put_nibble(x, y, 0xF & (value >> 4));
|
put_nibble(x, y, 0xF & (value >> 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_hex(uint8_t x, uint8_t y, uint16_t value) {
|
static void put_hex(uint8_t x, uint8_t y, uint16_t value)
|
||||||
put_hex(x+2,y, static_cast<std::uint8_t>(0xFF & value));
|
{
|
||||||
put_hex(x,y, static_cast<std::uint8_t>(0xFF & (value >> 8)));
|
put_hex(x + 2, y, static_cast<std::uint8_t>(0xFF & value));
|
||||||
|
put_hex(x, y, static_cast<std::uint8_t>(0xFF & (value >> 8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_graphic(uint8_t x, uint8_t y, const auto &graphic)
|
static void put_graphic(uint8_t x, uint8_t y, const auto &graphic)
|
||||||
{
|
{
|
||||||
for (uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) {
|
for (uint8_t cur_y = 0; cur_y < graphic.height(); ++cur_y) {
|
||||||
for (uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) {
|
for (uint8_t cur_x = 0; cur_x < graphic.width(); ++cur_x) { putc(cur_x + x, cur_y + y, graphic(cur_x, cur_y)); }
|
||||||
putc(cur_x + x, cur_y + y, graphic(cur_x, cur_y));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Clock {
|
struct Clock
|
||||||
|
{
|
||||||
using milliseconds = std::chrono::duration<std::uint16_t, std::milli>;
|
using milliseconds = std::chrono::duration<std::uint16_t, std::milli>;
|
||||||
|
|
||||||
// return elapsed time since last restart
|
// return elapsed time since last restart
|
||||||
[[nodiscard]] milliseconds restart() noexcept {
|
[[nodiscard]] milliseconds restart() noexcept
|
||||||
|
{
|
||||||
// stop Timer A
|
// stop Timer A
|
||||||
poke(0xDC0E, 0b00000000);
|
poke(0xDC0E, 0b00000000);
|
||||||
|
|
||||||
// last value
|
// last value
|
||||||
const auto previous_value = static_cast<std::uint16_t>(
|
const auto previous_value = static_cast<std::uint16_t>(peek(0xDC04) | (static_cast<uint16_t>(peek(0xDC05)) << 8));
|
||||||
peek(0xDC04) | (static_cast<uint16_t>(peek(0xDC05)) << 8));
|
|
||||||
|
|
||||||
// reset timer
|
// reset timer
|
||||||
poke(0xDC04, 0xFF);
|
poke(0xDC04, 0xFF);
|
||||||
@ -281,20 +243,18 @@ struct Clock {
|
|||||||
// restart timer A
|
// restart timer A
|
||||||
poke(0xDC0E, 0b00010001);
|
poke(0xDC0E, 0b00010001);
|
||||||
|
|
||||||
return milliseconds{0xFFFF - previous_value};
|
return milliseconds{ 0xFFFF - previous_value };
|
||||||
}
|
}
|
||||||
|
|
||||||
Clock() noexcept { [[maybe_unused]] const auto value = restart(); }
|
Clock() noexcept { [[maybe_unused]] const auto value = restart(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void cls() {
|
static void cls()
|
||||||
for (std::uint16_t i = 0x400; i < 0x400 + 1000; ++i) {
|
{
|
||||||
poke(i, 32);
|
for (std::uint16_t i = 0x400; i < 0x400 + 1000; ++i) { poke(i, 32); }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::uint8_t Width, std::uint8_t Height>
|
template<std::uint8_t Width, std::uint8_t Height> struct SimpleSprite
|
||||||
struct SimpleSprite
|
|
||||||
{
|
{
|
||||||
std::uint8_t x = 0;
|
std::uint8_t x = 0;
|
||||||
std::uint8_t y = 0;
|
std::uint8_t y = 0;
|
||||||
@ -302,32 +262,30 @@ struct SimpleSprite
|
|||||||
Graphic<Width, Height> graphic;
|
Graphic<Width, Height> graphic;
|
||||||
Graphic<Width, Height> saved_background{};
|
Graphic<Width, Height> saved_background{};
|
||||||
|
|
||||||
constexpr SimpleSprite(std::initializer_list<uint8_t> data_) noexcept
|
constexpr SimpleSprite(std::initializer_list<uint8_t> data_) noexcept : graphic(data_) {}
|
||||||
: graphic(data_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// helper type for the visitor #4
|
// helper type for the visitor #4
|
||||||
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
template<class... Ts> struct overloaded : Ts...
|
||||||
|
{
|
||||||
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
// explicit deduction guide (not needed as of C++20)
|
// explicit deduction guide (not needed as of C++20)
|
||||||
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||||
|
|
||||||
struct Screen
|
struct Screen
|
||||||
{
|
{
|
||||||
void load(std::uint8_t x, std::uint8_t y, auto &s) {
|
void load(std::uint8_t x, std::uint8_t y, auto &s)
|
||||||
|
{
|
||||||
for (std::uint8_t cur_y = 0; cur_y < s.height(); ++cur_y) {
|
for (std::uint8_t cur_y = 0; cur_y < s.height(); ++cur_y) {
|
||||||
for (std::uint8_t cur_x = 0; cur_x < s.width(); ++cur_x) {
|
for (std::uint8_t cur_x = 0; cur_x < s.width(); ++cur_x) { s(cur_x, cur_y) = loadc(cur_x + x, cur_y + y); }
|
||||||
s(cur_x, cur_y) = loadc(cur_x + x, cur_y + y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void show(std::uint8_t x, std::uint8_t y, auto &s) {
|
void show(std::uint8_t x, std::uint8_t y, auto &s)
|
||||||
if (s.is_shown) {
|
{
|
||||||
put_graphic(s.x, s.y, s.saved_background);
|
if (s.is_shown) { put_graphic(s.x, s.y, s.saved_background); }
|
||||||
}
|
|
||||||
|
|
||||||
s.is_shown = true;
|
s.is_shown = true;
|
||||||
|
|
||||||
@ -335,110 +293,36 @@ struct Screen
|
|||||||
s.y = y;
|
s.y = y;
|
||||||
load(x, y, s.saved_background);
|
load(x, y, s.saved_background);
|
||||||
|
|
||||||
put_graphic(x,y,s.graphic);
|
put_graphic(x, y, s.graphic);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
template<std::uint8_t Width, std::uint8_t Height>
|
||||||
//static constexpr auto charset = load_charset(uppercase);
|
struct Map;
|
||||||
|
|
||||||
static constexpr auto town =
|
struct GameState
|
||||||
Graphic<4,4> {
|
{
|
||||||
85,67,67,73,
|
|
||||||
93,233,223,93,
|
|
||||||
93,160,160,93,
|
|
||||||
74,67,67,75};
|
|
||||||
|
|
||||||
static constexpr auto mountain =
|
std::uint8_t endurance{ 10 };
|
||||||
Graphic<4,4> {
|
std::uint8_t stamina{ max_stamina() };
|
||||||
32,78,77,32,
|
std::uint16_t cash{ 100 };
|
||||||
32,32,78,77,
|
std::uint8_t x = 20;
|
||||||
78,77,32,32,
|
std::uint8_t y = 12;
|
||||||
32,78,77,32
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
auto character =
|
|
||||||
SimpleSprite<2,3> {
|
|
||||||
32,87,
|
|
||||||
78,79,
|
|
||||||
78,77
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static constexpr auto overview_map =
|
|
||||||
Graphic<10, 5> {
|
|
||||||
3,1,1,0,3,0,0,0,0,0,
|
|
||||||
0,0,1,1,0,0,0,0,3,0,
|
|
||||||
0,0,1,0,0,0,0,0,0,0,
|
|
||||||
0,3,0,0,0,0,0,0,0,0,
|
|
||||||
0,1,1,1,0,0,3,0,0,0,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cls();
|
|
||||||
|
|
||||||
poke(53280,0);
|
|
||||||
poke(53281,0);
|
|
||||||
|
|
||||||
static constexpr std::array<void (*)(std::uint8_t, std::uint8_t), 4> tile_types{
|
|
||||||
[](std::uint8_t x, std::uint8_t y) {
|
|
||||||
/* do nothing for 0th */
|
|
||||||
},
|
|
||||||
[](std::uint8_t x, std::uint8_t y) {
|
|
||||||
put_graphic(x,y,mountain);
|
|
||||||
},
|
|
||||||
[](std::uint8_t x, std::uint8_t y) {
|
|
||||||
/* do nothing for 2 */
|
|
||||||
},
|
|
||||||
[](std::uint8_t x, std::uint8_t y) {
|
|
||||||
put_graphic(x,y,town);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const auto draw_map = [](const auto &map) {
|
|
||||||
for (std::size_t tile = 0; tile < tile_types.size(); ++tile) {
|
|
||||||
for (std::uint8_t map_large_y =0; map_large_y < map.height(); ++map_large_y) {
|
|
||||||
for (std::uint8_t map_large_x = 0; map_large_x < map.width(); ++map_large_x) {
|
|
||||||
if (map(map_large_x,map_large_y) == tile) {
|
|
||||||
tile_types[tile](map_large_x*4,map_large_y*4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr auto draw_box = [](uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
|
|
||||||
putc(x,y, 85);
|
|
||||||
putc(x+width-1,y, 73);
|
|
||||||
putc(x+width-1,y+height-1,75);
|
|
||||||
putc(x,y+height-1,74);
|
|
||||||
|
|
||||||
for (uint8_t cur_x = x+1; cur_x < x+width-1; ++cur_x) {
|
|
||||||
putc(cur_x, y, 67);
|
|
||||||
putc(cur_x, y+height-1, 67);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t cur_y = y+1; cur_y < y+height-1; ++cur_y) {
|
|
||||||
putc(x, cur_y, 93);
|
|
||||||
putc(x+width-1, cur_y, 93);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct GameState {
|
|
||||||
|
|
||||||
std::uint8_t endurance{10};
|
|
||||||
std::uint8_t stamina{max_stamina()};
|
|
||||||
std::uint16_t cash{100};
|
|
||||||
|
|
||||||
Clock game_clock{};
|
Clock game_clock{};
|
||||||
|
|
||||||
constexpr std::uint8_t max_stamina() const noexcept {
|
Map<10, 5> const *current_map = nullptr;
|
||||||
return endurance * 5;
|
|
||||||
|
constexpr void execute_actions(const auto &character) noexcept
|
||||||
|
{
|
||||||
|
if (current_map) {
|
||||||
|
for (auto &action : current_map->actions) {
|
||||||
|
action.execute_if_collision(x,y,character.width(), character.height(), *this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::uint8_t max_stamina() const noexcept { return endurance * 5; }
|
||||||
|
|
||||||
struct JoyStick1StateChanged
|
struct JoyStick1StateChanged
|
||||||
{
|
{
|
||||||
@ -460,64 +344,177 @@ int main() {
|
|||||||
|
|
||||||
std::uint8_t last_joystick_2_state = peek(0xDC00);
|
std::uint8_t last_joystick_2_state = peek(0xDC00);
|
||||||
|
|
||||||
Event next_event() noexcept {
|
Event next_event() noexcept
|
||||||
|
{
|
||||||
const auto new_joystick_2_state = peek(0xDC00);
|
const auto new_joystick_2_state = peek(0xDC00);
|
||||||
|
|
||||||
if (new_joystick_2_state != last_joystick_2_state) {
|
if (new_joystick_2_state != last_joystick_2_state) {
|
||||||
last_joystick_2_state = new_joystick_2_state;
|
last_joystick_2_state = new_joystick_2_state;
|
||||||
return JoyStick2StateChanged{Joystick{new_joystick_2_state}};
|
return JoyStick2StateChanged{ Joystick{ new_joystick_2_state } };
|
||||||
}
|
}
|
||||||
|
|
||||||
return TimeElapsed{game_clock.restart()};
|
return TimeElapsed{ game_clock.restart() };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Map_Action
|
||||||
|
{
|
||||||
|
std::uint8_t x{};
|
||||||
|
std::uint8_t y{};
|
||||||
|
|
||||||
|
std::uint8_t width{};
|
||||||
|
std::uint8_t height{};
|
||||||
|
|
||||||
|
using Action_Func = void (*)(GameState &);
|
||||||
|
Action_Func action = nullptr;
|
||||||
|
|
||||||
|
constexpr void execute_if_collision(std::uint8_t obj_x, std::uint8_t obj_y, std::uint8_t obj_width, std::uint8_t obj_height, GameState &game) const {
|
||||||
|
if (action == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::uint8_t rect1_x1 = x;
|
||||||
|
const std::uint8_t rect1_x2 = x + width - 1;
|
||||||
|
const std::uint8_t rect1_y1 = y;
|
||||||
|
const std::uint8_t rect1_y2 = y + height - 1;
|
||||||
|
|
||||||
|
const std::uint8_t rect2_x1 = obj_x;
|
||||||
|
const std::uint8_t rect2_x2 = obj_x + obj_width - 1;
|
||||||
|
const std::uint8_t rect2_y1 = obj_y;
|
||||||
|
const std::uint8_t rect2_y2 = obj_y + obj_height - 1;
|
||||||
|
|
||||||
|
if (rect1_x1 < rect2_x2 && rect1_x2 > rect2_x1 &&
|
||||||
|
rect1_y1 < rect2_y2 && rect1_y2 > rect2_y1) {
|
||||||
|
action(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<std::uint8_t Width, std::uint8_t Height>
|
||||||
|
struct Map {
|
||||||
|
Graphic<Width, Height> layout;
|
||||||
|
|
||||||
|
std::span<const Map_Action> actions;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// static constexpr auto charset = load_charset(uppercase);
|
||||||
|
|
||||||
|
static constexpr auto town = Graphic<4, 4>{
|
||||||
|
85, 67, 67, 73,
|
||||||
|
93, 233, 223, 93,
|
||||||
|
93, 160, 160, 93,
|
||||||
|
74, 67, 67, 75 };
|
||||||
|
|
||||||
|
static constexpr auto mountain = Graphic<4, 4>{
|
||||||
|
32, 78, 77, 32,
|
||||||
|
32, 32, 78, 77,
|
||||||
|
78, 77, 32, 32,
|
||||||
|
32, 78, 77, 32 };
|
||||||
|
|
||||||
|
|
||||||
|
auto character = SimpleSprite<2, 3>{
|
||||||
|
32, 87,
|
||||||
|
78, 79,
|
||||||
|
78, 77 };
|
||||||
|
|
||||||
|
static constexpr auto overview_actions = std::array {
|
||||||
|
Map_Action { 12,0,4,4, [](GameState &g) { g.x = 30; g.y=5; } }
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr auto overview_map = Map<10, 5>{
|
||||||
|
{
|
||||||
|
3, 1, 1, 0, 3, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 1, 1, 0, 0, 0, 0, 3, 0,
|
||||||
|
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 1, 1, 1, 0, 0, 3, 0, 0, 0,
|
||||||
|
},
|
||||||
|
std::span<const Map_Action>(begin(overview_actions), end(overview_actions))
|
||||||
|
};
|
||||||
|
|
||||||
|
cls();
|
||||||
|
|
||||||
|
poke(53280, 0);
|
||||||
|
poke(53281, 0);
|
||||||
|
|
||||||
|
static constexpr std::array<void (*)(std::uint8_t, std::uint8_t), 4> tile_types{
|
||||||
|
[](std::uint8_t x, std::uint8_t y) {
|
||||||
|
/* do nothing for 0th */
|
||||||
|
},
|
||||||
|
[](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, mountain); },
|
||||||
|
[](std::uint8_t x, std::uint8_t y) {
|
||||||
|
/* do nothing for 2 */
|
||||||
|
},
|
||||||
|
[](std::uint8_t x, std::uint8_t y) { put_graphic(x, y, town); },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const auto draw_map = [](const auto &map) {
|
||||||
|
for (std::size_t tile = 0; tile < tile_types.size(); ++tile) {
|
||||||
|
for (std::uint8_t map_large_y = 0; map_large_y < map.height(); ++map_large_y) {
|
||||||
|
for (std::uint8_t map_large_x = 0; map_large_x < map.width(); ++map_large_x) {
|
||||||
|
if (map(map_large_x, map_large_y) == tile) { tile_types[tile](map_large_x * 4, map_large_y * 4); }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GameState game;
|
constexpr auto draw_box = [](uint8_t x, uint8_t y, uint8_t width, uint8_t height) {
|
||||||
|
putc(x, y, 85);
|
||||||
|
putc(x + width - 1, y, 73);
|
||||||
|
putc(x + width - 1, y + height - 1, 75);
|
||||||
|
putc(x, y + height - 1, 74);
|
||||||
|
|
||||||
// draw_map(map1);
|
for (uint8_t cur_x = x + 1; cur_x < x + width - 1; ++cur_x) {
|
||||||
draw_map(overview_map);
|
putc(cur_x, y, 67);
|
||||||
draw_box(0,20,40,5);
|
putc(cur_x, y + height - 1, 67);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t cur_y = y + 1; cur_y < y + height - 1; ++cur_y) {
|
||||||
|
putc(x, cur_y, 93);
|
||||||
|
putc(x + width - 1, cur_y, 93);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
GameState game;
|
||||||
|
game.current_map = &overview_map;
|
||||||
|
|
||||||
|
// draw_map(map1);
|
||||||
|
draw_map(game.current_map->layout);
|
||||||
|
draw_box(0, 20, 40, 5);
|
||||||
|
|
||||||
constexpr auto show_stats = [](const auto &cur_game) {
|
constexpr auto show_stats = [](const auto &cur_game) {
|
||||||
puts(1, 21, "stamina:");
|
puts(1, 21, "stamina:");
|
||||||
put_hex(12, 21, cur_game.stamina);
|
put_hex(12, 21, cur_game.stamina);
|
||||||
put_hex(15, 21, cur_game.max_stamina());
|
put_hex(15, 21, cur_game.max_stamina());
|
||||||
puts(14,21, "/");
|
puts(14, 21, "/");
|
||||||
puts(1, 22, "endurance:");
|
puts(1, 22, "endurance:");
|
||||||
put_hex(12,22, cur_game.endurance);
|
put_hex(12, 22, cur_game.endurance);
|
||||||
puts(1,23, "cash: ");
|
puts(1, 23, "cash: ");
|
||||||
put_hex(12,23, cur_game.cash);
|
put_hex(12, 23, cur_game.cash);
|
||||||
};
|
};
|
||||||
|
|
||||||
Screen screen;
|
Screen screen;
|
||||||
|
|
||||||
show_stats(game);
|
show_stats(game);
|
||||||
|
|
||||||
std::uint8_t x = 20;
|
auto eventHandler = overloaded{ [&](const GameState::JoyStick2StateChanged &e) {
|
||||||
std::uint8_t y = 12;
|
if (e.state.up()) { --game.y; }
|
||||||
|
if (e.state.down()) { ++game.y; }
|
||||||
|
if (e.state.left()) { --game.x; }
|
||||||
|
if (e.state.right()) { ++game.x; }
|
||||||
|
|
||||||
auto eventHandler = overloaded {
|
game.execute_actions(character.graphic);
|
||||||
[&](const GameState::JoyStick2StateChanged &e) {
|
|
||||||
if (e.state.up()) {
|
screen.show(game.x, game.y, character);
|
||||||
--y;
|
|
||||||
}
|
|
||||||
if (e.state.down()) {
|
|
||||||
++y;
|
|
||||||
}
|
|
||||||
if (e.state.left()) {
|
|
||||||
--x;
|
|
||||||
}
|
|
||||||
if (e.state.right()) {
|
|
||||||
++x;
|
|
||||||
}
|
|
||||||
screen.show(x, y, character);
|
|
||||||
|
|
||||||
put_hex(36, 1, e.state.state);
|
put_hex(36, 1, e.state.state);
|
||||||
},
|
},
|
||||||
[](const GameState::TimeElapsed &e) {
|
[](const GameState::TimeElapsed &e) { put_hex(36, 0, e.us.count()); } };
|
||||||
put_hex(36, 0, e.us.count());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
std::visit(eventHandler, game.next_event());
|
std::visit(eventHandler, game.next_event());
|
||||||
|
@ -815,7 +815,8 @@ void to_mos6502(const Personality &personality, const AVR &from_instruction, std
|
|||||||
const auto matched_gs = results.get<1>().to_string();
|
const auto matched_gs = results.get<1>().to_string();
|
||||||
instructions.emplace_back(ASMLine::Type::Directive, ".word " + matched_gs);
|
instructions.emplace_back(ASMLine::Type::Directive, ".word " + matched_gs);
|
||||||
} else {
|
} else {
|
||||||
spdlog::warn("Unknown .word directive");
|
instructions.emplace_back(ASMLine::Type::Directive, ".word " + from_instruction.text.substr(6));
|
||||||
|
// spdlog::warn("Unknown .word directive '{}'", from_instruction.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (from_instruction.text.starts_with(".byte")) {
|
} else if (from_instruction.text.starts_with(".byte")) {
|
||||||
|
Loading…
Reference in New Issue
Block a user