Player attributes decoding is complete and fully working
This commit is contained in:
parent
33e9cdaa75
commit
33b1915b83
3 changed files with 199 additions and 41 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
|
use super::esh::{ESHValue, ESH};
|
||||||
use super::stream::{ReadStream, WriteStream};
|
use super::stream::{ReadStream, WriteStream};
|
||||||
use super::esh::{ESH, ESHValue};
|
|
||||||
use super::tag::Tag;
|
use super::tag::Tag;
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
|
|
||||||
const STATS: [&str; 7] = [
|
const STATS: [&str; 7] = [
|
||||||
"strength",
|
"strength",
|
||||||
|
|
@ -11,7 +11,7 @@ const STATS: [&str; 7] = [
|
||||||
"charisma",
|
"charisma",
|
||||||
"intelligence",
|
"intelligence",
|
||||||
"agility",
|
"agility",
|
||||||
"luck"
|
"luck",
|
||||||
];
|
];
|
||||||
|
|
||||||
const TRAITS: [&str; 11] = [
|
const TRAITS: [&str; 11] = [
|
||||||
|
|
@ -25,7 +25,7 @@ const TRAITS: [&str; 11] = [
|
||||||
"age",
|
"age",
|
||||||
"bonusAC",
|
"bonusAC",
|
||||||
"sex",
|
"sex",
|
||||||
"race"
|
"race",
|
||||||
];
|
];
|
||||||
|
|
||||||
const DERIVED: [&str; 26] = [
|
const DERIVED: [&str; 26] = [
|
||||||
|
|
@ -54,7 +54,7 @@ const DERIVED: [&str; 26] = [
|
||||||
"meleeDamage",
|
"meleeDamage",
|
||||||
"bonusDamage",
|
"bonusDamage",
|
||||||
"skillPerLevel",
|
"skillPerLevel",
|
||||||
"levelsPerPerk"
|
"levelsPerPerk",
|
||||||
];
|
];
|
||||||
|
|
||||||
const SKILLS: [&str; 18] = [
|
const SKILLS: [&str; 18] = [
|
||||||
|
|
@ -75,7 +75,7 @@ const SKILLS: [&str; 18] = [
|
||||||
"pilot",
|
"pilot",
|
||||||
"barter",
|
"barter",
|
||||||
"gambling",
|
"gambling",
|
||||||
"outdoorsman"
|
"outdoorsman",
|
||||||
];
|
];
|
||||||
|
|
||||||
const OPT_TRAITS: [&str; 38] = [
|
const OPT_TRAITS: [&str; 38] = [
|
||||||
|
|
@ -116,9 +116,137 @@ const OPT_TRAITS: [&str; 38] = [
|
||||||
"doDieHard",
|
"doDieHard",
|
||||||
"doHthEvade",
|
"doHthEvade",
|
||||||
"doDrunkenMaster",
|
"doDrunkenMaster",
|
||||||
"doNightPerson"
|
"doNightPerson",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const PERKS: [&str; 111] = [
|
||||||
|
"awareness",
|
||||||
|
"bonusHtHAttacks",
|
||||||
|
"bonusHtHDamage",
|
||||||
|
"bonusMove",
|
||||||
|
"bonusRangedDamage",
|
||||||
|
"bonusRateofFire",
|
||||||
|
"fasterHealing",
|
||||||
|
"moreCriticals",
|
||||||
|
"nightVision",
|
||||||
|
"radResistance",
|
||||||
|
"toughness",
|
||||||
|
"strongBack",
|
||||||
|
"sharpshooter",
|
||||||
|
"silentRunning",
|
||||||
|
"survivalist",
|
||||||
|
"masterTrader",
|
||||||
|
"educated",
|
||||||
|
"healer",
|
||||||
|
"fortuneFinder",
|
||||||
|
"betterCriticals",
|
||||||
|
"slayer",
|
||||||
|
"sniper",
|
||||||
|
"silentDeath",
|
||||||
|
"actionBoy",
|
||||||
|
"lifegiver",
|
||||||
|
"dodger",
|
||||||
|
"snakeater",
|
||||||
|
"mrFixit",
|
||||||
|
"medic",
|
||||||
|
"masterThief",
|
||||||
|
"heaveHo",
|
||||||
|
"pickpocket",
|
||||||
|
"ghost",
|
||||||
|
"explorer",
|
||||||
|
"flowerChild",
|
||||||
|
"pathfinder",
|
||||||
|
"scout",
|
||||||
|
"mysteriousStranger",
|
||||||
|
"ranger",
|
||||||
|
"quickPockets",
|
||||||
|
"swiftLearner",
|
||||||
|
"tag",
|
||||||
|
"mutate",
|
||||||
|
"adrenalineRush",
|
||||||
|
"cautiousNature",
|
||||||
|
"comprehension",
|
||||||
|
"demolitionExpert",
|
||||||
|
"gambler",
|
||||||
|
"gainStrenght",
|
||||||
|
"gainPerception",
|
||||||
|
"gainEndurance",
|
||||||
|
"gainCharisma",
|
||||||
|
"gainIntelligence",
|
||||||
|
"gainAgility",
|
||||||
|
"gainLuck",
|
||||||
|
"harmless",
|
||||||
|
"hereandNow",
|
||||||
|
"hthEvade",
|
||||||
|
"lightStep",
|
||||||
|
"livingAnatomy",
|
||||||
|
"negotiator",
|
||||||
|
"packRat",
|
||||||
|
"pyromaniac",
|
||||||
|
"quickRecovery",
|
||||||
|
"salesman",
|
||||||
|
"stonewall",
|
||||||
|
"thief",
|
||||||
|
"weaponHandling",
|
||||||
|
"stuntMan",
|
||||||
|
"crazyBomber",
|
||||||
|
"roadWarrior",
|
||||||
|
"gunner",
|
||||||
|
"leadFoot",
|
||||||
|
"tunnelRat",
|
||||||
|
"bracing",
|
||||||
|
"flexible",
|
||||||
|
"bendTheRules",
|
||||||
|
"breakTheRules",
|
||||||
|
"loner",
|
||||||
|
"teamPlayer",
|
||||||
|
"leader",
|
||||||
|
"hitTheDeck",
|
||||||
|
"boneHead",
|
||||||
|
"brownNoser",
|
||||||
|
"dieHard",
|
||||||
|
"drunkenMaster",
|
||||||
|
"stat",
|
||||||
|
"radChild",
|
||||||
|
"cancerousGrowth",
|
||||||
|
"bonsai",
|
||||||
|
"steadyArm",
|
||||||
|
"psychotic",
|
||||||
|
"toughHige",
|
||||||
|
"deathSense",
|
||||||
|
"brutishHulk",
|
||||||
|
"talonOfFear",
|
||||||
|
"hideOfScars",
|
||||||
|
"wayOfTheFruit",
|
||||||
|
"twitchGamer",
|
||||||
|
"bluffMaster",
|
||||||
|
"divineFavour",
|
||||||
|
"unk1",
|
||||||
|
"unk2",
|
||||||
|
"unk3",
|
||||||
|
"unk4",
|
||||||
|
"unk5",
|
||||||
|
"unk6",
|
||||||
|
"unk7",
|
||||||
|
"unk8",
|
||||||
|
"unk9",
|
||||||
|
"unk10",
|
||||||
|
];
|
||||||
|
|
||||||
|
const ADDICTIONS: [&str; 10] = [
|
||||||
|
"buffoutAddiction",
|
||||||
|
"afterburnerAddiction",
|
||||||
|
"mentatsAddiction",
|
||||||
|
"psychoAddiction",
|
||||||
|
"radAwayAddiction",
|
||||||
|
"voodooAddiction",
|
||||||
|
"nukaColaAddiction",
|
||||||
|
"boozeAddiction",
|
||||||
|
"withdrawal",
|
||||||
|
"drunk",
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Attributes {
|
pub struct Attributes {
|
||||||
esh: ESH,
|
esh: ESH,
|
||||||
pub stats: IndexMap<&'static str, u32>,
|
pub stats: IndexMap<&'static str, u32>,
|
||||||
|
|
@ -128,11 +256,11 @@ pub struct Attributes {
|
||||||
pub skill_tags: IndexMap<&'static str, bool>,
|
pub skill_tags: IndexMap<&'static str, bool>,
|
||||||
pub opt_traits: IndexMap<&'static str, bool>,
|
pub opt_traits: IndexMap<&'static str, bool>,
|
||||||
pub perks: IndexMap<&'static str, u32>,
|
pub perks: IndexMap<&'static str, u32>,
|
||||||
pub addictions: IndexMap<&'static str, u32>
|
pub addictions: IndexMap<&'static str, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attributes {
|
impl Attributes {
|
||||||
fn from_binary(bin: &[u8]) -> Result<Self> {
|
pub fn from_binary(bin: &[u8]) -> Result<Self> {
|
||||||
let mut rd = ReadStream::new(bin, 0);
|
let mut rd = ReadStream::new(bin, 0);
|
||||||
|
|
||||||
let _ = rd.read_u32()?;
|
let _ = rd.read_u32()?;
|
||||||
|
|
@ -141,24 +269,59 @@ impl Attributes {
|
||||||
return Err(anyhow!("Attributes Binary == false"));
|
return Err(anyhow!("Attributes Binary == false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut stats: IndexMap<&'static str, u32>;
|
let mut stats: IndexMap<&'static str, u32> = IndexMap::with_capacity(7);
|
||||||
let mut traits: IndexMap<&'static str, u32>;
|
let mut traits: IndexMap<&'static str, u32> = IndexMap::with_capacity(11);
|
||||||
let mut derived: IndexMap<&'static str, u32>;
|
let mut derived: IndexMap<&'static str, u32> = IndexMap::with_capacity(26);
|
||||||
let mut skills: IndexMap<&'static str, u32>;
|
let mut skills: IndexMap<&'static str, u32> = IndexMap::with_capacity(18);
|
||||||
let mut skill_tags: IndexMap<&'static str, bool>;
|
let mut skill_tags: IndexMap<&'static str, bool> = IndexMap::with_capacity(18);
|
||||||
let mut opt_traits: IndexMap<&'static str, bool>;
|
let mut opt_traits: IndexMap<&'static str, bool> = IndexMap::with_capacity(38);
|
||||||
let mut perks: IndexMap<&'static str, u32>;
|
let mut perks: IndexMap<&'static str, u32> = IndexMap::with_capacity(111);
|
||||||
let mut addictions: IndexMap<&'static str, u32>;
|
let mut addictions: IndexMap<&'static str, u32> = IndexMap::with_capacity(10);
|
||||||
|
|
||||||
if let ESHValue::Binary(binary) = &esh.props["esbin"] {
|
if let ESHValue::Binary(binary) = &esh.props["esbin"] {
|
||||||
let mut rd = ReadStream::new(&binary, 0);
|
let mut rd = ReadStream::new(&binary, 0);
|
||||||
|
|
||||||
let _ = rd.read_u32()?;
|
let _ = rd.read_u32()?;
|
||||||
let _: Tag = rd.read()?;
|
let _: Tag = rd.read()?;
|
||||||
|
|
||||||
|
for i in 0..7 {
|
||||||
|
stats.insert(STATS[i], rd.read_u32()?);
|
||||||
|
}
|
||||||
|
for i in 0..11 {
|
||||||
|
traits.insert(TRAITS[i], rd.read_u32()?);
|
||||||
|
}
|
||||||
|
for i in 0..26 {
|
||||||
|
derived.insert(DERIVED[i], rd.read_u32()?);
|
||||||
|
}
|
||||||
|
for i in 0..18 {
|
||||||
|
skills.insert(SKILLS[i], rd.read_u32()?);
|
||||||
|
}
|
||||||
|
for i in 0..18 {
|
||||||
|
skill_tags.insert(SKILLS[i], rd.read_bool()?);
|
||||||
|
}
|
||||||
|
for i in 0..38 {
|
||||||
|
opt_traits.insert(OPT_TRAITS[i], rd.read_bool()?);
|
||||||
|
}
|
||||||
|
for i in 0..111 {
|
||||||
|
perks.insert(PERKS[i], rd.read_u32()?);
|
||||||
|
}
|
||||||
|
for i in 0..10 {
|
||||||
|
addictions.insert(ADDICTIONS[i], rd.read_u32()?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Attributes {
|
||||||
|
esh,
|
||||||
|
stats,
|
||||||
|
traits,
|
||||||
|
derived,
|
||||||
|
skills,
|
||||||
|
skill_tags,
|
||||||
|
opt_traits,
|
||||||
|
perks,
|
||||||
|
addictions,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow!("Attributes has no esbin"));
|
return Err(anyhow!("Attributes has no esbin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,10 @@ impl<'a> ReadStream<'a> {
|
||||||
Ok(self.rdr.read_u8()?)
|
Ok(self.rdr.read_u8()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_bool(&mut self) -> Result<bool> {
|
||||||
|
Ok(self.read_u8()? != 0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_u16(&mut self) -> Result<u16> {
|
pub fn read_u16(&mut self) -> Result<u16> {
|
||||||
Ok(self.rdr.read_u16::<LittleEndian>()?)
|
Ok(self.rdr.read_u16::<LittleEndian>()?)
|
||||||
}
|
}
|
||||||
|
|
@ -148,6 +152,10 @@ impl WriteStream {
|
||||||
Ok(self.buf.write_u8(val)?)
|
Ok(self.buf.write_u8(val)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_bool(&mut self, val: bool) -> Result<()> {
|
||||||
|
self.write_u8(val as u8)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn write_u16(&mut self, val: u16) -> Result<()> {
|
pub fn write_u16(&mut self, val: u16) -> Result<()> {
|
||||||
Ok(self.buf.write_u16::<LittleEndian>(val)?)
|
Ok(self.buf.write_u16::<LittleEndian>(val)?)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use crate::fot::attributes;
|
||||||
|
|
||||||
use super::decoder::DecoderCtx;
|
use super::decoder::DecoderCtx;
|
||||||
use super::entitylist::{EntityEncoding, EntityList};
|
use super::entitylist::{EntityEncoding, EntityList};
|
||||||
use super::fstring::FString;
|
use super::fstring::FString;
|
||||||
|
|
@ -12,6 +14,7 @@ use deflate::deflate_bytes_zlib;
|
||||||
use inflate::inflate_bytes_zlib;
|
use inflate::inflate_bytes_zlib;
|
||||||
|
|
||||||
use super::esh::{ESHValue, ESH};
|
use super::esh::{ESHValue, ESH};
|
||||||
|
use super::attributes::Attributes;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub struct World {
|
pub struct World {
|
||||||
|
|
@ -43,25 +46,9 @@ impl World {
|
||||||
//self.entlist.dump_to_entfile(ent, Path::new("D:\\actor.ent"))?;
|
//self.entlist.dump_to_entfile(ent, Path::new("D:\\actor.ent"))?;
|
||||||
|
|
||||||
println!("");
|
println!("");
|
||||||
if let ESHValue::Binary(attributes) = &esh.props["Attributes"] {
|
if let ESHValue::Binary(binary) = &esh.props["Attributes"] {
|
||||||
let mut rd = ReadStream::new(&attributes, 0);
|
let attributes = Attributes::from_binary(&binary)?;
|
||||||
|
dbg!(attributes);
|
||||||
let size = rd.read_u32()?;
|
|
||||||
let attrs_esh: ESH = rd.read()?;
|
|
||||||
for (name, value) in &attrs_esh.props {
|
|
||||||
println!("{} {}", name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("");
|
|
||||||
if let ESHValue::Binary(attributes) = &esh.props["Modifiers"] {
|
|
||||||
let mut rd = ReadStream::new(&attributes, 0);
|
|
||||||
|
|
||||||
let size = rd.read_u32()?;
|
|
||||||
let attrs_esh: ESH = rd.read()?;
|
|
||||||
for (name, value) in &attrs_esh.props {
|
|
||||||
println!("{} {}", name, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue