1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-11-27 06:27:17 +00:00

Initialization with hyperrogue-66

This commit is contained in:
Alexandre Moine 2015-08-08 15:57:52 +02:00
parent 4b5634b554
commit 9b11f1b6c5
52 changed files with 24855 additions and 24 deletions

View File

@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/> Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
Preamble Preamble
The licenses for most software are designed to take away your The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public freedom to share and change it. By contrast, the GNU General Public
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to the GNU Library General Public License instead.) You can apply it to
your programs, too. your programs, too.
When we speak of free software, we are referring to freedom, not When we speak of free software, we are referring to freedom, not
@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains 0. This License applies to any program or other work which contains
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
License. (Exception: if the Program itself is interactive but License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on does not normally print such an announcement, your work based on
the Program is not required to print an announcement.) the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program, identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in and can be reasonably considered independent and separate works in
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not distribution of the source code, even though third parties are not
compelled to copy the source along with the object code. compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program 4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is otherwise to copy, modify, sublicense or distribute the Program is
@ -225,7 +225,7 @@ impose that choice.
This section is intended to make thoroughly clear what is believed to This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License. be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in 8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License original copyright holder who places the Program under this License
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally. of promoting the sharing and reuse of software generally.
NO WARRANTY NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it possible use to the public, the best way to achieve this is to make it
@ -290,8 +290,8 @@ to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found. the "copyright" line and a pointer to where the full notice is found.
{description} <one line to give the program's name and a brief idea of what it does.>
Copyright (C) {year} {fullname} Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -303,16 +303,17 @@ the "copyright" line and a pointer to where the full notice is found.
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License along You should have received a copy of the GNU General Public License
with this program; if not, write to the Free Software Foundation, Inc., along with this program; if not, write to the Free Software
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail. Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this If the program is interactive, make it output a short notice like this
when it starts in an interactive mode: when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details. under certain conditions; type `show c' for details.
@ -329,12 +330,11 @@ necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker. `Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989 <signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice Ty Coon, President of Vice
This General Public License does not permit incorporating your program into This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General library. If this is what you want to do, use the GNU Library General
Public License instead of this License. Public License instead of this License.

BIN
DejaVuSans-Bold.ttf Normal file

Binary file not shown.

32
LICENSE-ogg-vorbis.txt Normal file
View File

@ -0,0 +1,32 @@
The source code to this library used with SDL_mixer can be found here:
http://www.libsdl.org/projects/SDL_mixer/libs/
---
Copyright (c) 2002-2008 Xiph.org Foundation
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
- Neither the name of the Xiph.org Foundation nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

13
LICENSE-sdl.txt Normal file
View File

@ -0,0 +1,13 @@
Please distribute this file with the SDL runtime environment:
The Simple DirectMedia Layer (SDL for short) is a cross-platfrom library
designed to make it easy to write multi-media software, such as games and
emulators.
The Simple DirectMedia Layer library source code is available from:
http://www.libsdl.org/
This library is distributed under the terms of the GNU LGPL license:
http://www.gnu.org/copyleft/lesser.html

10
Makefile Normal file
View File

@ -0,0 +1,10 @@
CXXFLAGS ?=
hyper: hyper.cpp graph.cpp hyperpoint.cpp geometry.cpp cell.cpp heptagon.cpp game.cpp classes.cpp polygons.cpp language.cpp language-data.cpp achievement.cpp
g++ hyper.cpp -o hyper -lSDL -lSDL_ttf -lSDL_mixer -DFHS -Wall -lSDL_gfx ${CXXFLAGS} ${CPPFLAGS} ${LDFLAGS} -lGL -O3
langen: langen.cpp language-cz.cpp language-pl.cpp language-tr.cpp language-ru.cpp
g++ langen.cpp -o langen
language-data.cpp: langen
./langen > language-data.cpp

7
Makefile.mac Normal file
View File

@ -0,0 +1,7 @@
# note: this Makefile for Mac is based on this post. I have no resources to test it myself.
# http://groups.google.com/group/rec.games.roguelike.development/browse_thread/thread/9c02e09c0195dc16/3cbde3dc4a0b7e4e
#
# You will also probably need to configure it yourself a bit to make it work.
hyper: hyper.cpp graph.cpp hyperpoint.cpp geometry.cpp cell.cpp heptagon.cpp game.cpp polygons.cpp classes.cpp
g++ -m32 -I/sw/include hyper.cpp -L/sw/lib -lSDL -lSDLMain -lSDL_ttf -lSDL_gfx -framework AppKit -DMAC -O3

11
Makefile.mgw Normal file
View File

@ -0,0 +1,11 @@
hyper.exe: hyper.cpp graph.cpp hyperpoint.cpp geometry.cpp cell.cpp heptagon.cpp game.cpp polygons.cpp classes.cpp hyper.res language-data.cpp
g++ -mwindows hyper.cpp hyper.res -o hyper.exe -lSDL -lSDL_mixer -lopengl32 SDL_ttf.dll SDL_gfx.dll -O3
hyper.res: hyper.rc hr-icon.ico
windres hyper.rc -O coff -o hyper.res
langen.exe: langen.cpp language-cz.cpp language-pl.cpp language-tr.cpp language-ru.cpp
g++ langen.cpp -o langen.exe
language-data.cpp: langen.exe
./langen.exe > language-data.cpp

BIN
SDL.dll Normal file

Binary file not shown.

BIN
SDL_gfx.dll Normal file

Binary file not shown.

BIN
SDL_mixer.dll Normal file

Binary file not shown.

BIN
SDL_ttf.dll Normal file

Binary file not shown.

323
achievement.cpp Normal file
View File

@ -0,0 +1,323 @@
#define NUMLEADER 26
#define SCORE_UNKNOWN (-1)
#define NO_SCORE_YET (-2)
int currentscore[NUMLEADER];
const char* leadernames[NUMLEADER] = {
"Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs",
"Shards", "Totems", "Daisies", "Statues", "Feathers", "Sapphires",
"Hyperstones", "Time to Win", "Turns to Win",
"Time to 10 Hyperstones-62", "Turns to 10 Hyperstones-62", "Orbs of Yendor",
"Fern Flowers",
"Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires",
"Holy Grails"
};
bool haveLeaderboard(int id);
void upload_score(int id, int v);
string achievementMessage[3];
int achievementTimer;
// vector<string> achievementsReceived;
void achievement_log(const char* s, bool euclideanAchievement) {
if(cheater) return;
if(euclid != euclideanAchievement) return;
for(int i=0; i<size(achievementsReceived); i++)
if(achievementsReceived[i] == s) return;
achievementsReceived.push_back(s);
#ifndef ANDROID
FILE *f = fopen(scorefile, "at");
if(!f) return;
int t = time(NULL) - timerstart;
time_t timer = time(NULL);
char buf[128]; strftime(buf, 128, "%c", localtime(&timer));
fprintf(f, "ACHIEVEMENT %s turns: %d time: %d at: %d c: %d date: %s\n",
s, turncount, t, int(timerstart), achievement_certify(s, turncount, t, timerstart), buf);
fclose(f);
#endif
}
#ifdef STEAM
#include "hypersteam.cpp"
#else
#ifndef ANDROID
void achievement_init() {}
void achievement_close() {}
void achievement_gain(const char* s, bool euclideanAchievement) {
achievement_log(s, euclideanAchievement);
}
#endif
#endif
void achievement_collection(eItem it, int prevgold, int newgold) {
if(cheater) return;
int q = items[it];
if(q == 1) {
if(it == itDiamond) achievement_gain("DIAMOND1");
if(it == itRuby) achievement_gain("RUBY1");
if(it == itHyperstone) achievement_gain("HYPER1");
if(it == itGold) achievement_gain("GOLD1");
if(it == itStatue) achievement_gain("STATUE1");
if(it == itShard) achievement_gain("MIRROR1");
if(it == itBone) achievement_gain("TOTEM1");
if(it == itSpice) achievement_gain("SPICE1");
if(it == itElixir) achievement_gain("ELIXIR1");
if(it == itHell) achievement_gain("DAISY1");
if(it == itFeather) achievement_gain("FEATHER1");
if(it == itSapphire) achievement_gain("SAPPHIRE1");
if(it == itFernFlower) achievement_gain("FERN1");
if(it == itRoyalJelly) achievement_gain("JELLY1");
if(it == itWine) achievement_gain("WINE1");
if(it == itPower) achievement_gain("POWER1");
if(it == itEmerald) achievement_gain("EMERALD1");
if(it == itSilver) achievement_gain("SILVER1");
if(it == itGrimoire) achievement_gain("GRIMOIRE1");
}
// 32
if(it == itHolyGrail) {
if(q == 1) achievement_gain("GRAIL2");
if(q == 3) achievement_gain("GRAIL3");
if(q == 8) achievement_gain("GRAIL4");
}
if(q == 10) {
if(it == itDiamond) achievement_gain("DIAMOND2");
if(it == itRuby) achievement_gain("RUBY2");
if(it == itHyperstone) achievement_gain("HYPER2");
if(it == itGold) achievement_gain("GOLD2");
if(it == itStatue) achievement_gain("STATUE2");
if(it == itShard) achievement_gain("MIRROR2");
if(it == itBone) achievement_gain("TOTEM2");
if(it == itSpice) achievement_gain("SPICE2");
if(it == itElixir) achievement_gain("ELIXIR2");
if(it == itHell) achievement_gain("DAISY2");
if(it == itFeather) achievement_gain("FEATHER2");
if(it == itSapphire) achievement_gain("SAPPHIRE2");
if(it == itFernFlower) achievement_gain("FERN2");
if(it == itRoyalJelly) achievement_gain("JELLY2");
if(it == itWine) achievement_gain("WINE2");
if(it == itPower) achievement_gain("POWER2");
if(it == itEmerald) achievement_gain("EMERALD2");
if(it == itSilver) achievement_gain("SILVER2");
if(it == itGrimoire) achievement_gain("GRIMOIRE2");
}
if(q == 25) {
if(it == itDiamond) achievement_gain("DIAMOND3");
if(it == itRuby) achievement_gain("RUBY3");
if(it == itHyperstone) achievement_gain("HYPER3");
if(it == itGold) achievement_gain("GOLD3");
if(it == itStatue) achievement_gain("STATUE3");
if(it == itShard) achievement_gain("MIRROR3");
if(it == itBone) achievement_gain("TOTEM3");
if(it == itSpice) achievement_gain("SPICE3");
if(it == itElixir) achievement_gain("ELIXIR3");
if(it == itHell) achievement_gain("DAISY3");
if(it == itFeather) achievement_gain("FEATHER3");
if(it == itSapphire) achievement_gain("SAPPHIRE3");
if(it == itFernFlower) achievement_gain("FERN3");
if(it == itRoyalJelly) achievement_gain("JELLY3");
if(it == itWine) achievement_gain("WINE3");
if(it == itPower) achievement_gain("POWER3");
if(it == itEmerald) achievement_gain("EMERALD3");
if(it == itSilver) achievement_gain("SILVER3");
if(it == itGrimoire) achievement_gain("GRIMOIRE3");
}
if(q == 50) {
if(it == itDiamond) achievement_gain("DIAMOND4");
if(it == itRuby) achievement_gain("RUBY4");
if(it == itHyperstone) achievement_gain("HYPER4");
if(it == itGold) achievement_gain("GOLD4");
if(it == itStatue) achievement_gain("STATUE4");
if(it == itShard) achievement_gain("MIRROR4");
if(it == itBone) achievement_gain("TOTEM4");
if(it == itSpice) achievement_gain("SPICE4");
if(it == itElixir) achievement_gain("ELIXIR4");
if(it == itHell) achievement_gain("DAISY4");
if(it == itFeather) achievement_gain("FEATHER4");
if(it == itSapphire) achievement_gain("SAPPHIRE4");
if(it == itFernFlower) achievement_gain("FERN4");
if(it == itRoyalJelly) achievement_gain("JELLY4");
if(it == itWine) achievement_gain("WINE4");
if(it == itPower) achievement_gain("POWER4");
if(it == itEmerald) achievement_gain("EMERALD4");
if(it == itSilver) achievement_gain("SILVER4");
if(it == itGrimoire) achievement_gain("GRIMOIRE4");
}
if(it == itOrbYendor)
achievement_gain("YENDOR2");
}
void achievement_count(const string& s, int current, int prev) {
if(cheater) return;
if(s == "GOLEM" && current >= 5)
achievement_gain("GOLEM2");
if(s == "GOLEM" && current >= 10)
achievement_gain("GOLEM3");
if(s == "STAB" && current >= 1)
achievement_gain("STABBER1");
if(s == "STAB" && current >= 2)
achievement_gain("STABBER2");
if(s == "STAB" && current >= 4)
achievement_gain("STABBER3");
if(s == "MIRRORKILL" && current-prev >= 1)
achievement_gain("MIRRORKILL1");
if(s == "MIRRORKILL" && current-prev >= 2)
achievement_gain("MIRRORKILL2");
if(s == "MIRRORKILL" && current-prev >= 3)
achievement_gain("MIRRORKILL3");
if(s == "FLASH" && current-prev >= 1)
achievement_gain("FLASH1");
if(s == "FLASH" && current-prev >= 5)
achievement_gain("FLASH2");
if(s == "FLASH" && current-prev >= 10)
achievement_gain("FLASH3");
if(s == "LIGHTNING" && current-prev >= 1)
achievement_gain("LIGHTNING1");
if(s == "LIGHTNING" && current-prev >= 5)
achievement_gain("LIGHTNING2");
if(s == "LIGHTNING" && current-prev >= 10)
achievement_gain("LIGHTNING3");
if(s == "MIRAGE" && current >= 35)
achievement_gain("MIRAGE", true);
if(s == "ORB" && current >= 10)
achievement_gain("ORB3");
if(s == "BUG" && current >= 1000)
achievement_gain("BUG3");
}
int specific_improved = 0;
int specific_what = 0;
void improve_score(int i, eItem what) {
#ifdef HAVE_ACHIEVEMENTS
if(items[what] && haveLeaderboard(i)) {
if(items[what] > currentscore[i] && currentscore[i] != SCORE_UNKNOWN) {
specific_improved++; specific_what = what;
currentscore[i] = items[what];
}
upload_score(i, items[what]);
}
#endif
}
void achievement_final(bool really_final) {
#ifdef HAVE_ACHIEVEMENTS
if(cheater) return;
if(euclid) return;
int total_improved = 0;
specific_improved = 0;
specific_what = 0;
for(int i=1; i<=12; i++) improve_score(i, eItem(i));
improve_score(17, itOrbYendor);
improve_score(18, itFernFlower);
improve_score(19, itRoyalJelly);
improve_score(20, itPower);
improve_score(21, itSilver);
improve_score(22, itWine);
improve_score(23, itEmerald);
improve_score(24, itGrimoire);
improve_score(25, itHolyGrail);
int tg = gold();
if(tg && haveLeaderboard(0)) {
if(tg > currentscore[0] && currentscore[0] != SCORE_UNKNOWN) {
if(currentscore[0] < 0) total_improved += 2;
total_improved++; currentscore[0] = tg;
}
upload_score(0, tg);
}
if(total_improved >= 2) {
addMessage(XLAT("Your total treasure has been recorded in the "LEADERFULL"."));
addMessage(XLAT("Congratulations!"));
}
else if(total_improved && specific_improved >= 2)
addMessage(XLAT("You have improved your total high score and %1 specific high scores!", its(specific_improved)));
else if(total_improved && specific_improved)
addMessage(XLAT("You have improved your total and '%1' high score!", iinf[specific_what].name));
else if(total_improved)
addMessage(XLAT("You have improved your total high score on "LEADER". Congratulations!"));
else if(specific_improved >= 2)
addMessage(XLAT("You have improved %1 of your specific high scores!", its(specific_improved)));
else if(specific_improved)
addMessage(XLAT("You have improved your '%1' high score on "LEADER"!", iinf[specific_what].name));
#endif
}
void achievement_victory(bool hyper) {
#ifdef HAVE_ACHIEVEMENTS
if(cheater) return;
if(euclid) return;
int t = savetime + time(NULL) - timerstart;
int ih1 = hyper ? 15 : 13;
int ih2 = hyper ? 16 : 14;
int improved = 0;
if(currentscore[ih1] == NO_SCORE_YET || currentscore[ih2] == NO_SCORE_YET)
improved += 4;
if(currentscore[ih1] < 0 || currentscore[ih1] > t) {
improved++; currentscore[ih1] = t;
}
if(currentscore[ih2] < 0 || currentscore[ih2] > turncount) {
improved+=2; currentscore[ih2] = turncount;
}
if(hyper)
addMessage(XLAT("You have collected 10 treasures of each type."));
if(improved) {
if(improved >= 4) {
if(!hyper) addMessage(XLAT("This is your first victory!"));
addMessage(XLAT("This has been recorded in the " LEADERFULL "."));
addMessage(XLAT("The faster you get here, the better you are!"));
}
else if(improved >= 3)
addMessage(XLAT("You have improved both your real time and turn count. Congratulations!"));
else if(improved == 1)
addMessage(XLAT("You have used less real time than ever before. Congratulations!"));
else if(improved == 2)
addMessage(XLAT("You have used less turns than ever before. Congratulations!"));
}
upload_score(ih1, t);
upload_score(ih2, turncount);
#endif
}
void achievement_pump();
void achievement_display() {
#ifdef HAVE_ACHIEVEMENTS
achievement_pump();
if(achievementTimer) {
int col = (ticks - achievementTimer);
if(col > 5000) { achievementTimer = 0; return; }
if(col > 2500) col = 5000 - col;
col /= 10; col *= 0x10101;
displayfr(vid.xres/2, vid.yres/4, 2, vid.fsize * 2, achievementMessage[0], col & 0xFFFF00, 8);
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*2, 2, vid.fsize * 2, achievementMessage[1], col, 8);
displayfr(vid.xres/2, vid.yres/4 + vid.fsize*4, 2, vid.fsize, achievementMessage[2], col, 8);
}
#endif
}

30
achievement.h Normal file
View File

@ -0,0 +1,30 @@
// initialize the achievement system.
void achievement_init();
// close the achievement system.
void achievement_close();
// gain the achievement with the given name.
// Only awarded if euclid equals euclideanAchievement.
void achievement_gain(const char*, bool euclideanAchievement = false);
// gain the achievement for collecting a number of 'it'.
void achievement_collection(eItem it, int prevgold, int newgold);
// this is used for 'counting' achievements, such as kill 10
// monsters at the same time.
void achievement_count(const string& s, int current, int prev);
// gain the victory achievements. Set 'hyper' to true for
// the Hyperstone victory, and false for the Orb of Yendor victory.
void achievement_victory(bool hyper);
// gain the final achievements. Called with really=false whenever the user
// looks at their score, and really=true when the game really ends.
void achievement_final(bool really);
// display the last achievement gained.
void achievement_display();
// achievements received this game
vector<string> achievementsReceived;

375
cell.cpp Normal file
View File

@ -0,0 +1,375 @@
// Hyperbolic Rogue
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
// cells the game is played on
int fix6(int a) { return (a+96)% 6; }
struct cell : gcell {
char type; // 6 for hexagons, 7 for heptagons
unsigned char spn[7];
heptagon *master;
cell *mov[7]; // meaning very similar to heptagon::move
};
int cellcount = 0;
void initcell(cell *c); // from game.cpp
cell *newCell(int type, heptagon *master) {
cell *c = new cell;
cellcount++;
c->type = type;
c->master = master;
for(int i=0; i<7; i++) c->mov[i] = NULL;
initcell(c);
return c;
}
void merge(cell *c, int d, cell *c2, int d2) {
c->mov[d] = c2;
c->spn[d] = d2;
c2->mov[d2] = c;
c2->spn[d2] = d;
}
typedef unsigned short eucoord;
cell*& euclideanAtCreate(eucoord x, eucoord y);
union heptacoder {
heptagon *h;
struct { eucoord x; eucoord y; } c;
};
void decodeMaster(heptagon *h, eucoord& x, eucoord& y) {
heptacoder u;
u.h = h; x = u.c.x; y = u.c.y;
}
heptagon* encodeMaster(eucoord x, eucoord y) {
heptacoder u;
u.c.x = x; u.c.y = y;
return u.h;
}
// very similar to createMove in heptagon.cpp
cell *createMov(cell *c, int d) {
if(euclid && !c->mov[d]) {
eucoord x, y;
decodeMaster(c->master, x, y);
for(int dx=-1; dx<=1; dx++)
for(int dy=-1; dy<=1; dy++)
euclideanAtCreate(x+dx, y+dy);
if(!c->mov[d]) { printf("fail!\n"); }
}
if(c->mov[d]) return c->mov[d];
else if(c->type == 7) {
cell *n = newCell(6, c->master);
c->mov[d] = n; n->mov[0] = c;
c->spn[d] = 0; n->spn[0] = d;
heptspin hs; hs.h = c->master; hs.spin = d;
heptspin hs2 = hsstep(hsspin(hs, 3), 3);
// merge(hs2.h->c7, hs2.spin, n, 2);
hs2.h->c7->mov[hs2.spin] = n; n->mov[2] = hs2.h->c7;
hs2.h->c7->spn[hs2.spin] = 2; n->spn[2] = hs2.spin;
hs2 = hsstep(hsspin(hs, 4), 4);
// merge(hs2.h->c7, hs2.spin, n, 4);
hs2.h->c7->mov[hs2.spin] = n; n->mov[4] = hs2.h->c7;
hs2.h->c7->spn[hs2.spin] = 4; n->spn[4] = hs2.spin;
}
else if(d == 5) {
int di = fixrot(c->spn[0]+1);
cell *c2 = createMov(c->mov[0], di);
merge(c, 5, c2, fix6(c->mov[0]->spn[di] + 1));
// c->mov[5] = c->mov[0]->mov[fixrot(c->spn[0]+1)];
// c->spn[5] = fix6(c->mov[0]->spn[fixrot(c->spn[0]+1)] + 1);
}
else if(d == 1) {
int di = fixrot(c->spn[0]-1);
cell *c2 = createMov(c->mov[0], di);
merge(c, 1, c2, fix6(c->mov[0]->spn[di] - 1));
// c->mov[1] = c->mov[0]->mov[fixrot(c->spn[0]-1)];
// c->spn[1] = fix6(c->mov[0]->spn[fixrot(c->spn[0]-1)] - 1);
}
else if(d == 3) {
int di = fixrot(c->spn[2]-1);
cell *c2 = createMov(c->mov[2], di);
merge(c, 3, c2, fix6(c->mov[2]->spn[di] - 1));
// c->mov[3] = c->mov[2]->mov[fixrot(c->spn[2]-1)];
// c->spn[3] = fix6(c->mov[2]->spn[fixrot(c->spn[2]-1)] - 1);
}
return c->mov[d];
}
// similar to heptspin from heptagon.cpp
struct cellwalker {
cell *c;
int spin;
cellwalker(cell *c, int spin) : c(c), spin(spin) {}
cellwalker() {}
};
void cwspin(cellwalker& cw, int d) {
cw.spin = (cw.spin+d + 42) % cw.c->type;
}
bool cwstepcreates(cellwalker& cw) {
return cw.c->mov[cw.spin] == NULL;
}
void cwstep(cellwalker& cw) {
createMov(cw.c, cw.spin);
int nspin = cw.c->spn[cw.spin];
cw.c = cw.c->mov[cw.spin];
cw.spin = nspin;
}
void eumerge(cell* c1, cell *c2, int s1, int s2) {
if(!c2) return;
c1->mov[s1] = c2; c1->spn[s1] = s2;
c2->mov[s2] = c1; c2->spn[s2] = s1;
}
struct euclideanSlab {
cell* a[256][256];
euclideanSlab() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
a[y][x] = NULL;
}
~euclideanSlab() {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(a[y][x]) delete a[y][x];
}
};
euclideanSlab* euclidean[256][256];
// map<pair<eucoord, eucoord>, cell*> euclidean;
cell*& euclideanAt(eucoord x, eucoord y) {
euclideanSlab*& slab(euclidean[y>>8][x>>8]);
if(!slab) slab = new euclideanSlab;
return slab->a[y&255][x&255];
}
cell*& euclideanAtCreate(eucoord x, eucoord y) {
cell*& c ( euclideanAt(x,y) );
if(!c) {
c = newCell(6, &origin);
c->master = encodeMaster(x,y);
euclideanAt(x,y) = c;
eumerge(c, euclideanAt(x+1,y), 0, 3);
eumerge(c, euclideanAt(x,y+1), 1, 4);
eumerge(c, euclideanAt(x-1,y+1), 2, 5);
eumerge(c, euclideanAt(x-1,y), 3, 0);
eumerge(c, euclideanAt(x,y-1), 4, 1);
eumerge(c, euclideanAt(x+1,y-1), 5, 2);
}
return c;
}
// initializer (also inits origin from heptagon.cpp)
void initcells() {
origin.s = hsOrigin;
origin.fjordval = 98;
for(int i=0; i<7; i++) origin.move[i] = NULL;
origin.alt = NULL;
origin.distance = 0;
if(euclid)
origin.c7 = euclideanAtCreate(0,0);
else
origin.c7 = newCell(7, &origin);
// origin.fjordval =
}
#define DEBMEM(x) // { x fflush(stdout); }
void clearcell(cell *c) {
if(!c) return;
DEBMEM ( printf("c%d %p\n", c->type, c); )
for(int t=0; t<c->type; t++) if(c->mov[t]) {
DEBMEM ( printf("mov %p [%p] S%d\n", c->mov[t], c->mov[t]->mov[c->spn[t]], c->spn[t]); )
if(c->mov[t]->mov[c->spn[t]] != NULL &&
c->mov[t]->mov[c->spn[t]] != c) {
printf("cell error\n");
exit(1);
}
c->mov[t]->mov[c->spn[t]] = NULL;
}
DEBMEM ( printf("DEL %p\n", c); )
delete c;
}
heptagon deletion_marker;
#include <queue>
void clearfrom(heptagon *at) {
queue<heptagon*> q;
q.push(at);
at->alt = &deletion_marker;
//int maxq = 0;
while(!q.empty()) {
at = q.front();
// if(q.size() > maxq) maxq = q.size();
q.pop();
DEBMEM ( printf("from %p\n", at); )
for(int i=0; i<7; i++) if(at->move[i]) {
if(at->move[i]->alt != &deletion_marker)
q.push(at->move[i]);
at->move[i]->alt = &deletion_marker;
DEBMEM ( printf("!mov %p [%p]\n", at->move[i], at->move[i]->move[at->spin[i]]); )
if(at->move[i]->move[at->spin[i]] != NULL &&
at->move[i]->move[at->spin[i]] != at) {
printf("hept error\n");
exit(1);
}
at->move[i]->move[at->spin[i]] = NULL;
at->move[i] = NULL;
}
DEBMEM ( printf("at %p\n", at); )
if(at->c7) {
for(int i=0; i<7; i++)
clearcell(at->c7->mov[i]);
clearcell(at->c7);
}
DEBMEM ( printf("!DEL %p\n", at); )
if(at != &origin) delete at;
}
//printf("maxq = %d\n", maxq);
}
void verifycell(cell *c) {
int t = c->type;
for(int i=0; i<t; i++) {
cell *c2 = c->mov[i];
if(c2) {
if(t == 7) verifycell(c2);
if(c2->mov[c->spn[i]] && c2->mov[c->spn[i]] != c)
printf("cell error %p %p\n", c, c2);
}
}
}
void verifycells(heptagon *at) {
for(int i=0; i<7; i++) if(at->move[i] && at->spin[i] == 0 && at->move[i] != &origin)
verifycells(at->move[i]);
for(int i=0; i<7; i++) if(at->move[i] && at->move[i]->move[at->spin[i]] && at->move[i]->move[at->spin[i]] != at) {
printf("hexmix error %p %p %p\n", at, at->move[i], at->move[i]->move[at->spin[i]]);
}
verifycell(at->c7);
}
bool ishept(cell *c) {
// EUCLIDEAN
if(euclid) {
eucoord x, y;
decodeMaster(c->master, x, y);
return (short(y+2*x))%3 == 0;
}
else return c->type == 7;
}
void clearMemory() {
extern void clearGameMemory();
clearGameMemory();
// EUCLIDEAN
if(euclid) {
for(int y=0; y<256; y++) for(int x=0; x<256; x++)
if(euclidean[y][x]) {
delete euclidean[y][x];
euclidean[y][x] = NULL;
}
}
else {
DEBMEM ( verifycells(&origin); )
clearfrom(&origin);
for(int i=0; i<size(allAlts); i++) clearfrom(allAlts[i]);
allAlts.clear();
}
DEBMEM ( printf("ok\n"); )
}
int fjordval(cell *c) {
if(euclid) return 0;
if(c->type == 7)
return c->master->fjordval >> 3;
else {
return fjord_hexagon(
fjordval(createMov(c,0)),
fjordval(createMov(c,2)),
fjordval(createMov(c,4))
);
}
}
int eudist(short sx, short sy) {
int z0 = abs(sx);
int z1 = abs(sy);
int z2 = abs(sx+sy);
return max(max(z0,z1), z2);
}
int celldist(cell *c) {
if(euclid) {
eucoord x, y;
decodeMaster(c->master, x, y);
return eudist(x, y);
}
if(c->type == 7) return c->master->distance;
int dx[3];
for(int u=0; u<3; u++)
dx[u] = createMov(c, u+u)->master->distance;
int mi = min(min(dx[0], dx[1]), dx[2]);
if(dx[0] > mi+2 || dx[1] > mi+2 || dx[2] > mi+2)
return -1; // { printf("cycle error!\n"); exit(1); }
if(dx[0] == mi+2 || dx[1] == mi+2 || dx[2] == mi+2)
return mi+1;
return mi;
}
#define ALTDIST_BOUNDARY 99999
#define ALTDIST_UNKNOWN 99998
// defined in 'game'
int euclidAlt(short x, short y);
int celldistAlt(cell *c) {
if(euclid) {
eucoord x, y;
decodeMaster(c->master, x, y);
return euclidAlt(x, y);
}
if(c->type == 7) return c->master->alt->distance;
int dx[3];
for(int u=0; u<3; u++) if(createMov(c, u+u)->master->alt == NULL)
return ALTDIST_UNKNOWN;
for(int u=0; u<3; u++)
dx[u] = createMov(c, u+u)->master->alt->distance;
int mi = min(min(dx[0], dx[1]), dx[2]);
if(dx[0] > mi+2 || dx[1] > mi+2 || dx[2] > mi+2)
return ALTDIST_BOUNDARY; // { printf("cycle error!\n"); exit(1); }
if(dx[0] == mi+2 || dx[1] == mi+2 || dx[2] == mi+2)
return mi+1;
return mi;
}
#define GRAIL_FOUND 0x4000
#define GRAIL_RADIUS_MASK 0x3FFF

696
classes.cpp Normal file
View File

@ -0,0 +1,696 @@
// --- help ---
#define MC
#define M
const char *wormdes =
MC"These huge monsters normally live below the sand, but your movements have "
MC"disturbed them. They are too big to be slain with your "
MC"weapons, but you can defeat them by making them unable to move. "
M "This also produces some Spice. They move two times slower than you.";
const char *cocytushelp =
M "This frozen lake is a hellish version of the Icy Land. Now, your body heat melts the floor, not the walls.";
const char *tentdes =
MC"The tentacles of Cthulhu are like sandworms, but longer. "
M "They also withdraw one cell at a time, instead of exploding instantly.";
const char *gameboardhelp =
MC"Ever wondered how some boardgame would look on the hyperbolic plane? "
MC"I wondered about Go, so I have created this feature. Now you can try yourself!\n"
MC"Enter = pick up an item (and score), space = clear an item\n"
M "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 =
MC"A huge plant growing in the Jungle. Each Ivy has many branches, "
MC"and one branch grows per each of your moves. Branches grow in a clockwise "
M "order. The root itself is vulnerable.";
const char *slimehelp =
MC"The Alchemists produce magical potions from pools of blue and red slime. You "
MC"can go through these pools, but you cannot move from a blue pool to a red "
MC"pool, or vice versa. Pools containing items count as colorless, and "
MC"they change color to the PC's previous color when the item is picked up. "
MC"Slime beasts also have to keep to their own color, "
MC"but when they are killed, they explode, destroying items and changing "
M "the color of the slime and slime beasts around them.";
const char *gdemonhelp =
MC "These creatures are slow, but very powerful... more powerful than you. "
MC "You need some more experience in demon fighting before you will be able to defeat them. "
MC "Even then, you will be able to slay this one, but more powerful demons will come...\n\n"
MC "Each 10 lesser demons you kill, you become powerful enough to kill all the greater "
M "demons on the screen, effectively turning them into lesser demons.";
const char *ldemonhelp =
M "These creatures are slow, but they often appear in large numbers.";
const char *trollhelp =
MC"A big monster from the Living Caves. A dead Troll will be reunited "
M "with the rocks, causing some walls to grow around its body.";
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 worth 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 =
M "Huge, impassable walls which separate various lands.";
const char *cavehelp =
MC"This cave contains walls which are somehow living. After each turn, each cell "
MC"counts the number of living wall and living floor cells around it, and if it is "
MC"currently of a different type than the majority of cells around it, it switches. "
MC"Items count as three floor cells, and dead Trolls count as five wall cells. "
M "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 =
MC"This forest is quite dry. Beware the bushfires!\n"
MC"Trees catch fire on the next turn. The temperature of the grass cells "
MC"rises once per turn for each fire nearby, and becomes fire itself "
MC"when its temperature has risen 10 times.\n"
M "You can also cut down the trees. Big trees take two turns to cut 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?";
// --- monsters ---
const int motypes = 67;
struct monstertype {
char glyph;
int color;
const char *name;
const char *help;
};
#define BUGCOLORS 3
monstertype minf[motypes] = {
{ 0, 0, "none" , NULL},
{ 'Y', 0x4040FF, "Yeti" ,
M "A big and quite intelligent monster living in the Icy Land."
},
{ 'W', 0xD08040, "Icewolf" ,
MC "A nasty predator from the Icy Land. Contrary to other monsters, "
M "it tracks its prey by their heat."
},
{ 'W', 0xD08040, "Icewolf" , ""},
{ 'R', 0xFF8000, "Ranger" ,
MC "Rangers take care of the magic mirrors in the Land of Mirrors. "
MC "They know that rogues like to break these mirrors... so "
M "they will attack you!"
},
{ 'T', 0xD0D0D0, "Rock Troll", trollhelp},
{ 'G', 0x20D020, "Goblin",
MC "A nasty creature native to the Living Caves. They don't like you "
M "for some reason."
},
{ 'S', 0xE0E040, "Sand Worm", wormdes },
{ 's', 0x808000, "Sand Worm Tail", wormdes },
{ 'S', 0x808000, "Sand Worm W", wormdes },
{ 'H', 0x80FF00, "Hedgehog Warrior",
MC "These warriors of the Forest wield exotic weapons called hedgehog blades. "
MC "These blades protect them from a frontal attack, but they still can be 'stabbed' "
M "easily by moving from one place next to them to another."
},
{ 'M', 0x806050, "Desert Man",
M "A tribe of men native to the Desert. They have even tamed the huge Sandworms, who won't attack them."},
{ 'C', 0x00FFFF, "Ivy Root", ivydes},
{ 'C', 0xFFFF00, "Active Ivy", ivydes},
{ 'C', 0x40FF00, "Ivy Branch", ivydes},
{ 'C', 0x006030, "Dormant Ivy", ivydes},
{ 'C', 0x800000, "Ivy N", ivydes},
{ 'C', 0x800000, "Ivy D", ivydes},
{ 'M', 0x804000, "Giant Ape",
M "This giant ape thinks that you are an enemy."},
{ 'B', 0x909000, "Slime Beast", slimehelp},
{ '@', 0x8080FF, "Mirror Image",
M "A magical being which copies your movements."
},
{ '@', 0xFF8080, "Mirage",
MC "A magical being which copies your movements. "
M "You feel that it would be much more useful in an Euclidean space."
},
{ '@', 0x509050, "Golem",
M "You can summon these friendly constructs with a magical process."
},
{ '@', 0x509050, "Golem",
M "You can summon these friendly constructs with a magical process."
},
{ 'E', 0xD09050, "Eagle",
M "A majestic bird, who is able to fly very fast."
},
{ 'S', 0xFF8080, "Seep",
M "A monster who is able to live inside the living cave wall."
},
{ 'Z', 0x804000, "Zombie",
M "A typical Graveyard monster."
},
{ 'G', 0xFFFFFF, "Ghost",
M "A typical monster from the Graveyard, who moves through walls.\n\n"
"There are also wandering Ghosts. They will appear "
"if you do not explore any new places for a long time (about 100 turns). "
"They can appear anywhere in the game."
},
{ 'N', 0x404040, "Necromancer",
M "Necromancers can raise ghosts and zombies from fresh graves."
},
{ 'S', 0x404040, "Shadow",
M "A creepy monster who follows you everywhere in the Graveyard."
},
{ 'T', 0x40E040, "Tentacle", tentdes },
{ 't', 0x008000, "Tentacle Tail", tentdes },
{ 'T', 0x008000, "Tentacle W", tentdes },
{ 'z', 0xC00000, "Tentacle (withdrawing)", tentdes },
{ 'P', 0xFF8000, "Cultist",
M "People worshipping Cthulhu. They are very dangerous."
},
{ 'P', 0xFFFF00, "Fire Cultist",
MC "People worshipping Cthulhu. This one is especially dangerous, "
M "as he is armed with a weapon which launches fire from afar."
},
{ 'D', 0xFF0000, "Greater Demon", gdemonhelp},
{ 'D', 0x800000, "Greater Demon", gdemonhelp},
{ 'd', 0xFF2020, "Lesser Demon", ldemonhelp},
{ 'd', 0x802020, "Lesser Demon", ldemonhelp},
{ 'S', 0x2070C0, "Ice Shark",
M "This dangerous predator has killed many people, and has been sent to Cocytus."
},
{ 'W', 0xFFFFFF, "Running Dog",
MC "This white dog is able to run all the time. It is the only creature "
M "able to survive and breed in the Land of Eternal Motion."
},
{ 'S', 0xC00040, "Demon Shark",
MC "Demons of Hell do not drown when they fall into the lake in Cocytus. "
M "They turn into demonic sharks, enveloped in a cloud of steam."
},
{ 'S', 0xC00040, "Fire Fairy",
MC "These fairies would rather burn the forest, than let you get some Fern Flowers. "
MC "The forest is infinite, after all...\n\n"
M "Fire Fairies transform into fires when they die."
},
{ 'C', 0x4000C0, "Crystal Sage",
MC "This being radiates an aura of wisdom. "
MC "It is made of a beautiful crystal, you would love to take it home. "
MC "But how is it going to defend itself? Better not to think of it, "
MC "thinking causes your brain to go hot...\n\n"
M "Crystal Sages melt at -30 °C, and they can rise the temperature around you from afar."
},
{ 'P', 0x4040C0, "Pikeman",
"When Pikemen move, they attack all cells which are now adjacent to them. "
"Luckily, they can be killed in the same way.\n\n"
"They never move if this would attack their friends."
},
{ 'F', 0xC04040, "Flail Guard",
"This guard of the Emerald Mine is wielding a huge flail. "
"You cannot attack him directly, as the flail would still hit you then. "
"Luckily, you have learned a trick: if you step away from him, "
"he will hit himself with the flail!"
},
{ 'M', 0x404040, "Miner",
"Miners have special tools for dealing with the Living Cave. "
"When they die, these tools activate, destroying the living cave "
"around them."
},
{ 'V', 0x421C52, "Vine Beast",
"A beast made of vines!\n\n"
"Vine Beasts turn into vines when they die."
},
{ 'V', 0x003000, "Vine Spirit",
"A spirit living in the vines!\n\n"
"Vine Spirits destroy the vines when they die."
},
{ 'T', 0x803030, "Dark Troll",
"A Troll without the power of Life."
},
{ 'E', 0xFFFF40, "Earth Elemental",
"A rare unliving construct from the Dead Caves. "
"It instantly destroys cave walls next to its path, and also leaves "
"an impassable wall behind it. You suppose that this impassable wall helps it to "
"escape from some threats. You hope you won't meet these threats..."
},
{ 'B', 0xC04040, "Red Hyperbug", hivehelp},
{ 'B', 0x40C040, "Green Hyperbug", hivehelp},
{ 'B', 0x4040C0, "Blue Hyperbug", hivehelp},
{ 'W', 0x404040, "Witch Apprentice",
"A Witch without any special powers. But watch out! She will "
"pick up any basic Orbs on her path, and use their powers."
},
{ 'W', 0xFF4040, "Speed Witch",
"A Witch with a Speed spell. She moves twice as fast as you. Unless you "
"have an Orb of Speed too, of course!"
},
{ 'W', 0xFFFFFF, "Flash Witch",
"A Witch with a Flash spell. Very dangerous!\n\n"
"Luckily, she never uses the spell if it would kill her friends. "
"She could destroy an Evil Golem, though."
},
{ 'W', 0xFF8000, "Fire Witch",
"A Witch with a Fire spell. She will leave a trail of fire behind her."
},
{ 'W', 0x8080FF, "Winter Witch",
"A Witch with a Winter spell. She is able to move through fire."
},
{ 'W', 0x808080, "Aether Witch",
"A Witch with an Aether spell. She is able to move through fire and walls."
},
{ '@', 0x905050, "Evil Golem",
"Somebody has summoned these evil constructs with a magical process."
},
{ '@', 0x8080FF, "Knight", camelothelp },
{ 'P', 0xD10000, "Cult Leader",
"These Cultists can push the statues, just like you."
},
{ 'B', 0x909000, "Slime Beast", slimehelp},
{ '@', 0x8080FF, "Knight", camelothelp }, // knight moved
{ '@', 0x8B4513, "Illusion",
"Illusions are targetted "
"by most monsters, just like yourself, Thumpers, and your friends."
},
};
enum eMonster {
moNone,
moYeti, moWolf, moWolfMoved,
moRanger,
moTroll, moGoblin,
moWorm, moWormtail, moWormwait, moHedge,
moDesertman,
moIvyRoot, moIvyHead, moIvyBranch, moIvyWait, moIvyNext, moIvyDead,
moMonkey,
moSlime,
moMirror, moMirage, moGolem, moGolemMoved,
moEagle, moSeep,
moZombie, moGhost, moNecromancer, moShadow,
moTentacle, moTentacletail, moTentaclewait, moTentacleEscaping,
moCultist, moPyroCultist,
moGreater, moGreaterM, moLesser, moLesserM,
moShark, moRunDog, moGreaterShark, moFireFairy,
moCrystalSage, moLancer, moFlailer, moMiner,
moVineBeast, moVineSpirit, moDarkTroll, moEarthElemental,
moBug0, moBug1, moBug2,
moWitch, moWitchSpeed, moWitchFlash, moWitchFire, moWitchWinter, moWitchGhost,
moEvilGolem, moKnight, moCultistLeader, moSlimeNextTurn, moKnightMoved,
moIllusion,
// temporary
moDeadBug, moLightningBolt
};
#define NUMWITCH 7
// --- items ----
const int ittypes = 40;
struct itemtype {
char glyph;
int color;
const char *name;
const char *help;
};
itemtype iinf[ittypes] = {
{ 0, 0, "none", NULL},
{ '*', 0xFFFFFF, "Ice Diamond",
M "Cold white gems, found in the Icy Land."
},
{ '$', 0xFFD700, "Gold",
MC "An expensive metal from the Living Caves. For some reason "
M "gold prevents the living walls from growing close to it."
},
{ ';', 0xFF4000, "Spice",
MC "A rare and expensive substance found in the Desert. "
M "It is believed to extend life and raise special psychic powers."
},
{ '*', 0xC00000, "Ruby",
M "A beautiful gem from the Jungle."
},
{ '!', 0xFFFF00, "Elixir of Life",
MC "A wonderful beverage, apparently obtained by mixing red and blue slime. You definitely feel more "
M "healthy after drinking it, but you still fell that one hit of a monster is enough to kill you."},
{ '%', 0xFF00FF, "Shard",
MC "A piece of a magic mirror, or a mirage cloud, that can be used for magical purposes. Only mirrors and clouds "
M "in the Land of Mirrors leave these."},
{ '/', 0xFF8000, "Necromancer's Totem",
M "These sinister totems contain valuable gems."},
{ '%', 0x00D000, "Demon Daisy",
M "These star-shaped flowers native to Hell are a valuable alchemical component."},
{ '/', 0x00FF00, "Statue of Cthulhu",
M "This statue is made of materials which cannot be found in your world."},
{ '*', 0xFF8000, "Phoenix Feather",
M "One of few things that does not cause the floor in the Land of Eternal Motion to collapse. Obviously they are quite valuable."
},
{ '*', 0x8080FF, "Ice Sapphire",
M "Cold blue gems, found in the Cocytus."
},
{ '*', 0xEEFF20, "Hyperstone",
M "These bright yellow gems can be found only by those who have mastered the Crossroads."
},
{ '[', 0x8080FF, "Key",
MC "That's all you need to unlock the Orb of Yendor! Well... as long as you are able to return to the Orb that this key unlocks...\n\n"
M "Each key unlocks only the Orb of Yendor which led you to it."
},
{ 'o', 0x306030, "Dead Orb",
MC "These orbs can be found in the Graveyard. You think that they were once powerful magical orbs, but by now, their "
M "power is long gone. No way to use them, you could as well simply drop them...\n\n"
},
{ 'o', 0xFF20FF, "Orb of Yendor",
MC "This wonderful Orb can only be collected by those who have truly mastered this hyperbolic universe, "
MC "as you need the right key to unlock it. Luckily, your psychic abilities will let you know "
M "where the key is after you touch the Orb." },
{ 'o', 0xFFFF00, "Orb of Storms",
M "This orb can be used to invoke the lightning spell, which causes lightning bolts to shoot from you in all directions."},
{ 'o', 0xFFFFFF, "Orb of Flash",
M "This orb can be used to invoke a flash spell, which destroys almost everything in radius of 2."},
{ 'o', 0x8080FF, "Orb of Winter",
M "This orb can be used to invoke a wall of ice. It also protects you from fires."},
{ 'o', 0xFF6060, "Orb of Speed",
M "This orb can be used to move faster for some time."},
{ 'o', 0x90B090, "Orb of Life",
M "This orb can be used to summon friendly golems. It is used instantly when you pick it up."},
{ 'o', 0x60D760, "Orb of Shielding",
M "This orb can protect you from damage."},
{ 'o', 0x606060, "Orb of Earth",
M "This orb lets you go through living walls. It also has powers in some of the other lands."},
{ 'o', 0x20FFFF, "Orb of Teleport",
MC "This orb lets you instantly move to another location on the map. Just click a location which "
M "is not next to you to teleport there. "
},
{ 'o', 0xA0FF40, "Orb of Safety",
MC "This orb lets you instantly move to a safe faraway location. Knowing the nature of this strange world, you doubt "
MC "that you will ever find the way back...\n\n"
MC "Your game will be saved if you quit the game while the Orb of Safety is still powered.\n\n"
M "Technical note: as it is virtually impossible to return, this Orb recycles memory used for the world so far (even if you do not use it to save the game). "
},
{ 'o', 0x40C000, "Orb of Thorns",
M "This orb allows attacking Hedgehog Warriors directly, as well as stabbing other monsters.\n"
},
{ '%', 0x0000FF, "Fern Flower",
M "This flower brings fortune to the person who finds it.\n"
},
{ '!', 0x900000, "Wine",
M "Wine grown under hyperbolic sun would be extremely prized in your home location."
},
{ 'o', 0x706070, "Orb of Aether",
M "This orb allows one to pass through all kinds of walls and chasms."
},
{ '$', 0xFFFFC0, "Silver",
"A precious metal from the Dead Caves."
},
{ 'o', 0x005050, "Orb of the Mind",
"This orb allows you to instantly kill a non-adjacent enemy by clicking it. "
"Each use drains 30 charges."
},
{ '!', 0xE2B227, "Royal Jelly",
"This is what Hyperbug Queens eat. Very tasty and healthy."
},
{ '*', 0x60C060, "Emerald",
"A precious green gem from the Emerald Mines."
},
{ 'o', 0x421C52, "Orb of Invisibility",
"When you have this Orb, most monsters won't see you, unless "
"you are standing still, attacking, or picking up items."
},
{ '*', 0xFFFF00, "Powerstone",
"A Stone from the Land of Power. You are not sure what it is exactly, but "
"as the Powerstones are kept in crystal cabinets, they are surely valuable."
},
{ 'o', 0xFF4000, "Orb of Fire",
"When you have this Orb, you will leave a trail of fire behind you."
},
{ '!', 0xFFFF00, "Holy Grail", camelothelp },
{ '?', 0x00FF00, "Grimoire",
"The Grimoires contain many secrets of the Great Old Ones. "
"Each new inner circle in the Temple of Cthulhu contains new Grimoires, with new secrets. "
"You hope to read them when you return home, and to learn many things. "
"The knowledge is valuable to you, but it is rather pointless to try to get "
"several copies of the same Grimoire..."
},
{ 'o', 0xFF8000, "Orb of the Dragon",
"This Orb allows you to throw fire, just like the Fire Cultists.\n\n"
"Each fire drains 5 charges. You are not allowed to throw fire into adjacent cells."
},
{ 'o', 0x8B4513, "Orb of Trickery",
"This Orb allows you to create illusions of yourself. Illusions are targetted "
"by most monsters, just like yourself, Thumpers, and your friends.\n\n"
"Each illusion takes 5 charges to create, and one extra charge "
"per turn. You can also click your illusion to take it away, restoring 4 charges.\n\n"
"If you have both Orb of Teleport and Orb of Trickery, Illusion is cast "
"first -- you can then teleport on your Illusion to switch places with it."
},
};
enum eItem { itNone, itDiamond, itGold, itSpice, itRuby, itElixir, itShard, itBone, itHell, itStatue,
itFeather, itSapphire, itHyperstone, itKey,
itGreenStone, itOrbYendor,
itOrbLightning, itOrbFlash, itOrbWinter, itOrbSpeed, itOrbLife, itOrbShield, itOrbDigging,
itOrbTeleport, itOrbSafety,
itOrbThorns, itFernFlower,
itWine, itOrbGhost, itSilver, itOrbPsi,
itRoyalJelly, itEmerald, itOrbInvis, itPower, itOrbFire,
itHolyGrail, itGrimoire,
itOrbDragon, itOrbIllusion
};
// --- wall types ---
const int walltypes = 37;
struct walltype {
char glyph;
int color;
const char *name;
const char *help;
};
const char *lakeDesc = "Hell has these lakes everywhere... They are shaped like evil stars, and filled with burning sulphur.";
walltype winf[walltypes] = {
{ '.', 0xFF00FF, "none", NULL},
{ '#', 0x8080FF, "ice wall",
M "Ice Walls melt after some time has passed."
},
{ '#', 0xC06000, "great wall", barrierhelp},
{ '+', 0x900030, "red slime", slimehelp },
{ '+', 0x300090, "blue slime", slimehelp },
{ '#', 0xA0D0A0, "living wall", cavehelp},
{ '.', 0x306060, "living floor",cavehelp},
{ '#', 0xD03030, "dead troll", trollhelp},
{ '#', 0xCDA98F, "sand dune",
M "A natural terrain feature of the Desert."
},
{ '%', 0xC0C0FF, "Magic Mirror",
M "You can go inside the Magic Mirror, and produce some mirror images to help you."
},
{ '%', 0xFFC0C0, "Cloud of Mirage",
MC "Tiny droplets of magical water. You see images of yourself inside them. "
M "Go inside the cloud, to make these images help you."},
{ '^', 0x8D694F, "Thumper",
M "A device that attracts sandworms and other enemies. You need to activate it."},
{ '^', 0x804000, "Bonfire",
M "A heap of wood that can be used to start a fire. Everything is already here, you just need to touch it to fire it."
},
{ '+', 0xC0C0C0, "ancient grave",
M "An ancient grave."
},
{ '+', 0xD0D080, "fresh grave",
M "A fresh grave. Necromancers like those."
},
{ '#', 0x00FFFF, "column",
M "A piece of architecture typical to R'Lyeh."
},
{ '=', 0xFFFF00, "lake of sulphur", lakeDesc },
{ '=', 0xFFFF00, "lake of sulphur", lakeDesc },
{ '=', 0x000080, "lake",
M "An impassable lake in Cocytus."
},
{ '_', 0x000080, "frozen lake", cocytushelp },
{ '>', 0x101010, "chasm",
M "It was a floor... until something walked on it."
},
{ '>', 0x101010, "chasmD",
M "It was a floor... until something walked on it."
},
{ '#', 0x60C000, "big tree", foresthelp},
{ '#', 0x006000, "tree", foresthelp},
{ '#', 0x421C52*2, "vine", vinehelp},
{ ':', 0x006000, "vine", hvinehelp},
{ ';', 0x006000, "vine", hvinehelp},
{ '^', 0x804000, "partial fire", "This cell is partially on fire."},
{ '#', 0xA07070, "dead wall", deadcavehelp},
{ '.', 0x401010, "dead floor",deadcavehelp},
{ '.', 0x905050, "rubble", "Dead floor, with some rubble."},
{ '#', 0xD0D010, "weird rock",
"A weirdly colored rock. Hyperentomologists claim that the "
"Hyperbug armies use these rocks to navigate back home after a victorious battle."
},
{ '#', 0x8080C0, "crystal cabinet",
"Witches use these crystal cabinets to protect Powerstones, as well as the more "
"expensive Orbs. They are partially protected from thieves: they are too strong "
"to be smashed by conventional attacks, and if you try to steal the item "
"using an Orb of Aether, your Aether power will be completely drained."
},
{ '#', 0xC0C0C0, "wall of Camelot", camelothelp },
{ '#', 0xA06000, "Round Table", camelothelp },
{ '=', 0x0000A0, "moat of Camelot", camelothelp},
{ '+', 0x606060, "big statue of Cthulhu",
"These statues of Cthulhu are too large to carry, and they don't look too "
"valuable anyway. Most monsters will never go through them... they probably have "
"their reasons. But you can go! When you move into the cell containing "
"a statue, you push the statue to the cell you left.\n"
}
};
enum eWall { waNone, waIcewall, waBarrier, waFloorA, waFloorB, waCavewall, waCavefloor, waDeadTroll, waDune,
waMirror, waCloud, waThumper, waBonfire, waAncientGrave, waFreshGrave, waColumn, waSulphurC, waSulphur,
waLake, waFrozenLake, waChasm, waChasmD, waDryTree, waWetTree,
waVinePlant, waVineHalfA, waVineHalfB, waPartialFire,
waDeadwall, waDeadfloor, waDeadfloor2, waWaxWall, waGlass, waCamelot, waRoundTable,
waCamelotMoat,
waBigStatue,
// temporary walls for various purposes
waTemporary, waEarthD
};
// --- land types ---
const int numLands = 20;
const int landtypes = numLands + 3;
struct landtype {
int color;
const char *name;
const char *help;
};
landtype linf[landtypes] = {
{ 0xFF00FF, "???" , ""},
{ 0xC06000, "Great Wall" , ""},
{ 0xFF0000, "Crossroads" ,
MC "This land is a quick gateway to other lands. It is very easy to find other lands "
MC "from the Crossroads. Which means that you find monsters from most other lands here!\n\n"
MC "As long as you have found enough treasure in their native lands, you can "
MC "find magical items in the Crossroads. Mirror Land brings mirrors and clouds, "
MC "and other land types bring magical orbs.\n\n"
MC "A special treasure, Hyperstone, can be found on the Crossroads, but only "
MC "after you have found 10 of every other treasure."
},
{ 0xCDA98F, "Desert",
M "A hot land, full of sand dunes, mysterious Spice, and huge and dangerous sand worms."
},
{ 0x8080FF, "Icy Land",
MC "A very cold land, full of ice walls. Your mere presence will cause these ice walls to "
M "melt, even if you don't want it."
},
{ 0x306060, "Living Cave", cavehelp},
{ 0x00C000, "Jungle",
M "A land filled with huge ivy plants and dangerous animals."
},
{ 0x900090, "Alchemist Lab", slimehelp},
{ 0x704070, "Mirror Land",
M "A strange land which contains mirrors and mirages, protected by Mirror Rangers."},
{ 0x404070, "Graveyard",
MC "All the monsters you kill are carried to this strange land, and buried. "
M "Careless Rogues are also carried here..."
},
{ 0x00FF00, "R'Lyeh",
M "An ancient sunken city which can be reached only when the stars are right.\n\n"
"You can find Temples of Cthulhu in R'Lyeh once you collect five Statues of Cthulhu."
},
{ 0xC00000, "Hell",
M "A land filled with demons and molten sulphur. Abandon all hope ye who enter here!"
},
{ 0x00FF00, "Cocytus",
cocytushelp
},
{ 0xFFFF00, "Land of Eternal Motion",
MC "A land where you cannot stop, because every piece of floor is extremely unstable. Only monsters who "
MC "can run forever are able to survive there, and only phoenix feathers are so light that they do not disturb "
M "the floor.\n"
},
{ 0x008000, "Dry Forest", foresthelp},
{ 0x0000C0, "Emerald Mine",
"Evil people are mining for emeralds in this living cave. "
"It does not grow naturally, but it is dug out in a regular "
"pattern, which is optimal according to the evil engineers."
},
{ 0x421C52, "Vineyard", foresthelp},
{ 0x104040, "Dead Cave", deadcavehelp},
{ 0x705020, "Hive", hivehelp},
{ 0xFFFF00, "Land of Power",
"The Land of Power is filled with everburning fire, magical Orbs, and guarded by "
"witches and golems. There are basic orbs lying everywhere, and more prized ones "
"are kept in crystal cabinets.\n\n"
"Witches are allowed to use all the powers of the "
"basic orbs against intruders. These powers never expire, but a Witch "
"can use only one power at a time (not counting Orbs of Life).\n\n"
"Witches and Golems don't pursue you into other Lands. Also, most Orb powers"
"are drained when you leave the Land of Power."
},
{ 0xD0D0D0, "Camelot", camelothelp },
{ 0xD000D0, "Temple of Cthulhu", templehelp },
{ 0xE08020, "Game Board", gameboardhelp}
};
enum eLand { laNone, laBarrier, laCrossroads, laDesert, laIce, laCaves, laJungle, laAlchemist, laMirror, laGraveyard,
laRlyeh, laHell, laCocytus, laMotion, laDryForest, laFjord, laWineyard, laDeadCaves,
laHive, laPower, laCamelot, laTemple, laGameBoard };
// cell information for the game
struct gcell {
// 8 bits
eLand land : 5;
unsigned mondir : 3;
// 8 bits
eMonster monst : 7;
unsigned ligon : 1;
// 16 bits
eWall wall : 6;
eLand barleft : 5, barright : 5;
// 16 bits
eItem item : 6;
unsigned cpdist : 5, mpdist : 5;
// 14 bits
unsigned pathdist : 10, bardir : 4;
short tmp;
float heat;
};
#define NODIR 7
#define NOBARRIERS 8

407
fjordgen.cpp Normal file
View File

@ -0,0 +1,407 @@
// rules for the fjordvalues of heptagons.
int fjord_heptagon(int parent, int dir) {
// no fjordgen here
if(parent == 0) return 0;
#define RULE(t1,s1,d,t2,s2) \
if(parent == t1*8+s1 && dir == d) return t2*8+s2;
RULE(8,0,3,12,4)
RULE(8,0,4,12,0)
RULE(8,0,5,42,0)
RULE(8,1,3,40,0)
RULE(8,1,4,12,4)
RULE(8,1,5,12,0)
RULE(8,2,3,34,0)
RULE(8,2,4,40,0)
RULE(8,2,5,12,4)
RULE(8,3,3,10,0)
RULE(8,3,4,34,0)
RULE(8,3,5,40,0)
RULE(8,4,3,32,0)
RULE(8,4,4,10,0)
RULE(8,4,5,34,0)
RULE(8,5,3,42,0)
RULE(8,5,4,32,0)
RULE(8,5,5,10,0)
RULE(8,6,3,12,0)
RULE(8,6,4,42,0)
RULE(8,6,5,32,0)
RULE(9,0,3,13,4)
RULE(9,0,4,13,0)
RULE(9,0,5,43,0)
RULE(9,1,3,41,0)
RULE(9,1,4,13,4)
RULE(9,1,5,13,0)
RULE(9,2,3,35,0)
RULE(9,2,4,41,0)
RULE(9,2,5,13,4)
RULE(9,3,3,11,0)
RULE(9,3,4,35,0)
RULE(9,3,5,41,0)
RULE(9,4,3,33,0)
RULE(9,4,4,11,0)
RULE(9,4,5,35,0)
RULE(9,5,3,43,0)
RULE(9,5,4,33,0)
RULE(9,5,5,11,0)
RULE(9,6,3,13,0)
RULE(9,6,4,43,0)
RULE(9,6,5,33,0)
RULE(10,0,3,14,4)
RULE(10,0,4,14,0)
RULE(10,0,5,40,3)
RULE(10,1,3,42,4)
RULE(10,1,4,14,4)
RULE(10,1,5,14,0)
RULE(10,2,3,32,1)
RULE(10,2,4,42,4)
RULE(10,2,5,14,4)
RULE(10,3,3,8,0)
RULE(10,3,4,32,1)
RULE(10,3,5,42,4)
RULE(10,4,3,34,6)
RULE(10,4,4,8,0)
RULE(10,4,5,32,1)
RULE(10,5,3,40,3)
RULE(10,5,4,34,6)
RULE(10,5,5,8,0)
RULE(10,6,3,14,0)
RULE(10,6,4,40,3)
RULE(10,6,5,34,6)
RULE(11,0,3,15,4)
RULE(11,0,4,15,0)
RULE(11,0,5,41,3)
RULE(11,1,3,43,4)
RULE(11,1,4,15,4)
RULE(11,1,5,15,0)
RULE(11,2,3,33,1)
RULE(11,2,4,43,4)
RULE(11,2,5,15,4)
RULE(11,3,3,9,0)
RULE(11,3,4,33,1)
RULE(11,3,5,43,4)
RULE(11,4,3,35,6)
RULE(11,4,4,9,0)
RULE(11,4,5,33,1)
RULE(11,5,3,41,3)
RULE(11,5,4,35,6)
RULE(11,5,5,9,0)
RULE(11,6,3,15,0)
RULE(11,6,4,41,3)
RULE(11,6,5,35,6)
RULE(12,0,3,8,4)
RULE(12,0,4,40,1)
RULE(12,0,5,14,2)
RULE(12,1,3,12,6)
RULE(12,1,4,8,4)
RULE(12,1,5,40,1)
RULE(12,2,0,14,2)
RULE(12,2,1,42,6)
RULE(12,2,2,8,3)
RULE(12,2,3,12,5)
RULE(12,2,4,12,6)
RULE(12,2,5,8,4)
RULE(12,2,6,40,1)
RULE(12,3,3,8,3)
RULE(12,3,4,12,5)
RULE(12,3,5,12,6)
RULE(12,4,3,42,6)
RULE(12,4,4,8,3)
RULE(12,4,5,12,5)
RULE(12,5,3,14,2)
RULE(12,5,4,42,6)
RULE(12,5,5,8,3)
RULE(12,6,3,40,1)
RULE(12,6,4,14,2)
RULE(12,6,5,42,6)
RULE(13,0,3,9,4)
RULE(13,0,4,41,1)
RULE(13,0,5,15,2)
RULE(13,1,3,13,6)
RULE(13,1,4,9,4)
RULE(13,1,5,41,1)
RULE(13,2,3,13,5)
RULE(13,2,4,13,6)
RULE(13,2,5,9,4)
RULE(13,3,3,9,3)
RULE(13,3,4,13,5)
RULE(13,3,5,13,6)
RULE(13,4,3,43,6)
RULE(13,4,4,9,3)
RULE(13,4,5,13,5)
RULE(13,5,3,15,2)
RULE(13,5,4,43,6)
RULE(13,5,5,9,3)
RULE(13,6,3,41,1)
RULE(13,6,4,15,2)
RULE(13,6,5,43,6)
RULE(14,0,3,10,4)
RULE(14,0,4,42,5)
RULE(14,0,5,12,2)
RULE(14,1,3,14,6)
RULE(14,1,4,10,4)
RULE(14,1,5,42,5)
RULE(14,2,0,12,2)
RULE(14,2,3,14,5)
RULE(14,2,4,14,6)
RULE(14,2,5,10,4)
RULE(14,3,3,10,3)
RULE(14,3,4,14,5)
RULE(14,3,5,14,6)
RULE(14,4,3,40,2)
RULE(14,4,4,10,3)
RULE(14,4,5,14,5)
RULE(14,5,3,12,2)
RULE(14,5,4,40,2)
RULE(14,5,5,10,3)
RULE(14,6,3,42,5)
RULE(14,6,4,12,2)
RULE(14,6,5,40,2)
RULE(15,0,3,11,4)
RULE(15,0,4,43,5)
RULE(15,0,5,13,2)
RULE(15,1,3,15,6)
RULE(15,1,4,11,4)
RULE(15,1,5,43,5)
RULE(15,2,3,15,5)
RULE(15,2,4,15,6)
RULE(15,2,5,11,4)
RULE(15,3,3,11,3)
RULE(15,3,4,15,5)
RULE(15,3,5,15,6)
RULE(15,4,3,41,2)
RULE(15,4,4,11,3)
RULE(15,4,5,15,5)
RULE(15,5,3,13,2)
RULE(15,5,4,41,2)
RULE(15,5,5,11,3)
RULE(15,6,3,43,5)
RULE(15,6,4,13,2)
RULE(15,6,5,41,2)
RULE(32,0,3,43,2)
RULE(32,0,4,33,3)
RULE(32,0,5,42,3)
RULE(32,1,3,33,5)
RULE(32,1,4,43,2)
RULE(32,1,5,33,3)
RULE(32,2,3,42,1)
RULE(32,2,4,33,5)
RULE(32,2,5,43,2)
RULE(32,3,3,8,1)
RULE(32,3,4,42,1)
RULE(32,3,5,33,5)
RULE(32,4,3,10,6)
RULE(32,4,4,8,1)
RULE(32,4,5,42,1)
RULE(32,5,3,42,3)
RULE(32,5,4,10,6)
RULE(32,5,5,8,1)
RULE(32,6,3,33,3)
RULE(32,6,4,42,3)
RULE(32,6,5,10,6)
RULE(33,0,3,42,2)
RULE(33,0,4,32,3)
RULE(33,0,5,43,3)
RULE(33,1,3,32,5)
RULE(33,1,4,42,2)
RULE(33,1,5,32,3)
RULE(33,2,3,43,1)
RULE(33,2,4,32,5)
RULE(33,2,5,42,2)
RULE(33,3,3,9,1)
RULE(33,3,4,43,1)
RULE(33,3,5,32,5)
RULE(33,4,3,11,6)
RULE(33,4,4,9,1)
RULE(33,4,5,43,1)
RULE(33,5,3,43,3)
RULE(33,5,4,11,6)
RULE(33,5,5,9,1)
RULE(33,6,3,32,3)
RULE(33,6,4,43,3)
RULE(33,6,5,11,6)
RULE(34,0,3,35,4)
RULE(34,0,4,41,5)
RULE(34,0,5,35,2)
RULE(34,1,3,40,4)
RULE(34,1,4,35,4)
RULE(34,1,5,41,5)
RULE(34,2,3,10,1)
RULE(34,2,4,40,4)
RULE(34,2,5,35,4)
RULE(34,3,3,8,6)
RULE(34,3,4,10,1)
RULE(34,3,5,40,4)
RULE(34,4,3,40,6)
RULE(34,4,4,8,6)
RULE(34,4,5,10,1)
RULE(34,5,3,35,2)
RULE(34,5,4,40,6)
RULE(34,5,5,8,6)
RULE(34,6,3,41,5)
RULE(34,6,4,35,2)
RULE(34,6,5,40,6)
RULE(35,0,3,34,4)
RULE(35,0,4,40,5)
RULE(35,0,5,34,2)
RULE(35,1,3,41,4)
RULE(35,1,4,34,4)
RULE(35,1,5,40,5)
RULE(35,2,3,11,1)
RULE(35,2,4,41,4)
RULE(35,2,5,34,4)
RULE(35,3,3,9,6)
RULE(35,3,4,11,1)
RULE(35,3,5,41,4)
RULE(35,4,3,41,6)
RULE(35,4,4,9,6)
RULE(35,4,5,11,1)
RULE(35,5,3,34,2)
RULE(35,5,4,41,6)
RULE(35,5,5,9,6)
RULE(35,6,3,40,5)
RULE(35,6,4,34,2)
RULE(35,6,5,41,6)
RULE(40,0,3,34,5)
RULE(40,0,4,10,2)
RULE(40,0,5,14,1)
RULE(40,1,3,35,3)
RULE(40,1,4,34,5)
RULE(40,1,5,10,2)
RULE(40,2,3,34,1)
RULE(40,2,4,35,3)
RULE(40,2,5,34,5)
RULE(40,3,3,8,5)
RULE(40,3,4,34,1)
RULE(40,3,5,35,3)
RULE(40,4,3,12,3)
RULE(40,4,4,8,5)
RULE(40,4,5,34,1)
RULE(40,5,3,14,1)
RULE(40,5,4,12,3)
RULE(40,5,5,8,5)
RULE(40,6,3,10,2)
RULE(40,6,4,14,1)
RULE(40,6,5,12,3)
RULE(41,0,3,35,5)
RULE(41,0,4,11,2)
RULE(41,0,5,15,1)
RULE(41,1,3,34,3)
RULE(41,1,4,35,5)
RULE(41,1,5,11,2)
RULE(41,2,3,35,1)
RULE(41,2,4,34,3)
RULE(41,2,5,35,5)
RULE(41,3,3,9,5)
RULE(41,3,4,35,1)
RULE(41,3,5,34,3)
RULE(41,4,3,13,3)
RULE(41,4,4,9,5)
RULE(41,4,5,35,1)
RULE(41,5,3,15,1)
RULE(41,5,4,13,3)
RULE(41,5,5,9,5)
RULE(41,6,3,11,2)
RULE(41,6,4,15,1)
RULE(41,6,5,13,3)
RULE(42,0,3,10,5)
RULE(42,0,4,32,2)
RULE(42,0,5,33,4)
RULE(42,1,3,14,3)
RULE(42,1,4,10,5)
RULE(42,1,5,32,2)
RULE(42,2,3,12,1)
RULE(42,2,4,14,3)
RULE(42,2,5,10,5)
RULE(42,3,3,8,2)
RULE(42,3,4,12,1)
RULE(42,3,5,14,3)
RULE(42,4,3,32,6)
RULE(42,4,4,8,2)
RULE(42,4,5,12,1)
RULE(42,5,3,33,4)
RULE(42,5,4,32,6)
RULE(42,5,5,8,2)
RULE(42,6,3,32,2)
RULE(42,6,4,33,4)
RULE(42,6,5,32,6)
RULE(43,0,3,11,5)
RULE(43,0,4,33,2)
RULE(43,0,5,32,4)
RULE(43,1,3,15,3)
RULE(43,1,4,11,5)
RULE(43,1,5,33,2)
RULE(43,2,3,13,1)
RULE(43,2,4,15,3)
RULE(43,2,5,11,5)
RULE(43,3,3,9,2)
RULE(43,3,4,13,1)
RULE(43,3,5,15,3)
RULE(43,4,3,33,6)
RULE(43,4,4,9,2)
RULE(43,4,5,13,1)
RULE(43,5,3,32,4)
RULE(43,5,4,33,6)
RULE(43,5,5,9,2)
RULE(43,6,3,33,2)
RULE(43,6,4,32,4)
RULE(43,6,5,33,6)
printf("HEPTAGONAL RULE MISSING for (%d,%d)\n", parent,dir);
exit(1);
}
// calculate the fjordvalue of a hexagonal cell,
// based on the fjordvalues of the neighbor heptacells.
int fjord_hexagon(int a, int b, int c) {
// pick the lexicographically smallest representation of the cycle
if(b <= a || c<a) { int t=a; a=b; b=c; c=t; }
if(b <= a || c<a) { int t=a; a=b; b=c; c=t; }
if(a==8 && b == 10 && c== 34) return 30;
if(a==8 && b == 12 && c== 12) return 4;
if(a==8 && b == 12 && c== 42) return 48;
if(a==8 && b == 32 && c== 10) return 28;
if(a==8 && b == 34 && c== 40) return 20;
if(a==8 && b == 40 && c== 12) return 16;
if(a==8 && b == 42 && c== 32) return 52;
if(a==9 && b == 11 && c== 35) return 31;
if(a==9 && b == 13 && c== 13) return 5;
if(a==9 && b == 13 && c== 43) return 49;
if(a==9 && b == 33 && c== 11) return 29;
if(a==9 && b == 35 && c== 41) return 21;
if(a==9 && b == 41 && c== 13) return 17;
if(a==9 && b == 43 && c== 33) return 53;
if(a==10 && b == 14 && c== 14) return 6;
if(a==10 && b == 14 && c== 40) return 50;
if(a==10 && b == 32 && c== 42) return 22;
if(a==10 && b == 40 && c== 34) return 54;
if(a==10 && b == 42 && c== 14) return 18;
if(a==11 && b == 15 && c== 15) return 7;
if(a==11 && b == 15 && c== 41) return 51;
if(a==11 && b == 33 && c== 43) return 23;
if(a==11 && b == 41 && c== 35) return 55;
if(a==11 && b == 43 && c== 15) return 19;
if(a==12 && b == 12 && c== 12) return 44;
if(a==12 && b == 14 && c== 42) return 38;
if(a==12 && b == 40 && c== 14) return 36;
if(a==13 && b == 13 && c== 13) return 45;
if(a==13 && b == 15 && c== 43) return 39;
if(a==13 && b == 41 && c== 15) return 37;
if(a==14 && b == 14 && c== 14) return 46;
if(a==15 && b == 15 && c== 15) return 47;
if(a==32 && b == 33 && c== 42) return 26;
if(a==32 && b == 33 && c== 43) return 57;
if(a==32 && b == 42 && c== 33) return 56;
if(a==32 && b == 43 && c== 33) return 27;
if(a==34 && b == 35 && c== 40) return 24;
if(a==34 && b == 35 && c== 41) return 59;
if(a==34 && b == 40 && c== 35) return 58;
if(a==34 && b == 41 && c== 35) return 25;
printf("HEXAGONAL RULE MISSING for (%d,%d,%d)\n", a,b,c);
return 0;
// exit(1);
}

5611
game.cpp Normal file

File diff suppressed because it is too large Load Diff

124
geometry.cpp Normal file
View File

@ -0,0 +1,124 @@
// Hyperbolic Rogue
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
// geometrical constants
ld tessf, crossf, hexf;
#define ALPHA (M_PI*2/7)
hyperpoint Crad[42];
transmatrix heptmove[7], hexmove[7];
void precalc() {
ld fmin = 1, fmax = 2;
for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2;
hyperpoint H = xpush(f) * C0;
ld v1 = intval(H, C0), v2 = intval(H, spin(2*M_PI/7)*H);
if(v1 > v2) fmin = f; else fmax = f;
}
tessf = fmin;
fmin = 0, fmax = 2;
for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2;
hyperpoint H = spin(M_PI/7) * xpush(f) * C0;
ld v1 = intval(H, C0), v2 = intval(H, xpush(tessf) * C0);
if(v1 < v2) fmin = f; else fmax = f;
}
crossf = fmin;
fmin = 0, fmax = tessf;
for(int p=0; p<100; p++) {
ld f = (fmin+fmax) / 2;
hyperpoint H = xpush(f) * C0;
hyperpoint H1 = spin(2*M_PI/7) * H;
hyperpoint H2 = xpush(tessf-f) * C0;
ld v1 = intval(H, H1), v2 = intval(H, H2);
if(v1 < v2) fmin = f; else fmax = f;
}
hexf = fmin;
for(int i=0; i<42; i++)
Crad[i] = spin(2*M_PI*i/42) * xpush(.4) * C0;
for(int d=0; d<7; d++)
heptmove[d] = spin(-d * ALPHA) * xpush(tessf) * spin(M_PI);
for(int d=0; d<7; d++)
hexmove[d] = spin(-d * ALPHA) * xpush(-crossf)* spin(M_PI);
}
transmatrix ddi(ld dir, ld dist) {
// EUCLIDEAN
if(euclid)
return eupush(cos(M_PI*dir/42) * dist, -sin(M_PI*dir/42) * dist);
else
return spin(M_PI*dir/42) * xpush(dist) * spin(-M_PI*dir/42);
}
// tesselation drawing
#define NUMFACE 500
transmatrix tess[NUMFACE];
void genTesselation() {
int N = 1;
tess[0] = Id;
for(int i=0; i<N; i++) {
for(int t=0; t<7; t++) {
ld trot = (t % 8) * M_PI * 2 / 7.0;
transmatrix T = spin(trot) * xpush(tessf) * /*spin(-trot) */ spin(M_PI) * tess[i];
for(int j=0; j<N; j++) if(intval(T*C0, tess[j]*C0) < 0.1) goto nextt;
// printf("%d:%d -> %d\n", i,t, N);
tess[N] = T; N++;
if(N == NUMFACE) return;
nextt: ;
}
}
}
struct ltd {
hyperpoint P1;
hyperpoint P2;
int col;
};
vector<ltd> lines;
void addline(hyperpoint P1, hyperpoint P2, int col) {
ltd L;
L.P1 = P1; L.P2 = P2; L.col = col;
lines.push_back(L);
}
void addlines() {
// change the if(0) conditions to see the underlying structure
if(0) for(int t =0; t<NUMFACE; t++) for(int u=1; u<8; u++) {
addline(View * tess[t] * C0, View * tess[t] * tess[u] * C0, u==1 ? 0xA000 : 0x4000);
}
if(0) for(int t =0; t<NUMFACE; t++) for(int r=0; r<7; r++) {
addline(
View * tess[t] * spin((2*r+1)*M_PI/7) * xpush(crossf) * C0,
View * tess[t] * spin((2*r+3)*M_PI/7) * xpush(crossf) * C0,
0x808080);
}
if(1) for(int t =0; t<NUMFACE; t++) for(int r=0; r<7; r++) {
addline(tess[t] * spin(M_PI*2*(r+1)/7) * xpush(hexf) * C0, tess[t] * spin(M_PI*2*r/7) * xpush(hexf) * C0, 0x404040);
addline(tess[t] * spin(M_PI*2*r/7) * xpush(hexf) * C0, tess[t] * spin(M_PI*2*r/7) * xpush(tessf/2) * C0, 0x404040);
}
}
void initgeo() {
precalc();
genTesselation();
addlines();
}

4405
graph.cpp Normal file

File diff suppressed because it is too large Load Diff

158
heptagon.cpp Normal file
View File

@ -0,0 +1,158 @@
// Hyperbolic Rogue
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
// heptagon here refers to underlying heptagonal tesselation
// (which you can see by changing the conditions in graph.cpp)
// automaton state
enum hstate { hsOrigin, hsA, hsB, hsError };
int fixrot(int a) { return (a+98)% 7; }
int fix42(int a) { return (a+420)% 42; }
struct heptagon;
struct cell;
cell *newCell(int type, heptagon *master);
struct heptagon {
// automaton state
hstate s : 8;
// we are spin[i]-th neighbor of move[i]
unsigned char spin[7];
// neighbors; move[0] always goes towards origin,
// and then we go clockwise
heptagon* move[7];
// distance from the origin
short distance;
// fjord/wineyard generator
short fjordval;
heptagon*& modmove(int i) { return move[fixrot(i)]; }
unsigned char& gspin(int i) { return spin[fixrot(i)]; }
cell *c7;
// associated generator of alternate structure, for Camelot and horocycles
heptagon *alt;
};
// the automaton is used to generate each heptagon in an unique way
// (you can see the tree obtained by changing the conditions in graph.cpp)
// from the origin we can go further in any direction, and from other heptagons
// we can go in directions 3 and 4 (0 is back to origin, so 3 and 4 go forward),
// and sometimes in direction 5
hstate transition(hstate s, int dir) {
if(s == hsOrigin) return hsA;
if(s == hsA && dir >= 3 && dir <= 4) return hsA;
if(s == hsA && dir == 5) return hsB;
if(s == hsB && dir == 4) return hsB;
if(s == hsB && dir == 3) return hsA;
return hsError;
}
heptagon origin;
vector<heptagon*> allAlts;
// create h->move[d] if not created yet
heptagon *createStep(heptagon *h, int d);
// create a new heptagon
heptagon *buildHeptagon(heptagon *parent, int d, hstate s, int pard = 0) {
heptagon *h = new heptagon;
h->alt = NULL;
h->s = s;
for(int i=0; i<7; i++) h->move[i] = NULL;
h->move[pard] = parent; h->spin[pard] = d;
parent->move[d] = h; parent->spin[d] = pard;
if(parent->c7) {
h->c7 = newCell(7, h);
h->fjordval = fjord_heptagon(parent->fjordval, d);
}
else {
h->c7 = NULL;
h->fjordval = 0;
}
//generateFjordval(parent);
//generateFjordval(h);
if(pard == 0) {
if(parent->s == hsOrigin) h->distance = 2;
else if(h->spin[0] == 5)
h->distance = parent->distance + 1;
else if(h->spin[0] == 4 && h->move[0]->s == hsB)
h->distance = createStep(h->move[0], (h->spin[0]+2)%7)->distance + 3;
else h->distance = parent->distance + 2;
}
else h->distance = parent->distance - 2;
return h;
}
void addSpin(heptagon *h, int d, heptagon *from, int rot, int spin) {
rot = fixrot(rot);
createStep(from, rot);
h->move[d] = from->move[rot];
h->spin[d] = fixrot(from->spin[rot] + spin);
h->move[d]->move[fixrot(from->spin[rot] + spin)] = h;
h->move[d]->spin[fixrot(from->spin[rot] + spin)] = d;
//generateFjordval(h->move[d]); generateFjordval(h);
}
heptagon *createStep(heptagon *h, int d) {
d = fixrot(d);
if(h->s != hsOrigin && !h->move[0]) {
buildHeptagon(h, 0, hsA, 4);
}
if(h->move[d]) return h->move[d];
if(h->s == hsOrigin) {
buildHeptagon(h, d, hsA);
}
else if(d == 1) {
addSpin(h, d, h->move[0], h->spin[0]-1, -1);
}
else if(d == 6) {
addSpin(h, d, h->move[0], h->spin[0]+1, +1);
}
else if(d == 2) {
createStep(h->move[0], h->spin[0]-1);
addSpin(h, d, h->move[0]->modmove(h->spin[0]-1), 5 + h->move[0]->gspin(h->spin[0]-1), -1);
}
else if(d == 5 && h->s == hsB) {
createStep(h->move[0], h->spin[0]+1);
addSpin(h, d, h->move[0]->modmove(h->spin[0]+1), 2 + h->move[0]->gspin(h->spin[0]+1), +1);
}
else
buildHeptagon(h, d, (d == 5 || (h->s == hsB && d == 4)) ? hsB : hsA);
return h->move[d];
}
// a structure used to walk on the heptagonal tesselation
// (remembers not only the heptagon, but also direction)
struct heptspin {
heptagon *h;
int spin;
};
heptspin hsstep(const heptspin &hs, int spin) {
createStep(hs.h, hs.spin);
heptspin res;
res.h = hs.h->move[hs.spin];
res.spin = fixrot(hs.h->spin[hs.spin] + spin);
return res;
}
heptspin hsspin(const heptspin &hs, int val) {
heptspin res;
res.h = hs.h;
res.spin = fixrot(hs.spin + val);
return res;
}
// display the coordinates of the heptagon
void backtrace(heptagon *pos) {
if(pos == &origin) return;
backtrace(pos->move[0]);
printf(" %d", pos->spin[0]);
}
void hsshow(const heptspin& t) {
printf("ORIGIN"); backtrace(t.h); printf(" (spin %d)\n", t.spin);
}

BIN
hr-icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
hr3-caves.ogg Normal file

Binary file not shown.

BIN
hr3-crossroads.ogg Normal file

Binary file not shown.

BIN
hr3-desert.ogg Normal file

Binary file not shown.

BIN
hr3-graveyard.ogg Normal file

Binary file not shown.

BIN
hr3-hell.ogg Normal file

Binary file not shown.

BIN
hr3-icyland.ogg Normal file

Binary file not shown.

BIN
hr3-jungle.ogg Normal file

Binary file not shown.

BIN
hr3-laboratory.ogg Normal file

Binary file not shown.

BIN
hr3-mirror.ogg Normal file

Binary file not shown.

BIN
hr3-motion.ogg Normal file

Binary file not shown.

BIN
hr3-rlyeh.ogg Normal file

Binary file not shown.

200
hyper.cpp Normal file
View File

@ -0,0 +1,200 @@
// Hyperbolic Rogue
// Copyright (C) 2011 Zeno Rogue
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
// disable for the Android version
#define ISANDROID 0
#define ISMOBILE 0
#define ISIOS 0
#define VER "6.6"
#define VERNUM 6600
#define VERNUM_HEX 0x6600
#include <SDL/SDL.h>
#ifndef MAC
#undef main
#endif
#include <SDL/SDL_ttf.h>
#include <math.h>
#include <time.h>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const char *scorefile = "hyperrogue.log";
const char *conffile = "hyperrogue.ini";
const char *musicfile = "";
typedef long double ld;
template<class T> int size(T& x) {return x.size(); }
string its(int i) { char buf[64]; sprintf(buf, "%d", i); return buf; }
string fts(float x) { char buf[64]; sprintf(buf, "%4.2f", x); return buf; }
#undef DEBT
void DEBT(const char *buf) {
printf("%4d %s\n", SDL_GetTicks(), buf);
}
string s0;
void addMessage(string s, char spamtype = 0);
int clWidth, clHeight, clFont;
string commandline;
#include "hyperpoint.cpp"
#include "fjordgen.cpp"
#include "heptagon.cpp"
#include "classes.cpp"
#include "language.cpp"
#ifdef STEAM
#define NOLICENSE
#endif
#include "achievement.h"
#include "cell.cpp"
#include "game.cpp"
#include "graph.cpp"
#include "achievement.cpp"
#include <unistd.h>
bool switchEuclid = false;
int main(int argc, char **argv) {
printf("HyperRogue by Zeno Rogue <zeno@attnam.com>, version "VER"\n");
#ifndef NOLICENSE
printf("released under GNU General Public License version 2 and thus\n");
printf("comes with absolutely no warranty; see COPYING for details\n");
#endif
achievement_init();
// printf("cell size = %d\n", int(sizeof(cell)));
srand(time(NULL));
#ifdef FHS
char sbuf[640], cbuf[640];
if(getenv("HOME")) {
snprintf(sbuf, 640, "%s/.%s", getenv("HOME"), scorefile); scorefile = sbuf;
snprintf(cbuf, 640, "%s/.%s", getenv("HOME"), conffile); conffile = cbuf;
}
#endif
for(int i=1; i<argc; i++) {
if(strcmp(argv[i], "-c") == 0 && i != argc-1) {conffile = argv[i+1]; i++;}
else if(strcmp(argv[i], "-s") == 0 && i != argc-1) {scorefile = argv[i+1]; i++;}
else if(strcmp(argv[i], "-m") == 0 && i != argc-1) {musicfile = argv[i+1]; i++;}
else if(strcmp(argv[i], "-W") == 0 && i != argc-1) {
for(int l=2; l<landtypes; l++) if(strstr(linf[l].name, argv[i+1]) != NULL)
firstland = euclidland = eLand(l);
i++;
}
else if(strcmp(argv[i], "-E") == 0) {
switchEuclid = true;
}
else if(strcmp(argv[i], "-f") == 0) { commandline += "f"; }
else if(strcmp(argv[i], "-w") == 0) { commandline += "w"; }
else if(strcmp(argv[i], "-e") == 0) { commandline += "e"; }
else if(strcmp(argv[i], "-a") == 0) { commandline += "a"; }
else if(strcmp(argv[i], "-p") == 0) { commandline += "p"; }
else if(strcmp(argv[i], "-o") == 0) { commandline += "o"; }
else if(strcmp(argv[i], "-r") == 0) {
i++;
sscanf(argv[i], "%dx%dx%d", &clWidth, &clHeight, &clFont);
}
else if(strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "-v") == 0) {
printf("HyperRogue version " VER "\n");
exit(0);
}
else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
printf("Press F1 while playing to get ingame options.\n\n");
printf("HyperRogue accepts the following command line options:\n");
printf(" -c FILE - use the specified configuration file\n");
printf(" -s FILE - use the specified highscore file\n");
printf(" -m FILE - use the specified soundtrack (music)\n");
printf(" --version, -v - show the version number\n");
printf(" --help, -h - show the commandline options\n");
printf(" -f, -w - start in the fullscreen or windowed mode\n");
printf(" -e, -a, -p - start in the Escher, ASCII, or Plain mode\n");
printf(" -r WxHxF - use the given resolution and font size\n");
printf(" -o - switch the OpenGL mode on or off\n");
printf(" -W LAND - start in the given land (cheat)\n");
printf(" -E - start in Euclidean\n");
exit(0);
}
else {
printf("Unknown option: %s\n", argv[i]);
exit(3);
}
}
/* transmatrix T;
for(int a=0; a<3; a++) for(int b=0; b<3; b++)
T[a][b] = (10 + a*a + b*4 + (b==1?a:0)) / 20.;
display(T);
transmatrix T2 = inverse(T);
display(T2);
display(T*T2); */
// initlanguage();
initcells();
/* for(int uu=9; uu >= 0; uu--) {
printf("uu=%d\n", uu);
initgame(uu);
restartGame();
} */
eLand f = firstland;
loadsave();
initgame();
restoreGolems(items[itOrbLife]); items[itOrbLife] = 0;
firstland = f;
// exit(1);
initgraph();
int t1 = SDL_GetTicks();
if(switchEuclid) restartGameSwitchEuclid();
mainloop();
achievement_final(!items[itOrbSafety]);
SDL_Quit();
saveStats();
int msec = SDL_GetTicks() - t1;
printf("frame : %f ms (%f fps)\n", 1.*msec/frames, 1000.*frames/msec);
clearMemory();
cleargraph();
achievement_close();
return 0;
}

BIN
hyper.exe Executable file

Binary file not shown.

26
hyper.rc Normal file
View File

@ -0,0 +1,26 @@
id ICON "hr-icon.ico"
1 VERSIONINFO
FILEVERSION 5,5,1,0
PRODUCTVERSION 5,5,1,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904E4"
BEGIN
VALUE "CompanyName", "Zeno Rogue"
VALUE "FileDescription", "A roguelike in non-euclidean space"
VALUE "FileVersion", "55a"
VALUE "InternalName", "hyper"
VALUE "LegalCopyright", "Zeno Rogue"
VALUE "OriginalFilename", "hyper.exe"
VALUE "ProductName", "HyperRogue"
VALUE "ProductVersion", "5.5a"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1252
END
END

250
hyperpoint.cpp Normal file
View File

@ -0,0 +1,250 @@
// Hyperbolic Rogue
// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details
// for the Euclidean mode...
bool euclid = false;
// hyperbolic points and matrices
// basic functions and types
//===========================
ld sinh(ld alpha) { return (exp(alpha) - exp(-alpha)) / 2; }
ld cosh(ld alpha) { return (exp(alpha) + exp(-alpha)) / 2; }
ld squar(ld x) { return x*x; }
int sig(int z) { return z<2?1:-1; }
// hyperbolic point:
//===================
// we represent the points on the hyperbolic plane
// by points in 3D space (Minkowski space) such that x^2+y^2-z^2 == -1, z > 0
// (this is analogous to representing a sphere with points such that x^2+y^2+z^2 == 1)
struct hyperpoint {
ld tab[3];
ld& operator [] (int i) { return tab[i]; }
const ld& operator [] (int i) const { return tab[i]; }
};
hyperpoint hpxyz(ld x, ld y, ld z) {
// EUCLIDEAN
hyperpoint r; r[0] = x; r[1] = y; r[2] = z; return r;
}
hyperpoint hpxy(ld x, ld y) {
// EUCLIDEAN
return hpxyz(x,y, euclid ? 1 : 1+x*x+y*y);
}
// center of the pseudosphere
hyperpoint Hypc = { {0,0,0} };
// origin of the hyperbolic plane
hyperpoint C0 = { {0,0,1} };
// a point (I hope this number needs no comments ;) )
hyperpoint Cx1 = { {1,0,1.41421356237} };
// this function returns approximate square of distance between two points
// (in the spherical analogy, this would be the distance in the 3D space,
// through the interior, not on the surface)
// also used to verify whether a point h1 is on the hyperbolic plane by using Hypc for h2
ld intval(const hyperpoint &h1, const hyperpoint &h2) {
return squar(h1[0]-h2[0]) + squar(h1[1]-h2[1]) - squar(h1[2]-h2[2]);
}
// display a hyperbolic point
char *display(const hyperpoint& H) {
static char buf[100];
sprintf(buf, "%8.4f:%8.4f:%8.4f", double(H[0]), double(H[1]), double(H[2]));
return buf;
}
// get the center of the line segment from H1 to H2
hyperpoint mid(const hyperpoint& H1, const hyperpoint& H2) {
hyperpoint H3;
H3[0] = H1[0] + H2[0];
H3[1] = H1[1] + H2[1];
H3[2] = H1[2] + H2[2];
ld Z = 2;
if(!euclid) {
Z = intval(H3, Hypc);
Z = sqrt(-Z);
}
for(int c=0; c<3; c++) H3[c] /= Z;
return H3;
}
// matrices
//==========
// matrices represent isometries of the hyperbolic plane
// (just like isometries of the sphere are represented by rotation matrices)
struct transmatrix {
ld tab[3][3];
ld * operator [] (int i) { return tab[i]; }
const ld * operator [] (int i) const { return tab[i]; }
};
// identity matrix
transmatrix Id = {{{1,0,0}, {0,1,0}, {0,0,1}}};
hyperpoint operator * (const transmatrix& T, const hyperpoint& H) {
hyperpoint z;
for(int i=0; i<3; i++) {
z[i] = 0;
for(int j=0; j<3; j++) z[i] += T[i][j] * H[j];
}
return z;
}
transmatrix operator * (const transmatrix& T, const transmatrix& U) {
transmatrix R;
for(int i=0; i<3; i++) for(int j=0; j<3; j++) R[i][j] = 0;
for(int i=0; i<3; i++) for(int j=0; j<3; j++) for(int k=0; k<3; k++)
R[i][j] += T[i][k] * U[k][j];
return R;
}
// rotate by alpha degrees
transmatrix spin(ld alpha) {
transmatrix T = Id;
T[0][0] = +cos(alpha); T[0][1] = +sin(alpha);
T[1][0] = -sin(alpha); T[1][1] = +cos(alpha);
T[2][2] = 1;
return T;
}
transmatrix eupush(ld x, ld y) {
transmatrix T = Id;
T[0][2] = x;
T[1][2] = y;
return T;
}
// push alpha units to the right
transmatrix xpush(ld alpha) {
if(euclid) return eupush(alpha, 0);
transmatrix T = Id;
T[0][0] = +cosh(alpha); T[0][2] = +sinh(alpha);
T[2][0] = +sinh(alpha); T[2][2] = +cosh(alpha);
return T;
}
// push alpha units vertically
transmatrix ypush(ld alpha) {
if(euclid) return eupush(0, alpha);
transmatrix T = Id;
T[1][1] = +cosh(alpha); T[1][2] = +sinh(alpha);
T[2][1] = +sinh(alpha); T[2][2] = +cosh(alpha);
return T;
}
// rotate the hyperplane around C0 such that H[1] == 0 and H[0] >= 0
transmatrix spintox(hyperpoint H) {
transmatrix T = Id;
ld R = sqrt(H[0] * H[0] + H[1] * H[1]);
if(R >= 1e-12) {
T[0][0] = +H[0]/R; T[0][1] = +H[1]/R;
T[1][0] = -H[1]/R; T[1][1] = +H[0]/R;
}
return T;
}
// reverse of spintox(H)
transmatrix rspintox(hyperpoint H) {
transmatrix T = Id;
ld R = sqrt(H[0] * H[0] + H[1] * H[1]);
if(R >= 1e-12) {
T[0][0] = +H[0]/R; T[0][1] = -H[1]/R;
T[1][0] = +H[1]/R; T[1][1] = +H[0]/R;
}
return T;
}
// for H such that H[1] == 0, this matrix pushes H to C0
transmatrix pushxto0(hyperpoint H) {
if(euclid) return eupush(-H[0], -H[1]);
transmatrix T = Id;
T[0][0] = +H[2]; T[0][2] = -H[0];
T[2][0] = -H[0]; T[2][2] = +H[2];
return T;
}
// reverse of pushxto0(H)
transmatrix rpushxto0(hyperpoint H) {
if(euclid) return eupush(H[0], H[1]);
transmatrix T = Id;
T[0][0] = +H[2]; T[0][2] = +H[0];
T[2][0] = +H[0]; T[2][2] = +H[2];
return T;
}
// generalization: H[1] can be non-zero
transmatrix gpushxto0(hyperpoint H) {
hyperpoint H2 = spintox(H) * H;
return rspintox(H) * pushxto0(H2) * spintox(H);
}
transmatrix rgpushxto0(hyperpoint H) {
hyperpoint H2 = spintox(H) * H;
return rspintox(H) * rpushxto0(H2) * spintox(H);
}
// fix the matrix T so that it is indeed an isometry
// (without using this, imprecision could accumulate)
void fixmatrix(transmatrix& T) {
for(int x=0; x<3; x++) for(int y=0; y<=x; y++) {
ld dp = 0;
for(int z=0; z<3; z++) dp += T[z][x] * T[z][y] * sig(z);
if(y == x) dp = 1 - sqrt(sig(x)/dp);
for(int z=0; z<3; z++) T[z][x] -= dp * T[z][y];
}
}
// show the matrix on screen
void display(const transmatrix& T) {
for(int y=0; y<3; y++) {
for(int x=0; x<3; x++) printf("%10.7f", double(T[y][x]));
printf(" -> %10.7f\n", double(squar(T[y][0]) + squar(T[y][1]) - squar(T[y][2])));
// printf("\n");
}
for(int x=0; x<3; x++) printf("%10.7f", double(squar(T[0][x]) + squar(T[1][x]) - squar(T[2][x]))); printf("\n");
for(int x=0; x<3; x++) {
int y = (x+1) % 3;
printf("%10.7f", double(T[0][x]*T[0][y] + T[1][x]*T[1][y] - T[2][x]*T[2][y]));
}
printf("\n\n");
}
transmatrix inverse(transmatrix T) {
ld det = 0;
for(int i=0; i<3; i++)
det += T[0][i] * T[1][(i+1)%3] * T[2][(i+2)%3];
for(int i=0; i<3; i++)
det -= T[0][i] * T[1][(i+2)%3] * T[2][(i+1)%3];
transmatrix T2;
if(det == 0) return T2;
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
T2[j][i] = (T[(i+1)%3][(j+1)%3] * T[(i+2)%3][(j+2)%3] - T[(i+1)%3][(j+2)%3] * T[(i+2)%3][(j+1)%3]) / det;
return T2;
}

33
hyperrogue-music.txt Normal file
View File

@ -0,0 +1,33 @@
# Crossroads [02]
[02] */hr3-crossroads.ogg
# Desert [03]
[03] */hr3-desert.ogg
# Icy Lands [04]
[04] */hr3-icyland.ogg
# Living Caves [05]
[05] */hr3-caves.ogg
# Jungle [06]
[06] */hr3-jungle.ogg
# Alchemist's Lab [07]
[07] */hr3-laboratory.ogg
# Mirror [08]
[08] */hr3-mirror.ogg
# Graveyard [09]
[09] */hr3-graveyard.ogg
# R'Lyeh [10]
[10] */hr3-rlyeh.ogg
# Hell [11]
[11] */hr3-hell.ogg
# Cheaterland [12]
[12] */hr3-icyland.ogg
# Motion [13]
[13] */hr3-motion.ogg
# Dry Forest [14]
[14] */hr3-jungle.ogg
# Game Board [15]
[15] */hr3-laboratory.ogg
# Barrier [01] (useless)
# None [00] (used when the window is out of focus)
HyperRogue soundtrack by Shawn Parrotte (http://www.shawnparrotte.com), under the Creative Commons BY-SA 3.0 license, http://creativecommons.org/licenses/by-sa/3.0/

107
hyperrogue.html Normal file
View File

@ -0,0 +1,107 @@
<html><head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>HyperRogue</title>
<link href="zeno.css" type=text/css rel=stylesheet>
</head><body>
<h1><center><font color="#0000ff">@</font> HyperRogue</center></h1>
<center><b>Current version: 5.5a (Feb 15, 2014)</b></center>
<hr>
<h2>The game</h2>
You are a lone outsider in a
<a href="http://zenorogue.blogspot.com/2012/03/hyperbolic-geometry-in-hyperbolic-rogue.html">strange, non-Euclidean world</a>.
You can move with the numpad, vi keys (hjklyubn), or mouse.
You can also skip turns by pressing ".".<br/><br/>
As a Rogue, your goal is to collect as many treasures as possible. However, collecting treasures attracts dangerous monsters
(on the other hand, killing the monsters allows more treasures to be generated).<br/><br/>
You can kill most monsters by moving into them. Similarly, if the monster was next to you at the end of your
turn, it would kill you. The game protects you from getting yourself killed accidentally by ignoring moves which
lead to instant death (similar to the check rule from Chess).
<br/><br/>
Ultimately, you will probably run into a situation where monsters surround you. That means that your adventure
is over, and you will have to teleport back to the Euclidean world to survive by pressing Escape (quit).
<br/><br/>
Collecting enough treasure also allows you to find rare magical orbs, which grant you one-time or time-limited
special abilities.
<br/><br/>
The world is a combination of thirteen types of lands. Each land type has specific style (monsters, treasure,
magical orbs, terrain features). Collecting treasures only attracts more monsters in lands of the same type,
so you can try to collect lots of treasure in several different lands!
<br/><br/>
Some of these lands are available from the beginning, others can be found only if you have proven yourself
(press ESC to know what you should do to access more lands). Ultimately, you will be able to access Hell,
and look for the fabulous <b>Orbs of Yendor</b> which are hidden there. Get at least one of them to prove that you are
a true winner! Only the best players will be able to face the challenges of Hell, but both the monsters and the
challenges associated with the Orbs of Yendor are different than in the rest of the game, so it should be worth it.
<br/><br/>
You can see tooltips by placing the mouse over stuff. You can also right click to get more information
about game objects.
<br/><br/>
[desktop only]
Press <b>v</b> to configure the game. You can also rotate the world by pressing <b>arrow keys</b>, <b>PageUp</b> and
<b>PageDn</b> (not numpad). You can center on the PC by pressing <b>Home</b>.<br/><br/>
Your scores and other stats about your games are recorded to file
<tt>hyperrogue.log</tt> (in Linux, <tt>~/.hyperrogue.log</tt>). You can save your configation to file
<tt>hyperrogue.ini</tt> (in Linux, <tt>~/.hyperrogue.ini</tt>).
<hr/>
<center><a href="http://roguetemple.com/z/hyper.php">See the website for some screenshots, and more detailed and up-to-date information!</a></center>
<hr/>
The surface the game is played on is called a hyperbolic plane. It seems there is just a very
small amount of games and other works of art which use hyperbolic geometry (the most well
known are some works of M.C.Escher).<br/><br>
The game dynamically generates new parts of the world as you move. Due to nature of the
hyperbolic plane, the chances that you get back to a place where you have been before
are very low (unless you go back exactly the same way). See more information about the geometry
used <a href="http://zenorogue.blogspot.com/2012/03/hyperbolic-geometry-in-hyperbolic-rogue.html">on the blog</a>.
<br/><br/>
You can aim for the Orb of Yendor, or you can simply aim for as high score as possible.
My best so far is $175 but it should be beatable (I mean, I have won fairly only once,
and that was my end score in the winning game).
<h2>Technical information</h2>
The HyperRogue package includes a Windows executable, documentation, and C++ source which has been tested under Linux
(you need SDL, SDL_ttf, and SDL_gfx). You should be able to compile on Ubuntu (or similar) with something like this:
<br/><br/>
<tt>
sudo apt-get install gcc libsdl1.2-dev libsdl-ttf2.0-dev libsdl-gfx1.2-dev<br/>
unzip hyperrogue-55.zip<br/>
cd hyperrogue-55<br/>
make
</tt>
<br/><br/>
It should also compile under MacOS with something like <tt>make -f Makefile.mac</tt> (note: I have no
access to a MacOS machine to test this makefile myself, it is based on
<a href="http://groups.google.com/group/rec.games.roguelike.development/browse_thread/thread/9c02e09c0195dc16/3cbde3dc4a0b7e4e">
this post</a> by Konstantin Stupnik).
<br/><br/>
Released under
<a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License, version 2</a>.
As such, it comes with without any warranty.
<br/><br/>
<hr>
If you would like to thank me for HyperRogue,
<a href="http://www.roguetemple.com/z/donate.php?id=NotEye">donations</a> are welcome.
<hr>
You can contact me at zeno@attnam.com, or at
<a href="http://www.roguetemple.com/forums/">RogueTemple</a>
or New Attnam forums (Z), or
at <a href="http://zenorogue.blogspot.com/">my blog</a>.
<br/>
<hr>
<center><a href="http://www.roguetemple.com/z/index.php">See my other games and stuff</a></center> <br>
</body></html>

249
hypersteam.cpp Normal file
View File

@ -0,0 +1,249 @@
// PRIVATE
#define HAVE_ACHIEVEMENTS
#define LEADERFULL "Steam Leaderboards"
#define LEADER "Steam"
#ifdef STEAMWIN
#include "sdk-w/public/steam/steam_api.h"
#else
#include "sdk/public/steam/steam_api.h"
#endif
#include "steamvisualinterface.h"
#define NOLICENSE
unsigned steam_appid;
SteamLeaderboard_t steamleader[NUMLEADER];
int lastleader;
void findLeaderboards() {
lastleader = ticks;
for(int i=0; i<NUMLEADER; i++) if(!steamleader[i]) if(leadernames[i][0] != '@') {
// printf("Looking for Leaderboard '%s'\n", leadernames[i]);
currentscore[i] = SCORE_UNKNOWN;
SteamAPICall_t hSteamAPICall =
SteamUserStats()->FindLeaderboard(leadernames[i]);
if(!hSteamAPICall) {
printf("Failed to look for leaderboard named '%s'\n", leadernames[i]);
}
else {
register_callback(hSteamAPICall);
return;
}
}
for(int i=0; i<NUMLEADER; i++) if(steamleader[i] && currentscore[i] == SCORE_UNKNOWN) {
SteamAPICall_t hSteamAPICall = SteamUserStats()->DownloadLeaderboardEntries(
steamleader[i], k_ELeaderboardDataRequestGlobalAroundUser, 0, 0);
register_callback_download(hSteamAPICall);
}
}
CSteamID whoami;
void OnUserStatsReceived( UserStatsReceived_t *pCallback ) {
if(steam_appid != pCallback->m_nGameID)
return;
if(pCallback->m_eResult == k_EResultOK) {
printf("Received stats and achievements from Steam\n" );
whoami = pCallback->m_steamIDUser;
/* string s = SteamUserStats()->GetAchievementDisplayAttribute("DIAMOND1", "name");
printf("Achievement name: '%s'\n", s.c_str());
if(s == "Ice Explorer") {
printf("Steam language is English\n");
default_language = 0;
}
else if(s == "Eksplorator") {
printf("Steam language is Polish\n");
default_language = 1;
}
else if(s == "Buz Kâşifi") {
printf("Steam language is Turkish\n");
default_language = 2;
}
else if(s == "Průzkumník Ledu") {
printf("Steam language is Czech\n");
default_language = 3;
} */
string l = SteamApps()->GetCurrentGameLanguage();
printf("Steam language: %s\n", l.c_str());
if(l == "english") default_language = 0;
if(l == "polish") default_language = 1;
if(l == "turkish") default_language = 2;
if(l == "czech") default_language = 3;
if(l == "russian") default_language = 4;
// SteamUserStats()->ClearAchievement("DIAMOND1");
}
else {
printf("RequestStats - failed, %d\n", pCallback->m_eResult);
}
}
void OnFindLeaderboard( LeaderboardFindResult_t *pFindLeaderboardResult, bool bIOFailure ) {
if ( !pFindLeaderboardResult->m_bLeaderboardFound || bIOFailure ) {
printf("Leaderboard not found!\n");
return;
}
// check to see which leaderboard handle we just retrieved
const char *pchName = SteamUserStats()->GetLeaderboardName( pFindLeaderboardResult->m_hSteamLeaderboard );
printf("Found leaderboard: '%s'\n", pchName);
for(int i=0; i<NUMLEADER; i++) if(strcmp( pchName, leadernames[i] ) == 0 )
steamleader[i] = pFindLeaderboardResult->m_hSteamLeaderboard;
findLeaderboards();
}
void OnScoresDownloaded( LeaderboardScoresDownloaded_t *p, bool bIOFailure ) {
if ( bIOFailure ) {
printf("OnScoresDownloaded failure!\n");
return;
}
printf("Download count: %d\n", p->m_cEntryCount);
if(p->m_cEntryCount) {
LeaderboardEntry_t entry;
SteamUserStats()->GetDownloadedLeaderboardEntry(
p->m_hSteamLeaderboardEntries,0,&entry,NULL,0
);
if(entry.m_steamIDUser == whoami) for(int i=0; i<NUMLEADER; i++)
if(p->m_hSteamLeaderboard == steamleader[i]) {
printf("Retrieved the current score for '%s': %d\n", leadernames[i], entry.m_nScore);
currentscore[i] = entry.m_nScore;
}
}
else {
for(int i=0; i<NUMLEADER; i++)
if(p->m_hSteamLeaderboard == steamleader[i])
currentscore[i] = NO_SCORE_YET;
}
findLeaderboards();
}
void achievement_init() {
if(SteamAPI_RestartAppIfNecessary(342610))
exit(0);
if(SteamAPI_Init()) {
steam_appid = SteamUtils()->GetAppID();
for(int i=0; i<NUMLEADER; i++)
steamleader[i] = 0;
if(!SteamUserStats()->RequestCurrentStats()) {
printf("Request failed\n");
}
init_steamvisualinterface(OnUserStatsReceived, OnFindLeaderboard, OnScoresDownloaded);
findLeaderboards();
}
else {
printf("Steam init failed\n");
return;
}
}
void achievement_gain(const char *name, bool euclideanAchievement) {
achievement_log(name, euclideanAchievement);
if(!steam_appid) return;
if(cheater) return;
if(euclid != euclideanAchievement) return;
bool achieved;
SteamUserStats()->GetAchievement(name, &achieved);
SteamUserStats()->SetAchievement(name);
SteamUserStats()->StoreStats();
if(!achieved) {
// printf("NEW ACHIEVEMENT\n");
achievementTimer = ticks;
achievementMessage[0] = XLAT("New Achievement:");
achievementMessage[1] = SteamUserStats()->GetAchievementDisplayAttribute(name, "name");
achievementMessage[2] = SteamUserStats()->GetAchievementDisplayAttribute(name, "desc");
}
/*
for(int i=0; i<int(sizeof(achievements)/sizeof(char*)); i++)
if(name == achievements[i]) {
return;
}
printf("Unknown achievement '%s'\n", name); */
}
unsigned char i8(int v) {
if(v < 0) return 255;
int b = 0;
if(v < 160) return v;
while(v > 160) {
b++; v -= (v/3);
}
return 160+b;
}
typedef unsigned char uchar;
uchar ugc[640], qugc;
void ugc_init() {
for(int x=0; x<640; x++) ugc[x] = 0;
qugc = 0;
}
void ugc_char(uchar& x) {
ugc[qugc++] = x;
}
void ugc_compress(int& x) {
ugc[qugc++] = i8(x);
}
template<class T> void ugc_nocompress(T& x) {
uchar *z = (uchar*) &x;
for(int i=0; i<(int) sizeof(T); i++) ugc_char(z[i]);
}
void upload_score(int id, int v) {
if(!steam_appid) return;
if(!steamleader[id]) return;
ugc_init();
short vs; int vi;
vs = VERNUM_HEX; ugc_nocompress(vs);
vi = timerstart; ugc_nocompress(vi);
vi = countMyGolems(); ugc_compress(vi);
ugc_compress(turncount);
ugc_compress(cellcount);
ugc_compress(savecount);
uchar l = lastland; if(tampered) l |= 64; ugc_char(l);
vi = celldist(cwt.c); ugc_compress(vi);
vi = savetime + (timerstopped ? 0 : (time(NULL) - timerstart)); ugc_compress(vi);
for(int i=0; i<40; i++) ugc_compress(items[i]);
for(int i=0; i<67; i++) ugc_compress(kills[i]);
ugc_compress(explore[0]); ugc_compress(explore[5]);
for(int i=0; i<23; i++) ugc_compress(exploreland[0][i]);
SteamUserStats()->UploadLeaderboardScore( steamleader[id], k_ELeaderboardUploadScoreMethodKeepBest, v, (int32*)&ugc, (qugc+3) / sizeof(int32));
}
bool haveLeaderboard(int id) {
return steamleader[id];
}
void achievement_close() {
if(!steam_appid) return;
SteamAPI_Shutdown();
}
void achievement_pump() {
SteamAPI_RunCallbacks();
if(ticks > lastleader + 30000)
findLeaderboards();
}

277
langen.cpp Normal file
View File

@ -0,0 +1,277 @@
#define GEN_M 0
#define GEN_F 1
#define GEN_N 2
#define GEN_O 3
using namespace std;
#include <map>
#include <string>
#include <stdio.h>
#include <vector>
#include <stdlib.h>
template<class T> int size(T x) { return x.size(); }
#define NUMLAN 5
// language generator
template<class T> struct dictionary {
map<string, T> m;
void add(const string& s, const T& val) { m[s] = val; }
T& operator [] (const string& s) { return m[s]; }
int count(const string& s) { return m.count(s); }
void clear() { m.clear(); }
};
dictionary<string> d[NUMLAN];
struct noun {
int genus;
string nom, nomp, acc, abl;
};
dictionary<noun> nouns[NUMLAN];
#include <set>
void addutftoset(set<string>& s, string& w) {
int i = 0;
//printf("%s\n", w.c_str());
while(i < size(w)) {
if(w[i] < 0) {
string z = w.substr(i, 2);
// printf("Insert: %s [%02x%02x]\n", z.c_str(), w[i], w[i+1]);
s.insert(w.substr(i, 2));
i += 2;
}
else {
s.insert(w.substr(i, 1));
i++;
}
}
}
void addutftoset(set<string>& s, noun& w) {
addutftoset(s, w.nom);
addutftoset(s, w.nomp);
addutftoset(s, w.acc);
addutftoset(s, w.abl);
}
template<class T>
void addutftoset(set<string>& s, dictionary<T>& w) {
for(typename map<string,T>::iterator it = w.m.begin(); it != w.m.end(); it++)
addutftoset(s, it->second);
}
set<string> allchars;
void printletters(dictionary<string>& la, dictionary<noun>& nounla, const char *lang) {
set<string> s;
addutftoset(s, la);
addutftoset(s, nounla);
addutftoset(allchars, la);
addutftoset(allchars, nounla);
//printf("%s:", lang);
//for(set<string>::iterator it = s.begin(); it != s.end(); it++)
// printf(" \"%s\",", it->c_str());
//printf("\n");
}
typedef unsigned hashcode;
hashcode hashval;
hashcode hash(const string& s) {
hashcode r = 0;
for(int i=0; i<size(s); i++) r = hashval * r + s[i];
return r;
}
map<hashcode, string> buildHashTable(set<string>& s) {
map<hashcode, string> res;
for(set<string>::iterator it = s.begin(); it != s.end(); it++)
res[hash(*it)] = *it;
return res;
}
const char *escape(string s, string dft) {
if(s == "") {
printf("/*MISSING*/ ");
s = dft;
}
static string t;
t = "\"";
for(int i=0; i<size(s); i++)
if(s[i] == '\\') t += "\\\\";
else if(s[i] == '\n') t += "\\n";
else if(s[i] == '\"') t += "\\\"";
else t += s[i];
t += "\"";
return t.c_str();
}
set<string> nothe;
set<string> plural;
#ifdef CHECKALL
const char* allstr[] = {
#include "d"
};
#endif
int main() {
nothe.insert("R'Lyeh");
plural.insert("Crossroads");
#define S(a,b) d[1].add(a,b);
#define N(a,b,c,d,e,f) \
{noun n; n.genus = b; n.nom = c; n.nomp = d; n.acc = e; n.abl = f; nouns[1].add(a,n);}
#include "language-pl.cpp"
#undef N
#undef S
#define S(a,b) d[2].add(a,b);
#define N5(a,b,c,d,e) \
{noun n; n.genus = b; n.nom = c; n.nomp = d; n.acc = e; n.abl = e; nouns[2].add(a,n);}
#define N(a,b,c,d,e,f) \
{noun n; n.genus = b; n.nom = c; n.nomp = d; n.acc = e; n.abl = f; nouns[2].add(a,n);}
#include "language-tr.cpp"
#undef N
#undef S
#define S(a,b) d[3].add(a,b);
#define N(a,b,c,d,e,f) \
{noun n; n.genus = b; n.nom = c; n.nomp = d; n.acc = e; n.abl = f; nouns[3].add(a,n);}
#include "language-cz.cpp"
#undef N
#undef S
#define S(a,b) d[4].add(a,b);
#define N(a,b,c,d,e,f) \
{noun n; n.genus = b; n.nom = c; n.nomp = d; n.acc = e; n.abl = f; nouns[4].add(a,n);}
#include "language-ru.cpp"
#undef N
#undef S
// verify
set<string> s;
for(int i=1; i<NUMLAN; i++)
for(map<string,string>::iterator it = d[i].m.begin(); it != d[i].m.end(); it++)
s.insert(it->first);
for(set<string>::iterator x=s.begin(); x != s.end(); x++) {
string mis = "";
for(int i=1; i<NUMLAN; i++) if(d[i].count(*x) == 0)
mis += d[i]["EN"];
if(mis != "")
printf("#warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?"));
}
s.clear();
for(int i=1; i<NUMLAN; i++)
for(map<string,noun>::iterator it = nouns[i].m.begin(); it != nouns[i].m.end(); it++)
s.insert(it->first);
for(set<string>::iterator x=s.begin(); x != s.end(); x++) {
string mis = "";
for(int i=1; i<NUMLAN; i++) if(nouns[i].count(*x) == 0)
mis += d[i]["EN"];
if(mis != "")
printf("#warning Missing [%s]: %s\n", mis.c_str(), escape(*x, "?"));
}
#ifdef CHECKALL
for(int i=1; i<NUMLAN; i++)
for(map<string,string>::iterator it = d[i].m.begin(); it != d[i].m.end(); it++)
s.insert(it->first);
int ca = sizeof(allstr) / sizeof(char*);
for(int i=0; i<ca; i++) if(!s.count(allstr[i])) {
printf("#warning GO %s\n", escape(allstr[i], "?"));
}
for(set<string>::iterator x=s.begin(); x != s.end(); x++) {
bool b = false;
for(int i=0; i<ca; i++) if(allstr[i] == *x) b = true;
if(!b) printf("#warning TO %s\n", escape(*x, "?"));
}
#endif
for(int i=1; i<NUMLAN; i++) {
printletters(d[i], nouns[i], "SOMETHING");
}
int c =0;
string javastring;
vector<string> vchars;
//printf("ALL:");
for(set<string>::iterator it = allchars.begin(); it != allchars.end(); it++) {
// printf(" \"%s\",", it->c_str());
if(size(*it) == 2) { javastring += (*it); vchars.push_back(*it); c++; }
}
printf("// DO NOT EDIT -- this file is generated automatically with langen\n");
printf("\n");
printf("#define NUMEXTRA %d\n", c);
printf("const char* natchars[NUMEXTRA] = {");
for(int i=0; i<c; i++) printf("\"%s\",", vchars[i].c_str());
printf("};\n");
printf("//javastring = \"%s\";\n", javastring.c_str());
set<string> allsent;
for(map<string, string>::iterator it = d[1].m.begin(); it != d[1].m.end(); it++)
allsent.insert(it->first);
set<string> allnouns;
for(map<string, noun>::iterator it = nouns[1].m.begin(); it != nouns[1].m.end(); it++)
allnouns.insert(it->first);
map<hashcode, string> ms, mn;
do {
hashval = rand();
printf("// check hash: %x\n", hashval);
ms = buildHashTable(allsent);
mn = buildHashTable(allnouns);
}
while(size(ms) != size(allsent) || size(mn) != size(allnouns));
printf("hashcode hashval = 0x%x;\n\n", hashval);
printf("sentence all_sentences[%d] = {\n", size(allsent));
for(map<hashcode,string>::iterator it = ms.begin(); it != ms.end(); it++) {
string s = it->second;
printf(" {0x%x, { // %s\n", it->first, escape(s, s));
for(int i=1; i<NUMLAN; i++) printf(" %s,\n", escape(d[i][s], s));
printf(" }},\n");
}
printf(" };\n\n");
printf("fullnoun all_nouns[%d] = {\n", size(allnouns));
for(map<hashcode,string>::iterator it = mn.begin(); it != mn.end(); it++) {
string s = it->second;
printf(" {0x%x, %d, { // \"%s\"\n", it->first,
(nothe.count(s) ? 1:0) + (plural.count(s) ? 2:0),
escape(s, s));
for(int i=1; i<NUMLAN; i++) {
printf(" {%d", nouns[i][s].genus);
printf(", %s", escape(nouns[i][s].nom, s));
printf(", %s", escape(nouns[i][s].nomp, s));
printf(", %s", escape(nouns[i][s].acc, s));
printf(", %s},\n", escape(nouns[i][s].abl, s));
}
printf(" }},\n");
}
printf(" };\n");
}

1518
language-cz.cpp Normal file

File diff suppressed because it is too large Load Diff

1480
language-de.cpp Normal file

File diff suppressed because it is too large Load Diff

1480
language-pl.cpp Normal file

File diff suppressed because it is too large Load Diff

1460
language-ru.cpp Normal file

File diff suppressed because it is too large Load Diff

1366
language-tr.cpp Normal file

File diff suppressed because it is too large Load Diff

249
language.cpp Normal file
View File

@ -0,0 +1,249 @@
// #define CHECKTRANS
#define NUMLAN 5
#define GEN_M 0
#define GEN_F 1
#define GEN_N 2
#define GEN_O 3
struct stringpar {
string v;
stringpar(string s) : v(s) { }
stringpar(const char* s) : v(s) { }
stringpar(eMonster m) { v= minf[m].name; }
stringpar(eLand l) { v= linf[l].name; }
stringpar(eWall w) { v= winf[w].name; }
stringpar(eItem i) { v= iinf[i].name; }
};
void rep(string& pattern, string what, string to) {
size_t at = pattern.find(what);
if(at != string::npos)
pattern = pattern.replace(at, what.size(), to);
}
typedef unsigned hashcode;
// a quick hack to make this unambiguous on Android
#define hash my_hash
struct sentence {
hashcode hash;
const char* xlat[NUMLAN-1];
};
struct noun {
int genus;
const char *nom, *nomp, *acc, *abl;
};
struct fullnoun {
hashcode hash;
int english_grammar_flags;
noun n[NUMLAN-1];
};
#include "language-data.cpp"
hashcode hash(const string& s) {
hashcode r = 0;
for(int i=0; i<size(s); i++) r = hashval * r + s[i];
return r;
}
template<class T> const T* findInHashTableS(string s, const T *table, int size) {
int b = 0, e = size;
hashcode h = hash(s);
while(b!=e) {
int m = (b+e)>>1;
// printf("b=%d e=%d m=%d h=%x s=%x\n", b, e, m, table[m].hash, h);
if(table[m].hash >= h) e = m;
else b = m+1;
}
if(e != size && table[e].hash == h)
return &table[e];
return NULL;
}
#define findInHashTable(s,t) findInHashTableS(s, t, sizeof(t) / sizeof(t[0]))
string choose3(int g, string a, string b, string c) {
if(g == GEN_M || g == GEN_O) return a;
if(g == GEN_F) return b;
if(g == GEN_N) return c;
return "unknown genus";
}
string choose4(int g, string a, string b, string c, string d) {
if(g == GEN_M) return a;
if(g == GEN_F) return b;
if(g == GEN_N) return c;
if(g == GEN_O) return d;
return "unknown genus";
}
int playergender();
int lang();
void basicrep(string& x) {
const sentence *s = findInHashTable(x, all_sentences);
if(!s) {
printf("WARNING: no translations for '%s'\n", x.c_str());
}
int l = lang();
if(l) {
const sentence *s = findInHashTable(x, all_sentences);
if(s) x = s->xlat[l-1];
}
if(l == 1) {
rep(x, "%łeś0", choose3(playergender(), "łeś", "łaś", "łoś"));
rep(x, "%ąłeś0", choose3(playergender(), "ąłeś", "ęłaś", "ęłoś"));
rep(x, "%ógł0", choose3(playergender(), "ógł", "ogła", "ogło"));
}
if(l == 3) {
rep(x, "%l0", choose3(playergender(), "l", "la", "lo"));
rep(x, "%d0", choose3(playergender(), "", "a", "o"));
}
}
void parrep(string& x, string w, stringpar p) {
int l = lang();
const fullnoun *N = findInHashTable(p.v, all_nouns);
if(l == 0) {
// proper names (R'Lyeh)
if(N && (N->english_grammar_flags & 1)) {
rep(x,"%"+w,p.v);
rep(x,"%the"+w, p.v);
rep(x,"%The"+w, p.v);
}
else {
rep(x,"%"+w,p.v);
rep(x,"%the"+w, "the " + p.v);
rep(x,"%The"+w, "The " + p.v);
}
// plural names (Crossroads)
if(N && (N->english_grammar_flags & 2))
rep(x,"%s"+w, "");
else
rep(x,"%s"+w, "s");
return;
}
if(l == 1) {
if(N) {
rep(x, "%"+w, N->n[0].nom);
rep(x, "%P"+w, N->n[0].nomp);
rep(x, "%a"+w, N->n[0].acc);
rep(x, "%abl"+w, N->n[0].abl);
rep(x, ""+w, choose3(N->n[0].genus, "ł", "ła", "ło"));
rep(x, "%ął"+w, choose3(N->n[0].genus, "ął", "ęła", "ęło"));
rep(x, "%ya"+w, choose3(N->n[0].genus, "y", "a", "e"));
rep(x, "%yą"+w, choose4(N->n[0].genus, "ego", "ą", "e", "y"));
rep(x, "%oa"+w, choose3(N->n[0].genus, "", "a", "o"));
rep(x, "%ymą"+w, choose3(N->n[0].genus, "ym", "ą", "ym"));
}
else {
rep(x,"%"+w, p.v);
rep(x, "%P"+w, p.v);
rep(x, "%a"+w, p.v);
rep(x, "%abl"+w, p.v);
rep(x, ""+w, choose3(0, "ł", "ła", "ło"));
}
}
if(lang() == 2) {
if(N) {
rep(x, "%"+w, N->n[1].nom);
rep(x, "%P"+w, N->n[1].nomp);
rep(x, "%a"+w, N->n[1].acc);
rep(x, "%abl"+w, N->n[1].abl);
}
else {
rep(x,"%"+w,p.v);
rep(x, "%P"+w, p.v);
rep(x, "%a"+w, p.v);
rep(x, "%abl"+w, p.v);
}
}
if(lang() == 3) {
if(N) {
rep(x, "%"+w, N->n[2].nom);
rep(x, "%P"+w, N->n[2].nomp);
rep(x, "%a"+w, N->n[2].acc);
rep(x, "%abl"+w, N->n[2].abl);
rep(x, ""+w, choose3(N->n[2].genus, "ý", "á", "é"));
rep(x, "%l"+w, choose3(N->n[2].genus, "l", "la", "lo"));
rep(x, "%el"+w, choose3(N->n[2].genus, "el", "la", "lo"));
rep(x, "%ůj"+w, choose4(N->n[2].genus, "ého", "ou", "é", "ůj"));
rep(x, "%ým"+w, choose3(N->n[2].genus, "ým", "ou", "ým"));
if(p.v == "Mirror Image")
rep(x, "%s"+w, "se");
if(p.v == "Mirage")
rep(x, "%s"+w, "s");
}
else {
rep(x,"%"+w,p.v);
rep(x, "%P"+w, p.v);
rep(x, "%a"+w, p.v);
rep(x, "%abl"+w, p.v);
}
}
if(lang() == 4) {
if(N) {
rep(x, "%"+w, N->n[3].nom);
rep(x, "%P"+w, N->n[3].nomp);
rep(x, "%a"+w, N->n[3].acc);
rep(x, "%abl"+w, N->n[3].abl);
rep(x, "%E"+w, choose3(N->n[3].genus, "", "а", "о"));
rep(x, "%A"+w, choose3(N->n[3].genus, "ый", "ая", "ое"));
}
else {
rep(x,"%"+w,p.v);
rep(x, "%P"+w, p.v);
rep(x, "%a"+w, p.v);
rep(x, "%abl"+w, p.v);
}
}
}
void postrep(string& s) {
}
string XLAT(string x) {
basicrep(x);
postrep(x);
return x;
}
string XLAT(string x, stringpar p1) {
basicrep(x);
parrep(x,"1",p1.v);
postrep(x);
return x;
}
string XLAT(string x, stringpar p1, stringpar p2) {
basicrep(x);
parrep(x,"1",p1.v);
parrep(x,"2",p2.v);
postrep(x);
return x;
}
string XLATN(string x) {
if(lang()) {
const fullnoun *N = findInHashTable(x, all_nouns);
if(N) return N->n[lang()-1].nomp;
}
return x;
}
string XLAT1(string x) {
if(lang()) {
const fullnoun *N = findInHashTable(x, all_nouns);
if(N) return N->n[lang()-1].nom;
}
return x;
}

BIN
libogg-0.dll Normal file

Binary file not shown.

BIN
libvorbis-0.dll Normal file

Binary file not shown.

BIN
libvorbisfile-3.dll Normal file

Binary file not shown.

3854
polygons.cpp Normal file

File diff suppressed because it is too large Load Diff

54
steamvisualinterface.cpp Normal file
View File

@ -0,0 +1,54 @@
// PRIVATE
#include "sdk/public/steam/steam_api.h"
#include "steamvisualinterface.h"
class SteamContact {
public:
STEAM_CALLBACK( SteamContact, OnUserStatsReceived, UserStatsReceived_t, m_CallbackStatsReceived );
SteamContact ();
void OnFindLeaderboard( LeaderboardFindResult_t *pFindLearderboardResult, bool bIOFailure );
void OnDownloadScores( LeaderboardScoresDownloaded_t *pLeaderboardScoresDownloaded, bool bIOFailure );
CCallResult<SteamContact, LeaderboardFindResult_t> m_SteamCallResultCreateLeaderboard;
CCallResult<SteamContact, LeaderboardScoresDownloaded_t> m_SteamCallResultScoresDownloaded;
};
SteamContact :: SteamContact()
: m_CallbackStatsReceived(this, &SteamContact::OnUserStatsReceived)
{ }
static SteamContact *steam;
callback_statsreceived sr;
callback_findleaderboard fl;
callback_scoresdownload sdl;
void init_steamvisualinterface(callback_statsreceived _sr, callback_findleaderboard _fl, callback_scoresdownload _sdl) {
sr = _sr;
fl = _fl;
sdl = _sdl;
steam = new SteamContact;
}
void register_callback(SteamAPICall_t handle) {
steam->m_SteamCallResultCreateLeaderboard.Set( handle, steam, &SteamContact::OnFindLeaderboard );
}
void register_callback_download(SteamAPICall_t handle) {
steam->m_SteamCallResultScoresDownloaded.Set( handle, steam, &SteamContact::OnDownloadScores );
}
void SteamContact::OnFindLeaderboard( LeaderboardFindResult_t *pFindLeaderboardResult, bool bIOFailure ) {
fl(pFindLeaderboardResult, bIOFailure);
}
void SteamContact::OnDownloadScores( LeaderboardScoresDownloaded_t *pLeaderboardScoresDownloaded, bool bIOFailure ) {
sdl(pLeaderboardScoresDownloaded, bIOFailure);
}
void SteamContact::OnUserStatsReceived( UserStatsReceived_t *pCallback ) {
sr(pCallback);
}

26
zeno.css Normal file
View File

@ -0,0 +1,26 @@
BODY {
background: #000000; color: #C0C0C0
}
A {
font-weight: bold; color: #FFFF00; text-decoration: none
}
A:hover {
font-weight: bold; color: #FF0000; text-decoration: underline
}
h1 {
color: #FF0000
}
h2 {
color: #FF8000
}
.pic {
vertical-align: top; width: 100; text-align: center
}
img {
border-style:outset; border-color: white; border-width:2px;
}
.noborder {
border-width:0px;
}
td {
padding-top:8px;