pgs/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! A library for structuring save files from the Birdiesoft classic game [Pokémon Simulator](http://birdiesoft.dk/software.php?id=2).
//!
//! All of the information in this has been reverse engineered. It only handles version 2 of the PGS (PokeGameSave) format and will panic if it tries to do version 1 or any other file.
//!
//! This library doesn't try to do any verification of your data, so you should look at the doumentation of this library to see what the valid details should be.

/// A structure for pokemon data.
///
/// Maximum values:
/// * `pokedex`: 386
/// * `level`: 100
#[derive(Debug)]
pub struct Pokemon {
	pub pokedex: u16,
	pub level: u8,
	pub experience: u32,
}

/// A structure for the PGS format.
///
/// Maximum values:
/// * `leaders_beaten`: 25
///
/// Required lengths:
/// * `beaten_flags`: 5
/// * `pokedex`: 386
/// * `items`: 6
///
/// Maximum lengths:
/// * `pokemon`: 10,000
#[derive(Debug)]
pub struct PGSv2 {
	pub name: String,
	pub beaten_flags: Vec<bool>,
	pub leaders_beaten: u8,
	pub money: u32,
	pub wins: u32,
	pub losses: u32,
	pub fights: u32,
	pub catches: u32,
	pub items: Vec<u32>,
	pub pokedex: Vec<bool>,
	pub pokemon: Vec<Pokemon>,
}

/// Converts a borrowed string of a PGS save file (which is in plain text) to a PGSv2 structure.
///
/// Blank pokemon values in the save file will terminate the search for more pokemon and return the file. Destructure will automatically fix this and put the valid amount of padding back.
///
/// Only accepts version 2 PGS save files, those starting with `VERSION2SAVEFILEIDENTIFIER`.
pub fn structure(save: &str) -> PGSv2 {
	let y = save.to_string();
	let x = y.split("\r\n");
	let mut i = 0;
	let mut name = "".to_string();
	let mut flags: Vec<bool> = vec![];
	let mut leaders_beaten: u8 = 0;
	let mut money: u32 = 0;
	let mut wins: u32 = 0;
	let mut losses: u32 = 0;
	let mut fights: u32 = 0;
	let mut catches: u32 = 0;
	let mut items: Vec<u32> = vec![];
	let mut pokedex: Vec<bool> = vec![];
	let mut pokemon: Vec<Pokemon> = vec![];
	let mut tmpdex: u16 = 0;
	let mut tmplvl: u8 = 0;
	let mut tmpexp: u32 = 0;
	'outer: for s in x {
		if i == 0 && s != "VERSION2SAVEFILEIDENTIFIER" { panic!("Not a valid save file!"); }
		if i == 1 { name = s.to_string(); }
		if i >= 2 && 6 >= i {
			if s == "TRUE".to_string() {
				flags.push(true);
			} else {
				flags.push(false);
			}
		}
		if i == 7 { leaders_beaten = s.parse::<u8>().unwrap(); }
		if i == 8 { money = s.parse::<u32>().unwrap(); }
		if i == 9 { wins = s.parse::<u32>().unwrap(); }
		if i == 10 { losses = s.parse::<u32>().unwrap(); }
		if i == 11 { fights = s.parse::<u32>().unwrap(); }
		if i == 12 { catches = s.parse::<u32>().unwrap(); }
		if i >= 13 && 18 >= i {
			let val = s.parse::<u32>().unwrap();
			items.push(val);
		}
		if i >= 19 && 404 >= i {
			if s == "TRUE".to_string() {
				pokedex.push(true);
			} else {
				pokedex.push(false);
			}
		}
		if i > 404 {
			if tmpdex == 0 {
				tmpdex = s.parse::<u16>().unwrap();
				if tmpdex == 0 {
					break 'outer;
				}
			} else if tmplvl == 0 {
				tmplvl = s.parse::<u8>().unwrap();
			} else if tmpexp == 0 {
				tmpexp = s.parse::<u32>().unwrap();
				let pkmn = Pokemon { pokedex: tmpdex, level: tmplvl, experience: tmpexp };
				tmpdex = 0;
				tmplvl = 0;
				tmpexp = 0;
				pokemon.push(pkmn);
			}
		}
		i = i + 1;
	}
	let pgs = PGSv2 { name: name, beaten_flags: flags, leaders_beaten: leaders_beaten, money: money, wins: wins, losses: losses, fights: fights, catches: catches, items: items, pokedex: pokedex, pokemon: pokemon };
	return pgs
}

fn append(x: String, y: String) -> String {
	let z = format!("{}{}\r\n", x, y);
	return z
}

/// Turns a PGSv2 structure back into a String.
///
/// Useful for destructuring a modified save and then saving it to a .pgs file.
pub fn destructure(pgs: PGSv2) -> String {
	let mut x = "VERSION2SAVEFILEIDENTIFIER\r\n".to_string();
	let mut a = 0;
	x = append(x, pgs.name);
	for flag in pgs.beaten_flags {
		let y;
		if flag == false {
			y = "FALSE".to_string();
		} else {
			y = "TRUE".to_string();
		}
		x = append(x, y);
	}
	x = append(x, pgs.leaders_beaten.to_string());
	x = append(x, pgs.money.to_string());
	x = append(x, pgs.wins.to_string());
	x = append(x, pgs.losses.to_string());
	x = append(x, pgs.fights.to_string());
	x = append(x, pgs.catches.to_string());
	for item in pgs.items {
		x = append(x, item.to_string());
	}
	for pokex in pgs.pokedex {
		let y;
		if pokex == false {
			y = "FALSE".to_string();
		} else {
			y = "TRUE".to_string();
		}
		x = append(x, y);
	}
	for pkmn in pgs.pokemon {
		x = append(x, pkmn.pokedex.to_string());
		x = append(x, pkmn.level.to_string());
		x = append(x, pkmn.experience.to_string());
	}
	let a = x.to_owned();
	let z = a.split("\r\n");
	let y: Vec<&str> = z.collect();
	let mut i: i64 = 30404 - y.len() as i64;
	while i > 0 {
		x = append(x, "0\r\n0\r\n0".to_string());
		i = i - 3;
	}
	return x
}