Skip to content

Commit

Permalink
Subnautica: add Radiation option and adjust location logic
Browse files Browse the repository at this point in the history
Add a Radiation Rule to the Subnautica options and adapt the location access
logic.
The new Radiation Rule makes it possible to consider zones inside the Radiation
zone of the Aurora without a Radiation Suit, depending on the rule chosen. By
default, players still need the Radiation Suit.

Most locations on the outer circle of the radiation zone are still easily
accessible without the radiation suit (players may need to have fins, a
seaglide, or to heal). This adds a bit more of challenge for those that want it.

Note: there is another rule in place to prevent locations farther than 800 units
from the origin to be considered without a Seaglide. In practice, this removes
most of those locations from the pool of accessible locations if the player
doesn't have a Seaglide (which should avoid making this too tedious).
Only the Grassy Plateaus East Wreck, Lifepod 4 and Lifepod 6 can be considered
by AP without a Seaglide (and they are definitely accessible without one).
  • Loading branch information
Kardyne committed Feb 19, 2025
1 parent 91a8fc9 commit 02b907e
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 3 deletions.
1 change: 1 addition & 0 deletions worlds/subnautica/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ def fill_slot_data(self) -> Dict[str, Any]:
"creatures_to_scan": self.creatures_to_scan,
"death_link": self.options.death_link.value,
"free_samples": self.options.free_samples.value,
"radiation_rule": self.options.radiation_rule.current_key,
}

return slot_data
Expand Down
29 changes: 29 additions & 0 deletions worlds/subnautica/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,34 @@ def weights_pair(self) -> typing.Tuple[typing.List[str], typing.List[int]]:
return list(self.value.keys()), list(accumulate(self.value.values()))


class RadiationRule(Choice):
"""By default (None), checks inside the radiation zone are logically expected only with a Radiation Suit.
None: Always require the Radiation Suit inside the radiation zone.
Outer: Checks may be expected on the outer parts of the radiation zone (but still inside it)
Inner: As Outer, but checks may also be expected on the inner parts of the radiation zone (i.e., Lifepod 4)
All: All locations will be considered accessible without a Radiation Suit (including inside the Aurora).
Warning: 'All' can be _very_ hard.
"""

display_name = "Radiation Rule"
option_none = 0
option_outer = 1
option_inner = 2
option_all = 3

@property
def distance(self) -> int:
# Distances were computed using the locations of the databoxes in locations.py
# Outer includes the following locations:
# - Bulb Zone West Wreck (800 units from Aurora)
# - Bulb Zone East Wreck (827 units from Aurora)
# - Grassy Plateaus East Wreck (940 units from Aurora)
# - Lifepod 6 (830 units from Aurora)
# - Lifepod 12 (780 units from Aurora)
# Inner adds Lifepod 4 (460 units) to the accessible locations
return [950, 750, 450, 0][self.value]


@dataclass
class SubnauticaOptions(PerGameCommonOptions):
swim_rule: SwimRule
Expand All @@ -140,3 +168,4 @@ class SubnauticaOptions(PerGameCommonOptions):
death_link: SubnauticaDeathLink
start_inventory_from_pool: StartInventoryPool
filler_items_distribution: FillerItemsDistribution
radiation_rule: RadiationRule
7 changes: 4 additions & 3 deletions worlds/subnautica/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,10 @@ def get_max_depth(state: "CollectionState", player: int):
)


def is_radiated(x: float, y: float, z: float) -> bool:
def is_radiation_suit_needed(state: "CollectionState", player: int, x: float, y: float, z: float) -> bool:
radiation_rule: RadiationRule = state.multiworld.worlds[player].options.radiation_rule
aurora_dist = math.sqrt((x - 1038.0) ** 2 + y ** 2 + (z - -163.1) ** 2)
return aurora_dist < 950
return aurora_dist < radiation_rule.distance


def can_access_location(state: "CollectionState", player: int, loc: LocationDict) -> bool:
Expand All @@ -240,7 +241,7 @@ def can_access_location(state: "CollectionState", player: int, loc: LocationDict
pos_y = pos["y"]
pos_z = pos["z"]

need_radiation_suit = is_radiated(pos_x, pos_y, pos_z)
need_radiation_suit = is_radiation_suit_needed(state, player, pos_x, pos_y, pos_z)
if need_radiation_suit and not state.has("Radiation Suit", player):
return False

Expand Down

0 comments on commit 02b907e

Please sign in to comment.