diff options
Diffstat (limited to 'libs/basic_games/games/stalkeranomaly/XRSave.py')
| -rw-r--r-- | libs/basic_games/games/stalkeranomaly/XRSave.py | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/libs/basic_games/games/stalkeranomaly/XRSave.py b/libs/basic_games/games/stalkeranomaly/XRSave.py new file mode 100644 index 0000000..b73a988 --- /dev/null +++ b/libs/basic_games/games/stalkeranomaly/XRSave.py @@ -0,0 +1,164 @@ +import io +import struct +from datetime import datetime +from pathlib import Path +from typing import BinaryIO, Optional, cast + +import lzokay # pyright: ignore[reportMissingTypeStubs] + +from .XRIO import XRReader, XRStream +from .XRObject import XRCreatureActor, XRFlag + + +class XRSave: + filepath: Path + player: XRCreatureActor + + _factions = { + 0: "Loner", + 1: "Monster", + 2: "Trader", + 3: "Army", + 4: "Sin", + 5: "Bandit", + 6: "Duty", + 7: "Ecologist", + 8: "Freedom", + 9: "Mercenary", + 10: "Army", + 11: "Monolith", + 12: "Sin", + 13: "Loner", + 14: "Zombified", + 15: "Clear Sky", + 16: "UNISG", + 17: "Renegade", + 18: "Loner", + 19: "Bandit", + 20: "Duty", + 21: "Freedom", + 22: "Clear Sky", + 23: "Ecologist", + 24: "Mercenary", + 25: "Military", + 26: "Monolith", + 27: "Zombified", + 28: "Sin", + 29: "UNISG", + 30: "Renegade", + 31: "Participant", + } + + _ranks = { + 1999: "Novice", + 3999: "Trainee", + 6999: "Experienced", + 9999: "Professional", + 14999: "Veteran", + 20999: "Expert", + 27999: "Master", + "max": "Legend", + } + + _reputation = { + -2000: "Terrible", + -1500: "Really Bad", + -1000: "Very Bad", + -500: "Bad", + 499: "Netural", + 999: "Good", + 1499: "Very Good", + 1999: "Really Good", + "max": "Excellent", + } + + def __init__(self, filepath: Path): + self.filepath = filepath + self.fetchInfo() + with open(filepath, "rb") as file: + stream = self.readFile(file) + if stream: + self.readObject(stream) + + def fetchInfo(self): + self.splitInfo() + self.time = self.filepath.stat().st_mtime + self.time_date = datetime.fromtimestamp(self.time) + self.time_fmt = self.time_date.strftime("%I:%M %m/%d/%Y") + + def splitInfo(self): + save_clean = self.filepath.name.split(".scop", 1)[0] + save_split = save_clean.split(" - ", 1) + self.user = save_split[0] + if len(save_split) > 1: + save_end = save_split[1].split("_", 1) + if len(save_end) > 1: + self.save_fmt = f"{save_end[0]} (#{save_end[1]})".title() + else: + self.save_fmt = f"{save_end[0]}".title() + else: + self.save_fmt = "Unknown" + + def readFile(self, file: BinaryIO) -> Optional[XRStream]: + size = self.filepath.stat().st_size + if size < 8: + return None + + (start, version, source) = struct.unpack("@iii", file.read(12)) + if (start == -1) and (version >= 6): + file.seek(12) + data = file.read(size - 12) + return XRStream( + cast( + bytes, + lzokay.decompress( # pyright: ignore[reportUnknownMemberType] + data, source + ), + ) + ) + + return None + + def readObject(self, stream: XRStream): + chunk = stream.open_chunk(XRFlag.CHUNK_OBJECT) + if chunk: + chunk.seek(4, io.SEEK_CUR) # obj_count + count_spawn = chunk.u16() + spawn = XRReader(chunk.read(count_spawn)) + actor = XRCreatureActor() + actor.read_spawn(spawn) + count_update = chunk.u16() + update = XRReader(chunk.read(count_update)) + actor.read_update(update) + if actor: + self.player = actor + return None + + def getFaction(self) -> str: + player = self.player + if player: + player_faction = player.community_index + for faction in self._factions: + if player_faction == faction: + return self._factions[faction] + return "Unknown" + + def getRank(self) -> str: + player = self.player + if player: + player_rank = player.rank + for rank in self._ranks: + if isinstance(rank, int): + if player_rank <= rank: + return self._ranks[rank] + return self._ranks["max"] + + def getReputation(self) -> str: + player = self.player + if player: + player_rep = player.reputation + for rep in self._reputation: + if isinstance(rep, int): + if player_rep <= rep: + return self._reputation[rep] + return self._reputation["max"] |
