See also: Halbu Editor
A .d2s file parsing library written in Rust.
⚠ NPCs and Items section are not yet supported. ⚠
⚠ Neither are hardcore mode and non-expansion characters ⚠
Notes regarding D2R with some useful information regarding quests in particular.
This library uses the log crate to log parsing errors.
use halbu::{quests::QuestFlag, waypoints::Waypoint, Class, Save};
fn main() {
// Open a save file
let save_file = std::fs::read("C:\\Users\\Example\\Saved Games\\Diablo II Resurrected\\Jamella.d2s").unwrap();
let mut save = Save::parse(&save_file);
// Alternatively, create a new save
save = Save::default_class(Class::Necromancer);
// Change class, name, etc
save.character.class = Class::Paladin;
save.character.name = String::from("Halbu");
// Warning: save.character.level and save.attributes.level must
// be the same or the game won't load!
save.character.level = 47;
save.attributes.level.value = 47;
// Change mercenary stats
// Refer to notes.md for a table with name/variant ID
save.character.mercenary.name_id = 3;
save.character.mercenary.variant_id = 34;
// Set an attribute
save.attributes.strength.value = 156;
// Attribute names are taken from itemstatcosts.txt
save.attributes.newskills.value = 5;
// Some attributes are stored as fixed point numbers in 21 bits,
// where the first 13 bits are the integer part and the last 8 the decimal
// For those attributes (Current/Max HP, Mana & Stamina), you must multiply
// the value by 256 to get the value displayed in game.
save.attributes.maxmana.value = 200 * 256;
println!(
"Max mana: {}",
save.attributes.maxmana.value as f64 / 256f64
);
// Acquire all waypoints in an act
save.waypoints.normal.act1.set_all(true);
// Set all waypoints in a difficulty
save.waypoints.hell.set_all(true);
// Get/set whether a specific waypoint is acquired
// Waypoints are a numbered 0-8 (0-2 for Act IV)
save.waypoints.hell.act4.set_num(1, true);
println!("Hell Act IV WP 1: {}", save.waypoints.hell.act4.get_num(1));
save.waypoints.hell.act4.set(Waypoint::CityOfTheDamned, false);
println!(
"Hell Act IV WP 1: {}",
save.waypoints.hell.act4.get(Waypoint::CityOfTheDamned)
);
// Set all skills to 20
save.skills.set_all(20);
println!("{}", save.skills);
// Set the skill points of a given skill to 0
save.skills.set(17, 0);
println!("Skillpoints: {}", save.skills.get(17));
// A quest is a struct with a single member State which is a hashset
// containing all the flags currently active for that quest.
// Clear all flags
// Warning: The quest numbers may not be what you think it is! Refer to NOTES.md.
save.quests.hell.act1.q1.state.clear();
println!("Hell Act I Q1 State: {}", save.quests.hell.act1.q1);
// The flag names are from D2MOO. Refer to NOTES.md for a flagname <> bit # table.
save.quests.hell.act1.q1.state.insert(QuestFlag::RewardGranted);
println!(
"Hell Act I Q1 Completed: {}",
save.quests.hell.act1.q1.state.contains(&QuestFlag::RewardGranted)
);
// Save the file
// Warning: The file name must match the character's name!
std::fs::write("C:\\Users\\Example\\Saved Games\\Diablo II Resurrected\\Halbu.d2s", save.to_bytes()).unwrap();
}
For more information, please check the documentation.
These resources have helped me understand the .d2s format. Many thanks to their authors for the work they've done!
- http://user.xmission.com/~trevin/DiabloIIv1.09_File_Format.shtml
- https://github.com/dschu012/D2SLib (Unless you specifically need a rust library, you should probably use this.)
- https://raw.githubusercontent.com/oaken-source/pyd2s/master/docs/d2s_save_file_format_1.13d.txt
- https://github.com/WalterCouto/D2CE/blob/main/d2s_File_Format.md
- https://github.com/krisives/d2s-format
- https://github.com/nokka/d2s/
- https://github.com/ThePhrozenKeep/D2MOO
- https://d2mods.info/forum/kb/index?c=4