Wintermute/Externals

From ScummVM :: Wiki
Jump to navigation Jump to search

This page lists known external functions for most Wintermute games.

Original WME 1.x allows game scripts to call external functions from DLL libraries. This way game creator can either call Win32 API functions or use custom extension DLL libraries.

ScummVM's WME contain mocks and reimplementations for functions listed below, emulating import those functions from a given DLL.

2D games

James Peris (Demo 2012)

geturl.dll

getURLContent

Used to download news headlines at Demo 2012 of James Peris

HTTP GET result is stored in 3rd param of the call as a plain string

Specification: external "geturl.dll" cdecl getURLContent(string, string, string)

Known usage: getURLContent("http://www.lacosaweb.com", <DirURL>, <Buffer>)

Sets 3rd param to "Request Error." on error

Context:

   var buf = new String(255);
   var buf2 = new String(255);
   getURLContent("http://www.lacosaweb.com", DirURL, buf);
   if((((buf == "Request Error.") || (buf == null)) || (buf == ""))) {
       SCUPDalt.Red = 0;
       textoscup1 = "www.jamesperis.com";
       textoscup2 = "www.jamesperis.com";
   }
   else {
       SCUPDalt.Red = 1;
       textoscup1 = buf;
       getURLContent("http://www.lacosaweb.com", DirURL2, buf2);
       textoscup2 = buf2;
   }

Various games by HeroCraft

tools.dll

SetValueToReg

Used to switch game's windowed/fullscreen mode at games by HeroCraft

Specification: external "tools.dll" cdecl SetValueToReg(string, string, long)

Known usage: SetValueToReg("Software\HeroCraft\<GameID>\Video", "Windowed", 1)

Context:

   if(checkBox.Pressed) {
       SetValueToReg("Software\HeroCraft\Pole\Video", "Windowed", 0);
       Game.windowedState = 0;
   }
   else {
       SetValueToReg("Software\HeroCraft\Pole\Video", "Windowed", 1);
       Game.windowedState = 1;
   }

img.dll

changeWindowCaption

Used to change game's window caption at games by HeroCraft

Specification: external "img.dll" cdecl changeWindowCaption(long, string)

Known usage: changeWindowCaption(Game.Hwnd, <Title>)

Context:

   if(Game.WindowedMode) {
       maximizedWindow(Game.Hwnd, 1024, 768);
   }
   changeWindowCaption(Game.Hwnd, getStr("Поле Чудес"));

maximizedWindow

Used to change game's window size at games by HeroCraft

Specification: external "img.dll" cdecl maximizedWindow(long, long, long)

Known usage: maximizedWindow(Game.Hwnd, 1024, 768)

Wilma Tetris

shell32.dll

ShellExecuteA

Used to open URL in browser at Wilma Tetris

Specification: external "shell32.dll" stdcall long ShellExecuteA(long, string, string, string, string, long)

Known usage: ShellExecuteA(0, "open", <URL>, "", "", 3)

Returns value >32 on success

Context:

   function RunDocument(Filename) {
       ShellExecuteA(0, "open", Filename, "", "", 3);
       return null;
   }
   
   ...
   
   on "off_url" {
       RunDocument("http://offstudio.fabry.cz");
       return;
   }
   on "dc_url" {
       RunDocument("http://dead-code.org");
       return;
   }

2.5D games

Those games are out of ScummVM scope and are not supported by ResidualVM yet. However, their external function calls are mocked or implemented.

Art of Murder: FBI Confidential

installutil.dll

_InstallUtilAnsi@0

Used to check if DVD is inserted at Art of Murder: FBI Confidential

Specification: external "installutil.dll" stdcall long _InstallUtilAnsi@0()

Known usage: _InstallUtilAnsi@0()

Returns 1 on success, other value on fail (which leads to Game.QuitGame() in non-Debug mode)

Context:

   var ivlmsg = Game.ExpandString("/vld0002/Proszę włożyć płytę Art of Murder Sztuka Zbrodni do napędu DVD-ROM.");
   var valid = _InstallUtilAnsi@0();
   if((valid != 1)) {
       var query = Game.ConfirmBox(ivlmsg);
       valid = _InstallUtilAnsi@0();
       if((valid != 1)) {
           if(Game.DebugMode) {
               Game.Msg("!!! no media !!!");
           }
           else {
               Game.QuitGame();
           }
       }
   }

Various games by Corbomite Games

dlltest.dll

IRC_init

Used to connect to debug IRC server at games by Corbomite Games

Specification: external "dlltest.dll" cdecl long IRC_init(string)

Known usage: IRC_init(<PlayerName>)

Known actions:

1. Connect to irc.starchat.net

2. Send "NICK ZU_<PlayerName>/"

3. Send "USER Blah ZbengHost ZbengServer ZbengRealname"

4. Send "Join #Zbeng"

Returns 0 on success, other value on error

Context:

   if(EnableIRC) {
       IRCConnected = IRC_init(PlayerName);
   } 

ChangeNick

Used to update nick at debug IRC server at games by Corbomite Games

Specification: external "dlltest.dll" cdecl long ChangeNick(string)

Known usage: ChangeNick(<PlayerName>)

Return value is never used

Context:

   if(EnableIRC) {
       ChangeNick(PlayerName);
   }

IRC_SendString

Used to send debug and chat lines to an IRC server at games by Corbomite Games

Specification: external "dlltest.dll" cdecl IRC_SendString(string, string)

Known usage: IRC_SendString(<Message>, <Channel>)

Known Channel values are: "#Zbeng" and "#ZbengDebug"

Context:

   function SendMessageToIrc(inStr) {
       if((IRCConnected == 0)) {
           IRC_SendString(inStr, "#zbeng");
       }
       return null;
   }
   function SendDebugMessageToIrc(inStr) {
       if((IRCConnected == 0)) {
           IRC_SendString(inStr, "#ZbengDebug");
       }
       return null;
   }

IRC_GetChatStrings

Used to get chat lines from an IRC server at games by Corbomite Games

Specification: external "dlltest.dll" cdecl IRC_GetChatStrings(string, long)

Known usage: IRC_GetChatStrings(<Buffer>, 65535)

IRC_quit

Used to disconnect from debug IRC server at games by Corbomite Games

Specification: external "dlltest.dll" cdecl IRC_quit()

Known usage: IRC_quit()

kernel32.dll

LoadLibraryA

Used for checking library availability at games by Corbomite Games

Specification: external "kernel32.dll" stdcall long LoadLibraryA(string)

Known usage: LoadLibraryA("httpconnect.dll"), LoadLibraryA("dlltest.dll")

Return values are only compared with zero and are never used in other APIs

Context:

   var inifile = new File("Zbang.ini");
   inifile.OpenAsText(1);
   IRCWinSetting = inifile.ReadText(1);
   if(((IRCWinSetting != 1) && (IRCWinSetting != 2))) {
       IRCWinSetting = 0;
   }
   DEBUG(("IRCWinSetting " + IRCWinSetting));
   if((IRCWinSetting > 0)) {
       IRCDllLib = LoadLibraryA("dlltest.dll");
   }
   if((IRCDllLib == 0)) {
       EnableIRC = 0;
   }

FreeLibrary

Declared at games by Corbomite Games

Seems to be unused, probably was used for unloading IRC & HTTP libraries

Specification: external "kernel32.dll" stdcall FreeLibrary(long)

GetEnvironmentVariableA

Used for getting environment variables at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest

Specification: external "kernel32.dll" stdcall long GetEnvironmentVariableA(string, string, long)

Known usage: GetEnvironmentVariableA(<EnvName>, <buffer>, 65535)

Known EnvName values used in debug code: "USERKEY", "ALTUSERNAME", "ENHFINGERPRINT", "EXTRAINFO", "FINGERPRINT", "KEYSTRING", "STOLENKEY", "TRIAL"

Known EnvName values used in licensing code: "FULLGAME"

Context:

   method getEnvironmentVar(envName) {
       var envContent = new String(65535);
       var retval = GetEnvironmentVariableA(envName, envContent, 65535);
       return envContent;
       return null;
   }
   method CheckArmadillo() {
       var path = getEnvironmentVar("");
       DEBUG(path);
       var variarblesArr = new Array("USERKEY", "ALTUSERNAME", "ENHFINGERPRINT", "EXTRAINFO", "FINGERPRINT", "KEYSTRING", "STOLENKEY", "TRIAL", "FULLGAME");
       var len = variarblesArr.Length;
       var i = 0;
       while((i < len)) {
           var key = variarblesArr[i];
           var variable = getEnvironmentVar(key);
           DEBUG(((key + "=") + variable));
           i = (i + 1);
       }
       global g_Publisher;
       if(!(g_Publisher.DRM)) {
           if(!(g_Publisher.OverrideFullgame)) {
               var PublisherFullGame = getEnvironmentVar("FULLGAME");
               if((PublisherFullGame != "TRUE")) {
                   isFullDemo = 1;
               }
           }
           else {
               global isBought = 1;
           }
       }
       return null;
   }

httpconnect

Register

Used to register license key online at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest

Specification: external "httpconnect.dll" cdecl long Register(string, long, string, long)

Known usage: Register(<productId>, 65535, <productKey>, 65535)

Known product ID values are: "357868", "353058" and "353006"

Known action: HTTP GET http://keygen.corbomitegames.com/keygen/validateKey.php?action=REGISTER&productId=productId&key=productKey

Returns 1 on success

Returns 0 on firewall error

Returns -1 on invalid product key

Returns -2 on invalid product ID

Returns -3 on expired product key

Returns -4 on invalid machine ID

Returns -5 on number of installations exceeded

Returns -6 on socket error

Returns -7 on no internet connection

Returns -8 on connection reset

Returns -11 on validation temporary unavaliable

Returns -12 on validation error

For some reason always returns -7 for me in a test game

Context:

   method RegisterKey(inProductkey) {
       var productID = new String(65535);
       var productKey = new String(65535);
       productKey = inProductkey;
       productID = "357868";
       var rerVal = Register(productID, 65535, productKey, 65535);
       DEBUG(("Validate : " + rerVal));
       if((rerVal == 1)) {
           return 1;
       }
       productID = "353058";
       rerVal = Register(productID, 65535, productKey, 65535);
       DEBUG(("Validate : " + rerVal));
       if((rerVal == 1)) {
           return 1;
       }
       productID = "353006";
       rerVal = Register(productID, 65535, productKey, 65535);
       DEBUG(("Validate : " + rerVal));
       if((rerVal == 1)) {
           return 1;
       }
       ShowMessage(rerVal);
       return rerVal;
       return null;
   }

Validate

Used to validate something at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest

Specification: external "httpconnect.dll" cdecl long Validate()

Known usage: Validate()

Known action: HTTP GET http://keygen.corbomitegames.com/keygen/validateKey.php?action=VALIDATE&productId=Ar&key=Ar

Used only when Debug mode is active or game is started with "INVALID" cmdline parameter

For some reason always returns 1 for me in a test game

SendHTTPAsync

Used to send game progress events to server at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest

Specification: external "httpconnect.dll" cdecl long SendHTTPAsync(string, long, string, long, string, long)

Known usage: SendHTTPAsync("backend.pizzamorgana.com", 65535, <FullURL>, 65535, <Buffer?!>, 65535)

FullURL is formed as "http://backend.pizzamorgana.com/event.php?Event=<EventName>&player=<PlayerName>&extraParams=<ExtraParams>&SN=<ProductKey>&Episode=1&GameTime=<CurrentTime>&UniqueID=<UniqueId>"

Known EventName values are: "GameStart", "ChangeGoal", "EndGame" and "QuitGame"

Known ExtraParams values are: "ACT0", "ACT1", "ACT2", "ACT3", "ACT4", "Ep0FindFood", "Ep0FindCellMenu", "Ep0BroRoom", "Ep0FindKey", "Ep0FindCellMenuKey", "Ep0FindMenuKey", "Ep0FindCell", "Ep0FindMenu", "Ep0OrderPizza", "Ep0GetRidOfVamp", "Ep0GetVampAttention", "Ep0License"

Return value is never used

Context:

   method sendEventNow(inEventName, extraParams) {
       global NetworkEnabled;
       if((NetworkEnabled != 1)) {
           DEBUG("Not sending event due to network disabled");
           return 0;
       }
       if(firewall) {
           DEBUG("Not sending event due to firewall");
           return 0;
       }
       var httpStr = new String(65535);
       var Request = new String(65535);
       var server = new String(65535);
       Request = ((((((((((("http://backend.pizzamorgana.com/event.php?Event=" + inEventName) + "&player=") + this.PlayerName) + "&extraParams=") + extraParams) + "&SN=") + this.SN) + "&Episode=1&GameTime=") + Game.CurrentTime) + "&UniqueID=") + this.Unique);
       server = "backend.pizzamorgana.com";
       DEBUG((((("Send: '" + Request) + "' to server '") + server) + "'"));
       if((Request != null)) {
           SendHTTPAsync(server, 65535, Request, 65535, httpStr, 65535);
       }
       httpStr = httpStr.Substr(0, 256);
       DEBUG((("Recv: '" + httpStr) + "'"));
       return httpStr;
       return null;
   }

SendRecvHTTP (6 params variant)

Declared at Pizza Morgana: Episode 1 - Monsters and Manipulations in the Magical Forest

Seems to be unused, probably SendRecvHTTP was initially used instead of SendHTTPAsync

Specification: external "httpconnect.dll" cdecl long SendRecvHTTP(string, long, string, long, string, long)

Always returns -7 for me in a test game, probably returns the same network errors as Register()

SendRecvHTTP (4 params variant)

Used to call HTTP methods at Zbang! The Game

Specification: external "httpconnect.dll" cdecl long SendRecvHTTP(string, long, string, long)

Known usage: SendRecvHTTP("scoresshort.php?player=<PlayerName>", 65535, <Buffer>, 65535)

Known usage: SendRecvHTTP("/update.php?player=<PlayerName>&difficulty=<Difficulty>&items=<CommaSeparatedItemList>", 65535, <Buffer>, 65535)

My Zbang demo does not have this dll, so there is no way to actually test it with a test game

Return value is never used in Zbang scripts

Stroke of Fate dilogy

[TODO]routine.dll

GetDPI

Used at CheckFont() function to select font DPI.

Unused, if Game.RegReadNumber("DefaultDPI", 0) is not 0.

Specification: external "routine.dll" cdecl long GetDPI()

Known usage: dpi = GetDPI()

Context:

   function CheckFont() {
       var dpi = Game.RegReadNumber("DefaultDPI", 0);
       BASEFONT = "fonts";
       if((dpi == 0)) {
           dpi = GetDPI();
       }
       if((dpi <= 72)) {
           dpi = 72;
       } else if((dpi <= 96)) {
           dpi = 96;
       } else if((dpi <= 120)) {
           dpi = 120;
       } else {
           dpi = 144;
       }
       if((dpi == 72)) {
           BASEFONT = "fonts.72";
       }
       if((dpi == 120)) {
           BASEFONT = "fonts.120";
       }
       if((dpi == 144)) {
           BASEFONT = "fonts.144";
       }
   }

GetCaption

Used at CheckCaption() function to get window title.

Expects CheckCaption(Game.Hwnd).IndexOf("Wintermute Engine", 0) >= 0

Specification: external "routine.dll" cdecl string GetCaption(long)

Known usage: GetCaption(Game.Hwnd)

Context:

   function CheckCaption() {
       var p = "Wintermute Engine";
       while(1) {
           var s = GetCaption(Game.Hwnd);
           s = new String(s);
           if((s.IndexOf(p, 0) >= 0)) {
               break;
           }
           Sleep(1);
       }
       SetCaption(Game.Hwnd, Game.ExpandString("/MAIN_CAPTION3/"));
   }

SetCaption

Used at CheckCaption() function to set window title.

Specification: external "routine.dll" cdecl bool SetCaption(long, string)

Known usage: SetCaption(Game.Hwnd, Game.ExpandString("/MAIN_CAPTION3/"))

RemoveFile

Used at SaveTempScreenShot() & RemoveTempScreenShot() functions to manage screenshot files.

Specification: external "routine.dll" cdecl bool RemoveFile(string)

Known usage: RemoveFile(Directory.TempDirectory + "\tempss.bmp")

Known usage: RemoveFile(Game.SaveDirectory + "\" + newname + ".bmp")

Context:

   var sd = Game.SaveDirectory;
   if((sd == NULL)) {
       sd = "qsaves";
   }
   sd = (sd + "\");
   this.SaveFilePath = sd;
   this.SaveFileExtention = ".dat";
   this.TempScreenShot = (Directory.TempDirectory + "\tempss.bmp");
   
   ...
   
   method RemoveTempScreenShot() {
       var filename = this.TempScreenShot;
       if(Game.FileExists(filename)) {
           RemoveFile(filename);
       }
       return null;
   }
   method SaveTempScreenShot(newname) {
       var oldname = this.TempScreenShot;
       if(!(Game.FileExists(oldname))) {
           log.Add((("svg::SaveTempScreenShot(" + GetValue(newname)) + ") error, temporary screenshot is unavailable"));
           return null;
       }
       if((newname == NULL)) {
           newname = "qsave";
       }
       newname = ((this.SaveFilePath + newname) + ".bmp");
       if(Game.FileExists(newname)) {
           RemoveFile(newname);
       }
       RenameFile(oldname, newname);
       return null;
   }

RenameFile

Used at SaveTempScreenShot() & RemoveTempScreenShot() functions to manage screenshot files.

Specification: external "routine.dll" cdecl bool RenameFile(string, string)

Known usage: RenameFile(Directory.TempDirectory + "\tempss.bmp", Game.SaveDirectory + "\" + newname + ".bmp")

[TODO]protect.dll

Steam version of Stroke of Fate: Operation Bunker does not have this DLL.

However, game code contain some checks that depend on GetOptions() results, which use some of those calls.

Specifications:

   external "protect.dll" stdcall long PSA_DisableFeaturesGrantedByLicense(membuffer);
   external "protect.dll" stdcall PSA_DummyFunction();
   external "protect.dll" stdcall long PSA_GetFeaturesGrantedByLicense(membuffer);
   external "protect.dll" stdcall long PSA_IsDemoMode(membuffer);
   external "protect.dll" stdcall long PSA_IsTrialMode(membuffer);

PSA_GetFeaturesGrantedByLicense sets 4-byte buffer's first 5 bits with some feature flags of unknown semantics. Maybe same game features are missing in Steam version because of this.

PSA_IsDemoMode sets 1-byte buffer to non-zero if license is Demo.

PSA_IsTrialMode sets 1-byte buffer to non-zero if license is Trial.

PSA_DisableFeaturesGrantedByLicense & PSA_DummyFunction are never used.

Context:

   function GetOptions() {
       var p;
       var buf = new MemBuffer(4);
       buf.SetInt(0, 0);
       PSA_GetFeaturesGrantedByLicense(buf);
       p.R1 = (buf.GetInt(0) % 2);
       p.R2 = (((buf.GetInt(0) - p.R1) / 2) % 2);
       p.R3 = (((buf.GetInt(0) - p.R2) / 4) % 2);
       p.R4 = (((buf.GetInt(0) - p.R3) / 8) % 2);
       p.R5 = (((buf.GetInt(0) - p.R4) / 16) % 2);
       buf.SetSize(1);
       buf.SetBool(0, FALSE);
       PSA_IsDemoMode(buf);
       p.D = buf.GetBool(0);
       buf.SetBool(0, FALSE);
       PSA_IsTrialMode(buf);
       p.T = buf.GetBool(0);
       return p;
   }

Known checks:

   o = (!(o.R1) && o.R5)
   if(((((Random(0, 1) == 0) || (enl.safe_state == "oil")) || DEBUG) && (!(o.D) && !(o.R2))))
   if(((quest.herda == 12) && o.R3))
   o = (!(o.T) && o.R3)
   if(o.R3)
   if(o.R4)
   if((((((((enl.linge_a && enl.linge_b1) && enl.linge_b2) && enl.linge_b3) && enl.linge_b4) && enl.linge_d) || TRUE) && (!(o.T) && o.R4)))