mirror of
https://gitlab.com/hashborgir/d2tools.git
synced 2024-11-30 04:26:03 +00:00
D2S Editing WIP
This commit is contained in:
parent
3357f757ea
commit
b9f4054028
34
res/app.js
34
res/app.js
@ -322,5 +322,37 @@ $(document).ready(function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Chars.php Character Editor AJAXIFY
|
||||||
|
// Prevent default form submit
|
||||||
|
$('form').submit(function (event) {
|
||||||
|
event.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$(".wpcheck").change(function () {
|
||||||
|
// Toggle the value between 0 and 1
|
||||||
|
var value = $(this).is(":checked") ? 1 : 0;
|
||||||
|
|
||||||
|
// Get the name of the checkbox
|
||||||
|
var name = $(this).attr("name");
|
||||||
|
|
||||||
|
// Get the name of the difficulty
|
||||||
|
var diff = $(this).attr("diff");
|
||||||
|
|
||||||
|
// Get the value of the input named "filePath"
|
||||||
|
var filePath = $("input[name='filePath']").val();
|
||||||
|
|
||||||
|
// Construct the URL for the GET request
|
||||||
|
var url = "/saveCharacter.php?cmd=wp&name=" + name + "&value=" + value + "&filePath=" + filePath + "&diff=" + diff;
|
||||||
|
|
||||||
|
|
||||||
|
// Send the GET request
|
||||||
|
$.get(url, function (response) {
|
||||||
|
// Handle the response if needed
|
||||||
|
console.log(response);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});// end document.ready
|
@ -1,17 +1,33 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// Set error reporting to only show errors and parse errors
|
||||||
error_reporting(E_ERROR | E_PARSE);
|
error_reporting(E_ERROR | E_PARSE);
|
||||||
|
|
||||||
|
// Set the time limit for script execution to unlimited
|
||||||
set_time_limit(-1);
|
set_time_limit(-1);
|
||||||
|
|
||||||
|
// Set the maximum input time to unlimited
|
||||||
ini_set('max_input_time', '-1');
|
ini_set('max_input_time', '-1');
|
||||||
|
|
||||||
|
// Set the maximum execution time to unlimited
|
||||||
ini_set('max_execution_time', '0');
|
ini_set('max_execution_time', '0');
|
||||||
|
|
||||||
|
// Start the session
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
|
// Start output buffering
|
||||||
ob_start();
|
ob_start();
|
||||||
|
|
||||||
|
// Define the constant 'DB_FILE' with the value of 'modname' session variable followed by ".db"
|
||||||
define('DB_FILE', $_SESSION['modname'] . ".db");
|
define('DB_FILE', $_SESSION['modname'] . ".db");
|
||||||
|
|
||||||
|
// Include the configuration file
|
||||||
require_once './config.php';
|
require_once './config.php';
|
||||||
|
|
||||||
|
// Include the PDO wrapper file
|
||||||
require_once './_pdo.php';
|
require_once './_pdo.php';
|
||||||
|
|
||||||
|
// Include the required class files
|
||||||
require_once "./src/D2Functions.php";
|
require_once "./src/D2Functions.php";
|
||||||
require_once "./src/D2Database.php";
|
require_once "./src/D2Database.php";
|
||||||
require_once './src/D2Files.php';
|
require_once './src/D2Files.php';
|
||||||
@ -19,120 +35,166 @@ require_once './src/D2TxtParser.php';
|
|||||||
require_once './src/D2ItemDesc.php';
|
require_once './src/D2ItemDesc.php';
|
||||||
require_once './src/D2Char.php';
|
require_once './src/D2Char.php';
|
||||||
require_once './src/D2CharStructureData.php';
|
require_once './src/D2CharStructureData.php';
|
||||||
|
require_once './src/D2ByteReader.php';
|
||||||
|
|
||||||
$dStruct = new D2CharStructureData();
|
// Create an instance of D2CharStructureData class
|
||||||
|
$csData = new D2CharStructureData();
|
||||||
|
|
||||||
|
$g = $_GET;
|
||||||
|
$cmd = $g['cmd'];
|
||||||
|
|
||||||
|
// Get the file path from the POST data and replace backslashes /
|
||||||
|
$filePath = $g['filePath'];
|
||||||
|
$filePath = str_replace("\\", "\\\\", $filePath);
|
||||||
|
|
||||||
|
// Handle the WP check/uncheck
|
||||||
|
if ($cmd == "wp") {
|
||||||
|
$diff = $g['diff'];
|
||||||
|
|
||||||
|
if ($diff == "Norm") {
|
||||||
|
$offset = 643;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($diff == "NM") {
|
||||||
|
$offset = 667;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($diff == "Hell") {
|
||||||
|
$offset = 691;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
array (size=5)
|
||||||
|
'cmd' => string 'wp' (length=2)
|
||||||
|
'name' => string '1' (length=1)
|
||||||
|
'value' => string '1' (length=1)
|
||||||
|
'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48)
|
||||||
|
'diff' => string 'Norm' (length=4)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
$p = $_POST;
|
|
||||||
|
|
||||||
// ddump($p);
|
$fileContents = file_get_contents($filePath); // Read the contents of the file
|
||||||
|
$ByteReader = new D2ByteReader($fileContents); // Create a new instance of D2ByteReader with the file data
|
||||||
|
$fileData = $ByteReader->getData(); // Get the data from the ByteReader instance
|
||||||
|
|
||||||
|
$wpBytes = $ByteReader->read($offset, 5, 1);
|
||||||
|
$wpBytesToBits = $ByteReader->toBits($wpBytes);
|
||||||
|
|
||||||
|
$BitReader = new D2BitReader($wpBytesToBits);
|
||||||
|
|
||||||
|
$BitReader->setBit($g['name'], $g['value']);
|
||||||
|
|
||||||
|
$newBits = $BitReader->getBits();
|
||||||
|
|
||||||
|
$newBitsToBytes = $ByteReader->bitsToHexString($newBits);
|
||||||
|
|
||||||
|
$ByteReader->writeBytes($offset, $newBitsToBytes);
|
||||||
|
|
||||||
|
$newFileData = $ByteReader->getData();
|
||||||
|
$fileSaved = file_put_contents($filePath, $newFileData);
|
||||||
|
$checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
|
||||||
|
|
||||||
|
if ($fileSaved) {
|
||||||
|
echo "Success";
|
||||||
|
} else {
|
||||||
|
echo "Fail";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
die();
|
||||||
|
|
||||||
|
// Get the POST data
|
||||||
|
$p = $_GET;
|
||||||
|
|
||||||
|
// Loop through each 'quest' element in the POST data and assign the corresponding value from 'dStruct->_qNorm' to 'q'
|
||||||
foreach ($p['quest'] as $k => $v) {
|
foreach ($p['quest'] as $k => $v) {
|
||||||
$q[$k] = ($dStruct->_qNorm[$k]);
|
$q[$k] = $dStruct->_qNorm[$k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$wpNames_flipped = array_values($dStruct->wpNames_flipped);
|
||||||
|
|
||||||
|
// Loop through each 'wp' element in the POST data and assign the corresponding value from 'dStruct->_qNorm' to 'w'
|
||||||
foreach ($p['wp'] as $k => $v) {
|
foreach ($p['wp'] as $k => $v) {
|
||||||
$w[$k] = ($dStruct->_qNorm[$k]);
|
$w[$k] = $dStruct->_qNorm[$k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the file path from the POST data and replace backslashes /
|
||||||
$filePath = $p['filePath'];
|
$filePath = $p['filePath'];
|
||||||
$filePath = str_replace("\\", "\\\\", $filePath);
|
$filePath = str_replace("\\", "\\\\", $filePath);
|
||||||
|
|
||||||
|
// Open the file in binary mode for both reading and writing
|
||||||
$fp = fopen($filePath, "rb+");
|
$fp = fopen($filePath, "rb+");
|
||||||
|
|
||||||
// delete old checksum at offset 0x0C - byte 12
|
// Edit quests which are checked to set them as 'Just finished' (FE FF)
|
||||||
//fseek($fp, 12);
|
|
||||||
// (I) unsigned integer (machine dependent size and byte order)
|
|
||||||
//fwrite($fp, pack('I', 0)); // produces 4 bytes
|
|
||||||
|
|
||||||
// edit quests which are checked, to Just finished FE FF
|
|
||||||
foreach ($q as $k => $v) {
|
foreach ($q as $k => $v) {
|
||||||
|
// Set the file pointer position to the quest offset
|
||||||
fseek($fp, $v);
|
fseek($fp, $v);
|
||||||
|
|
||||||
|
// Write the byte value 0xFE at the current position
|
||||||
fwrite($fp, pack('C', 0xFE));
|
fwrite($fp, pack('C', 0xFE));
|
||||||
|
|
||||||
|
// Move the file pointer to the next position
|
||||||
fseek($fp, $v + 1);
|
fseek($fp, $v + 1);
|
||||||
|
|
||||||
|
// Write the byte value 0xFF at the current position
|
||||||
fwrite($fp, pack('C', 0xFF));
|
fwrite($fp, pack('C', 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($p['wp_all'] == "1") {
|
|
||||||
fseek($fp, 643);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 644);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 645);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 646);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 647);
|
|
||||||
fwrite($fp, pack('C', 0x7F));
|
|
||||||
|
|
||||||
fseek($fp, 667);
|
// Array containing the fseek wp offsets
|
||||||
fwrite($fp, pack('C', 0xFF));
|
// 5 acts per difficulty
|
||||||
fseek($fp, 668);
|
// starts at 641, but we skip two bytes, go to 643, then read next 5 bytes, each byte is a bitfield per act.
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 669);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 670);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 671);
|
|
||||||
fwrite($fp, pack('C', 0x7F));
|
|
||||||
|
|
||||||
fseek($fp, 691);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 692);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 693);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 694);
|
|
||||||
fwrite($fp, pack('C', 0xFF));
|
|
||||||
fseek($fp, 695);
|
|
||||||
fwrite($fp, pack('C', 0x7F));
|
|
||||||
|
|
||||||
}
|
|
||||||
else if ($p['wp_all'] == "0")
|
|
||||||
{
|
|
||||||
fseek($fp, 643);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 644);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 645);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 646);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 647);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
|
|
||||||
fseek($fp, 667);
|
$offsets = [
|
||||||
fwrite($fp, pack('C', 0x00));
|
643, 644, 645, 646, 647, // First set of offsets Norm
|
||||||
fseek($fp, 668);
|
667, 668, 669, 670, 671, // Second set of offsets NM
|
||||||
fwrite($fp, pack('C', 0x00));
|
691, 692, 693, 694, 695 // Third set of offsets Hell
|
||||||
fseek($fp, 669);
|
];
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 670);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 671);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
|
|
||||||
fseek($fp, 691);
|
// Determine the value to write based on the condition $p['wp_all'] == "1"
|
||||||
fwrite($fp, pack('C', 0x00));
|
$valueToWrite = ($p['wp_all'] == "1") ? 0xFF : 0x00;
|
||||||
fseek($fp, 692);
|
|
||||||
fwrite($fp, pack('C', 0x00));
|
// Loop over each offset in the $offsets array
|
||||||
fseek($fp, 693);
|
foreach ($offsets as $offset) {
|
||||||
fwrite($fp, pack('C', 0x00));
|
// Set the file pointer position to the current offset
|
||||||
fseek($fp, 694);
|
fseek($fp, $offset);
|
||||||
fwrite($fp, pack('C', 0x00));
|
|
||||||
fseek($fp, 695);
|
// Write the value specified by pack('C', $valueToWrite)
|
||||||
fwrite($fp, pack('C', 0x00));
|
fwrite($fp, pack('C', $valueToWrite));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
|
$checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
|
||||||
|
|
||||||
// write NEW checksum at offset 0x0C - byte 12
|
|
||||||
//fseek($fp, 12);
|
|
||||||
// (I) unsigned integer (machine dependent size and byte order)
|
|
||||||
//fwrite($fp, pack('H*', $checksum)); // produces 4 bytes
|
|
||||||
|
|
||||||
|
|
||||||
fclose($fp);
|
fclose($fp);
|
||||||
|
|
||||||
header('Location: /');
|
header('Location: /');
|
314
src/D2Char.php
314
src/D2Char.php
@ -14,47 +14,60 @@ require_once 'D2Functions.php';
|
|||||||
class D2Char {
|
class D2Char {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var null
|
* @var null|string char data output
|
||||||
*/
|
*/
|
||||||
public $cData = null; // char data output
|
public $cData = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var null
|
* @var null|string char item data
|
||||||
*/
|
*/
|
||||||
public $items = null; // char item data
|
public $items = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var D2ByteReader|null
|
* @var D2ByteReader|null put $data into bytereader
|
||||||
*/
|
*/
|
||||||
public $ByteReader = null; // put $data into bytereader
|
public $ByteReader = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null
|
* @var null|string .d2s file path
|
||||||
*/
|
*/
|
||||||
public $filePath = null; // .d2s file path
|
public $filePath = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var D2CharStructureData
|
* @var D2CharStructureData char file structure data
|
||||||
*/
|
*/
|
||||||
private $sData = null; // char file structure data
|
private $sData = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var null
|
* @var null|string char binary data from d2s
|
||||||
*/
|
*/
|
||||||
private $bData = null; // char binary data from d2s
|
private $bData = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var false|resource
|
* @var false|resource file pointer
|
||||||
*/
|
*/
|
||||||
private $fp = null; // file pointer
|
private $fp = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var false|string
|
* @var false|string full d2s file loaded in $data
|
||||||
*/
|
*/
|
||||||
private $data = null; // full d2s file loaded in $data
|
private $data = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var null
|
* @var null
|
||||||
*/
|
*/
|
||||||
private $ISC = null;
|
private $ISC = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var null
|
* @var null
|
||||||
*/
|
*/
|
||||||
private $skillData = null;
|
private $skillData = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Saves the data to a file.
|
||||||
|
*
|
||||||
|
* This method updates the data with a new checksum and saves it to the specified file path.
|
||||||
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function save() {
|
public function save() {
|
||||||
@ -70,65 +83,70 @@ class D2Char {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $file
|
* Initializes the class instance with the given file.
|
||||||
|
*
|
||||||
|
* @param string $file The file to be processed.
|
||||||
*/
|
*/
|
||||||
public function __construct($file) {
|
public function __construct($file) {
|
||||||
$this->sData = new D2CharStructureData();
|
$this->sData = new D2CharStructureData(); // Create a new instance of D2CharStructureData
|
||||||
$this->filePath = $_SESSION['savepath'] . $file;
|
$this->filePath = $_SESSION['savepath'] . $file; // Set the file path based on the session save path and the provided file
|
||||||
$this->fp = fopen($this->filePath, "r+b");
|
$this->fp = fopen($this->filePath, "r+b"); // Open the file in read/write binary mode
|
||||||
$data = file_get_contents($this->filePath);
|
$data = file_get_contents($this->filePath); // Read the contents of the file
|
||||||
$this->ByteReader = new D2ByteReader($data);
|
$this->ByteReader = new D2ByteReader($data); // Create a new instance of D2ByteReader with the file data
|
||||||
$this->data = $this->ByteReader->getData();
|
$this->data = $this->ByteReader->getData(); // Get the data from the ByteReader instance
|
||||||
|
// Fetch itemstatcost data from the database and store it in $this->ISC
|
||||||
$sql = "SELECT ID,Stat,CSvBits,ValShift FROM itemstatcost WHERE Saved=1";
|
$sql = "SELECT ID,Stat,CSvBits,ValShift FROM itemstatcost WHERE Saved=1";
|
||||||
$ISCData = PDO_FetchAll($sql);
|
$ISCData = PDO_FetchAll($sql);
|
||||||
|
|
||||||
foreach ($ISCData as $k => $v) {
|
foreach ($ISCData as $k => $v) {
|
||||||
$this->ISC[$v['ID']] = $v;
|
$this->ISC[$v['ID']] = $v;
|
||||||
$this->_ISC[$v['Stat']] = $v;
|
$this->_ISC[$v['Stat']] = $v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read offsets here from sData and put into $this->bData
|
// Read offsets from sData and store them in $this->bData
|
||||||
// which will be used for cData output
|
|
||||||
foreach ($this->sData->offsets as $k => $v) {
|
foreach ($this->sData->offsets as $k => $v) {
|
||||||
fseek($this->fp, $k);
|
fseek($this->fp, $k); // Move the file pointer to the specified offset
|
||||||
$this->bData[$k] = fread($this->fp, $v);
|
$this->bData[$k] = fread($this->fp, $v); // Read data from the file at the current offset and store it in $this->bData
|
||||||
}
|
}
|
||||||
|
|
||||||
$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))]; // Determine the character class based on the byte read from the file
|
||||||
$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'";
|
||||||
$sd = PDO_FetchAll($sql);
|
$sd = PDO_FetchAll($sql); // Fetch skill data from the database
|
||||||
foreach ($sd as $k => $v) {
|
foreach ($sd as $k => $v) {
|
||||||
$this->skillData[$k + 1] = $v;
|
$this->skillData[$k + 1] = $v;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->parseChar(); // end of parseChar() calls parseItems(), parseStats, etc.
|
return $this->parseChar(); // Call the parseChar() method and return its result
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Parses the items in the data.
|
||||||
|
*
|
||||||
|
* This method extracts and processes the item data from the provided data.
|
||||||
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function parseItems() {
|
public function parseItems() {
|
||||||
$i_TotalOffset = strpos($this->data, "JM");
|
$i_TotalOffset = strpos($this->data, "JM"); // Find the offset of the "JM" marker in the data
|
||||||
fseek($this->fp, $i_TotalOffset + 2);
|
fseek($this->fp, $i_TotalOffset + 2); // Move the file pointer to the next position after the "JM" marker
|
||||||
$i_Total = unpack('S*', (fread($this->fp, 2)))[1];
|
$i_Total = unpack('S*', (fread($this->fp, 2)))[1]; // Read 2 bytes from the file and unpack them as an unsigned short (16-bit) value
|
||||||
|
|
||||||
$i_Offsets = [];
|
$i_Offsets = [];
|
||||||
for ($i = 0; $i <= $i_Total; $i++) {
|
for ($i = 0; $i <= $i_Total; $i++) {
|
||||||
$i_Offsets[] = strposX($this->data, "JM", $i + 2);
|
$i_Offsets[] = strposX($this->data, "JM", $i + 2); // Find the offsets of the "JM" markers for each item
|
||||||
}
|
}
|
||||||
foreach ($i_Offsets as $k => $v) {
|
foreach ($i_Offsets as $k => $v) {
|
||||||
$itemOffsets[$v] = $i_Offsets[$k + 1] - $i_Offsets[$k];
|
$itemOffsets[$v] = $i_Offsets[$k + 1] - $i_Offsets[$k]; // Calculate the length of each item's data by subtracting consecutive offsets
|
||||||
}
|
}
|
||||||
array_pop($itemOffsets);
|
array_pop($itemOffsets); // Remove the last element from the itemOffsets array
|
||||||
|
|
||||||
$_items = [];
|
$_items = [];
|
||||||
foreach ($itemOffsets as $offset => $bytes) {
|
foreach ($itemOffsets as $offset => $bytes) {
|
||||||
$this->items[] = new D2Item($this->ByteReader->toBits($this->ByteReader->readh($offset, $bytes)));
|
$this->items[] = new D2Item($this->ByteReader->toBits($this->ByteReader->readh($offset, $bytes))); // Create a new D2Item object and add it to the items array
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +184,6 @@ WHERE sk.charclass = '$class'";
|
|||||||
$cData['CharacterProgression'] = $this->sData->characterProgressionClassicHC[$progression];
|
$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('L', $this->bData[48])[0]);
|
$cData['Lastplayed'] = gmdate("Y-m-d\TH:i:s\Z", unpack('L', $this->bData[48])[0]);
|
||||||
@ -228,10 +245,12 @@ WHERE sk.charclass = '$class'";
|
|||||||
* @return array
|
* @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);
|
||||||
$skills = ($this->ByteReader->readc($if, ($jm - $if)));
|
$skills = ($this->ByteReader->readc($if, ($jm - $if)));
|
||||||
|
|
||||||
|
$cData = []; // Initialize the result array
|
||||||
|
|
||||||
foreach ($skills as $k => $v) {
|
foreach ($skills as $k => $v) {
|
||||||
if ($this->skillData[$k]['String']) {
|
if ($this->skillData[$k]['String']) {
|
||||||
$cData['skills'][$k] = [
|
$cData['skills'][$k] = [
|
||||||
@ -244,83 +263,108 @@ WHERE sk.charclass = '$class'";
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$cData['skills'] = array_values($cData['skills']);
|
|
||||||
|
$cData['skills'] = array_values($cData['skills']); // Reset the array keys
|
||||||
|
|
||||||
return $cData;
|
return $cData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $points
|
* Set all skills to a given number of points.
|
||||||
|
*
|
||||||
|
* @param int $points The number of points to set for all skills.
|
||||||
* @return void
|
* @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);
|
||||||
$len = $jm - $if;
|
$len = $jm - $if;
|
||||||
|
|
||||||
for ($i = 0; $i < $len; $i++) {
|
for ($i = 0; $i < $len; $i++) {
|
||||||
$this->ByteReader->writeByte($if + $i, $points);
|
$this->ByteReader->writeByte($if + $i, $points); // Set the skill points to the given value
|
||||||
}
|
}
|
||||||
$this->data = $this->ByteReader->getData();
|
|
||||||
$this->save();
|
$this->data = $this->ByteReader->getData(); // Update the character data
|
||||||
|
$this->save(); // Save the changes to the character file
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $skill
|
* Set the points for a specific skill.
|
||||||
* @param int $points
|
*
|
||||||
|
* @param int $skill The skill ID.
|
||||||
|
* @param int $points The number of points to set for the skill.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setSkill(int $skill, int $points) {
|
public function setSkill(int $skill, int $points) {
|
||||||
$skill -= 1;
|
$skill -= 1; // Adjust the skill ID to match the array index
|
||||||
$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);
|
||||||
// set $kill to $points
|
|
||||||
|
// Set the points for the specified skill
|
||||||
$this->ByteReader->writeByte($if + $skill, $points);
|
$this->ByteReader->writeByte($if + $skill, $points);
|
||||||
$this->data = $this->ByteReader->getData();
|
|
||||||
$this->save();
|
$this->data = $this->ByteReader->getData(); // Update the character data
|
||||||
|
$this->save(); // Save the changes to the character file
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Parse the character stats.
|
||||||
|
*
|
||||||
* @return void
|
* @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);
|
||||||
$len = $if - $gf;
|
$len = $if - $gf;
|
||||||
$stats = new D2BitReader($this->ByteReader->toBits($this->ByteReader->readh($gf, $len)));
|
$stats = new D2BitReader($this->ByteReader->toBits($this->ByteReader->readh($gf, $len)));
|
||||||
|
|
||||||
$bits = $stats->getBits();
|
$bits = $stats->getBits();
|
||||||
|
|
||||||
$bytes = $this->ByteReader->toBytes($bits);
|
$bytes = $this->ByteReader->toBytes($bits);
|
||||||
|
|
||||||
$stats->rewind();
|
$stats->rewind();
|
||||||
|
|
||||||
|
$ids = []; // Array to store the encountered stat IDs
|
||||||
|
// Iterate over the stats and collect their IDs
|
||||||
for ($i = 0; $i <= count($this->ISC); $i++) {
|
for ($i = 0; $i <= count($this->ISC); $i++) {
|
||||||
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
$id = hexdec($this->ByteReader->toBytesR($stats->readb(9)));
|
||||||
|
|
||||||
|
// Skip the bits corresponding to the stat if needed
|
||||||
if ($this->ISC[$id]['CSvBits'] !== NULL && $this->ISC[$id]['CSvBits'] !== '') {
|
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; // Store the ID in the array
|
||||||
}
|
}
|
||||||
|
|
||||||
$stats->rewind();
|
$stats->rewind();
|
||||||
|
|
||||||
|
$values = []; // Array to store the parsed stat values
|
||||||
|
// Iterate over the collected stat IDs and retrieve their values
|
||||||
foreach ($ids as $id) {
|
foreach ($ids as $id) {
|
||||||
$stats->skip(9);
|
$stats->skip(9);
|
||||||
|
|
||||||
|
// Skip the bits corresponding to the stat if needed
|
||||||
if ($this->ISC[$id]['CSvBits'] !== NULL && $this->ISC[$id]['CSvBits'] !== '') {
|
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'];
|
$stat = $this->ISC[$id]['Stat'];
|
||||||
$values[$stat] = hexdec($this->ByteReader->toBytesR($val));
|
$values[$stat] = hexdec($this->ByteReader->toBytesR($val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform additional calculations or conversions on specific stats
|
||||||
$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);
|
||||||
$values['mana'] = (int) round($values['mana'] >> 11);
|
$values['mana'] = (int) round($values['mana'] >> 11);
|
||||||
$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['soulcounter'] = (int) round($values['soulcounter'] / 2);
|
|
||||||
// $values['killcounter'] = (int) round($values['killcounter'] / 2);
|
|
||||||
|
|
||||||
$this->cData['stats'] = $values;
|
$this->cData['stats'] = $values; // Assign the parsed stats to the character data
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Set character attributes.
|
||||||
|
*
|
||||||
* @param string $stat
|
* @param string $stat
|
||||||
* @param mixed $val
|
* @param mixed $val
|
||||||
* @param mixed|null $val2
|
* @param mixed|null $val2
|
||||||
@ -349,61 +393,54 @@ WHERE sk.charclass = '$class'";
|
|||||||
];
|
];
|
||||||
$this->ByteReader->writeByte(40, $classes[$val]);
|
$this->ByteReader->writeByte(40, $classes[$val]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "CharacterLevel":
|
case "CharacterLevel":
|
||||||
if ($val > 99) {
|
if ($val > 99) {
|
||||||
$val = 99;
|
$val = 99;
|
||||||
}
|
}
|
||||||
// level is edited in two places.
|
|
||||||
// byte 43
|
|
||||||
$this->ByteReader->writeByte(43, $val);
|
$this->ByteReader->writeByte(43, $val);
|
||||||
// and in charstats
|
|
||||||
$this->setStat('level', $val);
|
$this->setStat('level', $val);
|
||||||
|
|
||||||
// now we have to set the experience stat for this level
|
|
||||||
// it's 1 level below as it starts from 0, for next level
|
|
||||||
// $val -= 1;
|
|
||||||
$sql = "SELECT {$this->cData['CharacterClass']} FROM experience WHERE level = '$val'";
|
$sql = "SELECT {$this->cData['CharacterClass']} FROM experience WHERE level = '$val'";
|
||||||
$res = PDO_FetchOne($sql);
|
$res = PDO_FetchOne($sql);
|
||||||
$this->setStat('experience', $res);
|
$this->setStat('experience', $res);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'CharacterStatus':
|
case 'CharacterStatus':
|
||||||
|
$status = strrev(strtobits($this->data[36]));
|
||||||
|
|
||||||
switch ($val) {
|
switch ($val) {
|
||||||
case 'Died':
|
case 'Died':
|
||||||
$status = (strtobits($this->data[36]));
|
|
||||||
$status[3] = $val2;
|
$status[3] = $val2;
|
||||||
$byte = $this->ByteReader->bitsToHexString($status);
|
|
||||||
$this->ByteReader->writeByte(36, hexdec($byte));
|
|
||||||
break;
|
break;
|
||||||
case 'Hardcore':
|
case 'Hardcore':
|
||||||
$status = (strtobits($this->data[36]));
|
|
||||||
$status[2] = $val2;
|
$status[2] = $val2;
|
||||||
$byte = $this->ByteReader->bitsToHexString($status);
|
|
||||||
$this->ByteReader->writeByte(36, hexdec($byte));
|
|
||||||
break;
|
break;
|
||||||
case 'Expansion':
|
case 'Expansion':
|
||||||
$status = strrev(strtobits($this->data[36]));
|
|
||||||
$status[5] = $val2;
|
$status[5] = $val2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
$byte = $this->ByteReader->bitsToHexString($status);
|
$byte = $this->ByteReader->bitsToHexString($status);
|
||||||
$this->ByteReader->writeByte(36, hexdec($byte));
|
$this->ByteReader->writeByte(36, hexdec($byte));
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
break;
|
case 'CharacterProgression':
|
||||||
case 'CharacterProgression': // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell
|
|
||||||
switch ($val) {
|
switch ($val) {
|
||||||
case 0: // in normal
|
case 0:
|
||||||
$this->data[37] = pack('C', 3);
|
$this->data[37] = pack('C', 3);
|
||||||
break;
|
break;
|
||||||
case 1: // finished normal
|
case 1:
|
||||||
$this->data[37] = pack('C', 8);
|
$this->data[37] = pack('C', 8);
|
||||||
break;
|
break;
|
||||||
case 2: // finished nm
|
case 2:
|
||||||
$this->data[37] = pack('C', 13);
|
$this->data[37] = pack('C', 13);
|
||||||
break;
|
break;
|
||||||
case 3: // finished hell
|
case 3:
|
||||||
$this->data[37] = pack('C', 15);
|
$this->data[37] = pack('C', 15);
|
||||||
break;
|
break;
|
||||||
$this->save();
|
|
||||||
}
|
}
|
||||||
|
$this->save();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'LeftmousebuttonskillID':
|
case 'LeftmousebuttonskillID':
|
||||||
@ -423,12 +460,13 @@ WHERE sk.charclass = '$class'";
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally save char data to d2s file
|
|
||||||
$this->data = $this->ByteReader->getData();
|
$this->data = $this->ByteReader->getData();
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Reset the file size of the D2S file.
|
||||||
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function resetFileSize() {
|
public function resetFileSize() {
|
||||||
@ -436,8 +474,8 @@ WHERE sk.charclass = '$class'";
|
|||||||
$this->fp = fopen($this->filePath, "r+b");
|
$this->fp = fopen($this->filePath, "r+b");
|
||||||
fseek($this->fp, 8);
|
fseek($this->fp, 8);
|
||||||
fwrite($this->fp, pack('L', $filesize));
|
fwrite($this->fp, pack('L', $filesize));
|
||||||
|
|
||||||
fclose($this->fp);
|
fclose($this->fp);
|
||||||
|
|
||||||
$this->fp = fopen($this->filePath, "r+b");
|
$this->fp = fopen($this->filePath, "r+b");
|
||||||
checksumFix($this->filePath);
|
checksumFix($this->filePath);
|
||||||
|
|
||||||
@ -446,54 +484,51 @@ WHERE sk.charclass = '$class'";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return false|string
|
* Generate all stats and update the D2S file.
|
||||||
|
*
|
||||||
|
* @return false|string The updated data of the D2S file.
|
||||||
*/
|
*/
|
||||||
public function generateAllStats() {
|
public function generateAllStats() {
|
||||||
// 003C08E081000F067860C001071C0008020800F040020064A000000A2C00C0030C000D000000006E05000000FE3F
|
|
||||||
$stats = '';
|
$stats = '';
|
||||||
for ($i = 0; $i < 16; $i++) {
|
for ($i = 0; $i < 16; $i++) {
|
||||||
$id = strrev(str_pad((decbin((int) $this->ISC[$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) $this->ISC[$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";
|
$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;
|
||||||
|
|
||||||
$bytes = $this->ByteReader->toBytes($stats);
|
$bytes = $this->ByteReader->toBytes($stats);
|
||||||
|
|
||||||
// refresh this data
|
// Refresh the data
|
||||||
$data = $this->ByteReader->getData();
|
$data = $this->ByteReader->getData();
|
||||||
// delete everything between GF---and---IF
|
// Delete everything between GF and IF
|
||||||
$data = substr_replace($data, "", $gf, $len);
|
$data = substr_replace($data, '', $gf, $len);
|
||||||
// pack hex bites into binary string
|
// Pack hex bytes into a binary string
|
||||||
$packedbytes = (pack('H*', $bytes));
|
$packedBytes = pack('H*', $bytes);
|
||||||
// now insert new packed byte stat data between gf and if
|
// Insert the new packed byte stat data between GF and IF
|
||||||
$data = substr_replace($data, $packedbytes, 767, 0);
|
$data = substr_replace($data, $packedBytes, 767, 0);
|
||||||
|
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
$this->save();
|
$this->save();
|
||||||
|
|
||||||
$this->resetFileSize();
|
$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;
|
return $this->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $stat
|
* Set a specific stat in the D2S file.
|
||||||
* @param mixed $val
|
*
|
||||||
|
* @param string $stat The stat to set.
|
||||||
|
* @param mixed $val The value to set for the stat.
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function setStat(string $stat, mixed $val) {
|
public function setStat(string $stat, mixed $val) {
|
||||||
@ -549,44 +584,59 @@ WHERE sk.charclass = '$class'";
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $file
|
* Get the quest data from the specified file.
|
||||||
* @return array
|
*
|
||||||
|
* @param string $file The file to read the quest data from.
|
||||||
|
* @return array The quest data.
|
||||||
*/
|
*/
|
||||||
public function getQuestData($file) {
|
public function getQuestData($file) {
|
||||||
$questsNorm = null;
|
$questsNorm = null;
|
||||||
$questsNM = null;
|
$questsNM = null;
|
||||||
$questsHell = null;
|
$questsHell = null;
|
||||||
$quests = null;
|
$quests = null;
|
||||||
|
|
||||||
|
// Read quests from qNorm
|
||||||
foreach ($this->sData->qNorm as $k => $v) {
|
foreach ($this->sData->qNorm as $k => $v) {
|
||||||
fseek($this->fp, $k);
|
fseek($this->fp, $k);
|
||||||
$questsNorm[$k] = fread($this->fp, 2);
|
$questsNorm[$k] = fread($this->fp, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read quests from qNM
|
||||||
foreach ($this->sData->qNM as $k => $v) {
|
foreach ($this->sData->qNM as $k => $v) {
|
||||||
fseek($this->fp, $k);
|
fseek($this->fp, $k);
|
||||||
$questsNM[$k] = fread($this->fp, 2);
|
$questsNM[$k] = fread($this->fp, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read quests from qHell
|
||||||
foreach ($this->sData->qHell as $k => $v) {
|
foreach ($this->sData->qHell as $k => $v) {
|
||||||
fseek($this->fp, $k);
|
fseek($this->fp, $k);
|
||||||
$questsHell[$k] = fread($this->fp, 2);
|
$questsHell[$k] = fread($this->fp, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process quests from qNorm
|
||||||
foreach ($questsNorm as $k => $v) {
|
foreach ($questsNorm as $k => $v) {
|
||||||
$x = (str_split(strtobits($v), 8));
|
$x = (str_split(strtobits($v), 8));
|
||||||
// if ($x[0][0]) {
|
// if ($x[0][0]) {
|
||||||
$quests['Norm'][$this->sData->qNorm[$k]] = $x[0][0];
|
$quests['Norm'][$this->sData->qNorm[$k]] = $x[0][0];
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process quests from qNM
|
||||||
foreach ($questsNM as $k => $v) {
|
foreach ($questsNM as $k => $v) {
|
||||||
$x = array_filter(str_split(strtobits($v), 8));
|
$x = array_filter(str_split(strtobits($v), 8));
|
||||||
// if ($x[0][0]) {
|
// if ($x[0][0]) {
|
||||||
$quests['NM'][$this->sData->qNM[$k]] = $x[0][0];
|
$quests['NM'][$this->sData->qNM[$k]] = $x[0][0];
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process quests from qHell
|
||||||
foreach ($questsHell as $k => $v) {
|
foreach ($questsHell as $k => $v) {
|
||||||
$x = array_filter(str_split(strtobits($v), 8));
|
$x = array_filter(str_split(strtobits($v), 8));
|
||||||
// if ($x[0][0]) {
|
// if ($x[0][0]) {
|
||||||
$quests['Hell'][$this->sData->qHell[$k]] = $x[0][0];
|
$quests['Hell'][$this->sData->qHell[$k]] = $x[0][0];
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
return $quests;
|
return $quests;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,44 +645,26 @@ WHERE sk.charclass = '$class'";
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getWaypointsData($file) {
|
public function getWaypointsData($file) {
|
||||||
$wp = null;
|
$wp = [];
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNorm);
|
$offsets = [
|
||||||
$a1 = strrev(strtobits(fread($this->fp, 1)));
|
'Norm' => $this->sData->wpOffsetsNorm,
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNorm + 1);
|
'NM' => $this->sData->wpOffsetsNM,
|
||||||
$a2 = strrev(strtobits(fread($this->fp, 1)));
|
'Hell' => $this->sData->wpOffsetsHell,
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNorm + 2);
|
];
|
||||||
$a3 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNorm + 3);
|
|
||||||
$a4 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNorm + 4);
|
|
||||||
$a5 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
$wp['Norm'] = str_split($a1 . $a2 . $a3 . $a4 . $a5);
|
|
||||||
|
|
||||||
// ddump($wp['Norm']);
|
foreach ($offsets as $difficulty => $offset) {
|
||||||
|
fseek($this->fp, $offset);
|
||||||
|
$waypointData = '';
|
||||||
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNM);
|
for ($i = 0; $i < 5; $i++) {
|
||||||
$a1 = strrev(strtobits(fread($this->fp, 1)));
|
$a = strrev(strtobits(fread($this->fp, 1)));
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNM + 1);
|
$waypointData .= $a;
|
||||||
$a2 = strrev(strtobits(fread($this->fp, 1)));
|
fseek($this->fp, $offset + $i + 1);
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNM + 2);
|
}
|
||||||
$a3 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNM + 3);
|
$wp[$difficulty] = str_split($waypointData);
|
||||||
$a4 = strrev(strtobits(fread($this->fp, 1)));
|
}
|
||||||
fseek($this->fp, $this->sData->wpOffsetsNM + 4);
|
|
||||||
$a5 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
$wp['NM'] = str_split($a1 . $a2 . $a3 . $a4 . $a5);
|
|
||||||
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsHell);
|
|
||||||
$a1 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsHell + 1);
|
|
||||||
$a2 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsHell + 2);
|
|
||||||
$a3 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsHell + 3);
|
|
||||||
$a4 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
fseek($this->fp, $this->sData->wpOffsetsHell + 4);
|
|
||||||
$a5 = strrev(strtobits(fread($this->fp, 1)));
|
|
||||||
$wp['Hell'] = str_split($a1 . $a2 . $a3 . $a4 . $a5);
|
|
||||||
|
|
||||||
foreach ($wp['Norm'] as $k => $v) {
|
foreach ($wp['Norm'] as $k => $v) {
|
||||||
// if ($v == 1) {
|
// if ($v == 1) {
|
||||||
|
@ -1,66 +1,12 @@
|
|||||||
<?php
|
|
||||||
$form = new Formr\Formr();
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
Copyright (C) 2021 Hash Borgir
|
|
||||||
|
|
||||||
This file is part of D2Modder
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with
|
|
||||||
or without modification, are permitted provided that the
|
|
||||||
following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above
|
|
||||||
copyright notice, this list of conditions and the
|
|
||||||
following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above
|
|
||||||
copyright notice, this list of conditions and the
|
|
||||||
following disclaimer in the documentation and/or other
|
|
||||||
materials provided with the distribution.
|
|
||||||
|
|
||||||
* This software must not be used for commercial purposes
|
|
||||||
* without my consent. Any sales or commercial use are prohibited
|
|
||||||
* without my express knowledge and consent.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY!
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
||||||
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
||||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
||||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
||||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
||||||
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
*/
|
|
||||||
//dump($charData);
|
|
||||||
?>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div style="text-align: center; margin-top: 20px;">
|
<div style="text-align: center; margin-top: 20px;">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<ul class="nav nav-tabs" id="CTabs" role="tablist">
|
<ul class="nav nav-tabs" id="CTabs" role="tablist">
|
||||||
|
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
foreach ($charData as $c) {
|
foreach ($charData as $c) {
|
||||||
|
|
||||||
$tabs = '';
|
$tabs = '';
|
||||||
// ddump($c);
|
// ddump($c);
|
||||||
|
|
||||||
$tabs .= <<<EOT
|
$tabs .= <<<EOT
|
||||||
|
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link btn btn-outline-danger" style="background: #ddd; border: 1px solid #888;" id="{$c->cData['CharacterName']}-tab" data-toggle="tab" href="#{$c->cData['CharacterName']}" role="tab" aria-controls="{$c->cData['CharacterName']}" aria-selected="true"><img height="64" width="" src="img/chars/{$c->cData['CharacterClass']}.gif">{$c->cData['CharacterName']}</a>
|
<a class="nav-link btn btn-outline-danger" style="background: #ddd; border: 1px solid #888;" id="{$c->cData['CharacterName']}-tab" data-toggle="tab" href="#{$c->cData['CharacterName']}" role="tab" aria-controls="{$c->cData['CharacterName']}" aria-selected="true"><img height="64" width="" src="img/chars/{$c->cData['CharacterClass']}.gif">{$c->cData['CharacterName']}</a>
|
||||||
</li>
|
</li>
|
||||||
@ -68,141 +14,88 @@ EOT;
|
|||||||
echo $tabs;
|
echo $tabs;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="tab-content" id="CTabContent">
|
<div class="tab-content" id="CTabContent">
|
||||||
<?php
|
<?php
|
||||||
foreach ($charData as $c) {
|
foreach ($charData as $c) {
|
||||||
|
|
||||||
$quests = null;
|
$quests = '';
|
||||||
foreach ($c->cData['Quests'] as $quest) {
|
foreach ($c->cData['Quests'] as $quest) {
|
||||||
foreach ($quest as $difficulty => $q) {
|
foreach ($quest as $difficulty => $q) {
|
||||||
$quests .= "<h2>$difficulty</h2>";
|
$quests .= "<h2>$difficulty</h2>";
|
||||||
|
|
||||||
foreach ($q as $k => $v) {
|
foreach ($q as $k => $v) {
|
||||||
$kD = str_replace("_", " ", $k);
|
$kD = str_replace("_", " ", $k);
|
||||||
$kD = str_replace(" NM", "", $kD);
|
$kD = str_replace([" NM", " Hell"], "", $kD);
|
||||||
$kD = str_replace(" Hell", "", $kD);
|
$checked = ($v == 1) ? 'checked' : '';
|
||||||
|
|
||||||
if ($v == 1) {
|
$quests .= "<input type='checkbox' value='1' name='quest[$k]' id='$k' $checked>";
|
||||||
$quests .= "<input type='checkbox' value='1' name='quest[$k]' id='$k' checked><label for='$k'>$kD</label><br>";
|
$quests .= "<label for='$k'>$kD</label><br>";
|
||||||
} else {
|
|
||||||
$quests .= "<input type='checkbox' value='1' name='quest[$k]' id='$k'><label for='$k'>$kD</label><br>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$wps = null;
|
$wps = '';
|
||||||
$wps .= "<input type='radio' value='1' name='wp_all' id='wp_all'><label style='font-size: 1.3em;color:green;' for='wp_all'>Enable All Waypoints</label><br><input type='radio' value='0' name='wp_all' id='wp_all_off'><label style='font-size: 1.3em; color: red;' for='wp_all_off'>Disable All Waypoints</label><hr>";
|
$wps .= "<input type='radio' value='1' name='wp_all' id='wp_all'>";
|
||||||
foreach ($c->cData['Waypoints'] as $diff => $waypoints) {
|
$wps .= "<label style='font-size: 1.3em;color:green;' for='wp_all'>Enable All Waypoints</label><br>";
|
||||||
|
$wps .= "<input type='radio' value='0' name='wp_all' id='wp_all_off'>";
|
||||||
|
$wps .= "<label style='font-size: 1.3em; color: red;' for='wp_all_off'>Disable All Waypoints</label><hr>";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($c->cData['Waypoints'] as $diff => $waypoints) { // diff is difficulty
|
||||||
$wps .= "<h2>$diff</h2>";
|
$wps .= "<h2>$diff</h2>";
|
||||||
array_pop($waypoints);
|
array_pop($waypoints);
|
||||||
|
$wp_count = 0;
|
||||||
foreach ($waypoints as $k => $v) {
|
foreach ($waypoints as $k => $v) {
|
||||||
|
|
||||||
$kD = str_replace("_", " ", $k);
|
$kD = str_replace("_", " ", $k);
|
||||||
$kD = str_replace(" NM", "", $kD);
|
$kD = str_replace([" NM", " Hell"], "", $kD);
|
||||||
$kD = str_replace(" Hell", "", $kD);
|
$checked = ($v == 1 && $k != '') ? 'checked ' : '';
|
||||||
if ($v == 1 && $k != ''){
|
|
||||||
$wps .= "<input type='checkbox' value='1' name='wp[$k]' id='$k' checked disabled><label for='$k'>$kD</label><br>";
|
$wps .= "<input diff='$diff' class='wpcheck' type='checkbox' value='1' name='$wp_count' id='$k' $checked>";
|
||||||
} else {
|
$wps .= "<label for='$k'>$kD</label><br>";
|
||||||
$wps .= "<input type='checkbox' value='1' name='wp[$k]' id='$k' disabled><label for='$k'>$kD</label><br>";
|
$wp_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$classOptions = [
|
||||||
|
'Amazon', 'Assassin', 'Barbarian', 'Druid', 'Paladin', 'Necromancer', 'Sorceress'
|
||||||
|
];
|
||||||
$option = '';
|
$option = '';
|
||||||
if ($c->cData['CharacterClass'] == 'Amazon'){
|
|
||||||
$option .= "<option value='Amazon' selected>Amazon</option>";
|
foreach ($classOptions as $class) {
|
||||||
} else {
|
$selected = ($c->cData['CharacterClass'] == $class) ? 'selected' : '';
|
||||||
$option .= "<option value='Amazon'>Amazon</option>";
|
$option .= "<option value='$class' $selected>$class</option>";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($c->cData['CharacterClass'] == 'Assassin'){
|
$difficulties = [
|
||||||
$option .= "<option value='Assassin' selected>Assassin</option>";
|
'Normal' => 'DifficultyNormal',
|
||||||
} else {
|
'NM' => 'DifficultyNM',
|
||||||
$option .= "<option value='Assassin'>Assassin</option>";
|
'Hell' => 'DifficultyHell'
|
||||||
}
|
];
|
||||||
|
|
||||||
if ($c->cData['CharacterClass'] == 'Barbarian'){
|
|
||||||
$option .= "<option value='Barbarian' selected>Barbarian</option>";
|
|
||||||
} else {
|
|
||||||
$option .= "<option value='Barbarian'>Barbarian</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($c->cData['CharacterClass'] == 'Druid'){
|
|
||||||
$option .= "<option value='Druid' selected>Druid</option>";
|
|
||||||
} else {
|
|
||||||
$option .= "<option value='Druid'>Druid</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($c->cData['CharacterClass'] == 'Paladin'){
|
|
||||||
$option .= "<option value='Paladin' selected>Paladin</option>";
|
|
||||||
} else {
|
|
||||||
$option .= "<option value='Paladin'>Paladin</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($c->cData['CharacterClass'] == 'Necromancer'){
|
|
||||||
$option .= "<option value='Necromancer' selected>Necromancer</option>";
|
|
||||||
} else {
|
|
||||||
$option .= "<option value='Necromancer'>Necromancer</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($c->cData['CharacterClass'] == 'Sorceress'){
|
|
||||||
$option .= "<option value='Sorceress' selected>Sorceress</option>";
|
|
||||||
} else {
|
|
||||||
$option .= "<option value='Sorceress'>Sorceress</option>";
|
|
||||||
}
|
|
||||||
|
|
||||||
$radio = '';
|
$radio = '';
|
||||||
if ($c->cData['Difficulty']['Norm'] == 1){
|
|
||||||
$radio .= '<input checked type="radio" id="DifficultyNormal" name="Difficulty" value="Normal">Normal<br>';
|
foreach ($difficulties as $difficulty => $id) {
|
||||||
} else {
|
$checked = ($c->cData['Difficulty'][$difficulty] == 1) ? 'checked' : '';
|
||||||
$radio .= '<input type="radio" id="DifficultyNormal" name="Difficulty" value="Normal">Normal<br>';
|
$radio .= "<input $checked type='radio' id='$id' name='Difficulty' value='$difficulty'>$difficulty<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ($c->cData['Difficulty']['NM'] == 1){
|
|
||||||
$radio .= '<input checked type="radio" id="DifficultyNM" name="Difficulty" value="NM">NM<br>';
|
|
||||||
} else {
|
|
||||||
$radio .= '<input type="radio" id="DifficultyNM" name="Difficulty" value="NM">NM<br>';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if ($c->cData['Difficulty']['Hell'] == 1){
|
|
||||||
$radio .= '<input checked type="radio" id="DifficultyHell" name="Difficulty" value="Hell">Hell<br>';
|
|
||||||
} else {
|
|
||||||
$radio .= '<input type="radio" id="DifficultyHell" name="Difficulty" value="Hell">Hell<br>';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if ($c->cData['Quests'][0]['Norm']["DenOfEvil"]) $a1q1 = "checked";
|
|
||||||
if ($c->cData['Quests'][0]['Norm']["SistersBurialGrounds"]) $a1q2 = "checked";
|
|
||||||
if ($c->cData['Quests'][0]['Norm']["TheSearchForCain"]) $a1q3 = "checked";
|
|
||||||
if ($c->cData['Quests'][0]['Norm']["TheForgottenTower"]) $a1q4 = "checked";
|
|
||||||
if ($c->cData['Quests'][0]['Norm']["ToolsOfTheTrade"]) $a1q5 = "checked";
|
|
||||||
if ($c->cData['Quests'][0]['Norm']["SistersToTheSlaughter"]) $a1q6 = "checked";
|
|
||||||
|
|
||||||
$skills = '';
|
$skills = '';
|
||||||
foreach ($c->cData['skills']['skills'] as $k => $skill) {
|
foreach ($c->cData['skills']['skills'] as $k => $skill) {
|
||||||
$skills .= "<input style='width: 64px;' class='skill-$k skill' name='$k' type='number' min='1' max='99' value='{$skill['points']}'>: {$skill['skill']}<hr>";
|
$skills .= "<input style='width: 64px;' class='skill-$k skill' name='skills[$k]' type='number' min='0' max='99' value='{$skill['points']}'>: {$skill['skill']}<hr>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// dump($c['Waypoints']);
|
// dump($c['Waypoints']);
|
||||||
$tabContent .= <<<EOT
|
$tabContent .= <<<EOT
|
||||||
<div style="background: white;" class="tab-pane fade" id="{$c->cData['CharacterName']}" role="tabpanel" aria-labelledby="{$c->cData['CharacterName']}-tab">
|
<div style="background: white;" class="tab-pane fade" id="{$c->cData['CharacterName']}" role="tabpanel" aria-labelledby="{$c->cData['CharacterName']}-tab">
|
||||||
<form method="POST" action="/saveCharacter.php">
|
<form class="charform" method="POST" action="/saveCharacter.php">
|
||||||
<input type="hidden" name="filePath" id="filePath" value="{$c->cData['filePath']}">
|
<input type="hidden" name="filePath" id="filePath" value="{$c->cData['filePath']}">
|
||||||
<div class="container" style="font-size: 14px;">
|
<div class="container" style="font-size: 14px;">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -217,21 +110,16 @@ EOT;
|
|||||||
Level: <input style="border: 1px solid black;width: 54px;" type="number" id="CharacterLevel" value="{$c->cData['CharacterLevel']}"><br>
|
Level: <input style="border: 1px solid black;width: 54px;" type="number" id="CharacterLevel" value="{$c->cData['CharacterLevel']}"><br>
|
||||||
$radio
|
$radio
|
||||||
$skills
|
$skills
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col"><h2>Quests</h2>
|
<div class="col">
|
||||||
|
<h2>Quests</h2>
|
||||||
$quests
|
$quests
|
||||||
</div>
|
</div>
|
||||||
<div class="col"><h2>Waypoints</h2>
|
<div class="col">
|
||||||
|
<h2>Waypoints</h2>
|
||||||
$wps
|
$wps
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<input class="btn btn-danger" style="" type="submit" value="Save Character">
|
<input class="btn btn-danger" style="" type="submit" value="Save Character">
|
||||||
</form>
|
</form>
|
||||||
|
Loading…
Reference in New Issue
Block a user