add configurable min levels for non-BB; closes #666
This commit is contained in:
+1
-1
@@ -35,7 +35,7 @@ struct GVRHeader {
|
||||
be_uint16_t height;
|
||||
} __packed_ws__(GVRHeader, 0x10);
|
||||
|
||||
string encode_gvm(const phosg::ImageRGBA8888& img, GVRDataFormat data_format, const string& internal_name, uint32_t global_index) {
|
||||
string encode_gvm(const phosg::ImageRGBA8888N& img, GVRDataFormat data_format, const string& internal_name, uint32_t global_index) {
|
||||
int8_t dimensions_field = -2;
|
||||
{
|
||||
size_t h = img.get_height();
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ enum class GVRDataFormat : uint8_t {
|
||||
};
|
||||
|
||||
std::string encode_gvm(
|
||||
const phosg::ImageRGBA8888& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index);
|
||||
const phosg::ImageRGBA8888N& img, GVRDataFormat data_format, const std::string& internal_name, uint32_t global_index);
|
||||
phosg::ImageRGB888 decode_fon(const std::string& data, size_t width);
|
||||
std::string encode_fon(const phosg::ImageRGB888& img);
|
||||
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ struct ItemData {
|
||||
// sending where needed.
|
||||
// Related note: PSO V2 has an annoyingly complicated format for mags that
|
||||
// doesn't match the above table. We decode this upon receipt and encode it
|
||||
// imemdiately before sending when interacting with V2 clients; see the
|
||||
// immediately before sending when interacting with V2 clients; see the
|
||||
// implementation of decode_for_version() for details.
|
||||
|
||||
union {
|
||||
|
||||
+4
-4
@@ -1183,7 +1183,7 @@ Action a_encode_gvm(
|
||||
} else {
|
||||
data = phosg::read_all(stdin);
|
||||
}
|
||||
auto img = phosg::ImageRGBA8888::from_file_data(data);
|
||||
auto img = phosg::ImageRGBA8888N::from_file_data(data);
|
||||
// If the image has any transparent pixels at all, use RGB5A3
|
||||
string encoded = encode_gvm(
|
||||
img, has_any_transparent_pixels(img) ? GVRDataFormat::RGB5A3 : GVRDataFormat::RGB565, "image.gvr", 0);
|
||||
@@ -2595,17 +2595,17 @@ Action a_generate_ep3_cards_html(
|
||||
phosg::parallel_range<uint32_t>([&](uint32_t index, size_t) -> bool {
|
||||
auto& info = this->card_infos[index];
|
||||
if (!info.large_filename.empty()) {
|
||||
auto img = phosg::ImageRGBA8888::from_file_data(phosg::load_file(info.large_filename));
|
||||
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(info.large_filename));
|
||||
img.resize(512, 399);
|
||||
info.large_data_url = img.serialize(phosg::ImageFormat::PNG_DATA_URL);
|
||||
}
|
||||
if (!info.medium_filename.empty()) {
|
||||
auto img = phosg::ImageRGBA8888::from_file_data(phosg::load_file(info.medium_filename));
|
||||
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(info.medium_filename));
|
||||
img.resize(184, 144);
|
||||
info.medium_data_url = img.serialize(phosg::ImageFormat::PNG_DATA_URL);
|
||||
}
|
||||
if (!info.small_filename.empty()) {
|
||||
auto img = phosg::ImageRGBA8888::from_file_data(phosg::load_file(info.small_filename));
|
||||
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(info.small_filename));
|
||||
img.resize(58, 43);
|
||||
info.small_data_url = img.serialize(phosg::ImageFormat::PNG_DATA_URL);
|
||||
}
|
||||
|
||||
+2
-2
@@ -830,8 +830,8 @@ static const QuestScriptOpcodeDefinition opcode_defs[] = {
|
||||
// regsA[0] = floor
|
||||
// regsA[1] = section
|
||||
// regsA[2] = group
|
||||
{0x8A, "unhide_obj", nullptr, {{REG_SET_FIXED, 3}}, F_V0_V4},
|
||||
{0x8B, "unhide_ene", nullptr, {{REG_SET_FIXED, 3}}, F_V0_V4},
|
||||
{0x8A, "construct_delayed_object", "unhide_obj", {{REG_SET_FIXED, 3}}, F_V0_V4},
|
||||
{0x8B, "construct_delayed_enemy", "unhide_ene", {{REG_SET_FIXED, 3}}, F_V0_V4},
|
||||
|
||||
// Starts a new thread when the player is close enough to the given point.
|
||||
// The collision is created on the current floor; the thread is created
|
||||
|
||||
+43
-35
@@ -400,23 +400,20 @@ shared_ptr<const QuestIndex> ServerState::quest_index(Version version) const {
|
||||
}
|
||||
|
||||
size_t ServerState::default_min_level_for_game(Version version, Episode episode, uint8_t difficulty) const {
|
||||
// A player's actual level is their displayed level - 1, so the minimums for
|
||||
// Episode 1 (for example) are actually 1, 20, 40, 80.
|
||||
const auto& min_levels = is_v4(version)
|
||||
? this->min_levels_v4
|
||||
: is_v3(version)
|
||||
? this->min_levels_v3
|
||||
: this->min_levels_v1_v2;
|
||||
switch (episode) {
|
||||
case Episode::EP1: {
|
||||
const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[0] : DEFAULT_MIN_LEVELS_V3;
|
||||
return min_levels.at(difficulty);
|
||||
}
|
||||
case Episode::EP2: {
|
||||
const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[1] : DEFAULT_MIN_LEVELS_V3;
|
||||
return min_levels.at(difficulty);
|
||||
}
|
||||
case Episode::EP1:
|
||||
return min_levels[0].at(difficulty);
|
||||
case Episode::EP2:
|
||||
return min_levels[1].at(difficulty);
|
||||
case Episode::EP3:
|
||||
return 0;
|
||||
case Episode::EP4: {
|
||||
const auto& min_levels = (version == Version::BB_V4) ? this->min_levels_v4[2] : DEFAULT_MIN_LEVELS_V3;
|
||||
return min_levels.at(difficulty);
|
||||
}
|
||||
case Episode::EP4:
|
||||
return min_levels[2].at(difficulty);
|
||||
default:
|
||||
throw runtime_error("invalid episode");
|
||||
}
|
||||
@@ -966,7 +963,7 @@ void ServerState::load_config_early() {
|
||||
} else if (lower_path.ends_with(".gvm")) {
|
||||
decompressed_gvm_data = phosg::load_file(path);
|
||||
} else if (lower_path.ends_with(".bmp")) {
|
||||
auto img = phosg::ImageRGBA8888::from_file_data(phosg::load_file(path));
|
||||
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(path));
|
||||
decompressed_gvm_data = encode_gvm(
|
||||
img,
|
||||
has_any_transparent_pixels(img) ? GVRDataFormat::RGB5A3 : GVRDataFormat::RGB565,
|
||||
@@ -1273,31 +1270,42 @@ void ServerState::load_config_early() {
|
||||
this->rare_enemy_rates_challenge = MapState::DEFAULT_RARE_ENEMIES;
|
||||
}
|
||||
|
||||
this->min_levels_v1_v2[0] = DEFAULT_MIN_LEVELS_V123;
|
||||
this->min_levels_v1_v2[1] = DEFAULT_MIN_LEVELS_V123;
|
||||
this->min_levels_v1_v2[2] = DEFAULT_MIN_LEVELS_V123;
|
||||
this->min_levels_v3[0] = DEFAULT_MIN_LEVELS_V123;
|
||||
this->min_levels_v3[1] = DEFAULT_MIN_LEVELS_V123;
|
||||
this->min_levels_v3[2] = DEFAULT_MIN_LEVELS_V123;
|
||||
this->min_levels_v4[0] = DEFAULT_MIN_LEVELS_V4_EP1;
|
||||
this->min_levels_v4[1] = DEFAULT_MIN_LEVELS_V4_EP2;
|
||||
this->min_levels_v4[2] = DEFAULT_MIN_LEVELS_V4_EP4;
|
||||
try {
|
||||
for (const auto& ep_it : this->config_json->get_dict("BBMinimumLevels")) {
|
||||
array<size_t, 4> levels({0, 0, 0, 0});
|
||||
for (size_t z = 0; z < 4; z++) {
|
||||
levels[z] = ep_it.second->get_int(z) - 1;
|
||||
}
|
||||
switch (episode_for_token_name(ep_it.first)) {
|
||||
case Episode::EP1:
|
||||
this->min_levels_v4[0] = levels;
|
||||
break;
|
||||
case Episode::EP2:
|
||||
this->min_levels_v4[1] = levels;
|
||||
break;
|
||||
case Episode::EP4:
|
||||
this->min_levels_v4[2] = levels;
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("unknown episode");
|
||||
auto populate_min_levels = [&](std::array<std::array<size_t, 4>, 3>& dest, const char* key_name) -> void {
|
||||
try {
|
||||
for (const auto& ep_it : this->config_json->get_dict(key_name)) {
|
||||
array<size_t, 4> levels({0, 0, 0, 0});
|
||||
for (size_t z = 0; z < 4; z++) {
|
||||
levels[z] = ep_it.second->get_int(z) - 1;
|
||||
}
|
||||
switch (episode_for_token_name(ep_it.first)) {
|
||||
case Episode::EP1:
|
||||
dest[0] = levels;
|
||||
break;
|
||||
case Episode::EP2:
|
||||
dest[1] = levels;
|
||||
break;
|
||||
case Episode::EP4:
|
||||
dest[2] = levels;
|
||||
break;
|
||||
default:
|
||||
throw runtime_error("unknown episode");
|
||||
}
|
||||
}
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
} catch (const out_of_range&) {
|
||||
}
|
||||
};
|
||||
populate_min_levels(this->min_levels_v1_v2, "V1V2MinimumLevels");
|
||||
populate_min_levels(this->min_levels_v3, "V3MinimumLevels");
|
||||
populate_min_levels(this->min_levels_v4, "BBMinimumLevels");
|
||||
|
||||
this->bb_required_patches.clear();
|
||||
try {
|
||||
|
||||
@@ -218,6 +218,8 @@ struct ServerState : public std::enable_shared_from_this<ServerState> {
|
||||
std::shared_ptr<const SetDataTableBase> bb_solo_set_data_table_ep1_ult;
|
||||
std::array<std::shared_ptr<const MapState::RareEnemyRates>, 4> rare_enemy_rates_by_difficulty;
|
||||
std::shared_ptr<const MapState::RareEnemyRates> rare_enemy_rates_challenge;
|
||||
std::array<std::array<size_t, 4>, 3> min_levels_v1_v2; // Indexed as [episode][difficulty]
|
||||
std::array<std::array<size_t, 4>, 3> min_levels_v3; // Indexed as [episode][difficulty]
|
||||
std::array<std::array<size_t, 4>, 3> min_levels_v4; // Indexed as [episode][difficulty]
|
||||
std::unordered_set<std::string> bb_required_patches;
|
||||
std::unordered_set<std::string> auto_patches;
|
||||
|
||||
@@ -805,7 +805,7 @@ char char_for_challenge_rank(uint8_t rank) {
|
||||
return "BAS"[rank];
|
||||
}
|
||||
|
||||
const array<size_t, 4> DEFAULT_MIN_LEVELS_V3({0, 19, 39, 79});
|
||||
const array<size_t, 4> DEFAULT_MIN_LEVELS_V123({0, 19, 39, 79});
|
||||
const array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP1({0, 19, 39, 79});
|
||||
const array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP2({0, 29, 49, 89});
|
||||
const array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP4({0, 39, 79, 109});
|
||||
|
||||
@@ -106,7 +106,7 @@ uint32_t class_flags_for_class(uint8_t char_class);
|
||||
|
||||
char char_for_challenge_rank(uint8_t rank);
|
||||
|
||||
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V3;
|
||||
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V123;
|
||||
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP1;
|
||||
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP2;
|
||||
extern const std::array<size_t, 4> DEFAULT_MIN_LEVELS_V4_EP4;
|
||||
|
||||
+2
-2
@@ -98,7 +98,7 @@ void TeamIndex::Team::save_config() const {
|
||||
}
|
||||
|
||||
void TeamIndex::Team::load_flag() {
|
||||
auto img = phosg::ImageRGBA8888::from_file_data(phosg::load_file(this->flag_filename()));
|
||||
auto img = phosg::ImageRGBA8888N::from_file_data(phosg::load_file(this->flag_filename()));
|
||||
if (img.get_width() != 32 || img.get_height() != 32) {
|
||||
throw runtime_error("incorrect flag image dimensions");
|
||||
}
|
||||
@@ -114,7 +114,7 @@ void TeamIndex::Team::save_flag() const {
|
||||
if (!this->flag_data) {
|
||||
return;
|
||||
}
|
||||
phosg::ImageRGBA8888 img(32, 32);
|
||||
phosg::ImageRGBA8888N img(32, 32);
|
||||
for (size_t y = 0; y < 32; y++) {
|
||||
for (size_t x = 0; x < 32; x++) {
|
||||
img.write(x, y, phosg::rgba8888_for_argb1555(this->flag_data->at(y * 0x20 + x)));
|
||||
|
||||
@@ -1195,8 +1195,15 @@
|
||||
// "RareEnemyRates-Ultimate": {...},
|
||||
// "RareEnemyRates-Challenge": {...},
|
||||
|
||||
// You can override the minimum character levels required to make BB games in
|
||||
// You can override the minimum character levels required to make games in
|
||||
// each episode and difficulty level here.
|
||||
"V1V2MinimumLevels": {
|
||||
"Episode1": [1, 20, 40, 80],
|
||||
},
|
||||
"V3MinimumLevels": {
|
||||
"Episode1": [1, 20, 40, 80],
|
||||
"Episode2": [1, 20, 40, 80],
|
||||
},
|
||||
"BBMinimumLevels": {
|
||||
"Episode1": [1, 20, 50, 90],
|
||||
"Episode2": [1, 30, 60, 100],
|
||||
|
||||
Reference in New Issue
Block a user