From dd662e26f65c1f057c06220c7a2c6374bb664258 Mon Sep 17 00:00:00 2001 From: Hash Borgir Date: Tue, 30 May 2023 12:06:58 -0600 Subject: [PATCH] Working copy --- .DS_Store | Bin 0 -> 10244 bytes .idea/vcs.xml | 1 + CharEditor.php | 42 ++++++++++------ D2Reviver.php | 114 +++++++++++++++++++++++++++++++++++++++++++ bin/D2SC.exe | Bin 0 -> 13824 bytes processFiles.php | 39 +++++++-------- src/D2BitReader.php | 3 +- src/D2ByteReader.php | 22 +++++++-- src/D2Char.php | 10 ++-- src/D2Database.php | 18 +++++++ test.php | 42 ---------------- 11 files changed, 206 insertions(+), 85 deletions(-) create mode 100644 .DS_Store create mode 100644 D2Reviver.php create mode 100644 bin/D2SC.exe delete mode 100644 test.php diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ded57de86b95f40b5b19c45d89f03dca61dff930 GIT binary patch literal 10244 zcmeHM&u<$=6n+z@ja@hCCQV9Pfn<>jQXAv6rBa2UuA5QGFK*m7EK*m7E z!2f{(?AcuMMJ2O)#z4kE#=vt1czr10Vp&b(u99-;z)cNh{j_0LBubRkRB^8`Ra`+HQ&muXY2-!RAm!vw0s*>3~V<2N-m;rTm zFE{&9uj%RM_e$kgF_s%Yba)~^kuT=&)b9oTdThsAQOyo-aceCIyyjlrZr*gAe#4r* z8u+p8`c5bTZrg#%?ay4l9rSC#mfwyfwys{}3;9CBI{EnVVrB7cY4Jkk$=TB5OXn(Q zOBc>xeDb7_pPPUC-POheuj>b2Dd$D90MO(>FkhoBsO+}3lSstR>X(R0<#)^4i=}X+ zcyw~=m^D3fe0p|zZtlcuC+AL`KJ|LTI^MKf4>}?Hcs1~Xu;y(!>uxLX>+U0GJ$80t zt~9Kf0lihHefPzqwTC_E%)WRaZCwu?$G_DH-S&;m&B%$@wfaWGIu^CU!1Gpu$c^2= z-?$xt-sRZoF8iASdfW!JH+uXky6J=wh zSqUAsB>S%S?3U|y<}d%HXq>OE>{Z@U6^rIog=oII`@O8^XZIc@QWVzwz;_Ds)sK@W zc{)Q^=p(ArJ?hgp^ez2BPw6N6jsBp&#ke>j-V|rV1@WG^EIt&UidE4PZQ+Xh3O}|t zylMeUgD@kPD39jHO|04@(yieJ5AJ@)+ z-j4%%r=jD+ZV1aRMNtK=1n?oA1CH+f*{$CMUUW za~6K~@bRQqG5p(-o-V-a7FxdKW!Sf819o!M1j08X7-N?8-lpg(Sg^svHE`k*_ZRNN z{C67jN2Om5?hhz}m)#LK9tj;cBje~I#sD}6{Vhlt!$vRNhGbs1F*#(Tj4X(lA2VXX z{2qk#fI}1mNM`gPBxfktGm(;I9eG50>(eF}?xaV^c`c?ib}fv@Im`tgzQtfELcI@u zBH&}>RBZN1VA;SIX$kmGfNtZ%ESDjhCW?7AP?Hk13jJ;Px}D%s<{|SsfMkE!%NHJ} zdMd!HfgFcl%ztG1#w;3o1?X{>b?MBI1R>a8Ht)XJj*Z2Iet-E7@9?r#r-Xu zmou90>GPQx)h!eUd?fbsGiDIR|~YviFo; zd8Uuu)i^A`%fvR;FkVkn=C*+-!V~O_k{cf1bY_r=2Fg~apyA0=2%7`(u z20n-Ap>4*`v)Ry^hCQBh&hwqc=7`W9v9BoA*Ko`hDD+NiMmVP0ZK8`0y%f;B(Lksb%&e`P6%vf>vMl z!{0>INd^z0~L>qq=rM#=<+UCs`XBMdmB_zQ$KxA`oeM56qaMpMxgs z4@3-JhO~xuF6PD1IxMq?XFa})3|IsYhVCJHBzJ?Mxy>9Hn%K;ddGmul^m5Pwp zM*si+a+8onmoe~)Ga$y7>Pt0{AVv_uzqOZeeU6I@>+LEjA-EZT1fan`$IBm*@UDWo fET~tx0=cUsYAFBxp8?tV-#jg6=YOJC>-_&ODK<@T literal 0 HcmV?d00001 diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..b681626 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/CharEditor.php b/CharEditor.php index a04b751..0c28dba 100644 --- a/CharEditor.php +++ b/CharEditor.php @@ -1,9 +1,5 @@ $v) { //$filePath = "D:\Diablo II\MODS\MedianXL2012\save\Test.d2s"; -$filePath = "Necro.d2s"; +$filePath = "Test.d2s"; $char = new D2Char($filePath); -$char->setChar("CharacterStatus", "Died", 0); -$char->setChar("CharacterStatus", "Hardcore", 1); + +//$char->setChar("CharacterStatus", "Died", 0); +//$char->setChar("CharacterStatus", "Hardcore", 1); //$char->setChar("CharacterStatus", "Expansion", 1); //$char->setChar("LeftmousebuttonskillID", 223); @@ -53,13 +55,21 @@ $char->setAllSkills(1); //$char->setSkill(1, 99); //$char->setChar("CharacterClass", "Necromancer"); // 127 //$char->setChar("CharacterProgression", 1); // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell -$char->setChar("CharacterLevel", 25); -//$char->setStat("strength", 70); -//$char->setStat("energy", 70); -//$char->setStat("dexterity", 70); -//$char->setStat("vitality", 70); -//$char->setStat("mana", 200); -//$char->setStat("maxmana", 200); + +//$char->setChar("CharacterStatus", "Died", 1); +$char->setChar("CharacterLevel", 99); +$char->setStat("strength", 270); +$char->setStat("energy", 270); +$char->setStat("dexterity", 270); +$char->setStat("vitality", 270); +$char->setStat("hitpoints", 100); +$char->setStat("maxhp", 150); +$char->setStat("stamina", 280); +$char->setStat("maxstamina", 290); +$char->setStat("mana", 70); +$char->setStat("maxmana", 200); + + //$char->setStat("soulcounter", 80); // //$char->setStat("hitpoints", 70); @@ -77,4 +87,6 @@ $char->setChar("CharacterLevel", 25); unset($char); // destroy $char so we can read it again after writing to it to get updated stats $char = new D2Char($filePath); -var_dump($char->cData); + +var_dump($char->cData['CharacterStatus']); +var_dump($char->cData['stats']); diff --git a/D2Reviver.php b/D2Reviver.php new file mode 100644 index 0000000..743b62c --- /dev/null +++ b/D2Reviver.php @@ -0,0 +1,114 @@ + <_____________> https://d2mods.org +EOT; +$cbits = [ + 0 => 10, 1 => 10, 2 => 10, 3 => 10, 4 => 10, 5 => 8, 6 => 21, 7 => 21, 8 => 21, 9 => 21, 10 => 21, + 11 => 21, 12 => 7, 13 => 32, 14 => 25, 15 => 25, 37 => 31, 39 => 31, 41 => 31, 43 => 31, 45 => 31, + 183 => 31, 184 => 31, 185 => 31]; // CSvBits to skip + +$exp = [ + 0, 500, 1500, 3750, 7875, 14175, 22680, 32886, 44396, 57715, 72144, 90180, 112725, 140906, 176132, 220165, 275207, 344008, + 430010, 537513, 671891, 839864, 1049830, 1312287, 1640359, 2050449, 2563061, 3203826, 3902260, 4663553, 5493363, 6397855, + 7383752, 8458379, 9629723, 10906488, 12298162, 13815086, 15468534, 17270791, 19235252, 21376515, 23710491, 26254525, 29027522, + 32050088, 35344686, 38935798, 42850109, 47116709, 51767302, 56836449, 62361819, 68384473, 74949165, 82104680, 89904191, 98405658, + 107672256, 117772849, 128782495, 140783010, 153863570, 168121381, 183662396, 200602101, 219066380, 239192444, 261129853, 285041630, + 311105466, 339515048, 370481492, 404234916, 441026148, 481128591, 524840254, 572485967, 624419793, 681027665, 742730244, 809986056, + 883294891, 963201521, 1050299747, 1145236814, 1248718217, 1361512946, 1484459201, 1618470619, 1764543065, 1923762030, 2097310703, + 2286478756, 2492671933, 2717422497, 2962400612, 3229426756, 3520485254, 3837739017]; + +//$file = "D:\Diablo II\MODS\ironman-dev\save\Necro.d2s"; +$file = $argv[1]; +if (!file_exists($file)) + die("$file does not exist!"); + +// create ByteReader object from file binary data +$BR = new D2ByteReader(file_get_contents($file)); +$data = $BR->getData(); + +// offset 36 +// 7 6 5 4 3 2 1 0 +// unknown Expansion Character unknown Died Hardcore unknown +$statusByte = unpack('C', $data[36])[1]; +$dBit = getBit($statusByte, 3); + +// if Character is dead, then make it alive, reduce 5 levels as penalty + +if ($dBit) { + // using {} for better readability + { + $gf = strposX($data, 'gf', 1) + 2; // find gf and skip it + $if = strposX($data, 'if', 1); + $len = $if - $gf; + // create bitstream + $stats = new D2BitReader($BR->toBits($BR->readh($gf, $len))); + // remove 0x1FF from end + $bits = $stats->getBits(); + $cleanbits = substr($bits, 0, -11); + $stats->setBits($cleanbits); + $bits = $stats->getBits(); + // rewind bitstream + $stats->rewind(); + // get bit offsets for each stat + $offsets = []; + for ($i = 0; $i < count($cbits); $i++) { + $id = hexdec($BR->toBytesR($stats->readb(9))); + $offsets[$id] = $stats->getOffset(); + $stats->skip($cbits[$id]); + } + $offsets[0] = 9; + // get current character level + $level = unpack('C', $data[43])[1]; + $stats->seek($offsets[12]); + $_level = hexdec($BR->toBytesR($stats->readb(7))); + // reduce current character level by 5, no penalty if < 6 + if ($_level >= 80) { + $level -= 10; + } else if ($_level >= 5 || $level <= 80) { + $level -= 5; + } else if ($_level <= 5) { + $level = 1; + } + } + $data[43] = pack('C', $level); + $statusByteNew = setBit($statusByte, 3, 0); // make character alive + $data[36] = pack('C', $statusByteNew); // make character alive + + $bitsToWriteLevel = strrev(str_pad(decbin(intval($level)), $cbits[12], 0, STR_PAD_LEFT)); + $bitsToWriteExp = strrev(str_pad(decbin(intval($exp[$level])), $cbits[13], 0, STR_PAD_LEFT)); + + $_newBitsTemp = $stats->writeBits($bits, $bitsToWriteLevel, $offsets[12]); + $newBits = $stats->writeBits($_newBitsTemp, $bitsToWriteExp, $offsets[13]) . "11111111100"; + $bytes = $BR->toBytes($newBits); + + $BR->setData($data); + $BR->writeBytes($gf, $bytes); + $BR->writeBytes(12, "00000000"); + $checksum = checksum(unpack('C*', $BR->getData())); + $BR->writeBytes(12, $checksum); + $data = $BR->getData(); + file_put_contents($file, $data); + + echo "
$str\n\n\nCharacter is now alive. Go take some mushrooms!\n";
+    echo "Previous Level: $_level\n";
+    echo "Revive Penalty: " . $_level - $level . "\n";
+    echo "New Level: $level\n";
+} else {
+    echo "
$str\n\n\nCharacter is not dead. Have you been taking mushrooms lately?";
+}
\ No newline at end of file
diff --git a/bin/D2SC.exe b/bin/D2SC.exe
new file mode 100644
index 0000000000000000000000000000000000000000..8b2dfed744c8177910b64be27fe5b38919ea98eb
GIT binary patch
literal 13824
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
J{x5srzW|OJZv+4U

literal 0
HcmV?d00001

diff --git a/processFiles.php b/processFiles.php
index 25605e4..a9bfcd8 100755
--- a/processFiles.php
+++ b/processFiles.php
@@ -107,14 +107,13 @@ if (file_exists(APP_DB)) {
     processFilesManuallyInSqlite();
     processFilesManuallyInSqliteLinux();
 
-    
     function toPngAll() {
         $q = realpath("bin\qdc6.exe");
-        $iPath = $_SESSION['modpath']."\data\global\items";
-        $oPath = realpath("docs\\{$_SESSION['modname']}\img\\items");       
-        exec("$q --first-frame-only \"$iPath\" -o \"$oPath\"");    
-    }    
-    
+        $iPath = $_SESSION['modpath'] . "\data\global\items";
+        $oPath = realpath("docs\\{$_SESSION['modname']}\img\\items");
+        exec("$q --first-frame-only \"$iPath\" -o \"$oPath\"");
+    }
+
     if (!is_dir("docs\\{$_SESSION['modname']}")) {
         mkdir("docs\\{$_SESSION['modname']}");
         mkdir("docs\\{$_SESSION['modname']}\\fonts", 0777, TRUE);
@@ -124,36 +123,38 @@ if (file_exists(APP_DB)) {
     rcopy(realpath('docs/template/fonts'), realpath("docs\\{$_SESSION['modname']}\\fonts"));
     rcopy(realpath('docs/template/img'), realpath("docs\\{$_SESSION['modname']}\\img"));
     rcopy(realpath('docs/template/res'), realpath("docs\\{$_SESSION['modname']}\\res"));
-    
+
     toPngAll();
-    
-    
-    
+
     /*
       Process tbl files
-     *
-     *
-    */
+     */
     $tbl = $_SESSION['tbl'];
-
     // ddump($tbl);
-
     /*
       $string = D2Tbl::getStrings($tbl."string.tbl");
       $stringExpansion = D2Tbl::getStrings($tbl."expansionstring.tbl");
       $stringPatch = D2Tbl::getStrings($tbl."patchstring.tbl");
-
       $strings = array_merge($stringPatch, $stringExpansion, $string);
      */
-
     $strs = ["dummy" => "dummy"];
     foreach (glob($tbl . "*.tbl") as $filename) {
         $strings = D2Tbl::getStrings($filename);
         if (!empty($strings))
             $strs = array_merge($strs, $strings);
     }
-
     $db->writeTbl($strs);
+
+    // write each table to invidual db table
+    $tbl = $_SESSION['tbl'];
+    foreach (glob($tbl . "*.tbl") as $filename) {
+        $tblName = pathinfo($filename)['filename'];
+        $strings = D2Tbl::getStrings($filename);
+        if (!empty($strings)) {
+            $db->writeTbls($tblName, $strings);
+        }
+        
+    }
 } else {
     // if config db does not exist, go to configure page
     header("Location: /src/D2Config.php");
@@ -167,7 +168,7 @@ if (file_exists(APP_DB)) {
 
 
     
-       
+        
     
     
     
diff --git a/src/D2BitReader.php b/src/D2BitReader.php
index 70c61a4..861c340 100644
--- a/src/D2BitReader.php
+++ b/src/D2BitReader.php
@@ -54,6 +54,7 @@ class D2BitReader {
      * @return array|string|string[]
      */
     public function writeBits(string $bits, string $bitsToWrite, int $offset) {
+        //$this->bits = substr_replace($bits, $bitsToWrite, $offset, strlen($bitsToWrite));
         return substr_replace($bits, $bitsToWrite, $offset, strlen($bitsToWrite));
     }
 
@@ -63,7 +64,7 @@ class D2BitReader {
      * @return string
      */
     public function readb(int $numBits = 0, bool $str = true): string {
-        $bits = null;
+        $bits = '';
         for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
             $str ? $bits .= $this->bits[$i] : $bits[] = $this->bits[$i];
         }
diff --git a/src/D2ByteReader.php b/src/D2ByteReader.php
index 4c087bd..35e62ff 100644
--- a/src/D2ByteReader.php
+++ b/src/D2ByteReader.php
@@ -54,7 +54,22 @@ class D2ByteReader {
      * @param bool $str
      * @return string
      */
-    public function readh(int $offset, int $numBytes, bool $str = true): string {
+    public function read(int $offset, int $numBytes) {
+        $this->seek($offset);
+        $bytes = null;
+        for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
+            $bytes .= $this->data[$i];
+        }
+        return $bytes;
+    }
+    
+    /**
+     * @param int $offset
+     * @param int $numBytes
+     * @param bool $str
+     * @return string
+     */
+    public function readh(int $offset, int $numBytes, bool $str = true) {
         $this->seek($offset);
         $bytes = null;
         for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
@@ -62,14 +77,14 @@ class D2ByteReader {
         }
         return unpack('H*', $bytes)[1];
     }
-
+    
     /**
      * @param int $offset
      * @param int $numBytes
      * @param bool $str
      * @return array
      */
-    public function readc(int $offset, int $numBytes, bool $str = true): array {
+    public function readc(int $offset, int $numBytes, bool $str = true) {
         $this->seek($offset);
         $bytes = null;
         for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
@@ -187,6 +202,7 @@ class D2ByteReader {
      * @return string
      */
     public function toBytesR(string $bits) : string {
+        $bytes = '';
         foreach (str_split($bits, 8) as $byteString) {
             $bytes .= strtoupper(str_pad(dechex(bindec(($byteString))), 2, 0, STR_PAD_LEFT));
         }
diff --git a/src/D2Char.php b/src/D2Char.php
index a4fdc75..5f8c6f7 100644
--- a/src/D2Char.php
+++ b/src/D2Char.php
@@ -219,7 +219,7 @@ WHERE sk.charclass = '$class'";
         unset($this->items);
         //unset($this->bData);
         unset($this->sData);
-        unset($this->fp);
+        //unset($this->fp);
 
         return $this->cData;
     }
@@ -292,7 +292,7 @@ WHERE sk.charclass = '$class'";
         $bytes = $this->ByteReader->toBytes($bits);
 
         $stats->rewind();
-        for ($i = 0; $i <= strlen($bits); $i++) {
+        for ($i = 0; $i <= count($this->ISC); $i++) {
             $id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
             if ($this->ISC[$id]['CSvBits'] !== NULL && $this->ISC[$id]['CSvBits'] !== '') {
                 $stats->skip($this->ISC[$id]['CSvBits']);
@@ -314,8 +314,8 @@ WHERE sk.charclass = '$class'";
         $values['maxmana'] = (int) round($values['maxmana'] >> 11);
         $values['stamina'] = (int) round($values['stamina'] >> 11);
         $values['maxstamina'] = (int) round($values['maxstamina'] >> 11);
-        $values['soulcounter'] = (int) round($values['soulcounter'] / 2);
-        $values['killcounter'] = (int) round($values['killcounter'] / 2);
+//        $values['soulcounter'] = (int) round($values['soulcounter'] / 2);
+//        $values['killcounter'] = (int) round($values['killcounter'] / 2);
 
         $this->cData['stats'] = $values;
     }
@@ -463,7 +463,7 @@ WHERE sk.charclass = '$class'";
         }
         $stats .= "000011111111100";
 
-        dump($stats);
+        //dump($stats);
 
         $gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
         $if = strposX($this->data, 'if', 1);
diff --git a/src/D2Database.php b/src/D2Database.php
index 80ac05f..1bd728b 100755
--- a/src/D2Database.php
+++ b/src/D2Database.php
@@ -140,6 +140,24 @@ class D2Database {
 		$res = PDO_Execute($sql);
 	}
 
+    /**
+     * @param $data
+     * @return void
+     */
+    public function writeTbls($table,$data) {
+		$sql = "CREATE TABLE IF NOT EXISTS `$table` (`Key` VARCHAR(255), `String` VARCHAR(255));";
+		$res = PDO_Execute($sql);
+
+		$sql = "INSERT INTO `$table` (`Key`,`String`) VALUES ";
+		foreach ($data as $k => $v) {
+			$sql .= "(\"$k\",\"$v\"),";
+		}
+		$sql = rtrim($sql, ", ");
+		$sql .= ";";
+
+		$res = PDO_Execute($sql);
+	}
+    
     /**
      * @param $key
      * @return mixed
diff --git a/test.php b/test.php
deleted file mode 100644
index 3c1c5e6..0000000
--- a/test.php
+++ /dev/null
@@ -1,42 +0,0 @@
- $byte) {
-        if ($k == 12 || $k == 13 || $k == 14 || $k == 15) {
-            $byte = 0;
-        }
-        $nSignature = ((($nSignature << 1) | ($nSignature >> 31)) + $byte & 0xFFFFFFFF);
-    }
-    return swapEndianness(str_pad(dechex($nSignature), 8, 0, STR_PAD_LEFT));
-}
-
-$filename = "D:\Diablo II\MODS\ironman-dev\save\Necro.d2s";
-$fp = fopen($filename, "r+b");
-
-fseek($fp, 12); // go to byte 12
-fwrite($fp, pack('I', 0)); // clear the checksum field uInt32
-
-$fileData = unpack('C*', file_get_contents($filename)); // open file and unpack
-
-
-var_dump(checksum($fileData));
-
-fseek($fp, 12); // go to byte 12
-fwrite($fp, pack('H8', checksum($fileData))); // write new checksum
-fclose($fp);
\ No newline at end of file