<!doctype html>
<meta charset="windows-1252">
textarea {
white-space: pre;
overflow: auto;
resize: horizontal;
}
<h1>JJ2 language file editor
</h1>
Open a j2s file to edit:
<br>
<input type="file" id="inputfile" accept=".j2s">
English for comparison:
<br>
<textarea id="original1" cols="37" rows="30" wrap="off" disabled onscroll="document.getElementById('linesarea1').scrollTop = this.scrollTop;">Please Reinstall Jazz2
#New Game
#Load Game
#Save Game
#Options
#Quit
#New Game
#Load Game
#Custom Game
#Options
#Quit
#High Scores
#Main Menu
Shareware
Press Fire
#Welcome Player %i
#Your Name
#Your Character
#Start Game
Type Your Name
Press Enter To Change
First type a name
Press Enter To Start
name:
char:
controls:
Players %u
#Choose Game Type
#Single Player
#Party Mode
#Choose Connection
#Local Play (Splitscreen)
#Internet Play
#Local Network (IPX)
#Modem Play
#Choose Party Game Mode
#Cooperative
#Battle
#Race
#Treasure Hunt
#Battle game
#Number of roasts to win
#Done
#Choose Episode
Episode not available
#Select Difficulty Level
#Easy
#Medium
#Hard
#Choose Character
LEVEL COMPLETE
TOTAL
unfinished
Winner
Loser
%s wins
%s loses
Press Fire To Continue
End of Episode
not done yet
#Set Game Options
#Options
#Controls
#Video
#Sound
#Controls
#Set Controls
#Press Enter To Change
#Press new Key or Button
#key
#joy
#Up
#Down
#Left
#Right
#Fire
#Select
#Jump
#Run
or
§2#Keyboard 1
§2#Keyboard 2
§2#Joystick 1
§2#Joystick 2
§2#Joystick 3
§2#Joystick 4
Loading...
#Video Options
#Resolution
#Detail
Low
Medium
High
#Sound Options
#Effect Volume
#Music Volume
#Advanced
#Done
§1#Use Left, Right or Fire to Change
#Output Mode
#Sampling Rate
#Mixing Precision
#Interpolation
#Done
On
Off
§2Min
§2Max
Pause
Are you Sure?
yes
no
LETS ROCK
GET READY
KICK SHELL
GET MOVING
SHAKE YOUR TAIL
BUST A MOVE
RABBIT ROAST
TRY AGAIN
BUMMER DUDE
YOU ATE IT
THATS GOTTA HURT
TOASTIED
SEE YA
FRIED RABBIT
roasts %u /%u
Find Exit
need
Extra Life
Lap %u\5
Help
#Cancel
fastfire
§1play the previous episode first
§2press any key to enter next episode
Finished
§1Empty
Cancel
§1Single Player Game
§1%i player %s
GAME SAVED
GAME OVER
#Sugar RUSH %u
#Select Language
#Installed Languages
Menu
Help
Load
Save
Quick Load
Quick Save
Game Info
#You Made It!
#Enter Name!
unknown
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
0
1
2
3
4
5
6
7
8
9
pad up
page up
up
pad down
page down
down
pad left
left
pad right
right
space
enter
backspace
minus
equal
pad plus
pad minus
home
end
ins
del
pad ins
pad del
pad home
pad end
pad pgup
pad pgdn
pad enter
left ctrl
right ctrl
left alt
right alt
shift
f1
f2
f3
f4
f5
f6
f7
f8
f9
f10
f11
f12
caps lock
Esc
button %u
NOT CONNECTED
power up
#Setup Network
#Local Network (TCP)
Chat:
Choose Number of Players
Local Players
Players
Setup Local Players
Setup Players
Setup Player %i
#Change Player %i
color:
default
control:
#Hardware Mode
#Textured 3D Background
#MMX Capabilities
#Ambient Lighting
Use the arrow keys to switch pages
Page %u of %u
Game List
Active Game List
Error Connecting to
List Servers
Press any key
Enter Address:
Retrieving Server Lists
Looking for servers...
Looking for local servers...
Game Server Setup
#Number of gems
#Number of laps
#Server Type
Open
Private
User server at
DEMO
Start Multiplayer game
#Join another game
#< Client >
#Start a new game
#< Server >
Players on this computer
#Select a Level
Connecting
Press Esc to abort
#Password:
Downloading
#Capture the Flag
#Number of wins
Capture
Treasure
Blue %i/%i
Red %i/%i
pinging
Network Error
§1Could not start Server
§1Version of server is different
§1Could not connect to server
§1Server denied you
Wrong password
Server wants password
Please visit :
www.jazzjackrabbit.com
for more information
%s captured the flag
%s roasted %s
you got roasted by %s
you killed yourself
%s got roasted
%s ate it
%s joined the game
%s left the game
Server is full
Error during handshaking
Feature not available in shareware
Error downloading file
Connection lost
Winsock error
Connection timed out
Server stopped
Blue Team scored a point
Red Team scored a point
Only in registered version
<textarea id="linesarea1" cols="103" rows="30" wrap="off" onscroll="document.getElementById('original1').scrollTop = this.scrollTop;"></textarea>
<textarea id="original2" cols="64" rows="30" wrap="off" disabled onscroll="document.getElementById('linesarea2').scrollTop = this.scrollTop;">@Destroy your enemy @ ten times to win.
@You found a secret area.
@Secret Treasure Room.
@Nothing to see here.
@Destroy your enemy @ ten times to win.
@You found a secret area.
@Secret Treasure Room.
@Nothing to see here.
@Spaz ate the dopefish.
@Find the gopher.
@Dragons live in burbank.
@Mark wears briefs. @Hoo Hah.
@Nick loves shiny.
@Stomp your booty to exit.
@A flame weapon can be @used to melt ice...
@Super dooper secret.
@Shields will give you unlimited @special ammo for a short time.
@Stopwatches will add time to@the life of a shield.
@This schwartzenguard is toast!
@Poles spin you around so@ you can go even faster.
@You found a secret area.
@Secret Treasure Room.
@Nothing to see here.
@Collect coins to activate @bonus warp devices.
@Cheese is green on tuesday.
@Craig is king doofus.
@To beat the queen @shoot her off her ledge.
@ Congratulations! @ You can now exit the castle!
@To kick through these@blocks, press down and jump!
@Press down and jump beneath @these blocks to break them!
@Buttstomp the metal box @to open key blocks!
@This level is not done.
@Spaz ate the dopefish.
@Find the gopher.
@Dragons live in burbank.
@Mark wears briefs. @Hoo Hah!
@Nick loves shiny. @Always has!
@Send Tim new socks.
@Send Nigel a green card.
@Beware of chainsaw schmalz.
@Dont give mark a burrito.
@Long live the ice level.
@This is not over yet!
@Falling boulders can @give you a headache.
@A Flamethrower works@well against bugs.
@@You cannot defeat me!@Prepare to face my superbot!
@@Ack! I'm outta here!
@Beware of falling enemies.
@Craig is still a doofus!
@Smoke rings will @make you dizzy.
@First player to the @finish wins the game.
@First player to the @finish wins the game.
@Poles spin you around so@ you can go even faster.
@You found a secret area.
@Secret Treasure Room.
@Nothing to see here.
@Collect coins to activate @bonus warp devices.
@Spaz ate the dopefish.
@Find the gopher.
@Dragons live in burbank.
@Mark wears briefs. @Hoo Hah.
@Nick loves shiny.
@Shoot these blocks!
@When in the air, press down@to stomp with your butt.
@To pass this area, stomp@the secret metal crate.
@You need twenty coins to pass @through this secret warp!
@Coins give you access to @warps that appear later.
@Stomp in the right place and@you might find a surprise!
@Some crates contain@bombs or baddies!
@You need twenty coins to pass @through this secret warp!
@A flamethrower works well @against nasty bugs.
@Smoke rings will make@you very dizzy!
@Beware the witch! She can@turn you into a frog.
@If you are turned into a frog@Eva Earlong can help!
@You made it! This is the end@ of the shareware version.
@Welcome to Jazz Jackrabbit 2. @ This is a training level.
@Collect goodies for@points and surprises.
@After jumping, press jump@again to do a special move.
@Some walls can be shot.
@When in the air, press down@to stomp with your butt.
@Secrets abound in Jazz 2. @ Check the walls.
@Good job. Remember to@look for secrets.
@Collect gems for @an extra life.
@Red Gems count@as one gem.
@Green gems count@as five gems.
@Blue gems count@as ten gems.
@Carrots give you health.
@Checkpoints save your@spot if you lose a life.
@Collect coins to@unlock bonus rooms.
@Beware of sharp stuff.@It hurts.
@Now youre ready to play.@ Good luck and have fun.
@Smoke rings will @make you dizzy.
@You can't buttstomp@so go up and around!
@No rewards to those@with itchy trigger fingers.
@Todays Forcast: Strong Winds!
@Find the crate@to clear your path.
@Welcome to@Jazz Jackrabbit 2:@The Secret Files!
@Only Spaz can get to@the room up on the left.@He may need something@to stand on.
@Don't beat Nigel at pool.@You've veen warned. :)
@Eating too many chocolate@eggs can make you sick :p
@Sloping Tunnel Entrance
@To access the tunnels above@find the access warp.
@One route leads to riches.@One route leads to battle.
@Only those who can double-jump@can get to the goodies!
@Find the crate to make@your climbing blocks appear
@Stomping this crate also@free's some enemies :)
@Enter the house with caution.....
@Silver Crates can't be broken underwater...
@Water Level control crate above.
@Stomping crates can be good and bad...
@But you need a way to get up there...
@Take to the roof tops!
@The skies above will reward@those who stomp...
@Jump as far over to the@right as you possibly can...
@Didn't make the jump huh? :)
@Well Done!
@Use your Special Moves to get up the air cons!@For Jazz, press Crouch and Jump.@For Spaz, Press Jump Twice!
@Find the crate and the gems are yours!
@Springs Don't Work When Frozen...
@Collecting 20 coins is more rewarding...
@Find the crate to clear the blocks....
@BEWARE! Flocks of Ravens can@be very dangerous.
@The remove the blocks@look to the tallest building.
@Choose a cover and stomp away!
@Hi Geobunny !
@Goto www.project2.com@use@password: BUNNYLOVER
</textarea>
<textarea id="linesarea2" cols="76" rows="30" wrap="off" onscroll="document.getElementById('original2').scrollTop = this.scrollTop;"></textarea>
/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */
var saveAs=saveAs||(function(h){"use strict";var r=h.document,l=function(){return h.URL||h.webkitURL||h},e=h.URL||h.webkitURL||h,n=r.createElementNS("http://www.w3.org/1999/xhtml","a"),g="download" in n,j=function(t){var s=r.createEvent("MouseEvents");s.initMouseEvent("click",true,false,h,0,0,0,0,0,false,false,false,false,0,null);return t.dispatchEvent(s)},o=h.webkitRequestFileSystem,p=h.requestFileSystem||o||h.mozRequestFileSystem,m=function(s){(h.setImmediate||h.setTimeout)(function(){throw s},0)},c="application/octet-stream",k=0,b=[],i=function(){var t=b.length;while(t--){var s=b[t];if(typeof s==="string"){e.revokeObjectURL(s)}else{s.remove()}}b.length=0},q=function(t,s,w){s=[].concat(s);var v=s.length;while(v--){var x=t["on"+s[v]];if(typeof x==="function"){try{x.call(t,w||t)}catch(u){m(u)}}}},f=function(t,u){var v=this,B=t.type,E=false,x,w,s=function(){var F=l().createObjectURL(t);b.push(F);return F},A=function(){q(v,"writestart progress write writeend".split(" "))},D=function(){if(E||!x){x=s(t)}w.location.href=x;v.readyState=v.DONE;A()},z=function(F){return function(){if(v.readyState!==v.DONE){return F.apply(this,arguments)}}},y={create:true,exclusive:false},C;v.readyState=v.INIT;if(!u){u="download"}if(g){x=s(t);n.href=x;n.download=u;if(j(n)){v.readyState=v.DONE;A();return}}if(h.chrome&&B&&B!==c){C=t.slice||t.webkitSlice;t=C.call(t,0,t.size,c);E=true}if(o&&u!=="download"){u+=".download"}if(B===c||o){w=h}else{w=h.open()}if(!p){D();return}k+=t.size;p(h.TEMPORARY,k,z(function(F){F.root.getDirectory("saved",y,z(function(G){var H=function(){G.getFile(u,y,z(function(I){I.createWriter(z(function(J){J.onwriteend=function(K){w.location.href=I.toURL();b.push(I);v.readyState=v.DONE;q(v,"writeend",K)};J.onerror=function(){var K=J.error;if(K.code!==K.ABORT_ERR){D()}};"writestart progress write abort".split(" ").forEach(function(K){J["on"+K]=v["on"+K]});J.write(t);v.abort=function(){J.abort();v.readyState=v.DONE};v.readyState=v.WRITING}),D)}),D)};G.getFile(u,{create:false},z(function(I){I.remove();H()}),z(function(I){if(I.code===I.NOT_FOUND_ERR){H()}else{D()}}))}),D)}),D)},d=f.prototype,a=function(s,t){return new f(s,t)};d.abort=function(){var s=this;s.readyState=s.DONE;q(s,"abort")};d.readyState=d.INIT=0;d.WRITING=1;d.DONE=2;d.error=d.onwritestart=d.onprogress=d.onwrite=d.onabort=d.onerror=d.onwriteend=null;h.addEventListener("unload",i,false);return a}(self));
(function () {
'use strict';
var inputFile = document.getElementById('inputfile');
var original1 = document.getElementById('original1');
var original2 = document.getElementById('original2');
var linesArea1 = document.getElementById('linesarea1');
var linesArea2 = document.getElementById('linesarea2');
var generateButton = document.getElementById('generate');
linesarea1.value = original1.textContent;
linesarea2.value = original2.textContent;
var filename = "Language.j2s";
inputFile.addEventListener('change', function () {
if (inputFile.files[0]) {
filename = inputFile.files[0].name;
var fr = new FileReader();
fr.onload = function () {
var buffer = fr.result;
var dv = new DataView(buffer);
var i = 0;
var offsetArraySize = dv.getUint32(i, true); i+=4;
var textArraySize = dv.getUint32(i, true); i+=4;
var textArray = new Uint8Array(buffer.slice(i, i+textArraySize)); i+=textArraySize;
var offsetArray = new Uint32Array(buffer.slice(i, i+offsetArraySize*4)); i+=offsetArraySize*4;
var texts1 = [];
for (var k = 1; k < offsetArray.length; k++) {
var offset = offsetArray[k];
var str = "";
while (textArray[offset] !== 0) {
str += String.fromCharCode(textArray[offset++]);
}
texts1.push(str);
}
linesArea1.value = texts1.join("\n");
var levelEntryCount = dv.getUint32(i, true); i+=4;
//console.log(levelEntryCount);
var levelEntries = [];
var amounts = [];
var offsets = [];
var unknowns = [];
var k = 0;
while (k < levelEntryCount) {
var str = "";
for (var j = 0; j < 8; j++) {
str += String.fromCharCode(dv.getUint8(i++));
}
levelEntries.push(str);
unknowns.push(dv.getUint8(i++)); // Always zero..
amounts.push(dv.getUint8(i++));
offsets.push(dv.getUint16(i, true)); i+=2;
k++;
}
var textArray2Size = dv.getUint32(i, true); i+=4;
offsets.push(textArray2Size);
var indices = [];
var texts2 = [];
var k = 0;
for (var l = 0; l < levelEntryCount; l++) { // For each level
var offset = offsets[l+1] || 0;
var amount = amounts[l];
//console.log(levelEntries[l], amount, offset);
var a = 0;
while (k < offset) { // For each helpstring in level
indices.push(dv.getUint8(i+k++));
var size = dv.getUint8(i+k++);
var str = "";
while (str.length < size) {
str += String.fromCharCode(dv.getUint8(i+k++));
}
texts2.push(str);
a++;
}
amounts[l] = a;
}
i+=k;
// End of data
var numberOfHelpStrings = texts2.length;
if (numberOfHelpStrings < 126) { // If the opened .j2s file didn't include enough strings (probably because it was made for 1.23), fill in the rest from English
var originalLines = original2.textContent.split("\n");
while (numberOfHelpStrings < 126) {
texts2.push(originalLines[numberOfHelpStrings++]);
}
}
linesArea2.value = texts2.join("\n");
};
fr.readAsArrayBuffer(inputFile.files[0]);
}
}, false);
generate.addEventListener('click', function () {
var texts1 = linesArea1.value.split("\n");
var texts2 = linesArea2.value.split("\n");
if (texts1.length < 327) {
if(confirm("The first box must contain atleast 327 lines. You have "+texts1.length+".\nClick OK to override.")) return;
}
if (texts2.length !== 126) {
if(!confirm("The second box must contain exactly 126 lines. You have "+texts2.length+".\nClick OK to override.")) return;
}
var offsetArraySize = texts1.length + 1;
var offsetArray = new Uint32Array(offsetArraySize);
var textArray = [0];
var offindex = 1;
var offset = 1;
for (var i = 0; i < texts1.length; i++) {
var str = texts1[i];
var k = 0;
while (k < str.length) {
textArray.push(str.charCodeAt(k++) & 0xFF);
}
textArray.push(0);
offsetArray[offindex++] = offset;
offset += str.length+1;
}
textArray = new Uint8Array(textArray);
var textArraySize = textArray.length;
var names = ["BATTLE1", "BATTLE3", "BATTLE4", "CARROT1", "CARROT1N", "CASTLE1", "CASTLE1N", "DAMN2", "DIAM1", "DIAM3", "HELL", "JUNG1", "LABRAT2", "MEDIVO1", "PSYCH1", "RACE1", "RACE2", "RACE3", "RACE4", "SHARE1", "SHARE2", "SHARE3", "TRAINER", "TREASUR3", "EASTER1", "EASTER2", "EASTER3", "HAUNTED1", "TOWN1", "TOWN2", "TOWN3"];
var unknowns = new Uint8Array([3, 3, 4, 1, 4, 4, 6, 0, 4, 3, 1, 1, 1, 1, 0, 0, 0, 4, 4, 6, 2, 2, 15, 0, 15, 2, 2, 6, 5, 2, 5]);
var amounts = new Uint8Array([4, 4, 5, 2, 4, 5, 7, 1, 5, 4, 2, 2, 2, 2, 1, 1, 1, 5, 5, 7, 3, 3, 16, 1, 8, 3, 3, 5, 6, 3, 6]);
var indices = new Uint8Array([0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 4, 0, 1, 0, 1, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 0, 0, 1, 2, 3, 4, 0, 1, 2, 3, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 0, 1, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 1, 2, 3, 4, 5, 6, 15, 0, 1, 2, 0, 1, 2, 0, 2, 3, 4, 6, 0, 1, 2, 3, 4, 5, 0, 1, 2, 0, 1, 2, 3, 4, 5 ]);
var offsets = [];
var textArray2 = [];
var i = 0;
var offset = 0;
for (var l = 0; l < names.length; l++) {
var amount = amounts[l];
offsets.push(offset);
for (var a = 0; a < amount; a++) {
var str = texts2[i];
var k = 0;
textArray2.push(indices[i] || 0);
textArray2.push(str.length);
while (k < str.length) {
textArray2.push(str.charCodeAt(k++) & 0xFF);
}
i++;
offset += str.length + 2;
}
}
textArray2 = new Uint8Array(textArray2);
var textArray2Size = textArray2.length;
var levelEntryCount = names.length;
var levelEntries = new Uint8Array(levelEntryCount*12);
var dv = new DataView(levelEntries.buffer);
var offset = 0;
for (var i = 0; i < levelEntryCount; i++) {
var str = names[i];
var k = 0;
while (k < 8) {
levelEntries[offset++] = (str.charCodeAt(k++) || 0) & 0xFF;
}
levelEntries[offset++] = 0;
levelEntries[offset++] = unknowns[i];
dv.setUint16(offset, offsets[i], true);
offset+=2;
}
var blob = new Blob([
new Uint32Array([
offsetArraySize,
textArraySize
]),
textArray,
offsetArray,
new Uint32Array([levelEntryCount]),
levelEntries,
new Uint32Array([textArray2Size]),
textArray2
]);
saveAs(blob, filename);
}, false);
}());
</script>