//include library.quests; //include library.ai; include library.battlefield; include library.regions; include library.group; include library.badge; //questStatus consts const int IS_ON_QUEST =1; const int COMPLETED_QUEST = 2; const int FAILED_QUEST =3; //Set the questStatus for player on QuestID void setQuestStatus( obj_id player, string questId, int questStatus ) { setObjVar(player, "themeparkQuestFlags."+ questId, questStatus); if ( ( questStatus == quests.COMPLETED_QUEST ) || ( questStatus == quests.FAILED_QUEST ) ) { clearAllWaypoints( player, questId ); removeObjVar( player, questId ); } } boolean hasQuest( obj_id player, string QUEST_ID ) { if ( getQuestStatus( player, QUEST_ID ) == IS_ON_QUEST ) return true; else return false; } //remove Quest Status and all quest flags for player on QuestId void removeQuestStatus( obj_id player, string questId) { removeObjVar(player, "themeparkQuestFlags."+ questId); clearAllWaypoints( player, questId ); removeObjVar( player, questId ); } //get the questStatus for player on QuestId int getQuestStatus( obj_id player, string questId) { if ( !hasObjVar(player, "themeparkQuestFlags."+ questId ) ) { return 0; } return getIntObjVar( player, "themeparkQuestFlags."+ questId ); } //flag questId completed for player, and remove all quest flags void completeQuest( obj_id player, string questId) { setQuestStatus( player, questId, quests.COMPLETED_QUEST ); } //returns true if player has completed questId boolean hasCompletedQuest( obj_id player, string questId ) { return ( getQuestStatus( player, questId) == quests.COMPLETED_QUEST ); } //set quest flagname to value for player on questId void setQuestFlag( obj_id player, string questId, string flagname, int value ) { setObjVar(player, questId + ".Flags."+ flagname, value); } //return value of quest flag for player on questId int getQuestFlag(obj_id player, string questId, string flagname) { if ( !hasObjVar(player, questId + ".Flags." + flagname )) { return 0; } return getIntObjVar( player, questId + ".Flags." + flagname ); } //remove quest flagname for player on questId void removeQuestFlag(obj_id player, string questId, string flagname) { removeObjVar( player, questId + ".Flags." + flagname ); } /* -------------------------------------------------- * Infiltration Quest Flags: * --------------------------------------------------*/ const int CAN_INFILTRATE = 1; const int COMPLETED_INFILTRATE = 2; boolean canInfiltrate( obj_id player, string questId ) { return hasObjVar(player, "themeparkQuestFlags.INFILTRATION." + questId); } void setInfiltrateFlag( obj_id player, string questId, int canInfiltrate ) { if ( canInfiltrate == CAN_INFILTRATE || canInfiltrate == COMPLETED_INFILTRATE) setObjVar(player, "themeparkQuestFlags.INFILTRATION."+ questId, canInfiltrate); else removeObjVar(player, "themeparkQuestFlags.INFILTRATION."+ questId); } void removeInfiltrateFlag( obj_id player, string questId ) { removeObjVar(player, "themeparkQuestFlags.INFILTRATION."+ questId); } int getInfiltrateFlag( obj_id player, string questId ) { return getIntObjVar(player, "themeparkQuestFlags.INFILTRATION." + questId); } /* -------------------------------------------------- * Waypoint and location Target stuff: * --------------------------------------------------*/ obj_id addQuestLocationTarget( obj_id player, string questId, string name, location loc, float radius ) { addLocationTarget( name, loc, radius ); obj_id waypoint = createWaypointInDatapad( player, loc ); if (!isIdValid(waypoint)) return null; setWaypointVisible( waypoint, true); setWaypointActive( waypoint, true); setObjVar( player, questId + ".waypoint." + name, waypoint ); return waypoint; } obj_id addThemeParkWaypoint( obj_id player, string questId, string name, location loc, float radius, string display, string file, string entry ) { addLocationTarget( name, loc, radius ); obj_id waypoint = createWaypointInDatapad( player, loc ); setWaypointActive( waypoint, true); setObjVar( player, questId + ".waypoint." + name, waypoint ); setObjVar (player, "game_created", 1); setWaypointName ( waypoint, display ); setObjVar (player, questId + ".entry", entry); setObjVar (player, questId + ".file", file); setObjVar (waypoint, "player", player); setObjVar (player, "questID", questId); return waypoint; } /* obj_id addQuestToken( obj_id player, string questId, string name, location loc, float radius, string display ) { addLocationTarget( name, loc, radius ); obj_id token = createToken( "object/mobile/jabba_the_hutt.iff", loc ); obj_id datapad = getObjectInSlot( player , "datapad"); putIn( token, datapad ); obj_id waypoint = getTokenWaypoint (token); if (waypoint == null) { debugSpeakMsg (getSelf(), "No Waypoint Loc"); } else { setWaypointVisible( waypoint, true); setWaypointActive( waypoint, true); setObjVar( player, questId + ".token." + name, waypoint); setObjVar (player, "game_created", 1); setName ( token, display ); } return token; } */ void clearQuestLocationTarget( obj_id player, string questId, string name ) { if ( hasObjVar( player, questId + ".waypoint." + name ) ) { obj_id waypoint = getObjIdObjVar( player, questId + ".waypoint." + name ); setWaypointVisible( waypoint, false); setWaypointActive( waypoint, false); destroyObject( waypoint ); removeLocationTarget (name); removeObjVar( player, questId + ".waypoint." + name ); return; } } void clearAllWaypoints( obj_id player, string questId ) { if ( !hasObjVar( player, questId + ".waypoint" )) return; obj_var_list waypointList = getObjVarList( player, questId + ".waypoint" ); if(waypointList == null) // Redundant check since we already make sure the player has the obj var return; // before we retrieve the list, but better safe than sorry... int count = waypointList.getNumItems(); for ( int i=0; i < count; ++i ) { obj_var waypointVar = waypointList.getObjVar( i ); obj_id waypoint = waypointVar.getObjIdData(); setWaypointVisible( waypoint, false); setWaypointActive( waypoint, false); destroyObject( waypoint ); } removeObjVar( player, questId + ".waypoint" ); } /* ------------------------------------------------- * This function spawns _template_ at _loc_ * and makes it attack _target_ * * e.g. "spawnAttacker( "../stormtrooper.iff", getLocation(target), target); * will spawn a stormtroopers and make it attack Target. * * The function returns the obj_id of the npc spawned. * * The function attaches npcdeath to the npc spawned * which causes the npc to emit a message to target * when it dies * messageHandler npcDestroyed * --------------------------------------------------*/ obj_id spawnAttacker( string msgHandlerName, string template, location loc, obj_id target ) { obj_id attacker = createObject( template, loc ); //ai.aiAttack( attacker, target ); setObjVar( attacker, "quests.target", target ); setObjVar( attacker, "quests.msgHandlerName", msgHandlerName ); attachScript( attacker, "theme_park.utils.npcdeath" ); return attacker; } obj_id spawnAttacker( string template, location loc, obj_id target ) { obj_id attacker = createObject( template, loc ); //ai.aiAttack( attacker, target ); return attacker; } /* -------------------------------------------------- * This function spawns multiple attackers within a couple meters * of the location passed to it and returns their obj_id's in an * array of obj_id's. * --------------------------------------------------*/ obj_id[] spawnAttackers( string msgHandlerName, int number, string template, location loc, obj_id target ) { obj_id[] attackers = new obj_id[ number ]; for ( int i = 0; i < number; i++ ) { location newloc = new location( loc ); newloc.x = loc.x + rand( -2, +2 ); newloc.z = loc.z + rand( -2, +2 ); attackers[ i ] = spawnAttacker( msgHandlerName, template, newloc, target ); } return attackers; } obj_id[] spawnAttackers( int number, string template, location loc, obj_id target ) { obj_id[] attackers = new obj_id[ number ]; for ( int i = 0; i < number; i++ ) { location newloc = new location( loc ); newloc.x = loc.x + rand( -2, +2 ); newloc.z = loc.z + rand( -2, +2 ); attackers[ i ] = spawnAttacker( template, newloc, target ); } return attackers; } location chooseNearbyLocation( obj_id self ) { location loc = new location( getLocation( self ) ); switch ( rand(1,4) ) { case 1 : loc.x = loc.x + 20; break; case 2 : loc.x = loc.x - 20; break; case 3 : loc.y = loc.y + 20; break; case 4 : loc.y = loc.y -20; break; } return loc; } location getTargetLocation (obj_id self) { obj_id containedBy = getTopMostContainer (self); location target = new location(); int x = 0; while (x < 10) { location here = getLocation (self); region quest = locations.getCityRegion(here); location questLoc = locations.getGoodLocationOutsideOfRegion(quest, 100f, 100f, 100f); if (questLoc != null) { target = questLoc; } x = x + 1; } return target; } string getConvoType( obj_id self ) { string convoType = "npc_mission/static_businessman_deliver"; string type = "businessman"; if(checkForSerendipity(self) == false) { if (!hasObjVar (self, "questType")) { int questType = rand (1,4); switch (questType) { case 1: type = "businessman"; break; case 2: type = "criminal"; break; case 3: type = "noble"; break; case 4: type = "scientist"; break; } convoType = "npc_mission/static_" + type + "_deliver"; } else { type = getStringObjVar (self, "questType"); convoType = "npc_mission/static_" + type + "_deliver"; } setObjVar (self, "questType", type); return convoType; } else { type = getCreatureName(self); convoType = "npc_mission/static_" + type + "_deliver"; setObjVar (self, "questType", type); return convoType; } } string getDataTableName( obj_id self ) { string datatable = "datatables/npc/static_quest/businessman_deliveries.iff"; string type = "businessman"; if (checkForSerendipity(self) == false) { if (!hasObjVar (self, "questType")) { int questType = rand (1,4); switch (questType) { case 1: type = "businessman"; break; case 2: type = "criminal"; break; case 3: type = "noble"; break; case 4: type = "scientist"; break; } datatable = "datatables/npc/static_quest/" + type + "_deliveries.iff"; } else { type = getStringObjVar (self, "questType"); datatable = "datatables/npc/static_quest/" + type + "_deliveries.iff"; } setObjVar (self, "questType", type); return datatable; } else { type = getCreatureName(self); setObjVar (self, "questType", type); datatable = "datatables/npc/static_quest/" + type + "_deliveries.iff"; return datatable; } } string getType ( obj_id self ) { string type = "businessman"; if (checkForSerendipity(self) == false) { if (!hasObjVar (self, "questType")) { int questType = rand (1,4); switch (questType) { case 1: type = "businessman"; break; case 2: type = "criminal"; break; case 3: type = "noble"; break; case 4: type = "scientist"; break; } } else { type = getStringObjVar (self, "questType"); } return type; } else { type = getCreatureName(self); } return type; } boolean checkForSerendipity (obj_id self) { const string npcType = getCreatureName(self); if (npcType == "noble" || npcType == "scientist" || npcType == "criminal" || npcType == "businessman") { return true; } else { return false; } } boolean checkForItem(obj_id inv) { string datatable = quests.getDataTableName(getSelf()); int questNum = getIntObjVar (getSelf(), "quest"); string giveMe = dataTableGetString (datatable, 0, questNum); boolean hadIt = false; obj_id[] contents = getContents(inv); for ( int i = 0; i < contents.length; i++ ) { string itemInInventory = getTemplateName (contents[i]); if (itemInInventory == giveMe) { destroyObject (contents[i]); hadIt = true; } } return hadIt; } location getThemeParkLocation (obj_id self) { location target = null; int x = 0; while (x < 10) { location here = getLocation (self); //LOG("quests", "here is "+here); obj_id bldg = getTopMostContainer (self); if (bldg == null) { return null; } location building = getLocation (bldg); //LOG("quests", "building is "+building); region[] rgnFoos = getRegionsWithGeographicalAtPoint(building, regions.GEO_CITY); if(rgnFoos==null) { region[] rgnTest = getRegionsAtPoint(building); if(rgnTest==null) { return null; } else { rgnFoos = rgnTest; } } region quest = rgnFoos[0]; //LOG("quest", "rgnFoos[0] name is "+rgnFoos[0].getName()); if (quest == null) { quest = locations.getCityRegion (building); if (quest == null) { return null; } } location questLoc = locations.getGoodLocationOutsideOfRegion(quest, 64f, 64f, 100f, false, true); //LOG("quest", "questLoc is "+questLoc); if (questLoc != null) { target = questLoc; //LOG("quest", "target is "+target); } //LOG("quest", "questLoc2 is "+questLoc); x = x + 1; } //Crack monkey stuff that has to be done to get a proper Y-Height if (target != null) { float xCoord = target.x; float zCoord = target.z; float newY = getHeightAtLocation (xCoord, zCoord); target.y = newY; } return target; } void giveThemeParkReward (obj_id self, obj_id player, int questNum) { string datatable = getStringObjVar (self, "quest_table"); datatable = "datatables/theme_park/" + datatable + ".iff"; string questID = dataTableGetString (datatable, questNum, "temp_objvar"); string gatingString = dataTableGetString (datatable, questNum, "overall_objvar"); string playerScript = dataTableGetString (datatable, questNum, "player_script"); string CONVO = dataTableGetString (datatable, questNum, "convo"); string messageCONVO = "theme_park/messages"; int gating = getIntObjVar (player, gatingString); if (group.isGrouped(player)) { Vector party = group.getPCMembersInRange(player); if ( party != null ) { for ( int i = 0; i < party.size(); i++ ) { int partyMemberGating = getIntObjVar ((obj_id)party.elementAt(i), gatingString); if (partyMemberGating == 0) { partyMemberGating = 1; } if (gating == partyMemberGating) { gating = gating + 1; setObjVar (player, gatingString, gating); setObjVar ((obj_id)party.elementAt(i), gatingString, gating); } } } } else { gating = gating + 1; setObjVar (player, gatingString, gating); } string type = dataTableGetString (datatable, questNum, "quest_type"); if (type == "rescue" || type == "escort") { obj_id vip = getObjIdObjVar (player, questID + ".vip"); messageTo (vip, "stopFollowing", null, 0, true); } //adding to detect & award badge for completeing theme park int badgeReward = dataTableGetInt (datatable, questNum, "badge_reward"); string badgeName = getCollectionSlotName(badgeReward); if ((badgeReward != 0) && (badgeName != null) && (badgeName.length() > 0)) { if(!badge.hasBadge(player, badgeName)) { // you get the badge for completing a themepark badge.grantBadge(player, badgeName); //return; } } obj_id playerInv = utils.getInventoryContainer(player); string reward = dataTableGetString (datatable, questNum, "reward"); string reward2 = dataTableGetString (datatable, questNum, "reward2"); string reward3 = dataTableGetString (datatable, questNum, "reward3"); string reward4 = dataTableGetString (datatable, questNum, "reward4"); if (reward != null && reward != "" && reward != "none") { obj_id rewardObject = createObject (reward, playerInv, ""); string_id gift = new string_id (messageCONVO, "theme_park_reward"); sendSystemMessage (player, gift); string objvar = dataTableGetString (datatable, questNum, "reward_objvar"); int value = dataTableGetInt (datatable, questNum, "reward_objvar_value"); if (objvar != null) { setObjVar (rewardObject, objvar, value); } } if (reward2 != null && reward2 != "" && reward2 != "none") { obj_id rewardObject2 = createObject (reward2, playerInv, ""); string_id gift2 = new string_id (messageCONVO, "theme_park_reward"); sendSystemMessage (player, gift2); string objvar2 = dataTableGetString (datatable, questNum, "reward2_objvar"); int value2 = dataTableGetInt (datatable, questNum, "reward2_objvar_value"); if (objvar2 != null) { setObjVar (rewardObject2, objvar2, value2); } } if (reward3 != null && reward3 != "" && reward2 != "none") { obj_id rewardObject3 = createObject (reward3, playerInv, ""); string_id gift3 = new string_id (messageCONVO, "theme_park_reward"); sendSystemMessage (player, gift3); string objvar3 = dataTableGetString (datatable, questNum, "reward3_objvar"); int value3 = dataTableGetInt (datatable, questNum, "reward3_objvar_value"); if (objvar3 != null) { setObjVar (rewardObject3, objvar3, value3); } } if (reward4 != null && reward4 != "" && reward2 != "none") { obj_id rewardObject4 = createObject (reward4, playerInv, ""); string_id gift4 = new string_id (messageCONVO, "theme_park_reward"); sendSystemMessage (player, gift4); string objvar4 = dataTableGetString (datatable, questNum, "reward4_objvar"); int value4 = dataTableGetInt (datatable, questNum, "reward4_objvar_value"); if (objvar4 != null) { setObjVar (rewardObject4, objvar4, value4); } } int credits = dataTableGetInt (datatable, questNum, "credits"); if (credits != 0) { string_id fake = new string_id(); dictionary params = new dictionary(); group.systemPayoutToGroup("reasonID", player, credits, fake, "returnHandler", params); //money.bankTo(money.ACCT_JABBA, player, credits); string_id credsMessage = new string_id (messageCONVO, "theme_park_credits"); sendSystemMessage (player, credsMessage); } string factionReward = dataTableGetString (datatable, questNum, "faction reward"); string factionReward2 = dataTableGetString (datatable, questNum, "faction_reward2"); string factionReward3 = dataTableGetString (datatable, questNum, "faction_reward3"); string factionReward4 = dataTableGetString (datatable, questNum, "faction_reward4"); if (factionReward != "none") { int factionAmt = dataTableGetInt (datatable, questNum, "faction_reward_amount"); if (factionAmt != 0) { factions.addFactionStanding(player,factionReward,factionAmt); } } if (factionReward2 != "none") { int factionAmt2 = dataTableGetInt (datatable, questNum, "faction_reward2_amount"); if (factionAmt2 != 0) { factions.addFactionStanding(player,factionReward2,factionAmt2); } } if (factionReward3 != "none") { int factionAmt3 = dataTableGetInt (datatable, questNum, "faction_reward3_amount"); if (factionAmt3 != 0) { factions.addFactionStanding(player,factionReward3,factionAmt3); } } if (factionReward4 != "none") { int factionAmt4 = dataTableGetInt (datatable, questNum, "faction_reward4_amount"); if (factionAmt4 != 0) { factions.addFactionStanding(player,factionReward4,factionAmt4); } } obj_id waypoint = getObjIdObjVar (player, questID + ".waypointhome"); if (waypoint != null) { destroyWaypointInDatapad(waypoint, player); } removeObjVar (player, questID); removeObjVar (player, "quest_table"); removeObjVar (player, "questNum"); if (hasScript (player, playerScript)) { detachScript (player, playerScript); } return; } // --------------------------------------------------------------------- // Used by Force Sensitive Quests and beyond // --------------------------------------------------------------------- int getQuestId(String questName) { return dataTableSearchColumnForString(questName, 0, "datatables/player/quests.iff"); } // --------------------------------------------------------------------- String getParentQuestName(String questName) { int questRow = getQuestId(questName); if(questRow > -1) { return dataTableGetString("datatables/player/quests.iff", questRow, "PARENT"); } return null; } // --------------------------------------------------------------------- boolean isComplete(String questName, obj_id player) { return isQuestComplete(player, getQuestId(questName)); } // --------------------------------------------------------------------- boolean canActivate(String questName, obj_id player) { // a quest can be activated if: // it has no parent // OR // it has a parent, but the parent quest has been completed // AND // the target quest is not active // AND // the target quest has not been completed boolean result = false; // bail out if the quest is already active if(! isActive(questName, player)) { // bail out if the parent hasn't been completed String parentQuestName = getParentQuestName(questName); if(parentQuestName != null && parentQuestName.length() > 0) { if(isComplete(parentQuestName, player)) { if(! isComplete(questName, player)) { LOG("newquests", (questName + " is available because the parent quest has been completed and " + questName + " has not been completed")); result = true; } else { LOG("newquests", (questName + " has already been completed")); } } else { LOG("newquests", (questName + " has a parent, " + parentQuestName + " but the parent quest is not complete")); } } else { if(! isActive(questName, player)) { if(! isComplete(questName, player)) { // quest has no parent, the quest can be activated result = true; } } } } else { LOG("newquests", (questName + " is active")); } LOG("newquests", ("canActivate(" + questName + ", " + player + ") returned " + result)); return result; } // --------------------------------------------------------------------- boolean isActive(String questName, obj_id player) { boolean result = false; int questRow = getQuestId(questName); if(questRow > -1) { result = isQuestActive(player, questRow); } return result; } // --------------------------------------------------------------------- void activate(String questName, obj_id player, obj_id questGiver) { if(questName == null) return; if(questName.length() < 1) return; LOG("newquests", "attempting to activate quest " + questName + " for player " + player + " npc " + questGiver); // open the quests datatable, retrieve quest information and setup the variables // associated with the quest string datatable = "datatables/player/quests.iff"; int questRow = getQuestId(questName); if(questRow > -1) { LOG("newquests", "found " + questName + " id=" + questRow); if(canActivate(questName, player)) { String scriptName = dataTableGetString(datatable, questRow, "ATTACH_SCRIPT"); // todo: deatch script doesn't detach the script? Always attempt to attach the script if(scriptName != null && scriptName.length() > 0) { LOG("newquests", "attaching script " + scriptName + " to player " + player + " for quest " + questName); attachScript(player, scriptName); } LOG("newquests", "activating quest " + questName + " for player " + player); if(questGiver != null) { String objvarname = "questlib." + questName + ".quest_giver"; LOG("newquests", "quests: activate setObjVar(" + player + ", " + objvarname + ", " + questGiver + ")"); setObjVar(player, objvarname, questGiver); questGiver = getObjIdObjVar(player, objvarname); LOG("newquests", "quests: activate, checking getObjIdObVar for quest giver. questGiver = " + questGiver); } activateQuest(player, questRow); int row = dataTableSearchColumnForString(questName, "NAME", "datatables/player/quests.iff"); int isVisible = dataTableGetInt ("datatables/player/quests.iff", row, "SHOW_SYSTEM_MESSAGES"); if(isVisible != 0) { string_id sid = new string_id ("quest/quests", "quest_journal_updated"); sendSystemMessage(player, sid); } } else { LOG("newquests", "quest " + questName + " for player " + player + " could not be activated"); } } else { LOG("newquests", "could not activate quest " + questName + " for player " + player + " because the quest could not be found in " + datatable); } } // --------------------------------------------------------------------- void complete(String questName, obj_id player, boolean succeeded) { LOG("newquest", "quests: complete(" + questName + ", " + player + ", " + succeeded + ")"); // send localized system message to player when a task is completed // if it is marked "visible" in the quests data table int row = dataTableSearchColumnForString(questName, "NAME", "datatables/player/quests.iff"); int isVisible = dataTableGetInt ("datatables/player/quests.iff", row, "SHOW_SYSTEM_MESSAGES"); //LOG("newquest", "isVisible ->" + isVisible); if(isVisible != 0) { String entry = getDataEntry(questName, "JOURNAL_ENTRY_SUMMARY"); if(entry != null && entry.length() > 0) { String[] entries = split(entry, ':'); if(entries.length > 1) { string_id qid = utils.unpackString(entry); //string_id qid = new string_id(entries[0], entries[1]); sendSystemMessage(player, qid); } } if(succeeded) { string_id sid = new string_id ("quest/quests", "task_complete"); sendSystemMessage (player, sid); } else { string_id sid = new string_id ("quest/quests", "task_failure"); sendSystemMessage (player, sid); } } obj_id questGiver = null; String objvarname = "questlib." + questName + ".quest_giver"; if(hasObjVar(player, objvarname)) { questGiver = getObjIdObjVar(player, objvarname); LOG("newquests", "quests: hasObjVar(" + player + ", " + objvarname + ") = true. setting questGiver=" + questGiver); } else { LOG("newquests", "quests: hasObjVar(" + player + ", " + objvarname + ") = false"); } deactivate(questName, player); completeQuest(player, getQuestId(questName)); Object[] params = new Object[3]; params[0] = player; params[1] = questName; params[2] = new Boolean(succeeded); script_entry.runScripts("OnForceSensitiveQuestCompleted", params); if(hasObjVar(player, "questlib." + questName)) { removeObjVar(player, "questlib." + questName); } // activate the next task String[] nextTasks = null; if(succeeded) { String taskList = getDataEntry(questName, "TASK_ON_COMPLETE"); nextTasks = split(taskList, ';'); } else { String taskList = getDataEntry(questName, "TASK_ON_FAIL"); nextTasks = split(taskList, ';'); } if(nextTasks != null && nextTasks.length > 0) { int iter = 0; for(iter = 0; iter < nextTasks.length; ++iter) { activate(nextTasks[iter], player, questGiver); } } if(hasObjVar(player, "quest." + questName)) { removeObjVar(player, "quest." + questName); } } // --------------------------------------------------------------------- void deactivate(String questName, obj_id player) { // open the quests datatable, retrieve quest information and setup the variables // associated with the quest string datatable = "datatables/player/quests.iff"; int questRow = getQuestId(questName); if(questRow > -1) { String scriptName = dataTableGetString(datatable, questRow, "ATTACH_SCRIPT"); if(hasScript(player, scriptName)) { int i = 0; int columnCount = dataTableGetNumRows(datatable); for(i = 0; i < columnCount; ++i) { if(i != questRow) { String s = dataTableGetString(datatable, i, "ATTACH_SCRIPT"); if(s != null && s == scriptName && isQuestActive(player, i)) { // don't detach! LOG("newquests", "not detaching script " + scriptName + " beacuse quest " + i + " is currently active and uses " + scriptName); return; } } } LOG("newquests", "deatching script " + scriptName + " from player " + player); detachScript(player, scriptName); } deactivateQuest(player, questRow); } } // --------------------------------------------------------------------- String[] getActiveQuestsWithScript(String scriptName, obj_id player) { resizeable String[] result = new Vector(); string datatable = "datatables/player/quests.iff"; int it = 0; int columnCount = dataTableGetNumRows(datatable); for(it = 0; it < columnCount; ++it) { String s = dataTableGetString(datatable, it, "ATTACH_SCRIPT"); if(s != null) { if(s == scriptName) { String taskName = dataTableGetString(datatable, it, "NAME"); if(isActive(taskName, player)) { result.add(taskName); } } } } return result; } // --------------------------------------------------------------------- String getDataEntry(String questName, String columnName) { String result = null; string datatable = "datatables/player/quests.iff"; int questRow = getQuestId(questName); if(questRow > -1) { result = dataTableGetString(datatable, questRow, columnName); } return result; } // --------------------------------------------------------------------- String getDataEntry(int questId, String columnName) { String result = null; if(questId > -1) { result = dataTableGetString("datatables/player/quests.iff", questId, columnName); } return result; } // --------------------------------------------------------------------- location getTheaterLocationTarget(obj_id self, int questRow) { location result = null; string questName = quests.getDataEntry(questRow, "NAME"); if(questName == null || questName.equals("") || !isActive(questName, self)) return null; string target = ""; float radius = 64.0f; float parameter = 1024.0f; location waitForPlanetWarp = null; // boolean waitForPlanetWarp = false; boolean haveParameter = false; if(hasObjVar(self, "quest." + questName + ".parameter")) radius = getFloatObjVar(self, "quest." + questName + ".parameter"); if(hasObjVar(self, "quest." + questName + ".target")) { target = getStringObjVar(self, "quest." + questName + ".target"); } else { string parameterString = quests.getDataEntry(questRow, "PARAMETER"); if(parameterString != null && !parameterString.equals("")) { LOG("newquests", "GET THEATER LOCATION TARGET: parsing parameter string: " + parameterString); string[] params = split(parameterString, ':'); for(int i = 0; i < params.length; i++) { if(Character.isDigit(params[i].charAt(0))) { parameter = utils.stringToFloat(params[i]); haveParameter = true; LOG("newquests", "GET THEATER LOCATION TARGET: search radius parameter found: " + parameter); } } } target = quests.getDataEntry(questRow, "TARGET"); } if (hasObjVar(self, "theaterRecoveryTarget")) { result = getLocationObjVar(self, "theaterRecoveryTarget"); if(result != null) { addLocationTarget(questName, result, radius); return result; } } if(target == null || target.equals("")) return null; boolean havePlanet = false; string[] tokens = split(target, ':'); string planet = null; if(tokens.length > 1) havePlanet = true; if(havePlanet) { if(tokens[0].indexOf(".iff") < 0) planet = tokens[0]; else planet = tokens[1]; } if(haveParameter && (parameter < 0)) { parameter = -parameter; parameter = rand(parameter - 200.0f, parameter + 200.0f); } if(!havePlanet && !haveParameter) { int attempts = 0; while(result == null && attempts < 15) { ++attempts; result = locations.getRandomGoodLocation(getLocation(self), 800.0f, 1500.0f, 32.0f); if(result != null) LOG("newquests", "GET THEATER LOCATION TARGET: no planet/no parameter - good location attempt: " + result.toString()); else LOG("newquests", "GET THEATER LOCATION TARGET: no planet/no parameter - good location attempt: null"); } } else if(!havePlanet && haveParameter) { int attempts = 0; while(result == null && attempts < 15) { ++attempts; result = locations.getRandomGoodLocation(getLocation(self), parameter - 200.0f, parameter + 600.0f, 32.0f); if(result != null) LOG("newquests", "GET THEATER LOCATION TARGET: no planet/parameter - good location attempt: " + result.toString()); else LOG("newquests", "GET THEATER LOCATION TARGET: no planet/parameter - good location attempt: null"); } } else if(havePlanet && haveParameter) { string currentScene = getCurrentSceneName(); if(currentScene != null && currentScene == planet) { int attempts = 0; while(result == null && attempts < 15) { ++attempts; result = locations.getRandomGoodLocation(getLocation(self), parameter - 200.0f, parameter + 600.0f, 32.0f); if(result != null) LOG("newquests", "GET THEATER LOCATION TARGET: planet/parameter - good location attempt: " + result.toString()); else LOG("newquests", "GET THEATER LOCATION TARGET: planet/parameter - good location attempt: null"); } } else { LOG("newquests", "GET THEATER LOCATION TARGET: planet/parameter - good location fall through: waiting for planet warp"); waitForPlanetWarp = new location(0.0f, 0.0f, 0.0f, planet); // waitForPlanetWarp = true; } } else if(havePlanet && !haveParameter) { string currentScene = getCurrentSceneName(); if(currentScene != null && currentScene == planet) { int attempts = 0; while(result == null && attempts < 15) { ++attempts; result = locations.getRandomGoodLocation(getLocation(self), 800.0f, 1500.0f, 32.0f); if(result != null) LOG("newquests", "GET THEATER LOCATION TARGET: planet/no parameter - good location attempt: " + result.toString()); else LOG("newquests", "GET THEATER LOCATION TARGET: planet/no parameter - good location attempt: null"); } } else { LOG("newquests", "GET THEATER LOCATION TARGET: planet/parameter - good location fall through: waiting for planet warp"); waitForPlanetWarp = new location(0.0f, 0.0f, 0.0f, planet); // waitForPlanetWarp = true; } } if(result != null) { region r = battlefield.getBattlefield(result); if(r != null) { if(isGod(self)) sendSystemMessageTestingOnly(self, "GOD MODE - WARNING: The good location chosen for the theater lies within a battlefield"); LOG("newquests", "the good location chosen for the theater lies within a battlefield: " + result.toString()); } LOG("newquests", "GET THEATER LOCATION TARGET: good location found: " + result.toString()); setObjVar(self, "quest." + questName + ".selected_location", result); if (!hasObjVar(self, "theaterRecoveryTarget")) { if ( (questName == "fs_theater_final") || (questName == "fs_theater_camp") ) { setObjVar(self, "theaterRecoveryTarget", result); } } addLocationTarget(questName, result, radius); } else if(waitForPlanetWarp != null) { // } else if(waitForPlanetWarp) { setObjVar(self, "quest." + questName + ".generate", waitForPlanetWarp); } return result; } // --------------------------------------------------------------------- location getLocationTarget(obj_id self, int questRow) { location result = null; // get the quest name from the row String questName = quests.getDataEntry(questRow, "NAME"); if(questName != null && questName.length() > 0 && isActive(questName, self)) { LOG("newquests", "initializing location task " + questName); float radius = 64.0f; boolean waitForPlanetWarp = false; if(hasObjVar(self, "quest." + questName + ".parameter")) { radius = getFloatObjVar(self, "quest." + questName + ".parameter"); LOG("newquests", "the target location radius is overridden by an object variable. radius = " + radius); } else { LOG("newquests", "default target radius of 64 meters will be used"); } // set up location target if(hasObjVar(self, "quest." + questName + ".target")) { result = getLocationObjVar(self, "quest." + questName + ".target"); if(result != null) { // the location target is overidden by an object variable //addLocationTarget("questName", result, radius); LOG("newquests", "location target for " + questName + " is overridden by an object variable. new location is " + result); } else { LOG("newquests", "location target for " + questName + " was supposed to be overridden, but the location could not be retrieved from the location object variable quest." + questName + ".target"); } } else { String planetName = null; obj_id cell = null; boolean haveCell = false; float x = 0.0f; boolean haveX = false; float z = 0.0f; boolean haveZ = false; float parameter = 1024.0f; boolean haveParameter = false; boolean haveTarget = false; String parameterString = quests.getDataEntry(questRow, "PARAMETER"); if(parameterString != null && parameterString.length() > 0) { LOG("newquests", "location parsing PARAMETER=" + parameterString); parameter = utils.stringToFloat(parameterString); haveParameter = true; } LOG("newquests", "location PARAMETER set to " + parameter); // use the location specified in the data table String locationString = quests.getDataEntry(questRow, "TARGET"); if(locationString != null && locationString.length() > 0) { haveTarget = true; LOG("newquests", "location parsing TARGET \"" + locationString + "\""); // target location is specified in the data table, // parse it string[] tokens = split(locationString, ':'); if(tokens.length > 0) { LOG("newquests", "location parsing " + tokens.length + " tokens"); String s = tokens[0]; if(!Character.isDigit(s.charAt(0))) { planetName = tokens[0]; LOG("newquests", "location parsed " + tokens[0] + " as the target planet"); if(tokens.length > 2) { LOG("newquests", "location parsing " + tokens[1] + " as x coordinate"); x = utils.stringToFloat(tokens[1]); haveX = true; LOG("newquests", "location parsing " + tokens[2] + " as z coordinate"); z = utils.stringToFloat(tokens[2]); haveZ = true; if(tokens.length > 3) { LOG("newquests", "location parsing " + tokens[3] + " as a cell ID"); cell = utils.stringToObjId(tokens[3]); haveCell = true; } } } else { LOG("newquests", "location first token is a number"); if(tokens.length > 1) { x = utils.stringToFloat(tokens[0]); z = utils.stringToFloat(tokens[1]); } } } } // create the location target if(! haveTarget && !haveParameter) { // generate a random location on the current planet // 1024 meters away int attempts = 0; while(result == null && attempts < 15) { ++attempts; result = locations.getRandomGoodLocation(getLocation(self), 800.0f, 1200.0f, 32.0f); LOG("newquests", "location generating a random location about 1 kilometer away " + result); } } else if(! haveTarget && haveParameter) { // generate a random location on the planet about // 'parameter' meters away result = locations.getRandomGoodLocation(getLocation(self), parameter - 100.0f, parameter + 100.0f, 32.0f); LOG("newquests", "location generating a random location between " + (parameter - 100.0f) + " and " + (parameter + 100.0f) + " meters away"); } else if(planetName != null && !haveX && !haveZ && !haveCell && haveParameter) { // generate a random location on the target planet about // 'parameter' meters away from wherever the player arrives on // the planet (if it's not the current planet), or if planetName // specifies THIS planet, generate a location about 'parameter' // meters away String currentScene = getCurrentSceneName(); if(currentScene != null && currentScene == planetName) { result = locations.getRandomGoodLocation(getLocation(self), parameter - 100.0f, parameter + 100.0f, 32.0f); LOG("newquests", "location generating a random location on " + planetName + " between " + (parameter - 100.0f) + " and " + (parameter + 100.0f) + " meters away"); } else { // need to select a location on login waitForPlanetWarp = true; LOG("newquests", "location generating a random location on " + planetName + " between " + (parameter - 100.0f) + " and " + (parameter + 100.0f) + " meters away"); } } else if(planetName != null && !haveX && !haveZ && !haveCell && !haveParameter) { // generate a random location on the target planet // about 'parameter' meters away from wherever the player // arrives on the planet, or if planetName specifies // THIS planet, generate a location about 1024 meters awawy string currentScene = getCurrentSceneName(); if(currentScene != null && currentScene == planetName) { result = locations.getRandomGoodLocation(getLocation(self), parameter - 800.0f, 1200.0f, 32.0f); LOG("newquests", "location generating a random location on " + planetName + " between 800 and 1200 meters away"); } else { // need to select a location on login waitForPlanetWarp = true; LOG("newquests", "location a location will be generated when the player travels to " + planetName); } } else if(planetName != null && haveX && haveZ && !haveCell && !haveParameter) { // generate a location at the requested coordinates result = new location(); result.x = x; result.z = z; result.area = planetName; LOG("newquests", "location generating a location at " + result); } else if(planetName != null && haveX && haveZ && !haveCell && haveParameter) { // generate a location with a sensitivity radius of 'parameter' meters result = new location(); result.x = x; result.z = z; result.area = planetName; radius = parameter; LOG("newquests", "location generating a location at " + result); } else if(planetName != null && haveX && haveZ && haveCell && !haveParameter) { // generate a location in the cell at the coordinates with a sensitivity // of 8 meters result = new location(); result.x = x; result.z = z; result.area = planetName; result.cell = cell; LOG("newquests", "location generating a location at " + result); } else if(planetName != null && haveX && haveZ && haveCell && haveParameter) { result = new location(); result.x = x; result.z = z; result.area = planetName; result.cell = cell; radius = parameter; LOG("newquests", "location generating a location at " + result); } } if(result != null) { setObjVar(self, "quest." + questName + ".selected_location", result); addLocationTarget(questName, result, radius); LOG("newquests", "location adding location target at " + result); } else if(waitForPlanetWarp == true) { setObjVar(self, "quest." + questName + ".generate", waitForPlanetWarp); } } return result; } // --------------------------------------------------------------------- boolean isMyQuest(int questRow, String scriptName) { boolean result = false; String s = getDataEntry(questRow, "ATTACH_SCRIPT"); if((s != null) && (scriptName != null) && (s == scriptName)) { result = true; } return result; } // --------------------------------------------------------------------- obj_id getTargetForQuest(obj_id self, String questName) { deltadictionary scriptVars = self.getScriptVars(); String objvarname = "encounter.target." + questName; obj_id result = scriptVars.getObjId(objvarname); LOG("newquests", "quest target " + objvarname + "=" + result + " self=" + self); return result; } // --------------------------------------------------------------------- int getQuestIdForTarget(obj_id self, obj_id target) { // determine if the target object is used for one of the player's // active tasks. Return the quest row in the quests.tab data table int result = -1; String objvarname = "questname"; if(isIdValid(target)) { if(hasObjVar(target, objvarname)) { // this is the name of the task which may have spawned the target, which // is cross-referenced by the TARGET quests table parameter or an override // objvar quest..target on the player String encounterQuestName = getStringObjVar(target, objvarname); if(encounterQuestName != null && encounterQuestName.length() > 0) { // the target object has a questname variable, it might be // a target for the player's task int numRows = dataTableGetNumRows("datatables/player/quests.iff"); int iter = 0; for(iter = 0; iter < numRows; ++iter) { if(isQuestActive(self, iter)) { LOG("newquests", "destroy - checking active quest " + iter); if(quests.isMyQuest(iter, "quest.task.destroy")) { LOG("newquest", "destroy - active quest " + iter + " is a destroy task"); String questName = quests.getDataEntry(iter, "NAME"); String targetName = null; objvarname = "quest." + questName + ".target"; if(hasObjVar(self, objvarname)) { targetName = getStringObjVar(self, objvarname); LOG("newquests", "destroy - target is overriden by objvar " + objvarname + " target=" + targetName); } else { targetName = quests.getDataEntry(iter, "TARGET"); LOG("newquests", "destroy - using data table target name " + targetName); } if(targetName != null && targetName.length() > 0) { if(targetName == encounterQuestName) { // this object might be for our task objvarname = targetName + ".holder"; LOG("newquests", "destroy - target is a quest target, maybe for this player, checking to see if the target has a holder objvar (" + objvarname +")"); if(hasObjVar(target, objvarname)) { obj_id holder = getObjIdObjVar(target, objvarname); LOG("newquests", "destroy - target has the " + objvarname + " objvar. It is set to " + holder); if(holder == self) { LOG("newquests", "destroy - target is ours"); // bingo! We're the target's quest source result = iter; break; } } else { LOG("newquests", "destroy - target does not have the " + objvarname + " objvar"); } } } } } } } else { LOG("newquests", "destroy - encounterName could not be determined"); } } else { LOG("newquests", "the " + objvarname + " objvar was not present"); } } else { LOG("newquests", "destroy - target id " + target + " is not valid"); } return result; } // --------------------------------------------------------------------- boolean doEncounterSpawn(obj_id self, int questRow) { // this is an encounter quest/task activation // track whether the encounter spawn succeeds boolean success = false; LOG("newquests", "encounter activating"); // get the name of the qust from the quests data table String questName = quests.getDataEntry(questRow, "NAME"); // object variable name for overriding the data table // defaults for spawning a creature from creatures.tab String objvarname = "quest." + questName + ".target"; // set creatureName to the override or to the data table entry // in quests.tab String creatureName = null; if(hasObjVar(self, objvarname)) { // an objvar is overriding the data table entry creatureName = getStringObjVar(self, objvarname); LOG("newquests", "encounter - target is overridden by " + objvarname + " (" + creatureName + ")"); } else { // get the creature name from the data table (used to spawn // from creatures.tab) creatureName = quests.getDataEntry(questRow, "TARGET"); LOG("newquests", "encounter - target is " + creatureName); } // select a nearby location ahead of the player to spawn the target LOG("newquests", "encounter - getting a spawn location"); float yaw = getYaw(self); location spawnLocation = utils.getLocationInArc(self, yaw-30, yaw+30, 48.0f); location l = locations.getGoodLocationAroundLocation(spawnLocation, 8, 8, 64, 64, false, true); if(l != null) { // location was successfully retrieved LOG("newquests", "encounter - found a location " + l); if(creatureName != null && creatureName.length() > 0) { // the creature name is valid, either from the quests data table // or overridden in the quest..target object variable // on the player LOG("newquests", "encounter - attempting to spawn " + creatureName); obj_id target = create.createCreature(creatureName, l, true); if(target != null) { // the creature spawned successfully, set some object // variables that might be used by other tasks tracking // this encounter (destroy, for example) LOG("newquests", "encounter - " + creatureName + " spawned"); objvarname = "questname"; setObjVar(target, objvarname, questName); objvarname = questName + ".holder"; setObjVar(target, objvarname, self); deltadictionary scriptVars = self.getScriptVars(); objvarname = "encounter.target." + questName; scriptVars.put(objvarname, target); LOG("newquests", "encounter - adding " + target + " to " + objvarname + " script variable"); // when calling quests.complete(), advise the quest // library that the encounter spawned successfully success = true; } } } else { LOG("newquests", "encounter - failed to get a spawn location"); } return success; } // --------------------------------------------------------------------- obj_id createSpawner(string spawner, location loc, string datatable) { return createSpawner(spawner, loc, datatable, null); } // --------------------------------------------------------------------- obj_id createSpawner(string spawner, location loc, string datatable, obj_id parent) { if (spawner == null || spawner.length() < 1) { LOG("quest", "quests.createSpawner -- spawner is null or empty"); return null; } if (loc == null) { LOG("quest", "quests.createSpawner -- loc is null"); return null; } if (datatable == null || datatable.length() < 1) { LOG("quest", "quests.createSpawner -- datatable is null or empty"); return null; } int index = dataTableSearchColumnForString(spawner, "type", datatable); if (index == -1) { LOG("quest", "quests.createSpawner -- can't find spawner " + spawner + " within datatable " + datatable); return null; } dictionary row = dataTableGetRow(datatable, index); if (row == null) { LOG("quest", "quests.createSpawner -- can't find data in row " + index + " for datatable " + datatable); return null; } int pulse = row.getInt("pulse"); int max_spawn = row.getInt("max_spawn"); int max_population = row.getInt("max_population"); int expire = row.getInt("expire"); obj_id spawner_object = createObject("object/tangible/spawning/quest_spawner.iff", loc); if (!isIdValid(spawner_object)) { LOG("quest", "quests.createSpawner -- can't create spawner object."); return null; } setObjVar(spawner_object, "quest_spawner.type", spawner); setObjVar(spawner_object, "quest_spawner.pulse", pulse); setObjVar(spawner_object, "quest_spawner.max_spawn", max_spawn); setObjVar(spawner_object, "quest_spawner.max_pop", max_population); if (expire > 1) setObjVar(spawner_object, "quest_spawner.time_expired" , expire + getGameTime()); else setObjVar(spawner_object, "quest_spawner.time_expired", 0); setObjVar(spawner_object, "quest_spawner.datatable", datatable); if(parent != null) setObjVar(spawner_object, "quest_spawner.parent", parent); return spawner_object; } obj_id getQuestGiver(String questName, obj_id player) { obj_id result = null; String objvarname = "questlib." + questName + ".quest_giver"; if(hasObjVar(player, objvarname)) { result = getObjIdObjVar(player, objvarname); } return result; } obj_id getQuestGiver(int questRow, obj_id player) { return getQuestGiver(getDataEntry(questRow, "NAME"), player); } /** * Checks for an objvar without matching list objvars "below" it. * e.g. match quest.wait_for_tasks without matching quest.wait_for_tasks.* * This is a workaround for objvar collision between * quest.task.wait_for_tasks and quest.task.ground.wait_for_tasks */ boolean safeHasObjVar(obj_id self, String objvarName) { obj_var ov = getObjVar(self, objvarName); // An obj_var is not an obj_var_list if its internal name == the full name you are looking for. if (ov != null && (ov.getName().equals(objvarName))) { return true; } return false; }