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 = "D:\Diablo II\MODS\MedianXL2012\save\Test.d2s";
|
||||||
|
|
||||||
|
|
||||||
$filePath = "Test.d2s";
|
$filePath = "Necro.d2s";
|
||||||
$char = new D2Char($filePath);
|
$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->setSkill(1, 99);
|
||||||
//$char->setChar("CharacterClass", 1); // 127
|
//$char->setChar("CharacterClass", "Necromancer"); // 127
|
||||||
$char->setChar("CharacterLevel", 0);
|
//$char->setChar("CharacterProgression", 1); // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell
|
||||||
$char->setStat("strength", 30);
|
$char->setChar("CharacterLevel", 25);
|
||||||
$char->setStat("energy", 30);
|
//$char->setStat("strength", 70);
|
||||||
$char->setStat("dexterity", 30);
|
//$char->setStat("energy", 70);
|
||||||
$char->setStat("vitality", 30);
|
//$char->setStat("dexterity", 70);
|
||||||
$char->setStat("mana", 120);
|
//$char->setStat("vitality", 70);
|
||||||
$char->setStat("maxmana", 200);
|
//$char->setStat("mana", 200);
|
||||||
$char->setStat("stamina", 80);
|
//$char->setStat("maxmana", 200);
|
||||||
$char->setStat("maxstamina", 120);
|
//$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
|
unset($char); // destroy $char so we can read it again after writing to it to get updated stats
|
||||||
|
|
||||||
$char = new D2Char($filePath);
|
$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
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2BitReader {
|
class D2BitReader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private string $bits = '';
|
private string $bits = '';
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
private int $offset = 0;
|
private int $offset = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
*/
|
||||||
public function __construct(string $bits = '') {
|
public function __construct(string $bits = '') {
|
||||||
$this->bits = $bits;
|
$this->bits = $bits;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $numBits
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function skip(int $numBits): int {
|
public function skip(int $numBits): int {
|
||||||
$this->offset += $numBits;
|
$this->offset += $numBits;
|
||||||
return $this->offset;
|
return $this->offset;
|
||||||
@ -17,6 +33,11 @@ class D2BitReader {
|
|||||||
|
|
||||||
/* read X number of bits, like fread */
|
/* 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 {
|
public function read(int $numBits = 0, bool $str = true): string {
|
||||||
$bits = null;
|
$bits = null;
|
||||||
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
||||||
@ -26,10 +47,21 @@ class D2BitReader {
|
|||||||
return $bits;
|
return $bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @param string $bitsToWrite
|
||||||
|
* @param int $offset
|
||||||
|
* @return array|string|string[]
|
||||||
|
*/
|
||||||
public function writeBits(string $bits, string $bitsToWrite, int $offset) {
|
public function writeBits(string $bits, string $bitsToWrite, int $offset) {
|
||||||
return substr_replace($bits, $bitsToWrite, $offset, strlen($bitsToWrite));
|
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 {
|
public function readb(int $numBits = 0, bool $str = true): string {
|
||||||
$bits = null;
|
$bits = null;
|
||||||
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
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));
|
return strrev(str_pad($bits, 16, 0, STR_PAD_RIGHT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $numBits
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function readr(int $numBits = 0): string {
|
public function readr(int $numBits = 0): string {
|
||||||
$bits = null;
|
$bits = null;
|
||||||
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
for ($i = $this->offset; $i < $this->offset + $numBits; $i++) {
|
||||||
@ -50,6 +86,10 @@ class D2BitReader {
|
|||||||
|
|
||||||
/* seek to offset (like fseek) */
|
/* seek to offset (like fseek) */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $pos
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function seek(int $pos): bool {
|
public function seek(int $pos): bool {
|
||||||
if ($pos < 0 || $pos > strlen($this->bits)) {
|
if ($pos < 0 || $pos > strlen($this->bits)) {
|
||||||
return false;
|
return false;
|
||||||
@ -60,6 +100,9 @@ class D2BitReader {
|
|||||||
|
|
||||||
/* rewind offset to 0 */
|
/* rewind offset to 0 */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function rewind(): bool {
|
public function rewind(): bool {
|
||||||
$this->offset = 0;
|
$this->offset = 0;
|
||||||
return true;
|
return true;
|
||||||
@ -67,6 +110,10 @@ class D2BitReader {
|
|||||||
|
|
||||||
/* Get Bit */
|
/* Get Bit */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bitNum
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function getBit(string $bitNum): int {
|
public function getBit(string $bitNum): int {
|
||||||
if ($bitNum < 0 || $bitNum > strlen($this->bits)) {
|
if ($bitNum < 0 || $bitNum > strlen($this->bits)) {
|
||||||
return false;
|
return false;
|
||||||
@ -76,6 +123,11 @@ class D2BitReader {
|
|||||||
|
|
||||||
/* Set Bit */
|
/* Set Bit */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $bitNum
|
||||||
|
* @param int $bitVal
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function setBit(int $bitNum, int $bitVal): bool {
|
public function setBit(int $bitNum, int $bitVal): bool {
|
||||||
if ($bitVal < 0 || $bitVal > 1) {
|
if ($bitVal < 0 || $bitVal > 1) {
|
||||||
return false;
|
return false;
|
||||||
@ -84,18 +136,32 @@ class D2BitReader {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getBits(): string {
|
public function getBits(): string {
|
||||||
return $this->bits;
|
return $this->bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setBits(string $bits) {
|
public function setBits(string $bits) {
|
||||||
$this->bits = $bits;
|
$this->bits = $bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function getOffset(): int {
|
public function getOffset(): int {
|
||||||
return $this->offset;
|
return $this->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function setOffset(int $offset): bool {
|
public function setOffset(int $offset): bool {
|
||||||
if ($offset < 0 || $offset > strlen($this->bits))
|
if ($offset < 0 || $offset > strlen($this->bits))
|
||||||
return false;
|
return false;
|
||||||
|
@ -3,17 +3,33 @@
|
|||||||
require_once './src/D2Functions.php';
|
require_once './src/D2Functions.php';
|
||||||
require_once './src/D2BitReader.php';
|
require_once './src/D2BitReader.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2ByteReader {
|
class D2ByteReader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private string $data = '';
|
private string $data = '';
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
private int $offset = 0;
|
private int $offset = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data
|
||||||
|
*/
|
||||||
public function __construct(string $data) {
|
public function __construct(string $data) {
|
||||||
if (!$data)
|
if (!$data)
|
||||||
return false;
|
return false;
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $numBytes
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function skip(int $numBytes): bool {
|
public function skip(int $numBytes): bool {
|
||||||
if ($numBytes < 0 || $numBytes > strlen($this->data))
|
if ($numBytes < 0 || $numBytes > strlen($this->data))
|
||||||
return false;
|
return false;
|
||||||
@ -21,6 +37,10 @@ class D2ByteReader {
|
|||||||
return $true;
|
return $true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $pos
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function seek(int $pos): bool {
|
public function seek(int $pos): bool {
|
||||||
if ($pos < 0 || $pos > strlen($this->data))
|
if ($pos < 0 || $pos > strlen($this->data))
|
||||||
return false;
|
return false;
|
||||||
@ -28,6 +48,12 @@ class D2ByteReader {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @param int $numBytes
|
||||||
|
* @param bool $str
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function readh(int $offset, int $numBytes, bool $str = true): string {
|
public function readh(int $offset, int $numBytes, bool $str = true): string {
|
||||||
$this->seek($offset);
|
$this->seek($offset);
|
||||||
$bytes = null;
|
$bytes = null;
|
||||||
@ -37,6 +63,12 @@ class D2ByteReader {
|
|||||||
return unpack('H*', $bytes)[1];
|
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): array {
|
||||||
$this->seek($offset);
|
$this->seek($offset);
|
||||||
$bytes = null;
|
$bytes = null;
|
||||||
@ -46,15 +78,28 @@ class D2ByteReader {
|
|||||||
return unpack('C*', $bytes);
|
return unpack('C*', $bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function rewind(): bool {
|
public function rewind(): bool {
|
||||||
$this->offset = 0;
|
$this->offset = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @param int $byte
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function writeByte(int $offset, int $byte) {
|
public function writeByte(int $offset, int $byte) {
|
||||||
$this->data[$offset] = pack('C', $byte);
|
$this->data[$offset] = pack('C', $byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @param string $bytes
|
||||||
|
* @return false|void
|
||||||
|
*/
|
||||||
public function writeBytes(int $offset, string $bytes) {
|
public function writeBytes(int $offset, string $bytes) {
|
||||||
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
||||||
return false;
|
return false;
|
||||||
@ -64,6 +109,12 @@ class D2ByteReader {
|
|||||||
$this->data[$pos] = pack('H*', $byte);
|
$this->data[$pos] = pack('H*', $byte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $offset
|
||||||
|
* @param string $bytes
|
||||||
|
* @return false|void
|
||||||
|
*/
|
||||||
public function insertBytes(int $offset, string $bytes) {
|
public function insertBytes(int $offset, string $bytes) {
|
||||||
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
|
||||||
return false;
|
return false;
|
||||||
@ -72,18 +123,32 @@ class D2ByteReader {
|
|||||||
$this->data = hex2bin($newData);
|
$this->data = hex2bin($newData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
public function getData() {
|
public function getData() {
|
||||||
return $this->data ? $this->data : false;
|
return $this->data ? $this->data : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setData($data){
|
public function setData($data){
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
public function getOffset(): int {
|
public function getOffset(): int {
|
||||||
return $this->offset;
|
return $this->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $str
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
public function isHexString(string $str): bool {
|
public function isHexString(string $str): bool {
|
||||||
if (strlen($str) % 2 == 0 && (ctype_xdigit($str))) {
|
if (strlen($str) % 2 == 0 && (ctype_xdigit($str))) {
|
||||||
return true;
|
return true;
|
||||||
@ -91,6 +156,10 @@ class D2ByteReader {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $input
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function toBits($input): string {
|
public function toBits($input): string {
|
||||||
$output = '';
|
$output = '';
|
||||||
if ($this->isHexString($input)) {
|
if ($this->isHexString($input)) {
|
||||||
@ -113,6 +182,10 @@ class D2ByteReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function toBytesR(string $bits) : string {
|
public function toBytesR(string $bits) : string {
|
||||||
foreach (str_split($bits, 8) as $byteString) {
|
foreach (str_split($bits, 8) as $byteString) {
|
||||||
$bytes .= strtoupper(str_pad(dechex(bindec(($byteString))), 2, 0, STR_PAD_LEFT));
|
$bytes .= strtoupper(str_pad(dechex(bindec(($byteString))), 2, 0, STR_PAD_LEFT));
|
||||||
@ -120,6 +193,10 @@ class D2ByteReader {
|
|||||||
return $bytes;
|
return $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function toBytes(string $bits) : string {
|
public function toBytes(string $bits) : string {
|
||||||
foreach (str_split($bits, 8) as $byteString) {
|
foreach (str_split($bits, 8) as $byteString) {
|
||||||
$bytes .= strtoupper(str_pad(dechex(bindec(strrev($byteString))), 2, 0, STR_PAD_LEFT));
|
$bytes .= strtoupper(str_pad(dechex(bindec(strrev($byteString))), 2, 0, STR_PAD_LEFT));
|
||||||
@ -127,6 +204,10 @@ class D2ByteReader {
|
|||||||
return $bytes;
|
return $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function bitsToHexString(string $bits): string {
|
public function bitsToHexString(string $bits): string {
|
||||||
$bytes = '';
|
$bytes = '';
|
||||||
foreach (str_split($bits, 8) as $byte) {
|
foreach (str_split($bits, 8) as $byte) {
|
||||||
@ -135,6 +216,10 @@ class D2ByteReader {
|
|||||||
return $bytes;
|
return $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function bitsToHexArray(string $bits): array {
|
public function bitsToHexArray(string $bits): array {
|
||||||
$bytes = [];
|
$bytes = [];
|
||||||
foreach (str_split($bits, 8) as $byte) {
|
foreach (str_split($bits, 8) as $byte) {
|
||||||
@ -143,6 +228,10 @@ class D2ByteReader {
|
|||||||
return $bytes;
|
return $bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function bitsToIntArray(string $bits): array {
|
public function bitsToIntArray(string $bits): array {
|
||||||
$bytes = [];
|
$bytes = [];
|
||||||
foreach (str_split($bits, 8) as $byte) {
|
foreach (str_split($bits, 8) as $byte) {
|
||||||
@ -151,18 +240,21 @@ class D2ByteReader {
|
|||||||
return $bytes;
|
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) {
|
public function setBit(int $byte, int $pos, bool $bit) {
|
||||||
return ($bit ? ($byte | (1 << $pos)) : ($byte & ~(1 << $pos)) );
|
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 {
|
public function getBit(int $byte, int $pos): int {
|
||||||
return intval(($byte & (1 << $pos)) != 0);
|
return intval(($byte & (1 << $pos)) != 0);
|
||||||
}
|
}
|
||||||
|
286
src/D2Char.php
286
src/D2Char.php
@ -8,24 +8,70 @@ require_once 'D2Item.php';
|
|||||||
require_once 'D2ByteReader.php';
|
require_once 'D2ByteReader.php';
|
||||||
require_once 'D2Functions.php';
|
require_once 'D2Functions.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2Char {
|
class D2Char {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
public $cData = null; // char data output
|
public $cData = null; // char data output
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
public $items = null; // char item data
|
public $items = null; // char item data
|
||||||
|
/**
|
||||||
|
* @var D2ByteReader|null
|
||||||
|
*/
|
||||||
public $ByteReader = null; // put $data into bytereader
|
public $ByteReader = null; // put $data into bytereader
|
||||||
|
/**
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
public $filePath = null; // .d2s file path
|
public $filePath = null; // .d2s file path
|
||||||
|
/**
|
||||||
|
* @var D2CharStructureData
|
||||||
|
*/
|
||||||
private $sData = null; // char file structure data
|
private $sData = null; // char file structure data
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
private $bData = null; // char binary data from d2s
|
private $bData = null; // char binary data from d2s
|
||||||
|
/**
|
||||||
|
* @var false|resource
|
||||||
|
*/
|
||||||
private $fp = null; // file pointer
|
private $fp = null; // file pointer
|
||||||
|
/**
|
||||||
|
* @var false|string
|
||||||
|
*/
|
||||||
private $data = null; // full d2s file loaded in $data
|
private $data = null; // full d2s file loaded in $data
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
private $ISC = null;
|
private $ISC = null;
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
private $skillData = null;
|
private $skillData = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function save() {
|
public function save() {
|
||||||
file_put_contents($this->filePath, $this->data);
|
$this->ByteReader->setData($this->data); // update bytereader data
|
||||||
checksumFix($this->filePath);
|
$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) {
|
public function __construct($file) {
|
||||||
$this->sData = new D2CharStructureData();
|
$this->sData = new D2CharStructureData();
|
||||||
$this->filePath = $_SESSION['savepath'] . $file;
|
$this->filePath = $_SESSION['savepath'] . $file;
|
||||||
@ -52,7 +98,7 @@ class D2Char {
|
|||||||
$classes = array_flip(['ama' => 0, 'sor' => 1, 'nec' => 2, 'pal' => 3, 'bar' => 4, 'dru' => 5, 'ass' => 6]);
|
$classes = array_flip(['ama' => 0, 'sor' => 1, 'nec' => 2, 'pal' => 3, 'bar' => 4, 'dru' => 5, 'ass' => 6]);
|
||||||
$class = $classes[hexdec($this->ByteReader->readh(40, 1))];
|
$class = $classes[hexdec($this->ByteReader->readh(40, 1))];
|
||||||
$sql = "SELECT sk.id,sk.Skill,sk.skilldesc,`str name`,strings.`String`,skilldesc.SkillPage,skilldesc.SkillRow,skilldesc.SkillColumn,skilldesc.ListRow,skilldesc.ListPool,skilldesc.IconCel
|
$sql = "SELECT sk.id,sk.Skill,sk.skilldesc,`str name`,strings.`String`,skilldesc.SkillPage,skilldesc.SkillRow,skilldesc.SkillColumn,skilldesc.ListRow,skilldesc.ListPool,skilldesc.IconCel
|
||||||
FROM skills as sk
|
FROM skills as sk
|
||||||
LEFT JOIN skilldesc ON sk.skilldesc = skilldesc.skilldesc
|
LEFT JOIN skilldesc ON sk.skilldesc = skilldesc.skilldesc
|
||||||
LEFT JOIN strings on skilldesc.`str name` = strings.Key
|
LEFT JOIN strings on skilldesc.`str name` = strings.Key
|
||||||
WHERE sk.charclass = '$class'";
|
WHERE sk.charclass = '$class'";
|
||||||
@ -64,6 +110,9 @@ WHERE sk.charclass = '$class'";
|
|||||||
return $this->parseChar(); // end of parseChar() calls parseItems(), parseStats, etc.
|
return $this->parseChar(); // end of parseChar() calls parseItems(), parseStats, etc.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function parseItems() {
|
public function parseItems() {
|
||||||
$i_TotalOffset = strpos($this->data, "JM");
|
$i_TotalOffset = strpos($this->data, "JM");
|
||||||
fseek($this->fp, $i_TotalOffset + 2);
|
fseek($this->fp, $i_TotalOffset + 2);
|
||||||
@ -83,6 +132,9 @@ WHERE sk.charclass = '$class'";
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
public function parseChar() {
|
public function parseChar() {
|
||||||
$cData = null;
|
$cData = null;
|
||||||
$cData['Identifier'] = bin2hex($this->bData[0]);
|
$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]]);
|
$cData['VersionID'] = ($this->sData->version[unpack('l', $this->bData[4])[1]]);
|
||||||
|
|
||||||
// 1.41 KB (1,447 bytes) - checks out
|
// 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['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['CharacterName'] = str_replace("\0", "", $this->bData[20]);
|
||||||
$cData['CharacterStatus'] = array_filter(str_split(strtobits($this->bData[36])));
|
$characterStatus = array_filter(str_split(strrev(strtobits($this->bData[36]))));
|
||||||
foreach ($cData['CharacterStatus'] as $k => $v) {
|
foreach ($characterStatus as $k => $v) {
|
||||||
$str .= ($characterStatus[$k]) . " ";
|
$str .= $this->sData->characterStatus[$k] . " ";
|
||||||
}
|
}
|
||||||
$cData['CharacterStatus'] = $str;
|
$cData['CharacterStatus'] = trim($str);
|
||||||
$cData['Characterprogression'] = bindec($this->bData[37]);
|
|
||||||
|
$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['CharacterClass'] = $this->sData->class[unpack('C', $this->bData[40])[1]];
|
||||||
$cData['CharacterLevel'] = unpack('C', $this->bData[43])[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]));
|
$skills = (unpack('l16', $this->bData[56]));
|
||||||
|
// Hotkey assigned skills
|
||||||
foreach ($skills as $skill) {
|
foreach ($skills as $skill) {
|
||||||
$cData['Assignedskills'][] = ($this->sData->skills[$skill]);
|
$cData['Assignedskills'][] = ($this->sData->skills[$skill]);
|
||||||
$cData['Assignedskills'] = array_filter($cData['Assignedskills']);
|
$cData['Assignedskills'] = array_filter($cData['Assignedskills']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$cData['LeftmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[120])[1]];
|
$cData['LeftmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[120])[1]];
|
||||||
$cData['RightmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[124])[1]];
|
$cData['RightmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[124])[1]];
|
||||||
$cData['LeftswapmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[128])[1]];
|
$cData['LeftswapmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[128])[1]];
|
||||||
$cData['RightswapmousebuttonskillID'] = $this->sData->skills[unpack('i', $this->bData[132])[1]];
|
$cData['RightswapmousebuttonskillID'] = $this->sData->skills[unpack('L', $this->bData[132])[1]];
|
||||||
|
|
||||||
// Char menu appearance not needed
|
// Char menu appearance not needed
|
||||||
// $cData['Charactermenuappearance'] = unpack('i', $this->bData[136]);
|
// $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
|
// found in the character.map file, according to the difficulty being played. Not needed
|
||||||
//$cData['MapID'] = $this->bData[171];
|
//$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.
|
// This looks like a random ID for your mercenary.
|
||||||
// $cData['MercenaryID'] = unpack('H*', $this->bData[179]);
|
// $cData['MercenaryID'] = unpack('H*', $this->bData[179]);
|
||||||
$cData['MercenaryNameID'] = unpack('S', $this->bData[183])[1];
|
$cData['MercenaryNameID'] = unpack('S', $this->bData[183])[1];
|
||||||
@ -149,13 +217,16 @@ WHERE sk.charclass = '$class'";
|
|||||||
$this->cData['skills'] = $this->parseSkills();
|
$this->cData['skills'] = $this->parseSkills();
|
||||||
|
|
||||||
unset($this->items);
|
unset($this->items);
|
||||||
unset($this->bData);
|
//unset($this->bData);
|
||||||
unset($this->sData);
|
unset($this->sData);
|
||||||
unset($this->fp);
|
unset($this->fp);
|
||||||
|
|
||||||
return $this->cData;
|
return $this->cData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function parseSkills() {
|
public function parseSkills() {
|
||||||
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
||||||
$jm = strposX($this->data, 'JM', 1);
|
$jm = strposX($this->data, 'JM', 1);
|
||||||
@ -177,6 +248,10 @@ WHERE sk.charclass = '$class'";
|
|||||||
return $cData;
|
return $cData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $points
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setAllSkills(int $points) {
|
public function setAllSkills(int $points) {
|
||||||
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
||||||
$jm = strposX($this->data, 'JM', 1);
|
$jm = strposX($this->data, 'JM', 1);
|
||||||
@ -188,6 +263,11 @@ WHERE sk.charclass = '$class'";
|
|||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $skill
|
||||||
|
* @param int $points
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setSkill(int $skill, int $points) {
|
public function setSkill(int $skill, int $points) {
|
||||||
$skill -= 1;
|
$skill -= 1;
|
||||||
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
$if = strposX($this->data, 'if', 1) + 2; // find if and skip it
|
||||||
@ -198,6 +278,9 @@ WHERE sk.charclass = '$class'";
|
|||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function parseStats() {
|
public function parseStats() {
|
||||||
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
||||||
$if = strposX($this->data, 'if', 1);
|
$if = strposX($this->data, 'if', 1);
|
||||||
@ -211,7 +294,7 @@ WHERE sk.charclass = '$class'";
|
|||||||
$stats->rewind();
|
$stats->rewind();
|
||||||
for ($i = 0; $i <= strlen($bits); $i++) {
|
for ($i = 0; $i <= strlen($bits); $i++) {
|
||||||
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
$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']);
|
$stats->skip($this->ISC[$id]['CSvBits']);
|
||||||
}
|
}
|
||||||
$ids[$id] = $id;
|
$ids[$id] = $id;
|
||||||
@ -219,11 +302,11 @@ WHERE sk.charclass = '$class'";
|
|||||||
$stats->rewind();
|
$stats->rewind();
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
$stats->skip(9);
|
$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']);
|
$val = $stats->readb($this->ISC[$id]['CSvBits']);
|
||||||
|
$stat = $this->ISC[$id]['Stat'];
|
||||||
|
$values[$stat] = hexdec($this->ByteReader->toBytesR($val));
|
||||||
}
|
}
|
||||||
$stat = $this->ISC[$id]['Stat'];
|
|
||||||
$values[$stat] = hexdec($this->ByteReader->toBytesR($val));
|
|
||||||
}
|
}
|
||||||
$values['hitpoints'] = (int) round($values['hitpoints'] >> 11);
|
$values['hitpoints'] = (int) round($values['hitpoints'] >> 11);
|
||||||
$values['maxhp'] = (int) round($values['maxhp'] >> 11);
|
$values['maxhp'] = (int) round($values['maxhp'] >> 11);
|
||||||
@ -231,12 +314,19 @@ WHERE sk.charclass = '$class'";
|
|||||||
$values['maxmana'] = (int) round($values['maxmana'] >> 11);
|
$values['maxmana'] = (int) round($values['maxmana'] >> 11);
|
||||||
$values['stamina'] = (int) round($values['stamina'] >> 11);
|
$values['stamina'] = (int) round($values['stamina'] >> 11);
|
||||||
$values['maxstamina'] = (int) round($values['maxstamina'] >> 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;
|
$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) {
|
switch ($stat) {
|
||||||
case 'CharacterName':
|
case 'CharacterName':
|
||||||
if (strlen($val) < 1 || strlen($val) > 15) {
|
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)));
|
$pack = $this->ByteReader->bitsToHexString($this->ByteReader->toBits(pack('Z16', $val)));
|
||||||
$this->ByteReader->writeBytes(20, $pack);
|
$this->ByteReader->writeBytes(20, $pack);
|
||||||
$this->data = $this->ByteReader->getData();
|
|
||||||
$this->save();
|
|
||||||
rename($this->filePath, $_SESSION['savepath'] . "$val.d2s");
|
rename($this->filePath, $_SESSION['savepath'] . "$val.d2s");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "CharacterClass":
|
case "CharacterClass":
|
||||||
$this->ByteReader->writeByte(40, $val);
|
$classes = [
|
||||||
$this->data = $this->ByteReader->getData();
|
'Amazon' => 0,
|
||||||
$this->save();
|
'Sorceress' => 1,
|
||||||
|
'Necromancer' => 2,
|
||||||
|
'Paladin' => 3,
|
||||||
|
'Barbarian' => 4,
|
||||||
|
'Druid' => 5,
|
||||||
|
'Assassin' => 6
|
||||||
|
];
|
||||||
|
$this->ByteReader->writeByte(40, $classes[$val]);
|
||||||
break;
|
break;
|
||||||
case "CharacterLevel":
|
case "CharacterLevel":
|
||||||
if ($val > 99) {
|
if ($val > 99) {
|
||||||
@ -271,25 +366,110 @@ WHERE sk.charclass = '$class'";
|
|||||||
$res = PDO_FetchOne($sql);
|
$res = PDO_FetchOne($sql);
|
||||||
$this->setStat('experience', $res);
|
$this->setStat('experience', $res);
|
||||||
break;
|
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() {
|
public function generateAllStats() {
|
||||||
// 003C08E081000F067860C001071C0008020800F040020064A000000A2C00C0030C000D000000006E05000000FE3F
|
// 003C08E081000F067860C001071C0008020800F040020064A000000A2C00C0030C000D000000006E05000000FE3F
|
||||||
$stats = '';
|
$stats = '';
|
||||||
foreach ($this->ISC as $i) {
|
for ($i = 0; $i < 16; $i++) {
|
||||||
$id = strrev(str_pad((decbin($i['ID'])), 9, 0, STR_PAD_LEFT));
|
$id = strrev(str_pad((decbin((int) $this->ISC[$i]['ID'])), 9, 0, STR_PAD_LEFT));
|
||||||
$val = strrev(str_pad((decbin(20)), (int) $i['CSvBits'], 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;
|
$stat = $id . $val;
|
||||||
$stats .= $stat;
|
$stats .= $stat;
|
||||||
}
|
}
|
||||||
|
$stats .= "000011111111100";
|
||||||
|
|
||||||
|
dump($stats);
|
||||||
|
|
||||||
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
||||||
$if = strposX($this->data, 'if', 1);
|
$if = strposX($this->data, 'if', 1);
|
||||||
$len = $if - $gf;
|
$len = $if - $gf;
|
||||||
|
|
||||||
$statall = $stats . "11111111100";
|
$bytes = $this->ByteReader->toBytes($stats);
|
||||||
$bytes = $this->ByteReader->toBytes($statall);
|
|
||||||
|
|
||||||
// refresh this data
|
// refresh this data
|
||||||
$data = $this->ByteReader->getData();
|
$data = $this->ByteReader->getData();
|
||||||
@ -303,11 +483,19 @@ WHERE sk.charclass = '$class'";
|
|||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
|
$this->resetFileSize();
|
||||||
|
|
||||||
$filedata = file_get_contents($this->filePath);
|
$filedata = file_get_contents($this->filePath);
|
||||||
$this->ByteReader = new D2ByteReader($filedata);
|
$this->ByteReader = new D2ByteReader($filedata);
|
||||||
$this->data = $this->ByteReader->getData();
|
$this->data = $this->ByteReader->getData();
|
||||||
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $stat
|
||||||
|
* @param mixed $val
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function setStat(string $stat, mixed $val) {
|
public function setStat(string $stat, mixed $val) {
|
||||||
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
$gf = strposX($this->data, 'gf', 1) + 2; // find gf and skip it
|
||||||
$if = strposX($this->data, 'if', 1);
|
$if = strposX($this->data, 'if', 1);
|
||||||
@ -324,7 +512,9 @@ WHERE sk.charclass = '$class'";
|
|||||||
for ($i = 0; $i <= strlen($bits); $i++) {
|
for ($i = 0; $i <= strlen($bits); $i++) {
|
||||||
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
||||||
$_offsets[$id] = $stats->getOffset();
|
$_offsets[$id] = $stats->getOffset();
|
||||||
$stats->skip($this->ISC[$id]['CSvBits']);
|
if ($this->ISC[$id]['CSvBits'] !== null && $this->ISC[$id]['CSvBits'] !== '') {
|
||||||
|
$stats->skip($this->ISC[$id]['CSvBits']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$_offsets[0] = 9;
|
$_offsets[0] = 9;
|
||||||
$offsets = null;
|
$offsets = null;
|
||||||
@ -332,7 +522,9 @@ WHERE sk.charclass = '$class'";
|
|||||||
$_stat = $this->ISC[$k]['Stat'];
|
$_stat = $this->ISC[$k]['Stat'];
|
||||||
$_stats[$_stat] = $this->ISC[$k]['Stat'];
|
$_stats[$_stat] = $this->ISC[$k]['Stat'];
|
||||||
$csvbits[$_stat] = $this->ISC[$k]['CSvBits'];
|
$csvbits[$_stat] = $this->ISC[$k]['CSvBits'];
|
||||||
$maxValues[$_stat] = pow(2, $this->ISC[$k]['CSvBits']) - 1;
|
if ($this->ISC[$k]['CSvBits'] !== null && $this->ISC[$k]['CSvBits'] !== '') {
|
||||||
|
$maxValues[$_stat] = pow(2, $this->ISC[$k]['CSvBits']) - 1;
|
||||||
|
}
|
||||||
$offsets[$_stat] = $v;
|
$offsets[$_stat] = $v;
|
||||||
}
|
}
|
||||||
if ($stat == 'hitpoints' || $stat == 'maxhp' || $stat == 'mana' || $stat == 'maxmana' || $stat == 'stamina' || $stat == 'maxstamina') {
|
if ($stat == 'hitpoints' || $stat == 'maxhp' || $stat == 'mana' || $stat == 'maxmana' || $stat == 'stamina' || $stat == 'maxstamina') {
|
||||||
@ -344,14 +536,22 @@ WHERE sk.charclass = '$class'";
|
|||||||
}
|
}
|
||||||
$bitsToWrite = strrev(str_pad(decbin(intval($val)), $csvbits[$_stats[$stat]], 0, STR_PAD_LEFT));
|
$bitsToWrite = strrev(str_pad(decbin(intval($val)), $csvbits[$_stats[$stat]], 0, STR_PAD_LEFT));
|
||||||
$statOffset = $offsets[$_stats[$stat]];
|
$statOffset = $offsets[$_stats[$stat]];
|
||||||
$newBits = $stats->writeBits($bits, $bitsToWrite, $statOffset) . "11111111100"; // 0x1FF padding
|
if (!array_key_exists($stat, $_stats)) {
|
||||||
$stats->setBits($newBits);
|
$this->ByteReader->toBits($this->generateAllStats());
|
||||||
$bytes = $this->ByteReader->toBytes($newBits);
|
} else {
|
||||||
$this->ByteReader->writeBytes($gf, $bytes);
|
$newBits = $stats->writeBits($bits, $bitsToWrite, $statOffset) . "11111111100"; // 0x1FF padding
|
||||||
$this->data = $this->ByteReader->getData();
|
$stats->setBits($newBits);
|
||||||
$this->save();
|
$bytes = $this->ByteReader->toBytes($newBits);
|
||||||
|
$this->ByteReader->writeBytes($gf, $bytes);
|
||||||
|
$this->data = $this->ByteReader->getData();
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getQuestData($file) {
|
public function getQuestData($file) {
|
||||||
$questsNorm = null;
|
$questsNorm = null;
|
||||||
$questsNM = null;
|
$questsNM = null;
|
||||||
@ -390,6 +590,10 @@ WHERE sk.charclass = '$class'";
|
|||||||
return $quests;
|
return $quests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getWaypointsData($file) {
|
public function getWaypointsData($file) {
|
||||||
$wp = null;
|
$wp = null;
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNorm);
|
fseek($this->fp, $this->sData->wpOffsetsNorm);
|
||||||
|
@ -2,84 +2,306 @@
|
|||||||
|
|
||||||
require_once 'D2BitReader.php';
|
require_once 'D2BitReader.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2CharItem {
|
class D2CharItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
private string $bits;
|
private string $bits;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $basename = ''; //name of the base item
|
public $basename = ''; //name of the base item
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $item_name = ''; //name string
|
public $item_name = ''; //name string
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $item_rank = ''; //normal/exceptional/elite
|
public $item_rank = ''; //normal/exceptional/elite
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $item_type = ''; //basic type: armor/weapon/misc
|
public $item_type = ''; //basic type: armor/weapon/misc
|
||||||
//flags
|
//flags
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $identified = 0;
|
public $identified = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $sockets = 0;
|
public $sockets = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $ear = 0;
|
public $ear = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $starter = 0;
|
public $starter = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $compact = 0;
|
public $compact = 0;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $ethereal;
|
public $ethereal;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $personalized;
|
public $personalized;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $runeword;
|
public $runeword;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $version;
|
public $version;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $runeword_name = '';
|
public $runeword_name = '';
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $runes_title = '';
|
public $runes_title = '';
|
||||||
//placement
|
//placement
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $location = 0;
|
public $location = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $body = 0;
|
public $body = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $col = 0;
|
public $col = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $row = 0;
|
public $row = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $container = 0;
|
public $container = 0;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $parent;
|
public $parent;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $storage;
|
public $storage;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $bodypart;
|
public $bodypart;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $invH = 0;
|
public $invH = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $invW = 0;
|
public $invW = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $beltrows = 1;
|
public $beltrows = 1;
|
||||||
//features
|
//features
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $item_code = ''; //3 letter code from txt
|
public $item_code = ''; //3 letter code from txt
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $SocketsFilled = 0;
|
public $SocketsFilled = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $SocketsNum = 0;
|
public $SocketsNum = 0;
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
public $socketable = false; //gem, rune, jewel
|
public $socketable = false; //gem, rune, jewel
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $fingerprint = '';
|
public $fingerprint = '';
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $itemlvl = 0; //item level
|
public $itemlvl = 0; //item level
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $quality = 0;
|
public $quality = 0;
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
public $isCharm = false;
|
public $isCharm = false;
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
public $isJewel = false;
|
public $isJewel = false;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $magic_rank = 'Normal'; //normal/magic/rare/crafted/set/unique
|
public $magic_rank = 'Normal'; //normal/magic/rare/crafted/set/unique
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $set_id = 0; //set item id from txt
|
public $set_id = 0; //set item id from txt
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $set_item = '';
|
public $set_item = '';
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $set_name = 0; //set name, if it is set item,
|
public $set_name = 0; //set name, if it is set item,
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $personname = '';
|
public $personname = '';
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $questdif = -1;
|
public $questdif = -1;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $gold;
|
public $gold;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $GUID = '';
|
public $GUID = '';
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $defense = 0;
|
public $defense = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $mindam = 0;
|
public $mindam = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $maxdam = 0;
|
public $maxdam = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $mindam2 = 0;
|
public $mindam2 = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $maxdam2 = 0;
|
public $maxdam2 = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $mindammi = 0;
|
public $mindammi = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $maxdammi = 0;
|
public $maxdammi = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $MaxDur = 0;
|
public $MaxDur = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $CurDur = 0;
|
public $CurDur = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $reqlvl = 0;
|
public $reqlvl = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $reqstr = 0;
|
public $reqstr = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $reqdex = 0;
|
public $reqdex = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $speed = 0;
|
public $speed = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $throwing = 0;
|
public $throwing = 0;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $stackable = 0;
|
public $stackable = 0;
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $charName = ''; //ear's name
|
public $charName = ''; //ear's name
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $gfx; //graphic file name
|
public $gfx; //graphic file name
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $baseTrans = -1; //transform indexes for colour remap base item
|
public $baseTrans = -1; //transform indexes for colour remap base item
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $magicTrans = -1; //transform indexes for colour remap magic item
|
public $magicTrans = -1; //transform indexes for colour remap magic item
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $type; //type column from txt
|
public $type; //type column from txt
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
public $spelldesc = ''; //desc for potions
|
public $spelldesc = ''; //desc for potions
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $ditem; //link to item properties from txt
|
public $ditem; //link to item properties from txt
|
||||||
//mods
|
//mods
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $dammult = 100; //damage multiply
|
public $dammult = 100; //damage multiply
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $damminadd = 0; //damage add
|
public $damminadd = 0; //damage add
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $dammaxadd = 0; //damage add
|
public $dammaxadd = 0; //damage add
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $defmult = 100; //defense multiply
|
public $defmult = 100; //defense multiply
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $defadd = 0; //defense multiply
|
public $defadd = 0; //defense multiply
|
||||||
|
/**
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
public $resist = array(0, 0, 0, 0, 0, 0); //phy, mag, fire, light, cold, poison
|
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
|
public $attributes = array(0, 0, 0, 0); //str, dex, vit, ene
|
||||||
|
|
||||||
//arrays
|
//arrays
|
||||||
@ -87,11 +309,23 @@ class D2CharItem {
|
|||||||
//socketed items, collected in above function,
|
//socketed items, collected in above function,
|
||||||
//because item has only data for itselt, and
|
//because item has only data for itselt, and
|
||||||
//gems/runes/jewels are standalone
|
//gems/runes/jewels are standalone
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $SocketItems = array();
|
public $SocketItems = array();
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $properties = array(); //item variable properties
|
public $properties = array(); //item variable properties
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $propids = array(); //properties ids list
|
public $propids = array(); //properties ids list
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $bits
|
||||||
|
*/
|
||||||
public function __construct(string $bits){
|
public function __construct(string $bits){
|
||||||
if ($bits == '') return false;
|
if ($bits == '') return false;
|
||||||
$this->bits = $bits;
|
$this->bits = $bits;
|
||||||
@ -99,6 +333,9 @@ class D2CharItem {
|
|||||||
return $this->parseItem();
|
return $this->parseItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function parseItem(){
|
public function parseItem(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,24 @@ ini_set('max_execution_time', '0');
|
|||||||
session_start();
|
session_start();
|
||||||
ob_start();
|
ob_start();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
define('DB_FILE', $_SESSION['modname'] . ".db");
|
define('DB_FILE', $_SESSION['modname'] . ".db");
|
||||||
PDO_Connect("sqlite:" . DB_FILE);
|
PDO_Connect("sqlite:" . DB_FILE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2CharStructureData {
|
class D2CharStructureData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $skills;
|
public $skills;
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $class = [
|
public $class = [
|
||||||
0 => 'Amazon',
|
0 => 'Amazon',
|
||||||
1 => 'Sorceress',
|
1 => 'Sorceress',
|
||||||
@ -22,6 +34,9 @@ class D2CharStructureData {
|
|||||||
5 => 'Druid',
|
5 => 'Druid',
|
||||||
6 => 'Assassin'
|
6 => 'Assassin'
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $characterStatus = [
|
public $characterStatus = [
|
||||||
0 => '',
|
0 => '',
|
||||||
1 => '',
|
1 => '',
|
||||||
@ -32,6 +47,93 @@ class D2CharStructureData {
|
|||||||
6 => 'Ladder',
|
6 => 'Ladder',
|
||||||
7 => ''
|
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 = [
|
public $offsets = [
|
||||||
0 => 4, // Identifier
|
0 => 4, // Identifier
|
||||||
4 => 4, // Version ID
|
4 => 4, // Version ID
|
||||||
@ -67,6 +169,9 @@ class D2CharStructureData {
|
|||||||
633 => 81, // Waypoints
|
633 => 81, // Waypoints
|
||||||
714 => 51, // NPC Introductions
|
714 => 51, // NPC Introductions
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $qNorm = [
|
public $qNorm = [
|
||||||
345 => 'introWarriv',
|
345 => 'introWarriv',
|
||||||
347 => 'Den_Of_Evil',
|
347 => 'Den_Of_Evil',
|
||||||
@ -110,8 +215,10 @@ class D2CharStructureData {
|
|||||||
423 => 'Rite_Of_Passage',
|
423 => 'Rite_Of_Passage',
|
||||||
425 => 'Eve_Of_Destruction',
|
425 => 'Eve_Of_Destruction',
|
||||||
// read 425, pointer at 427, + 14 = 441 qNM offset
|
// read 425, pointer at 427, + 14 = 441 qNM offset
|
||||||
|
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $qNM = [
|
public $qNM = [
|
||||||
441 => 'introWarrivNM',
|
441 => 'introWarrivNM',
|
||||||
443 => 'Den_Of_Evil_NM',
|
443 => 'Den_Of_Evil_NM',
|
||||||
@ -155,9 +262,10 @@ class D2CharStructureData {
|
|||||||
519 => 'Rite_Of_Passage',
|
519 => 'Rite_Of_Passage',
|
||||||
521 => 'Eve_Of_Destruction',
|
521 => 'Eve_Of_Destruction',
|
||||||
// read 521, pointer at 523, + 14 = 537 qHell offset
|
// read 521, pointer at 523, + 14 = 537 qHell offset
|
||||||
|
|
||||||
|
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $qHell = [
|
public $qHell = [
|
||||||
537 => 'introWarriv',
|
537 => 'introWarriv',
|
||||||
539 => 'Den_Of_Evil_Hell',
|
539 => 'Den_Of_Evil_Hell',
|
||||||
@ -198,10 +306,12 @@ class D2CharStructureData {
|
|||||||
609 => 'Rescue_On_MountArreat',
|
609 => 'Rescue_On_MountArreat',
|
||||||
611 => 'Prison_Of_Ice',
|
611 => 'Prison_Of_Ice',
|
||||||
613 => 'Betrayal_Of_Harrogath',
|
613 => 'Betrayal_Of_Harrogath',
|
||||||
615=> 'Rite_Of_Passage',
|
615 => 'Rite_Of_Passage',
|
||||||
617 => 'Eve_Of_Destruction',
|
617 => 'Eve_Of_Destruction',
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $version = [
|
public $version = [
|
||||||
71 => "1.00 through v1.06",
|
71 => "1.00 through v1.06",
|
||||||
87 => "1.07 or Expansion Set v1.08",
|
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.)",
|
92 => "v1.09 (both the standard game and the Expansion Set.)",
|
||||||
96 => "v1.10+"
|
96 => "v1.10+"
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $wpOffsetsNorm = 643;
|
public $wpOffsetsNorm = 643;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $wpOffsetsNM = 667;
|
public $wpOffsetsNM = 667;
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
public $wpOffsetsHell = 691;
|
public $wpOffsetsHell = 691;
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
public $wpNames = [
|
public $wpNames = [
|
||||||
0 => 'Act 1 - Rogue_Encampment',
|
0 => 'Act 1 - Rogue_Encampment',
|
||||||
1 => 'Act 1 - Cold_Plains',
|
1 => 'Act 1 - Cold_Plains',
|
||||||
@ -256,17 +375,22 @@ class D2CharStructureData {
|
|||||||
37 => "Act 5 - The_Ancients_Way",
|
37 => "Act 5 - The_Ancients_Way",
|
||||||
38 => 'Act 5 - Worldstone_Keep_level_2'
|
38 => 'Act 5 - Worldstone_Keep_level_2'
|
||||||
];
|
];
|
||||||
|
/**
|
||||||
|
* @var int[]|string[]
|
||||||
|
*/
|
||||||
public $_qNorm;
|
public $_qNorm;
|
||||||
|
/**
|
||||||
|
* @var int[]|string[]
|
||||||
|
*/
|
||||||
public $_qNM;
|
public $_qNM;
|
||||||
|
/**
|
||||||
|
* @var int[]|string[]
|
||||||
|
*/
|
||||||
public $_qHell;
|
public $_qHell;
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
*
|
||||||
Initialize Skills From Skills.txt
|
*/
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -42,13 +42,24 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2Database {
|
class D2Database {
|
||||||
|
|
||||||
public function __construct() {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
PDO_Connect("sqlite:" . DB_FILE);
|
PDO_Connect("sqlite:" . DB_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createTables($file, $data) {
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @param $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function createTables($file, $data) {
|
||||||
$tableName = basename($file);
|
$tableName = basename($file);
|
||||||
$tableName = strtolower(substr($tableName, 0, -4));
|
$tableName = strtolower(substr($tableName, 0, -4));
|
||||||
$sql = '';
|
$sql = '';
|
||||||
@ -68,7 +79,12 @@ class D2Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function fillsTables($file, $data) {
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @param $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function fillsTables($file, $data) {
|
||||||
$tableName = basename($file);
|
$tableName = basename($file);
|
||||||
$tableName = strtolower(substr($tableName, 0, -4));
|
$tableName = strtolower(substr($tableName, 0, -4));
|
||||||
|
|
||||||
@ -106,7 +122,11 @@ class D2Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function writeTbl($data) {
|
/**
|
||||||
|
* @param $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function writeTbl($data) {
|
||||||
$sql = 'CREATE TABLE IF NOT EXISTS `strings` (`Key` VARCHAR(255), `String` VARCHAR(255));';
|
$sql = 'CREATE TABLE IF NOT EXISTS `strings` (`Key` VARCHAR(255), `String` VARCHAR(255));';
|
||||||
$res = PDO_Execute($sql);
|
$res = PDO_Execute($sql);
|
||||||
|
|
||||||
@ -120,7 +140,11 @@ class D2Database {
|
|||||||
$res = PDO_Execute($sql);
|
$res = PDO_Execute($sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getString($key) {
|
/**
|
||||||
|
* @param $key
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getString($key) {
|
||||||
$sql = "SELECT String FROM `strings` WHERE `Key`='$key'";
|
$sql = "SELECT String FROM `strings` WHERE `Key`='$key'";
|
||||||
|
|
||||||
$res = PDO_FetchRow($sql);
|
$res = PDO_FetchRow($sql);
|
||||||
|
@ -42,8 +42,14 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2DocGenerator {
|
class D2DocGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
require_once './config.php';
|
require_once './config.php';
|
||||||
require_once './_pdo.php';
|
require_once './_pdo.php';
|
||||||
@ -61,6 +67,9 @@ class D2DocGenerator {
|
|||||||
$idata = new D2ItemData();
|
$idata = new D2ItemData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getIscProps() {
|
public function getIscProps() {
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT p.`code` as prop,
|
SELECT p.`code` as prop,
|
||||||
@ -103,6 +112,9 @@ class D2DocGenerator {
|
|||||||
return $isc;
|
return $isc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getStrings() {
|
public function getStrings() {
|
||||||
// load strings
|
// load strings
|
||||||
$sql = 'SELECT * FROM strings';
|
$sql = 'SELECT * FROM strings';
|
||||||
@ -110,6 +122,9 @@ class D2DocGenerator {
|
|||||||
return $strings;
|
return $strings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getItemTypesTbl() {
|
public function getItemTypesTbl() {
|
||||||
// load itemtypes table in memory
|
// load itemtypes table in memory
|
||||||
$sql = "SELECT ItemType,Code FROM itemtypes";
|
$sql = "SELECT ItemType,Code FROM itemtypes";
|
||||||
@ -118,6 +133,9 @@ class D2DocGenerator {
|
|||||||
return $itemtypesTbl;
|
return $itemtypesTbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
public function getNameStr() {
|
public function getNameStr() {
|
||||||
// load namestr from 3 files
|
// load namestr from 3 files
|
||||||
$sql = "SELECT code,namestr FROM armor
|
$sql = "SELECT code,namestr FROM armor
|
||||||
@ -130,6 +148,10 @@ class D2DocGenerator {
|
|||||||
return $namestr;
|
return $namestr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $code
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
public function getImage($code) {
|
public function getImage($code) {
|
||||||
$sql = "SELECT invfile FROM armor WHERE `code`=\"$code\" OR `type`=\"$code\" OR `type2`=\"$code\"";
|
$sql = "SELECT invfile FROM armor WHERE `code`=\"$code\" OR `type`=\"$code\" OR `type2`=\"$code\"";
|
||||||
$img = PDO_FetchOne($sql);
|
$img = PDO_FetchOne($sql);
|
||||||
@ -144,6 +166,10 @@ class D2DocGenerator {
|
|||||||
return $img = (!empty($img)) ? "$img.png" : "1.png";
|
return $img = (!empty($img)) ? "$img.png" : "1.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $code
|
||||||
|
* @return false
|
||||||
|
*/
|
||||||
public function getItemName($code) {
|
public function getItemName($code) {
|
||||||
$sql = "SELECT name FROM armor WHERE `code`=\"$code\" OR `type`=\"$code\" OR `type2`=\"$code\"";
|
$sql = "SELECT name FROM armor WHERE `code`=\"$code\" OR `type`=\"$code\" OR `type2`=\"$code\"";
|
||||||
$name = PDO_FetchOne($sql);
|
$name = PDO_FetchOne($sql);
|
||||||
@ -158,6 +184,9 @@ class D2DocGenerator {
|
|||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function generateDocs() {
|
public function generateDocs() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,23 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2Files {
|
class D2Files {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public $files = [];
|
public $files = [];
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $charFiles;
|
public $charFiles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$filesToIgnore = [
|
$filesToIgnore = [
|
||||||
"aiparms.txt",
|
"aiparms.txt",
|
||||||
@ -64,6 +76,9 @@ class D2Files {
|
|||||||
return $this->files;
|
return $this->files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
public function getSaveFiles() {
|
public function getSaveFiles() {
|
||||||
$glob = glob($_SESSION['savepath'] . '*.d2s');
|
$glob = glob($_SESSION['savepath'] . '*.d2s');
|
||||||
|
|
||||||
|
@ -42,6 +42,10 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $var
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
function ddump($var) {
|
function ddump($var) {
|
||||||
//echo "<pre>";
|
//echo "<pre>";
|
||||||
var_dump($var);
|
var_dump($var);
|
||||||
@ -51,6 +55,10 @@ function ddump($var) {
|
|||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $var
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
function dump($var) {
|
function dump($var) {
|
||||||
//echo "<pre>";
|
//echo "<pre>";
|
||||||
var_dump($var);
|
var_dump($var);
|
||||||
@ -59,6 +67,10 @@ function dump($var) {
|
|||||||
//echo json_encode($var, JSON_INVALID_UTF8_IGNORE | JSON_PRETTY_PRINT);
|
//echo json_encode($var, JSON_INVALID_UTF8_IGNORE | JSON_PRETTY_PRINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $str
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
function strtobits(string $str): string {
|
function strtobits(string $str): string {
|
||||||
$ret = "";
|
$ret = "";
|
||||||
for ($i = 0; $i < strlen($str); ++$i) {
|
for ($i = 0; $i < strlen($str); ++$i) {
|
||||||
@ -74,14 +86,29 @@ function strtobits(string $str): string {
|
|||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $hex
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
function swapEndianness(string $hex) {
|
function swapEndianness(string $hex) {
|
||||||
return implode('', array_reverse(str_split($hex, 2)));
|
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) {
|
function setBit(int $n, int $p, bool $b) {
|
||||||
return ($b ? ($n | (1 << $p)) : ($n & ~(1 << $p)) );
|
return ($b ? ($n | (1 << $p)) : ($n & ~(1 << $p)) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $b
|
||||||
|
* @param int $p
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
function getBit(int $b, int $p) {
|
function getBit(int $b, int $p) {
|
||||||
return intval(($b & (1 << $p)) !== 0);
|
return intval(($b & (1 << $p)) !== 0);
|
||||||
}
|
}
|
||||||
@ -91,29 +118,21 @@ function getBit(int $b, int $p) {
|
|||||||
* @param $data
|
* @param $data
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
//function checksum($data) {
|
function checksum($fileData) {
|
||||||
// $nSignature = 0;
|
$nSignature = 0;
|
||||||
// $checksum = 0;
|
foreach ($fileData as $k => $byte) {
|
||||||
// foreach ($data as $k => $byte) {
|
if ($k == 12 || $k == 13 || $k == 14 || $k == 15) {
|
||||||
//// if ($k == 12 || $k == 13 || $k == 14 || $k == 15) {
|
$byte = 0;
|
||||||
//// $byte = 0;
|
}
|
||||||
//// }
|
$nSignature = ((($nSignature << 1) | ($nSignature >> 31)) + $byte & 0xFFFFFFFF);
|
||||||
// $nSignature = ((($nSignature << 1) | ($nSignature >> 31)) + $byte) & 0xFFFFFFFF;
|
}
|
||||||
// $checksum = (($checksum << 1) & 0xffffffff) + $byte + (($checksum & 0x80000000) != 0 ? 1 : 0);
|
return swapEndianness(str_pad(dechex($nSignature), 8, 0, STR_PAD_LEFT));
|
||||||
// }
|
}
|
||||||
// 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
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $filePath
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
function checksumFix(string $filePath) {
|
function checksumFix(string $filePath) {
|
||||||
return trim(shell_exec("bin\d2scs.exe \"$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 {
|
function isBit(string $bit): int {
|
||||||
return ((int) $bit ? 1 : 0 );
|
return ((int) $bit ? 1 : 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $input
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
function toBits($input): string {
|
function toBits($input): string {
|
||||||
$output = '';
|
$output = '';
|
||||||
if (is_string($input)) {
|
if (is_string($input)) {
|
||||||
@ -156,6 +183,9 @@ function toBits($input): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
function print_mem() {
|
function print_mem() {
|
||||||
/* Currently used memory */
|
/* Currently used memory */
|
||||||
$mem_usage = memory_get_usage();
|
$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>';
|
echo 'Peak usage: <strong>' . round($mem_peak / 1024 / 1024) . 'MB</strong> RAM.<br><br>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $src
|
||||||
|
* @param $dst
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
function rcopy($src, $dst) {
|
function rcopy($src, $dst) {
|
||||||
// open the source directory
|
// open the source directory
|
||||||
$dir = opendir($src);
|
$dir = opendir($src);
|
||||||
@ -185,6 +220,10 @@ function rcopy($src, $dst) {
|
|||||||
closedir($dir);
|
closedir($dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $src
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
function rrmdir($src) {
|
function rrmdir($src) {
|
||||||
$dir = opendir($src);
|
$dir = opendir($src);
|
||||||
while (false !== ( $file = readdir($dir))) {
|
while (false !== ( $file = readdir($dir))) {
|
||||||
|
@ -3,11 +3,23 @@
|
|||||||
require_once 'D2BitReader.php';
|
require_once 'D2BitReader.php';
|
||||||
require_once 'D2ItemStructureData.php';
|
require_once 'D2ItemStructureData.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2Item {
|
class D2Item {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
private $bits = null;
|
private $bits = null;
|
||||||
|
/**
|
||||||
|
* @var null
|
||||||
|
*/
|
||||||
public $iData = null;
|
public $iData = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $bits
|
||||||
|
*/
|
||||||
public function __construct($bits) {
|
public function __construct($bits) {
|
||||||
if ($bits == '')
|
if ($bits == '')
|
||||||
return false;
|
return false;
|
||||||
@ -20,6 +32,9 @@ class D2Item {
|
|||||||
* @return array of item details
|
* @return array of item details
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return null
|
||||||
|
*/
|
||||||
private function parseItem() {
|
private function parseItem() {
|
||||||
$b = new D2BitReader($this->bits);
|
$b = new D2BitReader($this->bits);
|
||||||
|
|
||||||
|
@ -1,10 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2ItemData {
|
class D2ItemData {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $strings;
|
public $strings;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
public $images;
|
public $images;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function getImages() {
|
public function getImages() {
|
||||||
$sql = "SELECT code,uniqueinvfile,invfile,type,type2 FROM armor
|
$sql = "SELECT code,uniqueinvfile,invfile,type,type2 FROM armor
|
||||||
UNION ALL
|
UNION ALL
|
||||||
@ -24,6 +36,11 @@ class D2ItemData {
|
|||||||
unset($isc2);
|
unset($isc2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $index
|
||||||
|
* @param $doc
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
public function uniqueItems($index, $doc = FALSE) {
|
public function uniqueItems($index, $doc = FALSE) {
|
||||||
if (empty($this->images)) {
|
if (empty($this->images)) {
|
||||||
$this->getImages();
|
$this->getImages();
|
||||||
@ -897,6 +914,10 @@ class D2ItemData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $iscStat
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
public function getIscStrings($iscStat) {
|
public function getIscStrings($iscStat) {
|
||||||
if (empty($this->strings)) {
|
if (empty($this->strings)) {
|
||||||
$this->getStrings();
|
$this->getStrings();
|
||||||
@ -904,6 +925,9 @@ class D2ItemData {
|
|||||||
return ($this->strings[$iscStat]);
|
return ($this->strings[$iscStat]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public function getStrings() {
|
public function getStrings() {
|
||||||
$sql = "
|
$sql = "
|
||||||
SELECT p.`code` as prop,
|
SELECT p.`code` as prop,
|
||||||
|
@ -42,6 +42,9 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2ItemDesc {
|
class D2ItemDesc {
|
||||||
/*
|
/*
|
||||||
|
|
||||||
@ -135,14 +138,26 @@ class D2ItemDesc {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public $str = '';
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
public $str = '';
|
||||||
// takes value, param.
|
// takes value, param.
|
||||||
// value == Value to show on this stat
|
// value == Value to show on this stat
|
||||||
//descfunc 14
|
//descfunc 14
|
||||||
|
|
||||||
public $skilltabsDesc;
|
/**
|
||||||
public $skilltabsDescClean;
|
* @var
|
||||||
public $skilltabs = [
|
*/
|
||||||
|
public $skilltabsDesc;
|
||||||
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $skilltabsDescClean;
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
public $skilltabs = [
|
||||||
//ama
|
//ama
|
||||||
'0' => 'StrSklTabItem3',
|
'0' => 'StrSklTabItem3',
|
||||||
'1' => 'StrSklTabItem2',
|
'1' => 'StrSklTabItem2',
|
||||||
@ -172,7 +187,10 @@ class D2ItemDesc {
|
|||||||
'19' => 'StrSklTabItem20',
|
'19' => 'StrSklTabItem20',
|
||||||
'20' => 'StrSklTabItem21'
|
'20' => 'StrSklTabItem21'
|
||||||
];
|
];
|
||||||
public $charClass = [
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
public $charClass = [
|
||||||
"ama" => "Amazon",
|
"ama" => "Amazon",
|
||||||
"sor" => "Sorceress",
|
"sor" => "Sorceress",
|
||||||
"nec" => "Necromancer",
|
"nec" => "Necromancer",
|
||||||
@ -245,7 +263,13 @@ class D2ItemDesc {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function prep($par, $min, $max) {
|
/**
|
||||||
|
* @param $par
|
||||||
|
* @param $min
|
||||||
|
* @param $max
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function prep($par, $min, $max) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,16 +292,19 @@ class D2ItemDesc {
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public function __construct() {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $params
|
||||||
|
* @return false|string
|
||||||
|
*/
|
||||||
public function getDesc($params = []) {
|
public function getDesc($params = []) {
|
||||||
if (empty($params))
|
if (empty($params))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -1,40 +1,112 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2ItemLocation {
|
class D2ItemLocation {
|
||||||
|
|
||||||
//location
|
//location
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const STORED = 0;
|
const STORED = 0;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const EQUIPPED = 1;
|
const EQUIPPED = 1;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const BELTI = 2;
|
const BELTI = 2;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const CURSOR = 4;
|
const CURSOR = 4;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const ITEM = 6;
|
const ITEM = 6;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2ItemLocationStored {
|
class D2ItemLocationStored {
|
||||||
|
|
||||||
//storage
|
//storage
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const NONE = 0;
|
const NONE = 0;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const INVENTORY = 1;
|
const INVENTORY = 1;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const CUBE = 4;
|
const CUBE = 4;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const STASH = 5;
|
const STASH = 5;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2ItemLocationBody {
|
class D2ItemLocationBody {
|
||||||
|
|
||||||
//body parts
|
//body parts
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const HELMET = 1;
|
const HELMET = 1;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const AMULET = 2;
|
const AMULET = 2;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const ARMOR = 3;
|
const ARMOR = 3;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const WEAPONR = 4;
|
const WEAPONR = 4;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const WEAPONL = 5;
|
const WEAPONL = 5;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const RINGR = 6;
|
const RINGR = 6;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const RINGL = 7;
|
const RINGL = 7;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const BELT = 8;
|
const BELT = 8;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const BOOTS = 9;
|
const BOOTS = 9;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const GLOVES = 10;
|
const GLOVES = 10;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const WEAPONR2 = 11;
|
const WEAPONR2 = 11;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
const WEAPONL2 = 12;
|
const WEAPONL2 = 12;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,22 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2SaveTXT {
|
class D2SaveTXT {
|
||||||
|
|
||||||
public $path;
|
/**
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
public $path;
|
||||||
|
|
||||||
public function save($file, $data) {
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @param $data
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function save($file, $data) {
|
||||||
|
|
||||||
$fp = fopen($this->path.DIRECTORY_SEPARATOR.$file, 'a+');
|
$fp = fopen($this->path.DIRECTORY_SEPARATOR.$file, 'a+');
|
||||||
$this->saveBackup($file);
|
$this->saveBackup($file);
|
||||||
@ -54,7 +65,11 @@ class D2SaveTXT {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function saveBackup($file){
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function saveBackup($file){
|
||||||
|
|
||||||
// if dir doesn't exist, create it
|
// if dir doesn't exist, create it
|
||||||
if (!is_dir($this->path.DIRECTORY_SEPARATOR."backup")) mkdir($this->path."backup", 0700);
|
if (!is_dir($this->path.DIRECTORY_SEPARATOR."backup")) mkdir($this->path."backup", 0700);
|
||||||
@ -72,7 +87,11 @@ class D2SaveTXT {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function saveTblEnries($filename) {
|
/**
|
||||||
|
* @param $filename
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function saveTblEnries($filename) {
|
||||||
$post = $_POST;
|
$post = $_POST;
|
||||||
|
|
||||||
if (!is_dir($this->path."tblEntries")) mkdir($this->path."tblEntries", 0700);
|
if (!is_dir($this->path."tblEntries")) mkdir($this->path."tblEntries", 0700);
|
||||||
@ -83,7 +102,10 @@ class D2SaveTXT {
|
|||||||
file_put_contents($file, $str, FILE_APPEND);
|
file_put_contents($file, $str, FILE_APPEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct() {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
$this->path = TXT_PATH;
|
$this->path = TXT_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2Strings {
|
class D2Strings {
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
public array $strings;
|
public array $strings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$sql = "SELECT * FROM strings";
|
$sql = "SELECT * FROM strings";
|
||||||
$this->strings = PDO_FetchAssoc($sql);
|
$this->strings = PDO_FetchAssoc($sql);
|
||||||
|
@ -41,20 +41,41 @@
|
|||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class D2TxtParser {
|
class D2TxtParser {
|
||||||
|
|
||||||
public $path = TXT_PATH;
|
/**
|
||||||
|
* @var mixed
|
||||||
|
*/
|
||||||
|
public $path = TXT_PATH;
|
||||||
|
|
||||||
public $db;
|
/**
|
||||||
|
* @var
|
||||||
|
*/
|
||||||
|
public $db;
|
||||||
|
|
||||||
public function __construct() {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parseFile($file) {
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parseFile($file) {
|
||||||
return $this->parseData($file);
|
return $this->parseData($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterProps($file) {
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
function filterProps($file) {
|
||||||
$data = $this->parseData($file);
|
$data = $this->parseData($file);
|
||||||
$propsToFilter = file(FILTER_PROPERTIES_FILE, FILE_IGNORE_NEW_LINES);
|
$propsToFilter = file(FILTER_PROPERTIES_FILE, FILE_IGNORE_NEW_LINES);
|
||||||
foreach ($data as $d) {
|
foreach ($data as $d) {
|
||||||
@ -65,7 +86,11 @@ class D2TxtParser {
|
|||||||
return $filteredProps;
|
return $filteredProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function parseData($file) {
|
/**
|
||||||
|
* @param $file
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function parseData($file) {
|
||||||
$file = $this->path . $file;
|
$file = $this->path . $file;
|
||||||
$rows = array_map(function ($v) {
|
$rows = array_map(function ($v) {
|
||||||
return str_getcsv($v, "\t");
|
return str_getcsv($v, "\t");
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="center item_desc" style="">
|
<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">
|
<a href="" target="_blank" class="item_debug_link">
|
||||||
<img style="" class="item img-fluid" src="">
|
<img style="" class="item img-fluid" src="">
|
||||||
</a>
|
</a>
|
||||||
|
219
test.php
219
test.php
@ -1,195 +1,42 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// from unpack('H*', file_get_contents("Char.d2s")) for 3v4l.org to read d2s file here
|
/*
|
||||||
//$data = hex2bin('55aa55aa60000000f1060000b5bc59b300000000536f72630000000000000000000000002400000001103863000000003cc7ae62ffffffffffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000000000000570300000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000005e3e9b11000000008888d5f80100000035b70300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576f6f21060000002a0101000190fd9ffe9ffd9ffe9ffd9f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057530100000050000201ffffffff7f00000000000000000000000000000000000201ffffffff7f00000000000000000000000000000000000201ffffffff7f0000000000000000000000000000000000017734002e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067660028083082000a06644000b10252067094c1018082800020292400480a0a0030c202008cc060dcc0f0ca3afa160a0000e03f696600000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004a4d32004a4d100082006500069226160382af144fb080e03f4a4d1000820065000a9226260302791c00c480e03f4a4d10008000654415c076c606821c7ffff58080010a06fe034a4d1000800065008013268303827e82896086dccb000066c5bcfeffff014a4d1000820065000022f6860782b067b7ec80e03f4a4d1000820065001a922636038249b154da80a025040000c07f4a4d1000a0006500a442665363034a4d1000a0006500fe13367703024a4d1000a0006500de13362703024a4d1000a0006500be13361703024a4d1000a00065009e13360703024a4d1000a00065007e1336a707024a4d1000a00065005e13369707024a4d1000a00065003e1336f706024a4d1000a0006500c013e65606024a4d1000a00065006012d68607024a4d1000a00065000e12d60603024a4d1000a00065006412564306024a4d1000800065001e83179303029920441686e03f4a4d1000a0006500fe12d69606024a4d1000a0006500de12d68606024a4d1000a0006500be12d67606024a4d1000a00065009e12e67606024a4d1000a00065007e12e69606024a4d1000a0006500fc13e6a606024a4d1000a0006500dc13c68603024a4d1000a0006500bc13e6b606024a4d1000800065009c83272303826f9aed3186e03f4a4d1000800065007c8317730302acd0c26e86e03f4a4d1000a00065005c13560603024a4d1000a00065003c13569607024a4d1000a00065001c13464603024a4d1000a00065001212d66607024a4d1000a00865001412d66607024a4d1000a0006500fc1226f606024a4d1000a0006500dc12265607024a4d1000a0086500bc12265607024a4d1000a00865009c12265607024a4d1000a00865007c12265607024a4d1000a0086500fa13265607024a4d1000a0006500da43665363034a4d1000a0086500ba43665363034a4d1000a00065009a53468333064a4d10008000650016421616038245fc36c6822cff014a4d100080006500a032166707028c6e88690101000408052c30c0c00054e03f4a4d10008000650411c026c60602385900c78080010a08fe034a4d1000800065004632166707822c1b5e930001000498042c30c0c00054e03f4a4d1000800065007a8337130382a07c2a5786e03f4a4d1008800065000ec326c60602915c92ea8280010a07e23f4a4d100880046500b23237470612e9b107ed80104b83c140fc3776ece0f80f4a4d1000a00065180010365603024a4d00006a664a4d00006b6600');
|
Diablo 2 D2S Save File Checksum Calculator
|
||||||
|
By Hash Borgir (https://www.psychedelicsdaily.com)
|
||||||
|
@date 6/4/2022
|
||||||
|
|
||||||
require_once './src/D2Functions.php';
|
Checksum field is at byte 12.
|
||||||
require_once './src/D2BitReader.php';
|
Bytes 12/13/14/15 as a uint32.
|
||||||
|
Set this to 0.
|
||||||
class D2ByteReader {
|
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.
|
||||||
|
*/
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
public function setBit(int $byte, int $pos, bool $bit) {
|
|
||||||
return ($bit ? ($byte | (1 << $pos)) : ($byte & ~(1 << $pos)) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@return Bit at Nth position in Byte
|
|
||||||
*/
|
|
||||||
|
|
||||||
public function getBit(int $byte, int $pos): int {
|
|
||||||
return intval(($byte & (1 << $pos)) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
function swapEndianness(string $hex) {
|
||||||
|
return implode('', array_reverse(str_split($hex, 2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
$filename = "D:\Diablo II\MODS\ironman-dev\save\Barb.d2s";
|
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
|
||||||
|
|
||||||
$fileData = unpack('C*', file_get_contents($filename)); // open file and unpack
|
$fileData = unpack('C*', file_get_contents($filename)); // open file and unpack
|
||||||
|
|
||||||
|
|
||||||
var_dump(checksum($fileData));
|
var_dump(checksum($fileData));
|
||||||
|
|
||||||
|
fseek($fp, 12); // go to byte 12
|
||||||
|
fwrite($fp, pack('H8', checksum($fileData))); // write new checksum
|
||||||
|
fclose($fp);
|
||||||
//$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
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user