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 {
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;
if(hrand_monster(8000) < 15 + items[itBrownian])
if(hrand_monster_in(laBrownian, 8000) < 15 + items[itBrownian])
c->monst = moAcidBird;
else if(hrand_monster(8000) < 15)
else if(hrand_monster_in(laBrownian, 8000) < 15)
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->hitpoints = 3;
}
@ -291,7 +291,7 @@ extern array<feature, 21> features;
#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 {{
feature{(color_t)(-0x202020), 5, moNecromancer, VF {

View File

@ -1663,6 +1663,18 @@ EX void initConfig() {
param_i(stamplen, "stamplen");
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() {

View File

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

View File

@ -566,7 +566,7 @@ typedef function<int(struct cell*)> cellfunction;
// passable flags
#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 WORMLENGTH 15
#define PRIZEMUL 7

View File

@ -171,8 +171,8 @@ EX void place_elemental_wall(cell *c) {
else if(c->land == laEEarth) c->wall = waStone;
}
// automatically adjust monster generation for 3D geometries
EX int hrand_monster(int x) {
// automatically adjust monster generation for 3D geometries and custom difficulty
EX int hrand_monster_in(eLand l, int x) {
// dual geometry mode is much harder, so generate less monsters to balance it
if(dual::state) x *= 3;
// in 3D monster generation depends on the sight range
@ -180,9 +180,15 @@ EX int hrand_monster(int x) {
int t = isize(gmatrix);
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);
}
#define hrand_monster(x) hrand_monster_in(c->land, x)
EX bool is_zebra_trapdoor(cell *c) {
if(euclid && closed_or_bounded) return false;
#if CAP_ARCM
@ -280,6 +286,12 @@ EX void gen_baby_tortoise(cell *c) {
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) {
bool fargen = d == 9;
switch(c->land) {
@ -3139,4 +3151,6 @@ EX void setdist(cell *c, int d, cell *from) {
#endif
}
#undef hrand_monster
}

View File

@ -712,8 +712,15 @@ EX eLand getLandForList(cell *c) {
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) {
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((eubinary || sol) && isCyclic(l) && l != specialland) 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 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
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(casual) return UNKNOWN;
if(bow::weapon) return UNKNOWN;
if(use_custom_land_list) return UNKNOWN;
bool is_default_land_structure =
(princess::challenge || tactic::on) ? ls::single() :

View File

@ -685,6 +685,9 @@ EX void showChangeMode() {
multi::cpid = 0;
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::add_action_push(bow::showMenu);

View File

@ -192,7 +192,7 @@ EX int reptilemax() {
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;
a += yendor::hardness() + 1;
if(isCrossroads(cwt.at->land))
@ -206,6 +206,11 @@ bool wchance(int a, int of, int reduction = 0) {
a -= reduction;
if(a < 0) return false;
if(use_custom_land_list) {
of *= 100;
a *= custom_land_wandering[l];
}
return hrand(a+of) < a;
}
@ -337,7 +342,7 @@ EX void wandering() {
if(closed_or_bounded && specialland == laClearing)
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);
bool smallbounded_generation = smallbounded || (closed_manifold && specialland == laClearing);
@ -370,6 +375,8 @@ EX void wandering() {
cell *c = dcal[i];
if(!valid(c)) continue;
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) {
// place the sandstone wall completely randomly (but not on the player)

View File

@ -986,6 +986,16 @@ void save_mode_data(hstream& f) {
f.write<char>(bow::weapon);
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) {