From 3237ff455ef0eb196b18134b5159fee7f4f48ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eryk=20Kopczy=C5=84ski?= Date: Fri, 26 Aug 2016 11:58:03 +0200 Subject: [PATCH] Updated to 8.3j --- Makefile.mgw | 7 +- achievement.cpp | 998 +-- achievement.h | 30 - cell.cpp | 388 +- classes.cpp | 504 +- complex.cpp | 2102 +++++++ configure.ac | 4 +- conformal.cpp | 660 ++ fjordgen.cpp | 814 +-- flags.cpp | 555 ++ game.cpp | 9268 +++++++-------------------- geometry.cpp | 28 +- graph.cpp | 2960 +++++---- heptagon.cpp | 19 +- hyper.cpp | 149 +- hyper.h | 932 ++- hyper.rc | 8 +- hyperpoint.cpp | 95 +- hyperrogue-music.txt | 96 +- landgen.cpp | 4427 +++++++++++++ langen.cpp | 651 +- language-cz.cpp | 1074 +++- language-data.cpp | 10242 ++++++++++++++++++++++++++++++ language-de.cpp | 4842 ++++++++------ language-pl.cpp | 1060 +++- language-ru.cpp | 1166 +++- language-tr.cpp | 5600 +++++++++-------- language.cpp | 613 +- mapeditor.cpp | 3325 +++++----- menus.cpp | 796 +++ mtrand.cpp | 104 +- mtrand.h | 316 +- netgen.cpp | 702 +++ orbs.cpp | 949 +++ patterngen.cpp | 914 +-- patterns.cpp | 2110 +++---- polygons.cpp | 13978 ++++++++++++++++++++++++++--------------- rug.cpp | 697 ++ savepng.h | 45 + shmup.cpp | 4285 +++++++------ system.cpp | 1104 ++++ tools.cpp | 15 + yendor.cpp | 699 +++ 43 files changed, 54438 insertions(+), 24893 deletions(-) create mode 100644 complex.cpp create mode 100644 conformal.cpp create mode 100644 flags.cpp create mode 100644 landgen.cpp create mode 100644 language-data.cpp create mode 100644 menus.cpp create mode 100644 netgen.cpp create mode 100644 orbs.cpp create mode 100644 rug.cpp create mode 100644 savepng.h create mode 100644 system.cpp create mode 100644 tools.cpp create mode 100644 yendor.cpp diff --git a/Makefile.mgw b/Makefile.mgw index aa76f970..1369e617 100644 --- a/Makefile.mgw +++ b/Makefile.mgw @@ -1,5 +1,10 @@ +all: hyper.exe + +# for simplicity we use NOPNG here +# you can also include savepng.c and remove -DNOPNG + 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 + g++ -mwindows hyper.cpp hyper.res -o hyper.exe -lSDL -lSDL_mixer -lopengl32 SDL_ttf.dll SDL_gfx.dll -O3 -DNOPNG hyper.res: hyper.rc hr-icon.ico windres hyper.rc -O coff -o hyper.res diff --git a/achievement.cpp b/achievement.cpp index 22185b09..3d208d74 100644 --- a/achievement.cpp +++ b/achievement.cpp @@ -1,424 +1,574 @@ -#define NUMLEADER 40 - -#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-71", "Turns to Win-71", - "Time to 10 Hyperstones-73", "Turns to 10 Hyperstones-73", "Orbs of Yendor", - "Fern Flowers", - "Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires", - "Holy Grails", "Red Gems", "Pirate Treasures", - "Shmup Score", "Shmup Time to Win", "Shmup Knife to Win", - "Bomberbird Eggs", // 31 - "Ambers", // 32 - "Pearls", // 33 - "Hypersian Rugs", // 34 - "Garnets", // 35 - "Princess Challenge", // 36 - "Ivory Figurines", // 37 - "Elemental Gems", // 38 - "Onyxes" // 39 - }; - -bool haveLeaderboard(int id); - -void upload_score(int id, int v); - -string achievementMessage[3]; -int achievementTimer; -// vector achievementsReceived; - -void achievement_log(const char* s, bool euclideanAchievement, bool shmupAchievement) { - if(cheater) return; - if(euclid != euclideanAchievement) return; - if(shmup::on != shmupAchievement) return; - if(randomPatternsMode) return; - - for(int i=0; i= 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(haveLeaderboard(i)) updateHi(what, currentscore[i]); - 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_score(int cat, int number) { -#ifdef HAVE_ACHIEVEMENTS - if(cheater) return; - if(euclid) return; - if(randomPatternsMode) return; - upload_score(cat, number); -#endif - } - -void improveItemScores() { - 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); - improve_score(26, itRedGem); - improve_score(27, itPirate); - improve_score(31, itBombEgg); - improve_score(32, itCoast); - improve_score(33, itWhirlpool); - improve_score(34, itPalace); - improve_score(35, itFjord); - - improve_score(37, itEdge); - improve_score(38, itElemental); - improve_score(39, itZebra); - } - -void achievement_final(bool really_final) { -#ifdef HAVE_ACHIEVEMENTS - if(cheater) return; - if(euclid) return; - if(randomPatternsMode) return; - int total_improved = 0; - specific_improved = 0; - specific_what = 0; - - if(!shmup::on) improveItemScores(); - - int sid = shmup::on ? 28 : 0; - - int tg = gold(); - if(tg && haveLeaderboard(sid)) { - if(tg > currentscore[sid] && currentscore[sid] != SCORE_UNKNOWN) { - if(currentscore[sid] < 0) total_improved += 2; - total_improved++; currentscore[sid] = tg; - } - upload_score(sid, 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; - if(randomPatternsMode) return; - if(hyper && shmup::on) return; - - int t = savetime + time(NULL) - timerstart; - - int ih1 = hyper ? 15 : shmup::on ? 29 : 13; - int ih2 = hyper ? 16 : shmup::on ? 30 : 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) { - if(shmup::on) - addMessage(XLAT("You have improved both your real time and knife count. Congratulations!")); - else - 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) { - if(shmup::on) - addMessage(XLAT("You have used less knives than ever before. Congratulations!")); - else - 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 - } - +// Hyperbolic Rogue -- achievements +// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details + +#define NUMLEADER 57 + +#define SCORE_UNKNOWN (-1) +#define NO_SCORE_YET (-2) + +bool offlineMode = false; + +int syncstate = 0; + +int currentscore[NUMLEADER]; + +const char* leadernames[NUMLEADER] = { + "Score", "Diamonds", "Gold", "Spice", "Rubies", "Elixirs", + "Shards", "Totems", "Daisies", "Statues", "Feathers", "Sapphires", + "Hyperstones", "Time to Win-71", "Turns to Win-71", + "Time to 10 Hyperstones-83", "Turns to 10 Hyperstones-83", "Orbs of Yendor", + "Fern Flowers", + "Royal Jellies", "Powerstones", "Silver", "Wine", "Emeralds", "Grimoires", + "Holy Grails", "Red Gems", "Pirate Treasures", + "Shmup Score", "Shmup Time to Win", "Shmup Knife to Win", + "Bomberbird Eggs", // 31 + "Ambers", // 32 + "Pearls", // 33 + "Hypersian Rugs", // 34 + "Garnets", // 35 + "Princess Challenge", // 36 + "Ivory Figurines", // 37 + "Elemental Gems", // 38 + "Onyxes", // 39 + "Yendor Challenge", // 40 + "Pure Tactics Mode", // 41 + "Mutant Saplings", // 42 + "Fulgurites", // 43 + "Shmup Score 2p", // 44 + "Coop Shmup Time to Win", // 45 + "Black Lotuses", // 46 + "Mutant Fruits", // 47 + "White Dove Feathers", // 48 + "Pure Tactics Mode (shmup)", // 49 + "Pure Tactics Mode (2p)", // 50 + "Corals", // 51 + "Thornless Roses", // 52 + "Chaos Mode", // 53 + "Tortoise points", // 54 + "Dragon Scales", // 55 + "Apples", // 56 + }; + +bool haveLeaderboard(int id); + +void upload_score(int id, int v); + +string achievementMessage[3]; +int achievementTimer; +// vector achievementsReceived; + +bool wrongMode(char flags) { + if(cheater) return true; + if(purehepta != (flags == '7')) return true; + if(euclid != (flags == 'e')) return true; + if(shmup::on != (flags == 's')) return true; + if(randomPatternsMode) return true; + if(yendor::on) return true; + if(tactic::on) return true; + if(chaosmode != (flags == 'C')) return true; + return false; + } + +void achievement_log(const char* s, char flags) { + +#ifdef LOCAL + printf("achievement = %s [%d]\n", s, wrongMode(flags)); +#endif + + if(wrongMode(flags)) return; + + for(int i=0; i= 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", 'e'); + if(s == "ORB" && current >= 10) + achievement_gain("ORB3"); + if(s == "BUG" && current >= 1000) + achievement_gain("BUG3"); + if(s == "ELEC" && current >= 10) + achievement_gain("ELEC3"); + } + +int specific_improved = 0; +int specific_what = 0; + +void improve_score(int i, eItem what) { + if(offlineMode) return; +#ifdef HAVE_ACHIEVEMENTS + if(haveLeaderboard(i)) updateHi(what, currentscore[i]); + if(items[what] && haveLeaderboard(i)) { + if(items[what] > currentscore[i] && currentscore[i] != SCORE_UNKNOWN) { + specific_improved++; specific_what = what; + } + upload_score(i, items[what]); + } +#endif + } + +void achievement_score(int cat, int number) { + if(offlineMode) return; +#ifdef HAVE_ACHIEVEMENTS + if(cheater) return; + if(euclid) return; + if(purehepta) return; + if(randomPatternsMode) return; + if(shmup::on && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) return; + if(yendor::on && cat != LB_YENDOR_CHALLENGE) return; + if(tactic::on && cat != LB_PURE_TACTICS && cat != LB_PURE_TACTICS_SHMUP && cat != LB_PURE_TACTICS_COOP) + return; + upload_score(cat, number); +#endif + } + +void improveItemScores() { + 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); + improve_score(26, itRedGem); + improve_score(27, itPirate); + improve_score(31, itBombEgg); + improve_score(32, itCoast); + improve_score(33, itWhirlpool); + improve_score(34, itPalace); + improve_score(35, itFjord); + + improve_score(37, itEdge); + improve_score(38, itElemental); + improve_score(39, itZebra); + + improve_score(42, itMutant); + improve_score(43, itFulgurite); + + if(!isHaunted(cwt.c->land)) improve_score(46, itLotus); + improve_score(47, itMutant2); + improve_score(48, itWindstone); + + improve_score(51, itCoral); + improve_score(52, itRose); + + improve_score(54, itBabyTortoise); + improve_score(55, itDragon); + improve_score(56, itApple); + } + +void achievement_final(bool really_final) { + if(offlineMode) return; +#ifdef HAVE_ACHIEVEMENTS + if(cheater) return; + if(euclid) return; + if(purehepta) return; + if(randomPatternsMode) return; + + if(tactic::on) { + tactic::record(); + tactic::unrecord(); + tactic::uploadScore(); + return; + } + + if(yendor::on) return; + + if(shmup::on && chaosmode) return; + + int total_improved = 0; + specific_improved = 0; + specific_what = 0; + + if(!shmup::on && !chaosmode) improveItemScores(); + + int sid = chaosmode ? 53 : shmup::on ? (numplayers() > 1 ? 44 : 28) : 0; + + int tg = gold(); + if(tg && haveLeaderboard(sid)) { + if(tg > currentscore[sid] && currentscore[sid] != SCORE_UNKNOWN) { + if(currentscore[sid] < 0) total_improved += 2; + total_improved++; // currentscore[sid] = tg; + } + upload_score(sid, tg); + } + + if(total_improved >= 2) { +#ifndef ANDROID + addMessage(XLAT("Your total treasure has been recorded in the " LEADERFULL ".")); + addMessage(XLAT("Congratulations!")); +#endif + } + 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) { +#ifndef ANDROID + addMessage(XLAT("You have improved your total high score on " LEADER ". Congratulations!")); +#endif + } + else if(specific_improved >= 2) + addMessage(XLAT("You have improved %1 of your specific high scores!", its(specific_improved))); + else if(specific_improved) { +#ifndef ANDROID + addMessage(XLAT("You have improved your '%1' high score on " LEADER "!", iinf[specific_what].name)); +#endif + } +#endif + } + +void achievement_victory(bool hyper) { + if(offlineMode) return; +#ifdef HAVE_ACHIEVEMENTS + if(cheater) return; + if(euclid) return; + if(purehepta) return; + if(randomPatternsMode) return; + if(hyper && shmup::on) return; + if(yendor::on) return; + if(tactic::on) return; + if(chaosmode) return; + + int t = savetime + time(NULL) - timerstart; + + int ih1 = hyper ? 15 : shmup::on ? (numplayers() > 1 ? 45 : 29) : 13; + int ih2 = hyper ? 16 : shmup::on ? 30 : 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!")); +#ifndef ANDROID + addMessage(XLAT("This has been recorded in the " LEADERFULL ".")); +#endif + addMessage(XLAT("The faster you get here, the better you are!")); + } + else if(improved >= 3) { + if(shmup::on) + addMessage(XLAT("You have improved both your real time and knife count. Congratulations!")); + else + 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) { + if(shmup::on) + addMessage(XLAT("You have used less knives than ever before. Congratulations!")); + else + addMessage(XLAT("You have used less turns than ever before. Congratulations!")); + } + } + + upload_score(ih1, t); + upload_score(ih2, turncount); +#endif + } + +void achievement_pump(); + +#ifndef HAVE_ACHIEVEMENTS +void achievement_pump() {} +#endif + +void achievement_display() { + #ifdef HAVE_ACHIEVEMENTS + 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); + int w = 2 * vid.fsize; +#ifndef MOBILE + while(w>3 && textwidth(w, achievementMessage[1]) > vid.xres) w--; +#endif + displayfr(vid.xres/2, vid.yres/4 + vid.fsize*2, 2, w, achievementMessage[1], col, 8); + w = vid.fsize; +#ifndef MOBILE + while(w>3 && textwidth(w, achievementMessage[2]) > vid.xres) w--; +#endif + displayfr(vid.xres/2, vid.yres/4 + vid.fsize*4, 2, w, achievementMessage[2], col, 8); + } + #endif + } + diff --git a/achievement.h b/achievement.h index 339a3cba..e69de29b 100644 --- a/achievement.h +++ b/achievement.h @@ -1,30 +0,0 @@ -// 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 achievementsReceived; diff --git a/cell.cpp b/cell.cpp index b640e99a..3fcbb9a0 100644 --- a/cell.cpp +++ b/cell.cpp @@ -1,11 +1,18 @@ -// Hyperbolic Rogue -// Copyright (C) 2011-2012 Zeno Rogue, see 'hyper.cpp' for details +// Hyperbolic Rogue -- cells +// Copyright (C) 2011-2016 Zeno Rogue, see 'hyper.cpp' for details // cells the game is played on int fix6(int a) { return (a+96)% 6; } int fix7(int a) { return (a+84)% 7; } +int dirdiff(int dd, int t) { + dd %= t; + if(dd<0) dd += t; + if(t-dd < dd) dd = t-dd; + return dd; + } + struct cell : gcell { char type; // 6 for hexagons, 7 for heptagons unsigned char spn[7]; @@ -38,6 +45,8 @@ void merge(cell *c, int d, cell *c2, int d2) { typedef unsigned short eucoord; +#include + cell*& euclideanAtCreate(eucoord x, eucoord y); union heptacoder { @@ -69,6 +78,13 @@ cell *createMov(cell *c, int d) { } if(c->mov[d]) return c->mov[d]; + else if(purehepta) { + heptagon *h2 = createStep(c->master, d); + c->mov[d] = h2->c7; + c->spn[d] = c->master->spin[d]; + h2->c7->mov[c->spn[d]] = c; + h2->c7->spn[c->spn[d]] = d; + } else if(c->type == 7) { cell *n = newCell(6, c->master); @@ -203,11 +219,17 @@ cell*& euclideanAtCreate(eucoord x, eucoord y) { // initializer (also inits origin from heptagon.cpp) void initcells() { + DEBB(DF_INIT, (debugfile,"initcells\n")); origin.s = hsOrigin; origin.emeraldval = 98; origin.zebraval = 40; origin.fiftyval = 0; +#ifdef CDATA + origin.rval0 = origin.rval1 = 0; + origin.cdata = NULL; +#endif + for(int i=0; i<7; i++) origin.move[i] = NULL; origin.alt = NULL; origin.distance = 0; @@ -265,7 +287,7 @@ void clearfrom(heptagon *at) { } DEBMEM ( printf("at %p\n", at); ) if(at->c7) { - for(int i=0; i<7; i++) + if(!purehepta) for(int i=0; i<7; i++) clearcell(at->c7->mov[i]); clearcell(at->c7); } @@ -280,7 +302,7 @@ void verifycell(cell *c) { for(int i=0; imov[i]; if(c2) { - if(t == 7) verifycell(c2); + if(t == 7 && !purehepta) verifycell(c2); if(c2->mov[c->spn[i]] && c2->mov[c->spn[i]] != c) printf("cell error %p %p\n", c, c2); } @@ -318,31 +340,6 @@ bool ishex1(cell *c) { else return c->type == 7; } -void clearMemory() { - extern void clearGameMemory(); - clearGameMemory(); - if(shmup::on) shmup::clearMemory(); - cleargraphmemory(); -#ifndef MOBILE - mapeditor::clearModelCells(); -#endif - // 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; itype == 7) @@ -441,14 +438,21 @@ int cdist50(cell *c) { decodeMaster(c->master, x, y); int ix = short(x) + 99999 + short(y); int iy = short(y) + 99999; - char palacemap[3][10] = { - "012333321", - "112322232", - "222321123" - }; - ix += (iy/3) * 3; - iy %= 3; ix %= 9; - return palacemap[iy][ix] - '0'; + if(c->land == laPalace) { + char palacemap[3][10] = { + "012333321", + "112322232", + "222321123" + }; + ix += (iy/3) * 3; + iy %= 3; ix %= 9; + return palacemap[iy][ix] - '0'; + } + else { + const char *westmap = "0123333332112332223322233211233333322"; + int id = ix + iy * 26 + 28; + return westmap[id % 37] - '0'; + } } if(c->type == 7) return cdist50(fiftyval(c)); int a0 = cdist50(createMov(c,0)); @@ -566,11 +570,33 @@ int zebra3(cell *c) { } } +#define RPV_MODULO 5 + +#define RPV_RAND 0 +#define RPV_ZEBRA 1 +#define RPV_EMERALD 2 +#define RPV_PALACE 3 +#define RPV_CYCLE 4 + +int getCdata(cell *c, int j); + +// x mod 5 = pattern type +// x mod (powers of 2) = pattern type specific +// (x/5) mod 15 = picture for drawing floors +// x mod 7 = chance of pattern-specific pic +// whole = randomization + bool randpattern(cell *c, int rval) { int i, sw=0; - switch(rval & 3) { + switch(rval%5) { case 0: - return rand() < rval; + if(rval&1) { + return hrandpos() < rval; + } + else { + int cd = getCdata(c, 0); + return !((cd/(((rval/2)&15)+1))&1); + } case 1: i = zebra40(c); if(i&1) { if(rval&4) sw^=1; i &= ~1; } @@ -583,26 +609,58 @@ bool randpattern(cell *c, int rval) { i = emeraldval(c); if(i&1) { if(rval&4) sw^=1; i &= ~1; } if(i&2) { if(rval&8) sw^=1; i &= ~2; } + i >>= 2; i--; if(rval & (16<>2)&3)+"/"+its((rval>>4)&15); + case 2: + return "E/"+its((rval>>2)&3)+"/"+its((rval>>4)&2047); + case 3: + return "P/"+its((rval>>2)&3)+"/"+its((rval>>4)&255); + case 4: + return "C/"+its(rval&3)+"/"+its((rval>>2)&65535); + } + return "?"; + } + int randpatternCode(cell *c, int rval) { - switch(rval & 3) { + switch(rval % RPV_MODULO) { case 1: return zebra40(c); case 2: return emeraldval(c); case 3: return fiftyval049(c) + (polara50(c)?50:0) + (polarb50(c)?1000:0); + case 4: + return towerval(c, celldist) * 6 + celldist(c) % 6; } return 0; } @@ -616,14 +674,12 @@ void clearMemoRPM() { rpm_memoize[a][b][i] = 2; } -extern int randompattern[landtypes]; - bool randpatternMajority(cell *c, int ival, int iterations) { int rval = 0; if(ival == 0) rval = randompattern[laCaves]; if(ival == 1) rval = randompattern[laLivefjord]; if(ival == 2) rval = randompattern[laEmerald]; - if((rval&3) == 0) return randpattern(c, rval); + if(rval%RPV_MODULO == RPV_RAND) return randpattern(c, rval); int code = randpatternCode(c, rval); char& memo(rpm_memoize[ival][code][iterations]); if(memo < 2) return memo; @@ -639,3 +695,247 @@ bool randpatternMajority(cell *c, int ival, int iterations) { // printf("%p] rval = %X code = %d iterations = %d result = %d\n", c, rval, code, iterations, memo); return memo; } + +#ifdef CDATA + +#include +map spins; + +#define RVAL_MASK 0x10000000 +#define DATA_MASK 0x20000000 + +struct cdata { + int val[4]; + int bits; + }; + +map eucdata; +cdata orig_cdata; + +void affect(cdata& d, short rv, signed char signum) { + if(rv&1) d.val[0]+=signum; else d.val[0]-=signum; + if(rv&2) d.val[1]+=signum; else d.val[1]-=signum; + if(rv&4) d.val[2]+=signum; else d.val[2]-=signum; + if(rv&8) d.val[3]+=signum; else d.val[3]-=signum; + int id = (rv>>4) & 63; + if(id < 32) + d.bits ^= (1 << id); + } + +void setHeptagonRval(heptagon *h) { + if(!(h->rval0 || h->rval1)) { + h->rval0 = hrand(0x10000); + h->rval1 = hrand(0x10000); + } + } + +cdata *getHeptagonCdata(heptagon *h) { + if(h->cdata) return h->cdata; + + if(h == &origin) { + return h->cdata = new cdata(orig_cdata); + } + + cdata mydata = *getHeptagonCdata(h->move[0]); + + for(int di=3; di<5; di++) { + heptspin hs; hs.h = h; hs.spin = di; + int signum = +1; + while(true) { + heptspin hstab[15]; + hstab[7] = hs; + + for(int i=8; i<12; i++) { + hstab[i] = hsspin(hstab[i-1], (i&1) ? 4 : 3); + hstab[i] = hsstep(hstab[i], 0); + hstab[i] = hsspin(hstab[i], (i&1) ? 3 : 4); + } + + for(int i=6; i>=3; i--) { + hstab[i] = hsspin(hstab[i+1], (i&1) ? 3 : 4); + hstab[i] = hsstep(hstab[i], 0); + hstab[i] = hsspin(hstab[i], (i&1) ? 4 : 3); + } + + if(hstab[3].h->distance < hstab[7].h->distance) { + hs = hstab[3]; continue; + } + + if(hstab[11].h->distance < hstab[7].h->distance) { + hs = hstab[11]; continue; + } + + int jj = 7; + for(int k=3; k<12; k++) if(hstab[k].h->distance < hstab[jj].h->distance) jj = k; + + int ties = 0, tiespos = 0; + for(int k=3; k<12; k++) if(hstab[k].h->distance == hstab[jj].h->distance) + ties++, tiespos += (k-jj); + + // printf("ties=%d tiespos=%d jj=%d\n", ties, tiespos, jj); + if(ties == 2) jj += tiespos/2; + + if(jj&1) signum = -1; + hs = hstab[jj]; + + break; + } + hs = hsstep(hsspin(hs, 3), 0); + setHeptagonRval(hs.h); + + affect(mydata, hs.spin ? hs.h->rval0 : hs.h->rval1, signum); + + /* if(!(spins[hs.h] & hs.spin)) { + spins[hs.h] |= (1<cdata = new cdata(mydata); + } + +cdata *getEuclidCdata(heptagon *h) { + eucoord x, y; + if(eucdata.count(h)) return &(eucdata[h]); + decodeMaster(h, x, y); + + if(x == 0 && y == 0) { + cdata xx; + for(int i=0; i<4; i++) xx.val[i] = 0; + xx.bits = 0; + return &(eucdata[h] = xx); + } + int ord = 1, bid = 0; + while(!((x|y)&ord)) ord <<= 1, bid++; + + for(int k=0; k<3; k++) { + eucoord x1 = x + (k<2 ? ord : 0); + eucoord y1 = y - (k>0 ? ord : 0); + if((x1&ord) || (y1&ord)) continue; + eucoord x2 = x - (k<2 ? ord : 0); + eucoord y2 = y + (k>0 ? ord : 0); + + cdata *d1 = getEuclidCdata(encodeMaster(x1,y1)); + cdata *d2 = getEuclidCdata(encodeMaster(x2,y2)); + cdata xx; + double disp = pow(2, bid/2.) * 6; + + for(int i=0; i<4; i++) { + double dv = (d1->val[i] + d2->val[i])/2 + (hrand(1000) - hrand(1000))/1000. * disp; + xx.val[i] = floor(dv); + if(hrand(1000) / 1000. < dv - floor(dv)) xx.val[i]++; + } + xx.bits = 0; + + for(int b=0; b<32; b++) { + bool gbit = ((hrand(2)?d1:d2)->bits >> b) & 1; + int flipchance = (1< 512) flipchance = 512; + if(hrand(1024) < flipchance) gbit = !gbit; + if(gbit) xx.bits |= (1<master)->val[j]; + else if(c->type == 7) return getHeptagonCdata(c->master)->val[j]*3; + else { + int jj = 0; + for(int k=0; k<6; k++) if(c->mov[k] && c->mov[k]->type == 7) + jj += getHeptagonCdata(c->mov[k]->master)->val[j]; + return jj; + } + } + +int getBits(cell *c) { + if(euclid) return getEuclidCdata(c->master)->bits; + else if(c->type == 7) return getHeptagonCdata(c->master)->bits; + else { + int b0 = getHeptagonCdata(createMov(c, 0)->master)->bits; + int b1 = getHeptagonCdata(createMov(c, 2)->master)->bits; + int b2 = getHeptagonCdata(createMov(c, 4)->master)->bits; + return (b0 & b1) | (b1 & b2) | (b2 & b0); + } + } + +eLand getCLand(cell *c) { + int b = getBits(c); + b = (b&31) ^ (b>>5); + return land_scape[b & 31]; + } + +int celldistance(cell *c1, cell *c2) { + int d = 0; + cell *cl1=c1, *cr1=c1, *cl2=c2, *cr2=c2; + while(true) { + if(cl1 == cl2) return d; + if(cl1 == cr2) return d; + if(cr1 == cl2) return d; + if(cr1 == cr2) return d; + + if(isNeighbor(cl1, cl2)) return d+1; + if(isNeighbor(cl1, cr2)) return d+1; + if(isNeighbor(cr1, cl2)) return d+1; + if(isNeighbor(cr1, cr2)) return d+1; + + forCellEx(c, cl2) if(isNeighbor(c, cr1)) return d+2; + forCellEx(c, cl1) if(isNeighbor(c, cr2)) return d+2; + + int d1 = celldist(cl1), d2 = celldist(cl2); + + if(d1 >= d2) { + cl1 = chosenDown(cl1, -1, 0, celldist); +// cl1->item = eItem(rand() % 10); + cr1 = chosenDown(cr1, 1, 0, celldist); +// cr1->item = eItem(rand() % 10); + d++; + } + if(d1 <= d2) { + cl2 = chosenDown(cl2, -1, 0, celldist); +// cl2->item = eItem(rand() % 10); + cr2 = chosenDown(cr2, 1, 0, celldist); +// cr2->item = eItem(rand() % 10); + d++; + } + } + } + +void clearMemory() { + extern void clearGameMemory(); + clearGameMemory(); + if(shmup::on) shmup::clearMemory(); + cleargraphmemory(); +#ifndef MOBILE + mapeditor::clearModelCells(); +#endif + // 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; + } + eucdata.clear(); + } + else { + DEBMEM ( verifycells(&origin); ) + clearfrom(&origin); + for(int i=0; i