diff --git a/rust/data/presets/full-settings/Community Race Season 5.json b/rust/data/presets/full-settings/Community Race Season 5.json
index 7849f7668..2a4a26277 100644
--- a/rust/data/presets/full-settings/Community Race Season 5.json
+++ b/rust/data/presets/full-settings/Community Race Season 5.json
@@ -4284,6 +4284,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/full-settings/Default.json b/rust/data/presets/full-settings/Default.json
index 769504a14..681125a92 100644
--- a/rust/data/presets/full-settings/Default.json
+++ b/rust/data/presets/full-settings/Default.json
@@ -4284,6 +4284,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/full-settings/Mentor Tournament.json b/rust/data/presets/full-settings/Mentor Tournament.json
index 8932aaa99..dfce2e46b 100644
--- a/rust/data/presets/full-settings/Mentor Tournament.json
+++ b/rust/data/presets/full-settings/Mentor Tournament.json
@@ -4284,6 +4284,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/full-settings/Summer Series Expert Challenge.json b/rust/data/presets/full-settings/Summer Series Expert Challenge.json
index e2fa09e24..5e540bfbc 100644
--- a/rust/data/presets/full-settings/Summer Series Expert Challenge.json
+++ b/rust/data/presets/full-settings/Summer Series Expert Challenge.json
@@ -4284,6 +4284,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/item-progression/Challenge.json b/rust/data/presets/item-progression/Challenge.json
index 176ad8ff9..2f44ac6b0 100644
--- a/rust/data/presets/item-progression/Challenge.json
+++ b/rust/data/presets/item-progression/Challenge.json
@@ -11,6 +11,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/item-progression/Desolate.json b/rust/data/presets/item-progression/Desolate.json
index 6a7fdb90d..270308cdf 100644
--- a/rust/data/presets/item-progression/Desolate.json
+++ b/rust/data/presets/item-progression/Desolate.json
@@ -11,6 +11,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/item-progression/Normal.json b/rust/data/presets/item-progression/Normal.json
index f9b60ff2e..69138dd63 100644
--- a/rust/data/presets/item-progression/Normal.json
+++ b/rust/data/presets/item-progression/Normal.json
@@ -11,6 +11,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/item-progression/Technical.json b/rust/data/presets/item-progression/Technical.json
index 41aaabe6d..b9e0035f2 100644
--- a/rust/data/presets/item-progression/Technical.json
+++ b/rust/data/presets/item-progression/Technical.json
@@ -11,6 +11,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/data/presets/item-progression/Tricky.json b/rust/data/presets/item-progression/Tricky.json
index e4d9961c7..c40b3f219 100644
--- a/rust/data/presets/item-progression/Tricky.json
+++ b/rust/data/presets/item-progression/Tricky.json
@@ -11,6 +11,8 @@
"missile_size": 5,
"super_size": 5,
"powerbomb_size": 5,
+ "etank_multiplier": 1,
+ "reserve_multiplier": 1,
"item_pool": [
{
"item": "Missile",
diff --git a/rust/maprando-logic/src/lib.rs b/rust/maprando-logic/src/lib.rs
index 34707226d..312dcc969 100644
--- a/rust/maprando-logic/src/lib.rs
+++ b/rust/maprando-logic/src/lib.rs
@@ -48,6 +48,8 @@ impl GlobalState {
missile_size: u16,
super_size: u16,
powerbomb_size: u16,
+ etank_multiplier: u8,
+ reserve_multiplier: u8,
tech: &[bool],
) {
self.inventory.items[item as usize] = true;
@@ -83,7 +85,10 @@ impl GlobalState {
self.inventory.max_power_bombs = new_max_power_bombs;
}
Item::ETank => {
- self.inventory.max_energy = std::cmp::min(1499, self.inventory.max_energy + 100);
+ self.inventory.max_energy = std::cmp::min(
+ 1499,
+ self.inventory.max_energy + (100 * etank_multiplier as Capacity),
+ );
if !tech[game_data.manage_reserves_tech_idx] {
self.inventory.max_reserves =
Capacity::min(self.inventory.max_reserves, self.inventory.max_energy);
@@ -91,8 +96,11 @@ impl GlobalState {
}
Item::ReserveTank => {
self.inventory.collectible_reserve_tanks += 1;
- self.inventory.max_reserves =
- std::cmp::min(400, self.inventory.collectible_reserve_tanks * 100);
+ self.inventory.max_reserves = std::cmp::min(
+ 400,
+ self.inventory.collectible_reserve_tanks
+ * (100 * reserve_multiplier as Capacity),
+ );
if !tech[game_data.manage_reserves_tech_idx] {
self.inventory.max_reserves =
Capacity::min(self.inventory.max_reserves, self.inventory.max_energy);
diff --git a/rust/maprando-web/src/randomize_helpers.rs b/rust/maprando-web/src/randomize_helpers.rs
index 91ee9c39a..7af7b9168 100644
--- a/rust/maprando-web/src/randomize_helpers.rs
+++ b/rust/maprando-web/src/randomize_helpers.rs
@@ -43,6 +43,8 @@ pub struct SeedHeaderTemplate<'a> {
missile_size: i32,
super_size: i32,
powerbomb_size: i32,
+ etank_multiplier: i32,
+ reserve_multiplier: i32,
difficulty: &'a DifficultyConfig,
quality_of_life_preset: String,
supers_double: bool,
@@ -442,6 +444,14 @@ pub fn render_seed(
missile_size: seed_data.settings.item_progression_settings.missile_size as i32,
super_size: seed_data.settings.item_progression_settings.super_size as i32,
powerbomb_size: seed_data.settings.item_progression_settings.powerbomb_size as i32,
+ etank_multiplier: seed_data
+ .settings
+ .item_progression_settings
+ .etank_multiplier as i32,
+ reserve_multiplier: seed_data
+ .settings
+ .item_progression_settings
+ .reserve_multiplier as i32,
filler_items: seed_data
.settings
.item_progression_settings
diff --git a/rust/maprando-web/templates/generate/help/progression/ammo_size.html b/rust/maprando-web/templates/generate/help/progression/ammo_size.html
index 4c826a5e5..8f370f930 100644
--- a/rust/maprando-web/templates/generate/help/progression/ammo_size.html
+++ b/rust/maprando-web/templates/generate/help/progression/ammo_size.html
@@ -7,8 +7,14 @@
Ammo Size Settings
This setting affects the size of resource expansions.
-
The default (Vanilla) setting for Missiles, Super Missiles, and Power Bombs is 5 per pack. Setting this to larger values may cause some ammo packs to be removed from the item
- pool: the maximum total ammunition that can appear is 999 Missiles, 99 Supers, and 99 Power Bombs.
+
The default (Vanilla) setting for Missiles, Super Missiles, and Power Bombs is 5 per pack.
+
The default (Vanilla) setting for Energy and Reserve Tanks is 1 per pickup.
+
Regardless of these settings, a maximum limit is enforced in-game of the following maximum resource capacities:
+
+ - Ammo expansions will not increase capacity above 999 missiles, 99 super missiles, or 99 power bombs. Ammo will still be replenished for the full amount up to these limits.
+ - E-Tank expansions will not increase energy capacity above 1499 units (14 energy blocks). The effects of E-Tank energy refill under Quality-of-life options will still apply.
+ - Reserve Tank expansion will not increase reserve capacity above 400 units. Since reserve tanks normally come empty, there is no benefit to collecting further Reserve Tanks.
+
+
+
+
+
diff --git a/rust/maprando-web/templates/generate/scripts.html b/rust/maprando-web/templates/generate/scripts.html
index b3514ceb8..e0276b4ee 100644
--- a/rust/maprando-web/templates/generate/scripts.html
+++ b/rust/maprando-web/templates/generate/scripts.html
@@ -291,6 +291,8 @@
"missile_size": tryParseInt(formData.get("ammo_size_Missile")),
"super_size": tryParseInt(formData.get("ammo_size_Super")),
"powerbomb_size": tryParseInt(formData.get("ammo_size_PowerBomb")),
+ "etank_multiplier": tryParseInt(formData.get("multiplier_ETank")),
+ "reserve_multiplier": tryParseInt(formData.get("multiplier_ReserveTank")),
},
"quality_of_life_settings": {
"preset": formData.get("quality_of_life_preset"),
@@ -1220,6 +1222,8 @@
document.getElementById("ammoSizeMissile").value = preset.missile_size;
document.getElementById("ammoSizeSuper").value = preset.super_size;
document.getElementById("ammoSizePowerBomb").value = preset.powerbomb_size;
+ document.getElementById("multiplierETank").value = preset.etank_multiplier;
+ document.getElementById("multiplierReserveTank").value = preset.reserve_multiplier;
processItemPoolPreset();
applyRadioValue("startingItemsPreset", preset.starting_items_preset);
@@ -1342,6 +1346,8 @@
document.getElementById("ammoSizeMissile").value = "5";
document.getElementById("ammoSizeSuper").value = "5";
document.getElementById("ammoSizePowerBomb").value = "5";
+ document.getElementById("multiplierETank").value = "1";
+ document.getElementById("multiplierReserveTank").value = "1";
}
if (document.getElementById("itemPoolPresetReduced").checked) {
document.getElementById("stopItemPlacementEarlyYes").checked = true;
@@ -1356,6 +1362,8 @@
document.getElementById("ammoSizeMissile").value = "5";
document.getElementById("ammoSizeSuper").value = "5";
document.getElementById("ammoSizePowerBomb").value = "5";
+ document.getElementById("multiplierETank").value = "1";
+ document.getElementById("multiplierReserveTank").value = "1";
}
}
function validateAmmoSize() {
@@ -1374,6 +1382,23 @@
if (parseInt(document.getElementById("ammoSizePowerBomb").value) < 1) {
document.getElementById("ammoSizePowerBomb").value = "5";
}
+ if (parseInt(document.getElementById("ammoSizePowerBomb").value) > 99) {
+ document.getElementById("ammoSizePowerBomb").value = "99";
+ }
+
+ if (parseInt(document.getElementById("multiplierETank").value) < 1) {
+ document.getElementById("multiplierETank").value = "1";
+ }
+ if (parseInt(document.getElementById("multiplierETank").value) > 14) {
+ document.getElementById("multiplierETank").value = "14";
+ }
+
+ if (parseInt(document.getElementById("multiplierReserveTank").value) < 1) {
+ document.getElementById("multiplierReserveTank").value = "1";
+ }
+ if (parseInt(document.getElementById("multiplierReserveTank").value) > 4) {
+ document.getElementById("multiplierReserveTank").value = "4";
+ }
}
function validateItemPool() {
diff --git a/rust/maprando-web/templates/seed/item_progression_details.html b/rust/maprando-web/templates/seed/item_progression_details.html
index 4c81056af..f89140ca2 100644
--- a/rust/maprando-web/templates/seed/item_progression_details.html
+++ b/rust/maprando-web/templates/seed/item_progression_details.html
@@ -27,9 +27,9 @@
{% endif %}
-
Ammo Size:
+
Resource Customization:
- Missile {{+ missile_size }}, Super {{+ super_size }}, PowerBomb {{+ powerbomb_size }}
+ Missile {{+ missile_size }}, Super {{+ super_size }}, PowerBomb {{+ powerbomb_size }}, Energy {{+ etank_multiplier }}, Reserve {{+ reserve_multiplier }}
diff --git a/rust/maprando/src/patch.rs b/rust/maprando/src/patch.rs
index f35bf1fcb..cb46445f1 100644
--- a/rust/maprando/src/patch.rs
+++ b/rust/maprando/src/patch.rs
@@ -817,6 +817,24 @@ impl Patcher<'_> {
self.rom.write_u16(snes2pc(0x8BE71F), p_sz)?; // Credits, Power Bomb Item % Divisor
}
+ if self.settings.item_progression_settings.etank_multiplier > 1 {
+ let e_sz = self.settings.item_progression_settings.etank_multiplier as isize * 100;
+
+ self.rom.write_u16(snes2pc(0x84E0B8), e_sz)?; // PLM EED7 (E-Tank)
+ self.rom.write_u16(snes2pc(0x84E474), e_sz)?; // PLM EF2B (E-Tank, Chozo)
+ self.rom.write_u16(snes2pc(0x84E93F), e_sz)?; // PLM EF7F (E-Tank, Shot Block)
+ self.rom.write_u16(snes2pc(0x88E717), e_sz)?; // Credits, E-Tank Item % Divisor
+ }
+
+ if self.settings.item_progression_settings.reserve_multiplier > 1 {
+ let r_sz = self.settings.item_progression_settings.reserve_multiplier as isize * 100;
+
+ self.rom.write_u16(snes2pc(0x84E444), r_sz)?; // PLM EF27 (Reserve Tank)
+ self.rom.write_u16(snes2pc(0x84E909), r_sz)?; // PLM EF7B (Reserve Tank, Chozo)
+ self.rom.write_u16(snes2pc(0x84EE43), r_sz)?; // PLM EFCF (Reserve Tank, Shot Block)
+ self.rom.write_u16(snes2pc(0x88E719), r_sz)?; // Credits, Reserve Tank Item % Divisor
+ }
+
Ok(())
}
@@ -2311,9 +2329,13 @@ impl Patcher<'_> {
starting_missiles += (x.count as isize)
* (self.settings.item_progression_settings.missile_size as isize);
} else if x.item == Item::ETank {
- starting_energy += (x.count as isize) * 100;
+ starting_energy += (x.count as isize)
+ * 100
+ * (self.settings.item_progression_settings.etank_multiplier as isize);
} else if x.item == Item::ReserveTank {
- starting_reserves += (x.count as isize) * 100;
+ starting_reserves += (x.count as isize)
+ * 100
+ * (self.settings.item_progression_settings.reserve_multiplier as isize);
} else if x.item == Item::Super {
starting_supers += (x.count as isize)
* (self.settings.item_progression_settings.super_size as isize);
diff --git a/rust/maprando/src/randomize.rs b/rust/maprando/src/randomize.rs
index a2a426e25..09a74ef8e 100644
--- a/rust/maprando/src/randomize.rs
+++ b/rust/maprando/src/randomize.rs
@@ -3702,24 +3702,55 @@ impl<'r> Randomizer<'r> {
// Although ETanks and Reserve Tanks are fixed to 100 energy, the following
// code is written in a generic way that could support changing this in the future.
let mut minimal_energy = get_minimal_energy(&difficulty_tiers[0]);
+
+ let mut starting_etank_energy = 0 as Capacity;
+ let mut starting_reserve_energy = 0 as Capacity;
+
for x in &starting_items {
initial_items_remaining[x.item as usize] -=
usize::min(x.count, initial_items_remaining[x.item as usize]);
- if x.item == Item::ETank || x.item == Item::ReserveTank {
- minimal_energy = minimal_energy.saturating_sub(100 * x.count as Capacity);
- }
- }
+ if x.item == Item::ETank {
+ starting_etank_energy +=
+ (100 * x.count * settings.item_progression_settings.etank_multiplier as usize)
+ as Capacity;
+ } else if x.item == Item::ReserveTank {
+ starting_reserve_energy += (100
+ * x.count
+ * settings.item_progression_settings.reserve_multiplier as usize)
+ as Capacity;
+ }
+ }
+ minimal_energy = minimal_energy.saturating_sub(std::cmp::min(1400, starting_etank_energy));
+ minimal_energy = minimal_energy.saturating_sub(std::cmp::min(400, starting_reserve_energy));
+
+ let mut initial_etank_energy = std::cmp::min(
+ 1400,
+ (initial_items_remaining[Item::ETank as usize]
+ * settings.item_progression_settings.etank_multiplier as usize
+ * 100) as Capacity,
+ );
+ let mut initial_reserve_energy = std::cmp::min(
+ 400,
+ (initial_items_remaining[Item::ReserveTank as usize]
+ * settings.item_progression_settings.reserve_multiplier as usize
+ * 100) as Capacity,
+ );
- while ((initial_items_remaining[Item::ETank as usize] * 100) as Capacity
- + (initial_items_remaining[Item::ReserveTank as usize] * 100) as Capacity)
- < minimal_energy
- {
- if (initial_items_remaining[Item::ETank as usize] < 14)
- && ((initial_items_remaining[Item::ETank as usize] + 1) * 100 <= 1400)
- {
+ while initial_etank_energy + initial_reserve_energy < minimal_energy {
+ if initial_etank_energy < 1400 {
initial_items_remaining[Item::ETank as usize] += 1;
- } else if initial_items_remaining[Item::ReserveTank as usize] < 4 {
+ initial_etank_energy = std::cmp::min(
+ 1400,
+ initial_etank_energy
+ + 100 * settings.item_progression_settings.etank_multiplier as Capacity,
+ );
+ } else if initial_reserve_energy < 400 {
initial_items_remaining[Item::ReserveTank as usize] += 1;
+ initial_reserve_energy = std::cmp::min(
+ 400,
+ initial_reserve_energy
+ + 100 * settings.item_progression_settings.reserve_multiplier as Capacity,
+ );
} else {
panic!("Can't ensure enough energy!");
}
@@ -3738,9 +3769,15 @@ impl<'r> Randomizer<'r> {
.sum::()
.saturating_sub(available_items)
{
- let energy_left_to_place = ((initial_items_remaining[Item::ETank as usize] * 100)
- as Capacity)
- + ((initial_items_remaining[Item::ReserveTank as usize] * 100) as Capacity);
+ let etank_energy_left_to_place = (initial_items_remaining[Item::ETank as usize]
+ * 100
+ * settings.item_progression_settings.etank_multiplier as usize)
+ as Capacity;
+ let reserve_energy_left_to_place = (initial_items_remaining[Item::ReserveTank as usize]
+ * 100
+ * settings.item_progression_settings.reserve_multiplier as usize)
+ as Capacity;
+ let energy_left_to_place = etank_energy_left_to_place + reserve_energy_left_to_place;
let mut removal_options = ammo_shortage_weight.clone();
if energy_left_to_place > minimal_energy {
removal_options.extend(tank_shortage_weight.clone());
@@ -4414,6 +4451,8 @@ impl<'r> Randomizer<'r> {
self.settings.item_progression_settings.missile_size,
self.settings.item_progression_settings.super_size,
self.settings.item_progression_settings.powerbomb_size,
+ self.settings.item_progression_settings.etank_multiplier,
+ self.settings.item_progression_settings.reserve_multiplier,
&self.difficulty_tiers[0].tech,
);
}
@@ -5311,6 +5350,8 @@ impl<'r> Randomizer<'r> {
self.settings.item_progression_settings.missile_size,
self.settings.item_progression_settings.super_size,
self.settings.item_progression_settings.powerbomb_size,
+ self.settings.item_progression_settings.etank_multiplier,
+ self.settings.item_progression_settings.reserve_multiplier,
&self.difficulty_tiers[0].tech,
);
}
diff --git a/rust/maprando/src/settings.rs b/rust/maprando/src/settings.rs
index cd22f56ea..728397322 100644
--- a/rust/maprando/src/settings.rs
+++ b/rust/maprando/src/settings.rs
@@ -104,6 +104,8 @@ pub struct ItemProgressionSettings {
pub missile_size: u16,
pub super_size: u16,
pub powerbomb_size: u16,
+ pub etank_multiplier: u8,
+ pub reserve_multiplier: u8,
}
#[repr(u8)]
@@ -1125,6 +1127,12 @@ fn upgrade_item_progression_settings(settings: &mut serde_json::Value) -> Result
if !item_progression_settings.contains_key("powerbomb_size") {
item_progression_settings.insert("powerbomb_size".to_string(), (5).into());
}
+ if !item_progression_settings.contains_key("etank_multiplier") {
+ item_progression_settings.insert("etank_multiplier".to_string(), (1).into());
+ }
+ if !item_progression_settings.contains_key("reserve_multiplier") {
+ item_progression_settings.insert("reserve_multiplier".to_string(), (1).into());
+ }
Ok(())
}
diff --git a/rust/maprando/tests/logic_scenarios.rs b/rust/maprando/tests/logic_scenarios.rs
index 067788b8a..30b3862e8 100644
--- a/rust/maprando/tests/logic_scenarios.rs
+++ b/rust/maprando/tests/logic_scenarios.rs
@@ -203,6 +203,8 @@ fn get_settings(scenario: &Scenario) -> Result {
missile_size: 5,
super_size: 5,
powerbomb_size: 5,
+ etank_multiplier: 1,
+ reserve_multiplier: 1,
random_tank: true,
spazer_before_plasma: true,
item_pool_preset: None,