silkedit 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rbcli +0 -0
- data/CHANGELOG.md +7 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/LICENSE.txt +169 -0
- data/README.md +302 -0
- data/Rakefile +8 -0
- data/exe/silkedit +13 -0
- data/lib/commands/backup_restore.rb +25 -0
- data/lib/commands/cheat.rb +74 -0
- data/lib/commands/edit_diff.rb +47 -0
- data/lib/commands/examples/command.rb +51 -0
- data/lib/commands/examples/script.rb +36 -0
- data/lib/commands/journal.rb +34 -0
- data/lib/commands/permasave_permaload.rb +62 -0
- data/lib/commands/scripts/.keep +0 -0
- data/lib/commands/unpack_repack.rb +27 -0
- data/lib/commands/zone_mkzone.rb +103 -0
- data/lib/config/config.rb +28 -0
- data/lib/config/envvars.rb +23 -0
- data/lib/config/hooks.rb +22 -0
- data/lib/config/logger.rb +36 -0
- data/lib/config/parser.rb +34 -0
- data/lib/config/updatechecker.rb +12 -0
- data/lib/silkedit/cheats/cheatengine.rb +33 -0
- data/lib/silkedit/cheats/hollow_knight_cheats.rb +5 -0
- data/lib/silkedit/cheats/merger.rb +107 -0
- data/lib/silkedit/cheats/silksong_cheats.rb +161 -0
- data/lib/silkedit/cheats/silksong_enemyjournal.rb +120 -0
- data/lib/silkedit/cheats/silksong_zoner.rb +98 -0
- data/lib/silkedit/config/savegame.yaml +13 -0
- data/lib/silkedit/config/silkedit.yaml +6 -0
- data/lib/silkedit/config/silksong/cheatdata.yaml +1341 -0
- data/lib/silkedit/config/silksong/enemylist.yaml +1424 -0
- data/lib/silkedit/config/silksong/old.yaml +4345 -0
- data/lib/silkedit/config/silksong/permasaves.yaml +12 -0
- data/lib/silkedit/config/silksong/unfinished.yaml +628 -0
- data/lib/silkedit/config/silksong/zones.yaml +1738 -0
- data/lib/silkedit/images/.keep +0 -0
- data/lib/silkedit/images/silksong/Aknid.png +0 -0
- data/lib/silkedit/images/silksong/Alita.png +0 -0
- data/lib/silkedit/images/silksong/Barnak.png +0 -0
- data/lib/silkedit/images/silksong/Beastfly.png +0 -0
- data/lib/silkedit/images/silksong/Bell_Beast.png +0 -0
- data/lib/silkedit/images/silksong/Bell_Eater.png +0 -0
- data/lib/silkedit/images/silksong/Bloatroach.png +0 -0
- data/lib/silkedit/images/silksong/Broodmother.png +0 -0
- data/lib/silkedit/images/silksong/Brushflit.png +0 -0
- data/lib/silkedit/images/silksong/Burning_Bug.png +0 -0
- data/lib/silkedit/images/silksong/Caranid.png +0 -0
- data/lib/silkedit/images/silksong/Choir_Bellbearer.png +0 -0
- data/lib/silkedit/images/silksong/Choir_Clapper.png +0 -0
- data/lib/silkedit/images/silksong/Choir_Elder.png +0 -0
- data/lib/silkedit/images/silksong/Choir_Flyer.png +0 -0
- data/lib/silkedit/images/silksong/Choir_Hornhead.png +0 -0
- data/lib/silkedit/images/silksong/Choir_Pouncer.png +0 -0
- data/lib/silkedit/images/silksong/Choristor.png +0 -0
- data/lib/silkedit/images/silksong/Clawmaiden.png +0 -0
- data/lib/silkedit/images/silksong/Clover_Dancers.png +0 -0
- data/lib/silkedit/images/silksong/Cloverstag.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Choirbug.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Clapper.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Cleanser.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Crawler.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Dancers.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Defender.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Hauler.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Spine.png +0 -0
- data/lib/silkedit/images/silksong/Cogwork_Underfly.png +0 -0
- data/lib/silkedit/images/silksong/Cogworker.png +0 -0
- data/lib/silkedit/images/silksong/Conchfly.png +0 -0
- data/lib/silkedit/images/silksong/Coral_Furm.png +0 -0
- data/lib/silkedit/images/silksong/Corrcrust_Karaka.png +0 -0
- data/lib/silkedit/images/silksong/Covetous_Pilgrim.png +0 -0
- data/lib/silkedit/images/silksong/Craggler.png +0 -0
- data/lib/silkedit/images/silksong/Cragglite.png +0 -0
- data/lib/silkedit/images/silksong/Craw.png +0 -0
- data/lib/silkedit/images/silksong/Craw_Juror.png +0 -0
- data/lib/silkedit/images/silksong/Crawfather.png +0 -0
- data/lib/silkedit/images/silksong/Crust_King_Khann.png +0 -0
- data/lib/silkedit/images/silksong/Crustcrag.png +0 -0
- data/lib/silkedit/images/silksong/Crustcrawler.png +0 -0
- data/lib/silkedit/images/silksong/Deep_Diver.png +0 -0
- data/lib/silkedit/images/silksong/Disgraced_Chef_Lugoli.png +0 -0
- data/lib/silkedit/images/silksong/Drapefly.png +0 -0
- data/lib/silkedit/images/silksong/Drapelord.png +0 -0
- data/lib/silkedit/images/silksong/Drapemite.png +0 -0
- data/lib/silkedit/images/silksong/Dreg_Catcher.png +0 -0
- data/lib/silkedit/images/silksong/Dreg_Husk.png +0 -0
- data/lib/silkedit/images/silksong/Dregwheel.png +0 -0
- data/lib/silkedit/images/silksong/Driftlin.png +0 -0
- data/lib/silkedit/images/silksong/Driznarga.png +0 -0
- data/lib/silkedit/images/silksong/Driznit.png +0 -0
- data/lib/silkedit/images/silksong/Ductsucker.png +0 -0
- data/lib/silkedit/images/silksong/Elder_Pilgrim.png +0 -0
- data/lib/silkedit/images/silksong/Envoy.png +0 -0
- data/lib/silkedit/images/silksong/Escalion.png +0 -0
- data/lib/silkedit/images/silksong/Father_of_the_Flame.png +0 -0
- data/lib/silkedit/images/silksong/Fertid.png +0 -0
- data/lib/silkedit/images/silksong/First_Sinner.png +0 -0
- data/lib/silkedit/images/silksong/Flapping_Fertid.png +0 -0
- data/lib/silkedit/images/silksong/Flintbeetle.png +0 -0
- data/lib/silkedit/images/silksong/Flintflame_Flyer.png +0 -0
- data/lib/silkedit/images/silksong/Flintstone_Flyer.png +0 -0
- data/lib/silkedit/images/silksong/Fluttermite.png +0 -0
- data/lib/silkedit/images/silksong/Forebrothers_Signis_&_Gron.png +0 -0
- data/lib/silkedit/images/silksong/Fourth_Chorus.png +0 -0
- data/lib/silkedit/images/silksong/Freshfly.png +0 -0
- data/lib/silkedit/images/silksong/Furm.png +0 -0
- data/lib/silkedit/images/silksong/Gahlia.png +0 -0
- data/lib/silkedit/images/silksong/Gargant_Gloom.png +0 -0
- data/lib/silkedit/images/silksong/Garpid.png +0 -0
- data/lib/silkedit/images/silksong/Giant_Drapemite.png +0 -0
- data/lib/silkedit/images/silksong/Gloomsac.png +0 -0
- data/lib/silkedit/images/silksong/Grand_Mother_Silk.png +0 -0
- data/lib/silkedit/images/silksong/Grand_Reed.png +0 -0
- data/lib/silkedit/images/silksong/Great_Conchfly.png +0 -0
- data/lib/silkedit/images/silksong/Groal_the_Great.png +0 -0
- data/lib/silkedit/images/silksong/Grom.png +0 -0
- data/lib/silkedit/images/silksong/Gromling.png +0 -0
- data/lib/silkedit/images/silksong/Guardfly.png +0 -0
- data/lib/silkedit/images/silksong/Gurr_the_Outcast.png +0 -0
- data/lib/silkedit/images/silksong/Hardbone_Elder.png +0 -0
- data/lib/silkedit/images/silksong/Hardbone_Hopper.png +0 -0
- data/lib/silkedit/images/silksong/Hoker.png +0 -0
- data/lib/silkedit/images/silksong/Huge_Flea.png +0 -0
- data/lib/silkedit/images/silksong/Imoba.png +0 -0
- data/lib/silkedit/images/silksong/Judge.png +0 -0
- data/lib/silkedit/images/silksong/Kai.png +0 -0
- data/lib/silkedit/images/silksong/Kakri.png +0 -0
- data/lib/silkedit/images/silksong/Karak_Gor.png +0 -0
- data/lib/silkedit/images/silksong/Karaka.png +0 -0
- data/lib/silkedit/images/silksong/Kilik.png +0 -0
- data/lib/silkedit/images/silksong/Kindanir.png +0 -0
- data/lib/silkedit/images/silksong/Lace.png +0 -0
- data/lib/silkedit/images/silksong/Lampbearer.png +0 -0
- data/lib/silkedit/images/silksong/Last_Claw.png +0 -0
- data/lib/silkedit/images/silksong/Last_Judge.png +0 -0
- data/lib/silkedit/images/silksong/Lavalarga.png +0 -0
- data/lib/silkedit/images/silksong/Lavalug.png +0 -0
- data/lib/silkedit/images/silksong/Leaf_Glider.png +0 -0
- data/lib/silkedit/images/silksong/Leaf_Roller.png +0 -0
- data/lib/silkedit/images/silksong/Lost_Garmond.png +0 -0
- data/lib/silkedit/images/silksong/Lost_Lace.png +0 -0
- data/lib/silkedit/images/silksong/Maestro.png +0 -0
- data/lib/silkedit/images/silksong/Marrowmaw.png +0 -0
- data/lib/silkedit/images/silksong/Massive_Mossgrub.png +0 -0
- data/lib/silkedit/images/silksong/Mawling.png +0 -0
- data/lib/silkedit/images/silksong/Memoria.png +0 -0
- data/lib/silkedit/images/silksong/Minister.png +0 -0
- data/lib/silkedit/images/silksong/Miremite.png +0 -0
- data/lib/silkedit/images/silksong/Mite.png +0 -0
- data/lib/silkedit/images/silksong/Mitemother.png +0 -0
- data/lib/silkedit/images/silksong/Mnemonid.png +0 -0
- data/lib/silkedit/images/silksong/Mnemonord.png +0 -0
- data/lib/silkedit/images/silksong/Moorwing.png +0 -0
- data/lib/silkedit/images/silksong/Mortician.png +0 -0
- data/lib/silkedit/images/silksong/Moss_Mother.png +0 -0
- data/lib/silkedit/images/silksong/Mossgrub.png +0 -0
- data/lib/silkedit/images/silksong/Mossmir.png +0 -0
- data/lib/silkedit/images/silksong/Mothleaf_Lagnia.png +0 -0
- data/lib/silkedit/images/silksong/Muckmaggot.png +0 -0
- data/lib/silkedit/images/silksong/Muckroach.png +0 -0
- data/lib/silkedit/images/silksong/Nuphar.png +0 -0
- data/lib/silkedit/images/silksong/Nyleth.png +0 -0
- data/lib/silkedit/images/silksong/Overgrown_Pilgrim.png +0 -0
- data/lib/silkedit/images/silksong/Palestag.png +0 -0
- data/lib/silkedit/images/silksong/Pendra.png +0 -0
- data/lib/silkedit/images/silksong/Pendragor.png +0 -0
- data/lib/silkedit/images/silksong/Penitent.png +0 -0
- data/lib/silkedit/images/silksong/Phacia.png +0 -0
- data/lib/silkedit/images/silksong/Phantom.png +0 -0
- data/lib/silkedit/images/silksong/Pharlid.png +0 -0
- data/lib/silkedit/images/silksong/Pharlid_Diver.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Bellbearer.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Groveller.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Guide.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Hiker.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Hornfly.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Hulk.png +0 -0
- data/lib/silkedit/images/silksong/Pilgrim_Pouncer.png +0 -0
- data/lib/silkedit/images/silksong/Pinstress.png +0 -0
- data/lib/silkedit/images/silksong/Plasmid.png +0 -0
- data/lib/silkedit/images/silksong/Plasmidas.png +0 -0
- data/lib/silkedit/images/silksong/Plasmified_Zango.png +0 -0
- data/lib/silkedit/images/silksong/Pokenabbin.png +0 -0
- data/lib/silkedit/images/silksong/Pollenica.png +0 -0
- data/lib/silkedit/images/silksong/Pond_Skipper.png +0 -0
- data/lib/silkedit/images/silksong/Pondcatcher.png +0 -0
- data/lib/silkedit/images/silksong/Puny_Penitent.png +0 -0
- data/lib/silkedit/images/silksong/Reed.png +0 -0
- data/lib/silkedit/images/silksong/Rhinogrund.png +0 -0
- data/lib/silkedit/images/silksong/Roachcatcher.png +0 -0
- data/lib/silkedit/images/silksong/Roachfeeder.png +0 -0
- data/lib/silkedit/images/silksong/Roachkeeper.png +0 -0
- data/lib/silkedit/images/silksong/Roachserver.png +0 -0
- data/lib/silkedit/images/silksong/Sandcarver.png +0 -0
- data/lib/silkedit/images/silksong/Savage_Beastfly.png +0 -0
- data/lib/silkedit/images/silksong/Scabfly.png +0 -0
- data/lib/silkedit/images/silksong/Scrollreader.png +0 -0
- data/lib/silkedit/images/silksong/Second_Sentinel.png +0 -0
- data/lib/silkedit/images/silksong/Servitor_Boran.png +0 -0
- data/lib/silkedit/images/silksong/Servitor_Ignim.png +0 -0
- data/lib/silkedit/images/silksong/Shadow_Charger.png +0 -0
- data/lib/silkedit/images/silksong/Shadow_Creeper_(Silksong).png +0 -0
- data/lib/silkedit/images/silksong/Shardillard.png +0 -0
- data/lib/silkedit/images/silksong/Shellwood_Gnat.png +0 -0
- data/lib/silkedit/images/silksong/Shrine_Guardian_Seth.png +0 -0
- data/lib/silkedit/images/silksong/Silk_Snipper.png +0 -0
- data/lib/silkedit/images/silksong/Sister_Splinter.png +0 -0
- data/lib/silkedit/images/silksong/Skarr_Scout.png +0 -0
- data/lib/silkedit/images/silksong/Skarr_Stalker.png +0 -0
- data/lib/silkedit/images/silksong/Skarrgard.png +0 -0
- data/lib/silkedit/images/silksong/Skarrlid.png +0 -0
- data/lib/silkedit/images/silksong/Skarrsinger_Karmelita.png +0 -0
- data/lib/silkedit/images/silksong/Skarrwing.png +0 -0
- data/lib/silkedit/images/silksong/Skrill.png +0 -0
- data/lib/silkedit/images/silksong/Skull_Brute.png +0 -0
- data/lib/silkedit/images/silksong/Skull_Scuttler.png +0 -0
- data/lib/silkedit/images/silksong/Skull_Tyrant.png +0 -0
- data/lib/silkedit/images/silksong/Skullwing.png +0 -0
- data/lib/silkedit/images/silksong/Slubberlug.png +0 -0
- data/lib/silkedit/images/silksong/Smelt_Shoveller.png +0 -0
- data/lib/silkedit/images/silksong/Smokerock_Sifter.png +0 -0
- data/lib/silkedit/images/silksong/Snitchfly.png +0 -0
- data/lib/silkedit/images/silksong/Spear_Skarr.png +0 -0
- data/lib/silkedit/images/silksong/Spinebeak_Kai.png +0 -0
- data/lib/silkedit/images/silksong/Spit_Squit.png +0 -0
- data/lib/silkedit/images/silksong/Splinter.png +0 -0
- data/lib/silkedit/images/silksong/Splinterbark.png +0 -0
- data/lib/silkedit/images/silksong/Splinterhorn.png +0 -0
- data/lib/silkedit/images/silksong/Squatcraw.png +0 -0
- data/lib/silkedit/images/silksong/Squatcraw_Juror.png +0 -0
- data/lib/silkedit/images/silksong/Squirrm.png +0 -0
- data/lib/silkedit/images/silksong/Steelspine_Kai.png +0 -0
- data/lib/silkedit/images/silksong/Stilkin.png +0 -0
- data/lib/silkedit/images/silksong/Stilkin_Trapper.png +0 -0
- data/lib/silkedit/images/silksong/Summoned_Saviour.png +0 -0
- data/lib/silkedit/images/silksong/Surgeon.png +0 -0
- data/lib/silkedit/images/silksong/Swamp_Squit.png +0 -0
- data/lib/silkedit/images/silksong/Tallcraw.png +0 -0
- data/lib/silkedit/images/silksong/Tallcraw_Juror.png +0 -0
- data/lib/silkedit/images/silksong/Tarmite.png +0 -0
- data/lib/silkedit/images/silksong/The_Unravelled.png +0 -0
- data/lib/silkedit/images/silksong/Thread_Raker.png +0 -0
- data/lib/silkedit/images/silksong/Tormented_Trobbio.png +0 -0
- data/lib/silkedit/images/silksong/Trobbio.png +0 -0
- data/lib/silkedit/images/silksong/Undercrank.png +0 -0
- data/lib/silkedit/images/silksong/Underloft.png +0 -0
- data/lib/silkedit/images/silksong/Underpoke.png +0 -0
- data/lib/silkedit/images/silksong/Underscrub.png +0 -0
- data/lib/silkedit/images/silksong/Undersweep.png +0 -0
- data/lib/silkedit/images/silksong/Underworker.png +0 -0
- data/lib/silkedit/images/silksong/Vaultborn.png +0 -0
- data/lib/silkedit/images/silksong/Vaultkeeper.png +0 -0
- data/lib/silkedit/images/silksong/Verdanir.png +0 -0
- data/lib/silkedit/images/silksong/Vicious_Caranid.png +0 -0
- data/lib/silkedit/images/silksong/Void_Mass.png +0 -0
- data/lib/silkedit/images/silksong/Void_Tendrils_(Silksong).png +0 -0
- data/lib/silkedit/images/silksong/Voltvyrm.png +0 -0
- data/lib/silkedit/images/silksong/Wardenfly.png +0 -0
- data/lib/silkedit/images/silksong/Watcher_at_the_Edge.png +0 -0
- data/lib/silkedit/images/silksong/Widow.png +0 -0
- data/lib/silkedit/images/silksong/Winged_Furm.png +0 -0
- data/lib/silkedit/images/silksong/Winged_Lifeseed.png +0 -0
- data/lib/silkedit/images/silksong/Winged_Pilgrim.png +0 -0
- data/lib/silkedit/images/silksong/Winged_Pilgrim_Bellbearer.png +0 -0
- data/lib/silkedit/images/silksong/Wingmould_(Silksong).png +0 -0
- data/lib/silkedit/images/silksong/Wisp.png +0 -0
- data/lib/silkedit/images/silksong/Wood_Wasp.png +0 -0
- data/lib/silkedit/images/silksong/Wraith.png +0 -0
- data/lib/silkedit/images/silksong/Yago.png +0 -0
- data/lib/silkedit/images/silksong/Yuma.png +0 -0
- data/lib/silkedit/images/silksong/Yumama.png +0 -0
- data/lib/silkedit/savegame/crypto.rb +25 -0
- data/lib/silkedit/savegame/diff.rb +159 -0
- data/lib/silkedit/savegame/packer.rb +75 -0
- data/lib/silkedit/savegame/savefile.rb +157 -0
- data/lib/silkedit/util/system.rb +37 -0
- data/lib/silkedit/version.rb +5 -0
- data/lib/silkedit.rb +9 -0
- data/sig/silkedit.rbs +4 -0
- metadata +505 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Silkedit::Cheat
|
|
2
|
+
class Engine
|
|
3
|
+
def initialize(savedata)
|
|
4
|
+
@data = savedata
|
|
5
|
+
game = detect_game(@data)
|
|
6
|
+
@modules = %w[Cheats Zoner Journaler].map { |type| [type, Silkedit::Cheat.const_get("#{game}#{type}")]}.to_h
|
|
7
|
+
@modules.each_value { |mod| self.extend(mod) }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def apply_cheat(cheat, *args)
|
|
11
|
+
return :no_cheat unless cheat_exists?(cheat.to_s)
|
|
12
|
+
self.send(cheat.to_sym, *args)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply_cheats(cheats)
|
|
16
|
+
cheats.map { |cheat| apply_cheat(cheat) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def list_cheats
|
|
20
|
+
@modules['Cheats'].instance_methods.map(&:to_s).sort
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def cheat_exists?(cheat)
|
|
24
|
+
list_cheats.include?(cheat)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def detect_game(data = nil)
|
|
30
|
+
(data || @data).key?('firstGeo') ? 'HollowKnight' : 'Silksong'
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Silkedit::Cheat
|
|
2
|
+
def self.merge_cheat(data, cheat, should_merge_arrays: true, force_soft_reqs: false, enforce_min_act: false)
|
|
3
|
+
# 1. Check act requirement
|
|
4
|
+
game_act = self.get_game_act(data)
|
|
5
|
+
Rbcli.log.debug "Game act is #{game_act}, required act is #{cheat['min_act']}", 'CHEATS'
|
|
6
|
+
return :failed_act_check if enforce_min_act && cheat.key?('min_act') && game_act < cheat['min_act']
|
|
7
|
+
|
|
8
|
+
# 2. Check hard reqs and abort if not met
|
|
9
|
+
if cheat.key?('hard_reqs') && !cheat['hard_reqs'].nil? && !cheat['hard_reqs'].empty?
|
|
10
|
+
return :failed_hard_reqs unless verify_hash(data, cheat['hard_reqs'])
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# 3. Check soft reqs, and either queue them to be applied or abort
|
|
14
|
+
queue_soft_reqs = false
|
|
15
|
+
if cheat.key?('soft_reqs') && !cheat['soft_reqs'].nil? && !cheat['soft_reqs'].empty?
|
|
16
|
+
unless verify_hash(data, cheat['soft_reqs'])
|
|
17
|
+
return :failed_soft_reqs unless force_soft_reqs
|
|
18
|
+
queue_soft_reqs = true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# 4. Apply cheat
|
|
23
|
+
self.merge_hash(data, cheat['soft_reqs'], should_merge_arrays: true) if queue_soft_reqs
|
|
24
|
+
self.merge_hash(data, cheat['data'], should_merge_arrays: should_merge_arrays)
|
|
25
|
+
:success
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.merge_hash(data, cheat, should_merge_arrays: true)
|
|
29
|
+
cheat.each_key do |k|
|
|
30
|
+
if cheat[k].is_a?(Hash) && data[k].is_a?(Hash)
|
|
31
|
+
merge_hash(data[k], cheat[k])
|
|
32
|
+
elsif should_merge_arrays && cheat[k].is_a?(Array) && data[k].is_a?(Array)
|
|
33
|
+
if cheat[k][0].is_a?(Hash)
|
|
34
|
+
data[k] = merge_arrays_by_hash_keys(data[k], cheat[k])
|
|
35
|
+
else
|
|
36
|
+
data[k].merge!(cheat[k])
|
|
37
|
+
data[k].uniq!
|
|
38
|
+
end
|
|
39
|
+
else
|
|
40
|
+
data[k] = cheat[k]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
true
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.merge_arrays_by_hash_keys(data, cheat)
|
|
47
|
+
return data unless data.is_a?(Array) && cheat.is_a?(Array) && cheat.first.is_a?(Hash)
|
|
48
|
+
if data.empty?
|
|
49
|
+
data = cheat
|
|
50
|
+
return data
|
|
51
|
+
end
|
|
52
|
+
# First determine the primary key(s) for the object
|
|
53
|
+
pkeys = []
|
|
54
|
+
[%w[Name], %w[SceneName ID]].each do |pkey_arr|
|
|
55
|
+
pkeys = pkey_arr if pkey_arr.all? { |k| data.first.key?(k) || cheat.first.key?(k) }
|
|
56
|
+
end
|
|
57
|
+
cheat.each do |c|
|
|
58
|
+
idx = data.find_index { |d| d.is_a?(Hash) && pkeys.all? { |k| d.key?(k) && d[k] == c[k] } }
|
|
59
|
+
if idx
|
|
60
|
+
self.merge_hash(data[idx], c, should_merge_arrays: true)
|
|
61
|
+
else
|
|
62
|
+
data << c
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
data
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.verify_hash(data, reqs)
|
|
69
|
+
reqs.each_key do |k|
|
|
70
|
+
if reqs[k].is_a?(Hash) && data[k].is_a?(Hash)
|
|
71
|
+
return false unless verify_hash(data[k], reqs[k])
|
|
72
|
+
elsif reqs[k].is_a?(Array) && data[k].is_a?(Array)
|
|
73
|
+
if reqs[k].first.is_a?(Hash)
|
|
74
|
+
return false unless verify_array_of_hashes(data[k], reqs[k])
|
|
75
|
+
else
|
|
76
|
+
return false unless reqs[k].all? { |r| data[k].include?(r) }
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
return false unless data[k] == reqs[k]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
true
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.verify_array_of_hashes(data, reqs)
|
|
86
|
+
# First determine the primary key(s) for the object
|
|
87
|
+
pkeys = []
|
|
88
|
+
[%w[Name], %w[SceneName ID]].each do |pkey_arr|
|
|
89
|
+
pkeys = pkey_arr if pkey_arr.all? { |k| data.first.key?(k) || reqs.first.key?(k) }
|
|
90
|
+
end
|
|
91
|
+
reqs.each do |r|
|
|
92
|
+
idx = data.find_index { |d| d.is_a?(Hash) && pkeys.all? { |k| d.key?(k) && d[k] == r[k] } }
|
|
93
|
+
return false unless idx && self.verify_hash(data[idx], r)
|
|
94
|
+
end
|
|
95
|
+
true
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def self.get_game_act(data)
|
|
99
|
+
if %w[act3MapUpdated act3_wokeup].any? { |c| data['playerData'][c] }
|
|
100
|
+
3
|
|
101
|
+
elsif %w[act2started visitedCitadel defeatedLastJudge].any? { |c| data['playerData'][c] }
|
|
102
|
+
2
|
|
103
|
+
else
|
|
104
|
+
1
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module Silkedit::Cheat
|
|
4
|
+
module SilksongCheats
|
|
5
|
+
@cheatdata = YAML.safe_load_file(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'cheatdata.yaml'), symbolize_names: false)
|
|
6
|
+
@cheatdata['cheats'].each do |cheat, cht_data|
|
|
7
|
+
next if self.instance_methods.include?(cheat.to_sym)
|
|
8
|
+
self.define_method(cheat.to_sym) do
|
|
9
|
+
Rbcli.log.info "Applying cheat #{cheat}", 'CHEATS'
|
|
10
|
+
Silkedit::Cheat.merge_cheat(@data, cht_data, should_merge_arrays: true)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def unkill
|
|
15
|
+
Rbcli.log.info 'Reviving from death', 'CHEATS'
|
|
16
|
+
if @data['playerData']['permadeathMode'] == 2
|
|
17
|
+
@data['playerData']['permadeathMode'] = 1
|
|
18
|
+
end
|
|
19
|
+
@data['playerData']['geo'] += @data['playerData']['HeroCorpseMoneyPool']
|
|
20
|
+
@data['playerData']['HeroDeathScenePos'] = { 'x' => 0.0, 'y' => 0.0 }
|
|
21
|
+
@data['playerData']['HeroDeathSceneSize'] = { 'x' => 0.0, 'y' => 0.0 }
|
|
22
|
+
@data['playerData']['HeroCorpseType'] = 0
|
|
23
|
+
@data['playerData']['HeroCorpseMoneyPool'] = 0
|
|
24
|
+
@data['playerData']['hazardRespawnFacing'] = 0
|
|
25
|
+
@data['playerData']['IsSilkSpoolBroken'] = false
|
|
26
|
+
@data['playerData'].delete('HeroCorpseMarkerGuid')
|
|
27
|
+
@data['playerData'].delete('HeroCorpseScene')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def refresh
|
|
31
|
+
self.max_shards
|
|
32
|
+
self.max_liquids
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def max_everything
|
|
36
|
+
backup_data = @data.dup
|
|
37
|
+
result = %w[
|
|
38
|
+
max_health
|
|
39
|
+
max_silk
|
|
40
|
+
max_weapon
|
|
41
|
+
max_tool_upgrades
|
|
42
|
+
max_liquids
|
|
43
|
+
all_abilities
|
|
44
|
+
all_crests
|
|
45
|
+
all_crest_unlocks
|
|
46
|
+
all_eva_upgrades
|
|
47
|
+
all_spells
|
|
48
|
+
all_tools
|
|
49
|
+
give_consumables
|
|
50
|
+
max_rosaries
|
|
51
|
+
max_shards
|
|
52
|
+
].map { |cht| self.send(cht.to_sym) }
|
|
53
|
+
if result.all?(:success)
|
|
54
|
+
:success
|
|
55
|
+
else
|
|
56
|
+
@data = backup_data
|
|
57
|
+
result.reject { |r| r == :success }.first
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def max_shards
|
|
62
|
+
Rbcli.log.info 'Applying cheat max_shards', 'CHEATS'
|
|
63
|
+
@data['playerData']['ShellShards'] = 400 + (@data['playerData']['ToolPouchUpgrades'] || 0) * 100
|
|
64
|
+
:success
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def all_crests
|
|
68
|
+
cheatdata = Silkedit::Cheat::SilksongCheats.module_eval { @cheatdata }
|
|
69
|
+
Rbcli.log.info "Applying cheat all_crests", 'CHEATS'
|
|
70
|
+
Silkedit::Cheat.merge_cheat(@data, cheatdata['reference']['all_crests'], should_merge_arrays: true)
|
|
71
|
+
%w[CurrentCrestID PreviousCrestID].each do |equip|
|
|
72
|
+
%w[Hunter Hunter_v2].each do |hunter_crest_version|
|
|
73
|
+
@data['playerData'][equip] = 'Hunter_v3' if @data['playerData'][equip] == hunter_crest_version
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
:success
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def all_crest_unlocks
|
|
80
|
+
Rbcli.log.info 'Applying cheat all_crest_unlocks', 'CHEATS'
|
|
81
|
+
cheatdata = Silkedit::Cheat::SilksongCheats.module_eval { @cheatdata }
|
|
82
|
+
@data['playerData']['ToolEquips']['savedData'].each do |crest|
|
|
83
|
+
if crest['Data']['Slots'].nil? || crest['Data']['Slots'].empty?
|
|
84
|
+
newcrest = cheatdata['reference']['full_crests']['playerData']['ToolEquips']['savedData'].find { |c| c['Name'] == crest['Name'] }
|
|
85
|
+
next if newcrest.nil?
|
|
86
|
+
crest['Data'] = {} if crest['Data'].nil?
|
|
87
|
+
crest['Data']['Slots'] = newcrest['Data']['Slots'] if newcrest.key?('Data') && newcrest['Data'].key?('Slots')
|
|
88
|
+
end
|
|
89
|
+
crest['Data']['Slots'].each { |slot| slot['IsUnlocked'] = true }
|
|
90
|
+
end
|
|
91
|
+
:success
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def overcharge_tools
|
|
95
|
+
Rbcli.log.info "Applying cheat overcharge_tools", 'CHEATS'
|
|
96
|
+
@data['playerData']['Tools']['savedData'].each do |tool|
|
|
97
|
+
tool['Data']['AmountLeft'] = 1000
|
|
98
|
+
end
|
|
99
|
+
:success
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def toggle_map_reveal
|
|
103
|
+
@data['playerData']['mapAllRooms'] = !@data['playerData']['mapAllRooms']
|
|
104
|
+
Rbcli.log.info "Full map reveal is #{@data['playerData']['mapAllRooms'] ? 'enabled' : 'disabled'}", 'CHEATS'
|
|
105
|
+
:success
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def toggle_flea_reveal
|
|
109
|
+
flea_keys = @data['playerData'].keys.select { |k| k.start_with?('hasPinFlea') }
|
|
110
|
+
is_enabled = flea_keys.all? { |k| @data['playerData'][k] }
|
|
111
|
+
flea_keys.each { |k| @data[k] = !is_enabled }
|
|
112
|
+
Rbcli.log.info "Flea locations are #{is_enabled ? 'hidden' : 'revealed'} on map", 'CHEATS'
|
|
113
|
+
:success
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def toggle_cloakless
|
|
117
|
+
if @data['playerData']['CurrentCrestID'] != 'Cloakless'
|
|
118
|
+
Rbcli.log.info 'Going cloakless', 'CHEATS'
|
|
119
|
+
@data['playerData']['TempGeoStore'] = @data['playerData']['geo']
|
|
120
|
+
@data['playerData']['geo'] = 0
|
|
121
|
+
@data['playerData']['TempShellShardStore'] = @data['playerData']['ShellShards']
|
|
122
|
+
@data['playerData']['ShellShards'] = 0
|
|
123
|
+
@data['playerData']['PreviousCrestID'] = @data['playerData']['CurrentCrestID']
|
|
124
|
+
@data['playerData']['CurrentCrestID'] = 'Cloakless'
|
|
125
|
+
@data['playerData']['slab_cloak_battle_encountered'] = false
|
|
126
|
+
@data['playerData']['slab_cloak_battle_completed'] = false
|
|
127
|
+
@data['playerData']['IsSilkSpoolBroken'] = true
|
|
128
|
+
unless @data['playerData']['ToolEquips']['savedData'].find { |e| e['Name'] == 'Cloakless' }
|
|
129
|
+
cheatdata = Silkedit::Cheat::SilksongCheats.module_eval { @cheatdata }
|
|
130
|
+
@data['playerData']['ToolEquips']['savedData'].append(cheatdata['reference']['cloakless']['playerData']['ToolEquips']['savedData'].first)
|
|
131
|
+
end
|
|
132
|
+
else
|
|
133
|
+
Rbcli.log.info 'Recovering cloak', 'CHEATS'
|
|
134
|
+
@data['playerData']['geo'] = @data['playerData']['TempGeoStore']
|
|
135
|
+
@data['playerData']['TempGeoStore'] = 0
|
|
136
|
+
@data['playerData']['ShellShards'] = @data['playerData']['TempShellShardStore']
|
|
137
|
+
@data['playerData']['TempShellShardStore'] = 0
|
|
138
|
+
@data['playerData']['CurrentCrestID'] = @data['playerData']['PreviousCrestID']
|
|
139
|
+
@data['playerData']['PreviousCrestID'] = 'Cloakless'
|
|
140
|
+
# @data['playerData']['slab_cloak_battle_encountered'] = true
|
|
141
|
+
# @data['playerData']['slab_cloak_battle_completed'] = true
|
|
142
|
+
@data['playerData']['IsSilkSpoolBroken'] = false
|
|
143
|
+
end
|
|
144
|
+
:success
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def toggle_permadeath_mode
|
|
148
|
+
toggle = @data['playerData']['permadeathMode'] == 0
|
|
149
|
+
Rbcli.log.info "Toggling permadeath mode #{toggle ? 'ON' : 'OFF'}", 'CHEATS'
|
|
150
|
+
@data['playerData']['permadeathMode'] = toggle ? 1 : 0
|
|
151
|
+
:success
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def toggle_fly_mode
|
|
155
|
+
toggle = @data['playerData']['infiniteAirJump'] == false
|
|
156
|
+
Rbcli.log.info "Toggling fly mode #{toggle ? 'ON' : 'OFF'}", 'CHEATS'
|
|
157
|
+
@data['playerData']['infiniteAirJump'] = toggle ? true : false
|
|
158
|
+
:success
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require 'open-uri'
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
|
|
4
|
+
module Silkedit::Cheat
|
|
5
|
+
module SilksongJournaler
|
|
6
|
+
@enemylist = YAML.safe_load_file(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'enemylist.yaml'), symbolize_names: false)
|
|
7
|
+
|
|
8
|
+
def update_journal(should_update_kills_only: true)
|
|
9
|
+
enemylist = Silkedit::Cheat::SilksongJournaler.module_eval { @enemylist }
|
|
10
|
+
Rbcli.log.info 'Applying ', 'JOURNAL'
|
|
11
|
+
enemylist['playerData']['EnemyJournalKillData']['list'].sort_by { |known_enemy| known_enemy['Position']}.each do |known_enemy|
|
|
12
|
+
sleep 0.01
|
|
13
|
+
player_enemy = @data['playerData']['EnemyJournalKillData']['list'].find { |i| i['Name'] == known_enemy['Name'] }
|
|
14
|
+
self.display_enemy(known_enemy, player_enemy, show_images: false)
|
|
15
|
+
if player_enemy.nil?
|
|
16
|
+
if should_update_kills_only
|
|
17
|
+
Rbcli.log.info " Not Seen. Skipping.".colorize(:grey)
|
|
18
|
+
else
|
|
19
|
+
new_entry = {
|
|
20
|
+
'Name' => known_enemy['Name'],
|
|
21
|
+
'Record' => {
|
|
22
|
+
'Kills' => known_enemy['Record']['Kills'],
|
|
23
|
+
'HasBeenSeen' => false
|
|
24
|
+
} }
|
|
25
|
+
@data['playerData']['EnemyJournalKillData']['list'].append(new_entry)
|
|
26
|
+
Rbcli.log.info " Added to journal.".colorize(:magenta)
|
|
27
|
+
end
|
|
28
|
+
elsif player_enemy['Record']['Kills'] < known_enemy['Record']['Kills']
|
|
29
|
+
next if (known_enemy['Record']['Kills'] < 10) && !Silkedit::Sys.yes_no?(" Set #{known_enemy['GameName'].colorize(:blue)} kills from #{player_enemy['Record']['Kills'].to_s.colorize(:red)} to #{known_enemy['Record']['Kills'].to_s.colorize(:green)}?")
|
|
30
|
+
player_enemy['Record']['Kills'] = known_enemy['Record']['Kills']
|
|
31
|
+
player_enemy['Record']['HasBeenSeen'] = true
|
|
32
|
+
Rbcli.log.info " Updated kills.".colorize(:cyan)
|
|
33
|
+
else
|
|
34
|
+
Rbcli.log.info " Already Completed.".colorize(:green)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def enemy_list(only_missing: false, show_images: false)
|
|
40
|
+
enemylist = Silkedit::Cheat::SilksongJournaler.module_eval { @enemylist }
|
|
41
|
+
enemylist['playerData']['EnemyJournalKillData']['list'].sort_by { |known_enemy| known_enemy['Position']}.each do |known_enemy|
|
|
42
|
+
player_enemy = @data['playerData']['EnemyJournalKillData']['list'].find { |i| i['Name'] == known_enemy['Name'] }
|
|
43
|
+
left = player_enemy.nil? ? known_enemy['Record']['Kills'] : known_enemy['Record']['Kills'] - player_enemy['Record']['Kills']
|
|
44
|
+
left = 0 if left < 0
|
|
45
|
+
next if only_missing && left <= 0
|
|
46
|
+
self.display_enemy(known_enemy, player_enemy, show_images: show_images)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def display_enemy(known_enemy, player_enemy, show_images: false)
|
|
53
|
+
self.show_enemy_image(known_enemy['GameName']) if show_images
|
|
54
|
+
left = player_enemy.nil? ? known_enemy['Record']['Kills'] : known_enemy['Record']['Kills'] - player_enemy['Record']['Kills']
|
|
55
|
+
left = 0 if left < 0
|
|
56
|
+
e_complete = left <= 0 ? '*'.colorize(:cyan) : ' '
|
|
57
|
+
e_number = known_enemy['Position'].to_s.rjust(3)
|
|
58
|
+
e_name = known_enemy['GameName'].ljust(27).colorize(:blue).bold
|
|
59
|
+
e_seen = player_enemy.nil? ? 'N'.colorize(:red) : 'Y'.colorize(:green)
|
|
60
|
+
e_kills = (player_enemy.nil? ? 0 : player_enemy['Record']['Kills']).to_s.rjust(4).colorize(:green)
|
|
61
|
+
e_req = known_enemy['Record']['Kills'].to_s.rjust(4).colorize(:blue)
|
|
62
|
+
e_need = left.to_s.rjust(4).colorize(left <= 0 ? :cyan : :red)
|
|
63
|
+
Rbcli.log.info "#{e_number}. #{e_complete} #{e_name} Seen? #{e_seen} Kills: #{e_kills} Needed: #{e_req} Left: #{e_need}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def show_enemy_image(name)
|
|
67
|
+
`which imgcat > /dev/null 2>&1`
|
|
68
|
+
return false unless $?.success?
|
|
69
|
+
enemy_name = name.gsub(' ', '_')
|
|
70
|
+
# enemy_image_directory = File.expand_path(Rbcli::Warehouse.get(:config, :parsedopts)[:images_directory])
|
|
71
|
+
enemy_image_directory = File.join(Silkedit::LIBDIR, 'images', 'silksong')
|
|
72
|
+
cached_image_option_1 = File.join(enemy_image_directory, "#{enemy_name}.png")
|
|
73
|
+
cached_image_option_2 = File.join(enemy_image_directory, "#{enemy_name}_(Silksong).png")
|
|
74
|
+
|
|
75
|
+
command = "imgcat '%s'"
|
|
76
|
+
|
|
77
|
+
if File.exist?(cached_image_option_1)
|
|
78
|
+
system(format(command, cached_image_option_1))
|
|
79
|
+
elsif File.exist?(cached_image_option_2)
|
|
80
|
+
system(format(command, cached_image_option_2))
|
|
81
|
+
else
|
|
82
|
+
got_image = self.get_large_enemy_image(enemy_name, cached_image_option_1)
|
|
83
|
+
got_image = self.get_large_enemy_image("#{enemy_name}_(Silksong)", cached_image_option_2) unless got_image
|
|
84
|
+
show_enemy_image(name) if got_image
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def get_large_enemy_image(enemy_name, desired_filename)
|
|
89
|
+
begin
|
|
90
|
+
page_url = "https://hollowknight.wiki/w/#{enemy_name}"
|
|
91
|
+
html = URI.open(page_url, 'User-Agent' => 'Ruby/Nokogiri').read
|
|
92
|
+
doc = Nokogiri::HTML(html)
|
|
93
|
+
img = doc.at_css('img.pi-image-thumbnail')
|
|
94
|
+
return false unless img
|
|
95
|
+
|
|
96
|
+
raw = img['src'] || img['data-src'] || img['srcset']
|
|
97
|
+
return false unless raw && !raw.strip.empty?
|
|
98
|
+
|
|
99
|
+
raw = raw.split(',').first.split(/\s+/).first
|
|
100
|
+
image_url = if raw.start_with?('//')
|
|
101
|
+
"https:#{raw}"
|
|
102
|
+
elsif raw =~ %r{\Ahttps?://}
|
|
103
|
+
raw
|
|
104
|
+
else
|
|
105
|
+
URI.join(page_url, raw).to_s
|
|
106
|
+
end
|
|
107
|
+
URI.open(image_url, 'rb', 'User-Agent' => 'Ruby/Nokogiri') do |image_io|
|
|
108
|
+
FileUtils.mkdir_p(File.dirname(desired_filename)) unless File.directory?(File.dirname(desired_filename))
|
|
109
|
+
File.open(desired_filename, 'wb') do |file|
|
|
110
|
+
IO.copy_stream(image_io, file)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
return true
|
|
114
|
+
rescue StandardError => _e
|
|
115
|
+
return false
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
module Silkedit::Cheat
|
|
2
|
+
module SilksongZoner
|
|
3
|
+
@zonedata = YAML.safe_load_file(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'zones.yaml'), symbolize_names: false)
|
|
4
|
+
@shortcuts = @zonedata['_shortcuts']
|
|
5
|
+
@zonelist = @zonedata.reject { |k, _v| k.start_with?('_') }.to_a.map do |region, r_values|
|
|
6
|
+
r_values.map do |spawnpoint, data|
|
|
7
|
+
{
|
|
8
|
+
"slug" => "#{region}.#{spawnpoint}",
|
|
9
|
+
"shortcut" => @shortcuts.values.include?("#{region}.#{spawnpoint}") ? @shortcuts.key("#{region}.#{spawnpoint}") : nil
|
|
10
|
+
}.merge(data)
|
|
11
|
+
end
|
|
12
|
+
end.flatten
|
|
13
|
+
|
|
14
|
+
def list_zones
|
|
15
|
+
zonelist = Silkedit::Cheat::SilksongZoner.module_eval { @zonelist }
|
|
16
|
+
zonelist.map { |z| z.select { |k, _v| %w[slug shortcut min_act].include?(k) }.transform_keys(&:to_sym) }
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def list_shortcuts
|
|
20
|
+
Silkedit::Cheat::SilksongZoner.module_eval { @shortcuts }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def zone_to(zone, force_soft_reqs: false, enforce_min_act: true)
|
|
24
|
+
zonedata = Silkedit::Cheat::SilksongZoner.module_eval { @zonedata }
|
|
25
|
+
zonelist = Silkedit::Cheat::SilksongZoner.module_eval { @zonelist }
|
|
26
|
+
shortcuts = Silkedit::Cheat::SilksongZoner.module_eval { @shortcuts }
|
|
27
|
+
Rbcli.log.info "Zoning to #{zone}", 'ZONER'
|
|
28
|
+
return self.zone_to(shortcuts[zone], force_soft_reqs: force_soft_reqs, enforce_min_act: enforce_min_act) if shortcuts.key?(zone)
|
|
29
|
+
return :no_zone unless zonelist.find { |z| z['slug'] == zone }
|
|
30
|
+
region, target = zone.split('.')
|
|
31
|
+
Silkedit::Cheat.merge_cheat(
|
|
32
|
+
@data,
|
|
33
|
+
zonedata[region][target],
|
|
34
|
+
should_merge_arrays: true,
|
|
35
|
+
force_soft_reqs: force_soft_reqs,
|
|
36
|
+
enforce_min_act: enforce_min_act
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def save_current_zone(name, shortcut = nil, act_override = nil, overwrite: false)
|
|
41
|
+
region, target = name.downcase.split('.')
|
|
42
|
+
return :badname unless region && target
|
|
43
|
+
return :badact if !act_override.nil? && (act_override < 1 || act_override > 3)
|
|
44
|
+
return :badshortcut if !shortcut.nil? && shortcut.include?('.')
|
|
45
|
+
|
|
46
|
+
zone = {
|
|
47
|
+
'data' => {
|
|
48
|
+
'playerData' => {
|
|
49
|
+
'atBench' => @data['playerData']['atBench'],
|
|
50
|
+
'respawnScene' => @data['playerData']['respawnScene'],
|
|
51
|
+
'mapZone' => @data['playerData']['mapZone'],
|
|
52
|
+
'extraRestZone' => @data['playerData']['extraRestZone'],
|
|
53
|
+
'respawnMarkerName' => @data['playerData']['respawnMarkerName'],
|
|
54
|
+
'respawnType' => @data['playerData']['respawnType'],
|
|
55
|
+
'hazardRespawnFacing' => @data['playerData']['hazardRespawnFacing'],
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
'soft_reqs' => {},
|
|
59
|
+
'hard_reqs' => {},
|
|
60
|
+
'min_act' => act_override || Silkedit::Cheat.get_game_act(@data)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
rosarylock = @data['sceneData']['persistentBools']['serializedList'].find { |i| i['SceneName'] == @data['playerData']['respawnScene'] && i['ID'] == 'bell_toll_machine' }
|
|
64
|
+
zone['soft_reqs'].merge!({'sceneData' => {'persistentBools' => {'serializedList' => [rosarylock]}}}) unless rosarylock.nil?
|
|
65
|
+
leverlock = @data['sceneData']['persistentInts']['serializedList'].find { |i| i['SceneName'] == @data['playerData']['respawnScene'] && i['ID'].include?('Bellshrine Sequence') }
|
|
66
|
+
zone['soft_reqs'].merge!({'sceneData' => {'persistentInts' => {'serializedList' => [leverlock]}}}) unless leverlock.nil?
|
|
67
|
+
|
|
68
|
+
zonedata = Silkedit::Cheat::SilksongZoner.module_eval { @zonedata }
|
|
69
|
+
zonelist = Silkedit::Cheat::SilksongZoner.module_eval { @zonelist }
|
|
70
|
+
known_zone_idx = zonelist.find_index do |known_zone|
|
|
71
|
+
known_zone['data']['playerData']['respawnScene'] == zone['data']['playerData']['respawnScene'] &&
|
|
72
|
+
known_zone['data']['playerData']['respawnMarkerName'] == zone['data']['playerData']['respawnMarkerName']
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if known_zone_idx
|
|
76
|
+
if overwrite
|
|
77
|
+
old_region, old_target = zonelist[known_zone_idx]['slug'].split('.')
|
|
78
|
+
zonedata[old_region].delete(old_target)
|
|
79
|
+
zonedata.delete(old_region) if zonedata[old_region].empty?
|
|
80
|
+
else
|
|
81
|
+
return zonelist[known_zone_idx]['slug']
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
zonedata[region] ||= {}
|
|
86
|
+
zonedata[region][target] = zone
|
|
87
|
+
zonedata[region] = zonedata[region].sort_by { |k, _v| k }.to_h
|
|
88
|
+
zonedata = zonedata.sort_by { |k, _v| k }.to_h
|
|
89
|
+
|
|
90
|
+
if shortcut
|
|
91
|
+
zonedata['_shortcuts'][shortcut] = "#{region}.#{target}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
File.write(File.join(Silkedit::LIBDIR, 'config', 'silksong', 'zones.yaml'), YAML.safe_dump(zonedata))
|
|
95
|
+
:success
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
savegame_directory:
|
|
3
|
+
hollow_knight:
|
|
4
|
+
macos: '~/Library/Application Support/unity.Team Cherry.Hollow Knight'
|
|
5
|
+
linux: '~/.config/unity3d/Team Cherry/Hollow Knight'
|
|
6
|
+
windows: '%UserProfile%\AppData\LocalLow\Team Cherry\Hollow Knight'
|
|
7
|
+
silksong:
|
|
8
|
+
macos: '~/Library/Application Support/unity.Team-Cherry.Silksong/%STEAMID%'
|
|
9
|
+
linux: '~/.config/unity3d/Team Cherry/Hollow Knight Silksong/%STEAMID%'
|
|
10
|
+
windows: '%USERPROFILE%/AppData/LocalLow/Team Cherry/Hollow Knight Silksong/%STEAMID%'
|
|
11
|
+
max_backups: 5
|
|
12
|
+
use_yaml: true
|
|
13
|
+
aes_key: 'UKu52ePUBwetZ9wNX88o54dnfKRu0T1l'
|