PRC8/trunk/include/inc_letoscript.nss

657 lines
23 KiB
Plaintext
Raw Normal View History

#include "inc_utility"
#include "inc_sql"
//defining directories
//must be changed to each install
//it will use a local string on the module named NWN_DIR if set
const string DB_NAME = "prcnwnxleto";
const string DB_GATEWAY_VAR = "prcnwnxleto";
//set this to true if using build 18 or earlier of letoscript.dll
//again this is a PRC switch
/*YOU MUST ADD THE FOLLOWING TO YOUR ON CLIENT EXIT EVENT
object oPC = GetExitingObject();
LetoPCExit(oPC);
*/
/*YOU MUST ADD THE FOLLOWING TO YOUR ON CLIENT ENTER EVENT
object oPC = GetExitingObject();
LetoPCEnter(oPC);
*/
/* local copies for easy redistribution out of the PRC
//these are the names of local variables, normally ints, to set on the module
//set this if using any letoscript
const string PRC_USE_LETOSCRIPT = "PRC_USE_LETOSCRIPT";
//* Set this to 1 if using build 18
const string PRC_LETOSCRIPT_PHEONIX_SYNTAX = "PRC_LETOSCRIPT_PHEONIX_SYNTAX";
//* Letoscript needs a string named PRC_LETOSCRIPT_NWN_DIR set to the
//* directory of NWN. If it doesnt work, try different slash options: // \\ / \
const string PRC_LETOSCRIPT_NWN_DIR = "PRC_LETOSCRIPT_NWN_DIR";
//* Switch so that Unicorn will use the SQL database for SCO/RCO
//* Must have the zeoslib.dlls installed for this
//*
//* UNTESTED!!!
const string PRC_LETOSCRIPT_UNICORN_SQL = "PRC_LETOSCRIPT_UNICORN_SQL";
//* This is a string, not integer.
//* If the IP is set, Letoscript will use ActivatePortal instead of booting.
//* The IP and Password must be correct for your server or bad things will happen.
//* - If your IP is non-static make sure this is kept up to date.
//*
//* See the Lexicon entry on ActivatePortal for more information.
//*
//* @see PRC_LETOSCRIPT_PORTAL_PASSWORD
const string PRC_LETOSCRIPT_PORTAL_IP = "PRC_LETOSCRIPT_PORTAL_IP";
//* This is a string, not integer.
//* If the IP is set, Letoscript will use ActivatePortal instead of booting.
//* The IP and Password must be correct for your server or bad things will happen.
//* - If your IP is non-static make sure this is kept up to date.
//*
//* See the Lexicon entry on ActivatePortal for more information.
//*
//* @see PRC_LETOSCRIPT_PORTAL_IP
const string PRC_LETOSCRIPT_PORTAL_PASSWORD = "PRC_LETOSCRIPT_PORTAL_PASSWORD";
//* If set you must be using Unicorn.
//* Will use getnewest bic instead of filename reconstruction (which fails if
//* multiple characters have the same name)
const string PRC_LETOSCRIPT_GETNEWESTBIC = "PRC_LETOSCRIPT_GETNEWESTBIC";
// * Set this if you are using SQLite (the built-in database in NWNX-ODBC2).
// * This will use transactions and SQLite specific syntax.
const string PRC_DB_SQLLITE = "PRC_DB_SQLLITE";
const int PRC_SQL_ERROR = 0;
const int PRC_SQL_SUCCESS = 1;
// Function defintions
int GetPRCSwitch(string sSwitch);
void PRC_SQLExecDirect(string sSQL);
void PRC_SQLInit()
{
int i;
// Placeholder for ODBC persistence
string sMemory;
for (i = 0; i < 8; i++) // reserve 8*128 bytes
sMemory +=
"................................................................................................................................";
SetLocalString(GetModule(), "NWNX!ODBC!SPACER", sMemory);
}
void PRC_SQLExecDirect(string sSQL)
{
//PrintString(sSQL);
SetLocalString(GetModule(), "NWNX!ODBC!EXEC", sSQL);
}
int PRC_SQLFetch()
{
string sRow;
object oModule = GetModule();
SetLocalString(oModule, "NWNX!ODBC!FETCH", GetLocalString(oModule, "NWNX!ODBC!SPACER"));
sRow = GetLocalString(oModule, "NWNX!ODBC!FETCH");
if (GetStringLength(sRow) > 0)
{
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", sRow);
return PRC_SQL_SUCCESS;
}
else
{
SetLocalString(oModule, "NWNX_ODBC_CurrentRow", "");
return PRC_SQL_ERROR;
}
}
string PRC_SQLGetTick()
{
string sTick;
if(GetPRCSwitch(PRC_DB_SQLLITE))
sTick = "";
else
sTick = "`";
return sTick;
}
string PRC_SQLGetData(int iCol)
{
int iPos;
string sResultSet = GetLocalString(GetModule(), "NWNX_ODBC_CurrentRow");
// find column in current row
int iCount = 0;
string sColValue = "";
iPos = FindSubString(sResultSet, "<22>");
if ((iPos == -1) && (iCol == 1))
{
// only one column, return value immediately
sColValue = sResultSet;
}
else if (iPos == -1)
{
// only one column but requested column > 1
sColValue = "";
}
else
{
// loop through columns until found
while (iCount != iCol)
{
iCount++;
if (iCount == iCol)
sColValue = GetStringLeft(sResultSet, iPos);
else
{
sResultSet = GetStringRight(sResultSet, GetStringLength(sResultSet) - iPos - 1);
iPos = FindSubString(sResultSet, "<22>");
}
// special case: last column in row
if (iPos == -1)
iPos = GetStringLength(sResultSet);
}
}
return sColValue;
}
string ReplaceSingleChars(string sString, string sTarget, string sReplace)
{
if (FindSubString(sString, sTarget) == -1) // not found
return sString;
int i;
string sReturn = "";
string sChar;
// Loop over every character and replace special characters
for (i = 0; i < GetStringLength(sString); i++)
{
sChar = GetSubString(sString, i, 1);
if (sChar == sTarget)
sReturn += sReplace;
else
sReturn += sChar;
}
return sReturn;
}
int GetPRCSwitch(string sSwitch)
{
return GetLocalInt(GetModule(), sSwitch);
}
void DoDebug(string sString, object oAdditionalRecipient = OBJECT_INVALID)
{
SendMessageToPC(GetFirstPC(), sString);
if(oAdditionalRecipient != OBJECT_INVALID)
SendMessageToPC(oAdditionalRecipient, sString);
WriteTimestampedLogEntry(sString);
}
//*/
//instanty runs the letoscript sScript
//for sType see abive
//if sType is POLL, PollThread is atomatically started
//and sPollScript is passed as the script name
string LetoScript(string sScript, string sType = "SCRIPT", string sPollScript = "");
//This command adds the script to the cuttent superscript
//to run the superscript use StackedLetoScripRun
void StackedLetoScript(string sScript);
//poll an existing thread
//when the thread is finished, script sScript is run
void PollThread(string sThreadID, string sScript);
//credit to demux
//gets a bicpath of a pc
//must be servervault to work
string GetBicPath(object oPC);
//credit to demux
//gets the filename of a PCs bic
//must be servervault
string GetBicFileName(object oPC);
//This will automatically add the required code before and after, and will
//adapt based on PC/NPC/etc.
//This overwites the existing object which will break stored references
//such as henchmen. The new object is returned.
//the result of the script is stored on the module in LetoResult for 1 second
//if nDestroyOriginal is set then PCs will be booted and non-pcs will be destroyed
object RunStackedLetoScriptOnObject(object oObject, string sLetoTag = "OBJECT", string sType = "SCRIPT", string sPollScript = "", int nDestroyOriginal = TRUE);
//const int DEBUG = TRUE;
string GetNWNDir()
{
string sReturn = GetLocalString(GetModule(), PRC_LETOSCRIPT_NWN_DIR);
/*
if(GetStringRight(sReturn, 1) != "\"
&& GetStringRight(sReturn, 1) != "/")
sReturn += "\";
//" this is here so textpad doesnt go screwy becasue it escapes the quotes above.
*/
return sReturn;
}
//credit to demux
string GetBicFileName(object oPC)
{
string sChar, sBicName;
string sPCName = GetStringLowerCase(GetName(oPC));
int i, iNameLength = GetStringLength(sPCName);
for(i=0; i < iNameLength; i++) {
sChar = GetSubString(sPCName, i, 1);
if (TestStringAgainstPattern("(*a|*n|*w|'|-|_)", sChar)) {
if (sChar != " ") sBicName += sChar;
}
}
return GetStringLeft(sBicName, 16);
}
//credit to demux
string GetBicPath(object oPC)
{
// Gets a local var stored on oPC on "event client enter". I do this because
// "on even client leave", function GetPCPlayerName() can not be used. Since
// a .bic file can not be changed while the owner is logged in, it is typical
// to execute leto scripts when the client leaves (on event client leave).
string PlayerName = GetLocalString(oPC, "PlayerName");
if(PlayerName == "")
PlayerName = GetPCPlayerName(oPC);
// Retruns the full path to a .bic file.
return GetNWNDir()+"servervault/"+PlayerName+"/"+GetBicFileName(oPC)+".bic";
}
void VoidLetoScript(string sScript, string sType = "SCRIPT", string sPollScript = "")
{
LetoScript(sScript,sType,sPollScript);
}
string LetoScript(string sScript, string sType = "SCRIPT", string sPollScript = "")
{
string sAnswer;
if (DEBUG) DoDebug(sType+" >: "+sScript);
SetLocalString(GetModule(), "NWNX!LETO!"+sType, sScript);
sAnswer = GetLocalString(GetModule(), "NWNX!LETO!"+sType);
if (DEBUG) DoDebug(sType+" <: "+sAnswer);
if(sType == "SPAWN")
DelayCommand(1.0, PollThread(sAnswer, sPollScript));
return sAnswer;
}
void LetoPCEnter(object oPC)
{
SetLocalString(oPC, "Leto_Path", GetBicPath(oPC));
SetLocalString(oPC, "PCPlayerName", GetPCPlayerName(oPC));
DeleteLocalString(oPC, "LetoScript");
}
void LetoPCExit(object oPC)
{
string sScript = GetLocalString(oPC, "LetoScript");
if(sScript != "")
{
string sPath = GetLocalString(oPC, "Leto_Path");
if(sPath == "")
if (DEBUG) DoDebug("Path is Null");
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
{
//pheonix syntax
sScript = "<file:open CHAR <qq:"+sPath+">>"+sScript;
sScript += "<file:save CHAR <qq:"+sPath+">>";
sScript += "<file:close CHAR >";
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_GETNEWESTBIC))
{
sScript = "%char = FindNewestBic('"+GetNWNDir()+"servervault/"+GetLocalString(oPC, "PCPlayerName")+"'); "+sScript;
sScript += "%char = '>'; ";
sScript += "close %char; ";
}
else
{
//unicorn syntax
sScript = "%char= q{"+sPath+"}; "+sScript;
sScript += "%char = '>'; ";
sScript += "close %char; ";
}
}
string sScriptResult = LetoScript(sScript);
SetLocalString(GetModule(), "LetoResult", sScriptResult);
AssignCommand(GetModule(), DelayCommand(1.0, DeleteLocalString(GetModule(), "LetoResult")));
}
}
void StackedLetoScript(string sScript)
{
if (DEBUG) DoDebug("SLS :"+sScript);
SetLocalString(GetModule(), "LetoScript", GetLocalString(GetModule(), "LetoScript")+ sScript);
}
void PollThread(string sThreadID, string sScript)
{
if(GetLocalInt(GetModule(), "StopThread"+sThreadID) == TRUE)
return;
if (DEBUG) DoDebug("Polling: "+sThreadID);
//add blank space to capture error messages
string sResult = LetoScript(sThreadID+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" "
+" ", "POLL");
if(sResult == "Error: "+sThreadID+" not done.")
{
DelayCommand(1.0, PollThread(sThreadID, sScript));
return;
}
else
{
if (DEBUG) DoDebug("Poll: Executing: "+sScript);
SetLocalInt(GetModule(), "StopThread"+sThreadID, TRUE);
DelayCommand(6.0, DeleteLocalInt(GetModule(), "StopThread"+sThreadID));
location lLoc = GetLocalLocation(GetModule(), "Thread"+sThreadID+"_loc");
DelayCommand(1.0, DeleteLocalLocation(GetModule(), "Thread"+sThreadID+"_loc"));
if (DEBUG) DoDebug("Thread"+sThreadID+"_loc");
if (DEBUG) DoDebug(GetName(GetAreaFromLocation(lLoc)));
object oReturn;
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
{
oReturn = RetrieveCampaignObject(DB_NAME, DB_GATEWAY_VAR, lLoc);
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_UNICORN_SQL))
{
string sSQL = "SELECT blob FROM "+DB_NAME+" WHERE "+DB_GATEWAY_VAR+"="+DB_GATEWAY_VAR+" LIMIT 1";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
oReturn = RetrieveCampaignObject("NWNX", "-", lLoc);
}
else
{
oReturn = RetrieveCampaignObject(DB_NAME, DB_GATEWAY_VAR, lLoc);
}
}
if (DEBUG) DoDebug(GetName(oReturn));
SetLocalString(GetModule(), "LetoResult", sResult);
AssignCommand(GetModule(), DelayCommand(1.0, DeleteLocalString(GetModule(), "LetoResult")));
SetLocalObject(GetModule(), "LetoResultObject", oReturn);
AssignCommand(GetModule(), DelayCommand(1.0, DeleteLocalObject(GetModule(), "LetoResultObject")));
SetLocalString(GetModule(), "LetoResultThread", sThreadID);
AssignCommand(GetModule(), DelayCommand(1.0, DeleteLocalString(GetModule(), "LetoResultThread")));
ExecuteScript(sScript, OBJECT_SELF);
}
}
void VoidRunStackedLetoScriptOnObject(object oObject, string sLetoTag = "OBJECT",
string sType = "SCRIPT", string sPollScript = "", int nDestroyOriginal = TRUE)
{
RunStackedLetoScriptOnObject(oObject,sLetoTag,sType,sPollScript,nDestroyOriginal);
}
object RunStackedLetoScriptOnObject(object oObject, string sLetoTag = "OBJECT",
string sType = "SCRIPT", string sPollScript = "", int nDestroyOriginal = TRUE)
{
if(!GetIsObjectValid(oObject))
{
WriteTimestampedLogEntry("ERROR: "+GetName(oObject)+"is invalid");
WriteTimestampedLogEntry("Script was "+GetLocalString(GetModule(), "LetoScript"));
return OBJECT_INVALID;
}
string sCommand;
object oReturn;
location lLoc;
object oWPLimbo = GetObjectByTag("HeartOfChaos");
location lLimbo;
if(GetIsObjectValid(oWPLimbo))
lLimbo = GetLocation(oWPLimbo);
else
lLimbo = GetStartingLocation();
string sScript = GetLocalString(GetModule(), "LetoScript");
DeleteLocalString(GetModule(), "LetoScript");
string sScriptResult;
//check if its a DM or PC
//these use bic files
if(GetIsPC(oObject) || GetIsDM(oObject))
{
if(!nDestroyOriginal)//dont boot
{
string sPath = GetLocalString(oObject, "Leto_Path");
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
{
sCommand = "<file:open '"+sLetoTag+"' <qq:"+sPath+">>";
sScript = sCommand+sScript;
sCommand = "<file:close '"+sLetoTag+"'>";
sScript = sScript+sCommand;
//unicorn
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_GETNEWESTBIC))
{
sCommand = "%"+sLetoTag+" = FindNewestBic('"+GetNWNDir()+"servervault/"+GetLocalString(oObject, "PCPlayerName")+"'); ";
}
else
{
//unicorn syntax
sCommand = "%"+sLetoTag+" = q{"+sPath+"}; "; //qq{} doesnt work for me at the moment, wrong slashes
}
sScript = sCommand+sScript;
sCommand = "close %"+sLetoTag+"; ";
sScript = sScript+sCommand;
}
sScriptResult = LetoScript(sScript, sType, sPollScript);
}
else//boot
{
//this triggers the OnExit code to fire the letoscript
SetLocalString(oObject, "LetoScript", GetLocalString(oObject, "LetoScript")+sScript);
if(GetLocalString(GetModule(), PRC_LETOSCRIPT_PORTAL_IP) == "")
{
BootPC(oObject);
}
else
{
ActivatePortal(oObject,
GetLocalString(GetModule(), PRC_LETOSCRIPT_PORTAL_IP),
GetLocalString(GetModule(), PRC_LETOSCRIPT_PORTAL_PASSWORD),
"", //waypoint, may need to change
TRUE);
}
return oReturn;
}
}
//its an NPC/Placeable/Item, go through DB
else if(GetObjectType(oObject) == OBJECT_TYPE_CREATURE
|| GetObjectType(oObject) == OBJECT_TYPE_ITEM
|| GetObjectType(oObject) == OBJECT_TYPE_PLACEABLE
|| GetObjectType(oObject) == OBJECT_TYPE_STORE
|| GetObjectType(oObject) == OBJECT_TYPE_WAYPOINT)
{
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
{
//Put object into DB
StoreCampaignObject(DB_NAME, DB_GATEWAY_VAR, oObject);
// Reaquire DB with new object in it
sCommand += "<file:open FPT <qq:" + GetNWNDir() + "database/" + DB_NAME + ".fpt>>";
//Extract object from DB
sCommand += "<fpt:extract FPT '"+DB_GATEWAY_VAR+"' "+sLetoTag+">";
sCommand += "<file:close FPT>";
sCommand += "<file:use "+sLetoTag+">";
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_UNICORN_SQL))
{
//unicorn
//Put object into DB
string sSQL = "SELECT "+DB_GATEWAY_VAR+" FROM "+DB_NAME+" WHERE "+DB_GATEWAY_VAR+"="+DB_GATEWAY_VAR+" LIMIT 1";
PRC_SQLExecDirect(sSQL);
if (PRC_SQLFetch() == PRC_SQL_SUCCESS)
{
// row exists
sSQL = "UPDATE "+DB_NAME+" SET val=%s WHERE "+DB_GATEWAY_VAR+"="+DB_GATEWAY_VAR;
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
}
else
{
// row doesn't exist
// assume table doesnt exist too
sSQL = "CREATE TABLE "+DB_NAME+" ( "+DB_GATEWAY_VAR+" TEXT, blob BLOB )";
PRC_SQLExecDirect(sSQL);
sSQL = "INSERT INTO "+DB_NAME+" ("+DB_GATEWAY_VAR+", blob) VALUES" +
"("+DB_GATEWAY_VAR+", %s)";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
}
StoreCampaignObject ("NWNX", "-", oObject);
// Reaquire DB with new object in it
//force data to be written to disk
sSQL = "COMMIT";
PRC_SQLExecDirect(sSQL);
sCommand += "sql.connect 'root', '' or die $!; ";
sCommand += "sql.query 'SELECT blob FROM "+DB_NAME+" WHERE "+DB_GATEWAY_VAR+"="+DB_GATEWAY_VAR+" LIMIT 1'; ";
sCommand += "sql.retrieve %"+sLetoTag+"; ";
}
else
{
//Put object into DB
StoreCampaignObject(DB_NAME, DB_GATEWAY_VAR, oObject);
sCommand += "%"+sLetoTag+"; ";
//Extract object from DB
sCommand += "extract '"+GetNWNDir()+"database/"+DB_NAME+".fpt', '"+DB_GATEWAY_VAR+"', %"+sLetoTag+" or die $!;";
}
}
//store their location
lLoc = GetLocation(oObject);
if(!GetIsObjectValid(GetAreaFromLocation(lLoc)))
lLoc = GetStartingLocation();
sScript = sCommand + sScript;
sCommand = "";
//destroy the original
if(nDestroyOriginal)
{
AssignCommand(oObject, SetIsDestroyable(TRUE));
DestroyObject(oObject);
//its an NPC/Placeable/Item, go through DB
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
{
sCommand = "<file:open FPT <qq:" + GetNWNDir() + "database/" + DB_NAME + ".fpt>>";
sCommand += "<fpt:replace FPT '" +DB_GATEWAY_VAR+ "' "+sLetoTag+">";
sCommand += "<file:save FPT>";
sCommand += "<file:close FPT>";
sCommand += "<file:close "+sLetoTag+">";
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_UNICORN_SQL))
{
//unicorn
sCommand += "sql.query 'SELECT blob FROM "+DB_NAME+" WHERE "+DB_GATEWAY_VAR+"="+DB_GATEWAY_VAR+" LIMIT 1'; ";
sCommand += "sql.store %"+sLetoTag+"; ";
sCommand += "close %"+sLetoTag+"; ";
}
else
{
sCommand += "inject '"+GetNWNDir()+"database/"+DB_NAME+".fpt', '"+DB_GATEWAY_VAR+"', %"+sLetoTag+" or die $!;";
sCommand += "close %"+sLetoTag+"; ";
}
}
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
sCommand += "<file:close "+sLetoTag+">";
else
sCommand += "close %"+sLetoTag+"; ";
}
sScript = sScript + sCommand;
sScriptResult = LetoScript(sScript, sType, sPollScript);
if(nDestroyOriginal && sType != "SPAWN")
{
if(GetPRCSwitch(PRC_LETOSCRIPT_PHEONIX_SYNTAX))
{
if(GetObjectType(oObject) == OBJECT_TYPE_CREATURE)
{
oReturn = RetrieveCampaignObject(DB_NAME, DB_GATEWAY_VAR, lLimbo);
AssignCommand(oReturn, JumpToLocation(lLoc));
}
else
oReturn = RetrieveCampaignObject(DB_NAME, DB_GATEWAY_VAR, lLoc);
}
else
{
if(GetPRCSwitch(PRC_LETOSCRIPT_UNICORN_SQL))
{
string sSQL = "SELECT blob FROM "+DB_NAME+" WHERE "+DB_GATEWAY_VAR+"="+DB_GATEWAY_VAR+" LIMIT 1";
SetLocalString(GetModule(), "NWNX!ODBC!SETSCORCOSQL", sSQL);
if(GetObjectType(oObject) == OBJECT_TYPE_CREATURE)
{
oReturn = RetrieveCampaignObject("NWNX", "-", lLimbo);
AssignCommand(oReturn, JumpToLocation(lLoc));
}
else
oReturn = RetrieveCampaignObject("NWNX", "-", lLoc);
}
else
{
if(GetObjectType(oObject) == OBJECT_TYPE_CREATURE)
{
oReturn = RetrieveCampaignObject(DB_NAME, DB_GATEWAY_VAR, lLimbo);
AssignCommand(oReturn, JumpToLocation(lLoc));
}
else
oReturn = RetrieveCampaignObject(DB_NAME, DB_GATEWAY_VAR, lLoc);
}
}
}
else if(nDestroyOriginal && sType == "SPAWN")
{
SetLocalLocation(GetModule(), "Thread"+IntToString(StringToInt(sScriptResult))+"_loc", lLoc);
if (DEBUG) DoDebug("Thread"+IntToString(StringToInt(sScriptResult))+"_loc");
}
}
SetLocalString(GetModule(), "LetoResult", sScriptResult);
AssignCommand(GetModule(), DelayCommand(1.0, DeleteLocalString(GetModule(), "LetoResult")));
return oReturn;
}