hyperrogue/classes.cpp

1127 lines
57 KiB
C++

// Hyperbolic Rogue -- items, monsters, walls, lands, descriptions, etc.
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
/** \file classes.cpp
* \brief items, monsters, walls, lands, descriptions, etc.
*
* See content.cpp for actual items, monsters, walls and lands.
*/
#include "hyper.h"
namespace hr {
// --- help ---
const char *wormdes =
"These huge monsters normally live below the sand, but your movements have "
"disturbed them. They are too big to be slain with your "
"weapons, but you can defeat them by making them unable to move. "
"This also produces some Spice. They move two times slower than you.";
const char *cocytushelp =
"This frozen lake is a hellish version of the Icy Land. Now, your body heat melts the floor, not the walls.";
const char *tentdes =
"The tentacles of Cthulhu are like sandworms, but longer. "
"They also withdraw one cell at a time, instead of exploding instantly.";
const char *gameboardhelp =
"Ever wondered how some boardgame would look on the hyperbolic plane? "
"I wondered about Go, so I have created this feature. Now you can try yourself!\n"
"Enter = pick up an item (and score), space = clear an item\n"
"Other keys place orbs and terrain features of various kinds\n"
"In the periodic editor, press 0-4 to switch walls in different ways\n"
;
const char *ivydes =
"A huge plant growing in the Jungle. Each Ivy has many branches, "
"and one branch grows per each of your moves. Branches grow in a clockwise "
"order. The root itself is vulnerable.";
const char *slimehelp =
"The Alchemists produce magical potions from pools of blue and red slime. You "
"can go through these pools, but you cannot move from a blue pool to a red "
"pool, or vice versa. Pools containing items count as colorless, and "
"they change color to the PC's previous color when the item is picked up. "
"Slime beasts also have to keep to their own color, "
"but when they are killed, they explode, destroying items and changing "
"the color of the slime and slime beasts around them.";
const char *gdemonhelp =
"These creatures are slow, but very powerful... more powerful than you. "
"You need some more experience in demon fighting before you will be able to defeat them. "
"Even then, you will be able to slay this one, but more powerful demons will come...\n\n"
"Each 10 lesser demons you kill, you become powerful enough to kill all the greater "
"demons on the screen, effectively turning them into lesser demons.";
const char *ldemonhelp =
"These creatures are slow, but they often appear in large numbers.";
const char *trollhelp =
"A big monster from the Living Caves. A dead Troll will be reunited "
"with the rocks, causing some walls to grow around its body.";
EX const char *trollhelp2 =
" Additionally, all items around the killed Troll will be destroyed.";
const char *trollhelpX =
"There are several species of trolls living in the hyperbolic world. "
"Some of them leave this wall behind them when they die.";
const char *camelothelp =
"The Knights of the Round Table are the greatest warriors of these lands. "
"They are not very inventive with names though, as they call each of their "
"castles Camelot. "
"You are probably worthy of joining them, but they will surely give you "
"some quest to prove yourself...\n\n"
"Each castle contains a single treasure, the Holy Grail, in the center. "
"The radius of the Round Table is usually 28, but after you find a Holy Grail "
"successfully, each new castle (and each Round Table) you find will be bigger.";
const char *templehelp =
"The temple of Cthulhu consists of many concentric circles of columns. "
"You will surely encounter many Cultists there, who believe that a pilgrimage "
"to the inner circles will bring them closer to Cthulhu himself, and Grimoires "
"which surely contain many interesting secrets.\n\n"
"The circles in the temple of Cthulhu are actually horocycles. They are "
"infinite, and there is an infinite number of them.";
const char *barrierhelp =
"Huge, impassable walls which separate various lands.";
const char *cavehelp =
"This cave contains walls which are somehow living. After each turn, each cell "
"counts the number of living wall and living floor cells around it, and if it is "
"currently of a different type than the majority of cells around it, it switches. "
"Items count as three floor cells, and dead Trolls count as five wall cells. "
"Some foreign monsters also count as floor or wall cells.\n";
const char *vinehelp =
"The Vineyard is filled with vines. A very dense pattern of straight lines here...\n\n"
"Vine Beasts and Vine Spirits change vine cells to grass, and vice versa.";
const char *hvinehelp =
"A vine is growing here... but only on a half of the cell. How is that even possible?!"
"Most monsters cannot move from this cell to the cell containing the other half. "
"Vine spirits can move only to the adjacent cells which are also adjacent to the "
"other half.";
const char *deadcavehelp =
"Somehow, this cave has not received the spark of Life yet.";
const char *foresthelp =
"This forest is quite dry. Beware the bushfires!\n"
"Trees catch fire on the next turn. The temperature of the grass cells "
"rises once per turn for each fire nearby, and becomes fire itself "
"when its temperature has risen 10 times.\n"
"You can also chop down the trees. Big trees take two turns to chop down.";
const char *hivehelp =
"The Hive is filled with Hyperbugs. They are huge insects which look a bit like "
"ants, a bit like bees, and a bit like roaches. "
"They live in circular nests, and an army of Hyperbugs will attack any intruder, "
"including you and enemy Hyperbugs. Will you manage to get to the "
"heart of such a nest, and get the precious Royal Jelly?";
const char *redrockhelp =
"This land contains high rock formations. Most of the valley is at level 0, "
"while items are found at level 3. It is impossible to gain two or more levels, "
"or to lose three levels, in a single move, (attacks are possible at any "
"difference, though). Kill Red Trolls and Rock Snakes to make a cell higher.";
const char *caribbeanhelp =
"This dangerous sea contains nasty sharks and pirates. ";
const char *cislandhelp =
"The islands of Caribbean are infinite and circular, and "
"the pirates probably have hidden their treasures somewhere far from the coast.";
const char *redsnakedes =
"Rock snakes are similar to Sandworms, but they move each turn. However, they "
"only move on the hexagonal cells. They are also somewhat longer than the Sandworms.";
const char *minedesc =
"This minefield has been created by the Bomberbirds to protect their valuable eggs. "
"Mines explode when they are stepped on, creating fire all around them "
"(this fire never expires in the Minefield). If you don't step on a mine, you "
"know the number of mines in cells around you. These numbers are marked with "
"color codes on the cells you have visited.";
const char *palacedesc =
"So better just to concentrate on collecting treasure. "
"Beware the traps, and the guards, who are hard to kill!";
const char *gatedesc =
"Green pressure plates open all gates in radius 3 around them. "
"Similarly, red pressure plates close all gates in this radius.";
const char *princessdesc =
"A mouse squeaks at you. It seems that it wants you to go somewhere. "
"That's interesting, what could you find here?\n\n"
"Note: in the part of the Palace that you are exploring during this "
"quest, the distribution of monsters, pressure plates, and items has been "
"changed somewhat, to make it a bit more suitable for less "
"experienced players. The number of monsters does not depend on the "
"number of Hypersian Rugs you have collected, and there are more "
"opening plates.\n\n"
"However, even with the normal distribution, it appears that it should be "
"always possible to reach your goal. If you want this challenge, "
"select it from the special game modes menu.";
const char *elemdesc =
"The Elemental Planes are divided into four subzones: Planes of Fire, Water, Air, and Earth. "
"You need to collect a Shard from each Plane to construct an Elemental Gem. "
"It is dangerous to collect too many Shards of the same type without constructing a Gem.";
const char *wildwestdesc =
"Take a revolver, kill outlaws, collect bounties.\n\n"
"Note: since this land is anachronistic, it is not available in normal game. "
"It is only available in special modes.";
const char *elecdesc =
"Whenever after your move there is a connection between a charged and a "
"grounded cell, there is a short circuit. All cells on any "
"path connecting a charged and a grounded cell (without repeated cells, "
"or two consecutive grounded/charged cells) become damaged.\n\n"
"Sandstone walls and most creatures are conductive. Great Walls are "
"isolators, but lands beyond them count as grounded.\n\n"
"Fulgurite, the treasure, is created when you manage to short circuit "
"a sandstone wall, or a Rich Metal Beast.\n\n"
"Trolls leave conductive rocks when killed, and Metal Beasts can only "
"be killed by electricity -- your attacks only stun them, or push "
"them away if already stunned.";
const char *overdesc =
"The Overgrown Woods are filled with mutant ivies! These plants "
"grow very fast. Each leaf, after being grown, can grow itself "
"on the next turn. However, each part is only able to grow "
"once in 16 turns. Outside of the Overgrown Woods, the Mutant Ivy "
"may grow only on hexagonal cells.\n\n"
"Maybe such fast growing plants could help you solve the problem "
"of hunger in your world? Kill the Mutant Ivies to collect Mutant Saplings.";
const char *cleardesc =
"A clearing in the Overgrown Woods. Obviously, this gives "
"the Mutant Ivies an infinite space to grow...\n\n"
"Mutant Fruits rot if they are not adjacent to a Mutant Ivy.";
const char *winddesc =
"Someone has put air fans in these plains, causing strong winds everywhere. "
"You think that the purpose is to harness the magical power of Air Elementals, but "
"you are not sure.\n\n"
"All cells except fans are grouped into three colors according to a pattern. "
"Wind blows counterclockwise around each group of cells of a single color. "
"Cells which are blocked by walls, or at distance at most 2 from an Air Elemental, "
"do not count for this.\n\n"
"It is illegal to move in a direction which is closer to incoming wind than to "
"outgoing wind. However, you can move two cells with the wind in a single turn, "
"and so can the birds.";
const char *warningdesc =
"Warnings are issued when you try to do something that appears dangerous, "
"like stepping on a known mine, or getting your boat destroyed by "
"a Kraken without having Orb of the Fish. In some cases the action "
"might actually be safe -- so you can ignore the warning and do it anyway, "
"simply by repeating the action.";
const char *hauntdesc =
"A dark forest filled with ghosts and graves. But there is also treasure hidden "
"deep within... But don't let greed make you stray from your path, as "
"you can get lost!\n\n"
"The Haunted Woods are bounded by a single equidistant curve. It is not a circle or horocycle.\n\n";
const char *bulldashdesc =
"Butterflies don't pursue you -- unless you get next to them, they just spin around the obstacles. "
"They cannot be killed conventionally, but you get treasure when a Raging Bull crashes into a Butterfly. ";
const char *prairiedesc =
"You can find safety in some places in the Prairie, but if you want treasures, "
"they can be found only on the other side of a giant herd of bulls.";
const char *cadesc =
"A land for people wanting to experiment with cellular automata in the HyperRogue grid. "
"Rules can be given on the command line; the default rules are:\n"
"-c07 00100000 -c06 0010000 -c17 00011000 -c16 0001100 -caprob 0.3\n"
"(-c0 or -c1 can be given if the same rule is to be used for hexagonal "
"and heptagonal cells).";
const char *huntingdesc =
"The Happy Hunting Ground is the place where hunting is easy; "
"the spirits of hunters go here after their death, if their life was deemed worthy. "
"You did not qualify though, so you will not ever be able to find your way to the places "
"where the hunter spirits and game are... "
"and their hunting dogs will hunt you instead!\n\n"
"You hope to use this to learn some "
"skills in fighting in open hyperbolic space, though.";
const char *terradesc =
"Spending 3-5 turns next to the Terracotta Warriors will cause them to awaken. "
"They have 7 HP, and get stunned for longer and longer time with each attack.";
const char *terraldesc =
"The Emperor's mausoleum. The army "
"of Terracotta Warriors is supposed to protect him in his "
"afterlife, while the traps are to protect the treasures "
"in the mausoleum from thieves.";
const char *arrowtrapdesc =
"The arrow traps will automatically launch a deadly arrow when stepped on. They are quite old though, so the arrow will "
"actually fly at the end of the next turn.";
const char *lavadesc =
"The volcanic activity in this land is extremely unstable. "
"Lava is too hot to walk on. It cools quickly, but another "
"flow will come soon...";
const char *blizzarddesc =
"Once in the past there lived a tribe whose prophets warned about the great blizzard that was to come and freeze the world. "
"They thought it was the wrath of the gods, so they put some altars, so that the gods could hear their pleas. "
"The mighty golems guarded those altars, making sure nobody steals the jewels, because a robbed god is a angry god. "
"Unfortunately winter has come (maybe because only the monks knew how to stop the golems, and they were said to had escaped earlier with some of the jewels). "
"The tribe has frozen to death, altars got covered with snow and ice. Only ice golems still guard them waiting for the spring.";
const char *crystaldesc =
"Yes, this is definitely a crystal. A very regular crystalline structure.\n\n"
"This land has been designed as a tool to play with various geometries, and it does not appear during a normal gameplay.";
const char *NODESC = "No description yet.";
const char *NODESCYET = "No description yet.";
const char *GENDERSWITCH = NODESC;
// --- monsters ---
EX const char *rosedesc =
"Each eight turns, each rosebush at distance at most 5 from you will "
"release a wave of alluring scent. Creatures on the frontwave "
"will move towards where the scent came from. Even if it causes them "
"to attack their friends or beautiful creatures, or move into water, fire, chasm, or thorns of the rosebush. "
"Ivies, Ghosts, Rock Snakes, Rose Ladies and Lords, and monsters restricted to a specific "
"terrain are immune to scents.";
EX const char *warpdesc =
"This part of the world is warped, restricting the movement somewhat. "
"\"Diagonal\" movement and attacking between triangular cells is not allowed. "
"Flash, Storms, and Freedom spells ignore this, and Ghosts can move, attack, and "
"be attacked diagonally.";
const char *warplanddesc =
"This land is warped. Ironically, the coast is completely straight...";
const char *roselanddesc =
"This land is filled with beautiful, but dangerous, creatures and plants.";
const char *dragondesc =
"Dragons are powerful monsters. They are slow, but evil, "
"and love to pick on creatures who are even slower than "
"them. They must be stopped!\n\n"
"A Dragon moves each two turns. It may attack with all its segments, "
"or move its whole body forwards or "
"backwards, it may also move a frontal part backwards. To kill a Dragon, "
"you need to hit each of its segments. "
"The head will regenerate on the "
"turns the Dragon is not moving, so you will usually have to hit it with "
"your last attack; otherwise, if the head is healthy, it may breathe "
"fire (at range 3), losing the hitpoint. Killing the Dragon "
"while still in the Dragon Chasms gives you treasure.";
const char *tortoisedesc =
"Galápagos is the land of Tortoises. "
"They are very slow, which allows the Dragons to pick on them by "
"stealing and eating their young. Bring the Baby Tortoises back, "
"but, there is a catch: the Tortoises come in many varieties, depending "
"on the part of Galápagos they live in -- there are 21 binary environmental "
"factors, and thus "
"2097152 varieties. You'll have to find a "
"Tortoise which matches the baby exactly!\n\n"
"Tortoises move each 3 turns, and attacks only stun them.\n\n"
"Bringing back a Baby Tortoise counts as 5 $$$. The more factors agree in "
"the given location of Galápagos, the brighter it is shown on your screen.";
const char *krakendesc =
"There are Krakens in your homeland, too... huge sea monsters which "
"could easily destroy ships. The geometry of this strange world "
"prevents quick movement of huge objects, "
"so there are no large ships, only small boats, and "
"hyperbolic Krakens are relatively small too. Still, you suppose they might be "
"the widest creatures which could still move at considerable speed...\n\n"
"Kraken heads can move only on hexagons. You need to attack all the tentacles to "
"kill the Kraken. A tentacle cannot attack if it has been attacked on the "
"same turn. When a Kraken attacks you while you are in a boat, it "
"destroys the boat, but does not kill you.";
const char *halloweendesc =
"Halloween is a special land, that is available only in the spherical "
"or elliptic geometry (press 'o' to switch). You play on the surface of "
"a jack-o'-lantern, "
"and have to collect as many Treats as possible. Each Treat you collect "
"brings new monsters to fight, and new magical powers for you. You "
"have to fight the monsters while effectively managing your limited "
"resources.";
const char *reptiledesc =
"These reptiles are quite strange creatures. They "
"spend most of their lives sleeping as floors "
"that other creatures can walk on. "
"Sometimes they wake up to hunt their prey, "
"but they will happily go back to sleep if they "
"happen to move into a hole on their way. "
"Your attacks do not kill the Reptiles, but "
"you can push and stun them.";
const char *naturedesc =
"This Orb allows you to grow like an Ivy. "
"The Ivy is always rooted in your current location; "
"moving among the Ivy cells will move the root. "
"Moving to a new location will cause the Ivy to grow "
", if an Ivy could make that movement "
"(otherwise it breaks). "
"You can also target one of the cells adjacent to your ivy "
"(not to you) to grow or attack there.";
const char *mirroreddesc =
"A perfect mirror wall. It is unbreakable "
"and impassable "
"even for aethereal beings, and everything "
"you see inside is just an image of "
"the real world; you can swing your sword "
"at them, but that will not destroy them "
"in the real world. "
"Mirror walls reflect Mimics, lightning bolts, and "
"missiles perfectly.";
const char* tamebomberdesc =
"This bomberbird will follow you at some distance, and attack your enemies. "
"You can kill it to place a mine.";
const char *gargdesc =
"A being made of stone, who likes high buildings. It becomes normal stone when "
"killed, but only if next to something stable -- otherwise it falls.";
const char *lakeDesc = "Hell has these lakes everywhere... They are shaped like evil stars, and filled with burning sulphur.";
const char *thumpdesc = "A device that attracts sandworms and other enemies. You need to activate it.";
const char *twdesc = "This structure will disappear after some time.";
const char *jellydesc =
"Some of the Slime Beasts have decided to revolt against the color rules in the "
"Alchemist Lab. They have changed their shape and consistency, declared independence, and established their own Kingdom.\n\n"
"Jellies switch between being a wall and being a monster after every treasure you collect.";
const char *ruindesc =
"Once a beautiful city... but now overrun by the mighty Raiders of unknown origin.\n\n"
"Raiders cannot be harmed with mundane weapons, but each color has its movement restrictions.";
const char *rock_description =
"Shoot the Space Rocks for score. Large Rocks will split into two smaller rocks.";
#if HDR
enum eSlimegroup { sgNone, sgCave, sgWater, sgFloorA, sgFloorB, sgVine, sgTree };
#endif
#if HDR
// we use CF not MF to avoid confusion with MF_ movement flags
static constexpr flagtype CF_NOGHOST = Flag(0);
static constexpr flagtype CF_RAIDER = Flag(1);
static constexpr flagtype CF_PRINCESS = Flag(2);
static constexpr flagtype CF_MIMIC = Flag(3);
static constexpr flagtype CF_GOK = Flag(4);
static constexpr flagtype CF_NONLIVING = Flag(5);
static constexpr flagtype CF_METAL = Flag(6);
static constexpr flagtype CF_STUNNABLE = Flag(7);
static constexpr flagtype CF_HP = Flag(8);
static constexpr flagtype CF_MOUNTABLE = Flag(9);
static constexpr flagtype CF_FRIENDLY = Flag(10);
static constexpr flagtype CF_PLAYER = Flag(11);
static constexpr flagtype CF_BUG = Flag(12);
static constexpr flagtype CF_IVY = Flag(13);
static constexpr flagtype CF_PART = Flag(14);
static constexpr flagtype CF_MUTANTIVY = Flag(15);
static constexpr flagtype CF_ANYIVY = Flag(16);
static constexpr flagtype CF_BULLET = Flag(17);
static constexpr flagtype CF_DEMON = Flag(18);
static constexpr flagtype CF_WORM = Flag(19);
static constexpr flagtype CF_WITCH = Flag(20);
static constexpr flagtype CF_BIRD = Flag(21);
static constexpr flagtype CF_SLOWMOVER = Flag(22);
static constexpr flagtype CF_MAGNETIC = Flag(23);
static constexpr flagtype CF_SWITCH = Flag(24);
static constexpr flagtype CF_GHOST = Flag(25);
static constexpr flagtype CF_SHARK = Flag(26);
static constexpr flagtype CF_SLIME = Flag(27);
static constexpr flagtype CF_DRAGON = Flag(28);
static constexpr flagtype CF_KRAKEN = Flag(29);
static constexpr flagtype CF_NOBLOW = Flag(30);
static constexpr flagtype CF_MULTITILE = Flag(31);
static constexpr flagtype CF_LEADER = Flag(32);
static constexpr flagtype CF_FLYING = Flag(33);
static constexpr flagtype CF_ATTACK_THRU_VINE = Flag(34);
static constexpr flagtype CF_ATTACK_NONADJACENT = Flag(35);
static constexpr flagtype CF_NOHIGHLIGHT = Flag(36);
static constexpr flagtype CF_INACTIVE = Flag(37);
static constexpr flagtype CF_UNARMED = Flag(38);
static constexpr flagtype CF_IGNORE_PLATE = Flag(39);
static constexpr flagtype CF_BULL = Flag(40);
static constexpr flagtype CF_TROLL = Flag(41);
static constexpr flagtype CF_IGNORE_SMELL = Flag(42);
static constexpr flagtype CF_RATLING = Flag(43);
static constexpr flagtype CF_POWER = Flag(44);
static constexpr flagtype CF_GHOSTMOVER = Flag(45);
static constexpr flagtype CF_TECHNICAL = Flag(46);
static constexpr flagtype CF_MOVED = Flag(47);
static constexpr flagtype CF_FACING = Flag(48);
static constexpr flagtype CF_FACE_UP = Flag(49);
static constexpr flagtype CF_FACE_SIDE = Flag(50);
static constexpr flagtype CF_HIGH_THREAT = Flag(51);
static constexpr flagtype CF_SPAM = Flag(52);
enum eMonster {
#define MONSTER(a,b,c,d,e,f,g,h) d,
#include "content.cpp"
motypes
};
struct monstertype {
char glyph;
color_t color;
const char *name;
flagtype flags;
enum eMonster mgroup;
const char *help;
};
#endif
EX monstertype minf[motypes] = {
#define MONSTER(a,b,c,d,e,f,g,h) {a,b,c,e,g,h},
#include "content.cpp"
};
#if HDR
#define NUM_GS 8
struct genderswitch_t {
int gender;
eMonster m;
const char *name;
const char *desc;
};
#endif
EX genderswitch_t genderswitch[NUM_GS] = {
{ GEN_F, moFalsePrincess, "False Princess",
"Don't be fooled by this red-haired girl, or you will be stabbed if you come too close!"},
{ GEN_M, moFalsePrincess, "False Prince",
"Don't be fooled by this red-haired boy, or you will be stabbed if you come too close!"},
{ GEN_F, moRoseLady, "Rose Lady",
"This false princess is immune to the alluring scent of roses."},
{ GEN_M, moRoseLady, "Rose Lord",
"This false prince is immune to the alluring scent of roses."},
{ GEN_F, moRoseBeauty, "Rose Beauty",
"She has flowers in her long fair hair. You could not bring yourself to attack such a beautiful woman."},
{ GEN_M, moRoseBeauty, "Handsome Gardener",
"Tall, strong, and holding a flower in his hand. You could "
"not bring yourself to attack such a handsome man."},
{ GEN_F, moRusalka, "Rusałka",
"A malicious water being. When you kill her, she changes the tile you are standing on, from land to shallow water, or from shallow water to deep water."},
{ GEN_M, moRusalka, "Topielec",
"A malicious water being. When you kill him, he changes the tile you are standing on, from land to shallow water, or from shallow water to deep water."},
};
// --- items ---
#if HDR
enum eOrbshape { osNone, osLove, osRanged, osOffensive, osFriend, osUtility, osDirectional, osWarping, osFrog, osPowerUtility, osProtective, osMovement, osTerraform };
static constexpr flagtype ZERO = 0;
static constexpr flagtype IF_SHARD = Flag(0);
static constexpr flagtype IF_FIREPROOF = Flag(1);
static constexpr flagtype IF_PROTECTION = Flag(2);
static constexpr flagtype IF_EMPATHY = Flag(3);
static constexpr flagtype IF_RANGED = Flag(4);
static constexpr flagtype IF_SHMUPLIFE = Flag(5);
static constexpr flagtype IF_REVIVAL = Flag(6);
static constexpr flagtype IF_CURSE = Flag(7);
// 0 = basic treasure, 1 = other item, 2 = power orb, 3 = not an item
#define IC_TREASURE 0
#define IC_OTHER 1
#define IC_ORB 2
#define IC_NAI 3
struct itemtype {
char glyph;
color_t color;
const char *name;
int itemclass;
flagtype flags;
eOrbshape orbshape;
const char *help;
};
enum eItem {
#define ITEM(a,b,c,d,e,f,g,h,i) d,
#include "content.cpp"
ittypes
};
#endif
EX itemtype iinf[ittypes] = {
#define ITEM(a,b,c,d,e,f,g,h,i) {a,b,c,e,f,h,i},
#include "content.cpp"
};
// --- wall types ---
#if HDR
static constexpr flagtype WF_WATER = Flag(0);
static constexpr flagtype WF_BOAT = Flag(1);
static constexpr flagtype WF_CHASM = Flag(2);
static constexpr flagtype WF_NOFLIGHT = Flag(3);
static constexpr flagtype WF_FIRE = Flag(4);
static constexpr flagtype WF_THUMPER = Flag(5);
static constexpr flagtype WF_ACTIVABLE = Flag(6);
static constexpr flagtype WF_ALCHEMY = Flag(7);
static constexpr flagtype WF_RED = Flag(8);
static constexpr flagtype WF_WALL = Flag(9);
static constexpr flagtype WF_PUSHABLE = Flag(10);
static constexpr flagtype WF_CONE = Flag(11);
static constexpr flagtype WF_STDTREE = Flag(12);
static constexpr flagtype WF_GRAVE = Flag(13);
static constexpr flagtype WF_REPTILE = Flag(14);
static constexpr flagtype WF_HEATCOLOR = Flag(15);
static constexpr flagtype WF_HIGHWALL = Flag(16);
static constexpr flagtype WF_THORNY = Flag(17);
static constexpr flagtype WF_TIMEOUT = Flag(18);
static constexpr flagtype WF_CISLAND = Flag(19);
static constexpr flagtype WF_SULPHURIC = Flag(20);
static constexpr flagtype WF_HALFVINE = Flag(21);
static constexpr flagtype WF_NONBLOCK = Flag(22);
static constexpr flagtype WF_ON = Flag(23); // just for grammar: 'on' not 'in'
struct walltype {
char glyph;
color_t color;
const char *name;
flagtype flags;
int snakelevel;
eSlimegroup sg;
const char *help;
};
enum eWall {
#define WALL(a,b,c,d,e,f,g,h,i) d,
#include "content.cpp"
walltypes
};
#endif
EX walltype winf[walltypes] = {
#define WALL(a,b,c,d,e,f,g,h,i) {a,b,c,e,g,h,i},
#include "content.cpp"
};
// -- land types ---
#if HDR
enum eCanvasFloor { caflNone, caflM, caflFull, caflWarp, caflStar, caflCloud, caflCross, caflCharged,
caflSStar, caflOver, caflTri, caflFeather, caflBarrow, caflNew, caflTroll, caflButterfly, caflLava,
caflPalace, caflDemon, caflCave, caflDesert, caflPower, caflRose, caflTurtle, caflDragon, caflReptile,
caflHive, caflSwitch, caflTower, caflEND };
static constexpr flagtype LF_GENERATE_ALL = Flag(0);
static constexpr flagtype LF_ICY = Flag(1);
static constexpr flagtype LF_GRAVITY = Flag(2);
static constexpr flagtype LF_EQUI = Flag(3);
static constexpr flagtype LF_WARPED = Flag(4);
static constexpr flagtype LF_CYCLIC = Flag(5);
static constexpr flagtype LF_TECHNICAL = Flag(6);
static constexpr flagtype LF_MIRROR = Flag(7);
static constexpr flagtype LF_SEA = Flag(8);
static constexpr flagtype LF_COASTAL = Flag(9);
static constexpr flagtype LF_PURESEA = Flag(10);
static constexpr flagtype LF_ELEMENTAL = Flag(11);
static constexpr flagtype LF_HAUNTED = Flag(12);
static constexpr flagtype LF_TROLL = Flag(13);
static constexpr flagtype LF_INMIRROR = Flag(14);
static constexpr flagtype LF_INMIRRORORWALL = Flag(15);
static constexpr flagtype LF_ELECTRIC = Flag(17);
struct landtype {
color_t color;
const char *name;
flagtype flags;
eItem treasure;
const char *help;
};
enum eLand {
#define LAND(a,b,c,d,e,f,g) c,
#include "content.cpp"
landtypes
};
extern color_t floorcolors[landtypes];
#endif
EX const char *canvasFloorNames[caflEND] = {
"default", "smaller", "full", "warped", "star", "cloud", "cross", "charged",
"saloon", "overgrown", "triangle", "feather", "barrow", "elemental", "troll", "butterfly", "lava",
"palace", "demon", "cave", "desert", "power", "rose", "turtle", "dragon", "reptile",
"hive", "jelly", "tower"
};
EX const landtype linf[landtypes] = {
#define LAND(a,b,c,d,e,f,g) {a,b,d,e,g},
#include "content.cpp"
};
#if HDR
struct landtacinfo { eLand l; int tries, multiplier; };
#endif
EX vector<landtacinfo> land_tac = {
{laIce, 10, 1}, {laDesert, 10, 1},
{laHunting, 5, 2},
{laMotion, 10, 1}, {laCaves, 10, 1}, {laAlchemist, 10, 1},
{laJungle, 10, 1}, {laMirror, 10, 1}, {laZebra, 10, 1}, {laPalace, 10, 1},
{laOcean, 10, 1}, {laLivefjord, 10, 1}, {laWarpCoast, 10, 1}, {laRlyeh, 10, 1}, {laHell, 10, 1},
{laDryForest, 10, 1}, {laWineyard, 10, 1}, {laSwitch, 10, 1}, {laReptile, 10, 1},
{laDeadCaves, 10, 1}, {laGraveyard, 10, 1},
{laHaunted, 10, 1},
{laIvoryTower, 10, 1}, {laEndorian, 10, 1}, {laMountain, 5, 2}, {laDungeon, 5, 2},
{laRuins, 10, 1}, {laEmerald, 10, 1},
{laCocytus, 10, 1},
{laCaribbean, 5, 2}, {laWhirlpool, 5, 2}, {laKraken, 5, 2},
{laTemple, 5, 2}, {laMinefield, 5, 2},
{laPower, 5, 2}, {laHive, 5, 2}, {laRedRock, 5, 2}, {laStorms, 5, 2}, {laOvergrown, 5, 2},
{laClearing, 5, 2},
{laWhirlwind, 5, 2},
{laBlizzard, 10, 1},
{laRose, 5, 2}, {laVolcano, 10, 1}, {laDragon, 2, 5}, {laTortoise, 1, 10},
{laBurial, 5, 2},
{laElementalWall, 10, 1}, {laTrollheim, 5, 2},
{laPrairie, 5, 2}, {laBull, 5, 2}, {laTerracotta, 10, 1},
{laDice, 5, 2}, {laCursed, 5, 2},
{laCrossroads, 10, 1}, {laCrossroads2, 10, 1}, {laCrossroads3, 10, 1}, {laCrossroads4, 10, 1}, {laCrossroads5, 5, 2},
{laCamelot, 1, 100},
{laWildWest, 10, 1},
{laDual, 10, 1},
{laSnakeNest, 10, 1},
{laDocks, 10, 1},
{laBrownian, 10, 1},
{laVariant, 10, 1},
{laWestWall, 10, 1},
{laWet, 10, 1}, {laFrog, 10, 1}, {laEclectic, 10, 1},
};
EX vector<eLand> randlands = {
laIce, laDesert, laCaves, laAlchemist, laGraveyard, laPower, laLivefjord, laZebra,
laRlyeh, laDryForest, laEmerald, laWineyard, laDeadCaves, laRedRock,
laOvergrown, laWildWest, laWarpCoast, laRuins, laBull, laDragon, laReptile, laDocks,
laFrog, laWet, laZebra
};
#if HDR
enum eGeometry {
gNormal, gEuclid, gSphere, gElliptic, gZebraQuotient, gFieldQuotient, gTorus, gOctagon, g45, g46, g47, gSmallSphere, gTinySphere, gEuclidSquare, gSmallElliptic,
gKleinQuartic, gBolza, gBolza2, gMinimal, gBinaryTiling, gArchimedean,
gMacbeath, gBring, gSchmutzM2, gSchmutzM3, gCrystal, gOctahedron,
gBinary3, gCubeTiling, gCell120, gECell120, gRhombic3, gBitrunc3,
gSpace534, gSpace435,
gCell5,
gCell16, gECell16,
gCell8, gECell8,
gCell24, gECell24,
gCell600, gECell600,
gHoroTris, gHoroRec, gHoroHex,
gField435, gField534,
gBinary4, gSol,
gKiteDart2, gKiteDart3, gNil, gProduct, gRotSpace,
gTernary, gNIH, gSolN, gInfOrder, gSpace336, gSpace344, gCrystal344,
gArnoldCat, gArbitrary, gInfOrder4, gCrystal534,
gSpace535, gSpace536, gSeifertCover, gSeifertWeber, gHomologySphere,
gInfOrderMixed, gSpace436, gFake,
gSpace345, gSpace353, gSpace354, gSpace355,
gHalfBring,
gAperiodicHat,
gSierpinski3, gSierpinski4, gSixFlake, gMengerSponge, gSierpinskiTet,
gAperiodicSpectre,
gGUARD};
enum eGeometryClass { gcHyperbolic, gcEuclid, gcSphere, gcSol, gcNIH, gcSolN, gcNil, gcProduct, gcSL2 };
enum class eVariation { bitruncated, pure, goldberg, irregular, dual, untruncated, warped, unrectified, subcubes, coxeter, dual_subcubes, bch, bch_oct };
typedef int modecode_t;
/** only the actual geometry */
struct geometryinfo1 {
/** geometry class */
eGeometryClass kind;
/** dimension of the gameplay (2 for crystal) */
int gameplay_dimension;
/** dimension of the graphics, may be greater than gameplay_dimension with vid.always3 on */
int graphical_dimension;
/** dimension of the homogeneous vector space used, usually graphical_dimension+1, but 3 in product */
int homogeneous_dimension;
/** signature of the scalar product used */
int sig[4];
};
struct geometryinfo {
std::string tiling_name;
std::string quotient_name;
const char* menu_displayed_name;
const char* shortname;
int sides;
int vertex;
flagtype flags;
geometryinfo1 g;
std::array<int,2> distlimit; // bitrunc, non-bitrunc
eVariation default_variation;
};
static constexpr flagtype qCLOSED = 1;
static constexpr flagtype qANYQ = 2;
static constexpr flagtype qNONORIENTABLE = 4;
static constexpr flagtype qSMALL = 8;
static constexpr flagtype qFIELD = 16;
static constexpr flagtype qDOCKS = 32;
static constexpr flagtype qZEBRA = 64;
static constexpr flagtype qELLIPTIC = 128;
static constexpr flagtype qBINARY = 256;
static constexpr flagtype qKITE = 512;
static constexpr flagtype qREGULAR = 1024; /* not set! */
static constexpr flagtype qARCHI = 2048;
static constexpr flagtype qHYBRID = 4096;
static constexpr flagtype qCRYSTAL = 8192;
static constexpr flagtype qSOL = 16384;
static constexpr flagtype qEXPERIMENTAL = 32768;
static constexpr flagtype qNIH = 65536;
static constexpr flagtype qIDEAL = 131072;
static constexpr flagtype qHUGE_BOUNDED = 262144;
static constexpr flagtype qOPTQ = Flag(19);
static constexpr flagtype qSINGLE = Flag(20);
static constexpr flagtype qDEPRECATED = Flag(21);
static constexpr flagtype qINFMIXED = Flag(22);
static constexpr flagtype qRAYONLY = Flag(23);
static constexpr flagtype qAFFINE = Flag(24);
static constexpr flagtype qULTRA = Flag(25);
static constexpr flagtype qPORTALSPACE = Flag(26);
static constexpr flagtype qSTRETCHABLE = Flag(27);
static constexpr flagtype qCAT = Flag(28);
static constexpr flagtype qAPERIODIC = Flag(29);
static constexpr flagtype qHAT = Flag(30);
static constexpr flagtype qFRACTAL = Flag(31);
// note: dnext assumes that x&7 equals 7
static constexpr int SEE_ALL = 50;
// note: check_football_colorability in arbitrile.cpp assumes OINF is divisible by 3
static constexpr int OINF = 123;
extern eGeometry geometry;
extern eVariation variation;
#endif
#if HDR
static constexpr flagtype qsNONOR = qANYQ | qSMALL | qCLOSED | qNONORIENTABLE;
static constexpr flagtype qsNONORE = qsNONOR | qELLIPTIC;
static constexpr flagtype qsBQ = qANYQ | qSMALL | qCLOSED;
static constexpr flagtype qsSMALL = qANYQ | qSMALL | qCLOSED;
static constexpr flagtype qsSMALLN = qANYQ | qSMALL | qCLOSED | qNONORIENTABLE;
static constexpr flagtype qsZEBRA = qANYQ | qSMALL | qCLOSED | qZEBRA;
static constexpr flagtype qsFIELD = qANYQ | qFIELD | qCLOSED;
static constexpr flagtype qsDOCKS = qANYQ | qSMALL | qCLOSED | qDOCKS;
static constexpr flagtype qsSMALLB = qSMALL | qCLOSED;
static constexpr flagtype qsSMALLBF = qsSMALLB | qsFIELD | qANYQ;
static constexpr flagtype qsSMALLBE = qsSMALLB | qELLIPTIC | qANYQ;
static constexpr flagtype qsBP = qBINARY | qKITE;
static constexpr flagtype qsSINGLE = qANYQ | qSMALL | qCLOSED | qSINGLE;
#endif
EX geometryinfo1 giEuclid2 = { gcEuclid, 2, 2, 3, {1,1, 0,0 } };
EX geometryinfo1 giHyperb2 = { gcHyperbolic, 2, 2, 3, {1,1,-1,0 } };
EX geometryinfo1 giSphere2 = { gcSphere, 2, 2, 3, {1,1,+1,0 } };
EX geometryinfo1 giEuclid3 = { gcEuclid, 3, 3, 4, {1,1, 1,0 } };
EX geometryinfo1 giHyperb3 = { gcHyperbolic, 3, 3, 4, {1,1, 1,-1} };
EX geometryinfo1 giSphere3 = { gcSphere, 3, 3, 4, {1,1, 1,+1} };
EX geometryinfo1 giSol = { gcSol, 3, 3, 4, {1,1, 1,0 } };
EX geometryinfo1 giNIH = { gcNIH, 3, 3, 4, {1,1, 1,0 } };
EX geometryinfo1 giSolN = { gcSolN, 3, 3, 4, {1,1, 1,0 } };
EX geometryinfo1 giNil = { gcNil, 3, 3, 4, {1,1, 1,0 } };
EX geometryinfo1 giProductH= { gcProduct, 3, 3, 3, {1,1,-1,0 } };
EX geometryinfo1 giProductS= { gcProduct, 3, 3, 3, {1,1, 1,0 } };
EX geometryinfo1 giProduct = { gcProduct, 3, 3, 3, {1,1, 1,0 } /* will be filled in product::configure() */ };
EX geometryinfo1 giSL2 = { gcSL2, 3, 3, 4, {1,1,-1,-1} };
EX modecode_t no_code = 0x1;
/** list of available geometries */
EX vector<geometryinfo> ginf = {
{"{7,3}", "none", "{7,3} (standard HyperRogue map)", "HR", 7, 3, 0, giHyperb2, {{7, 5}}, eVariation::bitruncated},
{"{6,3}", "none", "{6,3} (euclidean Hex grid)", "euclid", 6, 3, qOPTQ, giEuclid2, {{7, 7}}, eVariation::bitruncated},
{"{5,3}", "none", "{5,3} (dodecahedron)", "sphere", 5, 3, qsSMALLB, giSphere2, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"{5,3}", "elliptic", "elliptic geometry in {5,3}", "elliptic", 5, 3, qsNONORE, giSphere2, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"{7,3}", "Zebra", "Zebra quotient", "Zebra", 7, 3, qsZEBRA, giHyperb2, {{7, 5}}, eVariation::bitruncated},
{"{7,3}", "field", "field quotient", "field", 7, 3, qsFIELD, giHyperb2, {{7, 5}}, eVariation::bitruncated},
{"{6,3}", "torus", "torus/Klein bottle/...", "torus", 6, 3, qsBQ|qDEPRECATED, giEuclid2, {{7, 7}}, eVariation::bitruncated},
{"{8,3}", "none", "{8,3} (like standard but with octagons)", "oct", 8, 3, 0, giHyperb2, {{6, 4}}, eVariation::bitruncated},
{"{5,4}", "none", "{5,4} (four pentagons)", "4x5", 5, 4, 0, giHyperb2, {{6, 4}}, eVariation::bitruncated},
{"{6,4}", "none", "{6,4} (four hexagons)", "4x6", 6, 4, 0, giHyperb2, {{5, 3}}, eVariation::bitruncated},
{"{7,4}", "none", "{7,4} (four heptagons)", "4x7", 7, 4, 0, giHyperb2, {{4, 3}}, eVariation::bitruncated},
{"{4,3}", "none", "{4,3} (cube)", "3x4", 4, 3, qsSMALLB, giSphere2, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"{3,3}", "none", "{3,3} (tetrahedron)", "3x3", 3, 3, qsSMALLB, giSphere2, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"{4,4}", "none", "{4,4} (Euclidean square grid)", "4x4", 4, 4, qOPTQ, giEuclid2, {{7, 7}}, eVariation::bitruncated},
{"{4,3}", "elliptic", "elliptic geometry in {4,3}", "e3x4", 4, 3, qsNONORE, giSphere2, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"{7,3}", "Klein", "Klein Quartic", "Klein", 7, 3, qsSMALL, giHyperb2, {{7, 5}}, eVariation::bitruncated},
{"{8,3}", "Bolza", "Bolza Surface", "Bolza", 8, 3, qsDOCKS, giHyperb2, {{6, 4}}, eVariation::bitruncated},
{"{8,3}", "Bolza2", "Bolza Surface x2", "Bolza2", 8, 3, qsDOCKS, giHyperb2, {{6, 4}}, eVariation::bitruncated},
{"{7,3}", "minimal", "minimal quotient", "minimal", 7, 3, qsSMALLN, giHyperb2, {{7, 5}}, eVariation::bitruncated},
{"binary","none", "variant of the binary tiling", "binary", 7, 3, qBINARY, giHyperb2, {{7, 5}}, eVariation::pure},
{"Arch", "none", "Archimedean", "A", 7, 3, qARCHI, giHyperb2, {{7, 5}}, eVariation::pure},
{"{7,3}", "Macbeath", "Macbeath Surface", "Macbeath", 7, 3, qsSMALL, giHyperb2, {{7, 5}}, eVariation::bitruncated},
{"{5,4}", "Bring", "Bring's Surface", "Bring", 5, 4, qsSMALL, giHyperb2, {{6, 4}}, eVariation::bitruncated},
{"{12,3}","M3", "Schmutz's M(3)", "M3", 12, 3, qsSMALL, giHyperb2, {{4, 2}}, eVariation::bitruncated},
{"{12,3}","M4", "Schmutz's M(4)", "M4", 12, 3, qsSMALL, giHyperb2, {{4, 2}}, eVariation::bitruncated},
{"{6,4}", "Crystal", "dimensional crystal", "Crystal", 6, 4, qANYQ|qCRYSTAL, giHyperb2, {{5, 3}}, eVariation::pure},
{"{3,4}", "none", "{3,4} (octahedron)", "4x3", 3, 4, qsSMALLB, giSphere2, {{SEE_ALL, SEE_ALL}}, eVariation::bitruncated},
{"bin{4,4}", "none", "{4,4} on horospheres", "bin44", 9, 3, qBINARY, giHyperb3, {{7, 3}}, eVariation::pure},
{"{4,3,4}","none", "{4,3,4} cube tiling", "434", 6, 4, qOPTQ, giEuclid3, {{7, 5}}, eVariation::pure},
{"{5,3,3}","none", "{5,3,3} 120-cell", "533", 12, 3, qsSMALLB | qSTRETCHABLE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{5,3,3}", "elliptic","{5,3,3} 120-cell (elliptic space)", "e533", 12, 3, qsSMALLBE | qSTRETCHABLE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"rh{4,3,4}","none", "rhombic dodecahedral honeycomb", "rh434", 12, 3, qOPTQ, giEuclid3, {{7, 5}}, eVariation::pure},
{"2t{4,3,4}","none", "bitruncated cubic honeycomb", "2t434", 14, 3, qOPTQ, giEuclid3, {{7, 5}}, eVariation::pure},
{"{5,3,4}","none", "{5,3,4} hyperbolic honeycomb", "534", 12, 4, 0, giHyperb3, {{7, 2}}, eVariation::pure},
{"{4,3,5}","none", "{4,3,5} hyperbolic honeycomb", "435", 6, 5, 0, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,3,3}","none", "{3,3,3} 5-cell", "333", 4, 3, qsSMALLB, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{3,3,4}","none", "{3,3,4} 16-cell", "334", 4, 4, qsSMALLB, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{3,3,4}","elliptic","{3,3,4} 16-cell (elliptic space)", "e334", 4, 4, qsSMALLBE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{4,3,3}","none", "{4,3,3} 8-cell", "433", 6, 4, qsSMALLB | qSTRETCHABLE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{4,3,3}","elliptic","{4,3,3} 8-cell (elliptic space)", "e433", 6, 4, qsSMALLBE | qSTRETCHABLE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{3,4,3}","none", "{3,4,3} 24-cell", "343", 8, 3, qsSMALLB | qSTRETCHABLE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{3,4,3}","elliptic","{3,4,3} 24-cell (elliptic space)", "e343", 8, 3, qsSMALLBE | qSTRETCHABLE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{3,3,5}","none", "{3,3,5} 600-cell", "335", 4, 3, qsSMALLB, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{3,3,5}","elliptic","{3,3,5} 600-cell (elliptic space)", "e335", 4, 3, qsSMALLBE, giSphere3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"bin{3,6}", "none", "{3,6} on horospheres", "bin36", 8, 3, qBINARY, giHyperb3, {{7, 3}}, eVariation::pure},
{"bin-rect", "none", "rectangles on horospheres", "bin44/2", 7, 3, qBINARY, giHyperb3, {{7, 3}}, eVariation::pure},
{"bin{6,3}", "none", "{6,3} on horospheres", "bin63", 14, 3, qBINARY, giHyperb3, {{7, 3}}, eVariation::pure},
{"{4,3,5}","field", "{4,3,5} field quotient space", "f435", 6, 5, qsSMALLBF | qDEPRECATED, giHyperb3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"{5,3,4}","field", "{5,3,4} field quotient space", "f435", 12, 4, qsSMALLBF | qDEPRECATED, giHyperb3, {{SEE_ALL, SEE_ALL}}, eVariation::pure},
{"binary4","none", "standard binary tiling", "binary4", 5, 3, qBINARY, giHyperb2, {{7, 5}}, eVariation::pure},
{"sol", "none", "Solv geometry", "sol", 8, 3, qBINARY|qSOL, giSol, {{7, 5}}, eVariation::pure},
{"kd2", "none", "kite-and-dart", "kd2", 4, 3, qKITE | qAPERIODIC, giEuclid2, {{7, 7}}, eVariation::pure},
{"kd3", "none", "kite-and-dart on horospheres", "kd3", 12, 3, qsBP, giHyperb3, {{7, 3}}, eVariation::pure},
{"nil", "none", "Nil geometry", "nil", 6, 3, qOPTQ, giNil, {{7, 5}}, eVariation::pure},
{"product","none", "product space", "product", 7, 3, qHYBRID, giProduct, {{7, 3}}, eVariation::pure},
{"twisted","none", "rotation space", "twisted", 7, 3, qHYBRID, giSL2, {{6, 4}}, eVariation::pure},
{"ternary","none", "standard ternary tiling", "ternary", 6, 3, qBINARY, giHyperb2, {{6, 4}}, eVariation::pure},
{"3x2", "none", "stretched hyperbolic", "3:2", 11, 3, qBINARY|qNIH, giNIH, {{6, 3}}, eVariation::pure},
{"3x1/2", "none", "stretched Solv", "3:1/2", 9, 3, (qBINARY|qSOL|qNIH), giSolN, {{7, 3}}, eVariation::pure},
{"{3,oo}", "none", "{3,∞} (infinite triangles)", "oox3", 3, OINF, qIDEAL, giHyperb2, {{7, 7}}, eVariation::pure},
{"{3,3,6}","none", "{3,3,6} hyperbolic honeycomb", "336", 4, 6, qIDEAL, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,4,4}","none", "{3,4,4} hyperbolic honeycomb", "344", 8, 4, qIDEAL, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,4,4}","Crystal", "4D crystal in H3", "Cryst3" , 8, 4, qIDEAL | qANYQ | qCRYSTAL, giHyperb3, {{7, 3}}, eVariation::pure},
{"cat", "cat", "Arnold's cat mapping torus", "cat", 12, 3, qBINARY | qSOL | qsBQ | qOPTQ | qCAT, giSol, {{6, 4}}, eVariation::pure},
{"file", "none", "load from file", "file", 7, 3, 0, giEuclid2, {{7, 5}}, eVariation::pure},
{"{4,oo}", "none", "{4,∞} (infinite squares)", "oox4", 4, OINF, qIDEAL, giHyperb2, {{5, 5}}, eVariation::pure},
{"{5,3,4}","Crystal", "6D crystal in H3", "Cryst6" , 12, 4, qANYQ | qCRYSTAL, giHyperb3, {{7, 3}}, eVariation::pure},
{"{5,3,5}","none", "{5,3,5} hyperbolic honeycomb", "535", 12, 5, 0, giHyperb3, {{7, 2}}, eVariation::pure},
{"{5,3,6}","none", "{5,3,6} hyperbolic honeycomb", "536", 12, 6, qIDEAL, giHyperb3, {{7, 2}}, eVariation::pure},
{"{5,3,5}","SWh", "{5,3,5} quotient", "535c", 12, 5, qsSMALLB | qANYQ, giHyperb3, {{7, 2}}, eVariation::pure},
{"{5,3,5}","SW", "Seifert-Weber space", "535s", 12, 5, qsSINGLE, giHyperb3, {{7, 2}}, eVariation::pure},
{"{5,3,3}","SW", "Poincaré homology sphere", "533s", 12, 3, qsSINGLE, giSphere3, {{7, 2}}, eVariation::pure},
{"{?,oo}", "none", "{3/4,∞} (infinite triangles and squares)", "ooxm", 3, OINF, qIDEAL | qINFMIXED, giHyperb2, {{6, 6}}, eVariation::pure},
{"{4,3,6}","none", "{4,3,6} hyperbolic honeycomb", "436", 6, 6, qIDEAL, giHyperb3, {{7, 2}}, eVariation::pure},
{"?", "none", "fake", "", 0, 0, qRAYONLY, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,4,5}","none", "{3,4,5} hyperbolic honeycomb", "345", 8, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,5,3}","none", "{3,5,3} hyperbolic honeycomb", "353", 20, 5, 0, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,5,4}","none", "{3,5,4} hyperbolic honeycomb", "354", 20, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
{"{3,5,5}","none", "{3,5,5} hyperbolic honeycomb", "355", 20, 5, qIDEAL | qULTRA, giHyperb3, {{7, 2}}, eVariation::pure},
{"{5,4}", "pBring", "projective Bring's Surface", "pBring", 5, 4, qsSMALLN, giHyperb2, {{6, 4}}, eVariation::bitruncated},
{"hat", "none", "aperiodic hat", "hat", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure},
{"triangle","none", "Sierpiński triangle", "S3", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
{"carpet", "none", "Sierpiński carpet", "S4", 4, 4, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
{"6-flake","none", "6-flake fractal", "S6", 6, 3, qFRACTAL, giEuclid2, {{10, 10}}, eVariation::pure},
{"{4,3,4}","none", "Menger sponge", "S8", 6, 4, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure},
{"rh{4,3,4}","none", "Sierpiński tetrahedron", "S4b", 12, 3, qFRACTAL, giEuclid3, {{10, 10}}, eVariation::pure},
{"spectre","none", "aperiodic spectre", "spectre", 14, 3, qAPERIODIC | qHAT, giEuclid2, {{7, 7}}, eVariation::pure},
};
// bits: 9, 10, 15, 16, (reserved for later) 17, 18
#if HDR
namespace mf {
static constexpr flagtype azimuthal = 1;
static constexpr flagtype cylindrical = 2; /* usually you want 'band' */
static constexpr flagtype equiarea = 4;
static constexpr flagtype equidistant = 8;
static constexpr flagtype conformal = 16;
static constexpr flagtype euc_boring = 32;
static constexpr flagtype space = 64;
static constexpr flagtype hyper_only = 128;
static constexpr flagtype hyper_or_torus = 256;
static constexpr flagtype pseudocylindrical = 512; /* includes cylindrical; usually you want 'band' or 'pseudoband' */
static constexpr flagtype equivolume = 1024;
static constexpr flagtype twopoint = 2048;
static constexpr flagtype uses_bandshift = 4096;
static constexpr flagtype broken = 8192; /* in spherical case, these are broken along the meridian 180 deg */
static constexpr flagtype technical = 16384; /* don't display in the list */
static constexpr flagtype product_special = (1<<15);
static constexpr flagtype axial = (1<<16);
static constexpr flagtype perspective = (1<<17);
static constexpr flagtype orientation = (1<<18);
static constexpr flagtype transition = (1<<19);
static constexpr flagtype werner = (1<<20);
static constexpr flagtype horocyclic = (1<<21);
static constexpr flagtype band = (cylindrical | pseudocylindrical | uses_bandshift | orientation);
static constexpr flagtype pseudoband = (pseudocylindrical | uses_bandshift | orientation);
}
struct modelinfo {
const char *name_hyperbolic;
const char *name_euclidean;
const char *name_spherical;
flagtype flags;
};
enum eModel : int {
mdDisk, mdHalfplane, mdBand, mdPolygonal, mdFormula,
// 5..8.
mdEquidistant, mdEquiarea, mdBall, mdHyperboloid,
// 9..13
mdHemisphere, mdBandEquidistant, mdBandEquiarea, mdSinusoidal, mdTwoPoint,
// 14..16
mdFisheye, mdJoukowsky, mdJoukowskyInverted,
// 17..19
mdRotatedHyperboles, mdSpiral, mdPerspective,
// 20..24
mdEquivolume, mdCentralInversion, mdSimulatedPerspective, mdTwoHybrid, mdGeodesic,
// 25..27
mdMollweide, mdCentralCyl, mdCollignon,
// 28..31
mdHorocyclic, mdQuadrant, mdAxial, mdAntiAxial,
// 32..38
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel,
// 39..48
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal, mdRelPerspective, mdRelOrthogonal,
// 49..50
mdHorocyclicEqa, mdConformalSquare, mdFisheye2, mdPolar,
// 51..
mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual
};
#endif
// remember to match the following mask when specifying codes for extra geometries: 0x78600
// (other bits are used for other information)
#define X3(x) x, x, x
/** list of available models (i.e., projections) */
EX vector<modelinfo> mdinf = {
{"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal},
{"half-plane", "inversion", "stereographic projection [VR]", mf::conformal | mf::orientation | mf::horocyclic},
{"band", "band", "Mercator", mf::band | mf::conformal | mf::transition},
{X3("polygonal"), mf::conformal | mf::orientation},
{X3("formula"), 0},
{X3("azimuthal equidistant"), mf::azimuthal | mf::equidistant | mf::euc_boring | mf::product_special},
{X3("azimuthal equi-area"), mf::azimuthal | mf::equiarea | mf::euc_boring},
{X3("ball model"), mf::conformal | mf::azimuthal | mf::space},
{"Minkowski hyperboloid", "plane", "sphere", mf::conformal | mf::space | mf::euc_boring},
{"hemisphere", "sphere", "Minkowski hyperboloid", mf::conformal | mf::space},
{X3("band equidistant"), mf::band | mf::equidistant | mf::euc_boring},
{X3("band equi-area"), mf::band | mf::equiarea | mf::euc_boring},
{X3("sinusoidal"), mf::pseudoband | mf::equiarea | mf::euc_boring},
{X3("two-point equidistant"), mf::equidistant | mf::euc_boring | mf::twopoint | mf::orientation},
{X3("fisheye"), 0},
{X3("Joukowsky transform"), mf::hyper_only | mf::conformal | mf::transition | mf::orientation},
{X3("Joukowsky+inversion"), mf::hyper_only | mf::conformal | mf::transition | mf::orientation},
{X3("rotated hyperboles"), mf::hyper_only | mf::orientation},
{X3("spiral/ring"), mf::hyper_or_torus | mf::uses_bandshift | mf::orientation},
{X3("native perspective"), mf::perspective | mf::product_special},
{X3("azimuthal equi-volume"), mf::azimuthal | mf::equivolume | mf::euc_boring},
{X3("central inversion"), mf::azimuthal | mf::conformal},
{X3("two-point azimuthal"), mf::euc_boring | mf::azimuthal | mf::twopoint | mf::orientation},
{X3("two-point hybrid"), mf::euc_boring | mf::azimuthal | mf::equidistant | mf::twopoint | mf::orientation},
{X3("geodesic"), mf::perspective | mf::product_special},
{X3("Mollweide"), mf::euc_boring | mf::pseudoband | mf::equiarea},
{X3("central cylindrical"), mf::euc_boring | mf::band},
{X3("Collignon"), mf::pseudoband | mf::equiarea},
{X3("horocyclic coordinates"), mf::euc_boring | mf::orientation | mf::horocyclic},
{X3("quadrant coordinates"), mf::euc_boring | mf::orientation},
{X3("axial coordinates"), mf::euc_boring | mf::transition | mf::orientation},
{X3("anti-axial coordinates"), mf::euc_boring | mf::orientation},
{X3("Werner projection"), mf::euc_boring | mf::broken | mf::werner | mf::orientation}, // keep distances from pole, and distances along parallels
{X3("Aitoff projection"), mf::euc_boring | mf::broken | mf::orientation}, // halve longitudes, do azequid, double x
{X3("Hammer projection"), mf::euc_boring | mf::broken | mf::orientation}, // halve longitudes, do azequia, double x
{X3("loximuthal projection"), mf::euc_boring | mf::broken | mf::orientation}, // map loxodromes azimuthally and equidistantly
{X3("Miller projection"), mf::euc_boring | mf::band}, // scale latitude 4/5 -> Mercator -> 5/4
{X3("Gall stereographic"), mf::euc_boring | mf::band}, // like central cylindrical but stereographic
{X3("Winkel tripel"), mf::euc_boring | mf::broken | mf::orientation}, // mean of equirec and Aitoff
{X3("Poor man's square"), mf::euc_boring | mf::orientation}, // https://archive.bridgesmathart.org/2018/bridges2018-59.html
{X3("Panini projection"), mf::euc_boring | mf::orientation},
{X3("Craig retroazimuthal"), mf::euc_boring | mf::broken | mf::pseudoband}, // retroazimuthal cylindrical
{X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken | mf::pseudoband}, // retroazimuthal conformal
{X3("Hammer retroazimuthal"), mf::euc_boring | mf::pseudoband}, // retroazimuthal equidistant
{X3("three-point equidistant"), mf::euc_boring | mf::equidistant | mf::orientation | mf::product_special | mf::twopoint},
{X3("Lie perspective"), mf::euc_boring | mf::perspective},
{X3("Lie orthogonal"), mf::euc_boring},
{X3("relativistic perspective"), mf::euc_boring | mf::perspective},
{X3("relativistic orthogonal"), mf::euc_boring},
{X3("horocyclic equal-area"), mf::euc_boring | mf::equiarea | mf::orientation | mf::horocyclic},
{X3("conformal square"), mf::orientation | mf::broken | mf::transition},
{X3("variant fisheye"), 0},
{X3("polar coordinates"), mf::orientation},
{X3("guard"), mf::technical},
{X3("pixel"), mf::technical},
{X3("hypflat"), mf::technical},
{X3("polynomial"), mf::technical | mf::conformal | mf::orientation},
{X3("manual"), mf::technical},
};
#undef X3
#if HDR
static inline bool orbProtection(eItem it) { return false; } // not implemented
// these markers use lands which never appear on barrier sides
const eLand NOWALLSEP = laNone;
const eLand NOWALLSEP_SWAP = laMountain;
const eLand NOWALLSEP_WALL = laHauntedWall;
const eLand NOWALLSEP_USED = laWhirlpool;
const eLand NOWALLSEP_WALL_CPOS = laBarrier;
const eLand NOWALLSEP_WALL_CNEG = laOceanWall;
const eLand NOWALLSEP_WALL_EPOS = laClearing;
const eLand NOWALLSEP_WALL_ENEG = laPrincessQuest;
#endif
}