The Merkury engine is a proprietary game engine developed by Krome Studios since at least 2001, known to run on PS2, PSP, Wii and with version 3 of the engine it added support for Xbox 360 and PS3. It is likely also running on the Nintendo Switch thanks to the recent port of Star Wars: The Force Unleashed to the console.
Nowadays new games are developed in Unity at Krome Studios (e.g Ty the Tasmanian Tiger 4) rather than the Merkury engine, but remaster of older games are still being relased based on the Merkury engine so Krome Studios are still activly developing with it.
It is best known for the custom versions of Star Wars: The Force Unleashed on less powerful consoles, because the LucasArts version for Xbox 360 and PS3 was too demanding to port directly to PS2, PSP or Wii. Because a significant installer base remained for those consoles, LucasArts opted to outsource a custom version to Krome, using their existing engine architecture under the name Merkury
The Merkury engine is first listed on the official Krome Studios website sometime before March 2001 (when it was archived by the wayback machine) where it claimed the engine had been in development for 3 years 1, so this would put the creation of the Merkury engine around with 1998 or 1999, depending on when the text was written on the website.
There are at least three known major versions of the Merkury engine:
On the official website archived on March 3rd 2001, it called Merkury a “world-class 3D game engine” 1 and it listed the featues of the engine as:
The first game that is oficially credited as using the engine is the Windows version of Championship Surfer from 2000 with Tony Ball being listed as the Merkury engine programmer in the credits section of the manual.
The Merkury engine was built in C++ with a few modules written in Assembler, with simultanious development of the engine on multiple platforms at once (Windows, PS2, GameCube and Xbox) 2.
On the port of the Merkury engine to GameCube for Ty the Tasmanian Tiger, Chris Lacy had the following to say in an interview with Nintendo World Report (NWR):
In about July of last year (2001) we received our first GameCube DevKit, which was very exciting for me, especially because I had been following the development of “Dolphin” since the PlanetN2000 days when Rick first broke the story about the codename for the project. To see it in person was so cool.
Within a couple of weeks, Tony Ball, our GameCube engine lead, had the character animating and drawing and doing most of what was doing in the PS2 version. A couple of months went by and by that point the GameCube version of the Merkury engine was pretty much inline with the PS2 version, so from then on development was simultaneous between the PS2 and GameCube, and later Xbox versions of the game.
The original Krome Studios website archived back in March 2001 has the following games as using the Merkury engine 1:
However the only actual reference in the game files for the name Merkury was in the 2000 windows release of Championship Surfer. The rest of the games refer to a game engine called BEAST and a 3D engine called Blast Graphics which we believe was simply just renamed to Merkury sometime during the development of Championship Surfer.
Because not all uses of Merkury are documented, below is a table of major titles developed by Krome Studios across platforms. This is a reference for potential engine use, not confirmation of Merkury integration.
Game Title | Platform(s) | Year | Using Merkury Engine? |
---|---|---|---|
Mike Stewart’s Pro Bodyboarding | Windows | February 1999 | Yes but the engine was known as BEAST and Blast Graphics for 3D |
The Chronicles of Jaru Tenk | Windows | October 1999 | Yes (Blast Graphics) |
Halloween Spirit Board | Windows | October 1999 | Yes (Blast Graphics) |
Championship Surfer | Windows, PlayStation, Dreamcast | 2000 | Yes for Windows (SURF_PC.rkv) and Dreamcast (SURF_DCP.rkv) but no for PS1 |
Barbie Beach Vacation | Windows | 2001 | No not a 3D game so neither Blast Graphics or Merkury |
Disney’s Extremely Goofy Skateboarding | Windows | 2001 | Yes (Blast graphics, uses fmod, bink, zip files) |
Sunny Garcia Surfing | PlayStation 2 | 2001 | Yes (Merkury creditied in game manual) |
Barbie: Sparkling Ice Show | Windows | 2002 | Yes (DATA_PC.rkv), DirectX8, fmod, bink |
Ty the Tasmanian Tiger | PS2, Xbox, GameCube, Windows, HD Remasters | 2002 | Yes |
The Adventures of Jimmy Neutron: Jet Fusion | PS2, GameCube | 2003 | Yes |
Ty the Tasmanian Tiger 2: Bush Rescue | PS2, Xbox, GameCube, Windows, HD Remasters | 2004 | Yes |
King Arthur | PS2, Xbox, GameCube | 2004 | |
Ty the Tasmanian Tiger 3: Night of the Quinkan | PS2, Xbox, GameCube, Windows, HD Remasters | 2005 | |
The Legend of Spyro: A New Beginning | PS2, Xbox, GameCube, GBA | 2006 | |
The Legend of Spyro: The Eternal Night | PS2, Wii | 2007 | |
Viva Piñata: Party Animals | Xbox 360 | 2007 | |
Hellboy: The Science of Evil | PS3, Xbox 360, PSP | 2008 | |
Star Wars: The Force Unleashed | PS2, PSP, Wii, Nintendo Switch | 2008, 2022 | Yes |
Star Wars: The Clone Wars - Lightsaber Duels | Wii | 2008 | |
Scene It? Box Office Smash | Xbox 360 | 2008 | |
Star Wars: The Clone Wars – Republic Heroes | PS3, Xbox 360, Wii, PS2, PSP, Windows | 2009 | Yes |
Transformers: Revenge of the Fallen | PS2, Wii | 2009 | |
Game Room | Xbox 360, Windows, Windows Phone 7 | 2010 | Yes (RKV files present in windows version) |
Blade Kitten | PS3, Xbox 360, Windows | 2010, 2012 | Yes (RKV files present) |
Legend of the Guardians: The Owls of Ga’Hoole | Xbox 360, PS3, Wii | 2010 | Yes (Merkury 3) |
Full House Poker | Xbox 360, Windows Phone 7 | 2011 | |
Backyard Sports Basketball 2015 | iOS, Android | 2015 | No (Unity) |
Ty the Tasmanian Tiger 4 | Windows | 2015 | No (Unity) |
Ty the Tasmanian Tiger HD | Xbox One, Series X/S, Switch, PS4, Windows | 2016, 2020 | Yes (RKV files present) |
Ty the Tasmanian Tiger 2: Bush Rescue HD | Xbox One, Series X/S, Switch, PS4, Windows | 2017, 2021 | Yes (RKV files present) |
Ty the Tasmanian Tiger 3: Night of the Quinkan HD | Windows | 2018 | Yes (RKV files present) |
The Bard’s Tale Trilogy | Windows, Xbox One | 2018, 2019 | No (Unity) |
Wasteland Remastered | Windows, Xbox One | 2020 | No (Unity) |
Ty the Tasmanian Tiger 4: Bush Rescue Returns | Nintendo Switch | 2023 | No (Unity) |
Monster Dash | iOS, Android | 2016 / ongoing | No (Unity) |
Gizmotablet (Kid World, Verizon) | Android Tablet (EdTech) | 2018 |
The company was originally founded as Interactive Binary Illusions in 1993 3, then renamed Gee Wizz! entertainment in 1996 on the release of their game Zombie Wars 4, it was formed by partners John Passfield and Steve Stamatiadis 5. It later became Krome Studios on the 1st November 1999 merging with Robert Walsh’s Pacific Interactive Entertainment 6.
Despite all the evolution, the studio continued to be based in Brisbane, Australia.
Interactive Binary Illusions (IBI) released their first game all the way back in 1993 called Alien Carnage (also known as Halloween Harry), followed by the graphic adventure Flight of the Amazon Queen in 1995 3.
They were working on a third title called Stereo Jack for planned release in 1996, however due to lack of funding it has to be cancelled and the pair instead formed a new company called Gee Wizz! entertainment.
Halloween Harry was a join effort between SubZero Software (later became Mind Mechanics 7) and Interactive Binary Illusions, the game itself later got renamed to Alien Carnage to avoid the consumer thinking it was a game that could only be enjoyed on October 31st.
John Passfield’s site has Alien Carnage (Halloween Harry) on the Free Stuff! - Passfield Games page but there is no download link, presumably the copyright of the game is owned by Apogee.
Flight of the Amazon Queen was released for DOS and Amiga in 1995 and then later Windows (2004), iPhone (2009), Mac (2013) and even Linux in 2021! 8.
Since the company was so small the copyright for these games is owned by the two co-founders of IBI and John Passfield has generously uploaded the original version of Flight of the Amazon Queen to his personal website which you can download completely free from his Free Stuff! - Passfield Games page!
We also highly recommend you buy the recent iOS re-release of the game on the App Store as its incredibly cheap and a great game to play on the go, along with supporting that amazing industry veteren Mr Passfield, a link to it is also available on his Free Stuff! - Passfield Games page.
The game was built with a custom game engine called JASPAR (John And Steve’s Programmable Adventure Resource) and John even wrote some game editor tools 9:
The game was first written in AMOS BASIC, then converted to C code for the final Amiga build, then the PC version was a port of this C code by Tony Ball. According to John the C code contained a lot of emulated AMOS function calls and game was still edited on the AMIGA using JOKER as they were still all written in AMOS BASIC 9. It was compiled using the WATCOM C toolchain accorsing to strings in the Queen.exe file.
In March 1997 they mentioned working on the new version of the engine JASPAR2 for their new game The Elf Lord’s Bane Quest Saga which sadly never got released 10.
The engine was the second non-LucasArts engine added to ScummVM on September 28th 2003 in version 0.6.0 where they called it the Queen engine due to the only game that used it was the Flight of the Amazon Queen and they possibly didn’t know about it being called JASPER at the time. The engine supports all known DOS and Amiga versions of the game, including multiple languages and demos 11.
For more information, you absolutely must read John’s blog post on the making of the game Game Musings: Making of Flight of the Amazon Queen - A 20th Anniversary Retrospective
What I also thought was super cool was at the end of John’s 2015 blog post he teased an Apple Watch version of the game with this screenshot:
However it was never released due to John realizing that there’s no market on the watch for this kind of game., which is sad because I would love to have seen how well this works on a watch, maybe adverture games are the perfect candidate for watch games? Although to be honest although I own an apple watch I have never downloaded a game for it… maybe I need to be the change I want to see in the market.
As facinating as the JASPAR engine is, this page is about Merkury and none of the Interactive Binary Illusions games have any hint of the Merkury (or Blast graphics) engines so lets keep going.
In 1996 Gee Wizz! entertainment was born and during their run until they become Krome Studios in 1999 they released the following games:
The original Gee Wizz! entertainment site from back in March 1997 has the following to say about each of the original team members 5:
# Steve Stamatiadis
Steve started out working in the comics field before he got into computer game design and graphics. After studying animation he worked on comics like The Statlight agency, Markam and even a did a short stint on From Hell as a background artist. In 1991 he worked on the movie Fortress after which he and John began work on Flight of the Amazon queen (which was done on a lowly Amiga). Today at Age 27 he is responsible for the look of Gee whiz! games and gets to work with more powerful machines and software to create really cool stuff.
# John Passfield
John had his first computer game published in 1985 at the ripe old age of 17. He later studied computer science and worked as a programmer for a telecommunications company before co-founding Gee Whiz! Entertainment. John prefers to think of himself as a member of the "Star Wars Generation" rather then "Generation X". John likes to write comic books - his credits include a two year stint writing Dingo Boy and Vixen Rangers for one of Australia's largest selling magazines, Stereo Jack for Issue One Comics and Jace Riegel for Dark Horse Comics.
# Robert Crane
Robert is a 24 year old programmer who spent his whole life dedicated to the cause of proving that Pascal is every bit as good as "C" as a programming language. In the process he has developed an install program for DOS that games publisher Apogee picked up and uses for its shareware titles. He is also an acknowledged database programmer but likes to keep that secret. His strongest point is doing graphics tools like game systems and sprite editors. Being around so much graphics, he also likes to dabble in 3d modeling.
# Tony Ball
Tony has worked on many games, some of which actually made it onto the shelves, including Halloween Harry, Alien Carnage and Flight of the Amazon Queen. He specializes in 'C' and Intel Assembly, particularly graphics code, and is currently working on some really cool stuff with Gee Whiz! Entertainment.
Zombie Wars was a sequal to Halloween Harry released in 1996 and written in Delphi, it has the codename Harry95 left in the executable.
Pratik Anand has reverse engineered the assets for Zombie wars and has an excellent write up here: Detective work on Reverse Engineering obscure 16-bit Windows game (Zombie Wars) · Pratik Anand
Sadly they found that reverse engineering an old Delphi executable is not easy with most modern tools. It is likely build using a very early version of Delphi such as 1.0 (1995) and their are tools that can help recovering the source files for Delphi 2.0/3.0 from compiled executables such as EXE2DPR - Delphi project sources Rescuer, but I don’t know of any software that works on 1.0 executables unfortunetly.
It was built using the Microsoft WinG library, which was the original name for DirectX. It also uses a library from SubZero Software with a build date of 4th December 1995. Since its assets are all stored in .SUB0 archives this hints at a library for packing game assets, SubZero Software are also listed as a join developer on the original Halloween Harry game.
For the limited analysis of the binary I can do there doesn’t seem to be any connection between the game and what would become the Merkury engine or the 3d library Blast Graphics) and it was written in a completely different programming language so it is unlikely there is a strong connection.
Robert Crane was a big fan of the Delphi programming langauge (Object Oriented version of Pascal) and exclaimed the following on the company website back in 1997 10:
Let me say that if it wasn’t for Delphi, this project would have been a nightmare of great proportions. If there are any sceptics of what Delphi is capable of, wait ‘til they see Zombie Wars.
Since all the coding of Zombie Wars (excluding graphics routines) is up to me, I have been REALLY busy just keeping up with the graphics that Steve does. I guess it is a little easier this time around because most of the code was a direct port from the old Halloween Harry. I am glad we chose to do the sequel though because I’ve added some really cool stuff to the engine.
Many of the games listed on the official website in 2001 as being Merkury engine games refer to the engine under a different name BEAST and Blast graphics. Later on Krome would come to retroactivley refer to these games as based on the Merkury engine.
In the Help file for Mike Stewart’s Pro Bodyboarding it lists two libraries used for making the game, BEAST and Blast Graphics:
The BEAST game engine was built by Mind Mechanics (SubZero Software) and was used for Mike Stewart’s Pro Bodyboarding and the surfing games that used the same engine.
In Championship Surfer we can clearly see the engine was called BEAST: // For use with the BEAST Game Engine
and contained a file called beast.cfg which is a plain text file with the text BEAST Config File at the top.
It was always compiled into the main game executable so unlike the Blast Graphics 3d library we don’t have a lot of information on what functions it contained.
What we do know is a few of the source file paths which were left in the Dreamcast version of championship surfer:
And from a crash log output found on the Russian Disc called Classic Fond 58 we have:
BEAST::Timer1Timer
BEAST::RunHub
BEAST::DoLogics
GAME::Main
GAME::B4MainMenu
GAME::PlayASong
BEAST::vLoadSFX
BEAST::myhandler
Release/beast98.exe
NB11P
.\Release\beast98.res
.\Release\StdAfx.obj
.\Release\INSIDEPOly.obj
.\Release\Filebank.obj
.\Release\dxinput.obj
.\Release\diskio.obj
.\Release\beast98.obj
.\Release\animscript.obj
Microsoft CVTRES 5.00.1720.1
C:\beast\INSIDEPOly.CPP
C:\bg\Filebank.cpp
C:\beast\dxinput.cpp
C:\beast\diskio.cpp
C:\beast\beast98.cpp
C:\beast\animscript.cpp
Type | Address | Demangled Name | Symbol Name | Segment |
---|---|---|---|---|
0x0000 | 0x401000 | int __cdecl GetValidAnimStr(char *, char *, int) | ?GetValidAnimStr@@YAHPAD0H@Z | 0x100 |
0x0000 | 0x401100 | int __cdecl DigitStr(char *, char *, int) | ?DigitStr@@YAHPAD0H@Z | 0x100 |
0x0000 | 0x401190 | int __cdecl NonDigitStr(char *, char *, int) | ?NonDigitStr@@YAHPAD0H@Z | 0x100 |
0x0000 | 0x401220 | void __cdecl ExtractFrameValues(char *, int &, int &, int &) | ?ExtractFrameValues@@YAXPADAAH11@Z | 0x100 |
0x0000 | 0x401340 | public: void __thiscall ANIMATION::Reset(void) | ?Reset@ANIMATION@@QAEXXZ | 0x100 |
0x0000 | 0x401360 | public: int __thiscall ANIMATION::GetFrameCount(void) | ?GetFrameCount@ANIMATION@@QAEHXZ | 0x100 |
0x0000 | 0x401370 | public: int __thiscall ANIMATION::GetSpeed(void) | ?GetSpeed@ANIMATION@@QAEHXZ | 0x100 |
0x0000 | 0x401380 | public: void __thiscall ANIMATION::NextFrame(void) | ?NextFrame@ANIMATION@@QAEXXZ | 0x100 |
0x0000 | 0x401500 | public: int __thiscall ANIMATION::GetCurrFrameNr(void) | ?GetCurrFrameNr@ANIMATION@@QAEHXZ | 0x100 |
0x0000 | 0x401510 | public: void __thiscall ANIMATION::SetCycle(int) | ?SetCycle@ANIMATION@@QAEXH@Z | 0x100 |
0x0000 | 0x401520 | public: int __thiscall ANIMATION::GetCycle(void) | ?GetCycle@ANIMATION@@QAEHXZ | 0x100 |
0x0000 | 0x401530 | public: void __thiscall ANIMATION::SetName(char *) | ?SetName@ANIMATION@@QAEXPAD@Z | 0x100 |
0x0000 | 0x401560 | public: char * __thiscall ANIMATION::GetName(void) | ?GetName@ANIMATION@@QAEPADXZ | 0x100 |
0x0000 | 0x401570 | public: void __thiscall ANIMATION::ProcessAnimData(char *) | ?ProcessAnimData@ANIMATION@@QAEXPAD@Z | 0x100 |
0x0000 | 0x401620 | void __cdecl nonewline(char *) | ?nonewline@@YAXPAD@Z | 0x100 |
0x0000 | 0x401640 | char * __cdecl StringRemainder(char *, int) | ?StringRemainder@@YAPADPADH@Z | 0x100 |
0x0000 | 0x4016A0 | private: void __thiscall ANIMSCRIPT::ParseBadFile(struct _iobuf *) | ?ParseBadFile@ANIMSCRIPT@@AAEXPAU_iobuf@@@Z | 0x100 |
0x0000 | 0x401B30 | public: void __thiscall ANIMSCRIPT::Load(char *) | ?Load@ANIMSCRIPT@@QAEXPAD@Z | 0x100 |
0x0000 | 0x401B70 | public: int __thiscall ANIMSCRIPT::GetAnimNumber(char *) | ?GetAnimNumber@ANIMSCRIPT@@QAEHPAD@Z | 0x100 |
0x0000 | 0x401BF0 | public: char * __thiscall ANIMSCRIPT::GetAnimName(int) | ?GetAnimName@ANIMSCRIPT@@QAEPADH@Z | 0x100 |
0x0000 | 0x401C60 | public: int __thiscall ANIMSCRIPT::GetFPS(void) | ?GetFPS@ANIMSCRIPT@@QAEHXZ | 0x100 |
0x0000 | 0x401C70 | public: int __thiscall ANIMSCRIPT::GetAnimCount(void) | ?GetAnimCount@ANIMSCRIPT@@QAEHXZ | 0x100 |
0x0000 | 0x401C80 | public: void __thiscall ANIMSCRIPT::SetAnim(int) | ?SetAnim@ANIMSCRIPT@@QAEXH@Z | 0x100 |
0x0000 | 0x401CD0 | public: int __thiscall ANIMSCRIPT::Animate(int) | ?Animate@ANIMSCRIPT@@QAEHH@Z | 0x100 |
0x0000 | 0x401D30 | public: int __thiscall ANIMSCRIPT::GetCurrFrameNr(void) | ?GetCurrFrameNr@ANIMSCRIPT@@QAEHXZ | 0x100 |
0x0000 | 0x401D50 | public: void __thiscall ANIMSCRIPT::Destroy(void) | ?Destroy@ANIMSCRIPT@@QAEXXZ | 0x100 |
0x0000 | 0x401D60 | public: void __thiscall STRPACK::constructor(void) | ??0STRPACK@@QAE@XZ | 0x100 |
0x0000 | 0x401D80 | public: void __thiscall STRPACK::LoadInto(char *) | ?LoadInto@STRPACK@@QAEXPAD@Z | 0x100 |
0x0000 | 0x401E70 | public: char * __thiscall STRPACK::Get(int) | ?Get@STRPACK@@QAEPADH@Z | 0x100 |
0x0000 | 0x401E80 | public: int __thiscall STRPACK::Count(void) | ?Count@STRPACK@@QAEHXZ | 0x100 |
0x0000 | 0x401E90 | public: void __thiscall STRPACK::~destructor(void) | ??1STRPACK@@QAE@XZ | 0x100 |
0x0000 | 0x401FA0 | int __cdecl RegisterItem(char *) | ?RegisterItem@@YAHPAD@Z | 0x100 |
0x0000 | 0x402270 | struct _RegItem * __cdecl RegDelete(char *) | ?RegDelete@@YAPAU_RegItem@@PAD@Z | 0x100 |
0x0000 | 0x402370 | void __cdecl BeastExit(void) | ?BeastExit@@YAXXZ | 0x100 |
0x0000 | 0x402730 | int __cdecl CompStrI(char *, char *) | ?CompStrI@@YAHPAD0@Z | 0x100 |
0x0000 | 0x402860 | void __cdecl PF(void) | ?PF@@YAXXZ | 0x100 |
0x0000 | 0x4028E0 | void __cdecl myhandler(char *, char *) | ?myhandler@@YAXPAD0@Z | 0x100 |
0x0000 | 0x4029D0 | char * __cdecl vSprintf(char *) | ?vSprintf@@YAPADPADZZ | 0x100 |
0x0000 | 0x402A60 | int __cdecl vRandom(int) | ?vRandom@@YAHH@Z | 0x100 |
0x0000 | 0x402AF0 | int __cdecl vRandom2(int, int) | ?vRandom2@@YAHHH@Z | 0x100 |
0x0000 | 0x402B90 | void __cdecl vRandomize(int, int) | ?vRandomize@@YAXHH@Z | 0x100 |
0x0000 | 0x402C10 | double __cdecl vFloor(float) | ?vFloor@@YANM@Z | 0x100 |
0x0000 | 0x402C30 | int __cdecl vF2I(float) | ?vF2I@@YAHM@Z | 0x100 |
0x0000 | 0x402C50 | int __cdecl vMAX(int, int) | ?vMAX@@YAHHH@Z | 0x100 |
0x0000 | 0x402C60 | int __cdecl vMIN(int, int) | ?vMIN@@YAHHH@Z | 0x100 |
0x0000 | 0x402C70 | int __cdecl vabs(int) | ?vabs@@YAHH@Z | 0x100 |
0x0000 | 0x402C80 | float __cdecl vabsf(float) | ?vabsf@@YAMM@Z | 0x100 |
0x0000 | 0x402CA0 | double __cdecl vSin(double) | ?vSin@@YANN@Z | 0x100 |
0x0000 | 0x402CB0 | double __cdecl vCos(double) | ?vCos@@YANN@Z | 0x100 |
0x0000 | 0x402CC0 | double __cdecl vATan2(double, double) | ?vATan2@@YANNN@Z | 0x100 |
0x0000 | 0x402CF0 | double __cdecl vSqrt(double) | ?vSqrt@@YANN@Z | 0x100 |
0x0000 | 0x402D10 | double __cdecl vACos(double) | ?vACos@@YANN@Z | 0x100 |
0x0000 | 0x402D40 | void __cdecl vMove(void *, void *, int) | ?vMove@@YAXPAX0H@Z | 0x100 |
0x0000 | 0x402DC0 | double __cdecl vatof(char *) | ?vatof@@YANPAD@Z | 0x100 |
0x0000 | 0x402DD0 | int __cdecl vatoi(char *) | ?vatoi@@YAHPAD@Z | 0x100 |
0x0000 | 0x402E10 | char * __cdecl vStrc(int) | ?vStrc@@YAPADH@Z | 0x100 |
0x0000 | 0x402E30 | int __cdecl vStrl(char *) | ?vStrl@@YAHPAD@Z | 0x100 |
0x0000 | 0x402E50 | int __cdecl vKey(int) | ?vKey@@YAHH@Z | 0x100 |
0x0000 | 0x402E70 | void * __cdecl vGetMem(int) | ?vGetMem@@YAPAXH@Z | 0x100 |
0x0000 | 0x402EF0 | void __cdecl vFreeMem(void *) | ?vFreeMem@@YAXPAX@Z | 0x100 |
0x0000 | 0x402F60 | float __cdecl vGetObjYWidth(int, int) | ?vGetObjYWidth@@YAMHH@Z | 0x100 |
0x0000 | 0x403000 | float __cdecl vGetObjXWidth(int, int) | ?vGetObjXWidth@@YAMHH@Z | 0x100 |
0x0000 | 0x4030A0 | float __cdecl vGetObjZWidth(int, int) | ?vGetObjZWidth@@YAMHH@Z | 0x100 |
0x0000 | 0x403140 | void __cdecl vBG_GetObjectBox(int, float *, float *, float *, float *, float *, float *) | ?vBG_GetObjectBox@@YAXHPAM00000@Z | 0x100 |
0x0000 | 0x4031D0 | void __cdecl vBG_MatriceClear(void) | ?vBG_MatriceClear@@YAXXZ | 0x100 |
0x0000 | 0x403270 | void __cdecl vDOUT(char *) | ?vDOUT@@YAXPADZZ | 0x100 |
0x0000 | 0x403360 | void __cdecl vFreeSFX(int) | ?vFreeSFX@@YAXH@Z | 0x100 |
0x0000 | 0x403430 | int __cdecl vLoadSFX(char *) | ?vLoadSFX@@YAHPAD@Z | 0x100 |
0x0000 | 0x403600 | void __cdecl vPlaySFX(int, int, float, float, float, int) | ?vPlaySFX@@YAXHHMMMH@Z | 0x100 |
0x0000 | 0x4036C0 | void __cdecl vSFXSetD(int, unsigned int, float, float, float) | ?vSFXSetD@@YAXHIMMM@Z | 0x100 |
0x0000 | 0x4036D0 | void __cdecl vStopSFX(int) | ?vStopSFX@@YAXH@Z | 0x100 |
0x0000 | 0x403770 | int __cdecl vPlayingSFX(int) | ?vPlayingSFX@@YAHH@Z | 0x100 |
0x0000 | 0x403790 | void __cdecl vKillSFX(int) | ?vKillSFX@@YAXH@Z | 0x100 |
0x0000 | 0x403830 | int __cdecl vJoyUp(int) | ?vJoyUp@@YAHH@Z | 0x100 |
0x0000 | 0x403900 | int __cdecl vJoyDown(int) | ?vJoyDown@@YAHH@Z | 0x100 |
0x0000 | 0x4039D0 | int __cdecl vJoyLeft(int) | ?vJoyLeft@@YAHH@Z | 0x100 |
0x0000 | 0x403AA0 | int __cdecl vJoyRight(int) | ?vJoyRight@@YAHH@Z | 0x100 |
0x0000 | 0x403B70 | int __cdecl vJoyFire(int, int) | ?vJoyFire@@YAHHH@Z | 0x100 |
0x0000 | 0x403C40 | void __cdecl vFree3D(int) | ?vFree3D@@YAXH@Z | 0x100 |
0x0000 | 0x403D00 | int __cdecl vLoad3D(char *) | ?vLoad3D@@YAHPADZZ | 0x100 |
0x0000 | 0x403F10 | void __cdecl vKillObject(void *) | ?vKillObject@@YAXPAX@Z | 0x100 |
0x0000 | 0x404020 | void * __cdecl vGetObj(int, int) | ?vGetObj@@YAPAXHH@Z | 0x100 |
0x0000 | 0x404060 | void * __cdecl vGetPlayer(int) | ?vGetPlayer@@YAPAXH@Z | 0x100 |
0x0000 | 0x404070 | void * __cdecl vGetInfo(int, int, int, int) | ?vGetInfo@@YAPAXHHHH@Z | 0x100 |
0x0000 | 0x404270 | void __cdecl ReloadVALSettings(void) | ?ReloadVALSettings@@YAXXZ | 0x100 |
0x0000 | 0x4042C0 | void __cdecl ReadandSpawn(void) | ?ReadandSpawn@@YAXXZ | 0x100 |
0x0000 | 0x4042D0 | void __cdecl LoadSOLFile(char *) | ?LoadSOLFile@@YAXPAD@Z | 0x100 |
0x0000 | 0x404640 | void __cdecl vLoad_LEV_File(char *) | ?vLoad_LEV_File@@YAXPADZZ | 0x100 |
0x0000 | 0x4049E0 | int __cdecl vDSprite(struct _dsprite *) | ?vDSprite@@YAHPAU_dsprite@@@Z | 0x100 |
0x0000 | 0x404B60 | void __cdecl vClearAllObjects(void) | ?vClearAllObjects@@YAXXZ | 0x100 |
0x0000 | 0x404C40 | void __cdecl vLoadingScreen(char *) | ?vLoadingScreen@@YAXPAD@Z | 0x100 |
0x0000 | 0x404D80 | void __cdecl vPushCameraState(void) | ?vPushCameraState@@YAXXZ | 0x100 |
0x0000 | 0x404E40 | void __cdecl vBG_SetCamera(float, float, float, float, float) | ?vBG_SetCamera@@YAXMMMMM@Z | 0x100 |
0x0000 | 0x404ED0 | void __cdecl vPopCameraState(void) | ?vPopCameraState@@YAXXZ | 0x100 |
0x0000 | 0x405050 | void __cdecl vClearScreen(void) | ?vClearScreen@@YAXXZ | 0x100 |
0x0000 | 0x405110 | void __cdecl vLoadObject0(char *) | ?vLoadObject0@@YAXPAD@Z | 0x100 |
0x0000 | 0x405190 | void __cdecl vInitVALFile(char *) | ?vInitVALFile@@YAXPAD@Z | 0x100 |
0x0000 | 0x405210 | char * __cdecl vGetStrValue(char *) | ?vGetStrValue@@YAPADPAD@Z | 0x100 |
0x0000 | 0x405370 | int __cdecl vGetIntValue(char *) | ?vGetIntValue@@YAHPAD@Z | 0x100 |
0x0000 | 0x405390 | double __cdecl vGetFloatValue(char *) | ?vGetFloatValue@@YANPAD@Z | 0x100 |
0x0000 | 0x4053F0 | void __cdecl vOpenFile(char *) | ?vOpenFile@@YAXPADZZ | 0x100 |
0x0000 | 0x4054A0 | char * __cdecl vReadFile(void) | ?vReadFile@@YAPADXZ | 0x100 |
0x0000 | 0x4054B0 | void __cdecl vCloseFile(void) | ?vCloseFile@@YAXXZ | 0x100 |
0x0000 | 0x4054C0 | double __cdecl vAngleDif(float, float) | ?vAngleDif@@YANMM@Z | 0x100 |
0x0000 | 0x405560 | unsigned int __cdecl vLoadDLL(char *) | ?vLoadDLL@@YAIPAD@Z | 0x100 |
0x0000 | 0x405720 | void * __cdecl vGetProcAddr(unsigned int, char *) | ?vGetProcAddr@@YAPAXIPAD@Z | 0x100 |
0x0000 | 0x405800 | int __cdecl vAS_Load(char *) | ?vAS_Load@@YAHPAD@Z | 0x100 |
0x0000 | 0x405A30 | int __cdecl vAS_GetAnim(int, char *) | ?vAS_GetAnim@@YAHHPAD@Z | 0x100 |
0x0000 | 0x405A50 | void __cdecl vAS_SetAnim(int, int) | ?vAS_SetAnim@@YAXHH@Z | 0x100 |
0x0000 | 0x405AD0 | int __cdecl vAS_Animate(int, int) | ?vAS_Animate@@YAHHH@Z | 0x100 |
0x0000 | 0x405AF0 | char __cdecl vCompareStr(char *, char *) | ?vCompareStr@@YADPAD0@Z | 0x100 |
0x0000 | 0x405B10 | void __cdecl vRunMenu(void) | ?vRunMenu@@YAXXZ | 0x100 |
0x0000 | 0x405B80 | struct HINSTANCE__ * __cdecl LoadDLL(char *) | ?LoadDLL@@YAPAUHINSTANCE__@@PAD@Z | 0x100 |
0x0000 | 0x405F30 | int __cdecl vBFileOpen(char *, char *) | ?vBFileOpen@@YAHPAD0@Z | 0x100 |
0x0000 | 0x405FD0 | int __cdecl vBFileRead(void *, int) | ?vBFileRead@@YAHPAXH@Z | 0x100 |
0x0000 | 0x406060 | void __cdecl vBFileWrite(void *, int) | ?vBFileWrite@@YAXPAXH@Z | 0x100 |
0x0000 | 0x4060E0 | void __cdecl vBFileClose(void) | ?vBFileClose@@YAXXZ | 0x100 |
0x0000 | 0x406160 | double __cdecl vA2F(char *) | ?vA2F@@YANPAD@Z | 0x100 |
0x0000 | 0x406170 | int __cdecl vA2I(char *) | ?vA2I@@YAHPAD@Z | 0x100 |
0x0000 | 0x406180 | char * __cdecl vI2A(int) | ?vI2A@@YAPADH@Z | 0x100 |
0x0000 | 0x4061A0 | double __cdecl vI2F(int) | ?vI2F@@YANH@Z | 0x100 |
0x0000 | 0x4061D0 | char * __cdecl vF2A(double) | ?vF2A@@YAPADN@Z | 0x100 |
0x0000 | 0x406200 | int __cdecl vFileExists(char *) | ?vFileExists@@YAHPADZZ | 0x100 |
0x0000 | 0x4062D0 | void __cdecl vFAIL(void) | ?vFAIL@@YAXXZ | 0x100 |
0x0000 | 0x4062E0 | void __cdecl SetupCalls(void) | ?SetupCalls@@YAXXZ | 0x100 |
0x0000 | 0x406670 | struct Object * __cdecl LoadObject(char *, char *) | ?LoadObject@@YAPAUObject@@PAD0@Z | 0x100 |
0x0000 | 0x4066F0 | void * __cdecl vSpawnObject(int, float, float, float, void *) | ?vSpawnObject@@YAPAXHMMMPAX@Z | 0x100 |
0x0000 | 0x406990 | void __cdecl Init(void) | ?Init@@YAXXZ | 0x100 |
0x0000 | 0x406AC0 | void __cdecl DoLogics(void) | ?DoLogics@@YAXXZ | 0x100 |
0x0000 | 0x406D30 | void __cdecl DoDraws(void) | ?DoDraws@@YAXXZ | 0x100 |
0x0000 | 0x406F70 | void __cdecl GetDetailsfromINI(void) | ?GetDetailsfromINI@@YAXXZ | 0x100 |
0x0000 | 0x407380 | int __cdecl GetKeyStr(int) | ?GetKeyStr@@YAHH@Z | 0x100 |
0x0000 | 0x408250 | int __cdecl GetJoyStr(int) | ?GetJoyStr@@YAHH@Z | 0x100 |
0x0000 | 0x408390 | void __cdecl Menu_Screen_DefineKeys(int) | ?Menu_Screen_DefineKeys@@YAXH@Z | 0x100 |
0x0000 | 0x408C30 | void __cdecl Menu_Screen_DefineJoy(int) | ?Menu_Screen_DefineJoy@@YAXH@Z | 0x100 |
0x0000 | 0x409900 | void __cdecl Menu_Screen_Controls(void) | ?Menu_Screen_Controls@@YAXXZ | 0x100 |
0x0000 | 0x40A410 | void __cdecl Menu_Screen(void) | ?Menu_Screen@@YAXXZ | 0x100 |
0x0000 | 0x40B120 | void __cdecl KillTempFiles(void) | ?KillTempFiles@@YAXXZ | 0x100 |
0x0000 | 0x40B240 | void __cdecl RunHub(void) | ?RunHub@@YAXXZ | 0x100 |
0x0000 | 0x40B500 | void __cdecl FreeDLLs(void) | ?FreeDLLs@@YAXXZ | 0x100 |
0x0000 | 0x40B510 | void __cdecl RemoveAllTempFiles(void) | ?RemoveAllTempFiles@@YAXXZ | 0x100 |
0x0000 | 0x40B520 | void __cdecl LoadAllDLLs(void) | ?LoadAllDLLs@@YAXXZ | 0x100 |
0x0000 | 0x40B830 | void __cdecl RemoveAllDLLs(void) | ?RemoveAllDLLs@@YAXXZ | 0x100 |
0x0000 | 0x40B8E0 | void __cdecl PrintOutAllStats(void) | ?PrintOutAllStats@@YAXXZ | 0x100 |
0x0000 | 0x40BEC0 | void __cdecl Test4INIFile(void) | ?Test4INIFile@@YAXXZ | 0x100 |
0x0000 | 0x40BF80 | void __cdecl LiftAndSeperate(void) | ?LiftAndSeperate@@YAXXZ | 0x100 |
0x0000 | 0x40C0A0 | void __cdecl FormCreate(void) | ?FormCreate@@YAXXZ | 0x100 |
0x0000 | 0x40C1E0 | void __cdecl ShowEntryScreens(void) | ?ShowEntryScreens@@YAXXZ | 0x100 |
0x0000 | 0x40C3A0 | void __cdecl ShowExitScreens(void) | ?ShowExitScreens@@YAXXZ | 0x100 |
0x0000 | 0x40C570 | void __cdecl ReadInBeastCFGValues(void) | ?ReadInBeastCFGValues@@YAXXZ | 0x100 |
0x0000 | 0x40C980 | void __cdecl SaveOutBeastCFGValues(void) | ?SaveOutBeastCFGValues@@YAXXZ | 0x100 |
0x0000 | 0x40CCD0 | void __cdecl Timer1Timer(void) | ?Timer1Timer@@YAXXZ | 0x100 |
0x0000 | 0x40D040 | void __cdecl ExitGame(void) | ?ExitGame@@YAXXZ | 0x100 |
0x0000 | 0x40D070 | void __cdecl CheckMessages(void) | ?CheckMessages@@YAXXZ | 0x100 |
0x0000 | 0x40D230 | unsigned short int cdecl MyRegisterClass(struct HINSTANCE *) | ?MyRegisterClass@@YAGPAUHINSTANCE__@@@Z | 0x100 |
0x0000 | 0x40D2C0 | int cdecl InitInstance(struct HINSTANCE *, int) | ?InitInstance@@YAHPAUHINSTANCE__@@H@Z | 0x100 |
0x0000 | 0x40D330 | long int stdcall WndProc(struct HWND *, unsigned int, unsigned int, long int) | ?WndProc@@YGJPAUHWND__@@IIJ@Z | 0x100 |
0x0000 | 0x40D470 | _WinMain@16 | _WinMain@16 | 0x100 |
0x0000 | 0x40D710 | public: void __thiscall BG::constructor(void) | ??0BG@@QAE@XZ | 0x100 |
0x0000 | 0x40E2C0 | void __cdecl expand(struct _iobuf *) | ?expand@@YAXPAU_iobuf@@@Z | 0x100 |
0x0000 | 0x40E420 | int __cdecl ExtractFromBank(char *, char *) | ?ExtractFromBank@@YAHPAD0@Z | 0x100 |
0x0000 | 0x40E510 | unsigned char * __cdecl extract_file(char *, unsigned int *) | ?extract_file@@YAPAEPADPAI@Z | 0x100 |
0x0000 | 0x40E640 | public: void __thiscall fileio::constructor(char *) | ??0fileio@@QAE@PAD@Z | 0x100 |
0x0000 | 0x40E670 | public: void __thiscall fileio::open(char *) | ?open@fileio@@QAEXPAD@Z | 0x100 |
0x0000 | 0x40E7C0 | public: void __thiscall fileio::close(void) | ?close@fileio@@QAEXXZ | 0x100 |
0x0000 | 0x40E7F0 | public: void __thiscall fileio::~destructor(void) | ??1fileio@@QAE@XZ | 0x100 |
0x0000 | 0x40E810 | public: void __thiscall fileio::reset(int) | ?reset@fileio@@QAEXH@Z | 0x100 |
0x0000 | 0x40E830 | public: long int __thiscall fileio::size(void) | ?size@fileio@@QAEJXZ | 0x100 |
0x0000 | 0x40E840 | public: long int __thiscall fileio::pos(void) | ?pos@fileio@@QAEJXZ | 0x100 |
0x0000 | 0x40E850 | public: unsigned short int __thiscall fileio::getword(void) | ?getword@fileio@@QAEGXZ | 0x100 |
0x0000 | 0x40E890 | public: unsigned char __thiscall fileio::getbyte(void) | ?getbyte@fileio@@QAEEXZ | 0x100 |
0x0000 | 0x40E8B0 | public: long int __thiscall fileio::getlong(void) | ?getlong@fileio@@QAEJXZ | 0x100 |
0x0000 | 0x40E900 | public: void __thiscall fileio::get(void *, int) | ?get@fileio@@QAEXPAXH@Z | 0x100 |
0x0000 | 0x40E950 | public: unsigned char __thiscall fileio::eof(void) | ?eof@fileio@@QAEEXZ | 0x100 |
0x0000 | 0x40E960 | public: long int __thiscall fileio::togo(void) | ?togo@fileio@@QAEJXZ | 0x100 |
0x0000 | 0x40E970 | public: void __thiscall fileio::write(void *, int) | ?write@fileio@@QAEXPAXH@Z | 0x100 |
0x0000 | 0x40E9D0 | public: void __thiscall fileio::writetofile(char *) | ?writetofile@fileio@@QAEXPAD@Z | 0x100 |
0x0000 | 0x40EA60 | public: char * __thiscall fileio::readline(void) | ?readline@fileio@@QAEPADXZ | 0x100 |
0x0000 | 0x40EB10 | unsigned int __cdecl joyGetOEMProductName(unsigned int, char *) | ?joyGetOEMProductName@@YAIIPAD@Z | 0x100 |
0x0000 | 0x40ECB0 | int __cdecl DXI_Init(void) | ?DXI_Init@@YAHXZ | 0x100 |
0x0000 | 0x40EE10 | void __cdecl DXI_Destroy(void) | ?DXI_Destroy@@YAXXZ | 0x100 |
0x0000 | 0x40EE20 | int __cdecl DXI_Total(void) | ?DXI_Total@@YAHXZ | 0x100 |
0x0000 | 0x40EE30 | char * __cdecl DXI_GetName(int) | ?DXI_GetName@@YAPADH@Z | 0x100 |
0x0000 | 0x40EE50 | void __cdecl DXI_Update(void) | ?DXI_Update@@YAXXZ | 0x100 |
0x0000 | 0x40EEB0 | int __cdecl DXI_Left(int) | ?DXI_Left@@YAHH@Z | 0x100 |
0x0000 | 0x40EF10 | int __cdecl DXI_Right(int) | ?DXI_Right@@YAHH@Z | 0x100 |
0x0000 | 0x40EF70 | int __cdecl DXI_Up(int) | ?DXI_Up@@YAHH@Z | 0x100 |
0x0000 | 0x40EFD0 | int __cdecl DXI_Down(int) | ?DXI_Down@@YAHH@Z | 0x100 |
0x0000 | 0x40F030 | int __cdecl DXI_Fire(int, int) | ?DXI_Fire@@YAHHH@Z | 0x100 |
0x0000 | 0x40F070 | int __cdecl fexists(char *) | ?fexists@@YAHPAD@Z | 0x100 |
0x0000 | 0x40F0A0 | public: void __thiscall FileBank::Init(char *) | ?Init@FileBank@@QAEXPAD@Z | 0x100 |
0x0000 | 0x40F1A0 | void __cdecl BuildBank(char *, char *, char *) | ?BuildBank@@YAXPAD00@Z | 0x100 |
0x0000 | 0x40F300 | public: char * __thiscall FileBank::Extract(char *) | ?Extract@FileBank@@QAEPADPAD@Z | 0x100 |
0x0000 | 0x40F4D0 | public: int __thiscall FileBank::Exists(char *) | ?Exists@FileBank@@QAEHPAD@Z | 0x100 |
0x0000 | 0x40F540 | int __cdecl insidepoly(float, float, int, struct insidepoint *) | ?insidepoly@@YAHMMHPAUinsidepoint@@@Z | 0x100 |
0x0000 | 0x40F600 | _WinExec@8 | _WinExec@8 | 0x100 |
0x0000 | 0x40F606 | _GetWindowsDirectoryA@8 | _GetWindowsDirectoryA@8 | 0x100 |
0x0000 | 0x40F60C | _GetCommandLineA@0 | _GetCommandLineA@0 | 0x100 |
0x0000 | 0x40F612 | _GetLastError@0 | _GetLastError@0 | 0x100 |
0x0000 | 0x40F618 | _LoadLibraryA@4 | _LoadLibraryA@4 | 0x100 |
0x0000 | 0x40F61E | _GetProcAddress@8 | _GetProcAddress@8 | 0x100 |
0x0000 | 0x40F624 | _FreeLibrary@4 | _FreeLibrary@4 | 0x100 |
0x0000 | 0x40F62A | _GetDriveTypeA@4 | _GetDriveTypeA@4 | 0x100 |
0x0000 | 0x40F630 | _GetDiskFreeSpaceExA@16 | _GetDiskFreeSpaceExA@16 | 0x100 |
0x0000 | 0x40F636 | _GlobalMemoryStatus@4 | _GlobalMemoryStatus@4 | 0x100 |
0x0000 | 0x40F63C | _ExitProcess@4 | _ExitProcess@4 | 0x100 |
0x0000 | 0x40F642 | _ClipCursor@4 | _ClipCursor@4 | 0x100 |
0x0000 | 0x40F648 | _GetAsyncKeyState@4 | _GetAsyncKeyState@4 | 0x100 |
0x0000 | 0x40F64E | _GetCursorPos@4 | _GetCursorPos@4 | 0x100 |
0x0000 | 0x40F654 | _ShowCursor@4 | _ShowCursor@4 | 0x100 |
0x0000 | 0x40F65A | _MessageBoxA@16 | _MessageBoxA@16 | 0x100 |
0x0000 | 0x40F660 | _DestroyWindow@4 | _DestroyWindow@4 | 0x100 |
0x0000 | 0x40F666 | _GetMessageA@16 | _GetMessageA@16 | 0x100 |
0x0000 | 0x40F66C | _DispatchMessageA@4 | _DispatchMessageA@4 | 0x100 |
0x0000 | 0x40F672 | _TranslateMessage@4 | _TranslateMessage@4 | 0x100 |
0x0000 | 0x40F678 | _PeekMessageA@20 | _PeekMessageA@20 | 0x100 |
0x0000 | 0x40F67E | _RegisterClassExA@4 | _RegisterClassExA@4 | 0x100 |
0x0000 | 0x40F684 | _LoadCursorA@8 | _LoadCursorA@8 | 0x100 |
0x0000 | 0x40F68A | _LoadIconA@8 | _LoadIconA@8 | 0x100 |
0x0000 | 0x40F690 | _UpdateWindow@4 | _UpdateWindow@4 | 0x100 |
0x0000 | 0x40F696 | _ShowWindow@8 | _ShowWindow@8 | 0x100 |
0x0000 | 0x40F69C | _CreateWindowExA@48 | _CreateWindowExA@48 | 0x100 |
0x0000 | 0x40F6A2 | _DefWindowProcA@16 | _DefWindowProcA@16 | 0x100 |
0x0000 | 0x40F6A8 | _SetForegroundWindow@4 | _SetForegroundWindow@4 | 0x100 |
0x0000 | 0x40F6AE | _LoadAcceleratorsA@8 | _LoadAcceleratorsA@8 | 0x100 |
0x0000 | 0x40F6B4 | _LoadStringA@16 | _LoadStringA@16 | 0x100 |
0x0000 | 0x40F6BA | _GetActiveWindow@0 | _GetActiveWindow@0 | 0x100 |
0x0000 | 0x40F6C0 | _RegCloseKey@4 | _RegCloseKey@4 | 0x100 |
0x0000 | 0x40F6C6 | _RegQueryValueExA@24 | _RegQueryValueExA@24 | 0x100 |
0x0000 | 0x40F6CC | _RegOpenKeyExA@20 | _RegOpenKeyExA@20 | 0x100 |
0x0000 | 0x40F6D2 | _timeGetTime@0 | _timeGetTime@0 | 0x100 |
0x0000 | 0x40F6D8 | _joyGetDevCapsA@12 | _joyGetDevCapsA@12 | 0x100 |
0x0000 | 0x40F6DE | _joyGetNumDevs@0 | _joyGetNumDevs@0 | 0x100 |
0x0000 | 0x40F6E4 | _joyGetPosEx@8 | _joyGetPosEx@8 | 0x100 |
0x0000 | 0x40F6EA | _isalpha | _isalpha | 0x100 |
0x0000 | 0x40F718 | _isupper | _isupper | 0x100 |
0x0000 | 0x40F740 | _islower | _islower | 0x100 |
0x0000 | 0x40F768 | _isdigit | _isdigit | 0x100 |
0x0000 | 0x40F790 | _isxdigit | _isxdigit | 0x100 |
0x0000 | 0x40F7BD | _isspace | _isspace | 0x100 |
0x0000 | 0x40F7E5 | _ispunct | _ispunct | 0x100 |
0x0000 | 0x40F80D | _isalnum | _isalnum | 0x100 |
0x0000 | 0x40F83B | _isprint | _isprint | 0x100 |
0x0000 | 0x40F869 | _isgraph | _isgraph | 0x100 |
0x0000 | 0x40F897 | _iscntrl | _iscntrl | 0x100 |
0x0000 | 0x40F8BF | ___isascii | ___isascii | 0x100 |
0x0000 | 0x40F8CC | ___toascii | ___toascii | 0x100 |
0x0000 | 0x40F8D4 | ___iscsymf | ___iscsymf | 0x100 |
0x0000 | 0x40F911 | ___iscsym | ___iscsym | 0x100 |
0x0000 | 0x40F94E | _atol | _atol | 0x100 |
0x0000 | 0x40F9D9 | _atoi | _atoi | 0x100 |
0x0000 | 0x40F9E4 | __atoi64 | __atoi64 | 0x100 |
0x0000 | 0x40FAA0 | _strncmp | _strncmp | 0x100 |
0x0000 | 0x40FAD8 | _fgets | _fgets | 0x100 |
0x0000 | 0x40FB3A | _fclose | _fclose | 0x100 |
0x0000 | 0x40FB6B | __fclose_lk | __fclose_lk | 0x100 |
0x0000 | 0x40FBB7 | __fsopen | __fsopen | 0x100 |
0x0000 | 0x40FBE8 | _fopen | _fopen | 0x100 |
0x0000 | 0x40FBFB | _sprintf | _sprintf | 0x100 |
0x0000 | 0x40FC4D | void * __cdecl operator new(unsigned int) | ??2@YAPAXI@Z | 0x100 |
0x0000 | 0x40FC5B | void __cdecl operator delete(void *) | ??3@YAXPAX@Z | 0x100 |
0x0000 | 0x40FC66 | void __stdcall _JumpToContinuation(void *, struct EHRegistrationNode *) | ?_JumpToContinuation@@YGXPAXPAUEHRegistrationNode@@@Z | 0x100 |
0x0000 | 0x40FC9A | void __stdcall _CallMemberFunction0(void *, void *) | ?_CallMemberFunction0@@YGXPAX0@Z | 0x100 |
0x0000 | 0x40FCA1 | void __stdcall _CallMemberFunction1(void *, void *, void *) | ?_CallMemberFunction1@@YGXPAX00@Z | 0x100 |
0x0000 | 0x40FCA8 | void __stdcall _CallMemberFunction2(void *, void *, void *, int) | ?_CallMemberFunction2@@YGXPAX00H@Z | 0x100 |
0x0000 | 0x40FCAF | void __stdcall _UnwindNestedFrames(struct EHRegistrationNode *, struct EHExceptionRecord *) | ?_UnwindNestedFrames@@YGXPAUEHRegistrationNode@@PAUEHExceptionRecord@@@Z | 0x100 |
0x0000 | 0x40FCFE | ___CxxFrameHandler | ___CxxFrameHandler | 0x100 |
0x0000 | 0x40FD34 | ___CxxLongjmpUnwind@4 | ___CxxLongjmpUnwind@4 | 0x100 |
0x0000 | 0x40FD4E | void * __cdecl _CallCatchBlock2(struct EHRegistrationNode *, struct _s_FuncInfo const *, void *, int, unsigned long int) | ?_CallCatchBlock2@@YAPAXPAUEHRegistrationNode@@PBU_s_FuncInfo@@PAXHK@Z | 0x100 |
0x0000 | 0x40FDC7 | int __cdecl _CallSETranslator(struct EHExceptionRecord *, struct EHRegistrationNode *, void *, void *, struct _s_FuncInfo const *, int, struct EHRegistrationNode *) | ?_CallSETranslator@@YAHPAUEHExceptionRecord@@PAUEHRegistrationNode@@PAX2PBU_s_FuncInfo@@H1@Z | 0x100 |
0x0000 | 0x40FEF2 | struct _s_TryBlockMapEntry const * __cdecl _GetRangeOfTrysToCheck(struct _s_FuncInfo const *, int, int, unsigned int *, unsigned int *) | ?_GetRangeOfTrysToCheck@@YAPBU_s_TryBlockMapEntry@@PBU_s_FuncInfo@@HHPAI1@Z | 0x100 |
0x0000 | 0x40FF70 | __global_unwind2 | __global_unwind2 | 0x100 |
0x0000 | 0x40FFB2 | __local_unwind2 | __local_unwind2 | 0x100 |
0x0000 | 0x41000A | __NLG_Return2 | __NLG_Return2 | 0x100 |
0x0000 | 0x41001A | __abnormal_termination | __abnormal_termination | 0x100 |
0x0000 | 0x41003D | __NLG_Notify1 | __NLG_Notify1 | 0x100 |
0x0000 | 0x410046 | __NLG_Notify | __NLG_Notify | 0x100 |
0x0000 | 0x410059 | __NLG_Dispatch | __NLG_Dispatch | 0x100 |
0x0000 | 0x41005E | __onexit | __onexit | 0x100 |
0x0000 | 0x4100DC | _atexit | _atexit | 0x100 |
0x0000 | 0x4100EE | ___onexitinit | ___onexitinit | 0x100 |
0x0000 | 0x41011D | _fprintf | _fprintf | 0x100 |
0x0000 | 0x410159 | _vsprintf | _vsprintf | 0x100 |
0x0000 | 0x4101AA | _srand | _srand | 0x100 |
0x0000 | 0x4101B7 | _rand | _rand | 0x100 |
0x0000 | 0x4101D9 | _floor | _floor | 0x100 |
0x0000 | 0x4102A8 | __fpmath | __fpmath | 0x100 |
0x0000 | 0x4102BF | __fpclear | __fpclear | 0x100 |
0x0000 | 0x4102C0 | __cfltcvt_init | __cfltcvt_init | 0x100 |
0x0000 | 0x4102F8 | ___setfflag | ___setfflag | 0x100 |
0x0000 | 0x410308 | __ftol | __ftol | 0x100 |
0x0000 | 0x410330 | __CIacos | __CIacos | 0x100 |
0x0000 | 0x410344 | _acos | _acos | 0x100 |
0x0000 | 0x4103FB | _atof | _atof | 0x100 |
0x0000 | 0x410460 | _fmod | _fmod | 0x100 |
0x0000 | 0x41046A | __CIfmod | __CIfmod | 0x100 |
0x0000 | 0x410492 | __cinit | __cinit | 0x100 |
0x0000 | 0x4104BF | _exit | _exit | 0x100 |
0x0000 | 0x4104D0 | __exit | __exit | 0x100 |
0x0000 | 0x4104E1 | __cexit | __cexit | 0x100 |
0x0000 | 0x4104F0 | __c_exit | __c_exit | 0x100 |
0x0000 | 0x4105A4 | __lockexit | __lockexit | 0x100 |
0x0000 | 0x4105AD | __unlockexit | __unlockexit | 0x100 |
0x0000 | 0x4105E0 | _strchr | _strchr | 0x100 |
0x0000 | 0x4105E6 | ___from_strstr_to_strchr | ___from_strstr_to_strchr | 0x100 |
0x0000 | 0x41069C | _sscanf | _sscanf | 0x100 |
0x0000 | 0x4106D0 | _strstr | _strstr | 0x100 |
0x0000 | 0x410750 | _fread | _fread | 0x100 |
0x0000 | 0x41077F | __fread_lk | __fread_lk | 0x100 |
0x0000 | 0x410867 | _fwrite | _fwrite | 0x100 |
0x0000 | 0x410896 | __fwrite_lk | __fwrite_lk | 0x100 |
0x0000 | 0x4109A0 | _rewind | _rewind | 0x100 |
0x0000 | 0x410A04 | __findfirst | __findfirst | 0x100 |
0x0000 | 0x410AD1 | __findnext | __findnext | 0x100 |
0x0000 | 0x410B99 | __findclose | __findclose | 0x100 |
0x0000 | 0x410BB9 | ___timet_from_ft | ___timet_from_ft | 0x100 |
0x0000 | 0x410C1D | _remove | _remove | 0x100 |
0x0000 | 0x410C47 | __unlink | __unlink | 0x100 |
0x0000 | 0x410C52 | _calloc | _calloc | 0x100 |
0x0000 | 0x410CDF | _time | _time | 0x100 |
0x0000 | 0x410DBB | _fseek | _fseek | 0x100 |
0x0000 | 0x410DE7 | __fseek_lk | __fseek_lk | 0x100 |
0x0000 | 0x410E74 | _ftell | _ftell | 0x100 |
0x0000 | 0x410E96 | __ftell_lk | __ftell_lk | 0x100 |
0x0000 | 0x410FF7 | _realloc | _realloc | 0x100 |
The Blast Graphics 3d library, which is 3D library used in early Merkury engine games is either located in the bg.dll file or compiled statically in the executable.
The following games have references to Blast graphics in their executables or contain the windows dynamic library bg.dll:
Thanks to compilers adding some additional metadata we know at least some of the file names that made up the source code for the Blast Graphics Library:
Looking at the exports table of one the the dlls we know it has the following functionality:
Name | Location | Function Signature | Function Size (bytes) | Description |
---|---|---|---|---|
AVIFileExit | 0x10032f0a | AVIFileExit() | 6 | |
AVIFileInit | 0x10032f34 | AVIFileInit() | 6 | |
AVIStreamInfoA | 0x10032f1c | AVIStreamInfoA() | 6 | |
AVIStreamLength | 0x10032f22 | AVIStreamLength() | 6 | |
AVIStreamOpenFromFileA | 0x10032f2e | AVIStreamOpenFromFileA() | 6 | |
AVIStreamRead | 0x10032f46 | AVIStreamRead() | 6 | |
AVIStreamReadFormat | 0x10032f28 | AVIStreamReadFormat() | 6 | |
AVIStreamRelease | 0x10032f10 | AVIStreamRelease() | 6 | |
BG_AddObject | 0x1000d1f0 | BG_AddObject(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8) | 5127 | |
BG_AddProjection | 0x10010380 | BG_AddProjection(param_1, param_2, param_3, param_4, param_5, param_6) | 835 | |
BG_AddQuad | 0x1000eda0 | BG_AddQuad(param_1, param_2, param_3) | 5566 | |
BG_AddSprite | 0x10008290 | BG_AddSprite(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10) | 5445 | |
BG_AddSpriteSection | 0x10008240 | BG_AddSpriteSection(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10, param_11) | 78 | |
BG_AddText | 0x10001aa0 | BG_AddText(param_1, param_2, param_3, param_4, param_5) | 1030 | |
BG_AddText2 | 0x10001eb0 | BG_AddText2(param_1, param_2, param_3, param_4, param_5, param_6) | 1030 | |
BG_AllocObject | 0x100028a0 | BG_AllocObject() | 43 | |
BG_AlterVertice | 0x10005500 | BG_AlterVertice(param_1, param_2, param_3, param_4, param_5) | 93 | |
BG_Animate | 0x100055e0 | BG_Animate(param_1, param_2) | 60 | |
BG_AnimateCustom | 0x100056e0 | BG_AnimateCustom(param_1, param_2, param_3) | 683 | |
BG_AnimateNode | 0x10005620 | BG_AnimateNode(param_1, param_2, param_3, param_4) | 177 | |
BG_BeginFullscreen | 0x10012750 | BG_BeginFullscreen() | 6 | |
BG_CallLogics | 0x10012370 | BG_CallLogics() | 198 | |
BG_ChangeRes | 0x10023160 | BG_ChangeRes() | 1 | |
BG_ClearObjects | 0x100231b0 | BG_ClearObjects() | 78 | |
BG_ClearRGB | 0x1001e870 | BG_ClearRGB(param_1, param_2, param_3) | 861 | |
BG_ClipOff | 0x10002490 | BG_ClipOff() | 28 | |
BG_ClipOn | 0x1001f470 | BG_ClipOn(param_1, param_2, param_3, param_4) | 280 | |
BG_CopyTexture | 0x1001d0c0 | BG_CopyTexture(param_1, param_2) | 345 | |
BG_CreateFont | 0x1001ef40 | BG_CreateFont(param_1, param_2) | 1197 | |
BG_DebugText | 0x10002430 | BG_DebugText(param_1) | 41 | |
BG_Disable | 0x1001dfc0 | BG_Disable(param_1) | 52 | |
BG_DisableOmni | 0x10009c20 | BG_DisableOmni(param_1) | 37 | |
BG_DrawBkg | 0x1001fa40 | BG_DrawBkg(param_1) | 378 | |
BG_DrawObjects | 0x10020c80 | BG_DrawObjects() | 6096 | |
BG_DrawOverlay | 0x10020140 | BG_DrawOverlay(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10, param_11, param_12, param_13, param_14, param_15, param_16, param_17, param_18, param_19, param_20, param_21, param_22) | 2797 | |
BG_DrawText | 0x100022c0 | BG_DrawText(param_1, param_2, param_3, param_4, param_5, param_6) | 359 | |
BG_Enable | 0x1001df40 | BG_Enable(param_1) | 51 | |
BG_EnableOmni | 0x10009c50 | BG_EnableOmni(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8) | 345 | |
BG_EnableSub | 0x100016d0 | BG_EnableSub(param_1, param_2, param_3) | 50 | |
BG_EnableVal | 0x1001df80 | BG_EnableVal(param_1, param_2) | 50 | |
BG_EnumDirectSound | 0x10010b20 | BG_EnumDirectSound() | 5 | |
BG_EnumerateModes | 0x1001f5f0 | BG_EnumerateModes() | 163 | |
BG_EnumHardware | 0x1001dc10 | BG_EnumHardware() | 28 | |
BG_EraseBkg | 0x1001e730 | BG_EraseBkg(param_1) | 91 | |
BG_Exit | 0x1001e000 | BG_Exit() | 260 | |
BG_Flip | 0x1001ebd0 | BG_Flip(param_1, param_2) | 742 | |
BG_FPS | 0x10002480 | BG_FPS() | 7 | |
BG_FrameUsed | 0x10012730 | BG_FrameUsed() | 3 | |
BG_FreeObject | 0x100028d0 | BG_FreeObject(param_1) | 694 | |
BG_GetCamera | 0x10011e40 | BG_GetCamera(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8) | 129 | |
BG_GetCaps | 0x10023170 | BG_GetCaps(param_1) | 42 | |
BG_GetDirectSound | 0x10010b30 | BG_GetDirectSound(param_1) | 14 | |
BG_GetDriverID | 0x1001ffd0 | BG_GetDriverID() | 14 | |
BG_GetFaceCount | 0x100076b0 | BG_GetFaceCount(param_1) | 22 | |
BG_GetFile | 0x100019d0 | BG_GetFile(param_1) | 14 | |
BG_GetFloor | 0x100065e0 | BG_GetFloor(param_1, param_2, param_3, param_4) | 363 | |
BG_GetFontMat | 0x10002460 | BG_GetFontMat(param_1) | 32 | |
BG_GetFrameCount | 0x10005990 | BG_GetFrameCount(param_1) | 40 | |
BG_GetFrontFaces | 0x100076a0 | BG_GetFrontFaces() | 6 | |
BG_GetFXPos | 0x10009b40 | BG_GetFXPos(param_1, param_2, param_3, param_4, param_5) | 174 | |
BG_GetHardware | 0x100019e0 | BG_GetHardware(param_1) | 49 | |
BG_GetInitError | 0x100024b0 | BG_GetInitError() | 14 | |
BG_GetLastColor | 0x1000e740 | BG_GetLastColor(param_1, param_2, param_3) | 567 | |
BG_GetLastMatNum | 0x1000ea30 | BG_GetLastMatNum() | 41 | |
BG_GetLastPlane | 0x1000e980 | BG_GetLastPlane(param_1, param_2, param_3, param_4) | 176 | |
BG_GetLastPoint | 0x1000e710 | BG_GetLastPoint(param_1, param_2, param_3) | 37 | |
BG_GetLastVector | 0x1000e680 | BG_GetLastVector(param_1, param_2, param_3) | 136 | |
BG_GetLocalNodePos | 0x10001950 | BG_GetLocalNodePos(param_1, param_2, param_3, param_4, param_5) | 113 | |
BG_GetLogicMul | 0x10012360 | BG_GetLogicMul() | 7 | |
BG_GetMatFaces | 0x100097e0 | BG_GetMatFaces(param_1, param_2, param_3, param_4, param_5) | 115 | |
BG_GetMatID | 0x10002870 | BG_GetMatID(param_1) | 41 | |
BG_GetMatNum | 0x1001ff80 | BG_GetMatNum(param_1) | 14 | |
BG_GetNearestColor | 0x10012740 | BG_GetNearestColor() | 3 | |
BG_GetNodeCount | 0x10001710 | BG_GetNodeCount(param_1) | 44 | |
BG_GetNodeName | 0x10001740 | BG_GetNodeName(param_1, param_2) | 135 | |
BG_GetNodeNum | 0x10001620 | BG_GetNodeNum(param_1, param_2) | 165 | |
BG_GetNodePos | 0x100017d0 | BG_GetNodePos(param_1, param_2, param_3, param_4, param_5) | 370 | |
BG_GetObjectBox | 0x100073e0 | BG_GetObjectBox(param_1, param_2, param_3, param_4, param_5, param_6, param_7) | 144 | |
BG_GetVertice | 0x10005560 | BG_GetVertice(param_1, param_2, param_3, param_4, param_5) | 121 | |
BG_GetVerticeCount | 0x100076d0 | BG_GetVerticeCount(param_1) | 21 | |
BG_GetWorldFXPos | 0x10009860 | BG_GetWorldFXPos(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10, param_11, param_12) | 731 | |
BG_GetYfromXZ | 0x10006420 | BG_GetYfromXZ(param_1, param_2, param_3) | 29 | |
BG_GrabMaterial | 0x100234a0 | BG_GrabMaterial(param_1, param_2, param_3, param_4, param_5) | 126 | |
BG_Init | 0x1001f6a0 | BG_Init(param_1, param_2) | 921 | |
BG_InitGL | 0x10012760 | BG_InitGL(param_1, param_2, param_3) | 19 | |
BG_KeyDown | 0x1001c590 | BG_KeyDown(param_1) | 17 | |
BG_Line | 0x1001e110 | BG_Line(param_1, param_2, param_3, param_4, param_5, param_6, param_7) | 844 | |
BG_LineIntersect | 0x1000ea90 | BG_LineIntersect(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10) | 423 | |
BG_LineIntersectCircle | 0x1000ec40 | BG_LineIntersectCircle(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9) | 340 | |
BG_LoadAnimation | 0x100041c0 | BG_LoadAnimation(param_1, param_2, param_3) | 4684 | |
BG_LoadBkg | 0x1001e790 | BG_LoadBkg(param_1, param_2) | 222 | |
BG_LoadCameraTrack | 0x10011910 | BG_LoadCameraTrack(param_1) | 1125 | |
BG_LoadColorMap | 0x100059c0 | BG_LoadColorMap(param_1, param_2) | 712 | |
BG_LoadMatProperties | 0x10022eb0 | BG_LoadMatProperties(param_1) | 679 | |
BG_LoadObject | 0x10005cb0 | BG_LoadObject(param_1, param_2, param_3, param_4, param_5, param_6, param_7, param_8, param_9, param_10, param_11, undefined1 param_12, undefined1 param_13, undefined1 param_14, undefined1 param_15, undefined1 param_16, undefined1 param_17, undefined1 param_18, undefined1 param_19, undefined2 param_20) | 1904 | |
BG_MatriceClear | 0x100076f0 | BG_MatriceClear() | 22 | |
BG_MatriceCustom | 0x10007ae0 | BG_MatriceCustom(param_1) | 107 | |
BG_MatricePoint | 0x10007b50 | BG_MatricePoint(param_1, param_2, param_3, param_4, param_5, param_6) | 151 | |
BG_MatriceRotate | 0x10007710 | BG_MatriceRotate(param_1, param_2, param_3, param_4) | 464 | |
BG_MatriceScale | 0x100079e0 | BG_MatriceScale(param_1, param_2, param_3) | 247 | |
BG_MatriceTranslate | 0x100078e0 | BG_MatriceTranslate(param_1, param_2, param_3) | 247 | |
BG_MatText | 0x1001d220 | BG_MatText(param_1) | 704 | |
BG_MoveWindow | 0x1001f3f0 | BG_MoveWindow(param_1) | 119 | |
BG_PageFlip | 0x1001eec0 | BG_PageFlip(param_1) | 90 | |
BG_PageFlipDC | 0x1001ef20 | BG_PageFlipDC(param_1) | 19 | |
BG_PlayAVI | 0x100011d0 | BG_PlayAVI(param_1, param_2, param_3, param_4) | 650 | |
BG_PopBkg | 0x1001d050 | BG_PopBkg() | 112 | |
BG_Profile | 0x10001570 | BG_Profile(param_1, param_2) | 168 | |
BG_PushBkg | 0x1001cf20 | BG_PushBkg() | 299 | |
BG_RestoreSurfaces | 0x1001ff90 | BG_RestoreSurfaces() | 49 | |
BG_SaveBitmap | 0x1001dc30 | BG_SaveBitmap(param_1, param_2, param_3, param_4, param_5, param_6, param_7) | 771 | |
BG_SaveObject | 0x10005c90 | BG_SaveObject(param_1, param_2) | 26 | |
BG_SaveViewTransform | 0x10010360 | BG_SaveViewTransform(param_1) | 21 | |
BG_ScreenPoint | 0x10007500 | BG_ScreenPoint(param_1, param_2, param_3, param_4, param_5) | 248 | |
BG_ScreenPoint3D | 0x10007600 | BG_ScreenPoint3D(param_1, param_2, param_3, param_4, param_5, param_6) | 159 | |
BG_SetAmbientLight | 0x100025f0 | BG_SetAmbientLight(param_1) | 10 | |
BG_SetCamera | 0x10011ed0 | BG_SetCamera(param_1, param_2, param_3, param_4, param_5) | 283 | |
BG_SetCameraTrack | 0x100118c0 | BG_SetCameraTrack(param_1) | 72 | |
BG_SetCameraVector | 0x10011d80 | BG_SetCameraVector(param_1, param_2, param_3, param_4, param_5, param_6) | 184 | |
BG_SetCameraZoom | 0x10011ff0 | BG_SetCameraZoom(param_1, param_2) | 86 | |
BG_SetFarPlane | 0x1001ffe0 | BG_SetFarPlane(param_1, param_2) | 91 | |
BG_SetFarPlaneEx | 0x10009bf0 | BG_SetFarPlaneEx(param_1, param_2, param_3) | 45 | |
BG_SetFileCallback | 0x10012350 | BG_SetFileCallback(param_1) | 10 | |
BG_SetFontHandle | 0x100231a0 | BG_SetFontHandle(param_1) | 10 | |
BG_SetFOV | 0x1000e600 | BG_SetFOV(param_1) | 118 | |
BG_SetHardware | 0x1001dbf0 | BG_SetHardware(param_1) | 24 | |
BG_SetLightColor | 0x100025c0 | BG_SetLightColor(param_1, param_2, param_3) | 40 | |
BG_SetLightVector | 0x10002540 | BG_SetLightVector(param_1, param_2, param_3) | 116 | |
BG_SetMatColor | 0x10002770 | BG_SetMatColor(param_1, param_2, param_3, param_4) | 65 | |
BG_SetMatColorA | 0x100027c0 | BG_SetMatColorA(param_1, param_2, param_3, param_4, param_5) | 65 | |
BG_SetMatFrame | 0x1000ea60 | BG_SetMatFrame(param_1, param_2) | 42 | |
BG_SetMatProperty | 0x100224c0 | BG_SetMatProperty(param_1, param_2) | 2544 | |
BG_SetMatRotate | 0x10002680 | BG_SetMatRotate(param_1, param_2, param_3, param_4) | 73 | |
BG_SetMatScroll | 0x100026d0 | BG_SetMatScroll(param_1, param_2, param_3) | 146 | |
BG_SetNode | 0x1000a490 | BG_SetNode(param_1, param_2, param_3) | 99 | |
BG_SetObjectLight | 0x10002600 | BG_SetObjectLight(param_1, param_2) | 49 | |
BG_SetObjectLightA | 0x10002640 | BG_SetObjectLightA(param_1, param_2, param_3) | 49 | |
BG_Status | 0x10002810 | BG_Status() | 95 | |
BG_SurfaceHit | 0x10006750 | BG_SurfaceHit(param_1, param_2, param_3, param_4, param_5, param_6, param_7) | 3212 | |
BG_Text | 0x1001e580 | BG_Text(param_1, param_2, param_3) | 419 | |
BG_TextLen | 0x1001e460 | BG_TextLen(param_1) | 283 | |
BG_TextLenFont | 0x10001a60 | BG_TextLenFont(param_1, param_2) | 59 | |
BG_TweenObject | 0x10005410 | BG_TweenObject(param_1, param_2, param_3, param_4) | 230 | |
BG_WaveAnimate | 0x10024c80 | BG_WaveAnimate(param_1) | 1257 | |
BG_WaveCollide | 0x10025360 | BG_WaveCollide(param_1, param_2, param_3, param_4, param_5, param_6) | 501 | |
BG_WaveCollidePost | 0x10025560 | BG_WaveCollidePost(param_1, param_2, param_3, param_4) | 880 | |
BG_WaveCreate | 0x10024200 | BG_WaveCreate(param_1, param_2, param_3, param_4, param_5, param_6, param_7) | 1743 | |
BG_WaveGetFX | 0x100258f0 | BG_WaveGetFX(param_1, param_2) | 23 | |
BG_WaveGetLastFrame | 0x10024020 | BG_WaveGetLastFrame() | 7 | |
BG_WaveGetPitch | 0x10025190 | BG_WaveGetPitch(param_1, param_2, param_3) | 320 | |
BG_WaveGetPitchPost | 0x100252d0 | BG_WaveGetPitchPost() | 7 | |
BG_WaveGetTime | 0x100252e0 | BG_WaveGetTime(param_1) | 30 | |
BG_WaveGetTimeXZ | 0x10024130 | BG_WaveGetTimeXZ(param_1, param_2) | 194 | |
BG_WaveHighestPoint | 0x100240f0 | BG_WaveHighestPoint(param_1, param_2, param_3) | 49 | |
BG_WaveLoadAnimation | 0x10024910 | BG_WaveLoadAnimation(param_1) | 832 | |
BG_WaveScale | 0x100248d0 | BG_WaveScale(param_1, param_2, param_3) | 20 | |
BG_WaveScaleColumn | 0x10024c50 | BG_WaveScaleColumn(param_1, param_2, param_3) | 44 | |
BG_WaveScroll | 0x10025300 | BG_WaveScroll(param_1, param_2) | 95 | |
BG_WaveSetControlPoints | 0x100248f0 | BG_WaveSetControlPoints(param_1) | 31 | |
BG_WaveSetLipZ | 0x10025920 | BG_WaveSetLipZ(param_1) | 10 | |
BG_WaveSetTime | 0x10025170 | BG_WaveSetTime(param_1, param_2) | 27 | |
BG_WaveSetValues | 0x100258d0 | BG_WaveSetValues(param_1) | 30 | |
BG_WaveSmooth | 0x10025910 | BG_WaveSmooth(param_1) | 10 | |
BG_WorldPoint | 0x10007470 | BG_WorldPoint(param_1, param_2, param_3, param_4, param_5, param_6) | 139 | |
BS_AllocSound | 0x100109f0 | BS_AllocSound() | 40 | |
BS_EnumDirectSound | 0x100107b0 | BS_EnumDirectSound() | 28 | |
BS_Exit | 0x10010950 | BS_Exit() | 66 | |
BS_FreeSound | 0x100109d0 | BS_FreeSound(param_1) | 28 | |
BS_GetDirectSound | 0x100107d0 | BS_GetDirectSound(param_1) | 33 | |
BS_Init | 0x10010800 | BS_Init(param_1, param_2) | 324 | |
BS_IsSoundPlaying | 0x10010b00 | BS_IsSoundPlaying(param_1) | 30 | |
BS_LoadSound | 0x100109a0 | BS_LoadSound(param_1, param_2, param_3) | 38 | |
BS_PlaySound | 0x10010a20 | BS_PlaySound(param_1, param_2) | 41 | |
BS_SetSoundFrequency | 0x10010aa0 | BS_SetSoundFrequency(param_1, param_2) | 33 | |
BS_SetSoundPosition | 0x10010ad0 | BS_SetSoundPosition(param_1, param_2, param_3, param_4) | 43 | |
BS_SetSoundVolume | 0x10010a70 | BS_SetSoundVolume(param_1, param_2) | 33 | |
BS_StopSound | 0x10010a50 | BS_StopSound(param_1) | 28 | |
Catch@10027184 | 0x10027184 | Catch@10027184() | 16 | |
Catch@10027715 | 0x10027715 | Catch@10027715() | 29 | |
DirectDrawCreate | 0x10025948 | DirectDrawCreate() | 6 | |
DirectDrawCreateEx | 0x1002593c | DirectDrawCreateEx() | 6 | |
DirectDrawEnumerateA | 0x10025942 | DirectDrawEnumerateA() | 6 | |
entry | 0x10034385 | entry(param_1, param_2, param_3) | 157 |
Although Blast Graphics was a 3D library it also contained alot of game engine functionality such as sound, keyboard input, AVI video playback, animation and more.
Mike Stewart’s Pro Bodyboarding (MSPB) was released to good reviews and would become Gee Whiz! Entertainment’s greatest accompllishment as a studio until they went on to become Krome Studios in November of the same year.
The official Krome Studio’s website from 2001 claimed that it was using the Merkury engine, but analysing the game files has no mention of the Merkury engine and instead seems to be using a custom engine called BEAST and Blast Graphics for the 3D.
It has a file called beast.cfg which has the following string at the top: BEAST Config File (c) Copyright 1999 Mind Mechanics
. Note that the next game that used the same engine, Championship Surfer had the name of the engine as Beast98 during development, the 1998 version of the BEAST game engine.
As for Mind Mechanics, they were previously known as SubZero software and had worked on multiple games with Gee Whizz! in the past. Including the Halloween Harry series and their website talked about plans for a 3rd in the series that was 3D, until their site went down at the end of 1999 (when Krome Studios was formed). They are also known for their game Rapid Glider The Race to Galamax 7.
We at least know that the wave generation engine was used in three games, as on the website announcing their new PS2 game Sunny Garcia Surfing it proudly announces it :
Ground breaking, 3rd generation, proprietary wave generation engine, first seen in Mike Stewart’s Pro Bodyboarding, then in Championship Surfer, creates stunningly realistic wave sets in full 3D.
On 10th of September 1998, Gee Whiz! Entertainment released a press release announcing that they were working on a new 3D title called The Chronicles of Jaruu Tenk with a planned release date of 4th Quarter 1998, however like most ambitious game project it was actually released later on 4th October 1999 12.
It was later released for free by John Passfield on his site Free Stuff! - Passfield Games and is still available to this day for everyone to enjoy!
It was so unique that they coined their own genre: “Screen Opera” and it was followed by another game in the same genre very shortly after called Halloween Spirit Board. They also planned a third “Screen Opera” game called Star Date but it was never released.
It was inspired by David Crane’s Little Computer People and then sold on their own Screen Opera website 13.
The was written in either C or C++ and it is built using DirectX 7 and likely Visual C++ as it uses the Microsoft Visual C++ Runtime Library.
The interesting thing about the game is it was listed as a Merkury engine game on the official Krome Studios website back in 2001 1. So if this was built in 1999 then it makes it one of the earliest games based on the Merkury engine!
Although the name “Merkury” wouldn’t appear until the founding of Krome Studios so it used the name Blast Graphics for the 3D engine with the functionality contained in bg.dll. See the Blast graphics section for more information.
Some notes about Jaruu:
Released on the 25th October 1999 for a price of $9.95 USD Halloween Spirit Board, it was the second game that Gee Wizz! created in a genre that they called “Screen Opera” 14, the first being Jaruu Tenk. Similar to Jaruu Tenk, you can download the game for free on John Passfield’s site: Free Stuff! - Passfield Games.
Although it is odd that both Jaruu Tenk and Halloween Spirit Board were released in exactly the same month but that is what their official press releases say 14.
Championship Surfer is a 2000 game available for Windows, Dreamcast (2001) and PS1 (2001), the Windows and Dreamcast versions are the first game credited as using the Merkury engine, with no mention of the engine for the PS1 release.
However it is presumed some of the code was re-used between the Windows and PS1 games so it is likely that even the PS1 version is using some Merkury engine code.
The PS1 version of Championship Surfer (SLUS_012.16) has no mention of the Merkury engine and it was developed by a compeltely different set of programmers at Krome:
The PS1 version does not use the RKV archive format and instead has files seperately on the disc in various PS1 optimized file formats (e.g TIM).
This is common with PS1 games as they all use a standard ISO 9660 filesystem, allowing individual files (textures, models, audio, maps, scripts, etc.) to be stored as separate, accessible files.
This makes it easy for the game executable to read specific assets directly from the disc and was practical considering memory limits and the way the PS1’s BIOS exposed disc access.
The Windows and Dreamcast versions of Championship Surfer (2001) is the first game credited as using the Merkury engine, with Tony Ball being listed as the Merkury engine programmer in the credits.
It is also the first game that uses the RKV archive format (still never found out what it stands for) in both the Dreamcast and Windows versions, see the section below for the format of these archives as they differ from later Merkury engine games that use the same file extension (.rkv).
Thanks to strings left in the Dreamcast version of the game we know that the main game specific code was in a folder called gamecode under the 1998 Version of their BEAST game engine called beast98. Interestingly call the game HotWaves internally which is a nice nod to Mattel who own the Hot wheels franchise and were also the publisher for this game!
The executable has a few paths left intact which give a hint as to the folder structure:
File Path | Description |
---|---|
C:\Src\beast98\beast98.cpp | |
C:\Src\beast98\animscript.cpp | |
C:\Src\beast98\gamecode\arcade.cpp | |
C:\Src\beast98\gamecode\championship.cpp | |
C:\Src\beast98\gamecode\credits.cpp | |
C:\Src\beast98\gamecode\duck.cpp | |
C:\Src\beast98\gamecode\elimination.cpp | |
C:\Src\beast98\gamecode\freesurf.cpp | |
C:\Src\beast98\gamecode\game.cpp | |
C:\Src\beast98\gamecode\mainmenu.cpp | |
C:\Src\beast98\gamecode\Replay.cpp | |
C:\Src\beast98\gamecode\Rumble.cpp | |
C:\Src\beast98\gamecode\rumbleicon.cpp | |
C:\Src\beast98\gamecode\settings.cpp | |
C:\Src\beast98\gamecode\wavegen.cpp | |
C:\Src\beast98\gamecode\surfdude.cpp | |
C:\Src\beast98\gamecode\dolphin.cpp | |
C:\Src\beast98\gamecode\photoman.cpp | |
C:\Src\beast98\gamecode\islandboy.cpp | |
C:\Src\beast98\gamecode\diver.cpp | |
C:\Src\beast98\gamecode\lifeguard.cpp | |
C:\Src\beast98\gamecode\femaleswimmer.cpp | |
C:\Src\beast98\gamecode\helicopter.cpp | |
C:\Src\beast98\gamecode\seagull.cpp | |
C:\Src\beast98\gamecode\shark.cpp | |
C:\Src\beast98\gamecode\world.cpp | |
C:\Src\beast98\gamecode\TextureMatrix.cpp |
The PC version also used the Beast98 code even although the strings above were stripped from the binary, we know this as there was a crash.log
file left in the Surf_PC.rkv archive:
("C:\src\beast98\PCRelease\Hotwaves.exe" -windowed -lang=2 -nomusic)
> Exception !!
C:\src\beast98\gamecode\game.cpp @ 3055
A few paths in the dreamcast version hint at there being a menu library for the main screens (frontend) with the following source files:
A few paths in the dreamcast version hint at there being a standard platform library with the following source files:
Also a few file paths are related to Blast Graphics which uses DirectX 7 on Dreamcast:
Based on other debug strings from error messages we know that the BG library contained the following functions:
The dreamcast version uses CRI Middleware’s Sound Factory version 1.51 (built in December 1999) for its audio processing, thanks to this information being left in the built executable.
Specifically we know it uses the following builds (all from December 8th 1999):
Other notes:
The windows version was also released in a collection called Crazy Fun Games by a french company called fun radio and Ubisoft, but it is currently unknown if it contains any differences or debug symbols present 15.
The RKV archive format differs from the one used in the more modern games such as Star Wars, but this same format was also used in early PS2 games running on the Merkury engine such as Jimmy Neutron: Jet Fusion!
It seems to be the first game that introduced the naming convention for the RKV archives which all have a 2-3 character suffix based on the platform the assets are for:
Since there is already both an RKV.bms
and RKV2.bms
script to extract RKV files with the QuickBMS tool, I have decided to call the BMS script to extract the early version of the RKV format RKV0.bms, here is a version that works with Surf_PC.rkv and some early PS2 games:
# QuickBMS: Old version of Merkury engine games such as Championship Surfing and PS2 games like Jimmy Neutron
get FILESIZE asize
if FILESIZE < 8
print "File too small"
cleanexit
endif
goto -8
get NUM_FILES long
get NUM_DIRS long
# directories block (NUM_DIRS * 256) ends at EOF-8
math DIRS_SIZE = NUM_DIRS
math DIRS_SIZE *= 256
math DIRS_START = FILESIZE
math DIRS_START -= 8
math DIRS_START -= DIRS_SIZE
print "Number of directories: %NUM_DIRS%"
print "Number of file entries: %NUM_FILES%"
print "Reading %DIRS_SIZE% bytes of directory entries starting at 0x%DIRS_START|X%"
# read and store dir names by index
goto DIRS_START
for i = 0 < NUM_DIRS
getdstring DIR_NAME 256
print "DIR[%i%]: %DIR_NAME%"
putarray 0 i DIR_NAME
next i
# files block (NUM_FILES * 64) is before directories
math FILES_SIZE = NUM_FILES
math FILES_SIZE *= 64
math FILES_START = DIRS_START
math FILES_START -= FILES_SIZE
print "Reading %FILES_SIZE% bytes of file entries starting at 0x%FILES_START|X%"
goto FILES_START
for i = 0 < NUM_FILES
getdstring FILE_NAME 32
get FOLDER_ID long
get FILE_SIZE long
get FILE_ZERO long
get FILE_OFFSET long
get FILE_META3 long
getdstring FILE_RESERVED 12
# resolve folder name if valid
set MATCH_DIR string ""
if FOLDER_ID >= 0
if FOLDER_ID < NUM_DIRS
getarray MATCH_DIR 0 FOLDER_ID
endif
endif
# build output path
strlen DIRLEN MATCH_DIR
set FULL_NAME string FILE_NAME
if DIRLEN > 0
set FULL_NAME string MATCH_DIR
string FULL_NAME + /
string FULL_NAME + FILE_NAME
endif
print "FILE[%i%] name: %FULL_NAME|S% is located at %FILE_OFFSET|X% with size: %FILE_SIZE|X%"
if FILE_ZERO != 0
print "FILE[%i%] Normally this is zero: %FILE_ZERO|X%"
endif
strlen RLEN FILE_RESERVED
if RLEN != 0
# Not Sure what this data is (CRC? Timestamps?)
# print "FILE[%i%] reserved: %FILE_RESERVED|X%"
endif
# extract
if FILE_OFFSET != -1
log FULL_NAME FILE_OFFSET FILE_SIZE
endif
next i
It would have been used in the cancelled Kat Burglar game that Krome Studios was working on in late 2000, which even advertised on their official website about the use of their proprietary Merkury engine 16:
Kat Burglar is a 3rd person action-adventure game set in the swinging 60's. Katherine Kelly is a millionaire playgirl by day and a Robin Hood style thief by night. Katherine ("Kat" to her friends) specializes in stealing hard to get items from museums and fortified storehouses.
But she doesn't steal for the money…
Of course we're not going to give it all away just yet. We are keeping a few things under our hat - Kat Burglar is full of secrets and surprises. What we can tell you is that Kat is being developed for next generation console platforms and uses our proprietary 3D graphics engine Merkury.
Kat Burglar focuses heavily on characters and storyline. This game isn't a shooter. While there will be occasions where Kat won't be able to avoid a fight, more emphasis is placed on stealth. As Kat Burglar, the player will be part of the story that unfolds on the island of Mont-St-Michel. Kat will also come across many characters in the game, some friends, some enemies and some she's just not sure about.
GamesOnNet a site that now seems to be defunct had the following to say about Kat Burglar 17:
One of the games that came closest to making it was Kat Burglar, an action-stealth game that began life in late 1998 during Steve’s time at Gee Whiz! Entertainment with John Passfield. A light-hearted game with a James Bond-style 60’s flair, Steve recalls that they encountered some difficulty selling their prototype to publishers in 2000. “It was about the same time that No One Lives Forever was being shown around. And the problem we were running into when we were showing publishers, was ‘Monolith is showing this game where they have this 60’s female spy, and you’re showing us this game with a 60’s female thief, you can’t have two games set in the 60’s with a female character in them! That’s the same thing!’. And we were like ‘Wait, what?’”
Recounting with a touch of bitterness that it was apparently okay to have a dozen identical “muscular space marine” games on the market at the same time, Steve and the team were forced to shelve the game. “They just weren’t getting it, even if they did like the characters”, says Steve, remembering failed deals with partners like Mattel. “I’ll always remember the guys came back from one meeting with a publisher, and the publishers said ‘We’re pretty sure there’s already a 60’s female thief game with a character that has red hair’, and I’m standing there going 'Are they... talking about our game?'”.
Set on the island of Mont-St. Michael, Kat Burglar featured a number of adventure-game driven mechanics similar to those found in Flight of the Amazon Queen, as well as AI sidekicks who you could give orders to through hand gestures. The intent was to have a Zelda-style unlockable open world, with the island opening up to you as you progressed. Despite the game being developed to a playable state through one prototyped level, they were unable to secure a publisher. Opportunity did come knocking later in the year, as Sony expressed a desire to publish a cartoony platformer on their PS2 - a desire that Krome were only too happy to help fulfill. That game that would later go on to become TY The Tasmanian Tiger, and one of the company’s most iconic franchises.
Many of the ideas and concepts of Kat Burglar were eventually carried over into one of Krome’s last published titles, Blade Kitten - including a strong resemblance between Katherine Kelly of Kat Burglar and the pink-haired Kit Ballard of Blade Kitten. “I had all these elements I wanted to use but we apparently couldn’t do a 60’s game,” says Steve, “so I went and turned it into a sci-fi, anime game instead”.
More information on Kat Burglar can be found on Unseen64 Kat Burglar- Unseen64
The game Disney’s Extremely Goofy Skateboarding pre-dates the Merkury engine and was built to be windows-only, but it was released in 2001 the same year that they released Sunny Garcia Surfing which did use the Merkury engine. Presumably they were working on a new PS2 engine for the surfing game while working on the Disney game for windows, so it would not be easy to just port the skateboarding game over to the new engine.
Although it doesn’t use Merkury it would be interesting to see if any code from this game made it into early versions of the Merkury engine.
The 3D Engine programmer for the Goofy game, Tony Ball was also one of the founding developers of the Merkury engine, for this game the Blast graphics engine was compiled statically inside the executable.
Differences from the Merkury engine:
If you run the binwalk
command on the Skating.exe executable you find that it actually has a few embeded executables too:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DECIMAL HEXADECIMAL DESCRIPTION
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
0 0x0 Windows PE binary, machine type: Intel x86
510344 0x7C988 Copyright text: "Copyright 1998 Gilles Vollant "
510760 0x7CB28 CRC32 polynomial table, little endian
518636 0x7E9EC Copyright text: "Copyright (C) 1996, Thomas G. Lane"
862766 0xD2A2E Copyright text: "Copyright (c) 1993 Tal Nevo."
872435 0xD4FF3 Windows PE binary, machine type: Intel x86
889647 0xD932F Windows PE binary, machine type: Intel x86
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The copyright messages hint at a few things:
The executable also has a few file paths left in which give a hint about the folder structure:
The reason we know it uses Blast Graphics is due to the string BLASTGRAPHICS Build Date : %s
but not sure what the build date actually was for the BlastGraphics library for this game.
Since the data0.pkg format is just simple zip compression, it is very easy to extract and modify the assets, so lets take a look at what it contains, there are 1,207 files so we will group files by their extension in the table below:
Extension | Number of Files | Description |
---|---|---|
wav | 463 | Waveform audio file, uncompressed sound effects or music |
tga | 343 | Targa image file, common raster graphic format supporting alpha channels |
bmp | 131 | Bitmap image file (case variant) |
ase | 101 | 3DS MAX ASCII EXPORT for the 3D models |
rpl | 49 | resource package file? |
bad | 32 | Basic Animation Descriptor - plain text files for animations that link a mesh (.ase) with a skeleton (.ase) and a vertex animation (.vat) |
bmp | 27 | Bitmap image file, uncompressed raster graphics |
mp3 | 15 | Audio file in MPEG Layer-3 format, compressed music or sound effects |
lvl | 15 | Level data file in XML format, stores game level layouts |
mad | 15 | Material Data - Plain text file setting key value pairs for values such as “color .5 .5 1 .8” |
vat | 11 | Vertex Animation in VAT2 format (Linked Vertex Information File ver 2), used for complex mesh animations in games |
lang | 2 | Language or localization resource file |
txt | 2 | Plain text file, often for logs, documentation, or configs |
cfg | 1 | Configuration file, plain text settings |
The ASE files confirm that the game’s 3d models were creating using 3D Studio Max 3 or 4 back in 2001, but not sure the exact version of 3ds Max (does AsciiExport Version 2.00 narrow it down?).
They show how the 3D artists named their 3ds max scene files:
It also shows the organised folder structure used during development of the game:
G:\Goofy Skateboarding\data\Models\Textures\badge.tga
\\Krome-fs4\data12\Goofy\Goofy Skateboarding\data\Models\Textures\ramp2.tga
- Shared Network drive?\\Krome-fs4\data12\Goofy\Graphics\Screens\S08_Beach\S08_03_BoardWalk\textures\jetty.bmp
- I wonder why screen graphics were kept seperate?The level files are plain text XML data which links together all the other files, it is extremely modder friendly, here is an example:
<LEVEL NAME="Downtown" MESH="riverbend.ase" ENV="Cloud_Blue_env.ASE" MATERIAL="riverbend.mad" ENVROT="0" MUSIC="SUBURB_2.mp3" AMBIENT="ambience_centralpark_01.wav">
<CLIP NEAR="100.00" FAR="8000.00" FOG="7000.00" COLOR="0.72,0.86,0.85">
<OBJECTIVES TYPE="SHRED" DATA1="23,7" DATA2="1,70" DATA3="24,7">
<OBJECTIVES TYPE="AGILITY" DATA1="3,7000" DATA2="4,7" DATA3="5,7" TIME="120">
<TRIGGER POS="355.37,-3350.55,6692.30" SIZE="100.00,100.00,100.00" TYPE="spawn" ID="0" DATA="0" ENTER="none" EXIT="none">
<OBJECT POS="4483.87,-3353.96,9730.11" ROT="0.00,0.00,0.00" SCALE="1.00" MESH="coin.ase" TYPE="collectible" UNIQUE="0" ID="1" DATA="0" FLAGS="4" SPEED="1.00">
<OBJECT POS="7183.09,-3706.17,11404.25" ROT="0.00,-90.00,0.00" SCALE="0.60" MESH="critter_duckling.bad" TYPE="duckling" UNIQUE="0" ID="0" DATA="0" FLAGS="31" SPEED="1.00">
</LEVEL>
As far as I know this is a custom format made for this game and not an industry standard.
Sunny Garcia Surfing was released on the PS2 in October 2001 in which Krome clearly listed the Merkury engine in the game credits. It has no mentions of Blast Graphics which makes sense as this is the first PS2 game they have released which would have required a complete re-write of the graphics engine to make the most out of the hardware.
The Merkury Engine programming for the game is credited to the following programmers in the manual for the game 18:
Barbie: Sparkling Ice Show was released in 2002 with support for DirectX8, it was the first game they released for windows that had no mentions of Blast Graphics at all and instead had strings related to Merkury in the game executable such as Merkury Options
.
This hints that they never updated the Blast Graphics engine to DirectX 8 and this was the first 3D game for Windows that was released without Blast graphics.
Ty the Tasmanian Tiger was released in 2002 for PS2, Gamecube and Xbox.
The Gamecube release of Ty the Tasmanian Tiger contains not only debug symbols but also 364 references to the names of the C++ source code files used to build the game, all in the main executable TY_REL.elf. Most of the strings are located in the string table section (.strtab) of the GameCube ELF file and thus the location in that section may not indicate anything about the location of the functions that were contained in that source file.
You can find the Source file names in the table below, any descriptions added are a guess at the purpose of the file by us:
Location (.strtab) | Source File Name | Description |
---|---|---|
0x00018ab2 | ZoneBlockerProp.cpp | |
0x00018979 | Z1_RainbowScales.cpp | |
0x000186ff | YabbyStalactite.cpp | |
0x0000bebe | Yabby.cpp | |
0x0002806b | xfontdata.cpp | |
0x0002803a | xFont.cpp | |
0x0000baba | Wombat.cpp | |
0x0002275a | WobbleTexture.cpp | |
0x00022720 | windmill.cpp | |
0x0000b899 | WhiteBat.cpp | |
0x00018528 | WhirlyWind.cpp | |
0x000226a5 | WeatherTypes.cpp | |
0x00018429 | WeatherProp.cpp | |
0x00003b38 | Weather.cpp | |
0x000182ce | WaterWheel.cpp | |
0x000181b6 | WaterVolume.cpp | |
0x00022455 | watertank.cpp | |
0x00022345 | WaterSlide.cpp | |
0x00017f2e | WaterPipe.cpp | |
0x000222a0 | WaterfallStream.cpp | |
0x000221c0 | WaterfallSpray.cpp | |
0x00022130 | WaterfallPoint.cpp | |
0x0002209c | WaterfallBase.cpp | |
0x00021fbf | Waterfall.cpp | |
0x00003af6 | Waterdrip.cpp | |
0x00002da2 | WaterDragon.cpp | |
0x00027fac | Water_GC.cpp | |
0x00017d90 | WarpFlower.cpp | |
0x00021f6e | wake.cpp | |
0x00027f1e | View_GC.cpp | |
0x00027ea6 | Video.cpp | |
0x00026926 | Vector.cpp | |
0x0002691c | Utils.cpp | |
0x00021f39 | UserInterface.cpp | |
0x00021e02 | underWaterEffects.cpp | |
0x0000f324 | UITools.cpp | |
0x00021c22 | TyMemCardQuery.cpp | |
0x00021b65 | TyMemCard.cpp | |
0x00021ac3 | TyHealth.cpp | |
0x00021976 | TyCollisions.cpp | |
0x00021882 | TyAttributes.cpp | |
0x0002181f | TyAnimTables.cpp | |
0x00020b32 | Ty.cpp | |
0x00002d07 | Turtle.cpp | |
0x00017c2a | TurningPlatform.cpp | |
0x00017af2 | TumbleWeed.cpp | |
0x000176cb | TriggerProp.cpp | |
0x00017522 | TreasureChest.cpp | |
0x0000b461 | TrapdoorSpider.cpp | |
0x000267c0 | Translation.cpp | |
0x00003adc | Trails.cpp | |
0x000209a7 | Torch.cpp | |
0x0002088b | tools.cpp | |
0x000267b6 | Timer.cpp | |
0x0000b1e8 | Tick.cpp | |
0x0001739f | ThunderEggCollector.cpp | |
0x00017227 | ThinIceProp.cpp | |
0x00027a04 | Texture.cpp | |
0x00017093 | Teleporter.cpp | |
0x00003a7f | Teleport.cpp | |
0x0002065b | target.cpp | |
0x00016f23 | Talisman.cpp | |
0x00027788 | System_GC.cpp | |
0x00027776 | system_extras.cpp | |
0x0000b049 | SynkerFrill.cpp | |
0x0000aea7 | SynkerBlueTongue.cpp | |
0x0002679b | Str.cpp | |
0x0002035d | stopwatch.cpp | |
0x00003a39 | Steam.cpp | |
0x0002675e | StdMath.cpp | |
0x00020325 | staticSpikes.cpp | |
0x00016c79 | StaticProp.cpp | |
0x0000f1ca | StartupScreens.cpp | |
0x00016b01 | Stalactite.cpp | |
0x000202ac | Spline.cpp | |
0x000169a2 | SpinningLog.cpp | |
0x000201f5 | SpikeyIce.cpp | |
0x00016862 | SpiderWeb.cpp | |
0x0000ad14 | SpiderTrapdoor.cpp | |
0x00002caf | Spider.cpp | |
0x000039aa | SpeedboatWake.cpp | |
0x0001ffa1 | SpecialPickup.cpp | |
0x00016764 | SpawnPoint.cpp | |
0x00016651 | SoundProp.cpp | |
0x0001fab5 | soundbank.cpp | |
0x00027487 | Sound.cpp | |
0x0000aa03 | SnowSpider.cpp | |
0x0000a774 | SnowRoo.cpp | |
0x00016478 | SnowPile.cpp | |
0x0000387f | SnowFootEffects.cpp | |
0x00003829 | SnowBall.cpp | |
0x00002a46 | SmallCrab.cpp | |
0x0000a3a2 | Sly.cpp | |
0x00009f93 | Skink.cpp | |
0x0001f7b4 | SignPost.cpp | |
0x0000d636 | sheila.cpp | |
0x0001f740 | shears.cpp | |
0x0000d516 | shazza.cpp | |
0x00016143 | Shatterable.cpp | |
0x0001f6b1 | Shatter.cpp | |
0x00016003 | SharkCage.cpp | |
0x00009d1e | Shark.cpp | |
0x00015c2b | ShadowBatProps.cpp | |
0x00009987 | ShadowBat.cpp | |
0x0001f671 | Shadow.cpp | |
0x0001f4d5 | setup.cpp | |
0x00015a52 | Sentinel.cpp | |
0x0001f2e6 | SeaMine.cpp | |
0x000095a9 | ScubaFrill.cpp | |
0x0000928e | ScrubTurkey.cpp | |
0x0001f142 | Script.cpp | |
0x000037c3 | SawDust.cpp | |
0x00008fe5 | rufus.cpp | |
0x00008c98 | Roach.cpp | |
0x00008994 | RhinoGround.cpp | |
0x000086ef | Rhino.cpp | |
0x00015834 | Rex.cpp | |
0x0001efc3 | renderTexture.cpp | |
0x0001ef0d | Reflection.cpp | |
0x0001eea5 | reeds.cpp | |
0x0001571c | RangStone.cpp | |
0x0001edae | RangeCheck.cpp | |
0x000036f2 | RainbowEffect.cpp | |
0x0000368e | Rain.cpp | |
0x00026736 | QuatRotation.cpp | |
0x0001ed78 | quadratic.cpp | |
0x00015712 | Props.cpp | |
0x0001560d | Projectile.cpp | |
0x0000f1a1 | ProgressBar.cpp | |
0x0001ec23 | portal.cpp | |
0x000154f1 | PontoonRope.cpp | |
0x0001e8b1 | Pontoon.cpp | |
0x0001530b | Platform.cpp | |
0x000151ee | PipePart.cpp | |
0x000150a5 | Picture.cpp | |
0x00014ede | PicnicBasket.cpp | |
0x00014c5d | PickupCounter.cpp | |
0x0000f180 | PauseScreen_SaveGame.cpp | |
0x0000f08d | PauseScreen_RangInfo.cpp | |
0x0000ef3c | PauseScreen_OptionSound.cpp | |
0x0000ee09 | PauseScreen_OptionScreen.cpp | |
0x0000edba | PauseScreen_Options.cpp | |
0x0000ec00 | PauseScreen_OptionControls.cpp | |
0x0000e9c1 | PauseScreen_Map.cpp | |
0x0000e7c6 | PauseScreen_GameTotals.cpp | |
0x0000e3c7 | PauseScreen_GameInfo.cpp | |
0x0000e2d9 | PauseScreen_Continue.cpp | |
0x0000dfeb | PauseScreen.cpp | |
0x0001e856 | Path.cpp | |
0x0002670d | ParticleSystemManager.cpp | |
0x00026677 | ParticleSystem.cpp | |
0x0001e4e3 | particleengine.cpp | |
0x0001e490 | ParticleEmitter.cpp | |
0x0001e007 | particleEffects.cpp | |
0x00014a1c | OpalCollector.cpp | |
0x0001df98 | NodeOverride.cpp | |
0x0000837a | NinjaGecko.cpp | |
0x0000801e | neddy.cpp | |
0x0001475c | MusicalIcicle.cpp | |
0x00007d88 | muddie.cpp | |
0x000028a8 | Moth.cpp | |
0x000145af | MorayEel.cpp | |
0x000273e4 | ModelGC.cpp | |
0x00026620 | Model.cpp | |
0x00014359 | MobilePlatform.cpp | |
0x000272f2 | MKShadow_GC.cpp | |
0x000264e7 | MKSceneManager.cpp | |
0x00026475 | MKRumble.cpp | |
0x000263c4 | MKParticleGen.cpp | |
0x000261af | MKPackage.cpp | |
0x00027012 | MKMemoryCard.cpp | |
0x00026116 | MKAnimScript.cpp | |
0x0001df67 | mist.cpp | |
0x0000fb22 | MiniGameObjective.cpp | |
0x0000fb12 | MiniGame_E4.cpp | |
0x0000fa86 | MiniGame_C3.cpp | |
0x0000f868 | MiniGame_C2.cpp | |
0x0000f638 | MiniGame_B3.cpp | |
0x0000f4d0 | MiniGame_B1.cpp | |
0x0000f3b7 | MiniGame_A2.cpp | |
0x0001de04 | MetalSpikes.cpp | |
0x0001dcf4 | Messages.cpp | |
0x0001dce5 | MessageMap.cpp | |
0x0000d33d | maurie.cpp | |
0x000260f2 | Matrix.cpp | |
0x00026cfc | Material_GC.cpp | |
0x0001da87 | main.cpp | |
0x0001414a | Log.cpp | |
0x0001d7e5 | LoadLevel.cpp | |
0x0001d7c1 | LineOfSight.cpp | |
0x0001403d | LilyPad.cpp | |
0x00007a52 | LilNeddy.cpp | |
0x0000359e | Lightning.cpp | |
0x0001d734 | LevelObjective.cpp | |
0x00002e40 | LetterBox.cpp | |
0x0001d6c1 | LensFlare.cpp | |
0x0000d07c | Lenny.cpp | |
0x000077d1 | leech.cpp | |
0x00013eae | LavaBurner.cpp | |
0x00013c82 | Lava.cpp | |
0x0001d496 | lasso.cpp | |
0x000260b5 | KromeIni.cpp | |
0x00013920 | KoalaKid.cpp | |
0x00002559 | KingFisher.cpp | |
0x0001d464 | Kinematics.cpp | |
0x0000cf2c | KenOath.cpp | |
0x0001379f | JuliusMachine.cpp | |
0x0000cd58 | julius.cpp | |
0x0001d132 | jeep.cpp | |
0x00026c17 | Input_GC.cpp | |
0x0001367f | IceRamp.cpp | |
0x00013300 | IceCoolant.cpp | |
0x0001cfbc | iceblock.cpp | |
0x00002391 | Ibis.cpp | |
0x0001cd9f | Hud.cpp | |
0x0001cd66 | heatflare.cpp | |
0x0002608d | Heap.cpp | |
0x0001cb9e | GuideParticle.cpp | |
0x0001ca97 | guidebarrel.cpp | |
0x0000755e | Grouper.cpp | |
0x00003539 | GreySmoke.cpp | |
0x0000220d | Grasshopper2.cpp | |
0x00026aee | Grass_GC.cpp | |
0x0001c7f8 | global.cpp | |
0x0001312c | Geyser.cpp | |
0x00012fb0 | Generator.cpp | |
0x00012cb1 | gem.cpp | |
0x00002012 | Gecko.cpp | |
0x0001c590 | Gate.cpp | |
0x00012b5f | GasJet.cpp | |
0x0001c55a | GameObjectManager.cpp | |
0x0001c491 | GameObject.cpp | |
0x0001c435 | GameData.cpp | |
0x00000905 | GameCameraTools.cpp | |
0x00000133 | GameCamera.cpp | |
0x00012939 | Furnace.cpp | |
0x0000df6f | FrontEnd_Videos.cpp | |
0x0000dec8 | FrontEnd_Title.cpp | |
0x0000dd57 | FrontEnd_MainMenu.cpp | |
0x0000dbd3 | FrontEnd_LoadLevel.cpp | |
0x0000db8b | FrontEnd_LoadGame.cpp | |
0x0000db32 | FrontEnd_LanguageSelect.cpp | |
0x0000da9d | FrontEnd_Gallery.cpp | |
0x0000d9e6 | FrontEnd_Extras.cpp | |
0x0000d821 | FrontEnd_Credits.cpp | |
0x0000d76a | FrontEnd.cpp | |
0x00001b49 | Frog.cpp | |
0x000071e2 | FrillSpeedboat.cpp | |
0x00006d9f | frilllizard.cpp | |
0x00006a66 | FrillBike.cpp | |
0x0000cc1c | Friend.cpp | |
0x00025fce | Font.cpp | |
0x000017a5 | Fly.cpp | |
0x00006357 | Fluffy.cpp | |
0x000127e5 | FlamingLog.cpp | |
0x000034f8 | Flame.cpp | |
0x00001377 | FishShoal.cpp | |
0x000012e2 | Fish.cpp | |
0x0001264c | FireDrum.cpp | |
0x0001c2ec | finishline.cpp | |
0x00025eb9 | FileSys.cpp | |
0x00026ad3 | File.cpp | |
0x0000ca40 | farlapp.cpp | |
0x00012528 | FallGuideProp.cpp | |
0x0001c2af | ExtendedAnalogControl.cpp | |
0x000033ba | Explosion.cpp | |
0x000061e5 | EnemySpawner.cpp | |
0x00005e73 | Enemies.cpp | |
0x0001bed0 | emu.cpp | |
0x0001bd8e | elle.cpp | |
0x00012307 | Elevator.cpp | |
0x00005bf2 | Eel.cpp | |
0x000120eb | E4_FlameThrower.cpp | |
0x00011f86 | E4_Door.cpp | |
0x0001bd53 | DustTrail.cpp | |
0x0001bc15 | Drum.cpp | |
0x0001bb0e | draw.cpp | |
0x00026a3e | DiscErrors.cpp | |
0x00025e8d | DirectLight.cpp | |
0x00003036 | DialogPlayer.cpp | |
0x00002e88 | DialogEffect.cpp | |
0x000059fc | Dennis.cpp | |
0x00026953 | demoinit.cpp | |
0x000280d3 | Debug.cpp | |
0x00011e8b | DDACheckpoint.cpp | |
0x0001baac | DDA.cpp | |
0x0001b80c | DataVal.cpp | |
0x00011d43 | Damageable.cpp | |
0x00011c55 | D1_Prop.cpp | |
0x00001122 | CuttleFish.cpp | |
0x000057db | croc.cpp | |
0x00001110 | Critters.cpp | |
0x00000e3b | Critterfield.cpp | |
0x00000df4 | CritterDefs.cpp | |
0x000119d2 | CrikeyProps.cpp | |
0x00005346 | Crikey.cpp | |
0x00025e6b | Crc.cpp | |
0x0001b30e | crate.cpp | |
0x0001b2ff | controlval.cpp | |
0x0001b29c | CollisionObject.cpp | |
0x00025a78 | Collision.cpp | |
0x00011881 | Collapsible.cpp | |
0x00011730 | Coconut.cpp | |
0x000032fd | ChronorangEffects.cpp | |
0x0001b0f0 | checkpoint.cpp | |
0x000050ba | CaveBat.cpp | |
0x00000bae | Cattle.cpp | |
0x00000001 | CameraOverride.cpp | |
0x00025a59 | Camera.cpp | |
0x000115bb | CableCar.cpp | |
0x0001126f | C3_Ringo.cpp | |
0x0000c763 | C3_MiniGame_Rex_Elle.cpp | |
0x00011165 | C3_Chest.cpp | |
0x00011071 | C1Water.cpp | |
0x00010efc | BuzzSaw2.cpp | |
0x0001ab67 | BushPig.cpp | |
0x00010d5e | BurningTree.cpp | |
0x00010baa | Burner.cpp | |
0x00010995 | Burnable.cpp | |
0x0001080a | BunyipStone.cpp | |
0x0000c582 | BunyipElder.cpp | |
0x0001a980 | bunyip.cpp | |
0x00004a61 | bull.cpp | |
0x000106ac | BubbleSpawner.cpp | |
0x000032c5 | Bubble.cpp | |
0x0001a95e | BoundingRegion.cpp | |
0x0001a4aa | BouncingBoulder.cpp | |
0x0001056d | Bouncer.cpp | |
0x0000493b | BossCass.cpp | |
0x0001a43f | boomerangManager.cpp | |
0x0001a3de | BoomerangHud.cpp | |
0x00019bf7 | boomerang.cpp | |
0x000101d4 | BonusPickup.cpp | |
0x0000452e | BlueTongueRock.cpp | |
0x000042d4 | BlueTongue.cpp | |
0x00028079 | Blitter.cpp | |
0x000009a8 | Bird.cpp | |
0x00019b08 | bilby.cpp | |
0x00019ac4 | BezierPathFollower.cpp | |
0x000100ab | BeachHut.cpp | |
0x0000406a | Bat.cpp | |
0x00003e25 | Barracuda.cpp | |
0x00019a8a | barbedWire.cpp | |
0x00003bb8 | BadBoonie.cpp | |
0x00003230 | Avalanche.cpp | |
0x0000c2b3 | AuroraKid.cpp | |
0x0000c13d | Aurora.cpp | |
0x000199a4 | AS_WaterStates.cpp | |
0x00019850 | AS_UnderWaterStates.cpp | |
0x0001965c | AS_SlideStates.cpp | |
0x000195a5 | AS_MiscStates.cpp | |
0x00019354 | AS_LandStates.cpp | |
0x00019205 | AS_LandActionStates.cpp | |
0x00018fbe | AS_BiteStates.cpp | |
0x00018e4c | AS_AirStates.cpp | |
0x0000ff68 | Aquarang.cpp | |
0x00018d44 | anthill.cpp | |
0x00025937 | Animation.cpp | |
0x0000fda3 | AnimatingProp.cpp | |
0x0000fc53 | A1_FrillObjective.cpp | |
0x00023a49 | __ppc_eabi_init.cpp | |
0x00024f88 | __init_cpp_exceptions.cpp | |
0x802764f8 | File.cpp | |
0x80275a18 | demoinit.cpp |
The 2003 game The Adventures of Jimmy Neutron: Jet Fusion is confirmed to use the Merkury engine (it uses RKV archives).
A Demo of the game was distributed in the Chirstmas 2003 issue (issue number 41) of the Official Playstation 2 magazine in the UK, the demo disc has the code SCED_51536.
It contained a DATA_P2.RKV (201.3MB) RKV archive containing all the game assets and the main game executable JIMMY.ELF (3.4MB).
As usual you can find out about all the interesting cut content that was available in the prototype version at The Cutting Room Floor: Proto:The Adventures of Jimmy Neutron Boy Genius: Jet Fusion (GameCube, PlayStation 2) - The Cutting Room Floor
Unlike the Xbox 360 and PS3 versions of Star Wars: The Force Unleashed the PS2, PSP and Wii versions were not built by LucasArts or use the Ronin engine. Instead they were developed by Krome Studios, a completely separate studio known for action-platformers and movie tie-in games.
Krome developed these versions with a separate engine tailored for the older hardware and with unique content and gameplay elements. It is unlikely that ILM/LucasArts would allow their Zeno/Zed software to be used by a third party developer, so we presume these versions were not made using Zed and any assets were either sent over manually to the studio or made custom by Krome.
Because of hardware constraints, these versions use the Open Dynamics Engine (ODE) for physics, rather than Havok, which powers the Xbox 360 / PS3 versions.
If you extract the files from the UMD disc you will get the following file structure: ./PSP_GAME
The main executables are EBOOT.BIN and BOOT.BIN, it contains the standard firmware update files directory, XMB metadata for the game, some standard PRX modules (think DLLs but for the PSP) and there are some PlayStation Media Format (.pmf) videos used for cutscenes and studio logos.
So it is all pretty standard PSP files apart from the RKV archives, these are where all the game data is stored, so any game modding or asset extraction takes places using these files.
The BOOT.BIN executable confirms it is using the Krome Studios Merkury engine rather than the LucasArts Ronin engine used for the PS3 and Xbox 360 versions.
For fun here is a list of unique strings that reference some of the original source code file names from inside the BOOT.BIN executable, they all seem to be related to the Ai system and all have the path prefix d:/starwars/src/StarWars/Source/ :
The game uses RKV archive format, specifically version 2 of the format, these can be extraced with Luigi Auriemma’s QuickBMS and the Rkv2 BMS script.
The data_pp.rkv file has 23,934 files in the PSP version, which seems to be unoptimized as it also contains assets with the Wii prefix such as Wii_Controller.tex and Wii_Vader_Gloves.min.
Due to the huge amount of files in the archive, we are not going to list them out in this page, but the file extensions used for all of the files are in the table below:
Extension | Number of Files | Description |
---|---|---|
tex | 4112 | Texture image file (Magic header: TEX) |
min | 3644 | Minimal index or metadata file? |
mdg | 2832 | Model geometry or mesh data |
mdl | 2832 | 3D model file |
bni | 2605 | Similar to bbi, a custom binary index file |
bbi | 1688 | Binary index or custom binary data file |
ang | 1682 | Possibly animation or angle data file |
anm | 1682 | Animation file |
pkg | 775 | Package file containing grouped assets |
cgr | 692 | Character graphics or 3D model data |
BPK | 451 | Likely a binary package or game resource file |
sbk | 278 | Sound bank file (see format below) |
at3 | 230 | ATRAC3 compressed audio format used in PSP |
pmd | 180 | Polygon model data |
psb | 88 | PlayStation bitmap or proprietary sprite sheet |
mcd | 66 | Mission/cutscene data or custom game data |
txt | 65 | Plain text file mostly used for Locale string definitions per game platform e.g Xbox, PS2, Wii |
bin | 11 | Generic binary data file |
fnt | 5 | Font file, often bitmap or vector font |
FontInfo | 3 | Plain text Font metadata containing a simple script setting variables like CharMap, AspectRatio, CharSpacing, FontXScale and FontYScale |
bmfc | 2 | Possibly custom file with material or font info? |
fnb | 2 | Font binary file |
inc | 1 | Include file, likely script or code include |
mdb | 1 | Possibly model data or database file? |
mdd | 1 | Model animation or motion data? |
mine, r11913, r11979 | 3 | Version Control files left over from a merge of the global.lv3.bni file (revision r11913 and r11979) |
tmp | 1 | Temporary file storing metadata, only used for one file called lastupdate.tmp |
csv | 1 | Comma-separated values text file |
xls | 1 | Excel spreadsheet file for translations (Translations.xls ) |
Not quite sure what *.BNI files are, they always start with the ASCII string “D:\starwars\data\RKVs..\Common”, but I presume they are an archive, possibly compressed (but there is a lot of strings so maybe not).
They also have a wide variety of names:
The lvl files contain strings such as:
The .mine, .r11913, .r11979 files suggest use of the RCS (Revision Control System) version control system as it uses these extensions to manage file revisions and resolve conflicts locally.
Also it also highlights that the RKV files have a lot of files that are not required by the game at runtime, these version control files and also the translation Excel spreadsheet Translations.xls
. it looks like they just archive a certain folder and distribute it with the game. Unfortunetly for us they didn’t accidently also include any debug symbols or source code in the archives.
LngEN_pp.rkv and LngFR_pp.rkv contain sound bank files (.sbk) for their respective languages, presumably all the voiced dialog in the game is contained in these and they have the file name format like cscc001_01_00_p01dven.sbk.
Likely naming format breakdown:
Possible cutscene codes are presented in the table below:
Cutscene ID | Likely scene | Rationale (where applicable) |
---|---|---|
csdv001 | Darth Vader prologue (Kashyyyk) | “DV” = Darth Vader; prologue is a Vader mission. |
cska2xx | Kashyyyk | “ka” matches planet. |
csfe1xx/2xx/20x/205 | Felucia | “fe” = Felucia. |
csrp1xx/2xx | Raxus Prime | “rp” = Raxus Prime. |
csjt1xx/2xx | Jedi Temple (trials) | “jt” = Jedi Temple. |
csmu001 | Mustafar (historic mission) | “mu” = Mustafar. |
csns201 | Nar Shaddaa | “ns” = Nar Shaddaa. |
cstc001/101 | TIE Construction Facility | “tc” = TIE Construction; early game mission. |
csds201 | The Dune Sea (Tatooine historic mission) | “ds” = Dune Sea; appears as historic mission. |
cscc001/201/202/204/205 | Carbonite Chamber (Bespin historic mission) | “cc” = Carbonite Chamber. |
cscg001 | Geonosis Colosseum (historic mission) | “cg” = Colosseum Geonosis. |
csdq001 | Dooku’s Quarters (Geonosis historic mission) | “dq” = Dooku’s Quarters. |
csvo001 | Vader’s Observatory/Vessel? | “vo” ambiguous; likely Vader-related interstitial. |
csvf101/102/104 | Vader’s Flagship/Facility? | “vf” ambiguous; Vader-adjacent (briefings/bridges). |
csqg001 | ? Geonosis-related (Qui-Gon is unlikely) | “qg” unclear; could be internal codename. |
cspl001 | ? Palace (Jabba’s) | “pl” plausible “(Jabba’s) Palace” historic. |
csps001 | ? Palace/Cantina sequence | “ps” ambiguous; may be Tatooine set-piece. |
csrg001 | ? Raxus (Gateway)/Royal Guard | “rg” unclear; could be encounter beat. |
csrh201 | ? Raxus H— (Hub/Hangar/Holo) | “rh” unclear; grouped with Raxus arc number. |
csrs001 | ? Raxus Scrap (yard) | “rs” plausible for “scrapyard”. |
csfd001 | ? Felucia derivative | “fd” could be Felucia boss/dialogue beat. |
csil101 | ? Imperial Laboratory/Library | “il” ambiguous; story contains Imperial facilities. |
csos001 | ? Ossus | “os” could be Ossus (Jedi world); unconfirmed. |
Although these are a guess, proper analysis including playing each of the SBK files while playing the game would be required to give more concrete information.
After some initial analysis it seems the .SBK (header: SB01) files contained in the RKV archives is a small custom container that wraps a mono PSX-ADPCM stream. The container adds a fixed header (magic/version/size/name/flags) and stores raw ADPCM frames without a VAGp/RIFF wrapper.
Here are the header Metadata fields, numbers are all 32-bit Little Endian:
The rest of the file is consistent with PSX ADPCM (a.k.a. VAG):
Here is a Python3 script to convert the .SBK files to WAV:
# Convert .SBK (Merkury Engine Sound Bank, Star Wars Force Unleashed) to WAV
import os, struct, wave, re
src = "./output/csch001_13_03_p01hten.sbk"
with open(src, "rb") as f:
blob = f.read()
# Basic SB01 parse
magic = blob[0:4]
version = int.from_bytes(blob[4:8], "little")
total_size = int.from_bytes(blob[8:12], "little")
name = blob[0x10:0x30].split(b"\x00",1)[0].decode("ascii", "replace")
hdr_size = int.from_bytes(blob[0x30:0x34], "little") # typically 0x50
data_size = int.from_bytes(blob[0x34:0x38], "little") # total_size - hdr_size
flags_sr = int.from_bytes(blob[0x38:0x3C], "little") # 0x80000000 | sample_rate
audio = blob[hdr_size:hdr_size+data_size]
# Extract sample rate from low 16/32 bits; keep high bit as a flag
sample_rate = flags_sr & 0x7FFFFFFF # remove 0x80000000
if sample_rate == 0 or sample_rate > 192000:
# fallback if the high bit wasn't just a flag
sample_rate = flags_sr & 0xFFFF
# Minimal PSX ADPCM (VAG) decoder (mono). Each frame is 16 bytes -> 28 samples.
COEFFS = [
(0.0, 0.0),
(60.0/64.0, 0.0),
(115.0/64.0, -52.0/64.0),
(98.0/64.0, -55.0/64.0),
(122.0/64.0, -60.0/64.0),
]
def decode_frame(frame, p1, p2):
shift = frame[0] & 0x0F
filt = frame[0] >> 4
flags = frame[1]
a1,a2 = COEFFS[filt] if 0 <= filt < len(COEFFS) else (0.0,0.0)
out = []
for i in range(2,16):
b = frame[i]
for nib in (b & 0x0F, (b >> 4) & 0x0F):
s = nib if nib < 8 else nib - 16
sample = (s << 12) >> shift
sample = int(sample + p1*a1 + p2*a2)
sample = max(min(sample, 32767), -32768)
p2, p1 = p1, sample
out.append(sample)
return out, p1, p2, flags
pcm = []
p1=p2=0
i=0
# Skip any leading 0x00 frames (padding)
while i+16 <= len(audio):
frame = audio[i:i+16]
if frame == b"\x00"*16:
i += 16
continue
batch, p1, p2, fl = decode_frame(frame, p1, p2)
pcm.extend(batch)
i += 16
dst = f"./{name}.wav"
with wave.open(dst, "wb") as w:
w.setnchannels(1)
w.setsampwidth(2)
w.setframerate(sample_rate if 8000 <= sample_rate <= 96000 else 19000)
w.writeframes(b"".join(struct.pack("<h", s) for s in pcm))
print ("Success:", dst, len(pcm), sample_rate, magic, version, total_size, hdr_size, data_size)
There is a video on youtube of a quick behind the scenes route of the Krome offices back in 2008 where they interview the lead programmer of Star Wars Lightsaber Duels Chris Lacey (The Shak EP454)?
Lead Environment Artist at Krome Studios Brent Waller posted a video showing off the new Merkury 3 engine in action which was built for the Xbox 360, Playstation 3 and Wii Title: The Legend of the Guardians: The Owls of Ga’hoole.
To quote Brent Waller 20:
The engine has such features as large scale (16 square kilometres) terrain rendering and LODing, grass and forest LODing and placement tools and real-time day and night cycles.
You can watch the video below:
Chris Lacy of Krome Studios talks to PGC! - Interview - Nintendo World Report ↩
RGB Classic Games - Company info for Gee Whiz! Entertainment ↩
PC Powerplay Issue 062 - July 2001 - Next Publishing Pty Ltd ↩
Flight Of The Amazon Queen / Flug Der Amazon Queen - Hall Of Light - The database of Amiga games ↩ ↩2
Kat Burgler on the official kromestudios.com website fetched on Dec 12th 2000 ↩
Sunny Garcia Surfing PS2 Manual ↩