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