Compare commits

..

No commits in common. "9bc4e21f10882c96419fda4ca30f5633739e12e6" and "dea9fea67f157405de2c15e74835ae64decf89ea" have entirely different histories.

15 changed files with 42 additions and 140 deletions

View File

@ -757,7 +757,7 @@ EX void killMonster(cell *c, eMonster who, flagtype deathflags IS(0)) {
// a reward for killing him before he shoots!
c->item = itOrbDragon;
}
if(m == moAsteroid && !shmup::on && c->item == itNone && c->wall != waChasm && c->land == laAsteroids) {
if(m == moAsteroid && !shmup::on && c->item == itNone && c->wall != waChasm) {
c->item = itAsteroid;
changes.value_add(splitrocks, 2);
}
@ -944,14 +944,6 @@ EX void fightmessage(eMonster victim, eMonster attacker, bool stun, flagtype fla
else
addMessage(XLAT("You pierce %the1.", victim)); // normal
}
else if(items[itOrbSlaying]) {
playSound(NULL, "hit-crush"+pick123());
addMessage(XLAT("You crush %the1!", victim)); // normal
}
else if(stun && items[itCurseWeakness]) {
playSound(NULL, "click");
addMessage(XLAT("You punch %the1.", victim)); // normal
}
else if(!peace::on) {
playSound(NULL, "hit-sword"+pick123());
addMessage(XLAT("You kill %the1.", victim)); // normal

View File

@ -1005,7 +1005,7 @@ EX void buildEquidistant(cell *c) {
if(c->landparam > 30 && b == laOcean && !generatingEquidistant && !mhybrid && hrand(10) < 5 && chance)
buildAnotherEquidistant(c);
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !mhybrid && hrand(100) < (PURE?25:5) && landUnlockedIngame(laHaunted) && chance)
if(c->landparam > HAUNTED_RADIUS+5 && b == laGraveyard && !generatingEquidistant && !mhybrid && hrand(100) < (PURE?25:5) && items[itBone] >= U10 && chance)
buildAnotherEquidistant(c);
}
@ -1876,13 +1876,13 @@ EX void build_horocycles(cell *c, cell *from) {
items[itEmerald] >= U5)))
start_camelot(c);
if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || (hrand(I2000) < 100 && landUnlockedIngame(laTemple))))
if(c->land == laRlyeh && can_start_horo(c) && (quickfind(laTemple) || peace::on || (hrand(I2000) < 100 && items[itStatue] >= U5)))
create_altmap(c, horo_gen_distance(), hsA);
if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlockedIngame(laMountain))))
if(c->land == laJungle && can_start_horo(c) && (quickfind(laMountain) || (hrand(I2000) < 100 && landUnlocked(laMountain))))
create_altmap(c, horo_gen_distance(), hsA);
if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && landUnlockedIngame(laClearing)))) {
if(c->land == laOvergrown && can_start_horo(c) && (quickfind(laClearing) || (hrand(I2000) < 25 && items[itMutant] >= U5 && isLandIngame(laClearing)))) {
heptagon *h = create_altmap(c, horo_gen_distance(), hsA);
if(h) clearing::bpdata[h].root = NULL;
}
@ -1894,12 +1894,11 @@ EX void build_horocycles(cell *c, cell *from) {
if(c->land == laOcean && deepOcean && !generatingEquidistant && !peace::on && can_start_horo(c) &&
(quickfind(laWhirlpool) || (
hrand(2000) < (PURE ? 500 : 1000) && landUnlockedIngame(laWhirlpool))))
hrand(2000) < (PURE ? 500 : 1000))))
create_altmap(c, horo_gen_distance(), hsA);
#if CAP_COMPLEX2
if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety && !ls::hv_structure()
&& landUnlockedIngame(laBrownian))
if(c->land == laOcean && deepOcean && !generatingEquidistant && hrand(10000) < 20 && no_barriers_in_radius(c, 2) && hyperbolic && !quotient && !tactic::on && !safety && !ls::hv_structure())
brownian::init_further(c);
#endif
@ -1920,7 +1919,7 @@ EX void build_horocycles(cell *c, cell *from) {
if(c->land == laPalace && can_start_horo(c) && !princess::generating && !shmup::on && multi::players == 1 && !weirdhyperbolic &&
(princess::forceMouse ? canReachPlayer(from, moMouse) :
(hrand(2000) < (peace::on ? 100 : 20))) &&
landUnlockedIngame(laPrincessQuest)) {
(princess::challenge || kills[moVizier] || peace::on)) {
create_altmap(c, PRADIUS0, hsOrigin, waPalace);
celllister cl(c, 5, 1000000, NULL);
for(cell *c: cl.lst) if(c->master->alt) currentmap->extend_altmap(c->master);
@ -2319,7 +2318,7 @@ EX void pregen() {
currentlands.clear();
if(ls::any_chaos() && !ls::std_chaos())
for(eLand l: land_over)
if(landUnlockedIngame(l))
if(landUnlocked(l) && isLandIngame(l))
currentlands.push_back(l);
}

View File

@ -5181,25 +5181,3 @@ Bug fixes:
* Fixed troll nests in Horodisk/Voronoi.
* Fixed a crash when running away from Clearing in single-land mode.
* Some values are tracked in savefiles while previously they did not (fatigue, snake oil, crossbow reload time, gun ammo, etc.) (Thanks to jlm)
2024-03-24 20:10 Update 13.0e:
* in Steam, option `-achievement-always` to always display achievements, even if you already got them.
* rosebushes now show up on the radar in 3D geometries, and they now blink if they are close to going off
* if you are in water (and have no Fish), you can now see Orbs of Fish and Aether in adjacent water tiles, and also you can move there and pick them up
* crossbow bolt now ignore rose restrictions on attack
* migrating to SDL2 caused crashes in shmup, with the game_keys_scroll option, and with the shift-target option -- this should be fixed
* 'custom' land list mode is now mentioned in the watermark (bottom left of the screen)
2024-03-27 23:47 Update 13.0f:
* new messages on Orb of Phasing, Slaying, and Weakness
* more accurate messages on dice pushing
* when loading save, load full mode data including custom lands
* irregular maps no longer change on every load due to floating point precision
* [custom lands list] Space Rock monsters now drop treasure only if in Space Rock land
* ineligible starting land also if land is not in game
* [custom lands list] do not freeze if no new sealand is available
* in countHyperstones, two variants of Mirror are counted once
* specially generated lands (horocycles, Brown Islands) now respect Unlocked and LandIngame rules
* fixed some more crashes related to SDL2 (e.g., right-click in shmup)

View File

@ -1298,7 +1298,7 @@ LAND( 0xE08020, "Canvas", laCanvas, ZERO | LF_TECHNICAL, itNone, RESERVED, "A fa
LAND( 0x00C000, "Palace Quest", laPrincessQuest, ZERO, itSavedPrincess, RESERVED, princessdesc) // fake
NATIVE(isNative(laPalace, m))
REQ(ACCONLY(laPalace) INMODE(princess::challenge) KILL(moVizier, laPalace))
REQ(ACCONLY(laPalace) KILL(moVizier, laPalace))
LAND( 0xD0D060, "Wild West", laWildWest, ZERO, itBounty, RESERVED, wildwestdesc)
NATIVE((m == moOutlaw) ? 2 : 0)
@ -1797,5 +1797,4 @@ MONSTER( '*', 0, "vertex", moRogueviz, ZERO | CF_TECHNICAL, RESERVED, moN
#undef ACCONLY2
#undef ACCONLY3
#undef ACCONLYF
#undef IFINGAME
#undef INMODE
#undef IFINGAME

View File

@ -660,9 +660,6 @@ int read_cheat_args() {
PHASEFROM(2);
shift(); vid.stereo_mode = eStereo(argi());
}
else if(argis("-save-cheats")) {
save_cheats = true;
}
else if(argis("-cmove")) {
PHASE(3); shift();
for(char c: args()) cheat_move(c);

View File

@ -700,7 +700,6 @@ void add_reqs(eLand l, string& s) {
#define COND(x,y) s += (y);
#define ITEMS_TOTAL(list, z) \
{ int now = 0; string t = "("; for(eItem i: list) { if(t!="(") t += " | "; t += XLATN(iinf[i].name); now += items[i]; } t += ")"; s += XLAT("Treasure required: %1 x %2.\n", its(z), t); buteol(s, now, z); }
#define INMODE(x) ;
#define ACCONLY(z) s += XLAT("Accessible only from %the1.\n", z);
#define ACCONLY2(z,x) s += XLAT("Accessible only from %the1 or %the2.\n", z, x);
#define ACCONLY3(z,y,x) s += XLAT("Accessible only from %the1, %2, or %3.\n", z, y, x);

View File

@ -13,8 +13,8 @@
#define _HYPER_H_
// version numbers
#define VER "13.0f"
#define VERNUM_HEX 0xAA06
#define VER "13.0d"
#define VERNUM_HEX 0xAA04
#include "sysconfig.h"

View File

@ -402,7 +402,10 @@ bool step(int delta) {
if(notfound) { status[4] = XLAT("cells badly paired: %1", its(notfound)); runlevel = 0; break; }
int heptas = 0;
for(auto p: cells_of_heptagon) heptas++;
for(auto p: cells_of_heptagon) {
printf("%p: %d\n", hr::voidp(p.first), isize(p.second));
heptas++;
}
if(heptas != isize(all)) {
status[4] = XLAT("cells not covered: %1", its(isize(all) - heptas));
@ -804,8 +807,6 @@ bool save_map(const string& fname) {
return true;
}
vector<ld> float_order;
EX void save_map_bin(hstream& f) {
if(!base) { f.write<short>(-1); return; }
auto& all = base->allcells();
@ -816,19 +817,6 @@ EX void save_map_bin(hstream& f) {
f.write<short> (base_geometry);
f.write<short> (isize(all));
f.write<short> (origcells);
int foi = 0;
auto check_float_order = [&] (ld x) {
if(foi >= isize(float_order)) {
float_order.push_back(x);
f.write<ld>(x);
}
else if(abs(float_order[foi] - x) > 1e-6) {
println(hlog, float_order[foi], " vs ", x, " : abs difference is ", abs(float_order[foi] - x));
float_order[foi] = x;
}
f.write<ld>(float_order[foi++]);
};
for(auto h: all) {
origcells = 0;
@ -838,9 +826,9 @@ EX void save_map_bin(hstream& f) {
f.write<short> (origcells);
for(auto i: cells_of_heptagon[h->master]) if(cells[i].generation == 0) {
auto &ci = cells[i];
check_float_order(ci.p[0]);
check_float_order(ci.p[1]);
check_float_order(ci.p[LDIM]);
f.write<ld>(ci.p[0]);
f.write<ld>(ci.p[1]);
f.write<ld>(ci.p[LDIM]);
}
}
}
@ -889,7 +877,6 @@ EX void load_map_bin(hstream& f) {
density = cellcount * 1. / isize(all);
cells.clear();
float_order.clear();
for(auto h: all) {
int q = f.get<short>();
@ -902,9 +889,6 @@ EX void load_map_bin(hstream& f) {
a = f.get<ld>();
b = f.get<ld>();
c = f.get<ld>();
float_order.push_back(a);
float_order.push_back(b);
float_order.push_back(c);
s.p = hpxyz(a, b, c);
s.p = normalize(s.p);
for(auto c0: all) s.relmatrices[c0] = calc_relative_matrix(c0, h, s.p);

View File

@ -230,7 +230,6 @@ EX bool landUnlocked(eLand l) {
#define ACCONLY3(x,y,z)
#define ACCONLYF(x)
#define IFINGAME(land, ok, fallback) if(isLandIngame(land)) { ok } else { fallback }
#define INMODE(x) if(x) return true;
#include "content.cpp"
case landtypes: return false;
@ -252,10 +251,7 @@ EX void countHyperstoneQuest(int& i1, int& i2) {
i1 = 0; i2 = 0;
generateLandList(isLandIngame);
for(eLand l: landlist) {
// no treasure
if(l == laCA) continue;
// same treasure, so count only once
if(l == laMirrorOld && isLandIngame(laMirror)) continue;
eItem ttype = treasureType(l);
if(!required_for_hyperstones(ttype)) continue;
i2++; if(items[ttype] >= R10) i1++;
@ -387,7 +383,7 @@ EX eLand pickluck(eLand l1, eLand l2) {
} */
EX eLand getNewSealand(eLand old) {
for(int it=0; it<100; it++) {
while(true) {
eLand p = pick(laOcean, pick(laCaribbean, laLivefjord, laWarpSea, laKraken, laDocks));
if(p == laKraken && !landUnlocked(p)) continue;
if(p == laKraken && peace::on) continue;
@ -396,7 +392,6 @@ EX eLand getNewSealand(eLand old) {
if(!isLandIngame(p)) continue;
return p;
}
return old;
}
EX bool createOnSea(eLand old) {
@ -746,11 +741,6 @@ EX bool isLandIngame(eLand l) {
return land_validity(l).flags & lv::appears_in_full;
}
EX bool landUnlockedIngame(eLand l) {
if(!peace::on && !landUnlocked(l)) return false;
return isLandIngame(l);
}
namespace lv {
flagtype q0 = lv::display_error_message | lv::display_in_help | lv::appears_in_geom_exp;

View File

@ -780,7 +780,7 @@ EX void showChangeMode() {
#endif
dialog::addBoolItem(XLAT("%1 Challenge", moPrincess), (princess::challenge), 'P');
dialog::add_action_confirmed([] {
if(!princess::everSaved && !autocheat)
if(!princess::everSaved)
addMessage(XLAT("Save %the1 first to unlock this challenge!", moPrincess));
else restart_game(rg::princess);
});

View File

@ -11,14 +11,13 @@ namespace hr {
EX namespace multi {
#if HDR
static constexpr int SCANCODES = 512;
static constexpr int MAXJOY = 8;
static constexpr int MAXBUTTON = 64;
static constexpr int MAXAXE = 16;
static constexpr int MAXHAT = 4;
struct config {
char keyaction[SCANCODES];
char keyaction[512];
char joyaction[MAXJOY][MAXBUTTON];
char axeaction[MAXJOY][MAXAXE];
char hataction[MAXJOY][MAXHAT][4];
@ -172,7 +171,7 @@ int* dzconfigs[24];
string listkeys(config& scfg, int id) {
#if CAP_SDL
string lk = "";
for(int i=0; i<SCANCODES; i++)
for(int i=0; i<512; i++)
if(scfg.keyaction[i] == id)
#if CAP_SDL2
lk = lk + " " + SDL_GetScancodeName(SDL_Scancode(i));
@ -266,8 +265,7 @@ struct key_configurer {
if(!setwhat) dialog::handleNavigation(sym, uni);
if(sym) {
if(setwhat) {
int scan = key_to_scan(sym);
if(scan >= 0 && scan < SCANCODES) which_config->keyaction[scan] = setwhat;
which_config->keyaction[sym] = setwhat;
setwhat = 0;
}
else if(uni >= 'a' && uni < 'a' + isize(shmupcmdtable) && shmupcmdtable[uni-'a'][0])
@ -586,19 +584,9 @@ void pressaction(int id) {
actionspressed[id]++;
}
EX int key_to_scan(int sym) {
#if CAP_SDL2
return SDL_GetScancodeFromKey(sym);
#else
return sym;
#endif
}
EX bool notremapped(int sym) {
auto& scfg = scfg_default;
int sc = key_to_scan(sym);
if(sc < 0 || sc >= SCANCODES) return true;
int k = scfg.keyaction[sc];
int k = scfg.keyaction[sym];
if(k == 0) return true;
k /= 16;
if(k > 3) k--; else if(k==3) k = 0;
@ -607,7 +595,7 @@ EX bool notremapped(int sym) {
EX void sconfig_savers(config& scfg, string prefix) {
// unfortunately we cannot use key names here because SDL is not yet initialized
for(int i=0; i<SCANCODES; i++)
for(int i=0; i<512; i++)
addsaver(scfg.keyaction[i], prefix + string("key:")+its(i));
for(int i=0; i<MAXJOY; i++) {
@ -625,7 +613,7 @@ EX void sconfig_savers(config& scfg, string prefix) {
}
EX void clear_config(config& scfg) {
for(int i=0; i<SCANCODES; i++) scfg.keyaction[i] = 0;
for(int i=0; i<512; i++) scfg.keyaction[i] = 0;
}
EX void initConfig() {

View File

@ -664,7 +664,7 @@ EX void teleportTo(cell *dest) {
}
/* calls changes.rollback or changes.commit */
EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone), cell *phasecell IS(nullptr)) {
EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMonster dashmon IS(moNone)) {
if(byWhat != itStrongWind) playSound(dest, "orb-frog");
cell *from = cwt.at;
changes.value_keep(cwt);
@ -683,10 +683,7 @@ EX bool jumpTo(orbAction a, cell *dest, eItem byWhat, int bonuskill IS(0), eMons
if(byWhat == itOrbPhasing) {
useupOrb(itOrbPhasing, 5);
if(phasecell->monst)
addMessage(XLAT("You phase through %the1!", phasecell->monst));
else
addMessage(XLAT("You phase through %the1!", phasecell->wall));
addMessage(XLAT("You jump!"));
}
movecost(from, dest, 1);
@ -1526,7 +1523,7 @@ EX eItem targetRangedOrb(cell *c, orbAction a) {
}
if(phasestate == 3) {
if(jumpTo(a, c, itOrbPhasing, 0, moNone, jumpthru)) phasestate = 4;
if(jumpTo(a, c, itOrbPhasing)) phasestate = 4;
else wouldkill_there = true;
}
else changes.rollback();

View File

@ -802,16 +802,6 @@ bool pcmove::actual_move() {
c2->monst = moNone;
c2->wall = waRichDie;
}
else {
if(vmsg(miWALL, siWALL, c2, c2->monst))
addMessage(XLAT("You can only push this die if the highest number would be on the top!"));
return false;
}
}
else if(mip.d == NO_SPACE) {
if(vmsg(miWALL, siWALL, c2, c2->monst))
addMessage(XLAT("No room to push %the1.", c2->monst));
return false;
}
}
#endif
@ -931,6 +921,8 @@ void pcmove::tell_why_cannot_attack() {
addMessage(XLAT("You cannot attack Raiders directly!"));
else if(isSwitch(c2->monst))
addMessage(XLAT("You cannot attack Jellies in their wall form!"));
else if(c2->monst == moAnimatedDie)
addMessage(XLAT("You can only push this die if the highest number would be on the top!"));
else if(c2->monst == moAngryDie)
addMessage(XLAT("This die is really angry at you!"));
else if((attackflags & AF_WEAK) && isIvy(c2))

View File

@ -187,7 +187,7 @@ EX void initgame() {
if(!safety) {
firstland = specialland;
ineligible_starting_land = !landUnlockedIngame(specialland);
ineligible_starting_land = !landUnlocked(specialland);
}
if(firstland == laNone || firstland == laBarrier)
@ -1047,19 +1047,17 @@ EX void remove_emergency_save() {
scores::score scorebox;
EX bool save_cheats;
EX void saveStats(bool emergency IS(false)) {
DEBBI(DF_INIT, ("saveStats [", scorefile, "]"));
if(autocheat && !save_cheats) return;
if(autocheat) return;
if(scorefile == "") return;
#if CAP_TOUR
if(tour::on && !save_cheats) return;
if(tour::on) return;
#endif
if(randomPatternsMode && !save_cheats) return;
if(randomPatternsMode) return;
if(daily::on) return;
if(peace::on && !save_cheats) return;
if(peace::on) return;
if(experimental) return;
if(!gold() && !racing::on) return;
@ -1217,13 +1215,8 @@ EX void loadsave() {
load_modecode_line(s);
}
if(buf[0] == 'H' && buf[1] == 'y') {
if(fscanf(f, "%9999s", buf) <= 0) break;
if(fscanf(f, "%s", buf) <= 0) break;
sc.ver = buf;
if(sc.ver == "CHEATER!" && save_cheats) {
fgets(buf, 12000, f);
if(fscanf(f, "%9999s", buf) <= 0) break;
sc.ver = buf;
}
if(sc.ver[1] != '.') sc.ver = '0' + sc.ver;
if(verless(sc.ver, "4.4") || sc.ver == "CHEATER!") { ok = false; continue; }
ok = true;
@ -1321,7 +1314,6 @@ EX void loadsave() {
}
fclose(f);
// this is the index of Orb of Safety
if(ok && sc.box[65 + 4 + itOrbSafety - itOrbLightning])
load_last_save();
}
@ -1340,12 +1332,7 @@ EX void load_last_save() {
shstream ss;
ss.s = meaning[sc.box[MODECODE_BOX]];
ss.read(ss.vernum);
if(ss.vernum < 0xAA05)
mapstream::load_geometry(ss);
else {
ss.write_char(0);
load_mode_data_with_zero(ss);
}
mapstream::load_geometry(ss);
}
loadBox();

View File

@ -1053,7 +1053,7 @@ EX void load_mode_data_with_zero(hstream& f) {
case 3: {
use_custom_land_list = true;
int lt = f.get<int>();
if(lt > landtypes) throw hstream_exception("too many landtypes");
if(lt > landtypes) throw hstream_exception();
for(int i=0; i<lt; i++) {
custom_land_list[i] = f.get<char>();
custom_land_treasure[i] = f.get<int>();
@ -1079,7 +1079,7 @@ EX void load_mode_data_with_zero(hstream& f) {
vid.creature_scale = f.get<ld>();
default:
throw hstream_exception("wrong option");
throw hstream_exception();
}
}
}