Files
dsrc/sku.0/sys.server/compiled/game/script/library/pclib.scriptlib
T
2013-09-10 23:17:15 -07:00

2176 lines
64 KiB
Plaintext

/**********************************************************************
* Copyright (c)2000-2002 Sony Online Entertainment Inc.
* All Rights Reserved
*
* Title: scriptlib
* Description: base player script library
* @author $Author:$
* @version $Revision:$
**********************************************************************/
/***** 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<myHateList.length;i++)
{
removeHateTarget(self, myHateList[i]);
removeHateTarget(myHateList[i], self);
}
}
/*****************************************************************
* @brief handles player respawn after death
*
* @param obj_id player
* @param boolean insured
* @param boolean closest
*
* @return boolean; false on error
*****************************************************************/
boolean playerRevive(obj_id player)
{
return playerRevive(player, getWorldLocation(player), getLocation(player), 0);
}
/*****************************************************************
* @brief handles player respawn after death
*
* @param obj_id player
* @param boolean insured
* @param boolean closest
*
* @return boolean; false on error
*****************************************************************/
boolean playerRevive(obj_id player, location reviveLoc, location spawnLoc, int damage)
{
if ( !isIdValid(player) )
return false;
if ( !isDead(player) )
{
LOG("playerRevive", "playerRevive: player is not dead!");
return false;
}
if (reviveLoc == null || spawnLoc == null)
return false;
setObjVar(player, "fullHealClone", true);
boolean warped = sendToCloneSpawn(player, HANDLER_CLONE_RESPAWN, reviveLoc, spawnLoc);
//if (damage > 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;
}