mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-07-31 00:15:54 -04:00
410 lines
14 KiB
Plaintext
410 lines
14 KiB
Plaintext
// mustafar events scriptlib - sets up oft-used functions used in the mustafar expansion.
|
|
|
|
// ********************************************************************
|
|
// INCLUDES
|
|
// ********************************************************************
|
|
|
|
include ai.ai;
|
|
include library.ai_lib;
|
|
include library.chat;
|
|
include library.create;
|
|
include library.groundquests;
|
|
include library.prose;
|
|
include library.space_dungeon;
|
|
include library.utils;
|
|
include library.sui;
|
|
|
|
// ********************************************************************
|
|
// CONSTS
|
|
// ********************************************************************
|
|
|
|
const string CONST_TBL_EVENT_DATA = "datatables/dungeon/mustafar_trials/obiwan_finale/obiwan_event_data.iff";
|
|
|
|
const string STF_OBI_MSGS ="mustafar/obiwan_finale";
|
|
|
|
const string_id SID_OBIWAN_BUSY = new string_id(STF_OBI_MSGS, "obi_busy_elsewhere");
|
|
const string_id SID_ALREADY_COMPLETED = new string_id(STF_OBI_MSGS, "obiquest_already_completed");
|
|
const string_id SID_NO_OBI_CONVO_YET = new string_id(STF_OBI_MSGS, "obiwan_finale_launch_before_convo");
|
|
const string_id SID_NOT_READY = new string_id(STF_OBI_MSGS, "not_prepared");
|
|
const string_id SID_MOUNTED = new string_id(STF_OBI_MSGS, "not_while_riding");
|
|
|
|
|
|
|
|
const string[] REQUIRED_QUEST_NAMES =
|
|
{
|
|
"som_kenobi_collectors_business_1",
|
|
"som_kenobi_cursed_shard_2",
|
|
"som_kenobi_hidden_treasure_2",
|
|
"som_kenobi_historian_2",
|
|
"som_kenobi_moral_choice_1",
|
|
"som_kenobi_reunite_shard_3",
|
|
"som_kenobi_samaritan_1",
|
|
"som_kenobi_serpent_shard_1",
|
|
"som_kenobi_symbiosis_1"
|
|
};
|
|
|
|
const boolean CONST_FLAG_DO_LOGGING = false;
|
|
|
|
|
|
//constants for quest grant SUI - jandank, blistmok, tulrus items.
|
|
const string STF = "som/som_quest";
|
|
const string QUEST_ACCEPT_OK = "@"+STF+":quest_accept_ok";
|
|
const string QUEST_ACCEPT_CANCEL = "@"+STF+":quest_accept_cancel";
|
|
const string BEGIN_QUEST_PROMPT = "@"+STF+":begin_quest_prompt";
|
|
const string BEGIN_QUEST_TITLE = "@"+STF+":begin_quest_title";
|
|
|
|
// ********************************************************************
|
|
// FUNCTIONS
|
|
// ********************************************************************
|
|
|
|
|
|
void debugLogging(string section, string message)
|
|
{
|
|
if (CONST_FLAG_DO_LOGGING)
|
|
LOG("debug/mustafar/"+section, message);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean canCallObiwan(obj_id player)
|
|
{
|
|
return canCallObiwan(player, null, false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean canCallObiwan(obj_id player, obj_id recallObject) //wrapper for canCallObiwan, which was altered to allow the player to receive feedback to why they can't call Obiwan.
|
|
{
|
|
return canCallObiwan(player, recallObject, false);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean canCallObiwan(obj_id player, obj_id recallObject, boolean giveFailureFeedback)
|
|
{
|
|
debugLogging("canCallObiwan: ", " entered.");
|
|
|
|
string planetName = getCurrentSceneName();
|
|
if (!planetName.startsWith("mustafar"))
|
|
return false;
|
|
|
|
|
|
obj_id topMostContainer = getTopMostContainer(player); // is the player outside? (btw, this should handle mounts as well, but just in case, see further down)
|
|
if ( (topMostContainer != player) || (topMostContainer == null) )
|
|
return false;
|
|
|
|
obj_id dungeon = space_dungeon.getDungeonIdForPlayer(player); // is the player in an instance?
|
|
if (isIdValid(dungeon))
|
|
return false;
|
|
|
|
if(isIdValid(getMountId(player))) // is the player mounted?
|
|
{
|
|
if (giveFailureFeedback)
|
|
sendSystemMessage(player, SID_MOUNTED);
|
|
debugLogging("canCallObiwan: ", " player mounted. No call.");
|
|
return false;
|
|
}
|
|
|
|
if(hasObjVar(player, "didMustafarCrystalLair")) // has the player not already accomplished this event?
|
|
{
|
|
sendSystemMessage(player, SID_ALREADY_COMPLETED);
|
|
debugLogging("canCallObiwan: ", " player has already completed final quest. No call.");
|
|
removeObjVar(player,"waitingOnObiwan");
|
|
removeObjVar(player,"quest.wait_for_signal.quest/som_kenobi_main_quest_3_b");
|
|
removeObjVar(player,"quest.wait_for_signal.quest/som_kenobi_main_quest_3");
|
|
return false;
|
|
}
|
|
|
|
if(!hasCompletedTrials(player) && !isGod(player)) // has the player accomplished the 10 quests yet?
|
|
{
|
|
if (giveFailureFeedback)
|
|
sendSystemMessage(player, SID_NOT_READY);
|
|
return false;
|
|
}
|
|
|
|
if(!obiwanAlreadyPresent(player, giveFailureFeedback)) // is there already an obiwan around? getObjects in range with a certain script?
|
|
{
|
|
debugLogging("canCallObiwan: ", " No obiwan in range. ok to call him.");
|
|
return true;
|
|
}
|
|
|
|
LOG("space_dungeon", "theme_park.dungeon.mustafar_trials.obiwan_finale.obiwan_recall_object.canCallObiwan");
|
|
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean obiwanAlreadyPresent(obj_id player, boolean giveFailureFeedback)
|
|
{
|
|
debugLogging("obiwanAlreadyPresent: ", " entered.");
|
|
|
|
location currentLoc = getLocation(player);
|
|
obj_id obiwanObject = getFirstObjectWithObjVar(currentLoc, 100f, "mustafar_obiwan");
|
|
if(isIdValid(obiwanObject))
|
|
{
|
|
if (giveFailureFeedback)
|
|
sendSystemMessage(player, SID_OBIWAN_BUSY);
|
|
debugLogging("obiwanAlreadyPresent: ", "found a pre-existing obiwan object.");
|
|
return true;
|
|
}
|
|
|
|
debugLogging("obiwanAlreadyPresent: ", "there is no pre-existing obiwan object");
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
obj_id callObiwan(obj_id player)
|
|
{
|
|
return callObiwan(player, null, false, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
obj_id callObiwan(obj_id player, boolean timeout)
|
|
{
|
|
return callObiwan(player, null, timeout, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
obj_id callObiwan(obj_id player, boolean timeout, int appearanceComment)
|
|
{
|
|
return callObiwan(player, null, timeout, appearanceComment);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
obj_id callObiwan(obj_id player, obj_id landmark)
|
|
{
|
|
return callObiwan(player, landmark, false, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
obj_id callObiwan(obj_id player, obj_id landmark, boolean timeout)
|
|
{
|
|
return callObiwan(player, landmark, timeout, 0);
|
|
}
|
|
//----------------------------------------------------------------------
|
|
|
|
obj_id callObiwan(obj_id player, obj_id landmark, boolean timeout, int appearanceComment)
|
|
{
|
|
debugLogging("//***// callObiwan: ", "////>>>> entered.");
|
|
|
|
location currentLoc = getLocation(player);
|
|
float landmarkDistanceOffset = 0f;
|
|
if (isIdValid(landmark))
|
|
{
|
|
location landmarkLoc = getLocation(landmark);
|
|
landmarkDistanceOffset = getDistance(player, landmark);
|
|
debugLogging("callObiwan: ", "landmark location is valid.");
|
|
}
|
|
|
|
float distance = landmarkDistanceOffset + 6f;
|
|
if (timeout)
|
|
if (distance < 11f)
|
|
distance = 11f;
|
|
|
|
location spawnLoc = utils.findLocInFrontOfTarget(player, distance);
|
|
|
|
obj_id obiwan = create.object ("som_kenobi_obi_wan_glowie", spawnLoc);
|
|
if (!isIdValid(obiwan))
|
|
{
|
|
debugLogging("callObiwan: ", "obiwan obj_id that we created is not valid");
|
|
return null;
|
|
}
|
|
|
|
//attachScript(obiwan, "theme_park.dungeon.mustafar_trials.obiwan_finale.obiwan_fader_handler");
|
|
|
|
//playClientEffectObj(obiwan, "clienteffect/pl_force_absorb.cef", obiwan, ""); <<<< add a cool 'appearance' effect when Obi shows up.
|
|
|
|
//setCreatureCover(obiwan, 125);
|
|
//setCreatureCoverVisibility(obiwan, false);
|
|
//playClientEffectObj(player, "clienteffect/combat_special_attacker_cover.cef", obiwan, "");
|
|
//messageTo (obiwan, "obiwanFadeIn", null, 5, false);
|
|
|
|
ai_lib.setDefaultCalmBehavior( obiwan, ai_lib.BEHAVIOR_SENTINEL );
|
|
faceTo(obiwan, player);
|
|
attachScript(obiwan,"theme_park.dungeon.mustafar_trials.obiwan_finale.obiwan_obi_facer");
|
|
setObjVar(obiwan,"mustafar_obiwan", 1);
|
|
// if(hasObjVar(player,"waitingOnObiwan"))
|
|
// removeObjVar(player,"waitingOnObiwan");
|
|
|
|
if (timeout)
|
|
{
|
|
utils.setScriptVar(obiwan, "player", player);
|
|
attachScript(obiwan, "theme_park.dungeon.mustafar_trials.obiwan_finale.obiwan_dynamic_timeout");
|
|
}
|
|
|
|
if (appearanceComment > 0)
|
|
{
|
|
string_id strSpam = new string_id(mustafar.STF_OBI_MSGS, "som_obi_greet_story_"+appearanceComment);
|
|
prose_package pp = prose.getPackage(strSpam);
|
|
prose.setTT( pp, player );
|
|
chat.chat (obiwan, player, pp);
|
|
}
|
|
|
|
return obiwan;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void spawnContents(obj_id dungeon, string spawnType, int numberOfCopies)
|
|
{
|
|
debugLogging("//***// spawnContents: ", "////>>>> entered. SpawnType requested was: "+spawnType);
|
|
string[] spawnTypeColumnData = dataTableGetStringColumnNoDefaults(CONST_TBL_EVENT_DATA, "dataType");
|
|
|
|
if (spawnTypeColumnData.length == 0)
|
|
return;
|
|
|
|
for (int i=0;i < spawnTypeColumnData.length;i++)
|
|
{
|
|
if (spawnTypeColumnData[i].equals(spawnType))
|
|
{
|
|
|
|
dictionary dict = dataTableGetRow(CONST_TBL_EVENT_DATA, i);
|
|
debugLogging("spawnContents: ", "Retrieving info for row("+i+")");
|
|
|
|
int locx = dict.getInt("locx");
|
|
int locy = dict.getInt("locy");
|
|
int locz = dict.getInt("locz");
|
|
location myself = getLocation (dungeon);
|
|
string scene = myself.area;
|
|
//string scene = getCurrentSceneName();
|
|
obj_id cell = getCellId(dungeon, "mainroom"); // <- name of instanced dungeon's cell
|
|
float yaw = dict.getFloat("yaw");
|
|
string script = dict.getString("script");
|
|
location spawnLoc = new location (locx, locy, locz, scene, cell);
|
|
string object = dict.getString("object");
|
|
if (dict.getString("dataType").equals("setpiece")) //if the object isn't a creature, spawn it this way
|
|
{
|
|
debugLogging("//***// spawnContents: ", "////>>>> Going to try to spawn a 'setpiece'");
|
|
|
|
obj_id item = createObjectInCell(object, dungeon, "mainroom", spawnLoc); // <- name of instanced dungeon's cell
|
|
if (!isIdValid(item))
|
|
{
|
|
debugLogging("spawnContents: ", "Tried to create invalid item("+object+")");
|
|
return;
|
|
}
|
|
setYaw(item, yaw);
|
|
if (!script.equals("none"))
|
|
attachScript(item, script);
|
|
|
|
utils.setScriptVar(item,"dungeon", dungeon);
|
|
debugLogging("spawnContents: ", "Created object("+object+"/"+item+") with script("+script+") with yaw ("+yaw);
|
|
|
|
}
|
|
else if (!dict.getString("dataType").equals("location") && !dict.getString("dataType").equals("forcePowerAttack")) // if the object IS a creature, spawn it this way
|
|
{
|
|
debugLogging("//***// spawnContents: ", "////>>>> Going to try to spawn a creature of some kind");
|
|
|
|
if (numberOfCopies < 1)
|
|
numberOfCopies = 1;
|
|
for (int j=0;j < numberOfCopies;j++)
|
|
{
|
|
obj_id creature = create.object (object, spawnLoc);
|
|
string creatureName = ai_lib.getCreatureName (creature);
|
|
obj_id[] players = getPlayerCreaturesInRange (creature, 60.0f);
|
|
|
|
if (!isIdValid(creature))
|
|
{
|
|
debugLogging("spawnContents: ", "Tried to create invalid creature("+object+")");
|
|
return;
|
|
}
|
|
if (!script.equals("none"))
|
|
attachScript(creature, script);
|
|
if (creatureName.startsWith ("som_kenobi_finale_minion"))
|
|
addHate(creature, players[i], 1000f);
|
|
|
|
utils.setScriptVar(creature,"dungeon", dungeon);
|
|
debugLogging("spawnContents: ", "Created object("+object+"/"+creature+") with script("+script);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean moveBossAround(string moveTargetName, obj_id boss, obj_id dungeon)
|
|
{
|
|
debugLogging("moveBoss: ", ">>>> entered.");
|
|
|
|
if(!isIdValid(dungeon))
|
|
{
|
|
debugLogging("moveBoss: ", ">>>> dungeon objId was invalid.");
|
|
return false;
|
|
}
|
|
|
|
int desiredDatatableRow = dataTableSearchColumnForString(moveTargetName, "dataType", mustafar.CONST_TBL_EVENT_DATA);
|
|
if (desiredDatatableRow < 0)
|
|
{
|
|
debugLogging("moveBoss: ", ">>>> desiredDatatableRow was no good");
|
|
return false;
|
|
}
|
|
dictionary dict = dataTableGetRow(mustafar.CONST_TBL_EVENT_DATA, desiredDatatableRow);
|
|
debugLogging("moveBoss: ", "Retrieving info for row("+desiredDatatableRow+")");
|
|
|
|
int locx = dict.getInt("locx");
|
|
int locy = dict.getInt("locy");
|
|
int locz = dict.getInt("locz");
|
|
string scene = getCurrentSceneName();
|
|
obj_id cell = getCellId(dungeon, "mainroom"); // <- name of instanced dungeon's cell
|
|
debugLogging("moveBoss: ", ">>>> locX: "+locx+" locY: "+locy+" locZ: "+locz+" scene: "+scene+" cell: "+cell);
|
|
location gotoLoc = new location (locx, locy, locz, scene, cell);
|
|
|
|
debugLogging("moveBoss: ", ">>>> executing pathTo.");
|
|
ai.pathTo(boss, gotoLoc);
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean hasCompletedTrials (obj_id player)
|
|
{
|
|
for(int i = 0; i < REQUIRED_QUEST_NAMES.length; i++) // has the player accomplished the trials quests yet?
|
|
{
|
|
if(!groundquests.hasCompletedQuest(player, REQUIRED_QUEST_NAMES[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
boolean stillWithinDungeonCheck (obj_id player, obj_id dungeon)
|
|
{
|
|
if(!isIdValid(player) || !isIdValid(dungeon))
|
|
return false;
|
|
|
|
obj_id currentTopMost = getTopMostContainer(player);
|
|
if (currentTopMost == dungeon)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void activateQuestAcceptSUI(obj_id player, obj_id self)
|
|
{
|
|
// Create the dialog page.
|
|
int pid = sui.createSUIPage(sui.SUI_MSGBOX, self, player, "handleQuestOfferResponse");
|
|
|
|
// Add elements text.
|
|
setSUIProperty(pid, sui.MSGBOX_TITLE, sui.PROP_TEXT, BEGIN_QUEST_TITLE);
|
|
setSUIProperty(pid, sui.MSGBOX_PROMPT, sui.PROP_TEXT, BEGIN_QUEST_PROMPT);
|
|
|
|
// Add buttons.
|
|
sui.msgboxButtonSetup(pid, sui.YES_NO);
|
|
setSUIProperty(pid, sui.MSGBOX_BTN_OK, sui.PROP_TEXT, QUEST_ACCEPT_OK);
|
|
setSUIProperty(pid, sui.MSGBOX_BTN_CANCEL, sui.PROP_TEXT, QUEST_ACCEPT_CANCEL);
|
|
|
|
// Show dialog.
|
|
sui.showSUIPage( pid );
|
|
}
|