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:
- current year
14Y
- current day
1D
- current hour
1:
- current minute
:1
- 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 pick(third) next owner-+
2 -life:attribute |
3 friend1 (has to be placed on scene) <-friend2 and pick(second) next owner-+---------------+
4 -dog:type |
5 -collar:item |
6 friend2 (has to be placed on scene) <-pick next owner-+-------------------+
7 -miner:type |
8 -life:attribute |
9 -pick:item -------------------------------------------+
Game features:
- 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
- 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); //always create all your objects with this method. DONT FORGET TO destroy THEM AFTER! First char is the object type.
virtual char* toStr(); //return init string
static unsigned int getDigit(const char* c); //iterate PROGMEM pointer while number
static void printName(Class * cl); //print name of class
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)
switch (key) {
case Class::Directive::Find: //atPut find reachable CLONE of Directive::Source by arg. Put Directive::Source and Directive::Target (optional) first.
case Class::Directive::Reach: //atPut check Directive::Source is reachable by arg. Put Directive::Source and Directive::Target (optional) first.
case Class::Directive::Source: //atPut save arg pointer in scene object for future operating
case Class::Directive::Target: //atPut save arg pointer in scene object for future operating
case Class::Directive::Greater: //atPut clone arg and set clone to be min path in autogenerated scene
case Class::Directive::Less: //atPut clone arg and set clone to be max path in autogenerated scene
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 0
case Class::Directive::Free: //atPut check path proto is near the arg and return arg if true. if false then return 0
case Class::Directive::Owner: //atPut get next nearest owner of arg in the scene if it exists or return NULL
case Class::Directive::Delete: //atPut delete arg from every other class on the scene if arg is not scene block
case Class::Directive::Move: //atPut move arg by shortest path
case Class::Directive::Turn: //atPut set next turn to all classes in the scene
case Class::Directive::Search: //atPut find next position of clone of arg in the scene and moves cursor. Use atGet ::Cursor to start search again
case Class::Directive::Next: //atPut clear the scene except arg and his classes
case Class::Directive::Far: //atPut place arg on scene to be farest by path from Directive::Source to Directive::Target with blocking path.
case Class::Directive::Close: //atPut place arg on scene to be closest by path from Directive::Source to Directive::Target with blocking path.
case Class::Directive::Mode: //atPut if arg then blocking mode on. if not then off.
case Class::Directive::Clear: //atPut clear all clones of arg in the scene
case Class::Directive::Path: //atPut clone arg and set clone to be path prototype for the scene
case Class::Directive::Block: //atPut clone arg and set clone to be block prototype for the scene
case Class::Directive::Map: //atPut clear paths and stubs on map and set paths leading to arg
case Class::Directive::Build: //atPut try to build the scene and bounds with x and y sizes already setted then place arg there. If fail then return NULL
case Class::Directive::Character: //atPut place arg under a cursor
case Class::Directive::X: //atPut clone x coordinate of a cursor within bounds if they exists. Set this to build initial scene
case Class::Directive::Y: //atPut clone y coordinate of a cursor within bounds if they exists. Set this to build initial scene
case Class::Directive::Up: //atPut move arg. Return NULL if success, class that blocks way, arg if bounds
case Class::Directive::Down: //atPut move arg. Return NULL if success, class that blocks way, arg if bounds
case Class::Directive::Left: //atPut move arg. Return NULL if success, class that blocks way, arg if bounds
case Class::Directive::Right: //atPut move arg. Return NULL if success, class that blocks way, arg if bounds
case Class::Directive::Show: //show scene on screen for spectator arg
case Class::Directive::Draw: //atPut draw scene on the screen for arg
case Class::Directive::Place: //atPut scene stub
}
Class *Scene::atGet(Directive key)
switch (key) {
case Class::Directive::Cursor: //atGet set cursor at start of scene
case Class::Directive::Delete: //atGet delete player under cursor from scene
case Class::Directive::Place: //atGet scene stub
case Class::Directive::Block: //atGet return block prototype of the scene
case Class::Directive::Save: //atGet save cursor position
case Class::Directive::Load: //atGet load cursor position
case Class::Directive::Path: //atGet return block prototype of the scene
case Class::Directive::Turn: //atGet get next class who has turn
case Class::Directive::Character: //atGet get the class under the cursor
case Class::Directive::Up: //atGet move the cursor within bounds. Return NULL if bounds, or y path prototype if moved
case Class::Directive::Down: //atGet move the cursor within bounds. Return NULL if bounds, or y path prototype if moved
case Class::Directive::Left: //atGet move the cursor within bounds. Return NULL if bounds, or y path prototype if moved
case Class::Directive::Right: //atGet move the cursor within bounds. Return NULL if bounds, or y path prototype if moved
case Class::Directive::X: //atGet get x coordinate of a cursor
case Class::Directive::Y: //atGet get y coordinate of a cursor
case Class::Directive::Build: //atGet initialize empty scene and its bounds. Set X and Y coordinates first before calling this method
}
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)
switch (key) {
case Class::Directive::Delete: //atPut delete arg from this class chain by pointer ignoring chain owner
case Class::Directive::Count: //atPut set effect counter to integer from arg. if NULL set effect counter to 0
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. Delete next arg chain before adding if arg not to be placed
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::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
}
Class *Player::atGet(Directive key)
switch (key) {
case Class::Directive::Next: //atGet get next class after this in class chain
case Class::Directive::Turn: //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 effect duration. Return this if duration not ended. If ended then 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::Draw: //atGet draw this class symbol on screen
}
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)
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
}
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
}
Stub
Needed for memory economy. Replaces coordinates.
char Stub::getTypeChar()
A
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
FateHack.zip (30.0 KB)
HEX
FateHack.ino-arduboy.hex (77.8 KB)