ruby_gs 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0da9e8c8ef97844c3eaecfca69c85fe1e0d953fc
4
- data.tar.gz: 81989859170a74f0c87f5c2fa869b888504a425f
3
+ metadata.gz: 86a1e014deb81957ade947e6c0e4e92fbb61ece9
4
+ data.tar.gz: 034dc05e5066e440ea4c40b2536807a3d915f8d5
5
5
  SHA512:
6
- metadata.gz: 42f4bb0288199f232d25a50d5a78818321cc3689ba33f301de98c2f064db30befbc99b9876ec64437b69aaf2e6fa74a159913329ba9296e476bac6242a032ae1
7
- data.tar.gz: 5f818eab58cec5f4926262015351143a1a3f9c96446540d0b527025a3bb18b3d4425a62ef2e5a132f1d150a8583da70cbe4413c072525df8779b2929dcf1febe
6
+ metadata.gz: 0c1e4c3ad975fdd15928f17f1d9330fde3d626e53ab8e11b91b6b5d3273151ce9a36301ddb7da8268dd0a961578031fec2399c2eeb656a493f3cd48df2253b6f
7
+ data.tar.gz: 560afb309a8d9f174a043eb78448ea3416821c22cc9a594968a08540e12154ed4598152c5107d14cfe42a4342777eb461339d5774bbec03b2f376dcab3f2146b
data/README.md CHANGED
@@ -35,6 +35,7 @@ frames = 20
35
35
  saved_game.time_played = [hours, minutes, seconds, frames] # The amount of frames is not visible to the player and is rather inconsequential in general.
36
36
 
37
37
  saved_game.item_pocket[3].kind = 1 # Change the 3rd item in our Item Pocket to a Master Ball.
38
+
38
39
  saved_game.item_pocket[3].amount = 255 # Gotta make sure we have enough for our journey.
39
40
 
40
41
  saved_game.write # This will write your changes directly to the same save file you opened initially.
@@ -49,7 +50,7 @@ saved_game.write "path/to/other/save/file.sav" # This will write your changes to
49
50
 
50
51
  ##TODO:
51
52
  + Support for Crystal.
52
- + Major refactoring.
53
+ + ~~Major refactoring.~~
53
54
  + Player Location editing.
54
55
  + Event Flag editing (and possibly documenting the purpose of each flag).
55
56
 
@@ -1,2 +1,8 @@
1
1
  require "ruby_gs/version"
2
2
  require "ruby_gs/save_file_reader"
3
+
4
+ ##
5
+ # Contains all of the structures and classes necessary for viewing and editing Pokemon Gold/Silver/Crystal save files.
6
+ module RubyGS
7
+
8
+ end
@@ -5,12 +5,18 @@ module RubyGS
5
5
 
6
6
  class SaveFileReader
7
7
 
8
+
9
+ ##
10
+ # Reads a .sav file and builds a SaveFile object from its data.
8
11
  def self.read(file)
9
12
  raise "filename cannot be nil" if not file
10
13
  SaveFile.new SaveFileGS.read(File.open(file,"r")), file, true # TODO: Detect whether save belongs to Gold/Silver or Crystal
11
14
  end
12
15
 
16
+ ##
17
+ # DEPRECATED: Calculates the checksum values for both regions within a save file.
13
18
  def self.calc_checksums(file)
19
+ warn "[DEPRECATION] SaveFileReader::calc_checksums is deprecated. Please use SaveFileReader::correct_checksums! instead."
14
20
  file.pos = 0
15
21
  content = file.read.split("").map(&:ord)
16
22
  c1 = content[0x2009..0x2D68].reduce(&:+)
@@ -19,6 +25,8 @@ module RubyGS
19
25
  [c1.to_s(16),c2.to_s(16)]
20
26
  end
21
27
 
28
+ ##
29
+ # Calculates the checksum values within a save file and writes them to the save file.
22
30
  def self.correct_checksums!(file)
23
31
  file.pos = 0
24
32
  content = file.read.split("").map(&:ord)
@@ -36,9 +44,18 @@ module RubyGS
36
44
 
37
45
  end
38
46
 
47
+ ##
48
+ # Represents a Gold/Silver/Crystal save file.
49
+ #
50
+ # @gs is set to true if the save file is from Gold/Silver and false otherwise.
51
+ #
52
+ # @filename is a string of the filename that the save file was originally read from.
53
+ #
54
+ # @save is the structure containing the save file's data and is delegated to SaveFile.
39
55
  class SaveFile
40
56
 
41
- attr_accessor :save, :gs, :filename
57
+ attr_accessor :save
58
+ attr_reader :gs, :filename
42
59
 
43
60
  def initialize save, filename, gs
44
61
  @save, @gs, @filename = save, gs, filename
@@ -53,27 +70,37 @@ module RubyGS
53
70
  end
54
71
  end
55
72
 
73
+ ##
74
+ # Writes the save structure to file.
75
+ #
76
+ # If loc is not provided, it will write directly to the original file.
56
77
  def write(loc = @filename)
57
78
  @save.write(File.open(loc, "wb"))
58
79
  verify_checksums
59
80
  end
60
81
 
82
+ ##
83
+ # A convenience method for setting the species of a PartyPokemon in its structure and in the Team species_list.
61
84
  def set_team_species slot, species
62
85
  return if !(0..5).include? slot
63
86
  @save.team.pokemon[slot].species.assign species
64
87
  @save.team.species_list[slot].assign species
65
88
  end
66
89
 
90
+ ##
91
+ # A convenience method for turning a PartyPokemon into an Egg and setting the steps required to hatch it.
67
92
  def set_team_egg slot, egg_cycles
68
93
  raise "slot index must be between 0 and 5, inclusive" if !(0..5).include? slot
69
94
  @save.team.species_list[slot] = 0xFD
70
- @save.team.pokemon[slot].happiness = egg_cycles
95
+ @save.team.pokemon[slot].happiness = egg_cycles
71
96
  end
72
97
 
98
+ ##
99
+ # A convenience method for turning an Egg into a Pokemon.
73
100
  def hatch_team_egg slot
74
101
  raise "slot index must be between 0 and 5, inclusive" if !(0..5).include? slot
75
102
  @save.team.species_list[slot].assign @save.team.pokemon[slot].species
76
- @save.team.pokemon[slot].happiness = 20
103
+ @save.team.pokemon[slot].happiness = 20
77
104
  end
78
105
 
79
106
  def method_missing(sym, *args, &block)
@@ -0,0 +1,23 @@
1
+ require_relative "../text_gs"
2
+
3
+ module RubyGS
4
+
5
+ ##
6
+ # A String representing the name of a PC Box.
7
+ #
8
+ # It can only contain 8 visible characters, the 9th being a terminator.
9
+ #
10
+ class BoxName < BinData::Primitive
11
+ string :val, :length => 9, :pad_byte => 'P'
12
+
13
+ def get
14
+ TextGS.decode self.val[0..7]
15
+ end
16
+
17
+ def set value
18
+ self.val = TextGS.encode value
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -4,6 +4,12 @@ require_relative "caught_data"
4
4
 
5
5
  module RubyGS
6
6
 
7
+ ##
8
+ # Represents a Pokemon within your current party.
9
+ #
10
+ # Contains 16 more bytes of data pertaining to combat stats than a PC Pokemon structure.
11
+ # These are recalculated upon withdrawal from the PC.
12
+ #
7
13
  class PartyPokemon < BinData::Record
8
14
  endian :big
9
15
  uint8 :species
@@ -0,0 +1,22 @@
1
+ require_relative "name_text"
2
+ require_relative "pc_pokemon"
3
+
4
+ module RubyGS
5
+
6
+ ##
7
+ # Represents a Pokemon Box inside of the PC.
8
+ #
9
+ # It has an identical structure to the Team structure, but is much longer in length.
10
+ #
11
+ class PCBox < BinData::Record
12
+ endian :big
13
+ uint8 :unused
14
+ uint8 :amount
15
+ array :species_list, :type => :uint8, :initial_length => 21
16
+ array :pokemon, :type => :pc_pokemon, :initial_length => 20
17
+ array :ot_name, :type => :name_text, :initial_length => 20
18
+ array :name, :type => :name_text, :initial_length => 20
19
+ uint8 :unused2
20
+ end
21
+
22
+ end
@@ -0,0 +1,38 @@
1
+ require_relative "iv_data"
2
+ require_relative "pp_data"
3
+ require_relative "caught_data"
4
+
5
+ module RubyGS
6
+
7
+ ##
8
+ # Represents the data describing a Pokemon stored within a PC Box.
9
+ #
10
+ # This is a stripped down version of the PartyPokemon structure as it lacks data on current combat stats.
11
+ #
12
+ class PCPokemon < BinData::Record
13
+ endian :big
14
+ uint8 :species
15
+ uint8 :held_item
16
+ uint8 :move_1
17
+ uint8 :move_2
18
+ uint8 :move_3
19
+ uint8 :move_4
20
+ uint16 :ot_id
21
+ bit :exp, :nbits => 24
22
+ uint16 :hp_ev
23
+ uint16 :attack_ev
24
+ uint16 :defense_ev
25
+ uint16 :speed_ev
26
+ uint16 :special_ev
27
+ iv_data :iv
28
+ pp_data :pp_1
29
+ pp_data :pp_2
30
+ pp_data :pp_3
31
+ pp_data :pp_4
32
+ uint8 :happiness
33
+ uint8 :pokerus
34
+ caught_data :caught # Crystal only; Filled with 0s otherwise.
35
+ uint8 :level
36
+ end
37
+
38
+ end
@@ -0,0 +1,37 @@
1
+
2
+
3
+ module RubyGS
4
+
5
+ ##
6
+ # Represents a Pokemon who has been seen or caught.
7
+ FOUND = 1
8
+ ##
9
+ # Represents a Pokemon who has not yet been seen or caught.
10
+ NOT_FOUND = 0
11
+
12
+ class PokedexArray < BinData::Array
13
+
14
+ def [] i
15
+ return @element_list[real_index(i)].snapshot
16
+ end
17
+
18
+ def []= i, v
19
+ @element_list[real_index(i)].assign v
20
+ end
21
+
22
+ private
23
+
24
+ def real_index n
25
+ return n if n % 8 == 0
26
+ ((n / 8).floor+2)*8 - (n % 8)
27
+ end
28
+
29
+ end
30
+
31
+ class PokedexData < BinData::Record
32
+ endian :big
33
+ pokedex_array :species, :type => :bit1, :initial_length => 251
34
+ array :unknown, :type => :bit1, :initial_length => 5
35
+ end
36
+
37
+ end
@@ -1,9 +1,15 @@
1
1
  require_relative "team"
2
+ require_relative "pc_box"
2
3
  require_relative "name_text"
4
+ require_relative "box_name"
3
5
  require_relative "item_entry"
6
+ require_relative "pokedex_data"
4
7
 
5
8
  module RubyGS
6
9
 
10
+ ##
11
+ # Represents the structure and data of a Gold/Silver Pokemon cartridge SRAM
12
+ #
7
13
  class SaveFileGS < BinData::Record
8
14
  endian :big
9
15
  array :unused, :type => :uint8, :initial_length => 0x2000
@@ -31,15 +37,19 @@ module RubyGS
31
37
  array :ball_pocket, :type => :uint8, :initial_length => 26
32
38
  array :pc_items, :type => :uint8, :initial_length => 102
33
39
  array :unused7, :type => :uint8, :initial_length => 0x240
34
- uint8 :current_box
35
- array :unused8, :type => :uint8, :initial_length => 0x2
36
- array :box_names, :type => :uint8, :initial_length => 126
37
- array :unused9, :type => :uint8, :initial_length => 0xE5
40
+ uint8 :current_box_index
41
+ array :unused8, :type => :uint8, :initial_length => 0x3
42
+ array :box_names, :type => :box_name, :initial_length => 14
43
+ array :unused9, :type => :uint8, :initial_length => 0xE4
38
44
  team :team
39
- array :unused10, :type => :uint8, :initial_length => 0x16
40
- array :dex_owned, :type => :uint8, :initial_length => 32
41
- array :dex_seen, :type => :uint8, :initial_length => 32
42
- array :footer, :type => :uint8, :initial_length => 0x559F
45
+ array :unused10, :type => :uint8, :initial_length => 0x15
46
+ pokedex_data :dex_owned
47
+ pokedex_data :dex_seen
48
+ array :unused11, :type => :uint8, :initial_length => 0x2E0
49
+ pc_box :current_box
50
+ array :unused12, :type => :uint8, :initial_length => 0xE44
51
+ array :pc_box, :type => :pc_box, :initial_length => 14
52
+ rest :rest
43
53
  end
44
54
 
45
55
  end
@@ -3,6 +3,12 @@ require_relative "party_pokemon"
3
3
 
4
4
  module RubyGS
5
5
 
6
+ ##
7
+ # Represents your party of Pokemon.
8
+ #
9
+ # Note that the species, nickname, and original trainer name of each Pokemon is stored separately
10
+ # from their respective structures, instead being stored directly within the Team structure.
11
+ #
6
12
  class Team < BinData::Record
7
13
  endian :big
8
14
  uint8 :unused
@@ -1,3 +1,3 @@
1
1
  module RubyGS
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_gs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Conrad King
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-06 00:00:00.000000000 Z
11
+ date: 2015-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -73,11 +73,15 @@ files:
73
73
  - lib/ruby_gs.rb
74
74
  - lib/ruby_gs/save_file_reader.rb
75
75
  - lib/ruby_gs/structs.rb
76
+ - lib/ruby_gs/structs/box_name.rb
76
77
  - lib/ruby_gs/structs/caught_data.rb
77
78
  - lib/ruby_gs/structs/item_entry.rb
78
79
  - lib/ruby_gs/structs/iv_data.rb
79
80
  - lib/ruby_gs/structs/name_text.rb
80
81
  - lib/ruby_gs/structs/party_pokemon.rb
82
+ - lib/ruby_gs/structs/pc_box.rb
83
+ - lib/ruby_gs/structs/pc_pokemon.rb
84
+ - lib/ruby_gs/structs/pokedex_data.rb
81
85
  - lib/ruby_gs/structs/pp_data.rb
82
86
  - lib/ruby_gs/structs/save_file.rb
83
87
  - lib/ruby_gs/structs/team.rb