mirror of
https://bitbucket.org/seefoe/dsrc.git
synced 2026-07-31 01:15:55 -04:00
2171 lines
64 KiB
Plaintext
2171 lines
64 KiB
Plaintext
/**********************************************************************
|
|
* 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<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;
|
|
}
|
|
|