Nooncraft/src/main.cpp

284 lines
6.9 KiB
C++

#include "render.h"
#include "world.h"
#include "camera.h"
#include "game.h"
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <gint/rtc.h>
#include <gint/cpu.h>
#include <libprof.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// #define NOONCRAFT_ENABLE_USB
#ifdef NOONCRAFT_ENABLE_USB
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <gint/display.h>
static bool getkey_recording = false;
static bool getkey_global_shortcuts(key_event_t ev)
{
if(usb_is_open() && ev.key == KEY_XOT && !ev.shift && !ev.alpha) {
usb_fxlink_screenshot(true);
return true;
}
if(usb_is_open() && ev.key == KEY_FRAC && !ev.shift && !ev.alpha) {
if(!getkey_recording) {
dupdate_set_hook(GINT_CALL(usb_fxlink_videocapture, (int)false));
usb_fxlink_videocapture(true);
getkey_recording = true;
}
else {
dupdate_set_hook(GINT_CALL_NULL);
getkey_recording = false;
}
return true;
}
return false;
}
#endif /* NOONCRAFT_ENABLE_USB */
static char debugMessage[128];
static void renderGame(Game *game)
{
Camera *camera = game->camera;
ItemStack const &hand = game->inventory[27 + game->hotbarCursor];
renderClear();
GlyphCluster playerCluster(GLYPH_DEGREE_UNDERLINE, ' ',
GLYPH_CAPITAL_LAMBDA, ' ');
GlyphCluster cursorCluster(0, GLYPH_OPLUS, 0, 0);
if(!hand.item.isBlock) {
ItemInfo *info = Nooncraft::getItemInfo(hand.item);
if(info && info->isTool) {
if(info->toolKind == ToolKind::Pickaxe)
cursorCluster.glyphs[1] = GLYPH_NORTH_EAST_ARROW;
else if(info->toolKind == ToolKind::Axe)
cursorCluster.glyphs[1] = 'P';
else if(info->toolKind == ToolKind::Shovel)
cursorCluster.glyphs[1] = 'b';
}
}
if(game->isBreakingBlock()) {
static Glyph breakingGlyphs[4] = {
GLYPH_MIDDLE_DOT, GLYPH_SMALL_SQUARE, GLYPH_CURRENCY_SIGN, 0x7f,
};
int stage = game->blockBreakingProgress();
cursorCluster.glyphs[1] = breakingGlyphs[stage];
}
Nooncraft::renderCamera(26, 12, camera, game->playerPos, playerCluster,
game->cursorPos, cursorCluster);
GlyphCluster invLeft(' ', '{', ' ', '{');
GlyphCluster invRight('}', ' ', '}', ' ');
int hudY = 27;
if(hand.qty > 1)
renderFormat(22, hudY+1, "HAND: %s (%d)", hand.name(), hand.qty);
else
renderFormat(22, hudY+1, "HAND: %s", hand.name());
renderFormat(46, hudY+1, "X%d Y%d", game->playerPos.x, game->playerPos.y);
BlockInfo *pointedBlockInfo = game->pointedBlockInfo();
char const *pointedBlockName =
pointedBlockInfo ? pointedBlockInfo->name : "(NOTHING)";
renderFormat(22, hudY+2, "CURSOR: %s", pointedBlockName);
renderFormat(22, hudY+3, debugMessage);
renderCluster(0, hudY+1, invLeft);
for(int i = 0; i < 9; i++) {
ItemStack const &stack = game->inventory[27 + i];
renderCluster(2 + 2*i, hudY+1, stack.cluster());
if(!stack.isNull() && stack.qty > 1)
renderFormat(2+2*i, hudY+3, "%2d", stack.qty);
}
renderCluster(20, hudY+1, invRight);
for(int i = 0; i < 28; i++) {
if(i == 1 + game->hotbarCursor)
renderText(2*i, hudY, "vv");
else
renderText(2*i, hudY, "--");
}
}
bool titleScreen(void)
{
int selection = 0;
while(1) {
renderClear();
renderText(22, 5, "+---------+");
renderText(22, 6, "|NOONCRAFT|");
renderText(22, 7, "+---------+");
if(selection == 0)
renderText(19, 10, "[PLAY DEMO WORLD]");
else
renderText(20, 10, "PLAY DEMO WORLD");
if(selection == 1)
renderText(18, 12, "[PLAY RANDOM WORLD]");
else
renderText(19, 12, "PLAY RANDOM WORLD");
renderUpdate();
int opt = GETKEY_DEFAULT & ~GETKEY_MOD_SHIFT & ~GETKEY_MOD_ALPHA;
int key = getkey_opt(opt, NULL).key;
if(key == KEY_EXE || key == KEY_SHIFT)
return selection == 1;
if(key == KEY_UP)
selection = 0;
if(key == KEY_DOWN)
selection = 1;
}
}
bool confirmExit(void)
{
renderClear();
renderText(1, 1, "QUIT? THE WORLD WILL BE LOST.");
renderText(1, 2, "F1: YES, QUIT");
renderText(1, 3, "F6: NO, GO BACK");
renderUpdate();
while(1) {
int opt = GETKEY_DEFAULT & ~GETKEY_MENU;
int key = getkey_opt(opt, NULL).key;
if(key == KEY_F1)
return true;
if(key == KEY_F6)
return false;
}
}
int main(void)
{
prof_init();
bool random = titleScreen();
srand(random ? rtc_ticks() : 0xc0ffee);
#ifdef NOONCRAFT_ENABLE_USB
usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
usb_open(interfaces, GINT_CALL_NULL);
getkey_set_feature_function(getkey_global_shortcuts);
#endif /* NOONCRAFT_ENABLE_USB */
/* Should be a square */
World *world = Nooncraft::mkWorld(128, 128);
if(!world)
return 0;
renderClear();
renderText(0, 0, "GENERATING WORLD...");
renderUpdate();
Nooncraft::genWorld(world);
Camera *camera = new Camera(world);
camera->visible = WorldRect(-13, 14, -6, 6);
Game game;
game.world = world;
game.camera = camera;
game.playerPos = world->findSpawnPoint();
// TODO: Potential world border overflow here (unlikely)
game.cursorPos = game.playerPos + WorldCoord::Right;
game.damageTicks = -1;
game.hotbarCursor = 0;
game.inventory[27] = ItemStack(Item(ItemID::WOODEN_PICKAXE));
volatile int nextFrame = 1;
int t = timer_configure(TIMER_ANY, 1000000/20, GINT_CALL_SET(&nextFrame));
timer_start(t);
bool runMainLoop = true;
int frameDuration = 0;
int tick = 0;
while(runMainLoop) {
while(!nextFrame)
sleep();
nextFrame = 0;
tick++;
frameDuration = prof_exec({
sprintf(debugMessage, "FRAME: %d MS", frameDuration);
// sprintf(debugMessage, "VORONOI: %d MS", voronoiTime / 1000);
renderGame(&game);
renderUpdate();
}) / 1000;
key_event_t ev;
while((ev = pollevent()).type != KEYEV_NONE) {
if(ev.type == KEYEV_UP) {
if(ev.key == KEY_OPTN) {
game.damageTicks = -1;
continue;
}
continue;
}
#ifdef NOONCRAFT_ENABLE_USB
if(getkey_global_shortcuts(ev))
continue;
#endif
if(ev.key == KEY_MENU && confirmExit())
runMainLoop = false;
int digit = keycode_digit(ev.key);
if(digit >= 1 && digit <= 9 && !game.isBreakingBlock()) {
game.hotbarCursor = digit - 1;
}
}
/* Clamp speed to 10 blocks/s */
if(tick % 2 == 0 && !game.isBreakingBlock()) {
if(keydown(KEY_LEFT) && !keydown(KEY_SHIFT))
game.movePlayerBy(WorldCoord::Left);
if(keydown(KEY_RIGHT) && !keydown(KEY_SHIFT))
game.movePlayerBy(WorldCoord::Right);
if(keydown(KEY_UP) && !keydown(KEY_SHIFT))
game.movePlayerBy(WorldCoord::Up);
if(keydown(KEY_DOWN) && !keydown(KEY_SHIFT))
game.movePlayerBy(WorldCoord::Down);
if(keydown(KEY_LEFT) && keydown(KEY_SHIFT))
game.moveCursorBy(WorldCoord::Left);
if(keydown(KEY_RIGHT) && keydown(KEY_SHIFT))
game.moveCursorBy(WorldCoord::Right);
if(keydown(KEY_UP) && keydown(KEY_SHIFT))
game.moveCursorBy(WorldCoord::Up);
if(keydown(KEY_DOWN) && keydown(KEY_SHIFT))
game.moveCursorBy(WorldCoord::Down);
}
if(keydown(KEY_OPTN) && !game.isBreakingBlock()) {
if(game.world->canBreakBlock(game.cursorPos))
game.damageTicks = 0;
}
if(keydown(KEY_VARS) && !game.isBreakingBlock()) {
game.place();
}
game.updateBlockBreaking();
}
timer_stop(t);
delete camera;
delete world;
prof_quit();
return 1;
}