Commit d376c60c authored by David Gonçalves's avatar David Gonçalves 📖

...

parent 3feb7abb
......@@ -8,6 +8,19 @@ Hero Fighter story editor is a program for making custom stages that can be down
- **Tommy Chan** - Developer
- **zlyfer** - Developer
## TO-DO
- Improve UI. Give it a modern look.
- Use Bootsrap.
- Have toggle menu on the left. Menu will have following options:
- **Drag & Drop** page, that will let users select what they want to do and have the code generated for them. **This is very low on the priority of things to do.**
- **Source mode** page, that is basically Ace editor.
- **Tutorial** page.
- **About** page.
- Both editing modes (drag & drop and source mode) will show a page that will be about selecting which stage to edit, we will call this page the story menu. More than one stage can be edited at the same time (just go to the story menu page and select another story, changes will not be lost). The story menu will have the list of stories available for editing, showing their names (that the user can edit) and *possibly* a preview of the background (that the user can select. When clicking on a stage to edit, the editor will be shown and the user can edit his text and save it to a XML file. In the editor page the user will have the option to load the original story, in case the editor is empty (this will give him a reference on how to do things). In order to generate the executable the user must go to the story menu, which will have this option available. All the stories that have been modified by the user will be replaced in the executable.
- Verify if user has Java installed and it is in the path environment variable.
- XLS for validating the story XML file.
## Updating
- Check for newer versions of Ace Editor and JPEXS and read the notes below about them.
......
......@@ -90,3 +90,129 @@ body::after {
#bg_selector {
width:110px;
}
/* LOADER - START */
/**
* When the body has the loading class, we turn
* the scrollbar off with overflow:hidden
* and our modal element will be visible
*/
body.loading .loader,
body.loading .loader_bg {
overflow: hidden;
display: block;
}
/**
* Loader taken from:
* https://projects.lukehaas.me/css-loaders/
*/
.loader_bg {
display: none;
position: fixed;
z-index: 999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
}
.loader {
display: none;
z-index: 1000;
color: #ffffff;
font-size: 10px;
position: fixed;
left: 50%;
top: 50%;
margin-left: 3em;
margin-top: 3em;
width: 1em;
height: 1em;
border-radius: 50%;
text-indent: -9999em;
-webkit-animation: load4 1.3s infinite linear;
animation: load4 1.3s infinite linear;
-webkit-transform: translateX(-500%) translateY(-500%) translateZ(0);
-ms-transform: translateX(-500%) translateY(-500%) translateZ(0);
transform: translateX(-500%) translateY(-500%) translateZ(0);
}
#loading_text {
top: 50%;
left: 50%;
position: fixed;
font-size: 30px;
margin-left: -170px;
margin-top: 80px;
}
@-webkit-keyframes load4 {
0%,
100% {
box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
}
12.5% {
box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
}
25% {
box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0,
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
}
37.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em,
0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
50% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em,
0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
62.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em,
0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
}
75% {
box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
}
87.5% {
box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
}
}
@keyframes load4 {
0%,
100% {
box-shadow: 0 -3em 0 0.2em, 2em -2em 0 0em, 3em 0 0 -1em, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 0;
}
12.5% {
box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em, 3em 0 0 0, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
}
25% {
box-shadow: 0 -3em 0 -0.5em, 2em -2em 0 0, 3em 0 0 0.2em, 2em 2em 0 0,
0 3em 0 -1em, -2em 2em 0 -1em, -3em 0 0 -1em, -2em -2em 0 -1em;
}
37.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 0, 2em 2em 0 0.2em,
0 3em 0 0em, -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
50% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 0em,
0 3em 0 0.2em, -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
}
62.5% {
box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em,
0 3em 0 0, -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
}
75% {
box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em, 3em 0em 0 -1em, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
}
87.5% {
box-shadow: 0em -3em 0 0, 2em -2em 0 -1em, 3em 0 0 -1em, 2em 2em 0 -1em,
0 3em 0 -1em, -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
}
}
/* LOADER - END */
......@@ -198,6 +198,13 @@
<input type="submit" id="engtochi_text" value="Eng to Chi" />
<span id="storyname_chi_text">Story name(Chinese): </span><input type="text" id="storynameb5" />
</div>
<!-- Place at bottom of page -->
<div class="loader_bg">
<div class="loader"></div>
<p id="loading_text">Loading. Please wait...</p>
</div>
</body>
</html>
......@@ -70,6 +70,7 @@ class Languages {
$("#editor_ch").text(this._lang.editor_ch);
$("#editor_ttln").text(this._lang.editor_totalline);
$("#replace_story_photo").text(this._lang.replace_story_photo);
$("#loading_text").text(this._lang.loading_text);
}
}
......
......@@ -29,10 +29,16 @@ function generateExe() {
const dialog = require('dialog'); // For some reason dialog was not defined...
$('#generate_exe').val(window.lang.loading_text);
// TODO Verify if Java is installed and in path
const xmlData = File.getDataFromEditor();
let xmlData;
try {
xmlData = File.getDataFromEditor();
} catch (err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
if (xmlData === undefined || xmlData === null || xmlData === '' || xmlData.length === 0) {
dialog.err(window.lang.empty_story_error, window.lang.error);
......@@ -87,7 +93,14 @@ function generateExe() {
require("electron").remote.dialog.showSaveDialog({
title: window.lang.prompt_text,
defaultPath: exe_filename
}, function(result){
}, function(result) {
if(!result) {
return;
}
$('body').addClass("loading");
//$('#generate_exe').val(window.lang.loading_text);
exe_filename = result;
......@@ -97,36 +110,38 @@ function generateExe() {
xml_storylist_filename = path.join(dir, xml_storylist_filename);
swf_filename = path.join(dir, swf_filename);
const dialog = require('dialog');
// Write Story XML file
fs.writeFile(xml_story_filename, xmlData, err => {
if (err) {
dialog.err(window.lang.save_error, window.lang.error);
return;
}
// Write StoryList XML file
fs.writeFile(xml_storylist_filename, storyListXML, err => {
if (err) {
fs.unlink(xml_story_filename, function(error) {
if (error) {
throw error;
}
});
dialog.err(window.lang.save_error, window.lang.error);
return;
}
// Create EXE file
compileExe();
try {
fs.writeFileSync(xml_story_filename, xmlData);
} catch(err) {
$('body').removeClass("loading");
console.log(err);
dialog.err(error, window.lang.error);
return;
}
// Write StoryList XML file
try {
fs.writeFileSync(xml_storylist_filename, storyListXML);
} catch(err) {
$('body').removeClass("loading");
fs.unlink(xml_story_filename, function(error) {
if (error) {
console.log(err);
dialog.err(error, window.lang.error);
}
});
console.log(err);
dialog.err(window.lang.save_error, window.lang.error);
return;
}
});
// Create EXE file
compileExe();
$('body').removeClass("loading");
//$('#generate_exe').val(window.lang.generate_exe);
});
}
function compileExe() {
......@@ -143,41 +158,71 @@ function compileExe() {
let storylist_id = "234";
// Replace Story XML
let ffdec = spawnSync('java', ['-jar', `${__dirname}/ffdec/ffdec.jar`, '-replace',
`${__dirname}/game/hf.swf`, swf_filename, story_ids[story_number], xml_story_filename]);
let ffdec;
try {
ffdec = spawnSync('java', ['-jar', `${__dirname}/ffdec/ffdec.jar`, '-replace',
`${__dirname}/game/hf.swf`, swf_filename, story_ids[story_number], xml_story_filename]);
} catch(err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
console.log(`stdout: ${ffdec.stdout}`);
console.log(`stderr: ${ffdec.stderr}`);
console.log(`exit: Child process exited with code ${ffdec.status}.`);
// Replace Story List XML
ffdec = spawnSync('java', ['-jar', `${__dirname}/ffdec/ffdec.jar`, '-replace',
swf_filename, swf_filename, storylist_id, xml_storylist_filename]);
try {
ffdec = spawnSync('java', ['-jar', `${__dirname}/ffdec/ffdec.jar`, '-replace',
swf_filename, swf_filename, storylist_id, xml_storylist_filename]);
} catch(err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
console.log(`stdout: ${ffdec.stdout}`);
console.log(`stderr: ${ffdec.stderr}`);
console.log(`exit: Child process exited with code ${ffdec.status}.`);
// Compress SWF
ffdec = spawnSync('java', ['-jar', `${__dirname}/ffdec/ffdec.jar`,
'-compress', 'zlib', swf_filename, swf_filename + "_compressed"]);
try {
ffdec = spawnSync('java', ['-jar', `${__dirname}/ffdec/ffdec.jar`,
'-compress', 'zlib', swf_filename, swf_filename + "_compressed"]);
} catch(err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
console.log(`stdout: ${ffdec.stdout}`);
console.log(`stderr: ${ffdec.stderr}`);
console.log(`exit: Child process exited with code ${ffdec.status}.`);
fs.unlinkSync(swf_filename);
try {
fs.unlinkSync(swf_filename);
} catch(err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
swf_filename = swf_filename + "_compressed";
swf2exe(swf_filename, exe_filename);
// Delete XML and SWF files
fs.unlinkSync(xml_story_filename);
fs.unlinkSync(xml_storylist_filename);
fs.unlinkSync(swf_filename);
try {
fs.unlinkSync(xml_story_filename);
fs.unlinkSync(xml_storylist_filename);
fs.unlinkSync(swf_filename);
} catch(err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
dialog.info(window.lang.exe_success, window.lang.success);
$('#generate_exe').val(window.lang.generate_exe);
}
......@@ -188,10 +233,16 @@ function swf2exe(swfFile, outputFile) {
let projectorData = fs.readFileSync(`${__dirname}/swf2exe/SA.exe`);
let swfData = fs.readFileSync(swfFile);
fs.writeFileSync(outputFile, projectorData);
fs.appendFileSync(outputFile, swfData);
fs.appendFileSync(outputFile, Buffer.from( new Uint8Array(footer) ));
fs.appendFileSync(outputFile, Buffer.from( new Uint8Array(intToByteArray(swfData.length))));
try {
fs.writeFileSync(outputFile, projectorData);
fs.appendFileSync(outputFile, swfData);
fs.appendFileSync(outputFile, Buffer.from( new Uint8Array(footer) ));
fs.appendFileSync(outputFile, Buffer.from( new Uint8Array(intToByteArray(swfData.length))));
} catch(err) {
console.log(err);
dialog.err(error, window.lang.error);
return;
}
function intToByteArray(int) {
// we want to represent the input as a 4-bytes array
......
......@@ -32,6 +32,6 @@
"cancel_text":"Cancel",
"comfirm_text":"Comfirm",
"prompt_text":"Please enter a file name",
"loading_text":"Generating...",
"loading_text":"Loading. Please wait...",
"replace_story_photo":"Story background: "
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment