ajaxify d2s editor

This commit is contained in:
Hash Borgir 2023-06-02 20:43:18 -06:00
parent ce83c42701
commit 81f1199a96
6 changed files with 223 additions and 70 deletions

View File

@ -43,7 +43,7 @@ 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 = "Pest.d2s";
$char = new D2Char($filePath); $char = new D2Char($filePath);
//$char->setChar("CharacterStatus", "Died", 0); //$char->setChar("CharacterStatus", "Died", 0);
@ -51,23 +51,23 @@ $char = new D2Char($filePath);
//$char->setChar("CharacterStatus", "Expansion", 1); //$char->setChar("CharacterStatus", "Expansion", 1);
//$char->setChar("LeftmousebuttonskillID", 223); //$char->setChar("LeftmousebuttonskillID", 223);
$char->setAllSkills(1); //$char->setAllSkills(1);
//$char->setSkill(1, 99); $char->setSkill(4, 99);
//$char->setChar("CharacterClass", "Necromancer"); // 127 //$char->setChar("CharacterClass", "Necromancer"); // 127
//$char->setChar("CharacterProgression", 1); // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell //$char->setChar("CharacterProgression", 1); // 0 in normal, 1 finished normal, 2 finished nm, 3 finished hell
//$char->setChar("CharacterStatus", "Died", 1); //$char->setChar("CharacterStatus", "Died", 1);
$char->setChar("CharacterLevel", 99); //$char->setChar("CharacterLevel", 99);
$char->setStat("strength", 270); //$char->setStat("strength", 270);
$char->setStat("energy", 270); //$char->setStat("energy", 270);
$char->setStat("dexterity", 270); //$char->setStat("dexterity", 270);
$char->setStat("vitality", 270); //$char->setStat("vitality", 270);
$char->setStat("hitpoints", 100); //$char->setStat("hitpoints", 100);
$char->setStat("maxhp", 150); //$char->setStat("maxhp", 150);
$char->setStat("stamina", 280); //$char->setStat("stamina", 280);
$char->setStat("maxstamina", 290); //$char->setStat("maxstamina", 290);
$char->setStat("mana", 70); //$char->setStat("mana", 70);
$char->setStat("maxmana", 200); //$char->setStat("maxmana", 200);
//$char->setStat("soulcounter", 80); //$char->setStat("soulcounter", 80);
@ -88,5 +88,5 @@ unset($char); // destroy $char so we can read it again after writing to it to ge
$char = new D2Char($filePath); $char = new D2Char($filePath);
var_dump($char->cData['CharacterStatus']); var_dump($char->cData);
var_dump($char->cData['stats']); //var_dump($char->cData['stats']);

View File

@ -334,9 +334,9 @@ $(document).ready(function () {
// Get the name of the checkbox // Get the name of the checkbox
var name = $(this).attr("name"); var name = $(this).attr("name");
// Get the name of the difficulty // Get the name of the difficulty
var diff = $(this).attr("diff"); var diff = $(this).attr("diff");
// Get the value of the input named "filePath" // Get the value of the input named "filePath"
var filePath = $("input[name='filePath']").val(); var filePath = $("input[name='filePath']").val();
@ -358,9 +358,9 @@ $(document).ready(function () {
// Get the name of the checkbox // Get the name of the checkbox
var name = $(this).attr("name"); var name = $(this).attr("name");
// Get the name of the difficulty // Get the name of the difficulty
var diff = $(this).attr("diff"); var diff = $(this).attr("diff");
// Get the value of the input named "filePath" // Get the value of the input named "filePath"
var filePath = $("input[name='filePath']").val(); var filePath = $("input[name='filePath']").val();
@ -376,5 +376,41 @@ $(document).ready(function () {
}); });
}); });
// Get the value of the input named "filePath"
function constructURL(cmd, name, value, filePath) {
return "/saveCharacter.php?cmd=" + cmd + "&name=" + name + "&value=" + value + "&filePath=" + filePath;
}
$(".charform input[name='Difficulty'], .charform .skill, #CharacterName, #CharacterClass, #CharacterLevel, #CharacterClass").change(function () {
var name = $(this).attr("name");
var newValue = $(this).val();
var cmd = $(this).attr("cmd") || $(this).attr("id") || name;
var parentFormId = $(this).closest("form").attr("id");
var parentFormClass = $(this).closest("form").attr("class");
var filePath = $(`#${parentFormId} input[name='filePath']`).val();
var url = constructURL(cmd, name, newValue, filePath);
console.log(url);
console.log(newValue)
$.get(url, function (response) {
if (cmd == 'CharacterName') {
location.reload();
}
console.log(response);
});
});
});// end document.ready });// end document.ready

View File

@ -36,6 +36,11 @@ 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'; require_once './src/D2ByteReader.php';
require_once './src/D2BitReader.php';
require_once './src/D2Item.php';
require_once './src/D2Char.php';
PDO_Connect("sqlite:" . DB_FILE);
// Create an instance of D2CharStructureData class // Create an instance of D2CharStructureData class
$csData = new D2CharStructureData(); $csData = new D2CharStructureData();
@ -45,8 +50,7 @@ $cmd = $g['cmd'];
// Get the file path from the POST data and replace backslashes / // Get the file path from the POST data and replace backslashes /
$filePath = $g['filePath']; $filePath = $g['filePath'];
$filePath = str_replace("\\", "\\\\", $filePath); //$filePath = str_replace("\\", "\\\\", $filePath);
// Handle the WP check/uncheck // Handle the WP check/uncheck
if ($cmd == "wp") { if ($cmd == "wp") {
$diff = $g['diff']; $diff = $g['diff'];
@ -74,7 +78,7 @@ if ($cmd == "wp") {
$fileContents = file_get_contents($filePath); // Read the contents of the file $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 $ByteReader = new D2ByteReader($fileContents); // Create a new instance of D2ByteReader with the file data
$fileData = $ByteReader->getData(); // Get the data from the ByteReader instance $fileData = $ByteReader->getData(); // Get the data from the ByteReader instance
$wpBytes = $ByteReader->read($offset, 5, 1); $wpBytes = $ByteReader->read($offset, 5, 1);
$wpBytesToBits = $ByteReader->toBits($wpBytes); $wpBytesToBits = $ByteReader->toBits($wpBytes);
@ -100,22 +104,22 @@ if ($cmd == "wp") {
/* /*
* array (size=5) * array (size=5)
'cmd' => string 'q' (length=1) 'cmd' => string 'q' (length=1)
'name' => string 'Sisters_Burial_Grounds' (length=29) 'name' => string 'Sisters_Burial_Grounds' (length=29)
'value' => string '1' (length=1) 'value' => string '1' (length=1)
'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48) 'filePath' => string 'D:\\Diablo II\\MODS\\ironman-dev\\save\\Sorc.d2s' (length=48)
'diff' => string 'Norm' (length=4) 'diff' => string 'Norm' (length=4)
At each quest offset, read a short, 2 bytes. At each quest offset, read a short, 2 bytes.
347 => 'Den_Of_Evil', 347 => 'Den_Of_Evil',
349 => 'Sisters_Burial_Grounds', 349 => 'Sisters_Burial_Grounds',
351 => 'Tools_Of_The_Trade', 351 => 'Tools_Of_The_Trade',
353 => 'The_Search_For_Cain', 353 => 'The_Search_For_Cain',
355 => 'The_Forgotten_Tower', 355 => 'The_Forgotten_Tower',
357 => 'Sisters_To_The_Slaughter', 357 => 'Sisters_To_The_Slaughter',
Each short is 16 bytes. Each short is 16 bytes.
* *
* 0xFEFF = 11111110 11111111 * 0xFEFF = 11111110 11111111
* Short #0 Den of Evil Bit 4 is set when you enter the Den. * Short #0 Den of Evil Bit 4 is set when you enter the Den.
@ -153,7 +157,7 @@ if ($cmd == "q") {
// Write the byte value 0xFF at the current position // Write the byte value 0xFF at the current position
fwrite($fp, pack('C', 0xFF)); fwrite($fp, pack('C', 0xFF));
echo "Quest Just Finished, Collect Reward!"; echo "Quest Just Finished, Collect Reward!";
} else { } else {
// Set the file pointer position to the quest offset // Set the file pointer position to the quest offset
@ -167,10 +171,75 @@ if ($cmd == "q") {
// Write the byte value 0xFF at the current position // Write the byte value 0xFF at the current position
fwrite($fp, pack('C', 0x00)); fwrite($fp, pack('C', 0x00));
echo "Quest Not Started Yet!"; echo "Quest Not Started Yet!";
} }
$checksum = (shell_exec("bin\d2scs.exe \"$filePath\"")); $checksum = (shell_exec("bin\d2scs.exe \"$filePath\""));
fclose($fp); fclose($fp);
} }
$cmd = $_GET['cmd'];
$name = $_GET['name'];
$value = $_GET['value'];
$char = new D2Char(basename($filePath));
switch ($cmd) {
case "CharacterName":
// Handle CharacterName command
// Validate the character name length
if (strlen($value) < 2 || strlen($value) > 15) {
echo "Character name must be between 2 and 15 characters long.";
// You can handle the error case accordingly (e.g., return an error response)
// Additional validation checks can be added here as needed
} else {
// Validate the character name format
$pattern = '/^[A-Za-z0-9_-]+$/'; // Regular expression pattern for allowed characters
if (!preg_match($pattern, $value)) {
echo "\nCharacter name contains invalid characters. Only alphabets, numbers, underscore, and dash are allowed.";
// Handle the error case accordingly
} else {
// The character name is valid, proceed with further processing
$char->setChar($cmd, $value);
echo "\nCharacter Name and filename Changed";
}
}
echo "\nHandling CharacterName command - Name: $value, File Path: $filePath";
break;
case "CharacterClass":
// Handle CharacterClass command
$char->setChar($cmd, $value);
echo "Handling CharacterClass command - Class: $value, File Path: $filePath";
break;
case "CharacterLevel":
// Handle CharacterLevel command
$char->setChar($cmd, $value);
echo "Handling CharacterLevel command - Level: $value, File Path: $filePath";
break;
// handle difficulty wierdly
case "Normal":
$char->setChar("Difficulty", $value);
echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
break;
case "NM":
$char->setChar("Difficulty", $value);
echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
break;
case "Hell":
$char->setChar("Difficulty", $value);
echo "Handling Difficulty command - Difficulty: $value, File Path: $filePath";
break;
// skills
case "skills":
//var_dump($char->cData);
$char->setSkill($name, $value);
echo "Handling skills command - Skill: $name, Value: $value, File Path: $filePath";
break;
default:
// Handle unknown command
echo "Unknown command: $cmd";
break;
}

View File

@ -254,6 +254,7 @@ WHERE sk.charclass = '$class'";
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] = [
'id' => $this->skillData[$k]['Id'],
'skill' => $this->skillData[$k]['String'], 'skill' => $this->skillData[$k]['String'],
'points' => $v, 'points' => $v,
'page' => $this->skillData[$k]['SkillPage'], 'page' => $this->skillData[$k]['SkillPage'],
@ -373,12 +374,23 @@ WHERE sk.charclass = '$class'";
public function setChar(string $stat, mixed $val, mixed $val2 = null) { 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) {
return false;
}
$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);
rename($this->filePath, $_SESSION['savepath'] . "$val.d2s"); $this->data = $this->ByteReader->getData();
$this->save();
// file is not being saved, and copied before being saved, hence the bug, fixed
$fileName = pathinfo($this->filePath, PATHINFO_FILENAME);
$originalFileNames = glob($_SESSION['savepath'] . $fileName . '*');
foreach ($originalFileNames as $originalFileName) {
$newFileName = $_SESSION['savepath'] . $val . '.' . pathinfo($originalFileName, PATHINFO_EXTENSION);
if ($originalFileName !== $newFileName) {
copy($originalFileName, $newFileName);
unlink($originalFileName);
}
}
break; break;
case "CharacterClass": case "CharacterClass":
@ -398,6 +410,7 @@ WHERE sk.charclass = '$class'";
if ($val > 99) { if ($val > 99) {
$val = 99; $val = 99;
} }
$this->ByteReader->writeByte(43, $val); $this->ByteReader->writeByte(43, $val);
$this->setStat('level', $val); $this->setStat('level', $val);
@ -443,6 +456,21 @@ WHERE sk.charclass = '$class'";
$this->save(); $this->save();
break; break;
case 'Difficulty':
switch ($val) {
case "Normal":
$this->data[168] = pack('C', 255); // 1000 0000 MSB = Difficulty
break;
case "NM":
$this->data[169] = pack('C', 255);
break;
case "Hell":
$this->data[170] = pack('C', 255);
break;
}
break;
case 'LeftmousebuttonskillID': case 'LeftmousebuttonskillID':
$this->ByteReader->writeBytes(120, dechex($val)); $this->ByteReader->writeBytes(120, dechex($val));
break; break;

View File

@ -8,7 +8,7 @@
$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"><span class="chartab">{$c->cData['CharacterName']}</span></a>
</li> </li>
EOT; EOT;
echo $tabs; echo $tabs;
@ -39,19 +39,17 @@ EOT;
} }
$wps = ''; $wps = '';
$wps .= "<input type='radio' value='1' name='wp_all' id='wp_all'>"; //$wps .= "<input type='radio' value='1' name='wp_all' id='wp_all'>";
$wps .= "<label style='font-size: 1.3em;color:green;' for='wp_all'>Enable All Waypoints</label><br>"; //$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 .= "<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>"; //$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 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; $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", " Hell"], "", $kD); $kD = str_replace([" NM", " Hell"], "", $kD);
$checked = ($v == 1 && $k != '') ? 'checked ' : ''; $checked = ($v == 1 && $k != '') ? 'checked ' : '';
@ -60,7 +58,6 @@ EOT;
$wps .= "<label for='$k'>$kD</label><br>"; $wps .= "<label for='$k'>$kD</label><br>";
$wp_count++; $wp_count++;
} }
} }
$classOptions = [ $classOptions = [
@ -74,54 +71,77 @@ EOT;
} }
$difficulties = [ $difficulties = [
'Normal' => 'DifficultyNormal', 'Normal' => '1',
'NM' => 'DifficultyNM', 'NM' => '2',
'Hell' => 'DifficultyHell' 'Hell' => '3'
]; ];
$radio = ''; $radio = '';
foreach ($difficulties as $difficulty => $id) { foreach ($difficulties as $difficulty => $id) {
$checked = ($c->cData['Difficulty'][$difficulty] == 1) ? 'checked' : ''; $checked = ($c->cData['Difficulty'][$difficulty] == 1) ? 'checked' : '';
$radio .= "<input $checked type='radio' id='$id' name='Difficulty' value='$difficulty'>$difficulty<br>"; $radio .= "<input $checked type='radio' id='$difficulty' name='Difficulty' value='$difficulty'>";
$radio .= "<label for='$difficulty'>$difficulty</label><br>";
} }
$skills = ''; $skills = '';
/*
'skills' =>
array (size=1)
'skills' =>
array (size=52)
0 =>
array (size=7)
'id' => int 36
'skill' => string 'Fire Bolt' (length=9)
'points' => int 0
'page' => int 3
'row' => int 1
'col' => int 2
'icon' => int 0
*/
$skillcounter = 1;
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='skills[$k]' type='number' min='0' max='99' value='{$skill['points']}'>: {$skill['skill']}<hr>"; $skills .= "<input cmd='skills' style='width: 64px;' class='skill-$k skill' name='$skillcounter' type='number' min='0' max='255' value='{$skill['points']}'>: {$skill['skill']}<hr>";
$skillcounter++;
} }
// 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; margin-top: 10px;" class="tab-pane fade" id="{$c->cData['CharacterName']}" role="tabpanel" aria-labelledby="{$c->cData['CharacterName']}-tab">
<form class="charform" method="POST" action="/saveCharacter.php"> <form id='{$c->cData['CharacterName']}' class="charform {$c->cData['CharacterName']}" 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">
<div class="col"> <div class="col">
<h1 style="margin: 15px;">{$c->cData['CharacterName']}</h1> <!--<input class="btn btn-danger" style="" type="submit" value="Save Character">
<input class="btn btn-danger" style="" type="submit" value="Save Character"> <img src="/img/chars/{$c->cData['CharacterClass']}.gif" style='height: 64px; width: 64px;'><br>-->
<img src="/img/chars/{$c->cData['CharacterClass']}.gif"><br> Name: <input type="text" id="CharacterName" name="CharacterName" maxlength="16" value="{$c->cData['CharacterName']}" pattern="[A-Za-z0-9_-]+" title="Character name can only contain alphabets, numbers, underscore, and dash." data-oldvalue="{$c->cData['CharacterName']}">
<input type="text" id="ChracterName" name="ChracterName" maxlength="16" value="{$c->cData['CharacterName']}"> <br>
<select id='CharacterClass'> <select id='CharacterClass' name='CharacterClass'>
$option $option
</select> </select><br>
Level: <input style="border: 1px solid black;width: 54px;" type="number" id="CharacterLevel" value="{$c->cData['CharacterLevel']}"><br> Character Level: <input style="border: 1px solid black;width: 54px;" type="number" name="CharacterLevel" id="CharacterLevel" value="{$c->cData['CharacterLevel']}"><br>
$radio <hr>
$skills <!--Difficulty:<br>
$radio-->
<div>
<h3>Skills</h3>
$skills
</div>
</div> </div>
<div class="col"> <div class="col">
<h2>Quests</h2> <h3>Quests</h3>
$quests $quests
</div> </div>
<div class="col"> <div class="col">
<h2>Waypoints</h2> <h3>Waypoints</h3>
$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>
</div> </div>
EOT; EOT;

View File

@ -179,7 +179,7 @@ $htmltop = <<<EOT
} }
.gemtable td img { .gemtable td img {
max-height: 128px; max-height: 64px;
} }
table { table {