1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-26 10:00:42 +00:00

customize land mode

This commit is contained in:
Zeno Rogue 2024-03-14 19:27:08 +01:00
parent e840e39ba0
commit 4421143ae5
10 changed files with 183 additions and 19 deletions

View File

@ -166,11 +166,11 @@ EX namespace brownian {
ONEMPTY { ONEMPTY {
if(hrand(10000) < min(250, 100 + 2 * PT(kills[moAcidBird] + kills[moBrownBug], 50)) * (25 + min(items[itBrownian], 100)) / 25 && c->landparam >= 4 && c->landparam < 24) if(hrand(10000) < min(250, 100 + 2 * PT(kills[moAcidBird] + kills[moBrownBug], 50)) * (25 + min(items[itBrownian], 100)) / 25 && c->landparam >= 4 && c->landparam < 24)
c->item = itBrownian; c->item = itBrownian;
if(hrand_monster(8000) < 15 + items[itBrownian]) if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian])
c->monst = moAcidBird; c->monst = moAcidBird;
else if(hrand_monster(8000) < 15) else if(hrand_monster_in(laBrownian, 8000) < 15)
c->monst = moAlbatross; c->monst = moAlbatross;
else if(hrand_monster(8000) < 15 + items[itBrownian]) { else if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian]) {
c->monst = moBrownBug; c->monst = moBrownBug;
c->hitpoints = 3; c->hitpoints = 3;
} }
@ -291,7 +291,7 @@ extern array<feature, 21> features;
#define VF [] (cell *c) #define VF [] (cell *c)
bool hrand_var(int i) { return hrand_monster(i) < 25 + items[itVarTreasure] + yendor::hardness(); } bool hrand_var(int i) { return hrand_monster_in(laVariant, i) < 25 + items[itVarTreasure] + yendor::hardness(); }
array<feature, 21> features {{ array<feature, 21> features {{
feature{(color_t)(-0x202020), 5, moNecromancer, VF { feature{(color_t)(-0x202020), 5, moNecromancer, VF {

View File

@ -1663,6 +1663,18 @@ EX void initConfig() {
param_i(stamplen, "stamplen"); param_i(stamplen, "stamplen");
param_f(anims::period, "animperiod"); param_f(anims::period, "animperiod");
addsaver(use_custom_land_list, "customland_use");
for(int i=0; i<landtypes; i++) {
custom_land_list[i] = true;
custom_land_treasure[i] = 100;
custom_land_difficulty[i] = 100;
custom_land_wandering[i] = 100;
addsaver(custom_land_list[i], "customland" + its(i) + "i", true);
addsaver(custom_land_treasure[i], "customland" + its(i) + "t", 100);
addsaver(custom_land_difficulty[i], "customland" + its(i) + "d", 100);
addsaver(custom_land_wandering[i], "customland" + its(i) + "w", 100);
}
} }
EX bool inSpecialMode() { EX bool inSpecialMode() {

View File

@ -1089,16 +1089,7 @@ EX void describeMouseover() {
#endif #endif
} }
EX void showHelp() { EX void addHelpWithTitle() {
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
getcstat = SDLK_ESCAPE;
if(help == "HELPFUN") {
help_delegate();
return;
}
gamescreen();
string help2;
if(help[0] == '@') { if(help[0] == '@') {
int iv = help.find("\t"); int iv = help.find("\t");
int id = help.find("\n"); int id = help.find("\n");
@ -1109,6 +1100,19 @@ EX void showHelp() {
dialog::init("help", forecolor, 120, 100); dialog::init("help", forecolor, 120, 100);
dialog::addHelp(help); dialog::addHelp(help);
} }
}
EX void showHelp() {
cmode = sm::HELP | sm::DOTOUR | sm::DARKEN;
getcstat = SDLK_ESCAPE;
if(help == "HELPFUN") {
help_delegate();
return;
}
gamescreen();
string help2;
addHelpWithTitle();
bool in_list = false; bool in_list = false;

View File

@ -566,7 +566,7 @@ typedef function<int(struct cell*)> cellfunction;
// passable flags // passable flags
#define SAGEMELT .1 #define SAGEMELT .1
#define PT(x, y) ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x)) #define PT(x, y) rebalance_treasure(x, y, c->land)
#define ROCKSNAKELENGTH 50 #define ROCKSNAKELENGTH 50
#define WORMLENGTH 15 #define WORMLENGTH 15
#define PRIZEMUL 7 #define PRIZEMUL 7

View File

@ -171,8 +171,8 @@ EX void place_elemental_wall(cell *c) {
else if(c->land == laEEarth) c->wall = waStone; else if(c->land == laEEarth) c->wall = waStone;
} }
// automatically adjust monster generation for 3D geometries // automatically adjust monster generation for 3D geometries and custom difficulty
EX int hrand_monster(int x) { EX int hrand_monster_in(eLand l, int x) {
// dual geometry mode is much harder, so generate less monsters to balance it // dual geometry mode is much harder, so generate less monsters to balance it
if(dual::state) x *= 3; if(dual::state) x *= 3;
// in 3D monster generation depends on the sight range // in 3D monster generation depends on the sight range
@ -180,9 +180,15 @@ EX int hrand_monster(int x) {
int t = isize(gmatrix); int t = isize(gmatrix);
if(t > 500) x = int(((long long)(x)) * t / 500); if(t > 500) x = int(((long long)(x)) * t / 500);
} }
if(use_custom_land_list) {
x = x * 100 / custom_land_difficulty[l];
if(x == 0) x = 1;
}
return hrand(x); return hrand(x);
} }
#define hrand_monster(x) hrand_monster_in(c->land, x)
EX bool is_zebra_trapdoor(cell *c) { EX bool is_zebra_trapdoor(cell *c) {
if(euclid && closed_or_bounded) return false; if(euclid && closed_or_bounded) return false;
#if CAP_ARCM #if CAP_ARCM
@ -280,6 +286,12 @@ EX void gen_baby_tortoise(cell *c) {
tortoise::babymap[c] = tortoise::getb(c) ^ tortoise::getRandomBits(); tortoise::babymap[c] = tortoise::getb(c) ^ tortoise::getRandomBits();
} }
EX int rebalance_treasure(int x, int y, eLand l) {
int res = ((tactic::on || quotient == 2 || daily::on) ? (y) : inv::on ? min(2*(y),x) : (x));
if(use_custom_land_list) res = (res * custom_land_treasure[l] + 50) / 100;
return res;
}
EX void giantLandSwitch(cell *c, int d, cell *from) { EX void giantLandSwitch(cell *c, int d, cell *from) {
bool fargen = d == 9; bool fargen = d == 9;
switch(c->land) { switch(c->land) {
@ -3139,4 +3151,6 @@ EX void setdist(cell *c, int d, cell *from) {
#endif #endif
} }
#undef hrand_monster
} }

View File

@ -712,8 +712,15 @@ EX eLand getLandForList(cell *c) {
return l; return l;
} }
EX bool use_custom_land_list;
EX array<bool, landtypes> custom_land_list;
EX array<int, landtypes> custom_land_treasure;
EX array<int, landtypes> custom_land_difficulty;
EX array<int, landtypes> custom_land_wandering;
EX bool isLandIngame(eLand l) { EX bool isLandIngame(eLand l) {
if(isElemental(l)) l = laElementalWall; if(isElemental(l)) l = laElementalWall;
if(use_custom_land_list) return custom_land_list[l];
if(dual::state == 2 && !dual::check_side(l)) return false; if(dual::state == 2 && !dual::check_side(l)) return false;
if((eubinary || sol) && isCyclic(l) && l != specialland) return false; if((eubinary || sol) && isCyclic(l) && l != specialland) return false;
if(l == laCamelot && hyperbolic && WDIM == 3) return false; if(l == laCamelot && hyperbolic && WDIM == 3) return false;
@ -802,6 +809,112 @@ EX const int cursed_when = 386;
EX const int walls_when = 388; EX const int walls_when = 388;
EX void mark_tamper() { cheater++; }
EX void customize_land_in_list(eLand l) {
cmode = sm::DARKEN; gamescreen();
dialog::init(XLATN(linf[l].name), linf[l].color);
help = generateHelpForLand(l);
addHelpWithTitle();
dialog::addBreak(100);
dialog::addBoolItem(XLAT("land in game"), custom_land_list[l], 'a');
dialog::add_action([l] {
custom_land_list[l] = !custom_land_list[l];
cheater++;
});
dialog::addSelItem(XLAT("treasure rate"), its(custom_land_treasure[l]), 't');
dialog::add_action([l] {
dialog::editNumber(custom_land_treasure[l], 0, 1000, 10, 100, XLAT("treasure rate in %the1", linf[l].name), "");
dialog::get_ne().reaction = mark_tamper;
});
dialog::addSelItem(XLAT("difficulty"), its(custom_land_difficulty[l]), 'd');
dialog::add_action([l] {
dialog::editNumber(custom_land_difficulty[l], 0, 1000, 10, 100, XLAT("difficulty of %the1", linf[l].name), "");
dialog::get_ne().reaction = mark_tamper;
});
dialog::addSelItem(XLAT("wandering"), its(custom_land_wandering[l]), 'w');
dialog::add_action([l] {
dialog::editNumber(custom_land_wandering[l], 0, 1000, 10, 100, XLAT("difficulty of %the1", linf[l].name), "");
dialog::get_ne().reaction = mark_tamper;
});
dialog::addBack();
dialog::display();
}
EX void customize_land_list() {
cmode = sm::DARKEN; gamescreen();
dialog::init(XLAT("custom land list"));
if(dialog::infix != "") mouseovers = dialog::infix;
generateLandList([] (eLand l) {
if(!use_custom_land_list) {
custom_land_list[l] = isLandIngame(l);
custom_land_treasure[l] = 100;
custom_land_difficulty[l] = 100;
custom_land_wandering[l] = 100;
}
if(dialog::infix != "" && !dialog::hasInfix(linf[l].name)) return false;
if(l == laCanvas) return true;
return !!(land_validity(l).flags & lv::appears_in_geom_exp);
});
stable_sort(landlist.begin(), landlist.end(), [] (eLand l1, eLand l2) { return land_validity(l1).quality_level > land_validity(l2).quality_level; });
dialog::start_list(900, 900, '1');
for(eLand l: landlist) {
dialog::addBoolItem(XLAT1(linf[l].name), custom_land_list[l], dialog::list_fake_key++);
string s;
if(custom_land_treasure[l] != 100) s += "$" + its(custom_land_treasure[l]) + " ";
if(custom_land_difficulty[l] != 100) s += "!" + its(custom_land_difficulty[l]) + " ";
if(custom_land_wandering[l] != 100) s += "^" + its(custom_land_wandering[l]) + " ";
if(s != "") dialog::lastItem().value = s;
dialog::add_action_confirmed([l] {
stop_game();
use_custom_land_list = true;
start_game();
pushScreen([l] { customize_land_in_list(l); });
});
}
dialog::end_list();
dialog::addInfo(XLAT("press letters to search"));
dialog::addBoolItem("custom land list mode", use_custom_land_list, 'U');
dialog::add_action_confirmed([] {
stop_game();
use_custom_land_list = !use_custom_land_list;
start_game();
});
dialog::addHelp();
dialog::add_action([] {
gotoHelp(XLAT(
"In this mode, you can choose the lands you want to be in game. You can also customize their treasure rate and difficulty.\n\n"
"While the game automatically selects a list of lands by default, "
"based on whether it thinks they work well in the currently selected tiling, "
"you might not agree with this selection.\n\n"
"Note that, often, lands are enabled or disabled for a GOOD reason! Use at your own risk.\n\n"
"Just click on a land to configure it. If you are not in the custom land list mode, "
"this will restart the game. You can change the settings during a custom game, but it counts as a cheat."
));
});
dialog::addBack();
dialog::display();
keyhandler = [] (int sym, int uni) {
dialog::handleNavigation(sym, uni);
if(dialog::editInfix(uni)) dialog::list_skip = 0;
else if(doexiton(sym, uni)) popScreen();
};
}
// check if the given land should appear in lists // check if the given land should appear in lists
EX land_validity_t& land_validity(eLand l) { EX land_validity_t& land_validity(eLand l) {

View File

@ -206,6 +206,7 @@ EX modecode_t legacy_modecode() {
if(int(geometry) > 3 || int(variation) > 1) return UNKNOWN; if(int(geometry) > 3 || int(variation) > 1) return UNKNOWN;
if(casual) return UNKNOWN; if(casual) return UNKNOWN;
if(bow::weapon) return UNKNOWN; if(bow::weapon) return UNKNOWN;
if(use_custom_land_list) return UNKNOWN;
bool is_default_land_structure = bool is_default_land_structure =
(princess::challenge || tactic::on) ? ls::single() : (princess::challenge || tactic::on) ? ls::single() :

View File

@ -685,6 +685,9 @@ EX void showChangeMode() {
multi::cpid = 0; multi::cpid = 0;
menuitem_land_structure('l'); menuitem_land_structure('l');
dialog::addBoolItem(XLAT("custom land list"), use_custom_land_list, 'L');
dialog::add_action_push(customize_land_list);
dialog::addBoolItem(XLAT("weapon selection"), bow::weapon, 'b'); dialog::addBoolItem(XLAT("weapon selection"), bow::weapon, 'b');
dialog::add_action_push(bow::showMenu); dialog::add_action_push(bow::showMenu);

View File

@ -192,7 +192,7 @@ EX int reptilemax() {
return r; return r;
} }
bool wchance(int a, int of, int reduction = 0) { bool wchance_in(eLand l, int a, int of, int reduction = 0) {
of *= 10; of *= 10;
a += yendor::hardness() + 1; a += yendor::hardness() + 1;
if(isCrossroads(cwt.at->land)) if(isCrossroads(cwt.at->land))
@ -206,6 +206,11 @@ bool wchance(int a, int of, int reduction = 0) {
a -= reduction; a -= reduction;
if(a < 0) return false; if(a < 0) return false;
if(use_custom_land_list) {
of *= 100;
a *= custom_land_wandering[l];
}
return hrand(a+of) < a; return hrand(a+of) < a;
} }
@ -337,7 +342,7 @@ EX void wandering() {
if(closed_or_bounded && specialland == laClearing) if(closed_or_bounded && specialland == laClearing)
clearing::new_root(); clearing::new_root();
if(cwt.at->land == laZebra && cwt.at->wall == waNone && wchance(items[itZebra], 20)) if(cwt.at->land == laZebra && cwt.at->wall == waNone && wchance_in(laZebra, items[itZebra], 20))
wanderingZebra(cwt.at); wanderingZebra(cwt.at);
bool smallbounded_generation = smallbounded || (closed_manifold && specialland == laClearing); bool smallbounded_generation = smallbounded || (closed_manifold && specialland == laClearing);
@ -371,6 +376,8 @@ EX void wandering() {
if(!valid(c)) continue; if(!valid(c)) continue;
if(isPlayerOn(c)) break; if(isPlayerOn(c)) break;
auto wchance = [c] (int a, int of, int reduction = 0) { return wchance_in(c->land, a, of, reduction); };
if(specialland == laStorms) { if(specialland == laStorms) {
// place the sandstone wall completely randomly (but not on the player) // place the sandstone wall completely randomly (but not on the player)
vector<cell*>& ac = currentmap->allcells(); vector<cell*>& ac = currentmap->allcells();

View File

@ -986,6 +986,16 @@ void save_mode_data(hstream& f) {
f.write<char>(bow::weapon); f.write<char>(bow::weapon);
f.write<char>(bow::style); f.write<char>(bow::style);
} }
if(use_custom_land_list) {
f.write<char>(3);
f.write<int>(landtypes);
for(int i=0; i<landtypes; i++) {
f.write<char>(custom_land_list[i]);
f.write<int>(custom_land_treasure[i]);
f.write<int>(custom_land_difficulty[i]);
f.write<int>(custom_land_wandering[i]);
}
}
} }
EX modecode_t modecode(int mode) { EX modecode_t modecode(int mode) {