aboutsummaryrefslogtreecommitdiff
path: root/libs/basic_games/games/stalkeranomaly/XRSave.py
diff options
context:
space:
mode:
Diffstat (limited to 'libs/basic_games/games/stalkeranomaly/XRSave.py')
-rw-r--r--libs/basic_games/games/stalkeranomaly/XRSave.py164
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"]