FateHack
Warning! This version uses “remove USB stack” technique. When you upload a new game, you need to hold down the DOWN button while Arduboy is starting up.
Roguelike game and probably tiniest roguelike library for Arduboy or its emulator influenced by NetHack and WildTangent’s FATE.
Bottom panel:
534
free memory left (destroy useless objects ifLOW
)- current year
14Y
(now removed) - current day
1D
(now removed) - current hour
1:
(now removed) - current minute
:1
(now removed) - current negative elevation
0
Controls:
- Up , Down , Left , Right - move cursor
- A or Ctrl + Up , Down , Left , Right - move player
- A or Ctrl - select object for action or give object to the next potential owner in your possessions
- B or Alt - toggle menu at cursor position or cancel action
- to take something ‘on this use player’
- to drop something ‘on floor
.
use this’
Inventory list schematic example
1 player1 (has to be placed on scene) <-friend1, friend2(second) and food(third) next owner-+
2 -life:attribute |
3 friend1 (has to be placed on scene) <-friend2 and food(second) next owner-+---------------+
4 -dog:type |
5 -collar:item |
6 friend2 (has to be placed on scene) <-food next owner-+-------------------+
7 -miner:type |
8 -life:attribute |
9 -food:item -------------------------------------------+
Game features:
- saving/loading using seed
- bot
- cursor
- pet
- toilet
- thirst
- priority of things relations over the soulless loot
Programming features for using as library for other Arduboy roguelikes:
- pathfinding algorithm for generating caves
- scene builder (no free memory, now commented)
- object builder
- dynamic memory allocation for every object (yes, you can run out of memory)
- OOP pattern at the core - prototype (exemplar)
- easy scripting for objects interactions
Roguelike library documentation:
Library uses dynamic memory allocation and parametric polymorphism principles. There is no memory for smart pointers implementation so don’t forget to delete
objects if you don’t need them anymore. Like this:
Class *c = Class::exemplar.make(object_template);
...some code...
delete c;
c = 0;
Class
Base class and interface for all objects. Is must be used everywhere. Inherit all your new classes from Class.
Class::exemplar
Object maker instance with Print custom tiles functionality.
virtual Class *make(const char* s, uint8_t is_eeprom = 0); //always create all your objects with this method. DONT FORGET TO destroy THEM AFTER! First char is the object type.
virtual void toStr(); //print init string on screen
unsigned int getDigit(char *c, int &s); //get digit after s chars from c. Iterating s
static int hasMoreMemory() { //returns free memory size or 0 if the size is under 300
static void printDebug(char* c); //use this for debuging purposes with itoa
static void setCursor(int8_t x, int8_t y); //Arduboy2 library analog with custom tiles
static void setTextColor(const uint8_t color); //Arduboy2 library analog with custom tiles
static void setTextBackground(const uint8_t color); //Arduboy2 library analog with custom tiles
Class::arduboy
Arduboy2 or Arduboy2Base class instance from Arduboy2 library.
Class::sprites
SpritesB instance from Arduboy2 library.
Scene
Map on the screen. Dynamically allocated array of pointers to Class.
char Scene::getTypeChar()
S
Class *Scene::atPut(Directive key, Class *arg)
Class *Scene::atPut(Directive key, Class *arg) {
switch (key) {
case Class::Directive::Find: //atPut find first clone of Directive::Source (including itself) which can be reached by arg. Then nullify Directive::Source and Directive::Target. Return NULL or found clone. Put Directive::Source before calling this method. TODO: Find closest clone
case Class::Directive::Reach: //atPut check Directive::Source can be reached by Directive::Target. Then nullify Directive::Source and Directive::Target. Return NULL or arg. Put Directive::Source and Directive::Target before calling this method.
case Class::Directive::Source: //atPut save source pointer. Return NULL
case Class::Directive::Target: //atPut save target pointer. Return NULL
case Class::Directive::Greater: //atPut set arg to be min path in autogenerated scene. Return this
case Class::Directive::Less: //atPut set arg to be max path in autogenerated scene. Return this
case Class::Directive::Cursor: //atPut set cursor on owner of arg or return NULL
case Class::Directive::Near: //atPut check arg is near the cursor and return arg if true. If false then return NULL
case Class::Directive::Free: //atPut check path prototype clone (movable space) is near the arg and return arg if true. If false then return NULL
case Class::Directive::Owner: //atPut get next nearest owner in owners tree of arg. Returns pointer to owner if owner exists. Returns arg if arg owns itself
case Class::Directive::Delete: //atPut delete arg from every other class on the scene if arg is not scene block. Returns NULL
case Class::Directive::Move: //atPut move arg by shortest path. Returns NULL if success, or class that blocks way, or arg if bounds
case Class::Directive::Turn: //atPut set next turn to all classes in the scene. Returns NULL
case Class::Directive::Search: //atPut find next position of clone of arg (including itself) in the scene and moves cursor to this position. Use atGet ::Cursor to start search from begining. Returns NULL if not found. Returns clone of arg pointer if found
case Class::Directive::Next: //atPut clear the scene except arg and its class chain. Returns NULL
case Class::Directive::Far: //atPut place arg on scene to be farest by path from Directive::Source to Directive::Target with trying to block that path. TODO: returns
case Class::Directive::Close: //atPut place arg on scene to be closest by path from Directive::Source to Directive::Target with trying to block that path. TODO: returns
case Class::Directive::Mode: //atPut if arg is not NULL then set blocking mode on. If arg is NULL then off. Returns this
case Class::Directive::Fill: //atPut if arg not NULL then set the scene to copy scene blocks istead of referencing the same class instance in every scene block cell. Returns this
case Class::Directive::Clear: //atPut clear all clones of arg in the scene. Returns this
case Class::Directive::Path: //atPut clone arg and set clone to be path prototype for the scene. Returns this
case Class::Directive::Reveal: //atPut if arg is not NULL then reveal explored on this map. if NULL then only near player is revealed
case Class::Directive::Block: //atPut clone arg and set clone to be block prototype for the scene. Returns this
case Class::Directive::Map: //atPut clear paths and stubs on map and set paths leading to arg. Returns this
case Class::Directive::Build: //atPut try to autogenerate the scene and its bounds. Then place arg on scene. Put Directive::X and Directive::Y before calling this method to set scene sizes. If fail then return NULL. Returns this if success
case Class::Directive::Character: //atPut place arg under a cursor. Returns arg
case Class::Directive::X: //atPut set x coordinate of a cursor within bounds if they exists. Returns NULL
case Class::Directive::Y: //atPut set y coordinate of a cursor within bounds if they exists. Returns NULL
case Class::Directive::Up: //atPut move arg. Return NULL if success, or class that blocks way, or arg if bounds
case Class::Directive::Down: //atPut move arg. Return NULL if success, or class that blocks way, or arg if bounds
case Class::Directive::Left: //atPut move arg. Return NULL if success, or class that blocks way, or arg if bounds
case Class::Directive::Right: //atPut move arg. Return NULL if success, or class that blocks way, or arg if bounds
case Class::Directive::Show: //atPut show scene on screen as arg field of view. Returns NULL
case Class::Directive::Draw: //atPut draw scene on the screen for arg
case Class::Directive::Pass: //atPut get next class who has turn ignoring arg itself. Returns NULL if no more classes with turns. Returns first class that has turn
default:
}
return 0;
}
Class *Scene::atGet(Directive key)
Class *Scene::atGet(Directive key) {
switch (key) {
case Class::Directive::Cursor: //atGet set cursor at start of scene. Returns NULL
case Class::Directive::Delete: //atGet delete player under cursor from scene. Returns NULL
case Class::Directive::Reveal: //atGet return NULL if scene not revealed
case Class::Directive::Block: //atGet returns block prototype of the scene
case Class::Directive::Save: //atGet save cursor position. Returns NULL
case Class::Directive::Load: //atGet restore saved cursor position. Returns NULL
case Class::Directive::Path: //atGet returns block prototype of the scene
case Class::Directive::Character: //atGet returns class under the cursor
case Class::Directive::Up: //atGet move the cursor within bounds. Returns NULL if bounds, or y path prototype if moved
case Class::Directive::Down: //atGet move the cursor within bounds. Returns NULL if bounds, or y path prototype if moved
case Class::Directive::Left: //atGet move the cursor within bounds. Returns NULL if bounds, or X path prototype if moved
case Class::Directive::Right: //atGet move the cursor within bounds. Returns NULL if bounds, or X path prototype if moved
case Class::Directive::X: //atGet returns x coordinate of a cursor
case Class::Directive::Y: //atGet returns y coordinate of a cursor
case Class::Directive::Build: //atGet initialize empty scene and its bounds. Call atPut Directive::X and Directive::Y coordinates first before calling this method. Returns this
default:
}
return 0;
}
Player
All objects placed on the scene are Player instances and have other Player in class chain.
int Player::toInt()
Returns script index in _init string.
char Player::getTypeChar()
P
Class *Player::atPut(Directive key, Class *arg)
Class *Player::atPut(Directive key, Class *arg)
{
switch (key)
{
case Class::Directive::Delete: // atPut delete arg from this class chain by pointer. Chain owner not will be deleted. Always return arg
case Class::Directive::Block: // atPut set this class as path blocker or bind to owner of class chain if arg is not NULL. if arg is NULL then unset
case Class::Directive::Character: // atPut find clone of arg in this class chain
case Class::Directive::Next: // atPut push arg to this class chain destructive. Don't use this method. Use Add
case Class::Directive::Add: // atPut push arg chain to class chain and return arg. Will delete next arg chain before adding if arg not to be placed
case Class::Directive::Count: // atPut increment counter by one if arg is not NULL. If arg is NULL then set couter to zero
case Class::Directive::Place: // atPut set this class has to be placed on scene if arg is not NULL. if arg is NULL then unset
case Class::Directive::Cursed: // atPut set this class has to be placed on scene if arg is not NULL. if arg is NULL then unset
case Class::Directive::Turn: // atPut set this class has turn in turn order. if arg is NULL then unset
case Class::Directive::Reveal: // atPut set this class to be hidden on scene. if arg is NULL then reveals
case Class::Directive::Stack: // atPut set this class to be stacked with same classes. if arg is NULL then not stacked
default:
}
return 0;
}
Class *Player::atGet(Directive key)
Class *Player::atGet(Directive key)
{
switch (key)
{
case Class::Directive::Next: // atGet get next class after this in class chain. Return NULL if end of chain
case Class::Directive::Turn: // atGet if return NULL then don't have turn
case Class::Directive::Cursed: // atGet if return NULL then don't have turn
case Class::Directive::Place: // atGet if return NULL then don't have to be placed on scene
case Class::Directive::Count: // atGet decrease counter. Return this if counter not zero. Else return NULL
case Class::Directive::Block: // atGet if return NULL then this class don't blocker or binded
case Class::Directive::Reveal: // atGet if return NULL then this revealed class
case Class::Directive::Stack: // atGet if return NULL then this not stacked class. Return this if stacked
case Class::Directive::Draw: // atGet draw this class symbol on screen
default:
}
return 0;
}
Coordinate
Needed to manipulate scene dimensions and class locations on the scene in polymorphic way.
int Coordinate::toInt()
Integer representation for scene dimension.
char Coordinate::getTypeChar()
C
Class *Coordinate::atPut(Directive key, Class *arg)
Class *Coordinate::atPut(Directive key, Class *arg)
{
switch (key)
{
case Class::Directive::Character: // atPut find clone of arg in first element of class chain
case Class::Directive::Next: // atPut push arg to this class destructive
case Class::Directive::Greater: // atPut return greater comparing this and arg
case Class::Directive::Less: // atPut return less comparing this and arg
default:
}
return 0;
}
Class *Coordinate::atGet(Directive key)
Class *Coordinate::atGet(Directive key)
{
switch (key)
{
case Class::Directive::Next: // atGet get next class after this in class chain
case Class::Directive::Reveal: // atGet return NULL if hidden
case Class::Directive::Draw: // atGet draw this class symbol on screen
case Class::Directive::Up: // atGet move coordinate up
case Class::Directive::Down: // atGet move coordinate down
default:
}
return 0;
}
How to add your classes:
Inherit from Class and implement interface:
virtual ~Class();
virtual Class *atPut(Directive key, Class *arg);
virtual Class *atGet(Directive key);
virtual Class *clone() const;
virtual Class *make(const char* s);
virtual char* toStr();
virtual int toInt();
virtual char getTypeChar();
Using existing macro:
#define REGISTER_PROTOTYPE(CLASS) static CLASS CLASS##Instance = CLASS(Exemplar())
register your subclass of Class before use:
REGISTER_PROTOTYPE(YourSubClass);
Source code
RogueBeyond.zip (143.6 KB)
HEX
RogueBeyond.ino-arduboy.hex (80.4 KB)