From 322f6d1223eaabe195c8d927e02aae1843b481d2 Mon Sep 17 00:00:00 2001 From: Hash Borgir Date: Sat, 7 May 2022 00:39:13 -0600 Subject: [PATCH] Quests parsed, cleanup needed --- D2SaveFileStructure.php | 353 +++++++++++++++++++++++++++++++++++----- 1 file changed, 316 insertions(+), 37 deletions(-) diff --git a/D2SaveFileStructure.php b/D2SaveFileStructure.php index 4f9626a..7060483 100644 --- a/D2SaveFileStructure.php +++ b/D2SaveFileStructure.php @@ -9,10 +9,7 @@ ob_start(); require_once './D2SaveFileStructureData.php'; - - - -$filePath = "D:\Diablo II\MODS\ironman-dev\save\Sorc.d2s"; +$filePath = "D:\Diablo II\MODS\ironman-dev\save\Barb.d2s"; $fp = fopen($filePath, "rb"); $offsets = [ 0 => 4, // Identifier @@ -50,17 +47,288 @@ $offsets = [ 714 => 51, // NPC Introductions ]; -foreach ($offsets as $k => $v){ +$questOffsetsNormal = [ + 345 => 2, + 347 => 2, + 349 => 2, + 351 => 2, + 353 => 2, + 355 => 2, + 357 => 2, + 359 => 2, + 361 => 2, + 363 => 2, + 365 => 2, + 367 => 2, + 369 => 2, + 371 => 2, + 373 => 2, + 375 => 2, + 377 => 2, + 379 => 2, + 381 => 2, + 383 => 2, + 385 => 2, + 387 => 2, + 389 => 2, + 391 => 2, + 393 => 2, + 395 => 2, + 397 => 2, + 399 => 2, + 401 => 2, + 403 => 2, + 405 => 2, + 407 => 2, + 409 => 2, + 414 => 2, + 416 => 2, + 418 => 2, + 420 => 2, + 422 => 2, + 424 => 2 +]; + +$questOffsetsNM = [ + 438 => 2, + 440 => 2, + 442 => 2, + 444 => 2, + 446 => 2, + 448 => 2, + 450 => 2, + 452 => 2, + 454 => 2, + 456 => 2, + 458 => 2, + 460 => 2, + 462 => 2, + 464 => 2, + 466 => 2, + 468 => 2, + 470 => 2, + 472 => 2, + 474 => 2, + 476 => 2, + 478 => 2, + 480 => 2, + 482 => 2, + 484 => 2, + 486 => 2, + 488 => 2, + 490 => 2, + 492 => 2, + 494 => 2, + 496 => 2, + 498 => 2, + 500 => 2, + 502 => 2, + 504 => 2, + 506 => 2, + 508 => 2, + 510 => 2, + 512 => 2, + 514 => 2, +]; + +$questOffsetsHell = [ + 528 => 2, + 530 => 2, + 532 => 2, + 534 => 2, + 536 => 2, + 538 => 2, + 540 => 2, + 542 => 2, + 544 => 2, + 546 => 2, + 548 => 2, + 550 => 2, + 552 => 2, + 554 => 2, + 556 => 2, + 558 => 2, + 560 => 2, + 562 => 2, + 564 => 2, + 566 => 2, + 568 => 2, + 570 => 2, + 572 => 2, + 574 => 2, + 576 => 2, + 578 => 2, + 580 => 2, + 582 => 2, + 584 => 2, + 586 => 2, + 588 => 2, + 590 => 2, + 592 => 2, + 594 => 2, + 596 => 2, + 598 => 2, + 600 => 2, + 602 => 2, + 604 => 2, +]; + +$qNorm = [ + 345 => 'introWarriv', + 347 => 'DenOfEvil', + 349 => 'SistersBurialGrounds', + 351 => 'ToolsOfTheTrade', + 353 => 'TheSearchForCain', + 355 => 'TheForgottenTower', + 357 => 'SistersToTheSlaughter', + 359 => 'traveledToAct2', + 361 => 'introJerhyn', + 363 => 'RadamentsLair', + 365 => 'TheHoradricStaff', + 367 => 'TaintedSun', + 369 => 'ArcaneSanctuary', + 371 => 'TheSummoner', + 373 => 'TheSevenTombs', + 375 => 'traveledToAct3', + 377 => 'introHratli', + 379 => 'LamEsensTome', + 381 => 'KhalimsWill', + 383 => 'BladeOfTheOldReligion', + 385 => 'TheGoldenBird', + 387 => 'TheBlackenedTemple', + 389 => 'TheGuardian', + 391 => 'traveledtoAct4', + 393 => 'introToAct4', + 395 => 'TheFallenAngel', + 397 => 'TerrorsEnd', + 399 => 'HellForge', + 401 => 'empty', + 403 => 'empty', + 405 => 'empty', + 407 => 'traveledToAct5', + 409 => 'completedTerrorsEnd', + 414 => 'SiegeOnHarrogath', + 416 => 'RescueOnMountArreat', + 418 => 'PrisonOfIce', + 420 => 'BetrayalOfHarrogath', + 422 => 'RiteOfPassage', + 424 => 'EveOfDestruction', +]; + +$qNM = [ + 438 => 'introWarrivNM', + 440 => 'DenOfEvilNM', + 442 => 'SistersBurialGroundsNM', + 444 => 'ToolsOfTheTradeNM', + 446 => 'TheSearchForCainNM', + 448 => 'TheForgottenTowerNM', + 450 => 'SistersToTheSlaughterNM', + 452 => 'traveledToAct2NM', + 454 => 'introJerhynNM', + 456 => 'RadamentsLairNM', + 458 => 'TheHoradricStaffNM', + 460 => 'TaintedSunNM', + 462 => 'ArcaneSanctuaryNM', + 464 => 'TheSummonerNM', + 466 => 'TheSevenTombsNM', + 468 => 'traveledToAct3NM', + 470 => 'introHratliNM', + 472 => 'LamEsensTomeNM', + 474 => 'KhalimsWillNM', + 476 => 'BladeOfTheOldReligionNM', + 478 => 'TheGoldenBirdNM', + 480 => 'TheBlackenedTempleNM', + 482 => 'TheGuardianNM', + 484 => 'traveledtoAct4NM', + 486 => 'introToAct4NM', + 488 => 'TheFallenAngelNM', + 490 => 'TerrorsEndNM', + 492 => 'HellForgeNM', + 494 => 'emptyNM', + 496 => 'emptyNM', + 498 => 'emptyNM', + 500 => 'traveledToAct5NM', + 502 => 'completedTerrorsEndNM', + 504 => 'SiegeOnHarrogathNM', + 506 => 'RescueOnMountArreatNM', + 508 => 'PrisonOfIceNM', + 510 => 'BetrayalOfHarrogathNM', + 512 => 'RiteOfPassageNM', + 514 => 'EveOfDestructionNM', +]; + +$qHell = [ + 528 => 'introWarrivHell', + 530 => 'DenOfEvilHell', + 532 => 'SistersBurialGroundsHell', + 534 => 'ToolsOfTheTradeHell', + 536 => 'TheSearchForCainHell', + 538 => 'TheForgottenTowerHell', + 540 => 'SistersToTheSlaughterHell', + 542 => 'traveledToAct2Hell', + 544 => 'introJerhynHell', + 546 => 'RadamentsLairHell', + 548 => 'TheHoradricStaffHell', + 550 => 'TaintedSunHell', + 552 => 'ArcaneSanctuaryHell', + 554 => 'TheSummonerHell', + 556 => 'TheSevenTombsHell', + 558 => 'traveledToAct3Hell', + 560 => 'introHratliHell', + 562 => 'LamEsensTomeHell', + 564 => 'KhalimsWillHell', + 566 => 'BladeOfTheOldReligionHell', + 568 => 'TheGoldenBirdHell', + 570 => 'TheBlackenedTempleHell', + 572 => 'TheGuardianHell', + 574 => 'traveledtoAct4Hell', + 576 => 'introToAct4Hell', + 578 => 'TheFallenAngelHell', + 580 => 'TerrorsEndHell', + 582 => 'HellForgeHell', + 584 => 'emptyHell', + 586 => 'emptyHell', + 588 => 'emptyHell', + 590 => 'traveledToAct5Hell', + 592 => 'completedTerrorsEndHell', + 594 => 'SiegeOnHarrogathHell', + 596 => 'RescueOnMountArreatHell', + 598 => 'PrisonOfIceHell', + 600 => 'BetrayalOfHarrogathHell', + 602 => 'RiteOfPassageHell', + 604 => 'EveOfDestructionHell', +]; +echo "
";
+
+function isCompleted($questData) {
+    return (($questData[0] >> 0) & 1) > 0;
+}
+
+foreach ($questOffsetsNormal as $k => $v) {
+    fseek($fp, $k);
+    $questsNorm[$k] = fread($fp, $v);
+}
+
+foreach ($questOffsetsNM as $k => $v) {
+    fseek($fp, $k);
+    $questsNM[$k] = fread($fp, $v);
+}
+
+foreach ($questOffsetsHell as $k => $v) {
+    fseek($fp, $k);
+    $questsHell[$k] = fread($fp, $v);
+}
+
+foreach ($offsets as $k => $v) {
     fseek($fp, $k);
     $data[$k] = fread($fp, $v);
 }
 
-function strtobits(string $str): string
-{
+function strtobits(string $str): string {
     $ret = "";
-    for ($i = 0; $i < strlen($str); ++ $i) {
+    for ($i = 0; $i < strlen($str); ++$i) {
         $ord = ord($str[$i]);
-        for ($bitnum = 7; $bitnum >= 0; -- $bitnum) {
+        for ($bitnum = 7; $bitnum >= 0; --$bitnum) {
             if ($ord & (1 << $bitnum)) {
                 $ret .= "1";
             } else {
@@ -71,64 +339,75 @@ function strtobits(string $str): string
     return $ret;
 }
 
-$charData['Identifier'] = bin2hex($data['0']);
+$charData['Identifier'] = bin2hex($data[0]);
 
-$charData['VersionID'] = unpack('l', $data['4'])[1]; // 96 is v1.10+ - check out
+$charData['VersionID'] = unpack('l', $data[4])[1]; // 96 is v1.10+ - check out
 
-$charData['Filesize'] = round(unpack('l', $data['8'])[1]/1024, 2) . " KB";   // 1.41 KB (1,447 bytes) - checks out
-
-// $charData['Checksum'] = bin2hex($data['12']);   
+$charData['Filesize'] = round(unpack('l', $data[8])[1] / 1024, 2) . " KB";   // 1.41 KB (1,447 bytes) - checks out
+// $charData['Checksum'] = bin2hex($data['12']);
 // $charData['Activeweapon'] = unpack('l', $data['16']);
 
-$charData['CharacterName'] = ($data['20']);
+$charData['CharacterName'] = ($data[20]);
 
+$charData['CharacterStatus'] = array_filter(str_split(strtobits($data[36])));
 
-$charData['CharacterStatus'] = array_filter(str_split(strtobits($data['36'])));
-
-foreach ($charData['CharacterStatus'] as $k => $v){
+foreach ($charData['CharacterStatus'] as $k => $v) {
     $str .= ($characterStatus[$k]) . " ";
 }
 
 $charData['CharacterStatus'] = $str;
 
-
-
 // $charData['Characterprogression'] = bindec($data['37']);
 
-$charData['CharacterClass'] = $class[unpack('C',$data['40'])[1]];
+$charData['CharacterClass'] = $class[unpack('C', $data[40])[1]];
 
+$charData['CharacterLevel'] = unpack('C', $data[43])[1];
 
-$charData['CharacterLevel'] = unpack('C', $data['43'])[1];
-
-
-
-$charData['Lastplayed'] = gmdate("Y-m-d\TH:i:s\Z", unpack('I', $data['48'])[0]);
+$charData['Lastplayed'] = gmdate("Y-m-d\TH:i:s\Z", unpack('I', $data[48])[0]);
 
 // $charData['Assignedskills'] = (unpack('i16', $data['56']));
 
-$charData['LeftmousebuttonskillID'] = $skills[unpack('i', $data['120'])[1]];
-$charData['RightmousebuttonskillID'] = $skills[unpack('i', $data['124'])[1]];
-$charData['LeftswapmousebuttonskillID'] = $skills[unpack('i', $data['128'])[1]];
-$charData['RightswapmousebuttonskillID'] = $skills[unpack('i', $data['132'])[1]];
+$charData['LeftmousebuttonskillID'] = $skills[unpack('i', $data[120])[1]];
+$charData['RightmousebuttonskillID'] = $skills[unpack('i', $data[124])[1]];
+$charData['LeftswapmousebuttonskillID'] = $skills[unpack('i', $data[128])[1]];
+$charData['RightswapmousebuttonskillID'] = $skills[unpack('i', $data[132])[1]];
 
-// $charData['Charactermenuappearance'] = unpack('i', $data['136']);
+// $charData['Charactermenuappearance'] = unpack('i', $data[136]);
 
-$charData['Difficulty'] = strtobits($data['168']);
+$charData['Difficulty'] = strtobits($data[168]);
 
 // $charData['MapID'] = $data['171'];
-
 //$charData['Mercenarydead'] = unpack('i', $data['177']);
 //$charData['MercenaryID'] = $data['179'];
 //$charData['MercenaryNameID'] = $data['183'];
 //$charData['Mercenarytype'] = $data['185'];
 //$charData['Mercenaryexperience'] = $data['187'];
 
-$charData['Quests'] = $data['335'];
-$charData['Waypoints'] = $data['633'];
-$charData['NPCIntroductions'] = $data['714'];
 
+foreach ($questsNorm as $k => $v) {
+    $x = array_filter(str_split(strtobits($v), 8));
+    if ($x[0][0]) {
+        $quests[] = ($qNorm[$k] . " => " . (($x[0][0]) ? "Completed" : "Not Started") . "
"); + } +} +foreach ($questsNM as $k => $v) { + $x = array_filter(str_split(strtobits($v), 8)); + if ($x[0][0]) { + $quests[] = ($qNM[$k] . " => " . (($x[0][0]) ? "Completed" : "Not Started") . "
"); + } +} +foreach ($questsHell as $k => $v) { + $x = array_filter(str_split(strtobits($v), 8)); + if ($x[0][0]) { + $quests[] = ($qHell[$k] . " => " . (($x[0][0]) ? "Completed" : "Not Started") . "
"); + } +} + +$charData['Quests'] = $quests; + +$charData['Waypoints'] = $data[633]; +$charData['NPCIntroductions'] = $data[714]; -echo "
";
 print_r($charData);
 
 // $charData['Unknown'] = $data['44'];