Skip to content

Commit

Permalink
Merge commit 'a10dfea'
Browse files Browse the repository at this point in the history
  • Loading branch information
progre committed Aug 5, 2024
2 parents 71cfe36 + a10dfea commit e7915e4
Show file tree
Hide file tree
Showing 38 changed files with 886 additions and 229 deletions.
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ If you feel stuck, see some tips below. They may help.

Place seed and La-Mulana install directory, select options, then push Apply.

### Current restrictions

- *Mini Doll*, *Pepper*, *Anchor*, and *Mulana Talisman* are still given by their respective NPCs.

### Note

- Certain situations can cause a softlock. For example, going to *Dimensional Corridor* without *Bronze Mirror*.
Expand Down
7 changes: 7 additions & 0 deletions src-tauri/res/00_Surface.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ roms:
- feather
nemesis3:
- pistol, ammunition
talks:
mulanaTalisman:
- diary
pr3:
- feather, sacredOrb:2
- feather, scalesphere
- feather, holyGrail
2 changes: 1 addition & 1 deletion src-tauri/res/01_Gate_of_Guidance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ subWeapons:
ankhJewel:gateOfGuidance:
chests:
treasures:
- event:pepper
- pepper
sacredOrb:gateOfGuidance:
crucifix:
- flareGun, flareGunAmmo,birthSeal
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/res/09_Shrine_of_the_Mother.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
chests:
crystalSkull:
- event:reachedFrontOfShrineOfTheMother, event:mulanaTalisman, lifeSeal
- event:reachedFrontOfShrineOfTheMother, mulanaTalisman, lifeSeal
- option:glitch, event:twinLabyrinthsGlitch, lifeSeal, twinStatue, knife, msx2, athleticLand, cabbagePatchKids # https://youtu.be/k4S4xUn8zFI
sacredOrb:shrineOfTheMother:
- event:reachedFrontOfShrineOfTheMother, originSeal, birthSeal, lifeSeal, deathSeal
Expand Down
9 changes: 8 additions & 1 deletion src-tauri/res/11_Gate_of_Illusion.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
chests:
keyOfEternity:
- event:reachedElevatorOfGateOfIllusion, event:miniDoll, event:escapeShu # need mini doll and a way to get out from Shu area
- event:reachedElevatorOfGateOfIllusion, miniDoll, event:escapeShu # need mini doll and a way to get out from Shu area
- option:glitch, event:reachedElevatorOfGateOfIllusion, spear, spearAmmo, holyGrail, sacredOrb:1, msx2, athleticLand, cabbagePatchKids # https://youtu.be/7_D0TQ7ZWk0?si=Cn2sTNOxnzGJOyMt&t=3223
- option:glitch, event:reachedElevatorOfGateOfIllusion, spear, spearAmmo, holyGrail, sacredOrb:2
protectiveClothes:
Expand All @@ -21,3 +21,10 @@ roms:
- event:reachedFrontOfGateOfIllusion
salamander:
- event:reachedFrontOfGateOfIllusion
talks:
miniDoll:
- event:reachedFrontOfGateOfIllusion, event:reachedGrailOfGateOfIllusion, handScanner, glyphReader, anchor
pepper:
- event:reachedFrontOfGateOfIllusion
anchor:
- event:reachedFrontOfGateOfIllusion, treasures
4 changes: 2 additions & 2 deletions src-tauri/res/15_Tower_of_Ruin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ subWeapons:
- event:reachedFrontOfTowerOfRuin
chests:
djedPillar:
- event:reachedBackDoorOfTowerOfRuin, event:mulanaTalisman, ocarina # need to talk to sage in spring. need mulana talisman to get item
- event:reachedBackDoorOfTowerOfRuin, mulanaTalisman, ocarina # need to talk to sage in spring. need mulana talisman to get item
map:towerOfRuin:
- event:reachedFrontOfTowerOfRuin
sacredOrb:towerOfRuin:
Expand All @@ -16,7 +16,7 @@ shops:
- event:reachedFrontOfTowerOfRuin, katana, boots, grappleClaw # can reach with boots and grapple claw
roms:
ruinsRam16K:
- event:reachedGrailOfGateOfIllusion, event:miniDoll
- event:reachedGrailOfGateOfIllusion, miniDoll
hyperSports3:
- event:reachedFrontOfTowerOfRuin, iceCape
shinSynthesizer:
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/res/18_Dimensional_Corridor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ subWeapons:
- event:reachedDimensionalCorridor
chests:
magatamaJewel:
- event:defeatedTiamat, event:mulanaTalisman # need mulana talisman to get item
- event:defeatedTiamat, mulanaTalisman # need mulana talisman to get item
- option:glitch, event:defeatedTiamat, option:glitch, grappleClaw, bomb, bombAmmo # https://youtu.be/AtvFGL1-2x4
sacredOrb:dimensionalCorridor:
- event:reachedDimensionalCorridor, feather, lampOfTime, sacredOrb:2 # do not need grapple claw. should have some health to beat bosses
Expand Down
17 changes: 4 additions & 13 deletions src-tauri/res/events.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
# TODO: 基本セットが必要かどうかはフィールドで判断する
event:basicSet:
- handScanner, shellHorn, holyGrail, gameMaster, glyphReader
# TODO: unsupported events
event:miniDoll:
- event:reachedFrontOfGateOfIllusion, event:reachedGrailOfGateOfIllusion, handScanner, glyphReader
event:pepper:
- event:reachedFrontOfGateOfIllusion
event:anchor:
- event:reachedFrontOfGateOfIllusion, treasures
event:mulanaTalisman:
- diary
event:subWeaponWallForward: # some forward sub weapons for various things
- shuriken, shurikenAmmo
- pistol, ammunition
Expand Down Expand Up @@ -71,8 +62,8 @@ event:reachedFrontOfShrineOfTheMother:
event:reachedFrontOfGateOfIllusion:
- event:reachedGrailOfTempleOfMoonlight
event:reachedElevatorOfGateOfIllusion:
- event:anchor, knife, sacredOrb:1 # event:anchor already includes getting to Illusion
- event:anchor, knife, scalesphere # need health to survive water
- anchor, knife, sacredOrb:1 # event:anchor already includes getting to Illusion
- anchor, knife, scalesphere # need health to survive water
- option:glitch, event:reachedFrontOfGateOfIllusion # https://youtu.be/VQ3e1CJxx5c
event:reachedGrailOfGateOfIllusion:
- event:reachedElevatorOfGateOfIllusion
Expand Down Expand Up @@ -105,7 +96,7 @@ event:reachedGrailOfTempleOfMoonlight:
- flareGun, flareGunAmmo, feather, event:escapeFromTempleOfMoonlight
event:escapeFromTempleOfMoonlight:
- holyGrail
- event:defeatedAmphisbaena, event:anchor, knife, bronzeMirror
- event:defeatedAmphisbaena, anchor, knife, bronzeMirror
- event:defeatedSakit, bronzeMirror

event:reachedTowerOfTheGoddess:
Expand All @@ -114,7 +105,7 @@ event:reachedTowerOfTheGoddess:

event:reachedFrontOfTowerOfRuin:
- event:reachedFrontOfGraveyardOfTheGiants
- event:reachedGrailOfGateOfIllusion, event:miniDoll
- event:reachedGrailOfGateOfIllusion, miniDoll
event:reachedBackDoorOfTowerOfRuin:
- event:reachedBackDoorOfSurface, event:defeatedBaphomet # reachedBackDoorOfSurface already includes bronze mirror

Expand Down
21 changes: 18 additions & 3 deletions src-tauri/src/dataset/game_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use vec1::Vec1;
use crate::{
dataset::spot::SpotName,
script::enums::{
ChestItem, Equipment, FieldNumber, MainWeapon, Rom, Seal, ShopItem, SubWeapon,
ChestItem, Equipment, FieldNumber, MainWeapon, Rom, Seal, ShopItem, SubWeapon, TalkItem,
},
};

use super::spot::{
AllRequirements, AnyOfAllRequirements, ChestSpot, MainWeaponSpot, RequirementFlag, RomSpot,
SealSpot, ShopSpot, SubWeaponSpot,
SealSpot, ShopSpot, SubWeaponSpot, TalkSpot,
};

pub struct GameStructureFiles {
Expand Down Expand Up @@ -51,6 +51,8 @@ pub struct FieldYaml {
pub roms: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub shops: BTreeMap<String, Vec<String>>,
#[serde(default)]
pub talks: BTreeMap<String, Vec<String>>,
}

impl FieldYaml {
Expand Down Expand Up @@ -118,6 +120,7 @@ pub struct GameStructure {
pub seals: Vec<SealSpot>,
pub roadside_roms: Vec<RomSpot>,
pub shops: Vec<ShopSpot>,
pub talks: Vec<TalkSpot>,
pub events: Vec<Event>,
}

Expand All @@ -129,6 +132,7 @@ impl GameStructure {
let mut seals = Vec::new();
let mut roadside_roms = Vec::new();
let mut shops = Vec::new();
let mut talks = Vec::new();
game_structure_files
.fields
.sort_by_key(|(field_number, _)| *field_number as u8);
Expand Down Expand Up @@ -212,6 +216,16 @@ impl GameStructure {
let spot = ShopSpot::new(field_number, name, items, any_of_all_requirements);
shops.push(spot)
}
for (key, value) in field_data.talks {
let pascal_case = to_pascal_case(&key);
let item = Equipment::from_str(&pascal_case)
.map(TalkItem::Equipment)
.or_else(|_| Rom::from_str(&pascal_case).map(TalkItem::Rom))?;
let name = SpotName::new(key.clone());
let requirements = to_any_of_all_requirements(value)?;
let spot = TalkSpot::new(field_number, name, item, requirements);
talks.push(spot);
}
}
let events = parse_event_requirements(game_structure_files.events.0)?;

Expand All @@ -220,8 +234,9 @@ impl GameStructure {
sub_weapon_shutters,
chests,
seals,
shops,
roadside_roms,
shops,
talks,
events,
})
}
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/src/dataset/spot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod rom_spot;
mod seal_spot;
mod shop_spot;
mod sub_weapon_spot;
mod talk_spot;

pub use {
chest_spot::ChestSpot,
Expand All @@ -14,4 +15,5 @@ pub use {
seal_spot::SealSpot,
shop_spot::ShopSpot,
sub_weapon_spot::SubWeaponSpot,
talk_spot::TalkSpot,
};
38 changes: 38 additions & 0 deletions src-tauri/src/dataset/spot/talk_spot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use std::fmt;

use crate::script::enums::{FieldNumber, TalkItem};

use super::{params::SpotParams, AnyOfAllRequirements, SpotName};

#[derive(Clone, Debug)]
pub struct TalkSpot(SpotParams<TalkItem>);

impl TalkSpot {
pub fn new(
field_number: FieldNumber,
name: SpotName,
content: TalkItem,
requirements: Option<AnyOfAllRequirements>,
) -> Self {
Self(SpotParams::new(field_number, name, content, requirements))
}

pub fn field_number(&self) -> FieldNumber {
self.0.field_number
}
pub fn name(&self) -> &SpotName {
&self.0.name
}
pub fn item(&self) -> TalkItem {
self.0.content
}
pub fn requirements(&self) -> Option<&AnyOfAllRequirements> {
self.0.requirements.as_ref()
}
}

impl fmt::Display for TalkSpot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f, "Talk")
}
}
4 changes: 2 additions & 2 deletions src-tauri/src/randomizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::{
TRUE_SHRINE_OF_THE_MOTHER_SEAL_COUNT, WARE_NO_MISE_COUNT,
},
script::{
data::{object::Shop, script::Script},
data::{object::ItemShop, script::Script},
editor::add_starting_items::add_starting_items,
enums::Rom,
file::scriptconverter::{build_script_dat, read_script_dat},
Expand All @@ -40,7 +40,7 @@ pub fn assert_eq_elem_count(source: &Storage, script: &Script) {
shop_count,
script
.shops()
.filter_map(|x| Shop::try_from_shop_object(x, &script.talks).transpose())
.filter_map(|x| ItemShop::try_from_shop_object(x, &script.talks).transpose())
.collect::<Result<Vec<_>>>()
.unwrap()
.len()
Expand Down
33 changes: 30 additions & 3 deletions src-tauri/src/randomizer/randomize_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ fn create_shuffled_storage(source: &Storage, spoiler_log: &SpoilerLogRef) -> Sto
let content = rom.spot.rom();
storage.roms.get_mut(&content).unwrap().item = rom.item.clone();
}
CheckpointRef::Talk(talk) => {
let item = talk.spot.item();
storage
.talks
.iter_mut()
.find(|x| x.spot.item() == item)
.unwrap()
.item = talk.item.clone();
}
CheckpointRef::Event(_) => {}
}
}
Expand Down Expand Up @@ -183,7 +192,7 @@ mod tests {
use super::*;

#[tokio::test]
async fn test_shuffle() -> Result<()> {
async fn test_shuffle_hash() -> Result<()> {
let game_structure_files = read_game_structure_files_debug().await?;
let game_structure = GameStructure::new(game_structure_files)?;
let opts = RandomizeOptions {
Expand All @@ -197,14 +206,32 @@ mod tests {

let shuffled_str = format!("{:?}", shuffled);
let shuffled_hash = hex::encode(sha3::Sha3_512::digest(shuffled_str));
const EXPECTED_SHUFFLED_HASH: &str = "1c6e666d6773b780d1a1a6f9dfe3ee92e9e18ad2714a77e5499851c2eb3d573683cfb2d287ed9b03aad7a930d56c06a386fa30284dfe4bfd30eab17eb5fd5bf5";
const EXPECTED_SHUFFLED_HASH: &str = "1bceba2304dcf0ceb71d632345039861b74417141223d680c997907107e8aa840032d498628364eeeb92096b5b527adef352dab30019fdaeaf589a3db2396835";
assert_eq!(shuffled_hash, EXPECTED_SHUFFLED_HASH);

let spoiler_log_str = format!("{}", spoiler_log.to_owned());
let spoiler_log_hash = hex::encode(sha3::Sha3_512::digest(spoiler_log_str));
const EXPECTED_SPOILER_LOG_HASH: &str = "b385880c3fdf6022f0d4bbd23ccffa0444954bb93a018b49a0231073912c0086b307f5e6de2c9b79bba3e984f95d913ec4777f9af5630a388c99c441ab0034cf";
const EXPECTED_SPOILER_LOG_HASH: &str = "f62e4ddc8b2a649220dfc80901409ec3b06b835ea22105d1e9ac42d1bc5f4c700a49f3e4e0f9ea7a03b6346d59b1b024fba9cfbaae658ee73a5c34b839eff31f";
assert_eq!(spoiler_log_hash, EXPECTED_SPOILER_LOG_HASH);

Ok(())
}

#[tokio::test]
async fn test_shuffle_multi_patterns() -> Result<()> {
let game_structure_files = read_game_structure_files_debug().await?;
let game_structure = GameStructure::new(game_structure_files)?;
for i in 0..100 {
let opts = RandomizeOptions {
seed: i.to_string(),
shuffle_secret_roms: true,
need_glitches: false,
absolutely_shuffle: false,
};
let source = create_source(&game_structure, &opts)?;
let (_, _) = shuffle(&source, &opts);
}

Ok(())
}
}
25 changes: 15 additions & 10 deletions src-tauri/src/randomizer/spoiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ fn ptr_eq<'a>(a: SpotRef<'a>, b: &CheckpointRef<'a>) -> bool {
(SpotRef::SubWeapon(a), CheckpointRef::SubWeapon(b)) => ptr::eq(a, b.spot),
(SpotRef::Chest(a), CheckpointRef::Chest(b)) => ptr::eq(a, b.spot),
(SpotRef::Seal(a), CheckpointRef::Seal(b)) => ptr::eq(a, b.spot),
(SpotRef::Shop(a), CheckpointRef::Shop(b)) => ptr::eq(a, b.spot),
(SpotRef::Rom(a), CheckpointRef::Rom(b)) => ptr::eq(a, b.spot),
(SpotRef::Talk(a), CheckpointRef::Talk(b)) => ptr::eq(a, b.spot),
(SpotRef::Shop(a), CheckpointRef::Shop(b)) => ptr::eq(a, b.spot),
_ => false,
}
}
Expand Down Expand Up @@ -92,18 +93,10 @@ pub fn spoiler<'a>(
) -> Option<SpoilerLogRef<'a>> {
let start = std::time::Instant::now();
let mut rng = make_rng(seed);
let mut items_pool = items.to_items_pool(&mut rng, spots.shops.len());
let mut items_pool = items.to_items_pool(&mut rng, spots.talk_spots.len(), spots.shops.len());
let mut remaining_spots = spots.clone();
let maps = maps(&mut rng, items.maps(), &mut remaining_spots);

debug_assert_eq!(
items.priority_items().len()
+ items.unsellable_items().len()
+ items.consumable_items().len()
+ items.sellable_items().len(),
remaining_spots.field_item_spots.len() + remaining_spots.shops.len()
);

let mut strategy_flags: HashSet<&'a StrategyFlag> = Default::default();
let mut progression = Vec::new();

Expand All @@ -124,6 +117,18 @@ pub fn spoiler<'a>(
progression.push(sphere);

if !remaining_spots.is_empty() {
debug_assert_eq!(
remaining_spots.field_item_spots.len(),
items_pool.field_items.len(),
);
debug_assert_eq!(
remaining_spots.talk_spots.len(),
items_pool.talk_items.len(),
);
debug_assert_eq!(
remaining_spots.shops.len(),
items_pool.shop_items.len() + items_pool.consumable_items.len(),
);
continue;
}
info!("Sphere: {}, time: {:?}", i, start.elapsed());
Expand Down
Loading

0 comments on commit e7915e4

Please sign in to comment.