/********************************************************************** * Title: scriptlib * Description: base player script library **********************************************************************/ /***** INCLUDES ********************************************************/ include library.structure; include library.sui; include library.corpse; include library.jedi; include library.utils; include library.prose; include library.healing; include library.battlefield; include library.combat; include library.factions; include library.dot; include library.group; include library.pvp; include library.ai_lib; include library.innate; include library.player_stomach; include library.slots; include library.money; include library.player_structure; include library.meditation; include library.city; include library.force_rank; include library.missions; include library.bounty_hunter; include library.smuggler; include library.buff; include ai.ai_combat; include java.util.Arrays; include java.util.Vector; include java.util.Enumeration; /***** CONSTANTS *******************************************************/ //NEWBIE EXEMPTIONS const int MAX_NEWBIE_DEATHS = 3; const string VAR_NEWBIE_BASE = "noob"; const string VAR_NEWBIE_DEATH = VAR_NEWBIE_BASE + ".death"; const string VAR_NEWBIE_CONFIRM_BASE = VAR_NEWBIE_BASE + ".confirm"; const string VAR_NEWBIE_CONFIRM_INSURE = VAR_NEWBIE_CONFIRM_BASE + ".insure"; const string VAR_NEWBIE_CONFIRM_BIND = VAR_NEWBIE_CONFIRM_BASE + ".bind"; const string_id SID_NEWBIE_STATUS_EXPIRED = new string_id("base_player","newbie_expired"); //CORPSE DRAG const string HANDLER_NONE = "noHandler"; const float RANGE_CORPSE_DRAG_NORMAL = 40.0f; const float RANGE_CORPSE_DRAG_INTERIOR = 100.0f; const string_id SID_TARGET_NOT_PLAYER = new string_id("error_message","target_not_player"); const string_id SID_TARGET_SELF_DISALLOWED = new string_id("error_message","target_self_disallowed"); //LOGOUT CONSTANTS const string VAR_SAFE_LOGOUT = "safeLogout"; const string DICT_COST = "cost"; const string VAR_FACILITY_CLONING = "isCloningFacility"; const string_id SID_ISF_BANK = new string_id("error_message","insufficient_funds_bank"); const string_id SID_ISF_CASH = new string_id("error_message","insufficient_funds_cash"); const string DICT_KILLER = "killer"; const string VAR_REVIVE_BASE = "revive"; const string VAR_REVIVE_OPTIONS = "revive.options"; const string VAR_REVIVE_CLONE = "revive.cloneLocs"; const string VAR_REVIVE_SPAWN = "revive.spawnLocs"; const string VAR_REVIVE_DAMAGE = "revive.damage"; const string VAR_SUI_CLONE = "sui.clone"; //CONSENT CONSTANTS const string VAR_CONSENT_TO_BASE = "consentTo"; const string VAR_CONSENT_TO_ID = "consentTo.id"; const string VAR_CONSENT_TO_NAME = "consentTo.name"; const string VAR_CONSENT_FROM_BASE = "consentFrom"; const string VAR_CONSENT_FROM_ID = "consentFrom.id"; const string VAR_CONSENT_FROM_NAME = "consentFrom.name"; const string_id PROSE_CONSENT = new string_id("base_player","prose_consent"); const string_id PROSE_UNCONSENT = new string_id("base_player","prose_unconsent"); const string_id PROSE_CONSENT_ALREADY_CONSENTING = new string_id("base_player","prose_consent_already_consenting"); const string_id PROSE_CONSENT_LIST_FULL = new string_id("base_player","prose_consent_list_full"); //const int CONSENT_TO_MAX = 5; const int LIMIT_CONSENT_TO = 5; const string DICT_CONSENTER_ID = "consenterId"; const string DICT_CONSENTER_NAME = "consenterName"; const string HANDLER_CONSENT_TO_LOGOUT = "handleConsentToLogout"; const string HANDLER_RECEIVED_CONSENT = "handleReceivedConsent"; const string HANDLER_RECEIVED_UNCONSENT = "handleReceivedUnconsent"; const string_id SID_TARGET_OFFLINE = new string_id("error_message","target_offline"); //COMMAND CONSTANTS const string_id SID_CMD_BAD_TARGET = new string_id("error_message","cmd_bad_target"); //INSURANCE CONSTANTS const int INSURE_COST_BASE = 65; const float INSURE_CONST = 0.015f; //const string VAR_IS_INSURED = "isInsured"; //const string VAR_ITEM_UNINSURABLE = "uninsurable"; const string VAR_TO_INSURE = "toInsure"; const string HANDLER_INSURE_REQUEST = "handleInsureRequest"; const string HANDLER_INSURE_SUCCESS = "handleInsureSuccess"; const string HANDLER_INSURE_FAILURE = "handleInsureFailure"; const string HANDLER_BULK_INSURE_SUCCESS = "handleBulkInsureSuccess"; const string HANDLER_BULK_INSURE_FAILURE = "handleBulkInsureFailure"; const string HANDLER_CASH_INSURE = "handleCashInsure"; const string HANDLER_REQUESTED_INSURANCE = "handleRequestedInsurance"; const int BATCH_SIZE = 10; const string DICT_ITEM_ID = "itemId"; const string VAR_INSURE_UI_OPTIONS = "insureUIOptions"; const string_id SID_INSURE_UI_ERROR = new string_id("error_message","insure_ui_error"); const string_id SID_NO_INSURABLES = new string_id("error_message","no_insurables"); const string_id SID_NOT_ALL_INSURABLE = new string_id("error_message","not_all_insurable"); const string_id SID_INSURE_SUCCESS = new string_id("base_player","insure_success"); const string_id PROSE_INSURE_SUCCESS = new string_id("base_player","prose_insure_success"); const string_id SID_BULK_INSURE_ERRORS_TITLE = new string_id("error_message","bulk_insure_errors_title"); const string_id SID_BULK_INSURE_ERRORS_PROMPT = new string_id("error_message","bulk_insure_errors_prompt"); const string_id PROSE_NSF_TO_INSURE = new string_id("error_message","prose_nsf_insure"); const string_id PROSE_ITEM_ALREADY_INSURED = new string_id("error_message","prose_item_already_insured"); const string_id PROSE_ITEM_UNINSURABLE = new string_id("error_message","prose_item_uninsurable"); const string_id SID_NO_CORPSE_PRODUCED = new string_id("base_player", "no_corpse_produced"); const string_id PROSE_NEWBIE_INSURED = new string_id("base_player", "prose_newbie_insured"); const string_id SID_LAST_NEWBIE_INSURE = new string_id("base_player", "last_newbie_insure"); //UNINSURABLE FLAGS (UF) //const int UF_GENERIC = 0; //generic uninsurable item //const int UF_AUTOINSURE = 1; //auto-insured item that shows as auto-insured (schematics) //const int UF_AUTOINSURE_INVISIBLE = 2; //auto-insured item that does NOT show on any insurance screen //MESSAGING CONSTANTS const string DICT_SCRIPT_NAME = "scriptName"; const string DICT_OBJVAR_NAME = "objVarName"; const string DICT_XP_TYPE = "xpType"; const string DICT_XP_AMOUNT = "xpAmount"; const string HANDLER_ATTACH_SCRIPT = "handleAttachScript"; const string HANDLER_DETACH_SCRIPT = "handleDetachScript"; const string HANDLER_REMOVE_OBJVAR = "handleRemoveObjVar"; const string HANDLER_GRANT_XP = "handleGrantXp"; //coup de grace constants const string_id SID_CANNOT_ATTACK_TARGET = new string_id("error_message","target_not_attackable"); const string_id SID_TARGET_NOT_INCAPACITATED = new string_id("error_message","target_not_incapacitated"); const string_id SID_TARGET_ALREADY_DEAD = new string_id("error_message","target_already_dead"); const string_id PROSE_TARGET_ALREADY_DEAD = new string_id("error_message","prose_target_already_dead"); const string_id SID_KILLER_TARGET_DEAD = new string_id("base_player","killer_target_dead"); const string_id SID_VICTIM_DEAD = new string_id("base_player","victim_dead"); const string_id PROSE_TARGET_DEAD = new string_id("base_player","prose_target_dead"); const string_id PROSE_VICTIM_DEAD = new string_id("base_player","prose_victim_dead"); const string_id SID_BIND_REMOVED = new string_id("base_player","bind_removed"); const string_id SID_YOU_HAVE_CONSENT_FROM = new string_id("base_player","you_have_conent_from"); const string_id SID_YOU_DO_NOT_HAVE_CONSENT = new string_id("base_player","you_do_not_have_consent"); const string_id SID_DEFEATED_BOUNTY_HUNTER = new string_id("base_player","defeated_bounty_hunter"); const string HANDLER_PLAYER_DEATH = "handlePlayerDeath"; const string HANDLER_CLONE_RESPAWN = "handleCloneRespawn"; const float TIME_DEATH = 0.25f; const string VAR_CORPSE_BASE = "corpse"; const string VAR_CORPSE_ID = "corpse.id"; const string VAR_CORPSE_KILLER = "corpse.killer"; const string VAR_CORPSE_STAMP = "corpse.stamp"; const string VAR_BEEN_COUPDEGRACED = "beenCoupDeGraced"; const string VAR_DEATHBLOW_KILLER = VAR_BEEN_COUPDEGRACED+".killer"; const string VAR_DEATHBLOW_STAMP = VAR_BEEN_COUPDEGRACED+".stamp"; const string DATATABLE_AI_SPECIES = "datatables/ai/species.iff"; const string DATATABLE_COL_SKELETON = "Skeleton"; const string SKELETON_HUMAN = "human"; //NOTIFY GM CODES (NC) const int NC_DEATH = 0; //STAT MIGRATION CONSTANTS const string HANDLER_STAT_MIGRATION = "handleStatMigration"; //TIP DEFINES const float TIP_WIRE_SURCHARGE = 0.05f; const string VAR_TIP_BASE = "tip"; const string VAR_TIP_TARGET = VAR_TIP_BASE + ".target"; const string VAR_TIP_TARGET_NAME = VAR_TIP_BASE + ".targetName"; const string VAR_TIP_AMT = VAR_TIP_BASE + ".amt"; const string VAR_TIP_SUI = VAR_TIP_BASE + ".sui"; const string_id SID_TIP_CLEAR = new string_id("base_player","tip_clear"); const string_id SID_TIP_ABORT = new string_id("base_player","tip_abort"); const string_id PROSE_TIP_ABORT = new string_id("base_player","prose_tip_abort"); const string_id SID_TIP_ERROR = new string_id("base_player","tip_error"); const string_id SID_TIP_TARGET_OFFLINE = new string_id("base_player", "tip_target_offline"); const string_id SID_TIP_NSF = new string_id("base_player", "tip_nsf"); const string_id SID_TIP_SYNTAX = new string_id("base_player", "tip_syntax"); const string_id SID_TIP_WIRE_TITLE = new string_id("base_player", "tip_wire_title"); const string_id SID_TIP_WIRE_PROMPT = new string_id("base_player", "tip_wire_prompt"); const string_id PROSE_INVALID_TIP_PARAM = new string_id("base_player", "prose_tip_invalid_param"); const string_id PROSE_INVALID_TIP_AMT = new string_id("base_player", "prose_tip_invalid_amt"); const string_id PROSE_TIP_NSF_CASH = new string_id("base_player", "prose_tip_nsf_cash"); const string_id PROSE_TIP_NSF_BANK = new string_id("base_player", "prose_tip_nsf_bank"); const string_id PROSE_TIP_NSF_WIRE = new string_id("base_player", "prose_tip_nsf_wire"); const string_id PROSE_TIP_RANGE = new string_id("base_player", "prose_tip_range"); const string_id PROSE_TIP_PASS_SELF = new string_id("base_player", "prose_tip_pass_self"); const string_id PROSE_TIP_PASS_TARGET = new string_id("base_player", "prose_tip_pass_target"); const string_id SID_WIRE_PASS_SELF = new string_id("base_player", "wire_pass_self"); const string_id PROSE_WIRE_PASS_SELF = new string_id("base_player", "prose_wire_pass_self"); const string_id PROSE_WIRE_PASS_TARGET = new string_id("base_player", "prose_wire_pass_target"); const string_id SID_MAY_NOT_TIP_TARGET = new string_id("base_player", "may_not_tip_target"); const string_id SID_ONLY_TIP_VALID_TARGETS = new string_id("base_player", "only_tip_valid_targets"); const string_id SID_WIRE_MAIL_SUBJECT = new string_id("base_player", "wire_mail_subject"); const string_id PROSE_WIRE_MAIL_FROM = new string_id("base_player", "prose_wire_mail_from"); //body prose strings const string_id PROSE_WIRE_MAIL_SELF = new string_id("base_player", "prose_wire_mail_self"); const string_id PROSE_WIRE_MAIL_TARGET = new string_id("base_player", "prose_wire_mail_target"); //COVERT RESPAWN STRING_IDS const string_id SID_COVERT_RESPAWN_UNALIGNED = new string_id("base_player", "covert_respawn_unaligned"); const string_id SID_COVERT_RESPAWN_UNFRIENDLY = new string_id("base_player", "covert_respawn_unfriendly"); const string_id SID_COVERT_RESPAWN_OUTSIDE = new string_id("base_player", "covert_respawn_outside"); //INSURABLE DECAY EVENT DEFINES const string TBL_INSURE_DECAY_EVENTS = "datatables/player/insure_decay_event.iff"; const string COL_EVENT = "EVENT"; const string COL_INSURED = "INSURED"; const string COL_UNINSURED = "UNINSURED"; const string COL_DO_UNINSURE = "DO_UNINSURE"; //JEDI DATA const int MIN_JEDI_WAIT_TIME = 60; // days before you can become a Jedi const string OBJVAR_JEDI_SKILL_REQUIREMENTS = "jedi.skillsNeeded"; // DAMAGE & DECAY const float DECAY_RATE = 0.002f; // 1 decay pt for every 500 damage const string DECAY_REMAINDER = "decay.remainder"; const float MIN_CLONING_SICKNESS_COST = 100; // credits const float MAX_CLONING_SICKNESS_COST = 5000; // credts int getCloningSicknessCureCost(obj_id player) { //Update 8 reduces the cost of Removing Cloning Sickness if the City you are in has the Specialization. float minCost = MIN_CLONING_SICKNESS_COST; float maxCost = MAX_CLONING_SICKNESS_COST; int city_id = city.checkCity(player, false); if(city_id > 0 && city.cityHasSpec(city_id, city.SF_SPEC_CLONING)) { minCost = MIN_CLONING_SICKNESS_COST/2; maxCost = MAX_CLONING_SICKNESS_COST/2; } //SF_SPEC_CLONING float level = getLevel(player); float costRatio = level / 90f; float cost = minCost + ((maxCost - minCost) * costRatio); return (int)cost; } boolean canAffordCloningSicknessCure(obj_id player) { int cost = getCloningSicknessCureCost(player); int balance = getTotalMoney(player); if(cost > balance) { return false; } return true; } void cureCloningSickness(obj_id player) { if(!canAffordCloningSicknessCure(player)) { sendSystemMessage(player, new string_id("spam", "not_enough_cash_4_cure")); return; } int cost = getCloningSicknessCureCost(player); if(cost > 0) { money.requestPayment(player, money.ACCT_CLONING, cost, "none", null, false); } playClientEffectObj(player, "appearance/pt_cure_cloning_sickness.prt", player, ""); buff.removeBuff(player, "cloning_sickness"); playMusic(player, "sound/vo_meddroid_01.snd"); } /***** BASE FUNCTIONS **************************************************/ /***************************************************************** * @brief grants a waypoint to the specified object to the player * * @param obj_id player * @param obj_id target * * @return obj_id; null on error *****************************************************************/ obj_id grantWayPoint(obj_id player, obj_id target) { if(!isIdValid(player) || (!isPlayer(player)) || !isIdValid(target)) { return null; } obj_id waypoint = createWaypointInDatapad(player, target); if(!isIdValid(waypoint)) return null; setWaypointActive(waypoint, true); setWaypointVisible(waypoint, true); return waypoint; } /***** TIPPING RELATED FUNCTIONS *******************************/ /***************************************************************** * @brief attempts to tip * * @param obj_id player * @param obj_id target * @param int amt * * @return boolean; false on error *****************************************************************/ boolean giveTip( obj_id player, obj_id target, string targetName, int amt, boolean useCash ) { // Abort if the targets are invalid. if ( !isIdValid(player) || !isIdValid(target) || targetName == null ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " -- Tip aborted: Target or tipper is invalid or Target Name is null." ); if ( isIdValid(player) ) sendSystemMessage( player, new string_id( "error_message", "tip_target_bad" ) ); return false; } CustomerServiceLog( "Trade", " Processing Tip, Player: " + player + " " + getName(player) + " Target: " + target + " " + getName(target) + " Amount: " + amt + " Cash: " + useCash ); // Check to see if we are tipping a player. if ( target.isLoaded() && !isPlayer(target) ) { if ( targetName == null || targetName.equals("") ) targetName = utils.getStringName(target); CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " -- Tip aborted: Target isn't a player." ); prose_package ppNoTipTarget = prose.getPackage(SID_MAY_NOT_TIP_TARGET); prose.setTT(ppNoTipTarget, target); sendSystemMessageProse( player, ppNoTipTarget ); sendSystemMessage( player, SID_ONLY_TIP_VALID_TARGETS ); return false; } // We can't tip less than 1 or more than 10 million. if ( amt < 1 ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " -- Tip aborted: Tip amount is less than 1." ); prose_package invalidAmt = prose.getPackage( PROSE_INVALID_TIP_AMT, amt ); sendSystemMessageProse( player, invalidAmt ); return false; } if ( amt > 1000000 ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " -- Tip aborted: Tip amount is greater than 1000000." ); prose_package invalidAmt = prose.getPackage( PROSE_INVALID_TIP_AMT, amt ); sendSystemMessageProse( player, invalidAmt ); return false; } // We can't send cash to an unloaded target. if ( !target.isLoaded() ) useCash = false; // Check our distance for cash transfers. if ( useCash ) { float dist = getDistance( getLocation(player), getLocation(target) ); if ( dist > 15f ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " -- Tip changing to bank transfer due to distance. Distance: " + dist ); prose_package tooFar = prose.getPackage( PROSE_TIP_RANGE, target ); sendSystemMessageProse( player, tooFar ); useCash = false; } } // Dispatch the money transfer. dictionary d = new dictionary(); d.put("target", target); d.put("amt", amt); d.put("useCash", useCash); d.put("targetName", targetName); if ( useCash ) { // Cash transfers use transferCashTo. int cash = getCashBalance( player ); if ( amt > cash ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " Target: " + target + " -- Tip aborted: Insufficient cash. Amt: " + amt + " Cash: " + cash ); prose_package nsfCash = prose.getPackage( PROSE_TIP_NSF_CASH, target, amt ); sendSystemMessageProse( player, nsfCash ); return false; } CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " Target: " + target + " -- Transferring Cash! Amt: " + amt ); if (utils.isFreeTrial(player, target)) doTipLogging(player, target, amt); // Transfer cash to the other player. boolean success = transferCashTo( player, target, amt, "handleTipSuccess", "handleTipFail", d ); if ( !success ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " Target: " + target + " -- Tip aborted: transferCashTo failed. Amt: " + amt ); sendSystemMessage( player, new string_id( "base_player", "cash_transfer_failed" ) ); return false; } } else { // Bank transfers pop up a bank UI. int bank = getBankBalance( player ); if ( amt > bank ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " Target: " + target + " -- Tip aborted: Insufficient bank balance. Amt: " + amt + " Bank: " + bank ); prose_package nsfBank = prose.getPackage( PROSE_TIP_NSF_BANK, target, amt ); sendSystemMessageProse( player, nsfBank ); return false; } int pid = showTipSui( player, target, targetName, amt ); if ( pid < 0 ) { CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " Target: " + target + " -- Tip aborted: Unable to create bank tip SUI window." ); sendSystemMessageTestingOnly( player, "Tip aborted: Unable to create bank tip SUI window." ); return false; } } // CustomerServiceLog("Trade","TIP: (" + player + ") " + getName(player) + " to (" + target + ") " + targetName + ": gracefully exiting giveTip() -> AMT="+amt); return true; } int showTipSui( obj_id player, obj_id target, string targetName, int amt ) { if ( !isIdValid(player) || !isIdValid(target) || (targetName == null) || (targetName.equals("")) ) { return -1; } CustomerServiceLog( "Trade", " Tip -- Player: " + player + " " + getName(player) + " Target: " + target + " -- Showing bank tip wire UI." ); string title = utils.packStringId(SID_TIP_WIRE_TITLE); string prompt = utils.packStringId(SID_TIP_WIRE_PROMPT); int cBox = sui.msgbox( player, player, prompt, sui.YES_NO, title, "handleWireConfirm" ); if ( cBox > -1 ) { utils.setScriptVar( player, VAR_TIP_SUI, cBox ); utils.setScriptVar( player, VAR_TIP_TARGET, target ); utils.setScriptVar( player, VAR_TIP_TARGET_NAME, targetName ); utils.setScriptVar( player, VAR_TIP_AMT, amt ); } return cBox; } void cleanupTipSui( obj_id player ) { if ( !isIdValid(player) ) { return; } utils.removeScriptVar( player, VAR_TIP_TARGET ); utils.removeScriptVar( player, VAR_TIP_TARGET_NAME ); utils.removeScriptVar( player, VAR_TIP_AMT ); utils.removeScriptVar( player, VAR_TIP_SUI ); } void doTipLogging(obj_id player, obj_id target, int amt) { int trackTipNumIn = 0; int trackTipAmtIn = 0; int trackTipNumOut = 0; int trackTipAmtOut = 0; if (!utils.hasScriptVar(player, utils.TIP_OUT_NUM)) { utils.setScriptVar(player, utils.TIP_OUT_NUM, 1); utils.setScriptVar(player, utils.TIP_OUT_AMMOUNT, amt); utils.setScriptVar(player, utils.TIP_OUT_THACK, getGameTime()); trackTipNumOut = 1; trackTipAmtOut = amt; } else { int tipNum = utils.getIntScriptVar(player, utils.TIP_OUT_NUM) +1; int tipAmt = utils.getIntScriptVar(player, utils.TIP_OUT_AMMOUNT) + amt; utils.setScriptVar(player, utils.TIP_OUT_NUM, tipNum); utils.setScriptVar(player, utils.TIP_OUT_AMMOUNT, tipAmt); trackTipNumOut = tipNum; trackTipAmtOut = tipAmt; } if (!utils.hasScriptVar(target, utils.TIP_IN_NUM)) { utils.setScriptVar(target, utils.TIP_IN_NUM, 1); utils.setScriptVar(target, utils.TIP_IN_AMMOUNT, amt); utils.setScriptVar(target, utils.TIP_IN_THACK, getGameTime()); trackTipNumIn = 1; trackTipAmtIn = amt; } else { int tipNum = utils.getIntScriptVar(target, utils.TIP_IN_NUM) +1; int tipAmt = utils.getIntScriptVar(target, utils.TIP_IN_AMMOUNT) + amt; utils.setScriptVar(target, utils.TIP_IN_NUM, tipNum); utils.setScriptVar(target, utils.TIP_IN_AMMOUNT, tipAmt); trackTipNumIn = tipNum; trackTipAmtIn = tipAmt; } if (trackTipNumIn > utils.TIP_NUM_MAX || trackTipAmtIn > utils.TIP_AMT_MAX || trackTipNumOut > utils.TIP_NUM_MAX || trackTipAmtOut > utils.TIP_AMT_MAX) { int pTimeHack = utils.getIntScriptVar(player, utils.TIP_OUT_THACK); int tTimeHack = utils.getIntScriptVar(target, utils.TIP_IN_THACK); pTimeHack = getGameTime() - pTimeHack; tTimeHack = getGameTime() - tTimeHack; CustomerServiceLog("exploit", "Free Trial Tipping -- Suspicious activity -- %TU has made "+trackTipNumOut+" tips for a total of "+trackTipAmtOut+" over the course of "+pTimeHack+"seconds, %TT has recieved "+trackTipNumIn+" tips for a total of "+trackTipAmtIn+" over the course of "+tTimeHack+" seconds.",player,target); } } /***** CONSENT RELATED FUNCTIONS *******************************/ /***************************************************************** * @brief attempts to relinquish consents that player has * * @param obj_id player * * @return boolean; false on error *****************************************************************/ boolean consent(obj_id player, obj_id target) { if ( !isIdValid(player) || !isIdValid(target) ) { return false; } if ( target == player ) { //target must be a player sendSystemMessage(player, SID_TARGET_SELF_DISALLOWED); return false; } if ( !isPlayer(target) ) { //target must be a player sendSystemMessage(player, SID_TARGET_NOT_PLAYER); return false; } resizeable obj_id[] consentTo = getResizeableObjIdArrayObjVar(player, VAR_CONSENT_TO_ID); if ( consentTo == null ) { resizeable obj_id[] newConsentTo = new obj_id[0]; consentTo = newConsentTo; } if ( utils.getElementPositionInArray(consentTo, target) > -1 ) { prose_package pp = prose.getPackage(PROSE_CONSENT_ALREADY_CONSENTING, getPlayerFullName(target)); sendSystemMessageProse(player, pp); return false; } else if ( consentTo.length >= LIMIT_CONSENT_TO ) { prose_package pp = prose.getPackage(PROSE_CONSENT_LIST_FULL, LIMIT_CONSENT_TO); sendSystemMessageProse(player, pp); return false; } else { consentTo = utils.addElement(consentTo, target); //process corpse consents... obj_id[] corpses = getObjIdArrayObjVar(player, VAR_CORPSE_ID); if ( (corpses != null) && (corpses.length > 0) ) { corpse.grantCorpseConsent(corpses, target); } if ( setObjVar(player, VAR_CONSENT_TO_ID, consentTo) ) { dictionary d = new dictionary(); d.put(DICT_CONSENTER_ID, player); prose_package pp = prose.getPackage(PROSE_CONSENT, getPlayerFullName(target)); sendSystemMessageProse(player, pp); messageTo(target, HANDLER_RECEIVED_CONSENT, d, 0, true); return true; } } return false; } boolean unconsent(obj_id player, obj_id target) { if ( !isIdValid(player) || !isIdValid(target) ) { return false; } if ( target == player ) { //target must be a player sendSystemMessage(player, SID_TARGET_SELF_DISALLOWED); return false; } //process corpse consents... obj_id[] corpses = getObjIdArrayObjVar(player, VAR_CORPSE_ID); if ( (corpses != null) && (corpses.length > 0) ) { corpse.revokeCorpseConsent(corpses, target); } else { removeObjVar(player, VAR_CORPSE_ID); } resizeable obj_id[] consentTo = getResizeableObjIdArrayObjVar(player, VAR_CONSENT_TO_ID); if ( consentTo != null ) { int idx = utils.getElementPositionInArray(consentTo, target); if ( idx > -1 ) { consentTo = utils.removeElementAt(consentTo, idx); if( consentTo.length == 0 ) // Zero length array check { removeObjVar(player, VAR_CONSENT_TO_BASE); } else { setObjVar(player, VAR_CONSENT_TO_ID, consentTo); } prose_package pp = prose.getPackage(PROSE_UNCONSENT, getPlayerFullName(target)); sendSystemMessageProse(player, pp); dictionary d = new dictionary(); d.put(DICT_CONSENTER_ID, player); messageTo(target, HANDLER_RECEIVED_UNCONSENT, d, 0, true); } else { return false; } } else { return false; } return true; } boolean hasConsent(obj_id player, obj_id target, boolean verbose) { if ( !isIdValid(player) || !isIdValid(target) ) { return false; } if ( target == player ) { //sendSystemMessage(player, SID_TARGET_SELF_DISALLOWED); return false; } boolean isConsented = false; obj_id[] consentFrom = getObjIdArrayObjVar(player, VAR_CONSENT_FROM_ID); if ( (consentFrom == null) || (consentFrom.length == 0) ) { //player is not consented by anyone } else { if ( utils.getElementPositionInArray(consentFrom, target) > -1 ) { isConsented = true; } } if ( verbose ) { if ( isConsented ) { prose_package ppYouHaveConsentFrom = prose.getPackage(SID_YOU_HAVE_CONSENT_FROM); prose.setTT(ppYouHaveConsentFrom, target); sendSystemMessageProse(player, ppYouHaveConsentFrom); } else { prose_package ppYouDoNotHaveConsent = prose.getPackage(SID_YOU_DO_NOT_HAVE_CONSENT); prose.setTT(ppYouDoNotHaveConsent, target); sendSystemMessageProse(player, ppYouDoNotHaveConsent); } } return isConsented; } boolean hasConsent(obj_id player, obj_id target) { return hasConsent(player, target, false); } /***************************************************************** * @brief attempts to relinquish consents that player has * * @param obj_id player * * @return boolean; false on error *****************************************************************/ boolean relinquishConsents(obj_id player) { if ( (player == null) || (!isPlayer(player)) ) { return false; } if ( hasObjVar(player, VAR_CONSENT_FROM_BASE) ) { obj_id[] consentFromList = getObjIdArrayObjVar(player, VAR_CONSENT_FROM_ID); if ( (consentFromList == null) || (consentFromList.length == 0) ) { return false; } dictionary d = new dictionary(); d.put(corpse.DICT_PLAYER_ID, player); boolean litmus = true; for ( int i = 0; i < consentFromList.length; i++ ) { litmus &= messageTo(consentFromList[i], HANDLER_CONSENT_TO_LOGOUT, d, 0, true); } removeObjVar(player, VAR_CONSENT_FROM_BASE); return litmus; } return false; } /***** DEATH FUNCTIONS **************************************************/ location getEffectiveDeathLocation(obj_id player) { // Note: this function should always return a location in the world cell // if we are dealing with an effective death location different from // the player's actual location. location loc = getLocation(player); if (!loc.area.startsWith("space_")) return loc; // We're in a space scene, so we should have an objvar on the player // saying where we last launched from. loc = getLocationObjVar(player, "space.launchLoc"); if (loc != null) return loc; // We're in a bad state, may as well pick the origin of tatooine. return new location(0.0f, 0.0f, 0.0f, "tatooine"); } ///wrapper for nik void killPlayer(obj_id player, obj_id killer) { killPlayer(player, killer, true); } /***************************************************************** * @brief handles player death * * @param obj_id player * @param obj_id killer * * @return boolean; false on error *****************************************************************/ void killPlayer (obj_id player, obj_id killer, boolean usePVPRules) { if ( !isIdValid(player) || !isIdValid(killer) || (!isPlayer(player)) ) { return; } //set all pools to -50 int dam = -(getAttrib(player, HEALTH) + 50); addAttribModifier(player, HEALTH, dam, 0f, 0f, MOD_POOL); coupDeGrace(player, killer, false, usePVPRules); } /***************************************************************** * @brief sets the players bind spot * * @param obj_id victim * @param obj_id killer * * @return boolean; false on error *****************************************************************/ void coupDeGrace(obj_id victim, obj_id killer, boolean playAnim) { coupDeGrace(victim, killer, playAnim, true); } void coupDeGrace(obj_id victim, obj_id killer, boolean playAnim, boolean usePVPRules) { //sendSystemMessageTestingOnly(victim, "coupDeGrace: entering..."); if ( !isIdValid(victim) || !isIdValid(killer)) { return; } //if victim has this scriptvar, someone is already trying to kill them //but they are on two different processes //to keep from having this scriptvar forever, we only leave it for 60 seconds if (utils.hasScriptVar(victim, "death.beingCoupDeGraced")) { int expireTime = utils.getIntScriptVar(victim, "death.beingCoupDeGraced"); int currentTime = getGameTime(); if(currentTime <= expireTime) { return; } else { utils.removeScriptVar(victim, "death.beingCoupDeGraced"); } } if(!victim.isAuthoritative() || !killer.isAuthoritative()) { //we are not the same server //lets force us to the same //messageTo in 2 seconds to check //put in pay load the # of times we have tried requestSameServer(victim, killer); int expireTime = getGameTime() + 60; utils.setScriptVar(victim, "death.beingCoupDeGraced", expireTime); int numberOfTries = 1; dictionary dict = new dictionary(); dict.put("numberOfTries", numberOfTries); dict.put("victim", victim); dict.put("killer", killer); dict.put("playAnim", playAnim); dict.put("usePVPRules", usePVPRules); messageTo(victim, "msgCoupDeGraceAuthoritativeCheck", dict, 2, false); return; } if ( isDead(victim) ) { prose_package pp = prose.getPackage(PROSE_TARGET_ALREADY_DEAD, victim); sendSystemMessageProse(killer, pp); //sendSystemMessage(killer, SID_TARGET_ALREADY_DEAD); return; } if ( !isIncapacitated(victim) ) { sendSystemMessage(killer, SID_TARGET_NOT_INCAPACITATED); return; } utils.setScriptVar(victim, "lastKiller", killer); if ( !hasObjVar(victim, VAR_BEEN_COUPDEGRACED) ) { setObjVar(victim, VAR_DEATHBLOW_KILLER, killer); setObjVar(victim, VAR_DEATHBLOW_STAMP, getGameTime()); } gcw.releaseGcwPointCredit(victim); obj_id master = null; obj_id pvpKiller = killer; if(!isPlayer(killer)) { if(isMob(killer)) { master = getMaster(killer); if(isIdValid(master) && isPlayer(master)) { pvpKiller = master; } } } if(isPlayer(pvpKiller)) { utils.setScriptVar(victim, "pvp_death", 1); pvp.bfCreditForKill(pvpKiller); gcw.gcwInvasionCreditForPVPKill(pvpKiller); pvp.bfCreditForDeath(victim, pvpKiller); } boolean onBattlefield = false; //insert battlefield stuff check here region r = battlefield.getBattlefield(victim); if ( r == null ) //not in battlefield { if(usePVPRules) { if ( !pvpCanAttack(killer, victim) && (killer != victim) ) { sendSystemMessage(killer, SID_CANNOT_ATTACK_TARGET); return; } } } else //we are in a battlefield { onBattlefield = true; if ( !pvpIsEnemy(killer, victim) && (killer != victim) ) { sendSystemMessage(killer, SID_CANNOT_ATTACK_TARGET); return; } } if ( playAnim ) { playDeathBlowAnimation(victim, killer); } //check to see if the killer and the victim are dueling; this must be done before //the call to setPosture(victim, POSTURE_DEAD) below because setting the posture //to POSTURE_DEAD will cause the duel pvp flags to get cleared boolean dueling = pvpIsDueling(victim, pvpKiller); if ( getPosture(victim) != POSTURE_DEAD ) { if ( !setPosture(victim, POSTURE_DEAD) ) { //debugSpeakMsg(victim, "coupDeGrace: unable to set my posture to dead!"); } } if ( killer != victim ) { prose_package ppToKiller = prose.getPackage(PROSE_TARGET_DEAD, victim); combat.sendCombatSpamMessageProse(killer, victim, ppToKiller, true, false, true); } if ( onBattlefield ) { //let ben handle this //make sure to remove the VAR_BEEN_COUPDEGRACED after you handle reviving the player... if (battlefield.isBattlefieldActive(r)) { battlefield.sendBattlefieldMessage(r, getFirstName(victim) + " has been eliminated by " + getFirstName(killer)); // Allow player to stay dead for a bit. Send a message to expel him. obj_id bf_object = battlefield.getMasterObjectFromRegion(r); dictionary params = new dictionary(); params.put("master_object", bf_object); messageTo(victim, "msgBattlefieldDeath", params, battlefield.DEATH_TIME, true); // Register the kill battlefield.registerBattlefieldKill(killer, victim, bf_object); return; } } else { /* //check pvp flags if ( pvpGetAlignedFaction(killer) != 0 && pvpGetType(killer) == PVPTYPE_COVERT ) pvpSetFactionEnemyFlag(killer, pvpGetAlignedFaction(victim)); */ } playerDeath(victim, killer, dueling); } void playDeathBlowAnimation(obj_id victim, obj_id killer) { if ( !isIdValid(victim) || !isIdValid(killer) ) return; string skeleton = ""; if ( dataTableOpen(DATATABLE_AI_SPECIES) ) { int species = getSpecies(killer); if ( species == -1 ) { //do nothing } else { skeleton = dataTableGetString(DATATABLE_AI_SPECIES, species, DATATABLE_COL_SKELETON); } } if ( skeleton != null && !skeleton.equals("") && (killer != victim) ) { if ( isPlayer(killer) || (skeleton.equals(SKELETON_HUMAN)) ) { // we need to do our animation crap.. This is a little whackaloony string strPlaybackScript = ""; obj_id objWeapon = getCurrentWeapon(killer); int intWeaponType = getWeaponType(objWeapon); int intWeaponCategory = combat.getWeaponCategory(intWeaponType); //LOG("combat_spam", "weapon category is "+intWeaponCategory); //LOG("combat_spam", "weapon Type is "+intWeaponType); //LOG("combat_spam", "weapon id is "+objWeapon); if(intWeaponCategory==combat.RANGED_WEAPON) { //LOG("combat_spam", "ranged coup de grace"); strPlaybackScript = "ranged_coup_de_grace"; } else { //LOG("combat_spam", "melee coup de grace"); // is it unarmed, or a weapon if(intWeaponType==WEAPON_TYPE_UNARMED) { strPlaybackScript = "unarmed_coup_de_grace"; } else { strPlaybackScript = "melee_coup_de_grace"; } } //LOG("combat_spam", "playback script is"+ strPlaybackScript); attacker_results cbtAttackerResults = new attacker_results(); defender_results[] cbtDefenderResults = new defender_results[1]; // ALWAYS AN ARRAY DO NOT EVER CHANGE DO NOT NEVER! cbtDefenderResults[0] = new defender_results(); // new this up otherwise we'll exception cbtAttackerResults.id = killer; cbtAttackerResults.endPosture = getPosture(killer); cbtAttackerResults.weapon = objWeapon; cbtDefenderResults[0].endPosture = POSTURE_DEAD; cbtDefenderResults[0].result = COMBAT_RESULT_HIT; cbtDefenderResults[0].id = victim; doCombatResults(strPlaybackScript, cbtAttackerResults, cbtDefenderResults); } } } /***************************************************************** * @brief death blow overload * * @param obj_id victim * @param obj_id killer * * @return boolean; false on error *****************************************************************/ void coupDeGrace(obj_id victim, obj_id killer) { coupDeGrace (victim, killer, true); } /***************************************************************** * @brief handles player death * * @param obj_id player * @param obj_id corpse * @param obj_id killer * @param boolean dueling - indicates if the death is from dueling between player and killer * * @return boolean; false on error *****************************************************************/ boolean playerDeath(obj_id player, obj_id killer, boolean dueling) { //sendSystemMessageTestingOnly(player, "playerDeath: entering..."); if ( !isIdValid(player) || killer == null ) return false; if ( !isDead(player) ) { sendSystemMessageTestingOnly(killer, "apparently, " + getName(player) + " is still not dead"); return false; } if ( killer == obj_id.NULL_ID || player == killer ) { sendSystemMessage(player, SID_VICTIM_DEAD); } else { prose_package ppToVictim = prose.getPackage(PROSE_VICTIM_DEAD, killer); sendSystemMessageProse(player, ppToVictim); } float factionMod = 1.0f; if(!isPlayer(killer) && isMob(killer) && isIdValid(getMaster(killer))) { killer = getMaster(killer); } if( isPlayer(killer) && player != killer ) { if(utils.isProfession(killer, utils.BOUNTY_HUNTER) && isBeingHuntedByBountyHunter(player, killer)) { bounty_hunter.winBountyMission(killer, player); smuggler.checkSmugglerMissionBountyFailure(player, killer); } else if(utils.isProfession(player, utils.BOUNTY_HUNTER) && isBeingHuntedByBountyHunter(killer, player)) { bounty_hunter.loseBountyMission(player, killer); } else { if((getTotalMoney(player) >= bounty_hunter.MIN_BOUNTY_SET) && (!dueling) && (getLevel(killer) >= 20)) bounty_hunter.showSetBountySUI(player, killer); } pvp.incrementPlayerDeathBounty(killer, player); // update guild war kill tracking, if necessary if (isPlayer(player)) { guildUpdateGuildWarKillTracking(killer, player); } } // Award kill faction. factions.grantCombatFaction( killer, player, factionMod ); // Remove all dots from the slain player. dot.removeAllDots(player); //remove all hate from player clearAllHate(player); //playMusic(player, sound.PLAYER_DEATH_VICTIM); playMusic(player, "sound/music_player_death.snd"); //notify group of death, if necessary obj_id gid = getGroupObject(player); if ( isIdValid(gid) ) group.notifyDeath(gid, player); messageTo(player, HANDLER_PLAYER_DEATH, null, TIME_DEATH, true); //messageHandler in base_player dictionary params = new dictionary(); params.put("victim", player); messageTo(killer, "handleKillerDeathBlow", params, 1, false); return true; } void clearAllHate(obj_id self) { obj_id[] myHateList = getHateList(self); if (myHateList == null || myHateList.length == 0) return; for (int i=0;i 0) //{ // cloninglib.damageItemsOnClone(player, damage); //} // if we haven't been warped to our respawn point, explicitly call the clone respawn callback if ( !warped ) { sendSystemMessage(player, cloninglib.SID_RESPAWN_CURRENT_LOCATION); messageTo(player, HANDLER_CLONE_RESPAWN, null, 2, true); } return true; } /***************************************************************** * @brief attempts to equip the clone * * @param obj_id player *****************************************************************/ boolean equipClone(obj_id player) { if ( !isIdValid(player) ) { return false; } obj_id inv = utils.getInventoryContainer(player); if ( !isIdValid(inv) ) { return false; } obj_id[] items = utils.getFilteredPlayerContents(player); if ( (items != null) && (items.length > 0) ) { for ( int i = 0; i < items.length; i++ ) { int got = getGameObjectType(items[i]); if ( isGameObjectTypeOf(got, GOT_clothing) || isGameObjectTypeOf(got, GOT_armor) ) { equip(items[i], player); } } } return true; } /***************************************************************** * @brief autoinsures an item; * * @param obj_id player * @param obj_id item * * @return boolean; false on error ******************************************************************/ boolean autoInsureItem(obj_id item) { if ( !isIdValid(item) ) return false; return setAutoInsured(item); } boolean resurrectPlayer(obj_id target) { return resurrectPlayer(target, false); } boolean resurrectPlayer(obj_id target, boolean playCloneAnimation) { if ( !isIdValid(target) || !isPlayer(target) ) return false; int posture = getPosture(target); if ( posture == POSTURE_DEAD ) { clearEffectsForDeath(target); if ( utils.hasScriptVar(target, VAR_SUI_CLONE) ) { int suiClone = utils.getIntScriptVar(target, VAR_SUI_CLONE); if ( suiClone > -1 ) { sui.closeSUI(target, suiClone); } } utils.removeScriptVar(target, VAR_SUI_CLONE); utils.removeScriptVar(target, VAR_REVIVE_OPTIONS); trimLastKiller(target); pvpRemoveAllTempEnemyFlags(target); removeObjVar(target, VAR_BEEN_COUPDEGRACED); queueCommand(target, ##"stand", target, "", COMMAND_PRIORITY_IMMEDIATE); if (playCloneAnimation) playClientEffectObj(target, "clienteffect/player_clone_compile.cef", target, null); } healing.fullHealEveryone(target); setAttrib(target, HEALTH, getMaxAttrib(target, HEALTH)); setAttrib(target, ACTION, getMaxAttrib(target, ACTION)); dot.removeAllDots(target); return true; } boolean clearCombatData(obj_id target) { queueCommand(target, ##"stand", target, "", COMMAND_PRIORITY_IMMEDIATE); // Force combat to stop setCombatTarget(target, null); stopCombat(target); obj_id[] objEnemies = getHateList(target); for (int i = 0; i < objEnemies.length; i++) { if (!isIdValid(objEnemies[i]) || !exists(objEnemies[i])) continue; if (!isPlayer(objEnemies[i])) { if (isIdValid(objEnemies[i]) && exists(objEnemies[i]) && isIdValid(target) && exists(target)) { removeHateTarget(objEnemies[i], target); } } else { setCombatTarget(objEnemies[i], null); } } // Clear combat timers removeObjVar(target, "intBurstRunning"); removeObjVar(target, "combat.intLastBurstRunTime"); utils.removeScriptVar(target, "combat.intKnockdownTime"); utils.removeScriptVar(target, "combat.intPostureChangeTime"); utils.removeScriptVarTree(target, "combat.combatDelay"); // Clear innate timers removeObjVar(target, innate.VAR_ROAR); removeObjVar(target, innate.VAR_VITALIZE); removeObjVar(target, innate.VAR_EQUILIBRIUM); removeObjVar(target, innate.VAR_REGENERATION); // Remove all TEFs pvpRemoveAllTempEnemyFlags(target); return true; } boolean clearBuffData(obj_id target) { return buff.removeAllBuffs(target); } void trimLastKiller(obj_id self) { resizeable obj_id[] killers = utils.getResizeableObjIdBatchObjVar(self, VAR_CORPSE_KILLER); if ( killers != null && killers.length > 0 ) { killers = utils.removeElementAt(killers, killers.length - 1); //strip last entry.. not needed anymore } if ( killers == null || killers.length == 0 ) { removeObjVar(self, VAR_CORPSE_KILLER); } else { utils.setResizeableBatchObjVar(self, VAR_CORPSE_KILLER, killers); } } /***************************************************************** * @brief checks to see if a covert respawn is necessary * * @param obj_id player *****************************************************************/ boolean checkCovertRespawn(obj_id player) { if ( !isIdValid(player) ) { return false; } string pFac = factions.getFaction(player); if ( factions.isDeclared(player) && pFac != null && !pFac.equals("") ) { obj_id topMost = getTopMostContainer(player); if ( isIdValid(topMost) ) { if ( topMost == player ) //recloned outside for some reason! { covertRespawn(player, "outside"); } else //must be inside something { string sFac = factions.getFaction(topMost); if ( sFac == null || sFac.equals("") || !sFac.equals(pFac) ) { covertRespawn(player, sFac); } } } } return false; } /***************************************************************** * @brief checks to see if a covert respawn is necessary * * @param obj_id player *****************************************************************/ void covertRespawn(obj_id player, string faction) { if ( !isIdValid(player) ) return; // IF you die on the Corellian Corvette, you don't get set to Covert if (hasScript (player, "theme_park.dungeon.corvette.timer") || getLocation(player).area.equals("adventure2")) { return; } pvpMakeCovert(player); removeObjVar(player, "travelingCovert"); if ( faction == null || faction.equals("") ) { sendSystemMessage(player, SID_COVERT_RESPAWN_UNALIGNED); } else if ( faction.equals("outside") ) { sendSystemMessage(player, SID_COVERT_RESPAWN_OUTSIDE); } else { sendSystemMessage(player, SID_COVERT_RESPAWN_UNFRIENDLY); } } /***************************************************************** * @brief destroys all of a player's equipped items. Mainly used for Jedi endgame. * * @param obj_id player *****************************************************************/ void destroyPlayerEquipment(obj_id player) { if ( !isIdValid(player) ) return; // we need to know if the player is Trandoshan, since we don't remove their shoes(feet) boolean isTrandoshan = isSpecies(player, SPECIES_TRANDOSHAN); for ( int i = 0; i < slots.EQ_SLOTS.length; ++i ) { // don't remove Trandoshan feet if ( isTrandoshan && slots.EQ_SLOTS[i] == slots.SHOES ) continue; obj_id object = getObjectInSlot(player, slots.EQ_SLOTS[i]); if ( isIdValid(object) ) { destroyObject(object); } } } /***************************************************************** * @brief destroys all of a player's inventory. Mainly used for Jedi endgame. * * @param obj_id player *****************************************************************/ void destroyPlayerInventory(obj_id player) { if ( !isIdValid(player) ) return; obj_id inventory = getObjectInSlot(player, utils.SLOT_INVENTORY); if ( !isIdValid(inventory) ) return; obj_id[] contents = getContents(inventory); if ( contents == null ) return; for ( int i = 0; i < contents.length; ++i ) { if ( isIdValid(contents[i]) ) destroyObject(contents[i]); } } /***************************************************************** * @brief destroys all of a player's inventory. Mainly used for Jedi endgame. * * @param obj_id player *****************************************************************/ void destroyPlayerBank(obj_id player) { if ( !isIdValid(player) ) return; obj_id inventory = getObjectInSlot(player, utils.SLOT_BANK); if ( !isIdValid(inventory) ) return; obj_id[] contents = getContents(inventory); if ( contents == null ) return; for ( int i = 0; i < contents.length; ++i ) { if ( isIdValid(contents[i]) ) destroyObject(contents[i]); } } void damageAndDecayItem(obj_id item, float percent) { // Damage & Decay removed with clicky-combat /* if (!isIdValid(item) || percent <= 0f) return; int max = getMaxHitpoints(item); int damage = Math.round(max * percent); damageAndDecayItem(item, damage); */ } void damageAndDecayItem(obj_id item, int amount) { // Damage & Decay removed with clicky-combat /* if (!isIdValid(item) || amount <= 0) return; // Damage the item int current = getHitpoints(item); int newHitpoints = current - amount; if (newHitpoints < 0) newHitpoints = 0; setInvulnerableHitpoints(item, newHitpoints); // item has been marked to not decay via the Veteran Reward Anti-Decay Kit if ( utils.isAntiDecay(item) ) return; //item is a static loot item if ( loot.isStaticItem(item) ) return; // Decay the item float decay = amount * DECAY_RATE; if (hasObjVar(item, DECAY_REMAINDER)) { decay += getFloatObjVar(item, DECAY_REMAINDER); } if (decay >= 1f) { int max = getMaxHitpoints(item); int damage = (int)decay; int newMax = max - damage; if (newMax < 0) newMax = 0; setMaxHitpoints(item, newMax); decay -= damage; } setObjVar(item, DECAY_REMAINDER, decay); */ } boolean sendToCloneSpawn(obj_id player, string callback, location world, location spawn) { ////debugSpeakMsg(player, "(sendToAnyLocation) w=" + world + " i=" + interior); if ( (player == null) || (world == null) || (!isPlayer(player)) ) return false; // we need to do a full warp so we can load the area we are moving to if ( spawn == null ) { // send to world location warpPlayer(player, world.area, world.x, world.y, world.z, null, world.x, world.y, world.z, callback); } else if ( spawn.cell == null || spawn.cell == obj_id.NULL_ID ) { // send to exterior world location warpPlayer(player, spawn.area, spawn.x, spawn.y, spawn.z, null, spawn.x, spawn.y, spawn.z, callback); } else { // send to interior location warpPlayer(player, world.area, world.x, world.y, world.z, spawn.cell, spawn.x, spawn.y, spawn.z, callback); } return true; } /***************************************************************** * @brief sends a player to any location * * @param obj_id player * @param location world the approximate world location to send the player to * @param location interior if the player is being sent to the interior, the cell and local position to go to * * @return boolean; false on error *****************************************************************/ boolean sendToAnyLocation(obj_id player, location world, location interior) { ////debugSpeakMsg(player, "(sendToAnyLocation) w=" + world + " i=" + interior); if ( (player == null) || (world == null) || (!isPlayer(player)) ) return false; // we need to do a full warp so we can load the area we are moving to if ( interior == null || interior.cell == null || interior.cell == obj_id.NULL_ID ) { // send to world location warpPlayer(player, world.area, world.x, world.y, world.z, null, world.x, world.y, world.z); } else { // send to interior location warpPlayer(player, world.area, world.x, world.y, world.z, interior.cell, interior.x, interior.y, interior.z); } return true; } /***************************************************************** * @brief sends a player to any location * * @param obj_id player * @param string callback messageHandler that will get called when the player arrives * @param location world the approximate world location to send the player to * @param location interior if the player is being sent to the interior, the cell and local position to go to * * @return boolean; false on error *****************************************************************/ boolean sendToAnyLocation(obj_id player, string callback, location world, location interior) { ////debugSpeakMsg(player, "(sendToAnyLocation) w=" + world + " i=" + interior); if ( (player == null) || (world == null) || (!isPlayer(player)) ) return false; utils.setScriptVar(player, "waitingOnCloneRespawn", 1); // we need to do a full warp so we can load the area we are moving to if ( interior == null || interior.cell == null || interior.cell == obj_id.NULL_ID ) { // send to world location warpPlayer(player, world.area, world.x, world.y, world.z, null, world.x, world.y, world.z, callback); } else { // send to interior location warpPlayer(player, world.area, world.x, world.y, world.z, interior.cell, interior.x, interior.y, interior.z, callback); } return true; } /***************************************************************** * @brief sends a player to any location * * @param obj_id player * @param location world the approximate world location to send the player to * @param location interior if the player is being sent to the interior, the local position to go to * @param string interiorCell if the player is being sent to the interior, the cell name to go to * * @return boolean; false on error *****************************************************************/ boolean sendToAnyLocation(obj_id player, location world, location interior, string interiorCell) { ////debugSpeakMsg(player, "(sendToAnyLocation2) w=" + world + " i=" + interior + " c=" + interiorCell); if ( (player == null) || (world == null) || (!isPlayer(player)) ) return false; // we need to do a full warp so we can load the area we are moving to if ( interior == null || interiorCell == null ) { // send to world location warpPlayer(player, world.area, world.x, world.y, world.z, null, world.x, world.y, world.z); } else { // send to interior location warpPlayer(player, world.area, world.x, world.y, world.z, interior.cell, interiorCell, interior.x, interior.y, interior.z); } return true; } /***************************************************************** * @brief sends a player to any location * * @param obj_id player * @param string callback messageHandler that will get called when the player arrives * @param location world the approximate world location to send the player to * @param location interior if the player is being sent to the interior, the local position to go to * @param string interiorCell if the player is being sent to the interior, the cell name to go to * * @return boolean; false on error *****************************************************************/ boolean sendToAnyLocation(obj_id player, string callback, location world, location interior, string interiorCell) { ////debugSpeakMsg(player, "(sendToAnyLocation2) w=" + world + " i=" + interior + " c=" + interiorCell); if ( (player == null) || (world == null) || (!isPlayer(player)) ) return false; utils.setScriptVar(player, "waitingOnCloneRespawn", 1); // we need to do a full warp so we can load the area we are moving to if ( interior == null || interiorCell == null ) { // send to world location warpPlayer(player, world.area, world.x, world.y, world.z, null, world.x, world.y, world.z, callback); } else { // send to interior location warpPlayer(player, world.area, world.x, world.y, world.z, interior.cell, interiorCell, interior.x, interior.y, interior.z, callback); } return true; } boolean clearEffectsForDeath(obj_id player) { if ( !isIdValid(player) ) { return false; } // Remove all dots from the slain player. dot.removeAllDots(player); removeAllAttribModifiers(player); // Clear medical buff data for (int i = 0; i < NUM_ATTRIBUTES; i++) { string objvarName = "healing." + healing.attributeToString(i).toLowerCase() + "_enhance"; if (hasObjVar(player, objvarName)) removeObjVar(player, objvarName); if (utils.hasScriptVar(player, objvarName)) utils.removeScriptVar(player, objvarName); } // Clear spice data removeObjVar(player, "spice"); utils.setScriptVar(player, "numPukes", 100 ); detachScript(player, "player.player_spice" ); if ( hasObjVar(player, meditation.VAR_POWERBOOST_ACTIVE) ) removeObjVar(player, meditation.VAR_POWERBOOST_ACTIVE); setPosture(player, POSTURE_INCAPACITATED); return true; } /***************************************************************** * @brief determines if an an item is insurable * * @param obj_id player * @param obj_id item * * @return boolean; false on error ******************************************************************/ boolean isContainedByPlayer(obj_id player, obj_id item) { if ( (player == null) || (item == null) ) { return false; } resizeable obj_id[] containers = new obj_id[0]; obj_id c = getContainedBy(item); if ( (c == obj_id.NULL_ID) || (c == null) ) { return false; } while ( (c != obj_id.NULL_ID) && (c != null) ) { containers = utils.addElement(containers, c); c = getContainedBy(c); } if ( utils.getElementPositionInArray(containers, player) > -1 ) { return true; } return false; } /***** MESSAGING FUNCTIONS *********************************************/ /***************************************************************** * @brief sends a guaranteed message to a player to handle script attachment * * @param obj_id player * @param string scriptName * * @return boolean; false on error ******************************************************************/ boolean msgAttachScript(obj_id player, string scriptName) { if ( (player == null) || (scriptName.equals("")) ) { return false; } dictionary params = new dictionary(); params.put(DICT_SCRIPT_NAME, scriptName); return messageTo(player, HANDLER_ATTACH_SCRIPT, params, 0, true); } /***************************************************************** * @brief sends a guaranteed message to a player to handle script detachment * * @param obj_id player * @param string scriptName * * @return boolean; false on error ******************************************************************/ boolean msgDetachScript(obj_id player, string scriptName) { if ( (player == null) || (scriptName.equals("")) ) { return false; } dictionary params = new dictionary(); params.put(DICT_SCRIPT_NAME, scriptName); return messageTo(player, HANDLER_DETACH_SCRIPT, params, 0, true); } /***************************************************************** * @brief sends a guaranteed message to a player to handle removing objvars * * @param obj_id player * @param string objVarName * * @return boolean; false on error ******************************************************************/ boolean msgRemoveObjVar(obj_id player, string objVarName) { if ( (player == null) || (objVarName.equals("")) ) { return false; } dictionary params = new dictionary(); params.put(DICT_OBJVAR_NAME, objVarName); return messageTo(player, HANDLER_REMOVE_OBJVAR, params, 0, true); } /***************************************************************** * @brief sends a guaranteed message to a player to handle remote XP granting * * @param obj_id player * @param string objVarName * * @return boolean; false on error ******************************************************************/ boolean msgGrantXP(obj_id player, string xpType, int xpAmount) { if ( (player == null) || (xpType.equals("")) ) { return false; } dictionary params = new dictionary(); params.put(DICT_XP_TYPE, xpType); params.put(DICT_XP_AMOUNT, xpAmount); return messageTo(player, HANDLER_GRANT_XP, params, 0, true); } /***** NOTIFY GM OF ERRORS FUNCTIONS *******************************/ /***************************************************************** * @brief notifies the GM channel that there is a problem with a character * * @param obj_id player * @param int nc (notify code) * * @return boolean; false on error ******************************************************************/ boolean notifyGM(obj_id player, int nc) { if ( player == null ) { return false; } switch (nc) { case NC_DEATH: sendSystemMessagePlanetTestingOnly("DEATH-related error for player " + getName(player) + " (" + player + "). Please alert a GM on their behalf."); break; default: sendSystemMessagePlanetTestingOnly("Unknown error for player " + getName(player) + " (" + player + "). Please alert a GM on their behalf."); break; } return true; } void requestWaypointDestroy(obj_id target, obj_id wp) { if ( !isIdValid(target) || !isIdValid(wp) ) return; dictionary params = new dictionary(); params.put("wp", wp); messageTo(target, "handleWaypointDestroyRequest", params, 1f, true); } void requestWaypointRename(obj_id target, obj_id wp, string name) { if ( !isIdValid(target) || !isIdValid(wp) || name == null || name.equals("") ) return; dictionary params = new dictionary(); params.put("wp", wp); params.put("name", name); messageTo(target, "handleWaypointRenameRequest", params, 1f, true); } void requestWaypointRename(obj_id target, obj_id wp, string_id sid_name) { if ( !isIdValid(target) || !isIdValid(wp) || sid_name == null ) return; string name = utils.packStringId(sid_name); requestWaypointRename(target, wp, name); } ////////////////////////////////////////////////////////////////////////////////// // Support functions for creating the Interplanetary Survey Droid survey report ////////////////////////////////////////////////////////////////////////////////// string[] buildSortedResourceList(obj_id[] resources, string resourceClass, int branchLevel) { resizeable string[] resourceList = new string[0]; for (int i = 0; i < resources.length; i++) { if (!isResourceDerivedFrom(resources[i], resourceClass)) continue; string parent = getResourceClass(resources[i]); string child = null; if (parent == null) continue; while (parent != resourceClass) { child = parent; parent = getResourceParentClass(child); } if (child == null) child = "\\#pcontrast1 "+getResourceName(resources[i])+"\\#."; for (int j = 0; j < branchLevel; j++) { child = " " + child; } if (resourceList.indexOf(child) == -1) { resourceList.add(child); } } for (int i = 0; i < resourceList.size(); i++) { string parent = resourceList[i].trim(); string[] childBranch = buildSortedResourceList(resources, parent, branchLevel+1); for (int j = 0; j < childBranch.length; j++) { resourceList.add(++i, childBranch[j]); } } return resourceList; } string createResourcePlanetReport(string[] resourceList, string planet, string resourceClass) { string report = "Incoming planetary survey report...\n\n"+ "\\#pcontrast3 Planet: \\#pcontrast1 "+toUpper(planet, 0)+"\n"+ "\\#pcontrast3 Resource Class: \\#pcontrast1 "+getClassString(resourceClass)+"\n\n"+ "\\#pcontrast3 Resources located...\\#.\n\n"; for (int i = 0; i < resourceList.length; i++) { string resourceName = resourceList[i].trim(); if (resourceName.startsWith("\\#")) resourceName = resourceName.substring(13, resourceName.length()-3); obj_id resourceId = getResourceTypeByName(resourceName); if (resourceId == null) { report += " "+getTab(resourceList[i])+getClassString(resourceName)+"\n"; } else { report += " "+resourceList[i]+"\n"; } } report += "\n\n"; return report; } string getClassString(string className) { const string resourceTable = "datatables/resource/resource_tree.iff"; string classString = ""; int row = dataTableSearchColumnForString(className, 1, resourceTable); int column = 2; while ((classString == null || classString.length() == 0) && column <= 9) { classString = dataTableGetString(resourceTable, row, column); column++; } return classString; } string getTab(string str) { string tab = ""; int idx = 0; while (str.charAt(idx) == ' ') { tab += " "; idx++; } return tab; }