mirror of
https://gitlab.com/hashborgir/d2tools.git
synced 2024-11-30 04:26:03 +00:00
Checksum code fixed. Added DocBlocks to D2Classes. TODO: Fill in docblocks, refactor, code cleanup
This commit is contained in:
parent
f3b24de2a8
commit
eb28039f88
8
.idea/.gitignore
vendored
Normal file
8
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
13
.idea/D2Modder.iml
Normal file
13
.idea/D2Modder.iml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/formr/formr" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/D2Modder.iml" filepath="$PROJECT_DIR$/.idea/D2Modder.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
.idea/php.xml
Normal file
12
.idea/php.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/formr/formr" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.4">
|
||||
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -42,23 +42,39 @@ foreach ($ISCData as $k => $v) {
|
||||
//$filePath = "D:\Diablo II\MODS\MedianXL2012\save\Test.d2s";
|
||||
|
||||
|
||||
$filePath = "Test.d2s";
|
||||
$filePath = "Necro.d2s";
|
||||
$char = new D2Char($filePath);
|
||||
//$char->setAllSkills(56);
|
||||
$char->setChar("CharacterStatus", "Died", 0);
|
||||
$char->setChar("CharacterStatus", "Hardcore", 1);
|
||||
//$char->setChar("CharacterStatus", "Expansion", 1);
|
||||
//$char->setChar("LeftmousebuttonskillID", 223);
|
||||
|
||||
$char->setAllSkills(1);
|
||||
//$char->setSkill(1, 99);
|
||||
//$char->setChar("CharacterClass", 1); // 127
|
||||
$char->setChar("CharacterLevel", 0);
|
||||
$char->setStat("strength", 30);
|
||||
$char->setStat("energy", 30);
|
||||
$char->setStat("dexterity", 30);
|
||||
$char->setStat("vitality", 30);
|
||||
$char->setStat("mana", 120);
|
||||
$char->setStat("maxmana", 200);
|
||||
$char->setStat("stamina", 80);
|
||||
$char->setStat("maxstamina", 120);
|
||||
//$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->setStat("soulcounter", 80);
|
||||
//
|
||||
//$char->setStat("hitpoints", 70);
|
||||
//$char->setStat("maxhp", 70);
|
||||
//$char->setStat("stamina", 70);
|
||||
//$char->setStat("maxstamina", 200);
|
||||
//
|
||||
//
|
||||
//$char->setStat("gold", 0);
|
||||
//$char->setStat("soulcounter", 40273409479012734098712903479012374091827349081273490172093478);
|
||||
|
||||
|
||||
|
||||
|
||||
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['stats']);
|
||||
var_dump($char->cData);
|
||||
|
BIN
bin/d2cr.exe
Normal file
BIN
bin/d2cr.exe
Normal file
Binary file not shown.
BIN
bin/d2sgcs.exe
BIN
bin/d2sgcs.exe
Binary file not shown.
BIN
img/bg.png
Normal file
BIN
img/bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
11
ironman-dev.sqbpro
Normal file
11
ironman-dev.sqbpro
Normal file
File diff suppressed because one or more lines are too long
@ -1,15 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2BitReader {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $bits = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private int $offset = 0;
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
*/
|
||||
public function __construct(string $bits = '') {
|
||||
$this->bits = $bits;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numBits
|
||||
* @return int
|
||||
*/
|
||||
public function skip(int $numBits): int {
|
||||
$this->offset += $numBits;
|
||||
return $this->offset;
|
||||
@ -17,6 +33,11 @@ class D2BitReader {
|
||||
|
||||
/* read X number of bits, like fread */
|
||||
|
||||
/**
|
||||
* @param int $numBits
|
||||
* @param bool $str
|
||||
* @return string
|
||||
*/
|
||||
public function read(int $numBits = 0, bool $str = true): string {
|
||||
$bits = null;
|
||||
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
||||
@ -26,10 +47,21 @@ class D2BitReader {
|
||||
return $bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @param string $bitsToWrite
|
||||
* @param int $offset
|
||||
* @return array|string|string[]
|
||||
*/
|
||||
public function writeBits(string $bits, string $bitsToWrite, int $offset) {
|
||||
return substr_replace($bits, $bitsToWrite, $offset, strlen($bitsToWrite));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numBits
|
||||
* @param bool $str
|
||||
* @return string
|
||||
*/
|
||||
public function readb(int $numBits = 0, bool $str = true): string {
|
||||
$bits = null;
|
||||
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
||||
@ -39,6 +71,10 @@ class D2BitReader {
|
||||
return strrev(str_pad($bits, 16, 0, STR_PAD_RIGHT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numBits
|
||||
* @return string
|
||||
*/
|
||||
public function readr(int $numBits = 0): string {
|
||||
$bits = null;
|
||||
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
||||
@ -50,6 +86,10 @@ class D2BitReader {
|
||||
|
||||
/* seek to offset (like fseek) */
|
||||
|
||||
/**
|
||||
* @param int $pos
|
||||
* @return bool
|
||||
*/
|
||||
public function seek(int $pos): bool {
|
||||
if ($pos < 0 || $pos > strlen($this->bits)) {
|
||||
return false;
|
||||
@ -60,6 +100,9 @@ class D2BitReader {
|
||||
|
||||
/* rewind offset to 0 */
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function rewind(): bool {
|
||||
$this->offset = 0;
|
||||
return true;
|
||||
@ -67,6 +110,10 @@ class D2BitReader {
|
||||
|
||||
/* Get Bit */
|
||||
|
||||
/**
|
||||
* @param string $bitNum
|
||||
* @return int
|
||||
*/
|
||||
public function getBit(string $bitNum): int {
|
||||
if ($bitNum < 0 || $bitNum > strlen($this->bits)) {
|
||||
return false;
|
||||
@ -76,6 +123,11 @@ class D2BitReader {
|
||||
|
||||
/* Set Bit */
|
||||
|
||||
/**
|
||||
* @param int $bitNum
|
||||
* @param int $bitVal
|
||||
* @return bool
|
||||
*/
|
||||
public function setBit(int $bitNum, int $bitVal): bool {
|
||||
if ($bitVal < 0 || $bitVal > 1) {
|
||||
return false;
|
||||
@ -84,18 +136,32 @@ class D2BitReader {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getBits(): string {
|
||||
return $this->bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @return void
|
||||
*/
|
||||
public function setBits(string $bits) {
|
||||
$this->bits = $bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset(): int {
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @return bool
|
||||
*/
|
||||
public function setOffset(int $offset): bool {
|
||||
if ($offset < 0 || $offset > strlen($this->bits))
|
||||
return false;
|
||||
|
@ -3,17 +3,33 @@
|
||||
require_once './src/D2Functions.php';
|
||||
require_once './src/D2BitReader.php';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2ByteReader {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $data = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private int $offset = 0;
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
*/
|
||||
public function __construct(string $data) {
|
||||
if (!$data)
|
||||
return false;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $numBytes
|
||||
* @return bool
|
||||
*/
|
||||
public function skip(int $numBytes): bool {
|
||||
if ($numBytes < 0 || $numBytes > strlen($this->data))
|
||||
return false;
|
||||
@ -21,6 +37,10 @@ class D2ByteReader {
|
||||
return $true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pos
|
||||
* @return bool
|
||||
*/
|
||||
public function seek(int $pos): bool {
|
||||
if ($pos < 0 || $pos > strlen($this->data))
|
||||
return false;
|
||||
@ -28,6 +48,12 @@ class D2ByteReader {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param int $numBytes
|
||||
* @param bool $str
|
||||
* @return string
|
||||
*/
|
||||
public function readh(int $offset, int $numBytes, bool $str = true): string {
|
||||
$this->seek($offset);
|
||||
$bytes = null;
|
||||
@ -37,6 +63,12 @@ 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 {
|
||||
$this->seek($offset);
|
||||
$bytes = null;
|
||||
@ -46,15 +78,28 @@ class D2ByteReader {
|
||||
return unpack('C*', $bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function rewind(): bool {
|
||||
$this->offset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param int $byte
|
||||
* @return void
|
||||
*/
|
||||
public function writeByte(int $offset, int $byte) {
|
||||
$this->data[$offset] = pack('C', $byte);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param string $bytes
|
||||
* @return false|void
|
||||
*/
|
||||
public function writeBytes(int $offset, string $bytes) {
|
||||
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
||||
return false;
|
||||
@ -64,6 +109,12 @@ class D2ByteReader {
|
||||
$this->data[$pos] = pack('H*', $byte);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $offset
|
||||
* @param string $bytes
|
||||
* @return false|void
|
||||
*/
|
||||
public function insertBytes(int $offset, string $bytes) {
|
||||
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
||||
return false;
|
||||
@ -72,18 +123,32 @@ class D2ByteReader {
|
||||
$this->data = hex2bin($newData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|string
|
||||
*/
|
||||
public function getData() {
|
||||
return $this->data ? $this->data : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function setData($data){
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getOffset(): int {
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return bool
|
||||
*/
|
||||
public function isHexString(string $str): bool {
|
||||
if (strlen($str) % 2 == 0 && (ctype_xdigit($str))) {
|
||||
return true;
|
||||
@ -91,6 +156,10 @@ class D2ByteReader {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $input
|
||||
* @return string
|
||||
*/
|
||||
public function toBits($input): string {
|
||||
$output = '';
|
||||
if ($this->isHexString($input)) {
|
||||
@ -113,6 +182,10 @@ class D2ByteReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @return string
|
||||
*/
|
||||
public function toBytesR(string $bits) : string {
|
||||
foreach (str_split($bits, 8) as $byteString) {
|
||||
$bytes .= strtoupper(str_pad(dechex(bindec(($byteString))), 2, 0, STR_PAD_LEFT));
|
||||
@ -120,6 +193,10 @@ class D2ByteReader {
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @return string
|
||||
*/
|
||||
public function toBytes(string $bits) : string {
|
||||
foreach (str_split($bits, 8) as $byteString) {
|
||||
$bytes .= strtoupper(str_pad(dechex(bindec(strrev($byteString))), 2, 0, STR_PAD_LEFT));
|
||||
@ -127,6 +204,10 @@ class D2ByteReader {
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @return string
|
||||
*/
|
||||
public function bitsToHexString(string $bits): string {
|
||||
$bytes = '';
|
||||
foreach (str_split($bits, 8) as $byte) {
|
||||
@ -135,6 +216,10 @@ class D2ByteReader {
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @return array
|
||||
*/
|
||||
public function bitsToHexArray(string $bits): array {
|
||||
$bytes = [];
|
||||
foreach (str_split($bits, 8) as $byte) {
|
||||
@ -143,6 +228,10 @@ class D2ByteReader {
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
* @return array
|
||||
*/
|
||||
public function bitsToIntArray(string $bits): array {
|
||||
$bytes = [];
|
||||
foreach (str_split($bits, 8) as $byte) {
|
||||
@ -151,18 +240,21 @@ class D2ByteReader {
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
@return Byte with Nth bit set to X
|
||||
/**
|
||||
* @param int $byte
|
||||
* @param int $pos
|
||||
* @param bool $bit
|
||||
* @return int
|
||||
*/
|
||||
|
||||
public function setBit(int $byte, int $pos, bool $bit) {
|
||||
return ($bit ? ($byte | (1 << $pos)) : ($byte & ~(1 << $pos)) );
|
||||
}
|
||||
|
||||
/*
|
||||
@return Bit at Nth position in Byte
|
||||
/**
|
||||
* @param int $byte
|
||||
* @param int $pos
|
||||
* @return int
|
||||
*/
|
||||
|
||||
public function getBit(int $byte, int $pos): int {
|
||||
return intval(($byte & (1 << $pos)) != 0);
|
||||
}
|
||||
|
266
src/D2Char.php
266
src/D2Char.php
@ -8,24 +8,70 @@ require_once 'D2Item.php';
|
||||
require_once 'D2ByteReader.php';
|
||||
require_once 'D2Functions.php';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2Char {
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
public $cData = null; // char data output
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
public $items = null; // char item data
|
||||
/**
|
||||
* @var D2ByteReader|null
|
||||
*/
|
||||
public $ByteReader = null; // put $data into bytereader
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $filePath = null; // .d2s file path
|
||||
/**
|
||||
* @var D2CharStructureData
|
||||
*/
|
||||
private $sData = null; // char file structure data
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $bData = null; // char binary data from d2s
|
||||
/**
|
||||
* @var false|resource
|
||||
*/
|
||||
private $fp = null; // file pointer
|
||||
/**
|
||||
* @var false|string
|
||||
*/
|
||||
private $data = null; // full d2s file loaded in $data
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $ISC = null;
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $skillData = null;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function save() {
|
||||
file_put_contents($this->filePath, $this->data);
|
||||
checksumFix($this->filePath);
|
||||
$this->ByteReader->setData($this->data); // update bytereader data
|
||||
$this->ByteReader->writeBytes(12, "00000000"); // clear old checksum
|
||||
$this->data = $this->ByteReader->getData(); // update this data to what we get from bytereader after clearing checksum
|
||||
$checksum = checksum(unpack('C*', $this->data)); // get new checksum
|
||||
|
||||
$this->ByteReader->setData($this->data); // update bytereader data
|
||||
$this->ByteReader->writeBytes(12, $checksum); // write new checksum
|
||||
$this->data = $this->ByteReader->getData(); // update this data
|
||||
file_put_contents($this->filePath, $this->data); // write file
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
*/
|
||||
public function __construct($file) {
|
||||
$this->sData = new D2CharStructureData();
|
||||
$this->filePath = $_SESSION['savepath'] . $file;
|
||||
@ -64,6 +110,9 @@ WHERE sk.charclass = '$class'";
|
||||
return $this->parseChar(); // end of parseChar() calls parseItems(), parseStats, etc.
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function parseItems() {
|
||||
$i_TotalOffset = strpos($this->data, "JM");
|
||||
fseek($this->fp, $i_TotalOffset + 2);
|
||||
@ -83,6 +132,9 @@ WHERE sk.charclass = '$class'";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|null
|
||||
*/
|
||||
public function parseChar() {
|
||||
$cData = null;
|
||||
$cData['Identifier'] = bin2hex($this->bData[0]);
|
||||
@ -90,30 +142,46 @@ WHERE sk.charclass = '$class'";
|
||||
$cData['VersionID'] = ($this->sData->version[unpack('l', $this->bData[4])[1]]);
|
||||
|
||||
// 1.41 KB (1,447 bytes) - checks out
|
||||
$cData['Filesize'] = round(unpack('l', $this->bData[8])[1] / 1024, 2) . " KB";
|
||||
//$cData['Filesize'] = round(unpack('l', $this->bData[8])[1] / 1024, 2) . " KB";
|
||||
$cData['Filesize'] = unpack('L', $this->bData[8])[1];
|
||||
$cData['Checksum'] = bin2hex($this->bData[12]);
|
||||
$cData['Activeweapon'] = unpack('l', $this->bData[16]);
|
||||
$cData['Activeweapon'] = unpack('L', $this->bData[16]);
|
||||
$cData['CharacterName'] = str_replace("\0", "", $this->bData[20]);
|
||||
$cData['CharacterStatus'] = array_filter(str_split(strtobits($this->bData[36])));
|
||||
foreach ($cData['CharacterStatus'] as $k => $v) {
|
||||
$str .= ($characterStatus[$k]) . " ";
|
||||
$characterStatus = array_filter(str_split(strrev(strtobits($this->bData[36]))));
|
||||
foreach ($characterStatus as $k => $v) {
|
||||
$str .= $this->sData->characterStatus[$k] . " ";
|
||||
}
|
||||
$cData['CharacterStatus'] = $str;
|
||||
$cData['Characterprogression'] = bindec($this->bData[37]);
|
||||
$cData['CharacterStatus'] = trim($str);
|
||||
|
||||
$progression = hexdec(bin2hex($this->bData[37]));
|
||||
$cData['CharacterProgression'] = $this->sData->characterProgressionClassic[$progression];
|
||||
|
||||
if ($cData['CharacterStatus'] == 'Hardcore Expansion') {
|
||||
$cData['CharacterProgression'] = $this->sData->characterProgressionExpHC[$progression];
|
||||
}
|
||||
if ($cData['CharacterStatus'] == "Expansion") {
|
||||
$cData['CharacterProgression'] = $this->sData->characterProgressionExp[$progression];
|
||||
}
|
||||
if ($cData['CharacterStatus'] == "Hardcore") {
|
||||
$cData['CharacterProgression'] = $this->sData->characterProgressionClassicHC[$progression];
|
||||
}
|
||||
|
||||
|
||||
$cData['CharacterClass'] = $this->sData->class[unpack('C', $this->bData[40])[1]];
|
||||
$cData['CharacterLevel'] = unpack('C', $this->bData[43])[1];
|
||||
$cData['Lastplayed'] = gmdate("Y-m-d\TH:i:s\Z", unpack('I', $this->bData[48])[0]);
|
||||
$cData['Lastplayed'] = gmdate("Y-m-d\TH:i:s\Z", unpack('L', $this->bData[48])[0]);
|
||||
|
||||
$skills = (unpack('l16', $this->bData[56]));
|
||||
// Hotkey assigned skills
|
||||
foreach ($skills as $skill) {
|
||||
$cData['Assignedskills'][] = ($this->sData->skills[$skill]);
|
||||
$cData['Assignedskills'] = array_filter($cData['Assignedskills']);
|
||||
}
|
||||
|
||||
$cData['LeftmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[120])[1]];
|
||||
$cData['RightmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[124])[1]];
|
||||
$cData['LeftswapmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[128])[1]];
|
||||
$cData['RightswapmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[132])[1]];
|
||||
$cData['LeftmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[120])[1]];
|
||||
$cData['RightmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[124])[1]];
|
||||
$cData['LeftswapmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[128])[1]];
|
||||
$cData['RightswapmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[132])[1]];
|
||||
|
||||
// Char menu appearance not needed
|
||||
// $cData['Charactermenuappearance'] = unpack('i', $this->bData[136]);
|
||||
@ -128,7 +196,7 @@ WHERE sk.charclass = '$class'";
|
||||
// found in the character.map file, according to the difficulty being played. Not needed
|
||||
//$cData['MapID'] = $this->bData[171];
|
||||
|
||||
$cData['MercenaryDead'] = unpack('i', $this->bData[177])[1];
|
||||
$cData['MercenaryDead'] = unpack('i-', $this->bData[177])[1];
|
||||
// This looks like a random ID for your mercenary.
|
||||
// $cData['MercenaryID'] = unpack('H*', $this->bData[179]);
|
||||
$cData['MercenaryNameID'] = unpack('S', $this->bData[183])[1];
|
||||
@ -149,13 +217,16 @@ WHERE sk.charclass = '$class'";
|
||||
$this->cData['skills'] = $this->parseSkills();
|
||||
|
||||
unset($this->items);
|
||||
unset($this->bData);
|
||||
//unset($this->bData);
|
||||
unset($this->sData);
|
||||
unset($this->fp);
|
||||
|
||||
return $this->cData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function parseSkills() {
|
||||
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
||||
$jm = strposX($this->data, 'JM', 1);
|
||||
@ -177,6 +248,10 @@ WHERE sk.charclass = '$class'";
|
||||
return $cData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $points
|
||||
* @return void
|
||||
*/
|
||||
public function setAllSkills(int $points) {
|
||||
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
||||
$jm = strposX($this->data, 'JM', 1);
|
||||
@ -188,6 +263,11 @@ WHERE sk.charclass = '$class'";
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $skill
|
||||
* @param int $points
|
||||
* @return void
|
||||
*/
|
||||
public function setSkill(int $skill, int $points) {
|
||||
$skill -= 1;
|
||||
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
||||
@ -198,6 +278,9 @@ WHERE sk.charclass = '$class'";
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function parseStats() {
|
||||
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
||||
$if = strposX($this->data, 'if', 1);
|
||||
@ -211,7 +294,7 @@ WHERE sk.charclass = '$class'";
|
||||
$stats->rewind();
|
||||
for ($i = 0; $i <= strlen($bits); $i++) {
|
||||
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
||||
if ($this->ISC[$id]['CSvBits'] !== NULL) {
|
||||
if ($this->ISC[$id]['CSvBits'] !== NULL && $this->ISC[$id]['CSvBits'] !== '') {
|
||||
$stats->skip($this->ISC[$id]['CSvBits']);
|
||||
}
|
||||
$ids[$id] = $id;
|
||||
@ -219,24 +302,31 @@ WHERE sk.charclass = '$class'";
|
||||
$stats->rewind();
|
||||
foreach ($ids as $id) {
|
||||
$stats->skip(9);
|
||||
if ($this->ISC[$id]['CSvBits'] !== NULL) {
|
||||
if ($this->ISC[$id]['CSvBits'] !== NULL && $this->ISC[$id]['CSvBits'] !== '') {
|
||||
$val = $stats->readb($this->ISC[$id]['CSvBits']);
|
||||
}
|
||||
$stat = $this->ISC[$id]['Stat'];
|
||||
$values[$stat] = hexdec($this->ByteReader->toBytesR($val));
|
||||
}
|
||||
}
|
||||
$values['hitpoints'] = (int) round($values['hitpoints'] >> 11);
|
||||
$values['maxhp'] = (int) round($values['maxhp'] >> 11);
|
||||
$values['mana'] = (int) round($values['mana'] >> 11);
|
||||
$values['maxmana'] = (int) round($values['maxmana'] >> 11);
|
||||
$values['stamina'] = (int) round($values['stamina'] >> 11);
|
||||
$values['maxstamina'] = (int) round($values['maxstamina'] >> 11);
|
||||
$values['killcounter'] = (int) round($values['killcounter'] >> 1);
|
||||
$values['soulcounter'] = (int) round($values['soulcounter'] / 2);
|
||||
$values['killcounter'] = (int) round($values['killcounter'] / 2);
|
||||
|
||||
$this->cData['stats'] = $values;
|
||||
}
|
||||
|
||||
public function setChar(string $stat, mixed $val) {
|
||||
/**
|
||||
* @param string $stat
|
||||
* @param mixed $val
|
||||
* @param mixed|null $val2
|
||||
* @return false|void
|
||||
*/
|
||||
public function setChar(string $stat, mixed $val, mixed $val2 = null) {
|
||||
switch ($stat) {
|
||||
case 'CharacterName':
|
||||
if (strlen($val) < 1 || strlen($val) > 15) {
|
||||
@ -244,15 +334,20 @@ WHERE sk.charclass = '$class'";
|
||||
}
|
||||
$pack = $this->ByteReader->bitsToHexString($this->ByteReader->toBits(pack('Z16', $val)));
|
||||
$this->ByteReader->writeBytes(20, $pack);
|
||||
$this->data = $this->ByteReader->getData();
|
||||
$this->save();
|
||||
rename($this->filePath, $_SESSION['savepath'] . "$val.d2s");
|
||||
break;
|
||||
|
||||
case "CharacterClass":
|
||||
$this->ByteReader->writeByte(40, $val);
|
||||
$this->data = $this->ByteReader->getData();
|
||||
$this->save();
|
||||
$classes = [
|
||||
'Amazon' => 0,
|
||||
'Sorceress' => 1,
|
||||
'Necromancer' => 2,
|
||||
'Paladin' => 3,
|
||||
'Barbarian' => 4,
|
||||
'Druid' => 5,
|
||||
'Assassin' => 6
|
||||
];
|
||||
$this->ByteReader->writeByte(40, $classes[$val]);
|
||||
break;
|
||||
case "CharacterLevel":
|
||||
if ($val > 99) {
|
||||
@ -271,25 +366,110 @@ WHERE sk.charclass = '$class'";
|
||||
$res = PDO_FetchOne($sql);
|
||||
$this->setStat('experience', $res);
|
||||
break;
|
||||
case 'CharacterStatus':
|
||||
switch ($val) {
|
||||
case 'Died':
|
||||
$status = (strtobits($this->data[36]));
|
||||
$status[3] = $val2;
|
||||
$byte = $this->ByteReader->bitsToHexString($status);
|
||||
$this->ByteReader->writeByte(36, hexdec($byte));
|
||||
break;
|
||||
case 'Hardcore':
|
||||
$status = (strtobits($this->data[36]));
|
||||
$status[2] = $val2;
|
||||
$byte = $this->ByteReader->bitsToHexString($status);
|
||||
$this->ByteReader->writeByte(36, hexdec($byte));
|
||||
break;
|
||||
case 'Expansion':
|
||||
$status = strrev(strtobits($this->data[36]));
|
||||
$status[5] = $val2;
|
||||
$byte = $this->ByteReader->bitsToHexString($status);
|
||||
$this->ByteReader->writeByte(36, hexdec($byte));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'CharacterProgression': // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell
|
||||
switch ($val) {
|
||||
case 0: // in normal
|
||||
$this->data[37] = pack('C', 3);
|
||||
break;
|
||||
case 1: // finished normal
|
||||
$this->data[37] = pack('C', 8);
|
||||
break;
|
||||
case 2: // finished nm
|
||||
$this->data[37] = pack('C', 13);
|
||||
break;
|
||||
case 3: // finished hell
|
||||
$this->data[37] = pack('C', 15);
|
||||
break;
|
||||
$this->save();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'LeftmousebuttonskillID':
|
||||
$this->ByteReader->writeBytes(120, dechex($val));
|
||||
break;
|
||||
|
||||
case 'RightmousebuttonskillID':
|
||||
$this->ByteReader->writeBytes(124, dechex($val));
|
||||
break;
|
||||
|
||||
case 'LeftswapmousebuttonskillID':
|
||||
$this->ByteReader->writeBytes(128, dechex($val));
|
||||
break;
|
||||
|
||||
case 'RightswapmousebuttonskillID':
|
||||
$this->ByteReader->writeBytes(132, dechex($val));
|
||||
break;
|
||||
}
|
||||
|
||||
// finally save char data to d2s file
|
||||
$this->data = $this->ByteReader->getData();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function resetFileSize() {
|
||||
$filesize = strlen($this->data);
|
||||
$this->fp = fopen($this->filePath, "r+b");
|
||||
fseek($this->fp, 8);
|
||||
fwrite($this->fp, pack('L', $filesize));
|
||||
|
||||
fclose($this->fp);
|
||||
$this->fp = fopen($this->filePath, "r+b");
|
||||
checksumFix($this->filePath);
|
||||
|
||||
fseek($this->fp, 8);
|
||||
//ddump(unpack('L', fread($this->fp, 4))[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|string
|
||||
*/
|
||||
public function generateAllStats() {
|
||||
// 003C08E081000F067860C001071C0008020800F040020064A000000A2C00C0030C000D000000006E05000000FE3F
|
||||
$stats = '';
|
||||
foreach ($this->ISC as $i) {
|
||||
$id = strrev(str_pad((decbin($i['ID'])), 9, 0, STR_PAD_LEFT));
|
||||
$val = strrev(str_pad((decbin(20)), (int) $i['CSvBits'], 0, STR_PAD_LEFT));
|
||||
for ($i = 0; $i < 16; $i++) {
|
||||
$id = strrev(str_pad((decbin((int) $this->ISC[$i]['ID'])), 9, 0, STR_PAD_LEFT));
|
||||
$val = strrev(str_pad((decbin(20)), (int) $this->ISC[$i]['CSvBits'], 0, STR_PAD_LEFT));
|
||||
|
||||
// dump($id);
|
||||
// dump($val);
|
||||
|
||||
$stat = $id . $val;
|
||||
$stats .= $stat;
|
||||
}
|
||||
$stats .= "000011111111100";
|
||||
|
||||
dump($stats);
|
||||
|
||||
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
||||
$if = strposX($this->data, 'if', 1);
|
||||
$len = $if - $gf;
|
||||
|
||||
$statall = $stats . "11111111100";
|
||||
$bytes = $this->ByteReader->toBytes($statall);
|
||||
$bytes = $this->ByteReader->toBytes($stats);
|
||||
|
||||
// refresh this data
|
||||
$data = $this->ByteReader->getData();
|
||||
@ -303,11 +483,19 @@ WHERE sk.charclass = '$class'";
|
||||
$this->data = $data;
|
||||
$this->save();
|
||||
|
||||
$this->resetFileSize();
|
||||
|
||||
$filedata = file_get_contents($this->filePath);
|
||||
$this->ByteReader = new D2ByteReader($filedata);
|
||||
$this->data = $this->ByteReader->getData();
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $stat
|
||||
* @param mixed $val
|
||||
* @return void
|
||||
*/
|
||||
public function setStat(string $stat, mixed $val) {
|
||||
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
||||
$if = strposX($this->data, 'if', 1);
|
||||
@ -324,15 +512,19 @@ WHERE sk.charclass = '$class'";
|
||||
for ($i = 0; $i <= strlen($bits); $i++) {
|
||||
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
||||
$_offsets[$id] = $stats->getOffset();
|
||||
if ($this->ISC[$id]['CSvBits'] !== null && $this->ISC[$id]['CSvBits'] !== '') {
|
||||
$stats->skip($this->ISC[$id]['CSvBits']);
|
||||
}
|
||||
}
|
||||
$_offsets[0] = 9;
|
||||
$offsets = null;
|
||||
foreach ($_offsets as $k => $v) {
|
||||
$_stat = $this->ISC[$k]['Stat'];
|
||||
$_stats[$_stat] = $this->ISC[$k]['Stat'];
|
||||
$csvbits[$_stat] = $this->ISC[$k]['CSvBits'];
|
||||
if ($this->ISC[$k]['CSvBits'] !== null && $this->ISC[$k]['CSvBits'] !== '') {
|
||||
$maxValues[$_stat] = pow(2, $this->ISC[$k]['CSvBits']) - 1;
|
||||
}
|
||||
$offsets[$_stat] = $v;
|
||||
}
|
||||
if ($stat == 'hitpoints' || $stat == 'maxhp' || $stat == 'mana' || $stat == 'maxmana' || $stat == 'stamina' || $stat == 'maxstamina') {
|
||||
@ -344,6 +536,9 @@ WHERE sk.charclass = '$class'";
|
||||
}
|
||||
$bitsToWrite = strrev(str_pad(decbin(intval($val)), $csvbits[$_stats[$stat]], 0, STR_PAD_LEFT));
|
||||
$statOffset = $offsets[$_stats[$stat]];
|
||||
if (!array_key_exists($stat, $_stats)) {
|
||||
$this->ByteReader->toBits($this->generateAllStats());
|
||||
} else {
|
||||
$newBits = $stats->writeBits($bits, $bitsToWrite, $statOffset) . "11111111100"; // 0x1FF padding
|
||||
$stats->setBits($newBits);
|
||||
$bytes = $this->ByteReader->toBytes($newBits);
|
||||
@ -351,7 +546,12 @@ WHERE sk.charclass = '$class'";
|
||||
$this->data = $this->ByteReader->getData();
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return array
|
||||
*/
|
||||
public function getQuestData($file) {
|
||||
$questsNorm = null;
|
||||
$questsNM = null;
|
||||
@ -390,6 +590,10 @@ WHERE sk.charclass = '$class'";
|
||||
return $quests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return array
|
||||
*/
|
||||
public function getWaypointsData($file) {
|
||||
$wp = null;
|
||||
fseek($this->fp, $this->sData->wpOffsetsNorm);
|
||||
|
@ -2,84 +2,306 @@
|
||||
|
||||
require_once 'D2BitReader.php';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2CharItem {
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $bits;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $basename = ''; //name of the base item
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $item_name = ''; //name string
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $item_rank = ''; //normal/exceptional/elite
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $item_type = ''; //basic type: armor/weapon/misc
|
||||
//flags
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $identified = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $sockets = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $ear = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $starter = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $compact = 0;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $ethereal;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $personalized;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $runeword;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $version;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $runeword_name = '';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $runes_title = '';
|
||||
//placement
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $location = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $body = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $col = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $row = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $container = 0;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $parent;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $storage;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $bodypart;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $invH = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $invW = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $beltrows = 1;
|
||||
//features
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $item_code = ''; //3 letter code from txt
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $SocketsFilled = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $SocketsNum = 0;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $socketable = false; //gem, rune, jewel
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $fingerprint = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $itemlvl = 0; //item level
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $quality = 0;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $isCharm = false;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $isJewel = false;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $magic_rank = 'Normal'; //normal/magic/rare/crafted/set/unique
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $set_id = 0; //set item id from txt
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $set_item = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $set_name = 0; //set name, if it is set item,
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $personname = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $questdif = -1;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $gold;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $GUID = '';
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $defense = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $mindam = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $maxdam = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $mindam2 = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $maxdam2 = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $mindammi = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $maxdammi = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $MaxDur = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $CurDur = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $reqlvl = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $reqstr = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $reqdex = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $speed = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $throwing = 0;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $stackable = 0;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $charName = ''; //ear's name
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $gfx; //graphic file name
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $baseTrans = -1; //transform indexes for colour remap base item
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $magicTrans = -1; //transform indexes for colour remap magic item
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $type; //type column from txt
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $spelldesc = ''; //desc for potions
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $ditem; //link to item properties from txt
|
||||
//mods
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $dammult = 100; //damage multiply
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $damminadd = 0; //damage add
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $dammaxadd = 0; //damage add
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $defmult = 100; //defense multiply
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $defadd = 0; //defense multiply
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
public $resist = array(0, 0, 0, 0, 0, 0); //phy, mag, fire, light, cold, poison
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
public $attributes = array(0, 0, 0, 0); //str, dex, vit, ene
|
||||
|
||||
//arrays
|
||||
@ -87,11 +309,23 @@ class D2CharItem {
|
||||
//socketed items, collected in above function,
|
||||
//because item has only data for itselt, and
|
||||
//gems/runes/jewels are standalone
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $SocketItems = array();
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $properties = array(); //item variable properties
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $propids = array(); //properties ids list
|
||||
|
||||
|
||||
/**
|
||||
* @param string $bits
|
||||
*/
|
||||
public function __construct(string $bits){
|
||||
if ($bits == '') return false;
|
||||
$this->bits = $bits;
|
||||
@ -99,6 +333,9 @@ class D2CharItem {
|
||||
return $this->parseItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function parseItem(){
|
||||
|
||||
}
|
||||
|
@ -7,12 +7,24 @@ ini_set('max_execution_time', '0');
|
||||
session_start();
|
||||
ob_start();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
define('DB_FILE', $_SESSION['modname'] . ".db");
|
||||
PDO_Connect("sqlite:" . DB_FILE);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2CharStructureData {
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $skills;
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $class = [
|
||||
0 => 'Amazon',
|
||||
1 => 'Sorceress',
|
||||
@ -22,6 +34,9 @@ class D2CharStructureData {
|
||||
5 => 'Druid',
|
||||
6 => 'Assassin'
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $characterStatus = [
|
||||
0 => '',
|
||||
1 => '',
|
||||
@ -32,6 +47,93 @@ class D2CharStructureData {
|
||||
6 => 'Ladder',
|
||||
7 => ''
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $characterProgressionClassicHC = [
|
||||
0 => '',
|
||||
1 => '',
|
||||
2 => '',
|
||||
3 => '',
|
||||
4 => 'Count / Countess',
|
||||
5 => 'Count / Countess',
|
||||
6 => 'Count / Countess',
|
||||
7 => 'Count / Countess',
|
||||
8 => 'Duke / Duchess',
|
||||
9 => 'Duke / Duchess',
|
||||
10 => 'Duke / Duchess',
|
||||
11 => 'Duke / Duchess',
|
||||
12 => 'Duke / Duchess',
|
||||
13 => '',
|
||||
14 => '',
|
||||
15 => '',
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $characterProgressionClassic = [
|
||||
0 => '',
|
||||
1 => '',
|
||||
2 => '',
|
||||
3 => '',
|
||||
4 => 'Sir / Dame',
|
||||
5 => 'Sir / Dame',
|
||||
6 => 'Sir / Dame',
|
||||
7 => 'Sir / Dame',
|
||||
8 => 'Lord / Lady',
|
||||
9 => 'Lord / Lady',
|
||||
10 => 'Lord / Lady',
|
||||
11 => 'Lord / Lady',
|
||||
12 => 'Baron / Baroness',
|
||||
13 => '',
|
||||
14 => '',
|
||||
15 => '',
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $characterProgressionExp = [
|
||||
0 => '',
|
||||
1 => '',
|
||||
2 => '',
|
||||
3 => '',
|
||||
4 => '',
|
||||
5 => 'Slayer',
|
||||
6 => 'Slayer',
|
||||
7 => 'Slayer',
|
||||
8 => 'Slayer',
|
||||
9 => '',
|
||||
10 => 'Champion',
|
||||
11 => 'Champion',
|
||||
12 => 'Champion',
|
||||
13 => 'Champion',
|
||||
14 => 'Patriarch / Matriarch ',
|
||||
15 => 'Patriarch / Matriarch ',
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $characterProgressionExpHC = [
|
||||
0 => '',
|
||||
1 => '',
|
||||
2 => '',
|
||||
3 => '',
|
||||
4 => '',
|
||||
5 => 'Destroyer',
|
||||
6 => 'Destroyer',
|
||||
7 => 'Destroyer',
|
||||
8 => 'Destroyer',
|
||||
9 => '',
|
||||
10 => 'Conqueror',
|
||||
11 => 'Conqueror',
|
||||
12 => 'Conqueror',
|
||||
13 => 'Conqueror',
|
||||
14 => 'Guardian',
|
||||
15 => 'Guardian',
|
||||
];
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
public $offsets = [
|
||||
0 => 4, // Identifier
|
||||
4 => 4, // Version ID
|
||||
@ -67,6 +169,9 @@ class D2CharStructureData {
|
||||
633 => 81, // Waypoints
|
||||
714 => 51, // NPC Introductions
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $qNorm = [
|
||||
345 => 'introWarriv',
|
||||
347 => 'Den_Of_Evil',
|
||||
@ -110,8 +215,10 @@ class D2CharStructureData {
|
||||
423 => 'Rite_Of_Passage',
|
||||
425 => 'Eve_Of_Destruction',
|
||||
// read 425, pointer at 427, + 14 = 441 qNM offset
|
||||
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $qNM = [
|
||||
441 => 'introWarrivNM',
|
||||
443 => 'Den_Of_Evil_NM',
|
||||
@ -155,9 +262,10 @@ class D2CharStructureData {
|
||||
519 => 'Rite_Of_Passage',
|
||||
521 => 'Eve_Of_Destruction',
|
||||
// read 521, pointer at 523, + 14 = 537 qHell offset
|
||||
|
||||
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $qHell = [
|
||||
537 => 'introWarriv',
|
||||
539 => 'Den_Of_Evil_Hell',
|
||||
@ -201,7 +309,9 @@ class D2CharStructureData {
|
||||
615 => 'Rite_Of_Passage',
|
||||
617 => 'Eve_Of_Destruction',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $version = [
|
||||
71 => "1.00 through v1.06",
|
||||
87 => "1.07 or Expansion Set v1.08",
|
||||
@ -209,12 +319,21 @@ class D2CharStructureData {
|
||||
92 => "v1.09 (both the standard game and the Expansion Set.)",
|
||||
96 => "v1.10+"
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $wpOffsetsNorm = 643;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $wpOffsetsNM = 667;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $wpOffsetsHell = 691;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $wpNames = [
|
||||
0 => 'Act 1 - Rogue_Encampment',
|
||||
1 => 'Act 1 - Cold_Plains',
|
||||
@ -256,17 +375,22 @@ class D2CharStructureData {
|
||||
37 => "Act 5 - The_Ancients_Way",
|
||||
38 => 'Act 5 - Worldstone_Keep_level_2'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int[]|string[]
|
||||
*/
|
||||
public $_qNorm;
|
||||
/**
|
||||
* @var int[]|string[]
|
||||
*/
|
||||
public $_qNM;
|
||||
/**
|
||||
* @var int[]|string[]
|
||||
*/
|
||||
public $_qHell;
|
||||
|
||||
|
||||
/*
|
||||
Initialize Skills From Skills.txt
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
public function __construct() {
|
||||
$sql = "
|
||||
SELECT
|
||||
|
@ -42,12 +42,23 @@
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2Database {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
PDO_Connect("sqlite:" . DB_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function createTables($file, $data) {
|
||||
$tableName = basename($file);
|
||||
$tableName = strtolower(substr($tableName, 0, -4));
|
||||
@ -68,6 +79,11 @@ class D2Database {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function fillsTables($file, $data) {
|
||||
$tableName = basename($file);
|
||||
$tableName = strtolower(substr($tableName, 0, -4));
|
||||
@ -106,6 +122,10 @@ class D2Database {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function writeTbl($data) {
|
||||
$sql = 'CREATE TABLE IF NOT EXISTS `strings` (`Key` VARCHAR(255), `String` VARCHAR(255));';
|
||||
$res = PDO_Execute($sql);
|
||||
@ -120,6 +140,10 @@ class D2Database {
|
||||
$res = PDO_Execute($sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getString($key) {
|
||||
$sql = "SELECT String FROM `strings` WHERE `Key`='$key'";
|
||||
|
||||
|
@ -42,8 +42,14 @@
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2DocGenerator {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
require_once './config.php';
|
||||
require_once './_pdo.php';
|
||||
@ -61,6 +67,9 @@ class D2DocGenerator {
|
||||
$idata = new D2ItemData();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getIscProps() {
|
||||
$sql = "
|
||||
SELECT p.`code` as prop,
|
||||
@ -103,6 +112,9 @@ class D2DocGenerator {
|
||||
return $isc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getStrings() {
|
||||
// load strings
|
||||
$sql = 'SELECT * FROM strings';
|
||||
@ -110,6 +122,9 @@ class D2DocGenerator {
|
||||
return $strings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getItemTypesTbl() {
|
||||
// load itemtypes table in memory
|
||||
$sql = "SELECT ItemType,Code FROM itemtypes";
|
||||
@ -118,6 +133,9 @@ class D2DocGenerator {
|
||||
return $itemtypesTbl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getNameStr() {
|
||||
// load namestr from 3 files
|
||||
$sql = "SELECT code,namestr FROM armor
|
||||
@ -130,6 +148,10 @@ class D2DocGenerator {
|
||||
return $namestr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @return string
|
||||
*/
|
||||
public function getImage($code) {
|
||||
$sql = "SELECT invfile FROM armor WHERE `code`=\"$code\" OR `type`=\"$code\" OR `type2`=\"$code\"";
|
||||
$img = PDO_FetchOne($sql);
|
||||
@ -144,6 +166,10 @@ class D2DocGenerator {
|
||||
return $img = (!empty($img)) ? "$img.png" : "1.png";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $code
|
||||
* @return false
|
||||
*/
|
||||
public function getItemName($code) {
|
||||
$sql = "SELECT name FROM armor WHERE `code`=\"$code\" OR `type`=\"$code\" OR `type2`=\"$code\"";
|
||||
$name = PDO_FetchOne($sql);
|
||||
@ -158,6 +184,9 @@ class D2DocGenerator {
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function generateDocs() {
|
||||
|
||||
}
|
||||
|
@ -42,11 +42,23 @@
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2Files {
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public $files = [];
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $charFiles;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
$filesToIgnore = [
|
||||
"aiparms.txt",
|
||||
@ -64,6 +76,9 @@ class D2Files {
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getSaveFiles() {
|
||||
$glob = glob($_SESSION['savepath'] . '*.d2s');
|
||||
|
||||
|
@ -42,6 +42,10 @@
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param $var
|
||||
* @return void
|
||||
*/
|
||||
function ddump($var) {
|
||||
//echo "<pre>";
|
||||
var_dump($var);
|
||||
@ -51,6 +55,10 @@ function ddump($var) {
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $var
|
||||
* @return void
|
||||
*/
|
||||
function dump($var) {
|
||||
//echo "<pre>";
|
||||
var_dump($var);
|
||||
@ -59,6 +67,10 @@ function dump($var) {
|
||||
//echo json_encode($var, JSON_INVALID_UTF8_IGNORE | JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $str
|
||||
* @return string
|
||||
*/
|
||||
function strtobits(string $str): string {
|
||||
$ret = "";
|
||||
for ($i = 0; $i < strlen($str); ++$i) {
|
||||
@ -74,14 +86,29 @@ function strtobits(string $str): string {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $hex
|
||||
* @return string
|
||||
*/
|
||||
function swapEndianness(string $hex) {
|
||||
return implode('', array_reverse(str_split($hex, 2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $n
|
||||
* @param int $p
|
||||
* @param bool $b
|
||||
* @return int
|
||||
*/
|
||||
function setBit(int $n, int $p, bool $b) {
|
||||
return ($b ? ($n | (1 << $p)) : ($n & ~(1 << $p)) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $b
|
||||
* @param int $p
|
||||
* @return int
|
||||
*/
|
||||
function getBit(int $b, int $p) {
|
||||
return intval(($b & (1 << $p)) !== 0);
|
||||
}
|
||||
@ -91,29 +118,21 @@ function getBit(int $b, int $p) {
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
//function checksum($data) {
|
||||
// $nSignature = 0;
|
||||
// $checksum = 0;
|
||||
// foreach ($data as $k => $byte) {
|
||||
//// if ($k == 12 || $k == 13 || $k == 14 || $k == 15) {
|
||||
//// $byte = 0;
|
||||
//// }
|
||||
// $nSignature = ((($nSignature << 1) | ($nSignature >> 31)) + $byte) & 0xFFFFFFFF;
|
||||
// $checksum = (($checksum << 1) & 0xffffffff) + $byte + (($checksum & 0x80000000) != 0 ? 1 : 0);
|
||||
// }
|
||||
// dump(swapEndianness(dechex($nSignature)));
|
||||
// dump(swapEndianness(dechex($checksum)));
|
||||
// //return swapEndianness(dechex($nSignature));
|
||||
// //return swapEndianness(dechex($checksum)); // all of a sudden started returning wrong value, no longer works
|
||||
//}
|
||||
//
|
||||
//function checksumFix(object $ByteReader, string $filePath) {
|
||||
// $ByteReader->writeBytes(12, 00000000); // zero old checksum
|
||||
// $newChecksum = checksum(unpack('C*', $ByteReader->getData())); // get new checksum
|
||||
// $ByteReader->writeBytes(12, $newChecksum); // write new checksum
|
||||
// file_put_contents($filePath, $ByteReader->getData()); // write bytestream to file
|
||||
//}
|
||||
function checksum($fileData) {
|
||||
$nSignature = 0;
|
||||
foreach ($fileData as $k => $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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filePath
|
||||
* @return string
|
||||
*/
|
||||
function checksumFix(string $filePath) {
|
||||
return trim(shell_exec("bin\d2scs.exe \"$filePath\""));
|
||||
}
|
||||
@ -135,10 +154,18 @@ function strposX($haystack, $needle, $number) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bit
|
||||
* @return int
|
||||
*/
|
||||
function isBit(string $bit): int {
|
||||
return ((int) $bit ? 1 : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $input
|
||||
* @return string
|
||||
*/
|
||||
function toBits($input): string {
|
||||
$output = '';
|
||||
if (is_string($input)) {
|
||||
@ -156,6 +183,9 @@ function toBits($input): string {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
function print_mem() {
|
||||
/* Currently used memory */
|
||||
$mem_usage = memory_get_usage();
|
||||
@ -167,6 +197,11 @@ function print_mem() {
|
||||
echo 'Peak usage: <strong>' . round($mem_peak / 1024 / 1024) . 'MB</strong> RAM.<br><br>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $src
|
||||
* @param $dst
|
||||
* @return void
|
||||
*/
|
||||
function rcopy($src, $dst) {
|
||||
// open the source directory
|
||||
$dir = opendir($src);
|
||||
@ -185,6 +220,10 @@ function rcopy($src, $dst) {
|
||||
closedir($dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $src
|
||||
* @return void
|
||||
*/
|
||||
function rrmdir($src) {
|
||||
$dir = opendir($src);
|
||||
while (false !== ( $file = readdir($dir))) {
|
||||
|
@ -3,11 +3,23 @@
|
||||
require_once 'D2BitReader.php';
|
||||
require_once 'D2ItemStructureData.php';
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2Item {
|
||||
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
private $bits = null;
|
||||
/**
|
||||
* @var null
|
||||
*/
|
||||
public $iData = null;
|
||||
|
||||
/**
|
||||
* @param $bits
|
||||
*/
|
||||
public function __construct($bits) {
|
||||
if ($bits == '')
|
||||
return false;
|
||||
@ -20,6 +32,9 @@ class D2Item {
|
||||
* @return array of item details
|
||||
*/
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
private function parseItem() {
|
||||
$b = new D2BitReader($this->bits);
|
||||
|
||||
|
@ -1,10 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2ItemData {
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $strings;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $images;
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function getImages() {
|
||||
$sql = "SELECT code,uniqueinvfile,invfile,type,type2 FROM armor
|
||||
UNION ALL
|
||||
@ -24,6 +36,11 @@ class D2ItemData {
|
||||
unset($isc2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $index
|
||||
* @param $doc
|
||||
* @return false|string
|
||||
*/
|
||||
public function uniqueItems($index, $doc = FALSE) {
|
||||
if (empty($this->images)) {
|
||||
$this->getImages();
|
||||
@ -897,6 +914,10 @@ class D2ItemData {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $iscStat
|
||||
* @return mixed
|
||||
*/
|
||||
public function getIscStrings($iscStat) {
|
||||
if (empty($this->strings)) {
|
||||
$this->getStrings();
|
||||
@ -904,6 +925,9 @@ class D2ItemData {
|
||||
return ($this->strings[$iscStat]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function getStrings() {
|
||||
$sql = "
|
||||
SELECT p.`code` as prop,
|
||||
|
@ -42,6 +42,9 @@
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2ItemDesc {
|
||||
/*
|
||||
|
||||
@ -135,13 +138,25 @@ class D2ItemDesc {
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $str = '';
|
||||
// takes value, param.
|
||||
// value == Value to show on this stat
|
||||
//descfunc 14
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $skilltabsDesc;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $skilltabsDescClean;
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $skilltabs = [
|
||||
//ama
|
||||
'0' => 'StrSklTabItem3',
|
||||
@ -172,6 +187,9 @@ class D2ItemDesc {
|
||||
'19' => 'StrSklTabItem20',
|
||||
'20' => 'StrSklTabItem21'
|
||||
];
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $charClass = [
|
||||
"ama" => "Amazon",
|
||||
"sor" => "Sorceress",
|
||||
@ -245,6 +263,12 @@ class D2ItemDesc {
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param $par
|
||||
* @param $min
|
||||
* @param $max
|
||||
* @return void
|
||||
*/
|
||||
public function prep($par, $min, $max) {
|
||||
|
||||
}
|
||||
@ -268,15 +292,18 @@ class D2ItemDesc {
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param $params
|
||||
* @return false|string
|
||||
*/
|
||||
public function getDesc($params = []) {
|
||||
if (empty($params))
|
||||
return false;
|
||||
|
@ -1,40 +1,112 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2ItemLocation {
|
||||
|
||||
//location
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const STORED = 0;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const EQUIPPED = 1;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const BELTI = 2;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const CURSOR = 4;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const ITEM = 6;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2ItemLocationStored {
|
||||
|
||||
//storage
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const NONE = 0;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const INVENTORY = 1;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const CUBE = 4;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const STASH = 5;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2ItemLocationBody {
|
||||
|
||||
//body parts
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const HELMET = 1;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const AMULET = 2;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const ARMOR = 3;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const WEAPONR = 4;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const WEAPONL = 5;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const RINGR = 6;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const RINGL = 7;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const BELT = 8;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const BOOTS = 9;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const GLOVES = 10;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const WEAPONR2 = 11;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const WEAPONL2 = 12;
|
||||
|
||||
}
|
||||
|
@ -42,10 +42,21 @@
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2SaveTXT {
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $path;
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @param $data
|
||||
* @return void
|
||||
*/
|
||||
public function save($file, $data) {
|
||||
|
||||
$fp = fopen($this->path.DIRECTORY_SEPARATOR.$file, 'a+');
|
||||
@ -54,6 +65,10 @@ class D2SaveTXT {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return void
|
||||
*/
|
||||
public function saveBackup($file){
|
||||
|
||||
// if dir doesn't exist, create it
|
||||
@ -72,6 +87,10 @@ class D2SaveTXT {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filename
|
||||
* @return void
|
||||
*/
|
||||
public function saveTblEnries($filename) {
|
||||
$post = $_POST;
|
||||
|
||||
@ -83,6 +102,9 @@ class D2SaveTXT {
|
||||
file_put_contents($file, $str, FILE_APPEND);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->path = TXT_PATH;
|
||||
}
|
||||
|
@ -1,8 +1,17 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2Strings {
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public array $strings;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct(){
|
||||
$sql = "SELECT * FROM strings";
|
||||
$this->strings = PDO_FetchAssoc($sql);
|
||||
|
@ -41,19 +41,40 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class D2TxtParser {
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
public $path = TXT_PATH;
|
||||
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
public $db;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return array
|
||||
*/
|
||||
public function parseFile($file) {
|
||||
return $this->parseData($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return array
|
||||
*/
|
||||
function filterProps($file) {
|
||||
$data = $this->parseData($file);
|
||||
$propsToFilter = file(FILTER_PROPERTIES_FILE, FILE_IGNORE_NEW_LINES);
|
||||
@ -65,6 +86,10 @@ class D2TxtParser {
|
||||
return $filteredProps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $file
|
||||
* @return array
|
||||
*/
|
||||
public function parseData($file) {
|
||||
$file = $this->path . $file;
|
||||
$rows = array_map(function ($v) {
|
||||
|
@ -47,7 +47,7 @@
|
||||
<div>
|
||||
<div class="center item_desc" style="">
|
||||
|
||||
<div style="height: 116px;background: url(/img/items/bg.png) center top no-repeat;">
|
||||
<div style="height: 116px;background: url(/img/bg.png) center top no-repeat;">
|
||||
<a href="" target="_blank" class="item_debug_link">
|
||||
<img style="" class="item img-fluid" src="">
|
||||
</a>
|
||||
|
211
test.php
211
test.php
@ -1,195 +1,42 @@
|
||||
<?php
|
||||
|
||||
// from unpack('H*', file_get_contents("Char.d2s")) for 3v4l.org to read d2s file here
|
||||
//$data = hex2bin('55aa55aa60000000f1060000b5bc59b300000000536f72630000000000000000000000002400000001103863000000003cc7ae62ffffffffffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000000000000570300000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000005e3e9b11000000008888d5f80100000035b70300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576f6f21060000002a0101000190fd9ffe9ffd9ffe9ffd9f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057530100000050000201ffffffff7f00000000000000000000000000000000000201ffffffff7f00000000000000000000000000000000000201ffffffff7f0000000000000000000000000000000000017734002e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067660028083082000a06644000b10252067094c1018082800020292400480a0a0030c202008cc060dcc0f0ca3afa160a0000e03f696600000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004a4d32004a4d100082006500069226160382af144fb080e03f4a4d1000820065000a9226260302791c00c480e03f4a4d10008000654415c076c606821c7ffff58080010a06fe034a4d1000800065008013268303827e82896086dccb000066c5bcfeffff014a4d1000820065000022f6860782b067b7ec80e03f4a4d1000820065001a922636038249b154da80a025040000c07f4a4d1000a0006500a442665363034a4d1000a0006500fe13367703024a4d1000a0006500de13362703024a4d1000a0006500be13361703024a4d1000a00065009e13360703024a4d1000a00065007e1336a707024a4d1000a00065005e13369707024a4d1000a00065003e1336f706024a4d1000a0006500c013e65606024a4d1000a00065006012d68607024a4d1000a00065000e12d60603024a4d1000a00065006412564306024a4d1000800065001e83179303029920441686e03f4a4d1000a0006500fe12d69606024a4d1000a0006500de12d68606024a4d1000a0006500be12d67606024a4d1000a00065009e12e67606024a4d1000a00065007e12e69606024a4d1000a0006500fc13e6a606024a4d1000a0006500dc13c68603024a4d1000a0006500bc13e6b606024a4d1000800065009c83272303826f9aed3186e03f4a4d1000800065007c8317730302acd0c26e86e03f4a4d1000a00065005c13560603024a4d1000a00065003c13569607024a4d1000a00065001c13464603024a4d1000a00065001212d66607024a4d1000a00865001412d66607024a4d1000a0006500fc1226f606024a4d1000a0006500dc12265607024a4d1000a0086500bc12265607024a4d1000a00865009c12265607024a4d1000a00865007c12265607024a4d1000a0086500fa13265607024a4d1000a0006500da43665363034a4d1000a0086500ba43665363034a4d1000a00065009a53468333064a4d10008000650016421616038245fc36c6822cff014a4d100080006500a032166707028c6e88690101000408052c30c0c00054e03f4a4d10008000650411c026c60602385900c78080010a08fe034a4d1000800065004632166707822c1b5e930001000498042c30c0c00054e03f4a4d1000800065007a8337130382a07c2a5786e03f4a4d1008800065000ec326c60602915c92ea8280010a07e23f4a4d100880046500b23237470612e9b107ed80104b83c140fc3776ece0f80f4a4d1000a00065180010365603024a4d00006a664a4d00006b6600');
|
||||
|
||||
require_once './src/D2Functions.php';
|
||||
require_once './src/D2BitReader.php';
|
||||
|
||||
class D2ByteReader {
|
||||
|
||||
private string $data;
|
||||
private int $offset = 0;
|
||||
|
||||
public function __construct(string $data) {
|
||||
if (!$data)
|
||||
return false;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function skip(int $numBytes): bool {
|
||||
if ($numBytes < 0 || $numBytes > strlen($this->data))
|
||||
return false;
|
||||
$this->offset += $numBytes;
|
||||
return $true;
|
||||
}
|
||||
|
||||
public function seek(int $pos): bool {
|
||||
if ($pos < 0 || $pos > strlen($this->data))
|
||||
return false;
|
||||
$this->offset = $pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function readh(int $offset, int $numBytes, bool $str = true): string {
|
||||
$this->seek($offset);
|
||||
$bytes = null;
|
||||
for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
|
||||
$str ? $bytes .= $this->data[$i] : $bytes[] = $this->data[$i];
|
||||
}
|
||||
return unpack('H*', $bytes)[1];
|
||||
}
|
||||
|
||||
public function readc(int $offset, int $numBytes, bool $str = true): array {
|
||||
$this->seek($offset);
|
||||
$bytes = null;
|
||||
for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
|
||||
$str ? $bytes .= $this->data[$i] : $bytes[] = $this->data[$i];
|
||||
}
|
||||
return unpack('C*', $bytes);
|
||||
}
|
||||
|
||||
public function rewind(): bool {
|
||||
$this->offset = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
public function writeByte(int $offset, int $byte) {
|
||||
$this->data[$offset] = pack('C', $byte);
|
||||
}
|
||||
|
||||
public function writeBytes(int $offset, string $bytes) {
|
||||
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
||||
return false;
|
||||
$_bytes = str_split($bytes, 2);
|
||||
foreach ($_bytes as $k => $byte) {
|
||||
$pos = $offset + $k;
|
||||
$this->data[$pos] = pack('H*', $byte);
|
||||
}
|
||||
}
|
||||
|
||||
public function getData() {
|
||||
return $this->data ? $this->data : false;
|
||||
}
|
||||
|
||||
public function getOffset(): int {
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
public function isHexString(string $str): bool {
|
||||
if (strlen($str) % 2 == 0 && (ctype_xdigit($str))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function toBits($input): string {
|
||||
$output = '';
|
||||
if ($this->isHexString($input)) {
|
||||
foreach (str_split($input, 2) as $byte) {
|
||||
$output .= (strrev(str_pad(decbin(hexdec($byte)), 8, 0, STR_PAD_LEFT)));
|
||||
}
|
||||
return $output;
|
||||
} else if (is_string($input)) {
|
||||
foreach (str_split($input) as $i) {
|
||||
$output .= strrev(str_pad(decbin(ord($i)), 8, 0, STR_PAD_LEFT));
|
||||
}
|
||||
return $output;
|
||||
} else if (is_int($input)) {
|
||||
return strrev(str_pad(decbin($input), 8, 0, STR_PAD_LEFT));
|
||||
} else if (is_array($input)) {
|
||||
foreach ($input as $i) {
|
||||
$output .= $this->tobits($i);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
public function toBytes(string $bits) {
|
||||
foreach (str_split($bits, 8) as $byteString) {
|
||||
$bytes[] = (bindec(strrev($byteString)));
|
||||
}
|
||||
foreach ($bytes as $byte) {
|
||||
dump($byte);
|
||||
}
|
||||
}
|
||||
|
||||
public function bitsToHexString(string $bits): string {
|
||||
$bytes = '';
|
||||
foreach (str_split($bits, 8) as $byte) {
|
||||
$bytes .= (str_pad(dechex((bindec(strrev($byte)))), 2, 0, STR_PAD_LEFT));
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
public function bitsToHexArray(string $bits): array {
|
||||
$bytes = [];
|
||||
foreach (str_split($bits, 8) as $byte) {
|
||||
$bytes[] = (str_pad(dechex((bindec(strrev($byte)))), 2, 0, STR_PAD_LEFT));
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
public function bitsToIntArray(string $bits): array {
|
||||
$bytes = [];
|
||||
foreach (str_split($bits, 8) as $byte) {
|
||||
$bytes[] = (int) (str_pad(dechex((bindec(strrev($byte)))), 2, 0, STR_PAD_LEFT));
|
||||
}
|
||||
return $bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
@return Byte with Nth bit set to X
|
||||
Diablo 2 D2S Save File Checksum Calculator
|
||||
By Hash Borgir (https://www.psychedelicsdaily.com)
|
||||
@date 6/4/2022
|
||||
|
||||
Checksum field is at byte 12.
|
||||
Bytes 12/13/14/15 as a uint32.
|
||||
Set this to 0.
|
||||
After clearing the checksum field add up the values of all the bytes in the file and rotate the running total one bit to the left before adding the next byte.
|
||||
*/
|
||||
|
||||
public function setBit(int $byte, int $pos, bool $bit) {
|
||||
return ($bit ? ($byte | (1 << $pos)) : ($byte & ~(1 << $pos)) );
|
||||
function swapEndianness(string $hex) {
|
||||
return implode('', array_reverse(str_split($hex, 2)));
|
||||
}
|
||||
|
||||
/*
|
||||
@return Bit at Nth position in Byte
|
||||
*/
|
||||
|
||||
public function getBit(int $byte, int $pos): int {
|
||||
return intval(($byte & (1 << $pos)) != 0);
|
||||
function checksum($fileData) {
|
||||
$nSignature = 0;
|
||||
foreach ($fileData as $k => $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
|
||||
|
||||
$filename = "D:\Diablo II\MODS\ironman-dev\save\Barb.d2s";
|
||||
$fileData = unpack('C*', file_get_contents($filename)); // open file and unpack
|
||||
|
||||
|
||||
var_dump(checksum($fileData));
|
||||
|
||||
|
||||
|
||||
|
||||
//$file = "D:\Diablo II\MODS\ironman-dev\save\Barb.d2s";
|
||||
//$data = file_get_contents($file);
|
||||
//
|
||||
//$c = new D2ByteReader($data);
|
||||
//
|
||||
//$checksum = checksum(unpack('C*', $c->getData()));
|
||||
//
|
||||
//ddump($checksum);
|
||||
|
||||
//$bytes = $c->readh(643, 5);
|
||||
//$bits = $c->toBits($bytes);
|
||||
//
|
||||
//$bits[4] = 0;
|
||||
//$bits[5] = 0;
|
||||
//$bits[8] = 0;
|
||||
|
||||
//$newBytes = $c->bitsToHexString($bits);
|
||||
//$c->writeBytes(643, $newBytes);
|
||||
//
|
||||
//$c->writeBytes(12, "00000000"); // zero old checksum
|
||||
//
|
||||
//dump($c->readh(12, 4));
|
||||
//
|
||||
//$newChecksum = checksum(unpack('C*', $c->getData())); // get new checksum
|
||||
//$c->writeBytes(12, $newChecksum); // write new checksum
|
||||
//
|
||||
//dump($c->readh(12, 4));
|
||||
//
|
||||
//file_put_contents($file, $c->getData()); // write bytestream to file
|
||||
|
||||
fseek($fp, 12); // go to byte 12
|
||||
fwrite($fp, pack('H8', checksum($fileData))); // write new checksum
|
||||
fclose($fp);
|
Loading…
Reference in New Issue
Block a user