Kittens, now for real. Also a lightweight curses relacement. Use it, love it.

develop
Petr Mrázek 2011-06-17 02:09:03 +02:00
parent 93be1eb1fb
commit 4da11927af
3 changed files with 588 additions and 20 deletions

@ -167,26 +167,26 @@ SDL_mutexP
SDL_DestroyMutex
void SDLCALL SDL_DestroyMutex(SDL_mutex *mutex);
*/
static vPtr (*_SDL_CreateMutex)(void) = 0;
DFhackCExport vPtr SDL_CreateMutex(void)
static DFMutex * (*_SDL_CreateMutex)(void) = 0;
DFhackCExport DFMutex * SDL_CreateMutex(void)
{
return _SDL_CreateMutex();
}
static int (*_SDL_mutexP)(vPtr mutex) = 0;
DFhackCExport int SDL_mutexP(vPtr mutex)
static int (*_SDL_mutexP)(DFMutex * mutex) = 0;
DFhackCExport int SDL_mutexP(DFMutex * mutex)
{
return _SDL_mutexP(mutex);
}
static int (*_SDL_mutexV)(vPtr mutex) = 0;
DFhackCExport int SDL_mutexV(vPtr mutex)
static int (*_SDL_mutexV)(DFMutex * mutex) = 0;
DFhackCExport int SDL_mutexV(DFMutex * mutex)
{
return _SDL_mutexV(mutex);
}
static void (*_SDL_DestroyMutex)(vPtr mutex) = 0;
DFhackCExport void SDL_DestroyMutex(vPtr mutex)
static void (*_SDL_DestroyMutex)(DFMutex * mutex) = 0;
DFhackCExport void SDL_DestroyMutex(DFMutex * mutex)
{
_SDL_DestroyMutex(mutex);
}
@ -661,8 +661,8 @@ DFhackCExport void *SDL_CreateSemaphore(uint32_t initial_value)
return _SDL_CreateSemaphore(initial_value);
}
static void * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0;
DFhackCExport void *SDL_CreateThread(int (*fn)(void *), void *data)
static DFThread * (*_SDL_CreateThread)(int (*fn)(void *), void *data) = 0;
DFhackCExport DFThread *SDL_CreateThread(int (*fn)(void *), void *data)
{
if(!inited)
FirstCall();
@ -759,11 +759,11 @@ bool FirstCall()
_SDL_CondWait = (int (*)(void*, void*))GetProcAddress(realSDLlib,"SDL_CondWait");
_SDL_ConvertSurface = (void*(*)(void*, void*, uint32_t))GetProcAddress(realSDLlib,"SDL_ConvertSurface");
_SDL_CreateCond = (void*(*)())GetProcAddress(realSDLlib,"SDL_CreateCond");
_SDL_CreateMutex = (void*(*)())GetProcAddress(realSDLlib,"SDL_CreateMutex");
_SDL_CreateMutex = (DFMutex*(*)())GetProcAddress(realSDLlib,"SDL_CreateMutex");
_SDL_CreateRGBSurface = (void*(*)(uint32_t, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_CreateRGBSurface");
_SDL_CreateRGBSurfaceFrom = (void*(*)(void*, int, int, int, int, uint32_t, uint32_t, uint32_t, uint32_t))GetProcAddress(realSDLlib,"SDL_CreateRGBSurfaceFrom");
_SDL_DestroyCond = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_DestroyCond");
_SDL_DestroyMutex = (void (*)(void*))GetProcAddress(realSDLlib,"SDL_DestroyMutex");
_SDL_DestroyMutex = (void (*)(DFMutex*))GetProcAddress(realSDLlib,"SDL_DestroyMutex");
_SDL_EnableKeyRepeat = (int (*)(int, int))GetProcAddress(realSDLlib,"SDL_EnableKeyRepeat");
_SDL_EnableUNICODE = (int (*)(int))GetProcAddress(realSDLlib,"SDL_EnableUNICODE");
_SDL_GetVideoSurface = (void*(*)())GetProcAddress(realSDLlib,"SDL_GetVideoSurface");
@ -796,8 +796,8 @@ bool FirstCall()
_SDL_UpperBlit = (int (*)(void*, void*, void*, void*))GetProcAddress(realSDLlib,"SDL_UpperBlit");
_SDL_WM_SetCaption = (void (*)(const char*, const char*))GetProcAddress(realSDLlib,"SDL_WM_SetCaption");
_SDL_WM_SetIcon = (void (*)(void*, uint8_t*))GetProcAddress(realSDLlib,"SDL_WM_SetIcon");
_SDL_mutexP = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_mutexP");
_SDL_mutexV = (int (*)(void*))GetProcAddress(realSDLlib,"SDL_mutexV");
_SDL_mutexP = (int (*)(DFMutex*))GetProcAddress(realSDLlib,"SDL_mutexP");
_SDL_mutexV = (int (*)(DFMutex*))GetProcAddress(realSDLlib,"SDL_mutexV");
_SDL_strlcpy = (size_t (*)(char*, const char*, size_t))GetProcAddress(realSDLlib,"SDL_strlcpy");
// stuff for SDL_Image
@ -814,7 +814,7 @@ bool FirstCall()
// new in DF 0.31.04
_SDL_CreateSemaphore = (void* (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_CreateSemaphore");
_SDL_CreateThread = (void* (*)(int (*fn)(void *), void *data))GetProcAddress(realSDLlib,"SDL_CreateThread");
_SDL_CreateThread = (DFThread* (*)(int (*fn)(void *), void *data))GetProcAddress(realSDLlib,"SDL_CreateThread");
_SDL_Delay = (void (*)(uint32_t))GetProcAddress(realSDLlib,"SDL_Delay");
_SDL_DestroySemaphore = (void (*)(void *))GetProcAddress(realSDLlib,"SDL_DestroySemaphore");
_SDL_GetAppState = (uint8_t (*)(void))GetProcAddress(realSDLlib,"SDL_GetAppState");

@ -42,8 +42,49 @@ using namespace std;
#include "dfhack/modules/Vegetation.h"
#include "dfhack/modules/Maps.h"
#include <dfhack/modules/World.h>
#include "rlutil.h"
#include <stdio.h>
using namespace DFHack;
int kittenz (void)
{
const char * kittenz1 []=
{
" ____",
" (. \\",
" \\ | ",
" \\ |___(\\--/)",
" __/ ( . . )",
" \"'._. '-.O.'",
" '-. \\ \"|\\",
" '.,,/'.,,mrf",
0
};
rlutil::hidecursor();
rlutil::cls();
int color = 1;
while(1)
{
rlutil::setColor(color);
int index = 0;
const char * kit = kittenz1[index];
rlutil::locate(1,1);
cout << "Your DF is now full of kittens!" << endl;
while (kit != 0)
{
rlutil::locate(5,5+index);
cout << kit;
index++;
kit = kittenz1[index];
}
fflush(stdout);
rlutil::msleep(60);
color ++;
if(color > 15)
color = 1;
rlutil::cls();
}
}
struct hideblock
{
uint32_t x;
@ -51,7 +92,6 @@ struct hideblock
uint32_t z;
uint8_t hiddens [16][16];
};
int reveal (void)
{
Core & c = DFHack::Core::getInstance();
@ -105,9 +145,9 @@ int reveal (void)
World->SetPauseState(true);
c.Resume();
cout << "Map revealed. The game has been paused for you." << endl;
cout << "Unpausing can unleash the forces of hell!" << endl << endl;
cout << "Unpausing can unleash the forces of hell!" << endl;
cout << "Saving will make this state permanent. Don't do it." << endl << endl;
cout << "Press any key to unreveal." << endl;
cout << "Close to keep the map revealed !!FOREVER!!" << endl;
cin.ignore();
cout << "Unrevealing... please wait." << endl;
// FIXME: do some consistency checks here!
@ -145,15 +185,23 @@ int fIOthread(void * _core)
}
if(command=="help" || command == "?")
{
cout << "It's simple really. You can run reveal with 'reveal'." << endl;
cout << "Available commands:" << endl;
// TODO: generic list of available commands!
cout << "reveal" << endl;
cout << "kittens" << endl;
}
// TODO: commands will be registered. We'll scan a map of command -> function pointer and call stuff.
else if(command == "reveal")
{
reveal();
}
else if(command == "kittens")
{
kittenz();
}
else
{
cout << "WHAT?" << endl;
cout << "Do 'help' or '?' for the list of available commands." << endl;
}
}
}

@ -0,0 +1,520 @@
#pragma once
/**
* File: rlutil.h
*
* About: Description
* This file provides some useful utilities for console mode
* roguelike game development with C and C++. It is aimed to
* be cross-platform (at least Windows and Linux).
*
* About: Copyright
* (C) 2011 The united church of gotoxy.
*
*/
/// Define: RLUTIL_USE_ANSI
/// Define this to use ANSI escape sequences also on Windows
/// (defaults to using WinAPI instead).
#if 0
#define RLUTIL_USE_ANSI
#endif
/// Define: RLUTIL_STRING_T
/// Define/typedef this to your preference to override rlutil's string type.
///
/// Defaults to std::string with C++ and char* with C.
#if 0
#define RLUTIL_STRING_T char*
#endif
#ifdef __cplusplus
/// Common C++ headers
#include <iostream>
#include <string>
#include <sstream>
/// Namespace forward declarations
namespace rlutil {
void locate(int x, int y);
}
#endif // __cplusplus
#ifdef WIN32
#include <windows.h> // for WinAPI and Sleep()
#include <conio.h> // for getch() and kbhit()
#else
#ifdef __cplusplus
#include <cstdio> // for getch()
#else // __cplusplus
#include <stdio.h> // for getch()
#endif // __cplusplus
#include <termios.h> // for getch() and kbhit()
#include <unistd.h> // for getch(), kbhit() and (u)sleep()
#include <sys/ioctl.h> // for getkey()
#include <sys/types.h> // for kbhit()
#include <sys/time.h> // for kbhit()
/// Function: getch
/// Get character without waiting for Return to be pressed.
/// Windows has this in conio.h
int getch() {
// Here be magic.
struct termios oldt, newt;
int ch;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
/// Function: kbhit
/// Determines if keyboard has been hit.
/// Windows has this in conio.h
int kbhit() {
// Here be dragons.
static struct termios oldt, newt;
int cnt = 0;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
newt.c_iflag = 0; // input mode
newt.c_oflag = 0; // output mode
newt.c_cc[VMIN] = 1; // minimum time to wait
newt.c_cc[VTIME] = 1; // minimum characters to wait for
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ioctl(0, FIONREAD, &cnt); // Read count
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100;
select(STDIN_FILENO+1, NULL, NULL, NULL, &tv); // A small time delay
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return cnt; // Return number of characters
}
#endif // WIN32
#ifndef gotoxy
/// Function: gotoxy
/// Same as <rlutil.locate>.
void inline gotoxy(int x, int y) {
#ifdef __cplusplus
rlutil::
#endif
locate(x,y);
}
#endif // gotoxy
#ifdef __cplusplus
/// Namespace: rlutil
/// In C++ all functions except <getch>, <kbhit> and <gotoxy> are arranged
/// under namespace rlutil. That is because some platforms have them defined
/// outside of rlutil.
namespace rlutil {
#endif
/**
* Defs: Internal typedefs and macros
* RLUTIL_STRING_T - String type depending on which one of C or C++ is used
* RLUTIL_PRINT(str) - Printing macro independent of C/C++
*/
#ifdef __cplusplus
#ifndef RLUTIL_STRING_T
typedef std::string RLUTIL_STRING_T;
#endif // RLUTIL_STRING_T
void inline RLUTIL_PRINT(RLUTIL_STRING_T st) { std::cout << st; }
#else // __cplusplus
#ifndef RLUTIL_STRING_T
typedef char* RLUTIL_STRING_T;
#endif // RLUTIL_STRING_T
#define RLUTIL_PRINT(st) printf("%s", st)
#endif // __cplusplus
/**
* Enums: Color codes
*
* BLACK - Black
* RED - Red
* GREEN - Green
* BROWN - Brown / dark yellow
* BLUE - Blue
* MAGENTA - Magenta / purple
* CYAN - Cyan
* GREY - Grey / dark white
* DARKGREY - Dark grey / light black
* LIGHTRED - Light red
* LIGHTGREEN - Light green
* YELLOW - Yellow (bright)
* LIGHTBLUE - Light blue
* LIGHTMAGENTA - Light magenta / light purple
* LIGHTCYAN - Light cyan
* WHITE - White (bright)
*/
enum {
BLACK,
RED,
GREEN,
BROWN,
BLUE,
MAGENTA,
CYAN,
GREY,
DARKGREY,
LIGHTRED,
LIGHTGREEN,
YELLOW,
LIGHTBLUE,
LIGHTMAGENTA,
LIGHTCYAN,
WHITE
};
/**
* Consts: ANSI color strings
*
* ANSI_CLS - Clears screen
* ANSI_BLACK - Black
* ANSI_RED - Red
* ANSI_GREEN - Green
* ANSI_BROWN - Brown / dark yellow
* ANSI_BLUE - Blue
* ANSI_MAGENTA - Magenta / purple
* ANSI_CYAN - Cyan
* ANSI_GREY - Grey / dark white
* ANSI_DARKGREY - Dark grey / light black
* ANSI_LIGHTRED - Light red
* ANSI_LIGHTGREEN - Light green
* ANSI_YELLOW - Yellow (bright)
* ANSI_LIGHTBLUE - Light blue
* ANSI_LIGHTMAGENTA - Light magenta / light purple
* ANSI_LIGHTCYAN - Light cyan
* ANSI_WHITE - White (bright)
*/
const RLUTIL_STRING_T ANSI_CLS = "\033[2J";
const RLUTIL_STRING_T ANSI_BLACK = "\033[22;30m";
const RLUTIL_STRING_T ANSI_RED = "\033[22;31m";
const RLUTIL_STRING_T ANSI_GREEN = "\033[22;32m";
const RLUTIL_STRING_T ANSI_BROWN = "\033[22;33m";
const RLUTIL_STRING_T ANSI_BLUE = "\033[22;34m";
const RLUTIL_STRING_T ANSI_MAGENTA = "\033[22;35m";
const RLUTIL_STRING_T ANSI_CYAN = "\033[22;36m";
const RLUTIL_STRING_T ANSI_GREY = "\033[22;37m";
const RLUTIL_STRING_T ANSI_DARKGREY = "\033[01;30m";
const RLUTIL_STRING_T ANSI_LIGHTRED = "\033[01;31m";
const RLUTIL_STRING_T ANSI_LIGHTGREEN = "\033[01;32m";
const RLUTIL_STRING_T ANSI_YELLOW = "\033[01;33m";
const RLUTIL_STRING_T ANSI_LIGHTBLUE = "\033[01;34m";
const RLUTIL_STRING_T ANSI_LIGHTMAGENTA = "\033[01;35m";
const RLUTIL_STRING_T ANSI_LIGHTCYAN = "\033[01;36m";
const RLUTIL_STRING_T ANSI_WHITE = "\033[01;37m";
/**
* Consts: Key codes for keyhit()
*
* KEY_ESCAPE - Escape
* KEY_ENTER - Enter
* KEY_SPACE - Space
* KEY_INSERT - Insert
* KEY_HOME - Home
* KEY_END - End
* KEY_DELETE - Delete
* KEY_PGUP - PageUp
* KEY_PGDOWN - PageDown
* KEY_UP - Up arrow
* KEY_DOWN - Down arrow
* KEY_LEFT - Left arrow
* KEY_RIGHT - Right arrow
* KEY_F1 - F1
* KEY_F2 - F2
* KEY_F3 - F3
* KEY_F4 - F4
* KEY_F5 - F5
* KEY_F6 - F6
* KEY_F7 - F7
* KEY_F8 - F8
* KEY_F9 - F9
* KEY_F10 - F10
* KEY_F11 - F11
* KEY_F12 - F12
* KEY_NUMDEL - Numpad del
* KEY_NUMPAD0 - Numpad 0
* KEY_NUMPAD1 - Numpad 1
* KEY_NUMPAD2 - Numpad 2
* KEY_NUMPAD3 - Numpad 3
* KEY_NUMPAD4 - Numpad 4
* KEY_NUMPAD5 - Numpad 5
* KEY_NUMPAD6 - Numpad 6
* KEY_NUMPAD7 - Numpad 7
* KEY_NUMPAD8 - Numpad 8
* KEY_NUMPAD9 - Numpad 9
*/
const int KEY_ESCAPE = 0;
const int KEY_ENTER = 1;
const int KEY_SPACE = 32;
const int KEY_INSERT = 2;
const int KEY_HOME = 3;
const int KEY_PGUP = 4;
const int KEY_DELETE = 5;
const int KEY_END = 6;
const int KEY_PGDOWN = 7;
const int KEY_UP = 14;
const int KEY_DOWN = 15;
const int KEY_LEFT = 16;
const int KEY_RIGHT = 17;
const int KEY_F1 = 18;
const int KEY_F2 = 19;
const int KEY_F3 = 20;
const int KEY_F4 = 21;
const int KEY_F5 = 22;
const int KEY_F6 = 23;
const int KEY_F7 = 24;
const int KEY_F8 = 25;
const int KEY_F9 = 26;
const int KEY_F10 = 27;
const int KEY_F11 = 28;
const int KEY_F12 = 29;
const int KEY_NUMDEL = 30;
const int KEY_NUMPAD0 = 31;
const int KEY_NUMPAD1 = 127;
const int KEY_NUMPAD2 = 128;
const int KEY_NUMPAD3 = 129;
const int KEY_NUMPAD4 = 130;
const int KEY_NUMPAD5 = 131;
const int KEY_NUMPAD6 = 132;
const int KEY_NUMPAD7 = 133;
const int KEY_NUMPAD8 = 134;
const int KEY_NUMPAD9 = 135;
/// Function: getkey
/// Reads a key press (blocking) and returns a key code.
///
/// See <Key codes for keyhit()>
///
/// Note:
/// Only Arrows, Esc, Enter and Space are currently working properly.
int getkey(void) {
#ifndef WIN32
int cnt = kbhit(); // for ANSI escapes processing
#endif
int k = getch();
switch(k) {
case 0: {
int kk;
switch (kk = getch()) {
case 71: return KEY_NUMPAD7;
case 72: return KEY_NUMPAD8;
case 73: return KEY_NUMPAD9;
case 75: return KEY_NUMPAD4;
case 77: return KEY_NUMPAD6;
case 79: return KEY_NUMPAD1;
case 80: return KEY_NUMPAD4;
case 81: return KEY_NUMPAD3;
case 82: return KEY_NUMPAD0;
case 83: return KEY_NUMDEL;
default: return kk-59+KEY_F1; // Function keys
}}
case 224: {
int kk;
switch (kk = getch()) {
case 71: return KEY_HOME;
case 72: return KEY_UP;
case 73: return KEY_PGUP;
case 75: return KEY_LEFT;
case 77: return KEY_RIGHT;
case 79: return KEY_END;
case 80: return KEY_DOWN;
case 81: return KEY_PGDOWN;
case 82: return KEY_INSERT;
case 83: return KEY_DELETE;
default: return kk-123+KEY_F1; // Function keys
}}
case 13: return KEY_ENTER;
#ifdef WIN32
case 27: return KEY_ESCAPE;
#else // WIN32
case 155: // single-character CSI
case 27: {
// Process ANSI escape sequences
if (cnt >= 3 && getch() == '[') {
switch (k = getch()) {
case 'A': return KEY_UP;
case 'B': return KEY_DOWN;
case 'C': return KEY_RIGHT;
case 'D': return KEY_LEFT;
}
} else return KEY_ESCAPE;
}
#endif // WIN32
default: return k;
}
}
/// Function: nb_getch
/// Non-blocking getch(). Returns 0 if no key was pressed.
int inline nb_getch() {
if (kbhit()) return getch();
else return 0;
}
/// Function: getANSIColor
/// Return ANSI color escape sequence for specified number 0-15.
///
/// See <Color Codes>
RLUTIL_STRING_T getANSIColor(const int c) {
switch (c) {
case 0 : return ANSI_BLACK;
case 1 : return ANSI_BLUE; // non-ANSI
case 2 : return ANSI_GREEN;
case 3 : return ANSI_CYAN; // non-ANSI
case 4 : return ANSI_RED; // non-ANSI
case 5 : return ANSI_MAGENTA;
case 6 : return ANSI_BROWN;
case 7 : return ANSI_GREY;
case 8 : return ANSI_DARKGREY;
case 9 : return ANSI_LIGHTBLUE; // non-ANSI
case 10: return ANSI_LIGHTGREEN;
case 11: return ANSI_LIGHTCYAN; // non-ANSI;
case 12: return ANSI_LIGHTRED; // non-ANSI;
case 13: return ANSI_LIGHTMAGENTA;
case 14: return ANSI_YELLOW; // non-ANSI
case 15: return ANSI_WHITE;
default: return "";
}
}
/// Function: setColor
/// Change color specified by number (Windows / QBasic colors).
///
/// See <Color Codes>
void inline setColor(int c) {
#if defined(WIN32) && !defined(RLUTIL_USE_ANSI)
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hConsole, c);
#else
RLUTIL_PRINT(getANSIColor(c));
#endif
}
/// Function: cls
/// Clears screen and moves cursor home.
void inline cls() {
#if defined(WIN32) && !defined(RLUTIL_USE_ANSI)
// TODO: This is cheating...
system("cls");
#else
RLUTIL_PRINT("\033[2J\033[H");
#endif
}
/// Function: locate
/// Sets the cursor position to 1-based x,y.
void locate(int x, int y) {
#if defined(WIN32) && !defined(RLUTIL_USE_ANSI)
COORD coord = {x-1, y-1}; // Windows uses 0-based coordinates
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
#else // WIN32 || USE_ANSI
#ifdef __cplusplus
std::ostringstream oss;
oss << "\033[" << y << ";" << x << "H";
RLUTIL_PRINT(oss.str());
#else // __cplusplus
char buf[32];
sprintf(buf, "\033[%d;%df", y, x);
RLUTIL_PRINT(buf);
#endif // __cplusplus
#endif // WIN32 || USE_ANSI
}
/// Function: hidecursor
/// Hides the cursor.
void inline hidecursor() {
#if defined(WIN32) && !defined(RLUTIL_USE_ANSI)
HANDLE hConsoleOutput;
CONSOLE_CURSOR_INFO structCursorInfo;
hConsoleOutput = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); // Get current cursor size
structCursorInfo.bVisible = FALSE;
SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo );
#else // WIN32 || USE_ANSI
RLUTIL_PRINT("\033[?25l");
#endif // WIN32 || USE_ANSI
}
/// Function: showcursor
/// Shows the cursor.
void inline showcursor() {
#if defined(WIN32) && !defined(RLUTIL_USE_ANSI)
HANDLE hConsoleOutput;
CONSOLE_CURSOR_INFO structCursorInfo;
hConsoleOutput = GetStdHandle( STD_OUTPUT_HANDLE );
GetConsoleCursorInfo( hConsoleOutput, &structCursorInfo ); // Get current cursor size
structCursorInfo.bVisible = TRUE;
SetConsoleCursorInfo( hConsoleOutput, &structCursorInfo );
#else // WIN32 || USE_ANSI
RLUTIL_PRINT("\033[?25h");
#endif // WIN32 || USE_ANSI
}
/// Function: msleep
/// Waits given number of milliseconds before continuing.
void inline msleep(unsigned int ms) {
#ifdef WIN32
Sleep(ms);
#else
// usleep argument must be under 1 000 000
if (ms > 1000) sleep(ms/1000000);
usleep((ms % 1000000) * 1000);
#endif
}
// TODO: Allow optional message for anykey()?
/// Function: anykey
/// Waits until a key is pressed.
void inline anykey() {
getch();
}
#ifndef min
/// Function: min
/// Returns the lesser of the two arguments.
#ifdef __cplusplus
template <class T> const T& min ( const T& a, const T& b ) { return (a<b)?a:b; }
#else
#define min(a,b) (((a)<(b))?(a):(b))
#endif // __cplusplus
#endif // min
#ifndef max
/// Function: max
/// Returns the greater of the two arguments.
#ifdef __cplusplus
template <class T> const T& max ( const T& a, const T& b ) { return (b<a)?a:b; }
#else
#define max(a,b) (((b)<(a))?(a):(b))
#endif // __cplusplus
#endif // max
// Classes are here at the end so that documentation is pretty.
#ifdef __cplusplus
/// Class: CursorHider
/// RAII OOP wrapper for <rlutil.hidecursor>.
/// Hides the cursor and shows it again
/// when the object goes out of scope.
struct CursorHider {
CursorHider() { hidecursor(); }
~CursorHider() { showcursor(); }
};
} // namespace rlutil
#endif