| Mar 8, 2010, 12:00 PM | |
| 
	
		
		
		
		 
		  
			
			Hey Jojo (saga_musix, right?  
		
		
		
		
		
		
		
	 ), I've actually been checking the OpenMPT sourceforge page every now and then so I could write a newspost when a new release is out (as it will contain J2B support) - and I've been using foo_dumb's source for some more insight in the format (though I've moved on to other stuff for the time being). OpenMPT's J2B support is based on foo_dumb's, right?I'm not very knowledgable about digital audio so I'm probably not the one to continue the work, but here's hoping someone uses this information to "finish" the file format spec I started...  | 
| Mar 8, 2010, 12:21 PM | |
| 
	
		
		
		
		 
		  
			
			Yep, this is Saga.  
		
		
		
		
		
		
		
	![]() I've mostly been relying on the foo_dumb indeed, and veryfied that everyone is playing correctly. I really hope that we can push out a new official version of OpenMPT soon, a testing version has been released a few weeks ago and since then, a few bugs have been discovered that need to be fixed before we can release a public version. This will hopefully be the case in a few weeks!  | 
| Aug 15, 2010, 10:20 PM | |
| 
	
		
		
		
		 
		  
			
			Has anyone looked into the save files yet? Primitively, they start out like this: 
		
		
		
		
		
		
			
		
		
		
		
		
			Code: 
	struct save_file {
	char Version[4]; //"23  " for 1.23, "24  " for TSF
	long ImgLen; //length of the first zlib-compressed block, which I believe is the screenshot showed in the Load menu
	(said zlib-compressed block)
	char Name[32]; //Name of save game
	char Filename[32]; //Filename of level saved at (not used)
	char Levelname[32]; //Said level's name (for display on load menu only)
	long Players; //number of players (01-04)
	long Gamemode; //traditional values
	char Unknown[76];
}
I haven't decompressed any of the other blocks, inspected those 84 bytes in more detail, or poked at those middle data (although I have a suspicion of what they might be) because I don't know if I'm just reinventing somebody else's wheel here. Yes? No? Last edited by Violet CLM; Aug 18, 2010 at 07:58 PM.  | 
| Aug 17, 2010, 11:26 PM | |
| 
	
		
		
		
		 
		  
			
			Confirmed that the first zlib block is indeed the save image: 
		
		
		
		
		
		
			
		
		
		
		
		
			![]() I didn't bother loading up the menu palette for that render, so that's just a sixteen-color grayscale palette. The format is a simple bitmap, with each byte ranging in value from 0 to 15 and representing (in reverse order) a color on the 128-143 palette line. ETA: The sixth/final zlib block is the triggers, it's a 32 bit string of zeroes (off) and ones (on). The fifth/penultimate is the dictionary, equivalent to Data3 in a .j2l file and seemingly using the exact same format. The second block seems to contain general info and is always 1444 bytes long. The fourth block is (width*height*4) bytes long, and looks to be the event map, with the otherwise-ignored fourth parameter bit (between difficulty/illuminate and the custom parameters) representing whether the object exists (1) or not (0). Zones, of course, leave this at 0. This event map is read in place of the one stored in the actual .j2l if you die, but is not read at the actual event of loading and will not itself add the sprites it needs. ETA2: Ammo is stored in the second block, starting at offset 1024. First there are nine longs representing ammo (blaster seems to start at 100; Toaster maxes out at 3168 instead of 99, because it depletes more slowly), then nine 0/1 bytes for whether the gun is powered-up or not. Lives are in the same block at offset 416. Score is two longs starting at offset 968; I assume one is the real score and the other is the score it's displaying, which may or may not have finished adding up to the real score. Sugar rush duration is at 1212; shield id (only 01 through 04 have bullets) at 1132 and shield duration at 1136. Health is at 62 and you will die on loading if it's set to 0, forcing the game to load the event map in the fourth block. ETA3: In the main file, the uncompressed data between the third and fourth zlib blocks is a long (minimum of 1), followed by (long-1) units (either longs of value 0 or strings of 128 bytes), representing objects current in memory: Code: 
	struct object {
	long unknown;
	long original Xpos;
	long Ypos;
	long current Xpos;
	char unknown[48];
	byte Strength;
	char unknown[67];
}
 
		Last edited by Violet CLM; Aug 18, 2010 at 08:30 PM.  | 
| Oct 17, 2010, 02:20 PM | |
| 
	
		
		
		
		 
		  
			
			Another question: does anyone know how data3 in .j2t files actually works? What Neobeo says (that it's the same format as data4) seems incorrect or at least only part of the story.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Oct 18, 2010, 06:48 AM | ||
| 
	
		
		
		
		 Quote: 
	
 It works fine in JCS but when playing it in JJ2 it messes up. Screen: ![]() Source for TilesetCompiler (PHP) 
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
||
| Oct 18, 2010, 12:45 PM | |
| 
	
		
		
		
		 
		  
			
			JCS doesn't read data3 at all, so that makes sense. 
		
		
		
		
		
		
			
		
		
		
		
		
			Oh, hey, DJazz! Did you ever figure out how layer speeds worked? I feel I'm really close to finding the right equation but I have a sign wrong somewhere or something like that. Last edited by Violet CLM; Oct 18, 2010 at 01:08 PM.  | 
| Oct 18, 2010, 09:47 PM | ||
| 
	
		
		
		
		 Quote: 
	
 PHP Code: 
	
			
	
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
||
| Oct 18, 2010, 09:58 PM | |
| 
	
		
		
		
		 
		  
			
			Oh, sorry, I meant for displaying relative to the window, not storing. They're definitely multiples of 65536.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Oct 18, 2010, 10:13 PM | ||
| 
	
		
		
		
		 Quote: 
	
 ![]() I'm using this code for WebJCS (JavaScript): PHP Code: 
	
			
	Full source for parallax.js Still, the wanted result is this: http://jazzjackrabbit.net/DJ/LvlView/ 
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
||
| Oct 20, 2010, 01:58 PM | |
| 
	
		
		
		
		 
		  
			
			Got it! For any resolution (width,height) at screen center (xpos,ypos), the top left corner of a window will be equivalent to, for a layer with speeds (xspeed,yspeed), pixel 
		
		
		
		
		
		
			
		
		
		
		
		
			(int((xpos-160)*xspeed-(width-320)/2), int((ypos-100)*yspeed-limitvisibleregion-(height-200)/2)). (xpos, ypos, xspeed, and yspeed are here in nice, pretty units, rather than multiples of 65536; adjust accordingly for your own needs.) (holds true for layers 1-7 only.) Last edited by Violet CLM; Oct 20, 2010 at 02:23 PM.  | 
| Oct 21, 2010, 02:08 PM | |||
| 
	
		
		
		
		 Quote: 
	
 Quote: 
	
 Code: 
	$tmp.=pack("N*",bindec(strrev($tmp3)));
Code: 
	$tmp.=pack("V*",bindec(strrev($tmp3)));
				__________________ 
		
		
		
		
	<TABLE border=1><TR><TD>Facts: Jazz Sprite Dynamite (JSD) Tileset Extractor Neobeo's Firetruck </TD><TD>Myths: Jazz Creation Station Plus (JCS+) - 10% Coming soon - a dedicated server! - 25% Jazz Sprite Dynamite v2 (JSDv2) - 2% Another generic single-player level - 0%</TD></TR></TABLE>  | 
|||
| Oct 21, 2010, 08:45 PM | |
| 
	
		
		
		
		 
		  
			
			They're probably the same format, I haven't looked in great detail, but there's more stuff in there too. Data4 seems to be nothing but 128-byte strings, but Data3 has some information between the strings and thus the offsets are not nice pretty multiples of 128.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Oct 21, 2010, 09:52 PM | |
| 
	
		
		
		
		 
		  
			
			Same result... I changed to N because V didnt work, forgot to change back
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
| Oct 22, 2010, 07:12 AM | |
| 
	
		
		
		
		 
		  
			
			I made a little comparison between TilesetCompiler's data3 and JCS's data3, as seen in the image below. 
		
		
		
		
		
		
			I use unpack to "split" the stream into longs, and decbin to convert it to a binary string. The "tiles" are splitted with a line. I used automask in both, and JCS's mask and TilesetCompiler's mask are equal (same as PHP's data3, because of automask). Below the black there's the tileset I used. ![]() I was using this code: PHP Code: 
	
			
	
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
| Oct 22, 2010, 02:01 PM | ||
| 
	
		
		
		
		 Quote: 
	
 PHP Code: 
	
			
	
				__________________ 
		
		
		
		
		
			<TABLE border=1><TR><TD>Facts: Jazz Sprite Dynamite (JSD) Tileset Extractor Neobeo's Firetruck </TD><TD>Myths: Jazz Creation Station Plus (JCS+) - 10% Coming soon - a dedicated server! - 25% Jazz Sprite Dynamite v2 (JSDv2) - 2% Another generic single-player level - 0%</TD></TR></TABLE> Last edited by Neobeo; Oct 22, 2010 at 02:05 PM. Reason: decreased code indent  | 
||
| Oct 22, 2010, 03:48 PM | |
| 
	
		
		
		
		 
		  
			
			I'll update data1 in j2l files on the wiki if you explain what that stuff is in words or a struct instead of oddly-colored php.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Oct 22, 2010, 04:00 PM | ||
| 
	
		
		
		
		 Quote: 
	
 Code: 
	For each row {
    Read one byte (this tells you how many contiguous opaque regions there are in the row) and call this byte n
    The next 2n bytes tell you alternatingly how many bytes to skip and how many bytes to draw
}
				__________________ 
		
		
		
		
	<TABLE border=1><TR><TD>Facts: Jazz Sprite Dynamite (JSD) Tileset Extractor Neobeo's Firetruck </TD><TD>Myths: Jazz Creation Station Plus (JCS+) - 10% Coming soon - a dedicated server! - 25% Jazz Sprite Dynamite v2 (JSDv2) - 2% Another generic single-player level - 0%</TD></TR></TABLE>  | 
||
| Oct 23, 2010, 02:53 AM | ||
| 
	
		
		
		
		 Quote: 
	
 Works in a recent Firefox and in Chrome/Chromium. 
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
||
| Oct 23, 2010, 09:14 AM | ||
| 
	
		
		
		
		 Quote: 
	
 
				__________________ 
		
		
		
		
	 | 
||
| Oct 23, 2010, 10:49 AM | |
| 
	
		
		
		
		 
		  
			
			Yes. Of course, it would be simpler just not to have a colored pixel there at all.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Oct 23, 2010, 10:54 AM | |
| 
	
		
		
		
		 
		  
			
			Awesome. So there is a way to use pure #000 black in JJ2 after all.
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	 | 
| Nov 17, 2010, 02:49 PM | ||
| 
	
		
		
		
		 Quote: 
	
 See live demo: http://jazzjackrabbit.net/DJ/WebJJ2/ Javascript code out of context: Code: 
	finalpos = [(rx*Layers[i].width)+Math.floor(x*32-(lastCamPos[0]+160)*Layers[i].XSpeed)+(640-320)/2, (ry*Layers[i].height)+Math.floor(y*32-(lastCamPos[1]+100)*Layers[i].YSpeed)+(480-200)/2]; 
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
||
| Nov 17, 2010, 07:50 PM | |
| 
	
		
		
		
		 
		  
			
			If you're going with a fixed resolution, you should probably simplify the (640-320)/2-type segments. :P And it looks like you don't have the Limit Visible Region modifier in there, which is 140 pixels at 640x480. (I'm sure it's an easy enough calculation for the other resolutions, I've just never run the numbers.) 
		
		
		
		
		
		
			
		
		
		
		
		
			ETA: So that future readers don't have to do the math themselves, the LVR modifier is also (height-200)/2, so you needn't divide by two if LVR is on for the layer. Last edited by Violet CLM; Jun 27, 2011 at 06:39 PM.  | 
| Jul 9, 2011, 04:51 AM | |
| 
	
		
		
		
		 
		  
			
			My first and crappy old source for reading the tileset-pic itself out of a tileset, I'm currently working on new reader units (with classes,...), but this can helpful for pascal / delphi beginners (even if its not very good written) that want to try to decrypt the fileformats 
		
		
		
		
		
		
			JJFHack.pas: Mainly for reading and uncompressing zlib-compressed files (used ZlibEx for uncompressing, normal zlib should work as well): Code: 
	unit JJFHack;
interface
uses
  SysUtils, Classes, StdCtrls, ZLibEx;
Function StartJJF(FileName:String):Boolean;
procedure LoadBinary(var Memo:TMemo);
procedure LoadBinaryFunc(var Data; Count:Cardinal; Memo:TMemo);
function GetZlibStreamPos:Integer;
procedure AddZlibStreamPos(Position : Integer);
procedure GetCVar(const Position:Integer);
function ReadCVar(Number:Integer):Integer;
procedure GetUVar(const Position:Integer);
function Uncompress(const Index:Integer; MemoryStream:TMemoryStream):Boolean;
function Compress(var MemoryStream:TMemoryStream; const Index:Integer):Boolean;
function ReadString(var MemoryStream:TMemorystream; const Position, StrLength : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):AnsiString;
procedure WriteString(var MemoryStream:TMemorystream; InputStr : Ansistring; const Position, StrLength : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
function ReadInteger(var MemoryStream:TMemorystream; const Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):Integer;
procedure WriteInteger(var MemoryStream:TMemorystream; const InputInt, Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
function ReadWord(var MemoryStream:TMemorystream; const Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):Word;
procedure WriteWord(var MemoryStream:TMemorystream; const InputWord:Word; Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
procedure WriteByte(var MemoryStream:TMemorystream; const InputByte:Byte; Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
function ReadByte(var MemoryStream:TMemorystream; const Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):Byte;
Procedure FreeJJF;
var
FStream : TFileStream;
ZLList, CList, UList : TStringlist;
implementation
//File in einen Stream Laden
Function StartJJF(FileName:String):Boolean;
begin
  ZLList := TStringlist.Create;
  CList := TStringlist.Create;
  UList := TStringlist.Create;
  try
  FStream := TFileStream.Create(FileName,fmOpenReadWrite);
  Result := True;
  except
  Result := False;
  end;
end;
//Lädt einen Stream in Memo (aufruf: LoadBinaryFunc(MS.Memory^,MS.Size,Memo)
procedure LoadBinaryFunc(var Data; Count: Cardinal; Memo: TMemo);
var
  line: string[80];
  i: Cardinal;
  p: PAnsiChar;
  nStr: string[4];
const
  posStart = 1;
  binStart = 7;
  ascStart = 57;
  HexChars: PAnsiChar = '0123456789ABCDEF';
begin
  p    := @Data;
  line := '';
  for i := 0 to Count - 1 do
  begin
    if (i mod 16) = 0 then
    begin
      if Length(line) > 0 then
        Memo.Lines.Add(line);
      FillChar(line, SizeOf(line), ' ');
      line[0] := Chr(72);
      nStr    := Format('%4.4X', [i]);
      Move(nStr[1], line[posStart], Length(nStr));
      line[posStart + 4] := ':';
    end;
    if p[i] >= ' ' then
      line[i mod 16 + ascStart] := p[i]
    else
      line[i mod 16 + ascStart] := '.';
    line[binStart + 3 * (i mod 16)]     := HexChars[(Ord(p[i]) shr 4) and $F];
    line[binStart + 3 * (i mod 16) + 1] := HexChars[Ord(p[i]) and $F];
  end;
  Memo.Lines.Add(line);
end;
//Lädt Momentan genutzen FileStream in Memo
procedure LoadBinary(var Memo:TMemo);
var MStream:TMemoryStream;
begin
  MStream.Create;
  try
    MStream.LoadFromStream(FStream);
    LoadBinaryFunc(MStream.Memory^,MStream.Size,Memo);
  finally
    MStream.Free;
  end;
end;
//Speichert Adressen der Komprimierten Streams in Stringlist, Rückgabewert: Anzahl
function GetZlibStreamPos:Integer;
var
I, I2 : Integer;
B1, B2 : Byte;
begin
  ZLList.Clear;
  I2 := 0;
       for I := 0 to FStream.Size do
           begin
             FStream.Seek(I,soFromBeginning);
             FStream.Read(B1,1);
             FStream.Seek(I+1,soFromBeginning);
             FStream.Read(B2,1);
             if (B1=$78) and (B2=$DA) then
                begin
                  I2 := I2+1;
                  ZLList.Add(IntToStr(I));
                end;
           end;
       Result := I2;
end;
procedure AddZlibStreamPos(Position : Integer);
begin
  ZLList.Add(IntToStr(Position));
end;
//Speichert Länge des komprimierten Sterams in StringList
procedure GetCVar(const Position:Integer);
var TmpInt : Integer;
begin
   FStream.Seek(Position,soFromBeginning);
   FStream.Read(TmpInt,4);
   FStream.Seek(0,soFromBeginning);
   CList.Add(IntToStr(TmPInt));
end;
function ReadCVar(Number:Integer):Integer;
begin
  Result := StrToInt(Clist[Number]);
end;
//Speichert Länge des unkomprimierten Streams in StringList (nicht zwingend notwendig)
procedure GetUVar(const Position:Integer);
var TmpInt : Integer;
begin
   FStream.Seek(Position,soFromBeginning);
   FStream.Read(TmpInt,4);
   FStream.Seek(0,soFromBeginning);
   UList.Add(IntToStr(TmPInt));
end;
//Dekomprimiert, Ausgabe sind MemoryStream und Boolean obs geklappt hat
function Uncompress(const Index:Integer; MemoryStream:TMemoryStream):Boolean;
var
InChr : PAnsiChar;
OutBuf : Pointer;
OutBytes : Integer;
begin
  try
    InChr := AllocMem(StrToInt(CList[Index]));
    fStream.Seek(StrtoInt(ZLList[Index]),soFromBeginning);
    fStream.Read(InChr^,StrToInt(CList[Index]));
    fStream.Seek(0,soFromBeginning);
    ZDecompress(InChr,StrToInt(CList[Index]),OutBuf,OutBytes);
    MemoryStream.Write(OutBuf^, OutBytes);
    if (UList[Index] <> '') and (OutBytes=StrToInt(UList[Index])) then
       Result := True Else
       Result := False;
  except
    Result := False;
  end;
end;
//Komprimiert, Ausgabe gibts obs geklappt hat und der neue String gleich lang ist
function Compress(var MemoryStream:TMemoryStream; const Index:Integer):Boolean;
var
InChr : PAnsiChar;
OutBuf : Pointer;
OutBytes : Integer;
begin
  try
    InChr := AllocMem(MemoryStream.Size);
    MemoryStream.Position := 0;
    MemoryStream.Read(InChr^,MemoryStream.Size);
    MemoryStream.Position := 0;
    ZCompress(InChr,MemoryStream.Size,OutBuf,OutBytes,zcLevel9);
    fStream.Seek(StrtoInt(ZLList[Index]),soFromBeginning);
    fStream.Write(OutBuf^,OutBytes);
    fStream.Seek(0,soFromBeginning);
    if (CList[Index] <> '') and (OutBytes=StrToInt(CList[Index])) then
       Result := True Else
       Result := False;
  except
    Result := False;
  end;
end;
//Lese String aus Stream, var MemoryStream wird ignoriert wenn Filestream genutzt wird
function ReadString(var MemoryStream:TMemorystream;
         const Position, StrLength : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):AnsiString;
var TmpStr : AnsiString;
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       SetLength(TmpStr,StrLength);
       FStream.Read(TmpStr[1],StrLength);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       SetLength(TmpStr,StrLength);
       MemoryStream.Read(TmpStr[1],StrLength);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
       Result := TmpStr;
end;
//Schreibe String in den entsperchenden Stream
procedure WriteString(var MemoryStream:TMemorystream; InputStr : Ansistring;
          const Position, StrLength : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
begin
  if Length(InputStr) > StrLength then
     SetLength(InputStr,StrLength);
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Write(PChar(InputStr)^,StrLength);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Write(PChar(InputStr)^,StrLength);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Lese Integer aus Stream
function ReadInteger(var MemoryStream:TMemorystream;
         const Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):Integer;
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Read(Result,4);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Read(Result,4);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Schreibe Integer in den entsprechende Stream
procedure WriteInteger(var MemoryStream:TMemorystream;
         const InputInt, Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Write(InputInt,4);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Write(InputInt,4);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Read Word aus Stream
function ReadWord(var MemoryStream:TMemorystream;
         const Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):Word;
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Read(Result,2);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Read(Result,2);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Schreibe Word in den entsprechende Stream
procedure WriteWord(var MemoryStream:TMemorystream;
         const InputWord:Word; Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Write(InputWord,2);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Write(InputWord,2);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Read Byte aus Stream, var MemoryStream wird ignoriert wenn Filestream genutzt wird
function ReadByte(var MemoryStream:TMemorystream;
         const Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False):Byte;
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Read(Result,1);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Read(Result,1);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Schreibe Word in den entsprechende Stream
procedure WriteByte(var MemoryStream:TMemorystream;
         const InputByte:Byte; Position : Integer; UseFilestream:Boolean=False;NotReadLast:Boolean=False;NotSetBack:Boolean=False);
begin
  if UseFileStream = True then
     begin
       if NotReadLast = False then
       FStream.Seek(Position,soFromBeginning);
       FStream.Write(InputByte,1);
       if NotSetBack = False then
       FStream.Seek(0,soFromBeginning);
     end Else
     begin
       if NotReadLast = False then
       MemoryStream.Position:=Position;
       MemoryStream.Write(InputByte,1);
       if NotSetBack = False then
       MemoryStream.Position:=0;
     end;
end;
//Schreibe das File und schließe alle offenen Streams (der komponente!)
procedure FreeJJF;
begin
   try
     FStream.Free;
   except
   end;
   try
     ZLList.Free;
   except
   end;
   try
     CList.Free;
   except
   end;
   try
     UList.Free;
   except
   end;
end;
end.
 :Code: 
	unit JJFHackTileset;
interface
uses JJFhack, Math, SysUtils, Classes, StdCtrls, Messages,Windows,
     Graphics, GR32, ImgList ,Controls;
type TBit = 0..1;
Function OpenTileSet(const TileSetFileName : String):Byte;
Procedure ReadDataStream(const StreamNumber : Byte);
Procedure ReadPalette;
Function GetUsed_Tiles:Integer;
Procedure GetTileAddr;
Procedure GetMaskAddr;
Procedure GetTileSetImage;
Procedure GetMaskVars;
Procedure GetMaskImage;
Procedure LoadTiles(Bitmap:TBitmap32);
Procedure LoadTiles2(Bitmap:TBitmap);
Procedure LoadTilestoList(ImgList:TImageList);
procedure FlipList(ImgList,FlippedImgList:TImageList);
Procedure LoadMask(Bitmap:TBitmap);
Procedure FreeTileSet;
var
MAX_TILES : Integer;
DataStream : Array [0..3] of TMemoryStream;
DataStreamBool : Array [0..3] of Boolean;
Palette : Array [0..255,0..2] of Byte;
TileAddr,MaskAddr : Array of Integer;
TileColorArray : Array of Array [0..1023] of Array [0..2] of Byte;
MaskColorArray : Array of Array [0..1023] of TColor;
MaskBoolArray : Array of Boolean;
TileSetName : AnsiString;
type
  TRGBArray = array[0..0] of TRGBTriple;
  pRGBArray = ^TRGBArray;
implementation
function Significance(DigitNr: Byte; Base: Byte): integer; overload;
begin
  result := Round(Power(Base,DigitNr));
end;
function Significance(BitNr: Byte): integer; overload;
begin
  result := Round(Significance(BitNr,2));
end;
function GetBit(Value: longint; BitNr: Byte): TBit;
begin
  result := Value and Significance(BitNr);
end;
function BitToBool(Bit: TBit): Boolean;
begin
  case Bit of
    0: result := False;
    1: result := True;
  end;
end;
function RGB2TColor(R, G, B: Byte): Integer;
begin
  // convert hexa-decimal values to RGB
  Result := R or (G shl 8) or (B shl 16);  // ich mochte das OR halt viel lieber
end;
Function OpenTileSet(const TileSetFileName : String):Byte;
var
Tmp : TMemoryStream; //Temporary, this is not used
FVersion : Word; //TileSetVersion
begin
  If JJFHack.StartJJF(TileSetFileName) = False then
     begin Result := 1; JJFHack.FreeJJF; end Else
     begin
  If JJFHack.ReadString(Tmp,180,4,True) <> 'TILE' then
     begin Result := 2; JJFHack.FreeJJF; end Else
     begin
     TileSetname := JJFHack.ReadString(Tmp,188,32,True);
     FVersion := JJFHack.ReadWord(Tmp,220,True);
  If FVersion = $200 then
     MAX_TILES := 1024 Else
  If FVersion = $201 then
     MAX_TILES := 4096 Else
     begin
       Result := 3;
       JJFHack.FreeJJF;
       exit;
     end;
        //Informations for Data1:
         JJFhack.GetCVar($E6);
         JJFhack.GetUVar($EA);
         JJFHack.AddZlibStreamPos($106);
       //Informations for Data2:
         JJFhack.GetCVar($EE);
         JJFhack.GetUVar($F2);
         JJFHack.AddZlibStreamPos($106+JJFHack.ReadCVar(0));
       //Informations for Data3:
         JJFhack.GetCVar($F6);
         JJFhack.GetUVar($FA);
         JJFHack.AddZlibStreamPos($106+JJFHack.ReadCVar(0)+JJFHack.ReadCVar(1));
       //Informations for Data4:
         JJFhack.GetCVar($FE);
         JJFhack.GetUVar($102);
         JJFHack.AddZlibStreamPos($106+JJFHack.ReadCVar(0)+JJFHack.ReadCVar(1)+JJFHack.ReadCVar(2));
     Result := 0;
     end;
     end;
end;
Procedure ReadDataStream(const StreamNumber : Byte);
begin
 if DataStreamBool[StreamNumber] = False then
 begin
 DataStream[StreamNumber] := TMemoryStream.Create;
 JJFHack.Uncompress(StreamNumber,DataStream[StreamNumber]);
 end;
 DataStreamBool[StreamNumber] := True;
end;
Procedure ReadPalette;
var
I : Integer;
begin
  ReadDataStream(0);
  for I := 0 to Length(Palette) - 1 do
      begin
        Palette[I,0] := JJFHack.ReadByte(DataStream[0],I*4);
        Palette[I,1] := JJFHack.ReadByte(DataStream[0],1+I*4);
        Palette[I,2] := JJFHack.ReadByte(DataStream[0],2+I*4);
      end;
end;
Function GetUsed_Tiles:Integer;
begin
  ReadDataStream(0);
  Result := JJFHack.ReadInteger(DataStream[0],$400);
end;
Procedure GetTileAddr;
var
TmPAddr, I : Integer;
begin
  ReadDataStream(0);
  TmpAddr := $404 + (2*MAX_TILES);
  SetLength(TileAddr,GetUsed_Tiles);
  for I := 0 to Length(TileAddr) - 1 do
      TileAddr[I] := JJFHack.ReadInteger(DataStream[0],TmpAddr+(I*4));
end;
Procedure GetMaskAddr;
var
TmPAddr, I : Integer;
begin
  ReadDataStream(0);
  TmpAddr := $404 + (10*MAX_TILES);
  SetLength(MaskAddr,GetUsed_Tiles);
  for I := 0 to Length(MaskAddr) - 1 do
      MaskAddr[I] := JJFHack.ReadInteger(DataStream[0],TmpAddr+(I*4));
end;
Procedure GetTileSetImage;
var I, I2 : Integer;
begin
  ReadPalette;
  GetTileAddr;
  SetLength(TileColorArray,GetUsed_Tiles);
  ReadDataStream(1);
  for I := 0 to Length(TileAddr) - 1 do
      begin
        for I2 := 0 to 1023 do
            begin
             TileColorArray[I,I2,0] := Palette[JJFHack.ReadByte(DataStream[1],TileAddr[I]+I2),0];
             TileColorArray[I,I2,1] := Palette[JJFHack.ReadByte(DataStream[1],TileAddr[I]+I2),1];
             TileColorArray[I,I2,2] := Palette[JJFHack.ReadByte(DataStream[1],TileAddr[I]+I2),2];
            end;
      end;
end;
Procedure GetMaskVars;
var
I, I2, I3, TmPInt, I4 : Integer;
B1, B0 :Byte;
begin
  I4 := 0;
  GetMaskAddr;
  ReadDataStream(2);
  SetLength(MaskBoolArray,Length(MaskAddr)*1024);
  for I := 0 to Length(MaskAddr) - 1 do
      begin
        for I2 := 0 to 31 do
            begin
             TmPInt := JJFHack.ReadInteger(DataStream[2],MaskAddr[I]+(I2*4));
             for I3 := 0 to 31 do
                 begin
                 MaskBoolArray[I4] := BitToBool(GetBit(TmPInt,I3));
                 I4 := I4 +1;
                 end;
            end;
      end;
end;
Procedure GetMaskImage;
var I, I2 : Integer;
begin
  GetMaskVars;
  SetLength(MaskColorArray,Length(MaskAddr));
  for I := 0 to Length(MaskAddr) do
      begin
        for I2 := 0 to 1023 do
            begin
            if MaskBoolArray[MaskAddr[I]+I2] = True then
                MaskColorArray[I,I2] := $FFFFFF Else
                MaskColorArray[I,I2] := $000000;
            end;
      end;
end;
Procedure LoadTiles(Bitmap:TBitmap32);
var
I, I2, TilePosX, TilePosY, X, Y : Integer;
LogPal  : TMaxLogPalette;
hPal : hPalette;
PLogPal : PLogPalette;
begin
   GetTileSetImage;
   Bitmap.Width := 320;
   Bitmap.Height := (Length(TileAddr)Div 10)*32;
   with LogPal do begin
        palVersion:=$0300;
        palNumEntries:=256;
        for i:=0 to 255 do begin
            with palPalEntry[i] do begin
                 peRed  := Palette[I,0];
                 peGreen:= Palette[I,1];
                 peBlue := Palette[I,2];
                 peFlags:=0;
            end;
       end;
   end;
   pLogPal:=@LogPal;
   hPal:=CreatePalette(pLogPal^);
   //Bitmap.PixelFormat:=pf8Bit;
   //Bitmap.Palette:=hPal;
         for I2 := 0 to Length(TileAddr)-1 do
          begin
          if I2 = 0 then
             begin
               TilePosX := 0;
               TilePosY := 0;
             end Else
             begin
          if TilePosX < 9 then
             TilePosX := TilePosX+1 Else
             begin
               TilePosX := 0;
               TilePosY := TilePosY+1;
             end;
             end;
          for I := 0 to 1023 do
              begin
                if I = 0 then
                   begin
                     x := 0;
                     y := 0;
                   end Else
                   begin
                     if x < 31 then
                        x := x +1 Else
                     begin
                        x := 0;
                        y := y+1;
                     end;
                   end;
               Bitmap.Canvas.Pixels[X+(TilePosX*32),Y+(TilePosY*32)] := RGB2TColor(TileColorArray[I2,I,0],TileColorArray[I2,I,1],TileColorArray[I2,I,2]);
              end;
          end;
end;
Procedure LoadTiles2(Bitmap:TBitmap);
var
I, I2, TilePosX, TilePosY, X, Y : Integer;
LogPal  : TMaxLogPalette;
hPal : hPalette;
PLogPal : PLogPalette;
begin
   GetTileSetImage;
   Bitmap.Width := 320;
   Bitmap.Height := (Length(TileAddr)Div 10)*32;
   with LogPal do begin
        palVersion:=$0300;
        palNumEntries:=256;
        for i:=0 to 255 do begin
            with palPalEntry[i] do begin
                 peRed  := Palette[I,0];
                 peGreen:= Palette[I,1];
                 peBlue := Palette[I,2];
                 peFlags:=0;
            end;
       end;
   end;
   pLogPal:=@LogPal;
   hPal:=CreatePalette(pLogPal^);
   //Bitmap.PixelFormat:=pf8Bit;
   //Bitmap.Palette:=hPal;
         for I2 := 0 to Length(TileAddr)-1 do
          begin
          if I2 = 0 then
             begin
               TilePosX := 0;
               TilePosY := 0;
             end Else
             begin
          if TilePosX < 9 then
             TilePosX := TilePosX+1 Else
             begin
               TilePosX := 0;
               TilePosY := TilePosY+1;
             end;
             end;
          for I := 0 to 1023 do
              begin
                if I = 0 then
                   begin
                     x := 0;
                     y := 0;
                   end Else
                   begin
                     if x < 31 then
                        x := x +1 Else
                     begin
                        x := 0;
                        y := y+1;
                     end;
                   end;
               Bitmap.Canvas.Pixels[X+(TilePosX*32),Y+(TilePosY*32)] := RGB2TColor(TileColorArray[I2,I,0],TileColorArray[I2,I,1],TileColorArray[I2,I,2]);
              end;
          end;
end;
Procedure LoadTilestoList(ImgList:TImageList);
var
I, I2, X, Y : Integer;
LogPal  : TMaxLogPalette;
hPal : hPalette;
PLogPal : PLogPalette;
Bitmap : TBitmap;
begin
   Bitmap := TBitmap.Create;
   try
   GetTileSetImage;
   Bitmap.Width := 32;
   Bitmap.Height := 32;
   {Bitmap.Width := 320;
   Bitmap.Height := (Length(TileAddr)Div 10)*32;   }
   with LogPal do begin
        palVersion:=$0300;
        palNumEntries:=256;
        for i:=0 to 255 do begin
            with palPalEntry[i] do begin
                 peRed  := Palette[I,0];
                 peGreen:= Palette[I,1];
                 peBlue := Palette[I,2];
                 peFlags:=0;
            end;
       end;
   end;
   pLogPal:=@LogPal;
   hPal:=CreatePalette(pLogPal^);
   Bitmap.PixelFormat:=pf8Bit;
   Bitmap.Palette:=hPal;
         for I2 := 0 to Length(TileAddr)-1 do
          begin
          for I := 0 to 1023 do
              begin
                if I = 0 then
                   begin
                     x := 0;
                     y := 0;
                   end Else
                   begin
                     if x < 31 then
                        x := x +1 Else
                     begin
                        x := 0;
                        y := y+1;
                     end;
                   end;
               Bitmap.Canvas.Pixels[X,Y] := RGB2TColor(TileColorArray[I2,I,0],TileColorArray[I2,I,1],TileColorArray[I2,I,2]);
              end;
               ImgList.Add(Bitmap,Nil);
          end;
   finally
     Bitmap.Free;
   end;
end;
//Flip einzelnes Img:
procedure FlipImg(const Bitmap: TBitmap);
var  Pict:TBitmap;
begin
  (* neue Bitmap erzeugen *)
  Pict:=TBitmap.Create;
  (* zu spiegelnde Bitmap zuweisen *)
  Pict.Assign(Bitmap);
  //Vertical:
  StretchBlt(Pict.Canvas.Handle, 0, 0, Pict.Width,
    Pict.Height, Bitmap.Canvas.Handle,
    Bitmap.Width-1, 0, -Bitmap.Width, Bitmap.Height, srccopy);
  //Horzontal:
  {
  StretchBlt(Pict.Canvas.Handle, 0, 0,
    Pict.Width, Pict.Height, Bitmap.Canvas.Handle,
    0, Bitmap.Height-1, Bitmap.Width, -Bitmap.Height, srccopy);     }
  (* das Alte gegen das Neue Bild austauschen *)
  Bitmap.Assign(Pict);
  Pict.Free
end;
procedure FlipList(ImgList,FlippedImgList:TImageList);
var
  TmpBmp: TBitmap;
  I: Integer;
begin
  TmpBmp := TBitmap.Create;
  TmpBmp.Height :=32;
  TmpBmp.Width :=32;
  try
  for I := 0 to ImgList.Count - 1 do
      begin
        ImgList.GetBitmap(I,TmpBmp);
        FlipImg(TmpBmp);
        FlippedImgList.Add(TmpBmp,nil);
      end;
  finally
    TmpBmp.Free;
  end;
end;
Procedure LoadMask(Bitmap:TBitmap);
var I, I2, X, Y, TilePosX, TilePosY : Integer;
begin
  GetMaskImage;
  Bitmap.Width := 320;
  Bitmap.Height := (Length(MaskAddr)Div 10)*32;
  Bitmap.PixelFormat:=pf8Bit;
         for I2 := 0 to Length(MaskAddr)-1 do
          begin
          if I2 = 0 then
             begin
               TilePosX := 0;
               TilePosY := 0;
             end Else
             begin
          if TilePosX < 9 then
             TilePosX := TilePosX+1 Else
             begin
               TilePosX := 0;
               TilePosY := TilePosY+1;
             end;
             end;
          for I := 0 to 1023 do
              begin
                if I = 0 then
                   begin
                     x := 0;
                     y := 0;
                   end Else
                   begin
                     if x < 31 then
                        x := x +1 Else
                     begin
                        x := 0;
                        y := y+1;
                     end;
                   end;
               Bitmap.Canvas.Pixels[X+(TilePosX*32),Y+(TilePosY*32)] := MaskColorArray[I2,I];
              end;
          end;
end;
Procedure FreeTileSet;
var I:Integer;
begin
  for I := 0 to 3 do
      begin
        DataStream[I].Free;
        DataStreamBool[I] := False;
      end;
  JJFHack.FreeJJF;
end;
end.
				__________________ 
		
		
		
		
		
			![]() I'm watching you!! Last edited by Sfaizst; Jul 9, 2011 at 05:03 AM.  | 
| Dec 5, 2011, 12:18 PM | |
| 
	
		
		
		
		 
		  
			
			I was able to extract the sound effects/sample data from the Anims.j2a file! 
		
		
		
		
		
		
			Place Anims.j2a in the same folder as this PHP script, it will create .wav files for each sample. Download zip containing .wav files: http://djazz.mine.nu/files/sfxTSF_wav.zip Listen to an extract here: PHP Code: 
	
			
	
				__________________ 
		
		
		
		
		
			WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler Last edited by djazz; Dec 6, 2011 at 12:46 AM. Reason: Added wav output instead of raw output  | 
| Dec 5, 2011, 12:20 PM | |
| 
	
		
		
		
		 
		  
			
			...is that an unused Lori hurt sound? You can definitely tell why it didn't work out.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Dec 5, 2011, 12:28 PM | |
| 
	
		
		
		
		 
		  
			
			The Anims.j2a library contains lots lots of unused sounds, and animations.
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
| Dec 5, 2011, 02:34 PM | |
| 
	
		
		
		
		 
		  
			
			I thought these were all extracted before? Because I have a complete folder of JJ2 samples in wav on my PC, and if I remember well I got them from somewhere around here.
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	"So unless I overwrote my heart with yours, I think not. But I might have." - Violet CLM Two Games Joined releases: Control / Splinter (twin singles) || Ballistic Bunny (EP) || Beyond (maxi-single) || Beyond: Remixed (remix EP) || Inner Monsters OST (mini-album) || Shadows (album)  | 
| Dec 5, 2011, 10:12 PM | |
| 
	
		
		
		
		 
		  
			
			Well, while we're submitting code I thought I should submit a full sound-playing C# code that doesn't use any libraries outside the .NET framework. This plays the input sample number as per the Ambient Sound sequence. For TSF, sound #306 is called sLORISOUNDS_TOUCH. Too bad ambient sound only goes up to 255 though... 
		
		
		
		
		
		
			Code: 
	using System;
using System.IO;
using System.IO.Compression;
namespace jj2sound
{
    class Program
    {
        static readonly byte[] magic = { 82, 73, 70, 70, 87, 65, 86, 69, 102, 109, 116, 32,
                                                16, 0, 0, 0, 1, 0, 1, 0, 100, 97, 116, 97 };
        static void Main()
        {
            using (var br = new BinaryReader(File.OpenRead(@"D:\Games\Jazz2TSF\Anims.j2a")))
            {
                br.ReadBytes(24);
                int i, s, sets = br.ReadInt32();
                while (true)
                {
                    Console.Write("Play sample #");
                    if (!int.TryParse(Console.ReadLine(), out s) || s < 0) break;
                    for (i = 0; i < sets; i++)
                    {
                        br.BaseStream.Position = 28 + i * 4;
                        br.BaseStream.Position = br.ReadInt32() + 5;
                        int samples = br.ReadByte();
                        if (s < samples) break;
                        else s -= samples;
                    }
                    if (i == sets) break;
                    br.ReadBytes(6);
                    int[] size = new int[8]; for (i = 0; i < 8; i++) size[i] = br.ReadInt32();
                    br.ReadBytes(size[0] + size[2] + size[4] + 2);
                    using (var bz = new BinaryReader(new DeflateStream(br.BaseStream, 0, true)))
                    {
                        for (i = 0; i < s; i++) bz.ReadBytes(bz.ReadInt32() - 4);
                        bz.ReadBytes(64);
                        int mul = bz.ReadInt16() / 4 + 1; bz.ReadInt16();
                        int length = bz.ReadInt32(); bz.ReadInt64();
                        int rate = bz.ReadInt32(); bz.ReadInt64();
                        Console.WriteLine("Length: {0:0.000}s", (double)length / rate);
                        length *= mul;
                        using (var bw = new BinaryWriter(new MemoryStream()))
                        {
                            bw.Write(magic, 0, 4);
                            bw.Write(length + 36);
                            bw.Write(magic, 4, 16);
                            bw.Write(rate);
                            bw.Write(rate * mul);
                            bw.Write(mul * 0x80001);
                            bw.Write(magic, 20, 4);
                            bw.Write(length);
                            for (i = 0; i < length; i++) bw.Write((byte)(bz.ReadByte() ^ (mul << 7)));
                            bw.Seek(0, 0);
                            new System.Media.SoundPlayer(bw.BaseStream).PlaySync();
                        }
                    }
                }
            }
            Console.WriteLine("Sample not found. Press any key to continue.");
            Console.ReadKey();
        }
    }
}
				__________________ 
		
		
		
		
	<TABLE border=1><TR><TD>Facts: Jazz Sprite Dynamite (JSD) Tileset Extractor Neobeo's Firetruck </TD><TD>Myths: Jazz Creation Station Plus (JCS+) - 10% Coming soon - a dedicated server! - 25% Jazz Sprite Dynamite v2 (JSDv2) - 2% Another generic single-player level - 0%</TD></TR></TABLE>  | 
| Dec 5, 2011, 10:46 PM | |
| 
	
		
		
		
		 
		  
			
			Mind if I steal that?
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Dec 5, 2011, 11:00 PM | |
| 
	
		
		
		
		 
		  
			
			Sure, go ahead!
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	<TABLE border=1><TR><TD>Facts: Jazz Sprite Dynamite (JSD) Tileset Extractor Neobeo's Firetruck </TD><TD>Myths: Jazz Creation Station Plus (JCS+) - 10% Coming soon - a dedicated server! - 25% Jazz Sprite Dynamite v2 (JSDv2) - 2% Another generic single-player level - 0%</TD></TR></TABLE>  | 
| Dec 6, 2011, 12:49 AM | |
| 
	
		
		
		
		 
		  
			
			I edited my post above with the edited code to output wav files, once again, thanks for letting me steal your code ^^ 
		
		
		
		
		
		
			Btw, found two new weird lori sounds: Wtf? Enjoy! 
				__________________ 
		
		
		
		
	WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler  | 
| Dec 6, 2011, 03:04 AM | |
| 
	
		
		
		
		 
		  
			
			I suppose these two Lori samples were meant for a new intro, I believe it was said that one was planned as well as a whole storyline for TSF, but it all got scrapped. 
		
		
		
		
		
		
			What about this one, guys? ![]() 
				__________________ 
		
		
		
		
	"So unless I overwrote my heart with yours, I think not. But I might have." - Violet CLM Two Games Joined releases: Control / Splinter (twin singles) || Ballistic Bunny (EP) || Beyond (maxi-single) || Beyond: Remixed (remix EP) || Inner Monsters OST (mini-album) || Shadows (album)  | 
| Dec 6, 2011, 11:03 AM | |
| 
	
		
		
		
		 
		  
			
			Over the past years we've done so many things with JJ2 by figuring out how it works down below. Really, isn't there some way to make JJ2 play samples with a higher index? Has anyone ever tried to find out?
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	 | 
| Dec 6, 2011, 11:48 AM | |
| 
	
		
		
		
		 
		  
			
			I can't imagine you could do anything about that in JCS. It's not like Set Light where the parameter sizes in JCS.ini don't match up with how JJ2 reads them. There are more parameter bits following those used for specifying the sample, but they're dedicated to Amplify and so on.
		 
		
		
		
		
		
		
			
		
		
		
		
	 | 
| Dec 6, 2011, 12:45 PM | |
| 
	
		
		
		
		 
		  
			
			For JJ2 to be able to look up a sound sample with an ID above 255 it needs to address those with at least a two-byte number. Since it gets only one byte from the event parameter, maybe we can somehow get it to fill the other(s) with something else than zeros. It would probably be a dirty bug if this is possible, but little would surprise me anymore.
		 
		
		
		
		
		
		
			
				__________________ 
		
		
		
		
	 | 
| Dec 6, 2011, 07:03 PM | ||
| 
	
		
		
		
		 Quote: 
	
 
				__________________ 
		
		
		
		
	<TABLE border=1><TR><TD>Facts: Jazz Sprite Dynamite (JSD) Tileset Extractor Neobeo's Firetruck </TD><TD>Myths: Jazz Creation Station Plus (JCS+) - 10% Coming soon - a dedicated server! - 25% Jazz Sprite Dynamite v2 (JSDv2) - 2% Another generic single-player level - 0%</TD></TR></TABLE>  | 
||
| Dec 10, 2011, 11:35 PM | |
| 
	
		
		
		
		 
		  
			
			I made a JJ2 sfx soundboard in JavaScript. 
		
		
		
		
		
		
			It's multithreaded, the worker thread reads and parsers the Anims.j2a file and creates wave-buffers. In the main thread, it creates a button for each sound, sorted after set. Enjoy! It requires Chrome and 1 Gb of RAM! 
				__________________ 
		
		
		
		
		
			WebJCS 2 (new and in progress) WebJCS 1 (old but complete) SGIP Simple Games in Progress list Level Packer v2 - With a GUI! PHP Tileset Compiler Last edited by djazz; Dec 11, 2011 at 02:07 AM.  | 
![]()  | 
  	
  	
  		
  		«
  			Previous Thread
  			|
  			Next Thread
  		»
  	
  
  
  
  
  
  
  
  
  
  
  
  | Thread Tools | |
  		
  | 
  	
  		
  | 
  
All times are GMT -8. The time now is 06:34 PM.
		Jazz2Online © 1999-INFINITY (Site Credits). Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats. Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Original site design by Ovi Demetrian. DrJones is the puppet master. Eat your lima beans, Johnny.




), I've actually been checking the OpenMPT sourceforge page every now and then so I could write a newspost when a new release is out (as it will contain J2B support) - and I've been using foo_dumb's source for some more insight in the format (though I've moved on to other stuff for the time being). OpenMPT's J2B support is based on foo_dumb's, right?



		



:
 
 