forked from mirror/Archipelago
Some checks failed
Analyze modified files / flake8 (push) Failing after 2m28s
Build / build-win (push) Has been cancelled
Build / build-ubuntu2204 (push) Has been cancelled
ctest / Test C++ ubuntu-latest (push) Has been cancelled
ctest / Test C++ windows-latest (push) Has been cancelled
Analyze modified files / mypy (push) Has been cancelled
Build and Publish Docker Images / Push Docker image to Docker Hub (push) Successful in 5m4s
Native Code Static Analysis / scan-build (push) Failing after 5m2s
type check / pyright (push) Successful in 1m7s
unittests / Test Python 3.11.2 ubuntu-latest (push) Failing after 16m23s
unittests / Test Python 3.12 ubuntu-latest (push) Failing after 28m19s
unittests / Test Python 3.13 ubuntu-latest (push) Failing after 14m49s
unittests / Test hosting with 3.13 on ubuntu-latest (push) Successful in 5m0s
unittests / Test Python 3.13 macos-latest (push) Has been cancelled
unittests / Test Python 3.11 windows-latest (push) Has been cancelled
unittests / Test Python 3.13 windows-latest (push) Has been cancelled
1316 lines
35 KiB
Python
1316 lines
35 KiB
Python
import base64
|
|
|
|
from encodings.base64_codec import base64_encode
|
|
from io import BytesIO, StringIO
|
|
|
|
from BaseClasses import CollectionState, ItemClassification
|
|
from . import GSTestBase
|
|
from .. import LocationName, ItemName, LocationType, location_type_to_data, loc_names_by_id, ItemType, create_item
|
|
|
|
OPTION_OFFSET = 17
|
|
|
|
class TestFormatBase(GSTestBase):
|
|
|
|
def setUp(self):
|
|
super().setUp()
|
|
world = self.get_world()
|
|
rando_content = BytesIO()
|
|
debug_content = StringIO()
|
|
world._generate_rando_data(rando_content, debug_content)
|
|
# self.rando_data = rando_content.getvalue()
|
|
self.rando_content = rando_content
|
|
|
|
def _get_option_byte(self, offset: int = 0) -> int:
|
|
self.rando_content.seek(OPTION_OFFSET + offset)
|
|
return int.from_bytes(self.rando_content.read(1), byteorder="big")
|
|
|
|
class TestRevealHiddenItem(GSTestBase):
|
|
options = {
|
|
"item_shuffle": 3
|
|
}
|
|
|
|
def test_hidden_requires_reveal(self):
|
|
world = self.get_world()
|
|
location = world.get_location(LocationName.Daila_Sleep_Bomb)
|
|
self.assertFalse(location.can_reach(world.multiworld.state))
|
|
self.collect_by_name(ItemName.Reveal)
|
|
self.assertTrue(location.can_reach(world.multiworld.state))
|
|
|
|
class TestRevealNotRequiredForHidden(GSTestBase):
|
|
options = {
|
|
"reveal_hidden_item": 0,
|
|
"item_shuffle": 3
|
|
}
|
|
|
|
def test_hidden_available(self):
|
|
world = self.get_world()
|
|
location = world.get_location(LocationName.Daila_Sleep_Bomb)
|
|
self.assertFalse(world.multiworld.state.has(ItemName.Reveal, world.player, 1))
|
|
self.assertTrue(location.can_reach(world.multiworld.state))
|
|
|
|
class TestRandoFormat(TestFormatBase):
|
|
|
|
options = {
|
|
"coop": 1
|
|
}
|
|
|
|
def test_file_structure(self):
|
|
world = self.get_world()
|
|
loc_count = 0
|
|
djinn_count = 0
|
|
for loc in world.multiworld.get_locations(world.player):
|
|
if loc.item is not None and loc.location_data.loc_type != LocationType.Event:
|
|
if loc.location_data.loc_type == LocationType.Djinn:
|
|
djinn_count += 1
|
|
else:
|
|
loc_count += 1
|
|
encoded_name = base64.b64encode(self.world.player_name.encode('utf-8'))
|
|
expected_length = 1 + 16 + 16 + len(encoded_name) + 1 + loc_count * 4 + 4 + djinn_count * 2 + 2 + 7*2
|
|
self.assertEqual(expected_length, len(self.rando_content.getvalue()))
|
|
|
|
self.rando_content.seek(0)
|
|
version = int.from_bytes(self.rando_content.read(1), byteorder='little')
|
|
self.assertEqual(1, version)
|
|
|
|
self.rando_content.seek(33)
|
|
name = base64.b64decode(self.rando_content.read(len(encoded_name)), validate=True).decode('utf-8')
|
|
self.assertEqual(self.world.player_name, name)
|
|
|
|
class TestMostItemShuffle(TestFormatBase):
|
|
options = {
|
|
"item_shuffle": 2,
|
|
"lemurian_ship": 2,
|
|
"reveal_hidden_item": False
|
|
}
|
|
|
|
def test_item_shuffle(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x80, 0xC0 & data)
|
|
|
|
def test_ensure_eclipse_needs_no_lucky(self):
|
|
world = self.get_world()
|
|
self.collect_by_name([ItemName.Grindstone])
|
|
loc = world.get_location(LocationName.Lemuria_Eclipse)
|
|
self.assertTrue(loc.can_reach(self.multiworld.state))
|
|
|
|
class TestAllItemShuffle(TestFormatBase):
|
|
options = {
|
|
"item_shuffle": 3,
|
|
"lemurian_ship": 2
|
|
}
|
|
|
|
def test_item_shuffle(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0xC0, 0xC0 & data)
|
|
|
|
def test_ensure_eclipse_needs_lucky(self):
|
|
world = self.get_world()
|
|
self.collect_by_name([ItemName.Grindstone])
|
|
loc = world.get_location(LocationName.Lemuria_Eclipse)
|
|
self.assertFalse(loc.can_reach(self.multiworld.state))
|
|
item = create_item(ItemName.Lucky_Medal, self.player, False, ItemClassification.progression)
|
|
self.collect(item)
|
|
self.assertTrue(loc.can_reach(self.multiworld.state))
|
|
|
|
class TestOmitAll(TestFormatBase):
|
|
options = {
|
|
"omit_locations": 2
|
|
}
|
|
|
|
def test_omit_all(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x20, 0x30 & data)
|
|
|
|
class TestOmitAnemos(TestFormatBase):
|
|
options = {
|
|
"omit_locations": 1
|
|
}
|
|
|
|
def test_omit_all(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x10, 0x30 & data)
|
|
|
|
class TestOmitNothing(TestFormatBase):
|
|
options = {
|
|
"omit_locations": 0
|
|
}
|
|
|
|
def test_omit_all(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x00, 0x30 & data)
|
|
|
|
class TestNoElvenShirtAndClericRing(TestFormatBase):
|
|
options = {
|
|
"add_elvenshirt_clericsring": 0
|
|
}
|
|
|
|
def test_no_gs1_items(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x0, 0x8 & data)
|
|
|
|
class TestElvenShirtAndClericRing(TestFormatBase):
|
|
options = {
|
|
"add_elvenshirt_clericsring": 1
|
|
}
|
|
|
|
def test_gs1_items(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x8, 0x8 & data)
|
|
|
|
class TestVisibleItems(TestFormatBase):
|
|
options = {
|
|
"trap_chance": 0,
|
|
"show_items_outside_chest": 1
|
|
}
|
|
|
|
def test_visible(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class TestNormalVisibility(TestFormatBase):
|
|
options = {
|
|
"show_items_outside_chest": 0
|
|
}
|
|
|
|
def test_invisible(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x0, 0x4 & data)
|
|
|
|
class TestMimicVisibility(TestFormatBase):
|
|
options = {
|
|
"show_items_outside_chest": 1,
|
|
"trap_chance": 50
|
|
}
|
|
|
|
def test_visible_with_mimic(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class TestNoUtilPsy(TestFormatBase):
|
|
|
|
def test_no_util_psy(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class TestUtilPsy(TestFormatBase):
|
|
options = {
|
|
"no_util_psynergy_from_classes": 0
|
|
}
|
|
|
|
def test_util_psy(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class NoRandomizeClassStats(TestFormatBase):
|
|
options = {
|
|
"randomize_class_stat_boosts": 0
|
|
}
|
|
|
|
def test_no_random_class_stats(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x0, 0x1 & data)
|
|
|
|
class RandomizeClassStats(TestFormatBase):
|
|
options = {
|
|
"randomize_class_stat_boosts": 1
|
|
}
|
|
|
|
def test_random_class_stats(self):
|
|
data = self._get_option_byte()
|
|
self.assertEqual(0x1, 0x1 & data)
|
|
|
|
class NoRandomizeEquipCompat(TestFormatBase):
|
|
options = {
|
|
"randomize_equip_compatibility": 0
|
|
}
|
|
|
|
def test_no_randomize_equip_compat(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x00, 0x80 & data)
|
|
|
|
class RandomizeEquipCompat(TestFormatBase):
|
|
options = {
|
|
"randomize_equip_compatibility": 1
|
|
}
|
|
|
|
def test_randomize_equip_compat(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x80, 0x80 & data)
|
|
|
|
class NoAdjustEquipPrices(TestFormatBase):
|
|
options = {
|
|
"adjust_equip_prices": 0
|
|
}
|
|
|
|
def test_no_adjust_equip_prices(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x00, 0x40 & data)
|
|
|
|
class AdjustEquipPrices(TestFormatBase):
|
|
options = {
|
|
"adjust_equip_prices": 1
|
|
}
|
|
|
|
def test_adjust_equip_prices(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x40, 0x40 & data)
|
|
|
|
class NoAdjustEquipStats(TestFormatBase):
|
|
options = {
|
|
"adjust_equip_stats": 0
|
|
}
|
|
|
|
def test_no_adjust_equip_stats(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x00, 0x20 & data)
|
|
|
|
class AdjustEquipStats(TestFormatBase):
|
|
options = {
|
|
"adjust_equip_stats": 1
|
|
}
|
|
|
|
def test_adjust_equip_stats(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x20, 0x20 & data)
|
|
|
|
class NoShuffleWeaponEffect(TestFormatBase):
|
|
options = {
|
|
"shuffle_weapon_effect": 0
|
|
}
|
|
|
|
def test_no_shuffle_weapon_effect(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x0, 0x8 & data)
|
|
|
|
class ShuffleWeaponEffect(TestFormatBase):
|
|
options = {
|
|
"shuffle_weapon_effect": 1
|
|
}
|
|
|
|
def test_shuffle_weapon_effect(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x8, 0x8 & data)
|
|
|
|
class NoShuffleArmourEffect(TestFormatBase):
|
|
options = {
|
|
"shuffle_armour_effect": 0
|
|
}
|
|
|
|
def test_no_shuffle_armour_effect(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x0, 0x4 & data)
|
|
|
|
class ShuffleArmourEffect(TestFormatBase):
|
|
options = {
|
|
"shuffle_armour_effect": 1
|
|
}
|
|
|
|
def test_shuffle_armour_effect(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class NoShuffleCurses(TestFormatBase):
|
|
options = {
|
|
"randomize_curses": 0
|
|
}
|
|
|
|
def test_no_shuffle_curses(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class ShuffleCurses(TestFormatBase):
|
|
options = {
|
|
"randomize_curses": 1
|
|
}
|
|
|
|
def test_shuffle_curses(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class NoAdjustPsynergyPower(TestFormatBase):
|
|
options = {
|
|
"adjust_psynergy_power": 0
|
|
}
|
|
|
|
def test_no_adjust_psynergy_power(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x0, 0x1 & data)
|
|
|
|
class AdjustPsynergyPower(TestFormatBase):
|
|
options = {
|
|
"adjust_psynergy_power": 1
|
|
}
|
|
|
|
def test_adjust_psynergy_power(self):
|
|
data = self._get_option_byte(1)
|
|
self.assertEqual(0x1, 0x1 & data)
|
|
|
|
class NoShuffleDjinnStatBoosts(TestFormatBase):
|
|
options = {
|
|
"shuffle_djinn_stat_boosts": 0
|
|
}
|
|
|
|
def test_no_shuffle_djinn_stat_boosts(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x00, 0x40 & data)
|
|
|
|
class ShuffleDjinnStatBoosts(TestFormatBase):
|
|
options = {
|
|
"shuffle_djinn_stat_boosts": 1
|
|
}
|
|
|
|
def test_shuffle_djinn_stat_boosts(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x40, 0x40 & data)
|
|
|
|
class NoAdjustDjinnAttackPower(TestFormatBase):
|
|
options = {
|
|
"adjust_djinn_attack_power": 0
|
|
}
|
|
|
|
def test_no_adjust_djinn_att_power(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x00, 0x20 & data)
|
|
|
|
class AdjustDjinnAttackPower(TestFormatBase):
|
|
options = {
|
|
"adjust_djinn_attack_power": 1
|
|
}
|
|
|
|
def test_adjust_djinn_att_power(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x20, 0x20 & data)
|
|
|
|
class NoRandoDjinnAttackAOE(TestFormatBase):
|
|
options = {
|
|
"randomize_djinn_attack_aoe": 0
|
|
}
|
|
|
|
def test_no_adjust_djinn_att_aoe(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x00, 0x10 & data)
|
|
|
|
class RandoDjinnAttackPower(TestFormatBase):
|
|
options = {
|
|
"randomize_djinn_attack_aoe": 1
|
|
}
|
|
|
|
def test_adjust_djinn_att_aoe(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x10, 0x10 & data)
|
|
|
|
class NoScaleDjinnDifficulty(TestFormatBase):
|
|
options = {
|
|
"scale_djinni_battle_difficulty": 0
|
|
}
|
|
|
|
def test_no_scale_djinn_difficulty(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x0, 0x8 & data)
|
|
|
|
|
|
class ScaleDjinnDifficulty(TestFormatBase):
|
|
options = {
|
|
"scale_djinni_battle_difficulty": 1
|
|
}
|
|
|
|
def test_scale_djinn_difficulty(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x8, 0x8 & data)
|
|
|
|
class NoRandomizeSummonCosts(TestFormatBase):
|
|
options = {
|
|
"randomize_summon_costs": 0
|
|
}
|
|
|
|
def test_no_randomize_summon_costs(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x0, 0x4 & data)
|
|
|
|
class RandomizeSummonCosts(TestFormatBase):
|
|
options = {
|
|
"randomize_summon_costs": 1
|
|
}
|
|
|
|
def test_randomize_summon_costs(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class NoAdjustSummonPower(TestFormatBase):
|
|
options = {
|
|
"adjust_summon_power": 0
|
|
}
|
|
|
|
def test_no_adjust_summon_power(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class AdjustSummonPower(TestFormatBase):
|
|
options = {
|
|
"adjust_summon_power": 1
|
|
}
|
|
|
|
def test_adjust_summon_power(self):
|
|
data = self._get_option_byte(2)
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class NoShuffleCharStats(TestFormatBase):
|
|
options = {
|
|
"character_stats": 0
|
|
}
|
|
|
|
def test_no_shuffle_char_stats(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x0, 0xC0 & data)
|
|
|
|
class ShuffleCharStats(TestFormatBase):
|
|
options = {
|
|
"character_stats": 1
|
|
}
|
|
|
|
def test_shuffle_char_stats(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x40, 0xC0 & data)
|
|
|
|
class RandomizeCharStats(TestFormatBase):
|
|
options = {
|
|
"character_stats": 2
|
|
}
|
|
|
|
def test_randomize_char_stats(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x80, 0xC0 & data)
|
|
|
|
class NoShuffleCharEle(TestFormatBase):
|
|
options = {
|
|
"character_elements": 0
|
|
}
|
|
|
|
def test_no_shuffle_char_ele(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x00, 0x30 & data)
|
|
|
|
class ShuffleCharEle(TestFormatBase):
|
|
options = {
|
|
"character_elements": 1
|
|
}
|
|
|
|
def test_shuffle_char_ele(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x10, 0x30 & data)
|
|
|
|
class RandomizeCharEle(TestFormatBase):
|
|
options = {
|
|
"character_elements": 2
|
|
}
|
|
|
|
def test_randomize_char_ele(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x20, 0x30 & data)
|
|
|
|
class NoAdjustPsynergyCost(TestFormatBase):
|
|
options = {
|
|
"adjust_psynergy_cost": 0
|
|
}
|
|
|
|
def test_no_adjust_psynergy_cost(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x0, 0x8 & data)
|
|
|
|
class AdjustPsynergyCost(TestFormatBase):
|
|
options = {
|
|
"adjust_psynergy_cost": 1
|
|
}
|
|
|
|
def test_adjust_psynergy_cost(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x8, 0x8 & data)
|
|
|
|
class NoRandomizePsynergyAOE(TestFormatBase):
|
|
options = {
|
|
"randomize_psynergy_aoe": 0
|
|
}
|
|
|
|
def test_no_rando_psy_aoe(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x0, 0x4 & data)
|
|
|
|
class RandomizePsynergyAOE(TestFormatBase):
|
|
options = {
|
|
"randomize_psynergy_aoe": 1
|
|
}
|
|
|
|
def test_rando_psy_aoe(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class NoAdjustEnemyPsyPower(TestFormatBase):
|
|
options = {
|
|
"adjust_enemy_psynergy_power": 0
|
|
}
|
|
|
|
def test_no_adjust_enemy_psy_power(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class AdjustEnemyPsyPower(TestFormatBase):
|
|
options = {
|
|
"adjust_enemy_psynergy_power": 1
|
|
}
|
|
|
|
def test_adjust_enemy_psy_power(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class NoRandomizeEnemyPsyAOE(TestFormatBase):
|
|
options = {
|
|
"randomize_enemy_psynergy_aoe": 0
|
|
}
|
|
|
|
def test_no_rando_enemy_psy_aoe(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x0, 0x1 & data)
|
|
|
|
class RandomizeEnemyPsyAOE(TestFormatBase):
|
|
options = {
|
|
"randomize_enemy_psynergy_aoe": 1
|
|
}
|
|
|
|
def test_rando_enemy_psy_aoe(self):
|
|
data = self._get_option_byte(3)
|
|
self.assertEqual(0x1, 0x1 & data)
|
|
|
|
class ClassPsyVanilla(TestFormatBase):
|
|
options = {
|
|
"class_psynergy": 0
|
|
}
|
|
|
|
def test_vanilla_psy(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x00, 0xe0 & data)
|
|
|
|
class ClassPsyClass(TestFormatBase):
|
|
options = {
|
|
"class_psynergy": 1
|
|
}
|
|
|
|
def test_class_psy(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x20, 0xe0 & data)
|
|
|
|
class ClassPsyGroup(TestFormatBase):
|
|
options = {
|
|
"class_psynergy": 2
|
|
}
|
|
|
|
def test_class_group_psy(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x40, 0xe0 & data)
|
|
|
|
class ClassPsyElement(TestFormatBase):
|
|
options = {
|
|
"class_psynergy": 3
|
|
}
|
|
|
|
def test_class_ele_psy(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x60, 0xe0 & data)
|
|
|
|
class ClassPsyFull(TestFormatBase):
|
|
options = {
|
|
"class_psynergy": 4
|
|
}
|
|
|
|
def test_class_full(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x80, 0xe0 & data)
|
|
|
|
class ClassPsyGroupElement(TestFormatBase):
|
|
options = {
|
|
"class_psynergy": 5
|
|
}
|
|
|
|
def test_class_group_ele_psy(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0xA0, 0xe0 & data)
|
|
|
|
class ClassPsyLevelVanilla(TestFormatBase):
|
|
options = {
|
|
"psynergy_levels": 0
|
|
}
|
|
|
|
def test_class_psy_vanilla(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x00, 0x18 & data)
|
|
|
|
class ClassPsyLevelShuffle(TestFormatBase):
|
|
options = {
|
|
"psynergy_levels": 1
|
|
}
|
|
|
|
def test_class_psy_shuffle(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x08, 0x18 & data)
|
|
|
|
class ClassPsyLevelRando(TestFormatBase):
|
|
options = {
|
|
"psynergy_levels": 2
|
|
}
|
|
|
|
def test_class_psy_rando(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x10, 0x18 & data)
|
|
|
|
#Qol Cutscenes, Tickets and Fastship test
|
|
class SectionFourQoL(TestFormatBase):
|
|
|
|
def test_ensure_qol(self):
|
|
data = self._get_option_byte(4)
|
|
self.assertEqual(0x07, 0x7 & data)
|
|
|
|
class LemurianShipVanilla(TestFormatBase):
|
|
options = {
|
|
"lemurian_ship": 0
|
|
}
|
|
|
|
def test_ship_vanilla(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x00, 0xC0 & data)
|
|
|
|
def test_no_ship(self):
|
|
world = self.get_world()
|
|
self.assertFalse(world.multiworld.state.has(ItemName.Ship, world.player, 1))
|
|
|
|
class LemurianShipFast(TestFormatBase):
|
|
options = {
|
|
"lemurian_ship": 1,
|
|
"djinn_logic": 0
|
|
}
|
|
|
|
def test_ship_fast(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x40, 0xC0 & data)
|
|
|
|
def test_no_ship(self):
|
|
world = self.get_world()
|
|
self.assertFalse(world.multiworld.state.has(ItemName.Ship, world.player, 1))
|
|
|
|
def test_ship_no_piers_or_crystal(self):
|
|
world = self.get_world()
|
|
state = self.multiworld.state
|
|
for item in [ItemName.Douse_Drop, ItemName.Isaac, ItemName.Frost_Jewel, ItemName.Aqua_Hydra_defeated]:
|
|
state.collect(world.create_item(item), True)
|
|
ship = world.get_location(LocationName.Lemurian_Ship_Engine_Room)
|
|
self.assertTrue(ship.can_reach(state))
|
|
|
|
class LemurianShipStart(TestFormatBase):
|
|
options = {
|
|
"lemurian_ship": 2,
|
|
"djinn_logic": 0
|
|
}
|
|
|
|
def test_ship_start(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x80, 0xC0 & data)
|
|
|
|
def test_has_ship(self):
|
|
world = self.get_world()
|
|
self.assertTrue(world.multiworld.state.has(ItemName.Ship, world.player, 1))
|
|
|
|
class AvoidCostVanilla(TestFormatBase):
|
|
options = {
|
|
"free_avoid": 0
|
|
}
|
|
|
|
def test_avoid_cost_vanilla(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class AvoidFree(TestFormatBase):
|
|
options = {
|
|
"free_avoid": 1
|
|
}
|
|
|
|
def test_avoid_free(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class RetreatCostVanilla(TestFormatBase):
|
|
options = {
|
|
"free_retreat": 0
|
|
}
|
|
|
|
def test_cost_retreat_vanilla(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x0, 0x1 & data)
|
|
|
|
class RetreatFree(TestFormatBase):
|
|
options = {
|
|
"free_retreat": 1
|
|
}
|
|
|
|
def test_retreat_free(self):
|
|
data = self._get_option_byte(5)
|
|
self.assertEqual(0x1, 0x1 & data)
|
|
|
|
class NoNonObtainableItems(TestFormatBase):
|
|
options = {
|
|
"add_non_obtainable_items": 0
|
|
}
|
|
|
|
def test_no_non_obtainable_items(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x00, 0xC0 & data)
|
|
|
|
class AddNoObtainableItems(TestFormatBase):
|
|
options = {
|
|
"add_non_obtainable_items": 1
|
|
}
|
|
|
|
def test_add_non_obtainable_items(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x40, 0xC0 & data)
|
|
|
|
class NoShuffleWeaponAtt(TestFormatBase):
|
|
options = {
|
|
"shuffle_weapon_attack": 0
|
|
}
|
|
|
|
def test_no_shuffle_weapon_att(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x00, 0x10 & data)
|
|
|
|
class ShuffleWeaponAtt(TestFormatBase):
|
|
options = {
|
|
"shuffle_weapon_attack": 1
|
|
}
|
|
|
|
def test_shuffle_weapon_att(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x10, 0x10 & data)
|
|
|
|
class NoStartHealingPsy(TestFormatBase):
|
|
options = {
|
|
"start_with_healing_psynergy": 0
|
|
}
|
|
|
|
def test_no_start_healing_psy(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x0, 0x4 & data)
|
|
|
|
class StartHealingPsy(TestFormatBase):
|
|
options = {
|
|
"start_with_healing_psynergy": 1
|
|
}
|
|
|
|
def test_start_healing_psy(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class NoStartRevive(TestFormatBase):
|
|
options = {
|
|
"start_with_revive": 0
|
|
}
|
|
|
|
def test_no_start_revive(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class StartRevive(TestFormatBase):
|
|
options = {
|
|
"start_with_revive": 1
|
|
}
|
|
|
|
def test_start_revive(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class NoStartReveal(TestFormatBase):
|
|
|
|
def test_no_start_reveal(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x0, 0x1 & data)
|
|
|
|
class StartReveal(TestFormatBase):
|
|
options = {
|
|
"start_inventory_from_pool": {
|
|
"Reveal": 1
|
|
}
|
|
}
|
|
|
|
def test_start_reveal(self):
|
|
data = self._get_option_byte(6)
|
|
self.assertEqual(0x1, 0x1 & data)
|
|
|
|
class ScaleExpAndCoin(TestFormatBase):
|
|
options = {
|
|
"scale_exp": 15,
|
|
"scale_coins": 15
|
|
}
|
|
|
|
def test_scale_exp(self):
|
|
data = self._get_option_byte(7)
|
|
self.assertEqual(0xF0, 0xF0 & data)
|
|
|
|
def test_scale_coin(self):
|
|
data = self._get_option_byte(7)
|
|
self.assertEqual(0x0F, 0x0F & data)
|
|
|
|
class NoShuffleArmourDef(TestFormatBase):
|
|
options = {
|
|
"shuffle_armour_defense": 0
|
|
}
|
|
|
|
def test_no_shuffle_armour_def(self):
|
|
data = self._get_option_byte(8)
|
|
self.assertEqual(0x00, 0x80 & data)
|
|
|
|
class ShuffleArmourDef(TestFormatBase):
|
|
options = {
|
|
"shuffle_armour_defense": 1
|
|
}
|
|
|
|
def test_shuffle_armour_def(self):
|
|
data = self._get_option_byte(8)
|
|
self.assertEqual(0x80, 0x80 & data)
|
|
|
|
class StartingLevels(TestFormatBase):
|
|
options = {
|
|
"starting_levels": 42
|
|
}
|
|
|
|
def test_starting_levels(self):
|
|
data = self._get_option_byte(8)
|
|
self.assertEqual(42 ,0x7F & data)
|
|
|
|
class EnemyElementalResVanilla(TestFormatBase):
|
|
options = {
|
|
"enemy_elemental_resistance": 0
|
|
}
|
|
|
|
def test_vanilla_enemy_ele_res(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x0 ,0xC0 & data)
|
|
|
|
class EnemyElementalResShuffled(TestFormatBase):
|
|
options = {
|
|
"enemy_elemental_resistance": 1
|
|
}
|
|
|
|
def test_shuffled_enemy_ele_res(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x40 ,0xC0 & data)
|
|
|
|
class EnemyElementalResRando(TestFormatBase):
|
|
options = {
|
|
"enemy_elemental_resistance": 2
|
|
}
|
|
|
|
def test_rando_enemy_ele_res(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x80 ,0xC0 & data)
|
|
|
|
class SanctumReviveCostVanilla(TestFormatBase):
|
|
options = {
|
|
"sanctum_revive_cost": 0
|
|
}
|
|
|
|
def test_sanctum_revive_vanilla(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x00 ,0x30 & data)
|
|
|
|
class SanctumReviveCostReduced(TestFormatBase):
|
|
options = {
|
|
"sanctum_revive_cost": 1
|
|
}
|
|
|
|
def test_sanctum_revive_reduced(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x10 ,0x30 & data)
|
|
|
|
class SanctumReviveCostFixed(TestFormatBase):
|
|
options = {
|
|
"sanctum_revive_cost": 2
|
|
}
|
|
|
|
def test_sanctum_revive_fixed(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x20 ,0x30 & data)
|
|
|
|
class CursesVanilla(TestFormatBase):
|
|
options = {
|
|
"remove_all_curses": 0
|
|
}
|
|
|
|
def test_curses_vanilla(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x00 ,0x8 & data)
|
|
|
|
class CursesDisabled(TestFormatBase):
|
|
options = {
|
|
"remove_all_curses": 1
|
|
}
|
|
|
|
def test_curses_disabled(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x8, 0x8 & data)
|
|
|
|
class AvoidVanilla(TestFormatBase):
|
|
options = {
|
|
"avoid_always_works": 0
|
|
}
|
|
|
|
def test_avoid_vanilla(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x0, 0x4 & data)
|
|
|
|
class AvoidAlways(TestFormatBase):
|
|
options = {
|
|
"avoid_always_works": 1
|
|
}
|
|
|
|
def test_avoid_always(self):
|
|
data = self._get_option_byte(9)
|
|
self.assertEqual(0x4, 0x4 & data)
|
|
|
|
class NoHardMode(TestFormatBase):
|
|
options = {
|
|
"enable_hard_mode": 0
|
|
}
|
|
|
|
def test_no_hard_mode(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x0, 0x80 & data)
|
|
|
|
class HardMode(TestFormatBase):
|
|
options = {
|
|
"enable_hard_mode": 1
|
|
}
|
|
|
|
def test_hard_mode(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x80, 0x80 & data)
|
|
|
|
class EncounterRateVanilla(TestFormatBase):
|
|
options = {
|
|
"reduced_encounter_rate": 0
|
|
}
|
|
|
|
def test_encounter_vanilla(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x00, 0x40 & data)
|
|
|
|
class EncounterRateHalved(TestFormatBase):
|
|
options = {
|
|
"reduced_encounter_rate": 1
|
|
}
|
|
|
|
def test_encounter_halved(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x40, 0x40 & data)
|
|
|
|
class BossDifficultyVanilla(TestFormatBase):
|
|
options = {
|
|
"easier_bosses": 0
|
|
}
|
|
|
|
def test_vanilla_bosses(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x00, 0x10 & data)
|
|
|
|
class BossDifficultyEasy(TestFormatBase):
|
|
options = {
|
|
"easier_bosses": 1
|
|
}
|
|
|
|
def test_easy_bosses(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x10, 0x10 & data)
|
|
|
|
class NamedPuzzlesVanilla(TestFormatBase):
|
|
options = {
|
|
"name_puzzles": 0
|
|
}
|
|
|
|
def test_named_puzzles_vanilla(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x0, 0xC & data)
|
|
|
|
class NamedPuzzlesFixed(TestFormatBase):
|
|
options = {
|
|
"name_puzzles": 1
|
|
}
|
|
|
|
def test_named_puzzles_fixed(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x4, 0xC & data)
|
|
|
|
class NamedPuzzlesRando(TestFormatBase):
|
|
options = {
|
|
"name_puzzles": 2
|
|
}
|
|
|
|
def test_named_puzzles_rando(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x8, 0xC & data)
|
|
|
|
class ManualRetreatGlitch(TestFormatBase):
|
|
options = {
|
|
"manual_retreat_glitch": 0
|
|
}
|
|
|
|
|
|
def test_manual_retreat(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x0, 0x2 & data)
|
|
|
|
class SelectRetreatGlitch(TestFormatBase):
|
|
options = {
|
|
"manual_retreat_glitch": 1
|
|
}
|
|
|
|
def test_select_retreat(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x2, 0x2 & data)
|
|
|
|
class NoWings(TestFormatBase):
|
|
options = {
|
|
"lemurian_ship": 2,
|
|
"start_with_wings_of_anemos": 0
|
|
}
|
|
|
|
def test_no_wings(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x0, 0x1 & data)
|
|
|
|
class StartWithWings(TestFormatBase):
|
|
options = {
|
|
"lemurian_ship": 2,
|
|
"start_with_wings_of_anemos": 1
|
|
}
|
|
|
|
def test_start_with_wings(self):
|
|
data = self._get_option_byte(10)
|
|
self.assertEqual(0x1, 0x1 & data)
|
|
|
|
class VanillaMusic(TestFormatBase):
|
|
options = {
|
|
"shuffle_music": 0
|
|
}
|
|
|
|
def test_vanilla_music(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x0, 0x80 & data)
|
|
|
|
class ShuffleMusic(TestFormatBase):
|
|
options = {
|
|
"shuffle_music": 1
|
|
}
|
|
|
|
def test_shuffle_music(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x80, 0x80 & data)
|
|
|
|
class RetreatVanilla(TestFormatBase):
|
|
options = {
|
|
"teleport_to_dungeons_and_towns": 0
|
|
}
|
|
|
|
def test_retreat_vanilla(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x00, 0x40 & data)
|
|
|
|
class RetreatIsTele(TestFormatBase):
|
|
options = {
|
|
"teleport_to_dungeons_and_towns": 1
|
|
}
|
|
|
|
def test_retreat_tele(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x40, 0x40 & data)
|
|
|
|
class BossDropsRando(TestFormatBase):
|
|
|
|
def test_boss_drops_rando(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x00, 0x20 & data)
|
|
|
|
class SuperBossRando(TestFormatBase):
|
|
|
|
def test_superboss_rando(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x00, 0x10 & data)
|
|
|
|
class AnemosAccessVanilla(TestFormatBase):
|
|
options = {
|
|
"anemos_inner_sanctum_access": 0
|
|
}
|
|
|
|
def test_anemos_access_vanilla(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x0, 0xC & data)
|
|
|
|
class AnemosAccessRando(TestFormatBase):
|
|
options = {
|
|
"anemos_inner_sanctum_access": 1
|
|
}
|
|
|
|
def test_anemos_access_rando(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x4, 0xC & data)
|
|
|
|
class AnemosAccessOpen(TestFormatBase):
|
|
options = {
|
|
"anemos_inner_sanctum_access": 2
|
|
}
|
|
|
|
def test_anemos_access_rando(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x8, 0xC & data)
|
|
|
|
class VanillaPCShuffle(TestFormatBase):
|
|
options = {
|
|
'shuffle_characters': 0
|
|
}
|
|
|
|
def test_vanilla_placement(self):
|
|
data = self._get_option_byte(11)
|
|
# Yes, 2 is correct; we want to enforce shuffle flag to be on incase players create additional character items
|
|
self.assertEqual(0x2, 0x3 & data)
|
|
|
|
def test_ensure_vanilla_placement(self):
|
|
world = self.get_world()
|
|
for char in location_type_to_data[LocationType.Character]:
|
|
self.assertEqual(LocationType.Character, char.loc_type)
|
|
name = loc_names_by_id[char.ap_id]
|
|
ap_loc = world.get_location(name)
|
|
ap_item = ap_loc.item
|
|
self.assertEqual(ItemType.Character, ap_item.item_data.type)
|
|
self.assertEqual(ap_loc.location_data.vanilla_contents, ap_item.item_data.id)
|
|
|
|
class PCShuffleInVanilla(TestFormatBase):
|
|
|
|
def test_vanilla_shuffle(self):
|
|
data = self._get_option_byte(11)
|
|
# Yes, 2 is correct; rando doesn't have this option
|
|
self.assertEqual(0x2, 0x3 & data)
|
|
|
|
def test_ensure_placement_within_vanilla(self):
|
|
world = self.get_world()
|
|
for char in location_type_to_data[LocationType.Character]:
|
|
self.assertEqual(LocationType.Character, char.loc_type)
|
|
name = loc_names_by_id[char.ap_id]
|
|
ap_loc = world.get_location(name)
|
|
ap_item = ap_loc.item
|
|
self.assertEqual(ItemType.Character, ap_item.item_data.type)
|
|
# self.assertEqual(ap_loc.location_data.vanilla_contents, ap_item.item_data.id)
|
|
|
|
class TestFullPCShuffle(TestFormatBase):
|
|
options = {
|
|
'shuffle_characters': 2
|
|
}
|
|
|
|
def test_pc_rando(self):
|
|
data = self._get_option_byte(11)
|
|
self.assertEqual(0x2, 0x3 & data)
|
|
|
|
def test_ensure_jenna_is_char(self):
|
|
world = self.get_world()
|
|
jenna_loc = world.get_location(LocationName.Idejima_Jenna)
|
|
self.assertEqual(ItemType.Character, jenna_loc.item.item_data.type)
|
|
|
|
|
|
class TestShortcutMarsLighthouse(TestFormatBase):
|
|
options = {
|
|
'shortcut_mars_lighthouse': 1,
|
|
'item_shuffle': 3,
|
|
'lemurian_ship': 2
|
|
}
|
|
|
|
def test_shortcut_msl_option(self):
|
|
data = self._get_option_byte(12)
|
|
self.assertEqual(0x10, 0x10 & data)
|
|
|
|
def test_shortcut_msl_logic(self):
|
|
self.collect_by_name([ItemName.Grindstone])
|
|
self.collect(self.get_item_by_name(ItemName.Ship_Cannon))
|
|
|
|
self.assertFalse(self.can_reach_location(LocationName.Mars_Lighthouse_Alastors_Hood))
|
|
self.assertTrue(self.can_reach_location(LocationName.Mars_Lighthouse_Apple))
|
|
|
|
self.collect_by_name(ItemName.Mars_Star)
|
|
self.assertTrue(self.can_reach_location(LocationName.Mars_Lighthouse_Alastors_Hood))
|
|
|
|
|
|
class TestVanillaMarsLighthouse(TestFormatBase):
|
|
options = {
|
|
'shortcut_mars_lighthouse': 0,
|
|
'item_shuffle': 3,
|
|
'lemurian_ship': 2
|
|
}
|
|
|
|
def test_vanilla_msl_option(self):
|
|
data = self._get_option_byte(12)
|
|
self.assertEqual(0x0, 0x10 & data)
|
|
|
|
def test_vanilla_msl_logic(self):
|
|
self.collect_by_name([ItemName.Grindstone])
|
|
self.collect(self.get_item_by_name(ItemName.Ship_Cannon))
|
|
|
|
self.assertFalse(self.can_reach_location(LocationName.Mars_Lighthouse_Alastors_Hood))
|
|
self.assertTrue(self.can_reach_location(LocationName.Mars_Lighthouse_Apple))
|
|
|
|
self.collect_by_name(ItemName.Mars_Star)
|
|
self.assertFalse(self.can_reach_location(LocationName.Mars_Lighthouse_Alastors_Hood))
|
|
|
|
self.collect(self.get_item_by_name(ItemName.Mars_Lighthouse_Heated))
|
|
self.assertTrue(self.can_reach_location(LocationName.Mars_Lighthouse_Alastors_Hood))
|
|
|
|
|
|
class TestShortcutMagmaRock(TestFormatBase):
|
|
options = {
|
|
'shortcut_magma_rock': 1,
|
|
'item_shuffle': 3,
|
|
'lemurian_ship': 2
|
|
}
|
|
|
|
def test_shortcut_mr_option(self):
|
|
data = self._get_option_byte(12)
|
|
self.assertEqual(0x8, 0x8 & data)
|
|
|
|
def test_shortcut_mr_logic(self):
|
|
self.collect_by_name([ItemName.Grindstone, ItemName.Lifting_Gem, ItemName.Burst_Brooch])
|
|
|
|
self.assertFalse(self.can_reach_location(LocationName.Magma_Rock_Golem_Core))
|
|
self.assertTrue(self.can_reach_location(LocationName.Magma_Rock_Mimic))
|
|
self.assertTrue(self.can_reach_location(LocationName.Magma_Rock_Blaze))
|
|
|
|
self.collect_by_name(ItemName.Whirlwind)
|
|
self.assertTrue(self.can_reach_location(LocationName.Magma_Rock_Golem_Core))
|
|
|
|
class TestVanillaMagmaRock(TestFormatBase):
|
|
options = {
|
|
'shortcut_magma_rock': 0,
|
|
'item_shuffle': 3,
|
|
'lemurian_ship': 2
|
|
}
|
|
|
|
def test_vanilla_mr_option(self):
|
|
data = self._get_option_byte(12)
|
|
self.assertEqual(0x0, 0x8 & data)
|
|
|
|
def test_vanilla_mr_logic(self):
|
|
self.collect_by_name([ItemName.Grindstone, ItemName.Lifting_Gem, ItemName.Burst_Brooch])
|
|
|
|
self.assertFalse(self.can_reach_location(LocationName.Magma_Rock_Golem_Core))
|
|
self.assertTrue(self.can_reach_location(LocationName.Magma_Rock_Mimic))
|
|
self.assertFalse(self.can_reach_location(LocationName.Magma_Rock_Blaze))
|
|
|
|
self.collect_by_name(ItemName.Whirlwind)
|
|
self.assertFalse(self.can_reach_location(LocationName.Magma_Rock_Golem_Core))
|
|
|
|
self.collect_by_name(ItemName.Growth)
|
|
self.collect_by_name(ItemName.Lash_Pebble)
|
|
self.assertTrue(self.can_reach_location(LocationName.Magma_Rock_Golem_Core))
|
|
|