render, block, world: first prototype
This commit is contained in:
parent
56fb2c8366
commit
b92cbcec5b
|
@ -5,7 +5,7 @@
|
|||
/*.g3a
|
||||
|
||||
# Python bytecode
|
||||
__pycache__/
|
||||
__pycache__/
|
||||
|
||||
# Common IDE files
|
||||
*.sublime-project
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
project(Nooncraft)
|
||||
project(Nooncraft LANGUAGES CXX)
|
||||
|
||||
include(GenerateG3A)
|
||||
include(Fxconv)
|
||||
find_package(Gint 2.8 REQUIRED)
|
||||
|
||||
set(SOURCES
|
||||
src/main.c
|
||||
# ...
|
||||
)
|
||||
# Shared assets, fx-9860G-only assets and fx-CG-50-only assets
|
||||
src/block.cpp
|
||||
src/graphics.cpp
|
||||
src/main.cpp
|
||||
src/render.cpp
|
||||
src/world.cpp)
|
||||
set(ASSETS
|
||||
# ...
|
||||
)
|
||||
assets-cg/font_nooncraft.png
|
||||
assets-cg/blockinfo.yaml)
|
||||
|
||||
fxconv_declare_assets(${ASSETS} WITH_METADATA)
|
||||
fxconv_declare_converters(converters.py)
|
||||
|
||||
add_executable(addin ${SOURCES} ${ASSETS})
|
||||
target_compile_options(addin PRIVATE -Wall -Wextra -Os)
|
||||
target_link_libraries(addin Gint::Gint)
|
||||
target_compile_options(addin PRIVATE -Wall -Wextra -Wno-narrowing -Os -std=c++20)
|
||||
target_link_libraries(addin Gint::Gint -lsupc++)
|
||||
|
||||
if("${FXSDK_PLATFORM_LONG}" STREQUAL fx9860G)
|
||||
message(FATAL_ERROR "This game is not supported on fx-9860G!")
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
- name: "AIR"
|
||||
cluster: " "
|
||||
walkable: yes
|
||||
breakability: Fluid
|
||||
|
||||
- name: "STONE"
|
||||
cluster: "□□□□"
|
||||
toolKind: Pickaxe
|
||||
|
||||
- name: "COBBLESTONE"
|
||||
cluster: "####"
|
||||
toolKind: Pickaxe
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,10 @@
|
|||
font_nooncraft.png:
|
||||
type: font
|
||||
name: font_nooncraft
|
||||
charset: ascii
|
||||
grid.size: 5x5
|
||||
grid.padding: 1
|
||||
|
||||
blockinfo.yaml:
|
||||
custom-type: blockinfo
|
||||
name: Nooncraft_blockInfo
|
Binary file not shown.
|
@ -0,0 +1,92 @@
|
|||
import fxconv
|
||||
import yaml
|
||||
|
||||
def convert(input, output, params, target):
|
||||
recognized = True
|
||||
if params["custom-type"] == "blockinfo":
|
||||
o = convert_blockinfo(input, params)
|
||||
else:
|
||||
recognized = False
|
||||
|
||||
if recognized:
|
||||
fxconv.elf(o, output, "_" + params["name"], **target)
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
def mkBreakability(br):
|
||||
return fxconv.u8({
|
||||
None: 0,
|
||||
"Fluid": 0,
|
||||
"ByAnything": 1,
|
||||
"ByTool": 2,
|
||||
"Unbreakable": 3,
|
||||
}[br])
|
||||
|
||||
def mkToolKind(tk):
|
||||
return fxconv.u8({
|
||||
None: 0,
|
||||
"Pickaxe": 0,
|
||||
"Axe": 1,
|
||||
"Shovel": 2,
|
||||
"Hoe": 3,
|
||||
}[tk])
|
||||
|
||||
def mkBool(b):
|
||||
if isinstance(b, str):
|
||||
b = b.lower()
|
||||
return fxconv.u8(b in [True, "yes", "true"])
|
||||
|
||||
def mkGlyph(s):
|
||||
assert len(s) == 1
|
||||
special = {
|
||||
0x2058: 1,
|
||||
0x00B7: 2,
|
||||
0x2225: 3,
|
||||
0x00A4: 4,
|
||||
0x2197: 5,
|
||||
0x00BB: 6,
|
||||
0x2193: 7,
|
||||
0x00EE: 8,
|
||||
0x222B: 9,
|
||||
0x25AA: 10,
|
||||
0x2605: 11,
|
||||
0x25A1: 0x7f,
|
||||
}
|
||||
if ord(s) >= 0x20 and ord(s) <= 0x7f:
|
||||
return fxconv.u8(ord(s))
|
||||
elif ord(s) in special:
|
||||
return fxconv.u8(special[ord(s)])
|
||||
else:
|
||||
raise ValueError(f"unknown glyph {s}")
|
||||
|
||||
def mkGlyphCluster(str):
|
||||
assert len(str) == 4
|
||||
return b"".join(mkGlyph(s) for s in str)
|
||||
|
||||
def convert_blockinfo(input, params):
|
||||
with open(input, "r") as fp:
|
||||
data = yaml.safe_load(fp.read())
|
||||
|
||||
o = fxconv.ObjectData()
|
||||
|
||||
for b in data:
|
||||
# Make sure there are no typos in the fields
|
||||
assert (f in ["name", "breakability", "toolKind",
|
||||
"baseBreakDurationTicks", "walkable"] for f in b)
|
||||
|
||||
# If a tool is specified, default to Breakability::ByTool
|
||||
tk = b.get("toolKind", None)
|
||||
br = b.get("breakability", "ByTool" if tk is not None else "Fluid")
|
||||
|
||||
o += fxconv.string(b["name"])
|
||||
o += mkGlyphCluster(b["cluster"])
|
||||
o += mkBreakability(br)
|
||||
o += mkToolKind(tk)
|
||||
o += fxconv.u16(int(b.get("baseBreakDurationTicks", "20")))
|
||||
o += mkBool(b.get("walkable", False))
|
||||
o += bytes(3)
|
||||
|
||||
o += fxconv.sym("Nooncraft_blockInfoCount")
|
||||
o += fxconv.u32(len(data))
|
||||
return o
|
|
@ -0,0 +1,17 @@
|
|||
#include "block.h"
|
||||
|
||||
extern "C" {
|
||||
extern BlockInfo Nooncraft_blockInfo[];
|
||||
extern int Nooncraft_blockInfoCount;
|
||||
}
|
||||
|
||||
namespace Nooncraft {
|
||||
|
||||
BlockInfo *getBlockInfo(Block b)
|
||||
{
|
||||
if(b >= Nooncraft_blockInfoCount)
|
||||
return nullptr;
|
||||
return &Nooncraft_blockInfo[b];
|
||||
}
|
||||
|
||||
} /* namespace Nooncraft */
|
|
@ -0,0 +1,35 @@
|
|||
// nooncraft.block: Block data in world map and general block information
|
||||
|
||||
#pragma once
|
||||
#include "item.h"
|
||||
#include "render.h"
|
||||
#include <cstdint>
|
||||
|
||||
using Block = uint16_t;
|
||||
|
||||
enum class Breakability: uint8_t {
|
||||
Fluid,
|
||||
ByAnything,
|
||||
ByTool,
|
||||
Unbreakable,
|
||||
};
|
||||
|
||||
/* General information on blocks */
|
||||
struct BlockInfo
|
||||
{
|
||||
char const *name;
|
||||
|
||||
// TODO: Upgrade to random and/or dimension-specific sprites
|
||||
GlyphCluster cluster;
|
||||
|
||||
Breakability breakability;
|
||||
ToolKind toolKind;
|
||||
int16_t baseBreakDurationTicks;
|
||||
bool walkable;
|
||||
};
|
||||
|
||||
namespace Nooncraft {
|
||||
|
||||
BlockInfo *getBlockInfo(Block b);
|
||||
|
||||
} /* namespace Nooncraft */
|
|
@ -0,0 +1,19 @@
|
|||
#include "graphics.h"
|
||||
#include "render.h"
|
||||
|
||||
namespace Nooncraft {
|
||||
|
||||
void renderCamera(int x, int y, Camera *camera)
|
||||
{
|
||||
if(!camera)
|
||||
return;
|
||||
|
||||
WorldRect r = camera->region;
|
||||
for(int dy = r.ymin; dy <= r.ymax; dy++)
|
||||
for(int dx = r.xmin; dx <= r.xmax; dx++) {
|
||||
GlyphCluster c('@', '#', '~', '&');
|
||||
renderCluster(x+2*dx, y+2*dy, c);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace Nooncraft */
|
|
@ -0,0 +1,24 @@
|
|||
// nooncraft.graphics: Application-level rendering logic
|
||||
|
||||
#pragma once
|
||||
#include "world.h"
|
||||
|
||||
struct Camera
|
||||
{
|
||||
Camera(World const *w): world {w}, center {0,0}, region {-1,1,-1,1} {}
|
||||
|
||||
/* Underlying world object */
|
||||
World const *world;
|
||||
|
||||
/* Coordinates of the center point */
|
||||
WorldCoord center;
|
||||
/* Local rectangle around center at (0,0). This influences how much of the
|
||||
screen the camera will take up when rendered */
|
||||
WorldRect region;
|
||||
};
|
||||
|
||||
namespace Nooncraft {
|
||||
|
||||
void renderCamera(int x, int y, Camera *camera);
|
||||
|
||||
} /* namespace Nooncraft */
|
|
@ -0,0 +1,8 @@
|
|||
// nooncraft.item: Item storage and properties
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
enum class ToolKind: uint8_t {
|
||||
Pickaxe, Axe, Shovel, Hoe,
|
||||
};
|
12
src/main.c
12
src/main.c
|
@ -1,12 +0,0 @@
|
|||
#include <gint/display.h>
|
||||
#include <gint/keyboard.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
dclear(C_WHITE);
|
||||
dtext(1, 1, C_BLACK, "Sample fxSDK add-in.");
|
||||
dupdate();
|
||||
|
||||
getkey();
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
#include "render.h"
|
||||
#include "world.h"
|
||||
#include "graphics.h"
|
||||
#include <gint/keyboard.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
World *world = Nooncraft::mkWorld(128, 128);
|
||||
if(!world)
|
||||
return 0;
|
||||
|
||||
Nooncraft::genWorld(world);
|
||||
|
||||
Camera *camera = new Camera(world);
|
||||
camera->region = WorldRect(-13, 14, -6, 6);
|
||||
|
||||
// -
|
||||
|
||||
char separator[57];
|
||||
memset(separator, '-', 56);
|
||||
separator[56] = 0;
|
||||
|
||||
renderClear();
|
||||
Nooncraft::renderCamera(26, 12, camera);
|
||||
|
||||
// HUD
|
||||
|
||||
GlyphCluster invLeft(' ', GLYPH_PARALLEL_TO, ' ', GLYPH_PARALLEL_TO);
|
||||
GlyphCluster invRight(GLYPH_PARALLEL_TO, ' ', GLYPH_PARALLEL_TO, ' ');
|
||||
int hudY = 27;
|
||||
|
||||
renderText(0, hudY, separator);
|
||||
renderText(24, hudY+1, "COBBLESTONE");
|
||||
renderCluster(0, hudY+1, invLeft);
|
||||
renderCluster(2, hudY+1, Nooncraft::getBlockInfo(2)->cluster);
|
||||
renderCluster(20, hudY+1, invRight);
|
||||
renderText(2, hudY+3, "1 2 3 4 5 6 7 8 9");
|
||||
|
||||
// -
|
||||
|
||||
renderText(0, 0, "NOONCRAFT");
|
||||
renderUpdate();
|
||||
|
||||
getkey();
|
||||
|
||||
//-
|
||||
|
||||
delete camera;
|
||||
delete world;
|
||||
|
||||
return 1;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
#include "render.h"
|
||||
#include <gint/display.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
extern "C" {
|
||||
extern font_t font_nooncraft;
|
||||
}
|
||||
|
||||
GCONSTRUCTOR
|
||||
static void init_font(void)
|
||||
{
|
||||
dfont(&font_nooncraft);
|
||||
}
|
||||
|
||||
static bool nightMode = false;
|
||||
|
||||
static inline int fg()
|
||||
{
|
||||
return nightMode ? C_WHITE : C_BLACK;
|
||||
}
|
||||
static inline int bg()
|
||||
{
|
||||
return nightMode ? C_BLACK : C_WHITE;
|
||||
}
|
||||
static inline void dglyph(int x, int y, Glyph g)
|
||||
{
|
||||
dtext_opt(x, y, fg(), bg(), DTEXT_LEFT, DTEXT_TOP, &g, 1);
|
||||
}
|
||||
|
||||
void renderSetNight(bool night)
|
||||
{
|
||||
nightMode = night;
|
||||
}
|
||||
|
||||
void renderClear(void)
|
||||
{
|
||||
dclear(bg());
|
||||
}
|
||||
|
||||
void renderUpdate(void)
|
||||
{
|
||||
dupdate();
|
||||
}
|
||||
|
||||
static int cellX(int x, bool text)
|
||||
{
|
||||
return 4 + 7 * x - (!text && (x & 1));
|
||||
}
|
||||
|
||||
static int cellY(int y, bool text)
|
||||
{
|
||||
(void)text;
|
||||
return 2 + 7 * y - (y & 1);
|
||||
}
|
||||
|
||||
void renderGlyph(int x, int y, Glyph g)
|
||||
{
|
||||
dglyph(cellX(x, true), cellY(y, true), g);
|
||||
}
|
||||
|
||||
void renderCluster(int x, int y, GlyphCluster c)
|
||||
{
|
||||
int px = cellX(x & -2, false);
|
||||
int py = cellY(y & -2, false);
|
||||
|
||||
dglyph(px, py, c.glyphs[0]);
|
||||
dglyph(px+6, py, c.glyphs[1]);
|
||||
dglyph(px, py+6, c.glyphs[2]);
|
||||
dglyph(px+6, py+6, c.glyphs[3]);
|
||||
}
|
||||
|
||||
void renderText(int x, int y, char const *text)
|
||||
{
|
||||
for(int i = 0; text[i]; i++)
|
||||
renderGlyph(x + i, y, text[i]);
|
||||
}
|
||||
|
||||
void renderFormat(int x, int y, char const *fmt, ...)
|
||||
{
|
||||
static char str[128];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(str, sizeof str, fmt, args);
|
||||
va_end(args);
|
||||
renderText(x, y, str);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// nooncraft.render: Grid-like text rendering
|
||||
//
|
||||
// Owing to the CPC constraint, the entire rendering system for this game is
|
||||
// just text with a single font. We make two adjustments on the grid model:
|
||||
//
|
||||
// 1. We group rows and columns by pairs, so that the row/column spacing
|
||||
// alternates between 1 and 3. This allows blocks to be represented by
|
||||
// "clusters" of 4 characters.
|
||||
// 2. To keep text natural, we provide a text function which forces column
|
||||
// spacing to 2, offsetting every other character by 1 pixel. Rows remain
|
||||
// irregularly spaced.
|
||||
//---
|
||||
|
||||
#pragma once
|
||||
|
||||
using Glyph = char;
|
||||
|
||||
/* Non-ASCII glyphs */
|
||||
enum {
|
||||
GLYPH_FOUR_DOT = 1, /* U+2058 FOUR DOT PUNCTUATION */
|
||||
GLYPH_MIDDLE_DOT = 2, /* U+00B7 MIDDLE DOT */
|
||||
GLYPH_PARALLEL_TO = 3, /* U+2225 PARALLEL TO */
|
||||
GLYPH_CURRENCY_SIGN = 4, /* U+00A4 CURRENCY SIGN */
|
||||
GLYPH_NORTH_EAST_ARROW = 5, /* U+2197 NORTH EAST ARROW */
|
||||
GLYPH_RIGHT_GUILLEMET = 6, /* U+00BB RIGHT GUILLEMET */
|
||||
GLYPH_DOWN_ARROW = 7, /* U+2193 DOWNARDS ARROW */
|
||||
GLYPH_I_CIRCUMFLEX = 8, /* U+00EE SMALL LATIN I WITH CIRCUMFLEX */
|
||||
GLYPH_INTEGRAL = 9, /* U+222B INTEGRAL */
|
||||
GLYPH_SMALL_SQUARE = 10, /* U+25AA BLACK SMALL SQUARE */
|
||||
GLYPH_STAR = 11, /* U+2605 BLACK STAR */
|
||||
};
|
||||
|
||||
/* A cluster of 4 glyphs. Can be conversion-constructed from a multi-byte
|
||||
character literal like 'AXE '. */
|
||||
struct GlyphCluster
|
||||
{
|
||||
GlyphCluster(Glyph g1, Glyph g2, Glyph g3, Glyph g4):
|
||||
glyphs {g1, g2, g3, g4}
|
||||
{}
|
||||
|
||||
GlyphCluster(int mbliteral) {
|
||||
this->glyphs[0] = mbliteral >> 24;
|
||||
this->glyphs[1] = (mbliteral >> 16) & 0xff;
|
||||
this->glyphs[2] = (mbliteral >> 8) & 0xff;
|
||||
this->glyphs[3] = mbliteral & 0xff;
|
||||
}
|
||||
|
||||
Glyph glyphs[4];
|
||||
};
|
||||
|
||||
/* Enable or disable night mode (black-on-white). */
|
||||
void renderSetNight(bool night);
|
||||
/* Clear the screen. */
|
||||
void renderClear(void);
|
||||
/* Update the screen. */
|
||||
void renderUpdate(void);
|
||||
|
||||
/* Render a single character with text alignment (2-pixel column spacing).
|
||||
The position (x,y) is counted in characters units with (0,0) top-left. */
|
||||
void renderGlyph(int x, int y, Glyph g);
|
||||
|
||||
/* Render a 2x2 cluster of 4 characters. The position (x,y) should be even on
|
||||
both axes. */
|
||||
void renderCluster(int x, int y, GlyphCluster c);
|
||||
|
||||
/* Render a string with text alignment. */
|
||||
void renderText(int x, int y, char const *text);
|
||||
/* Same with printf() formatting. */
|
||||
void renderFormat(int x, int y, char const *fmt, ...);
|
|
@ -0,0 +1,71 @@
|
|||
#include "world.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
WorldCoord WorldCoord::Up(0, -1);
|
||||
WorldCoord WorldCoord::Down(0, 1);
|
||||
WorldCoord WorldCoord::Left(-1, 0);
|
||||
WorldCoord WorldCoord::Right(1, 0);
|
||||
|
||||
namespace Nooncraft {
|
||||
|
||||
World *mkWorld(int width, int height)
|
||||
{
|
||||
WorldRect l, br;
|
||||
|
||||
World *w = (World *)malloc(sizeof *w);
|
||||
if(!w) goto fail;
|
||||
|
||||
w->cells = (Block *)malloc(width * height * sizeof *w->cells);
|
||||
if(!w->cells) goto fail;
|
||||
|
||||
l = WorldRect(
|
||||
-width / 2, width - width / 2,
|
||||
-height / 2, height - height / 2);
|
||||
br = WorldRect(
|
||||
l.xmin + 2, l.xmax - 2,
|
||||
l.ymin + 2, l.ymax - 2);
|
||||
|
||||
w->limits = l;
|
||||
w->worldBorder = br;
|
||||
return w;
|
||||
|
||||
fail:
|
||||
if(w)
|
||||
free(w->cells);
|
||||
free(w);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void genWorld(World *w)
|
||||
{
|
||||
memset(w->cells, 0, w->cellDataSize());
|
||||
|
||||
int x1 = w->worldBorder.xmin + 1;
|
||||
int x2 = w->worldBorder.xmax - 1;
|
||||
int y1 = w->worldBorder.ymin + 1;
|
||||
int y2 = w->worldBorder.ymax - 1;
|
||||
|
||||
for(int x = x1; x <= x2; x++) {
|
||||
w->cellAt(x, y1) = 1; // TODO: Use cobblestone enum?
|
||||
w->cellAt(x, y2) = 1;
|
||||
}
|
||||
for(int y = y1; y <= y2; y++) {
|
||||
w->cellAt(x1, y) = 1;
|
||||
w->cellAt(x2, y) = 1;
|
||||
}
|
||||
|
||||
for(int x = -1; x <= +1; x++)
|
||||
for(int y = -1; y <= +1; y++) {
|
||||
if(x || y)
|
||||
w->cellAt(x, y) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void freeWorld(World *w)
|
||||
{
|
||||
free(w->cells);
|
||||
free(w);
|
||||
}
|
||||
|
||||
} /* namespace Nooncraft */
|
|
@ -0,0 +1,92 @@
|
|||
// nooncraft.world: World data and structures
|
||||
|
||||
#pragma once
|
||||
#include "block.h"
|
||||
#include <stddef.h>
|
||||
#include <gint/defs/attributes.h>
|
||||
|
||||
struct WorldCoord
|
||||
{
|
||||
int16_t x, y;
|
||||
|
||||
constexpr WorldCoord(): x {0}, y {0} {}
|
||||
constexpr WorldCoord(int _x, int _y): x {(int16_t)_x}, y {(int16_t)_y} {}
|
||||
|
||||
inline constexpr WorldCoord &operator+=(WorldCoord const &other) {
|
||||
this->x += other.x;
|
||||
this->y += other.y;
|
||||
return *this;
|
||||
}
|
||||
inline constexpr WorldCoord operator-=(WorldCoord const &other) {
|
||||
this->x -= other.x;
|
||||
this->y -= other.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
static WorldCoord Up, Down, Left, Right;
|
||||
};
|
||||
|
||||
inline constexpr WorldCoord operator+(WorldCoord l, WorldCoord const &r) {
|
||||
return (l += r);
|
||||
}
|
||||
inline constexpr WorldCoord operator-(WorldCoord l, WorldCoord const &r) {
|
||||
return (l -= r);
|
||||
}
|
||||
|
||||
struct WorldRect
|
||||
{
|
||||
/* All included */
|
||||
int16_t xmin, xmax;
|
||||
int16_t ymin, ymax;
|
||||
|
||||
constexpr WorldRect(): xmin {0}, xmax {0}, ymin {0}, ymax {0} {}
|
||||
constexpr WorldRect(int _xmin, int _xmax, int _ymin, int _ymax):
|
||||
xmin {(int16_t)_xmin}, xmax {(int16_t)_xmax},
|
||||
ymin {(int16_t)_ymin}, ymax {(int16_t)_ymax} {}
|
||||
|
||||
int width() const {
|
||||
return xmax - xmin + 1;
|
||||
}
|
||||
int height() const {
|
||||
return ymax - ymin + 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct World
|
||||
{
|
||||
/* Map data limits (ie. how far blocks exist) */
|
||||
WorldRect limits;
|
||||
/* World border position */
|
||||
WorldRect worldBorder;
|
||||
|
||||
/* Block cells in row-major order */
|
||||
Block *cells;
|
||||
|
||||
int cellCount() const {
|
||||
return limits.width() * limits.height();
|
||||
}
|
||||
size_t cellDataSize() const {
|
||||
return cellCount() * sizeof(*cells);
|
||||
}
|
||||
GINLINE Block const &cellAt(int16_t x, int16_t y) const {
|
||||
int ix = (x + limits.xmin) + (y + limits.ymin) * limits.width();
|
||||
return cells[ix];
|
||||
}
|
||||
GINLINE Block &cellAt(int16_t x, int16_t y) {
|
||||
int ix = (x + limits.xmin) + (y + limits.ymin) * limits.width();
|
||||
return cells[ix];
|
||||
}
|
||||
};
|
||||
|
||||
namespace Nooncraft {
|
||||
|
||||
/* Make an empty uninitialized world map. */
|
||||
World *mkWorld(int width, int height);
|
||||
|
||||
/* Run the world generator, initializing the entire world. */
|
||||
void genWorld(World *w);
|
||||
|
||||
/* Free a world object. */
|
||||
void freeWorld(World *w);
|
||||
|
||||
} /* namespace Nooncraft */
|
Loading…
Reference in New Issue