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

5712 lines
168 KiB
Plaintext

/********************************************************************************************************************************************
* Copyright (c)2000-2002 Sony Online Entertainment Inc.
* All Rights Reserved
*
* Title: force_rank.scriptlib
* Description: Support functions for the Force Ranking System
* @author $Author:$
* @version $Revision:$
**********************************************************************/
/***** INCLUDES ********************************************************/
include library.skill;
include library.xp;
include library.utils;
include library.prose;
include library.pvp;
include library.trace;
include library.player_structure;
include java.lang.Math;
/***** CONSTANTS *******************************************************/
// System constants
const string FRS_DATATABLE = "datatables/pvp/force_rank.iff";
const string FRS_DARK_DATATABLE = "datatables/pvp/force_rank_dark.iff";
const string JEDI_TERMINAL_DATATABLE = "datatables/pvp/jedi_enclave_terminals.iff";
const string ENCLAVE_REWARDS_DATATABLE = "datatables/pvp/enclave_rewards.iff";
const string FRS_XP = "force_rank_xp";
const string STF_FILE = "force_rank";
const string CLUSTER_DATA_NAME = "jedi_frs";
const int PVP_BOARD_SIZE = 25;
const int UPDATE_INTERVAL = 900;
const int BACK_UP_INTERVAL = 172800;
const int MAX_RANK_SLOTS = 20;
const int PETITION_INTERVAL = 86400; // 86400
const int VOTING_INTERVAL = 86400; // 86400
const int ACCEPTANCE_INTERVAL = 86400; // 86400
const int MAX_PETITIONERS = 11;
const int MISSED_VOTE_PENALTY = 100;
const int REQUEST_DEMOTION_DURATION = 604800; // 604800;
const int REQUEST_DEMOTION_COST = 2500;
const int MAINTENANCE_PULSE = 1200; // 1200
const int BASE_XP_MAINTENANCE = 100;
const int XP_MAINTENANCE_INTERVAL = 86400; // 86400;
const int VOTE_CHALLENGE_COST = 2000;
const int VOTE_CHALLENGE_DURATION = 604800;
const int MAX_CHAL_LIST_SIZE = 20;
const int DEBUFF_DURATION = 120;
const string EMPTY_SLOT = "Open Seat";
const string SCRIPT_DATA_HANDLER = "systems.gcw.enclave_data_handler";
const string SCRIPT_FRS_PLAYER = "systems.gcw.player_force_rank";
const string SCRIPT_ENCLAVE_CONTROLLER = "systems.gcw.enclave_controller";
const string JEDI_ROOM_PERMISSIONS_TABLE = "datatables/pvp/jedi_enclave_room_permissions.iff";
const string DATA_COLUMN_COMMUNITY_CELLS = "_community_cells";
const boolean DEBUGGING = false;
// Councils
const int TEST_COUNCIL = 0;
const int DARK_COUNCIL = 1;
const int LIGHT_COUNCIL = 2;
const string[] COUNCIL_NAMES = {"Test Enclave", "Dark Enclave", "Light Enclave"};
// Player ObjVars
const string VAR_RATING = "force_rank.rating";
const string VAR_RANK = "force_rank.rank";
const string VAR_COUNCIL = "force_rank.council";
const string VAR_REQUEST_DEMOTE = "force_rank.request_demote";
const string VAR_VOTE_CHALLENGE = "force_rank.vote_challenge";
const string SCRIPT_VAR_DATA_REQUEST = "force_rank.data_request";
const string SCRIPT_VAR_PARAMS_REQUEST = "force_rank.rank_request";
const string SCRIPT_VAR_HANDLER_REQUEST = "force_rank.handler_request";
const string SCRIPT_VAR_SKILL_RESYNC = "force_rank.script_resync";
const string SCRIPT_VAR_REVALIDATE = "force_rank.revalidate";
// Voting Terminals
const string BATCH_VAR_VOTERS = "force_rank.voters_rank";
// Enclave ObjVars
const string VAR_RANK11 = "force_rank.roster.rank11";
const string VAR_RANK10 = "force_rank.roster.rank10";
const string VAR_RANK9 = "force_rank.roster.rank9";
const string VAR_RANK8 = "force_rank.roster.rank8";
const string VAR_RANK7 = "force_rank.roster.rank7";
const string VAR_RANK6 = "force_rank.roster.rank6";
const string VAR_RANK5 = "force_rank.roster.rank5";
const string VAR_RANK4 = "force_rank.roster.rank4";
const string VAR_RANK3 = "force_rank.roster.rank3";
const string VAR_RANK2 = "force_rank.roster.rank2";
const string VAR_RANK1 = "force_rank.roster.rank1";
const string VAR_RANK_BASE = "force_rank.roster.rank";
const string VAR_VOTING_BASE = "force_rank.voting.rank";
const string VAR_CHAL_VOTING_BASE = "force_rank.chal_voting";
const string VAR_MEMBER_DATA = "force_rank.data.";
const string VAR_BACKUP_TIME = "force_rank.backup_time";
const string STRING_CLUSTER_ENCLAVE_NAME = "enclave_";
const string BATCH_VAR_PVPBOARD_NAME = "force_rank.stats.pvpboard_name";
const string BATCH_VAR_PVPBOARD_RATING = "force_rank.stats.pvpboard_rating";
const string VAR_ENCLAVE = "force_rank.enclave"; // Cluster data only
const string VAR_XP_MAINTENANCE = "force_rank.xp_maintenance";
const int COUNCIL_RANK_NUMBER = 10;
const string SCRIPT_VAR_VOTE_TERMINAL = "force_rank.vote_terminal";
const string SCRIPT_VAR_CHAL_VOTE_TERMINAL = "force_rank.chal_vote_terminal";
const string ACTION_VENDETTA = "force_rank.vendettas";
const int ACTION_VENDETTA_DURATION = 604800;
const string ACTION_BANISHMENT = "force_rank.banishments";
const int ACTION_BANISHMENT_DURATION = 604800;
const string ACTION_PURGE_COUNCIL = "force_rank.councilPurges";
const int ACTION_PURGE_COUNCIL_DURATION = 604800;
const string ACTION_CANDIDATE_SUDDEN_DEATH = "force_rank.candidateSuddenDeath";
const int ACTION_CANDIATE_SUDDEN_DEATH_DURATION = 604800;
const string VAR_INITIATORS = ".initiators";
const string VAR_VICTIMS = ".victims";
const string VAR_START_TIMESTAMPS = ".timestamps";
const string VAR_NOTIFY_ENCLAVE_OF_DEATH = "force_rank.notifyEnclaveOfDeath"; // found on the player if the enclave needs to be notified when they die
const string VAR_MY_ENCLAVE_ID = "force_rank.myEnclaveId";
const float MIN_KILL_CONTRIB_FOR_ACTION_DEATH = .51f; // the minimum percent contribution that a dark jedi must have against another dark jedi death in order for the PVP ACTION to be considered "fulfilled".
/***** TRIGGERS ********************************************************/
/***** MESSAGEHANDLERS *************************************************/
/***** COMMANDHANDLERS *************************************************/
/***** FUNCTIONS *******************************************************/
/***********************************************************************
* @brief Initiates the player into the FRS
*
* @param obj_id player
* @param int faction_id
*
* @return boolean returns true if successful
***********************************************************************/
boolean addToForceRankSystem(obj_id player, int council)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.addToForceRankSystem -- player is invalid.");
return false;
}
if (council != LIGHT_COUNCIL && council != DARK_COUNCIL)
{
LOG("force_rank", "force_rank.addToForceRankSystem -- " + player + " has an invalid council value of " + council);
return false;
}
string rank_skill = getForceRankSkill(0, council);
if (rank_skill == null)
{
LOG("force_rank", "force_rank.addToForceRankSystem -- rank_skill is null for rank 0.");
return false;
}
setObjVar(player, VAR_RANK, 0);
setObjVar(player, VAR_COUNCIL, council);
// FRS Jedi are always overt.
if (council == LIGHT_COUNCIL)
{
setJediState(player, JEDI_STATE_FORCE_RANKED_LIGHT);
pvpSetAlignedFaction(player, getFactionId("Rebel"));
}
else
{
setJediState(player, JEDI_STATE_FORCE_RANKED_DARK);
pvpSetAlignedFaction(player, getFactionId("Imperial"));
}
pvpMakeDeclared(player);
grantSkill(player, rank_skill);
prose_package pp = prose.getPackage(new string_id(STF_FILE, "council_joined"), getCouncilName(council), 0);
sendSystemMessageProse(player, pp);
if (!hasScript(player, SCRIPT_FRS_PLAYER))
attachScript(player, SCRIPT_FRS_PLAYER);
// Set up the enclave obj_id
getEnclaveObjId(player, council, "enclaveIdResponse");
// Check for new items to grant
force_rank.grantRankItems(player);
return true;
}
/***********************************************************************
* @brief Removes the player from the FRS. The player must
* already be at FRS 0. Use fullDemotePlayer to do this.
*
* @param obj_id player
* @param boolean surrendered whether or not the player initiated
* the removal by surrendering the novice skill
*
* @return boolean returns true if successful
***********************************************************************/
boolean removeFromForceRankSystem(obj_id player, boolean surrendered)
{
LOG("force_rank", "force_rank.removeFromForceRankSystem");
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.removeFromForceRankSystem -- player is invalid.");
return false;
}
int council = getCouncilAffiliation(player);
if (council == -1)
{
LOG("force_rank", "force_rank.removeFromForceRankSystem -- " + player + " has an invalid council affiliation.");
return false;
}
if (getForceRank(player) > 0)
{
LOG("force_rank", "force_rank.removeFromForceRankSystem -- " + player + " has a force rank > 0.");
return false;
}
// Remove the skills
//string skill = force_rank.getForceRankSkill(0, council);
//if (skill != null)
//{
//
// revokeSkill(player, skill);
//}
if (!surrendered)
force_rank.removeForceRankSkills(player, -1);
//LOG("force_rank", "force_rank.removeFromForceRankSystem --- 1111");
// Remove the data.
removeObjVar(player, "force_rank");
if (hasScript(player, SCRIPT_FRS_PLAYER))
detachScript(player, SCRIPT_FRS_PLAYER);
//LOG("force_rank", "force_rank.removeFromForceRankSystem --- 2222");
prose_package pp = prose.getPackage(new string_id(STF_FILE, "council_left"), getCouncilName(council), 0);
sendSystemMessageProse(player, pp);
return true;
}
/***********************************************************************
* @brief Grants or removes FRS experience
*
* @param obj_id player
* @param int amount
*
* @return int returns the new xp total, -1 on error
***********************************************************************/
int adjustForceRankXP(obj_id player, int amt)
{
LOG("force_rank", "force_rank.adjustForceRankXP -- player ->" + player + " amt ->" + amt);
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.grantForceRankXP -- player is invalid.");
return -1;
}
if (amt == 0)
return getExperiencePoints(player, FRS_XP);
else if (amt > 0)
{
grantExperiencePoints(player, FRS_XP, amt);
prose_package pp = prose.getPackage(new string_id(STF_FILE, "experience_granted"), amt);
sendSystemMessageProse(player, pp);
}
else
{
int current_xp = getExperiencePoints(player, FRS_XP);
// Cannot go to negative xp.
if (amt * -1 > current_xp)
amt = current_xp * -1;
LOG("force_rank", "force_rank.adjustForceRankXP -- current_xp ->" + current_xp + " final amt ->" + amt);
grantExperiencePoints(player, FRS_XP, amt);
prose_package pp = prose.getPackage(new string_id(STF_FILE, "experience_lost"), amt * -1);
sendSystemMessageProse(player, pp);
// Check to see if this loss of xp drops the player down a rank. We only drop
// one rank max at a time.
current_xp += amt;
int rank = getForceRank(player);
int min_xp = getForceRankMinXp(rank);
LOG("force_rank", "rank ->" + rank + " min_xp ->" + min_xp + " current_xp ->" + current_xp);
if (min_xp > current_xp)
demoteForceRank(player, rank - 1);
}
return getExperiencePoints(player, FRS_XP);
}
/***********************************************************************
* @brief adds to the experience debt of a player. This should
* only be used to impose experience penalties when the player
* is off-line. Otherwise, use adjustForceRankXP.
*
* @param obj_id enclave
* @param string player_name
* @param int xp_debt
*
* @return boolean
***********************************************************************/
boolean addExperienceDebt(obj_id enclave, string player_name, int xp_debt)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.addExperienceDebt -- enclave is invalid.");
return false;
}
if (player_name == null)
{
LOG("force_rank", "force_rank.addExperienceDebt -- player_name is null.");
return false;
}
if (xp_debt < 1)
{
LOG("force_rank", "force_rank.addExperienceDebt -- illegal value for xp_debt: " + xp_debt);
return false;
}
// Check to see if the player is in the force ranks.
boolean in_rank = false;
for (int i = 1; i < 12; i++)
{
resizeable string[] rank_list = getPlayersInForceRankResizeable(enclave, i);
if (rank_list != null)
{
if (rank_list.indexOf(player_name) != -1)
{
in_rank = true;
break;
}
}
}
if (in_rank)
{
string obj_var_name = VAR_MEMBER_DATA + player_name + ".xp_debt";
int current_debt = 0;
if (hasObjVar(enclave, obj_var_name))
current_debt = getIntObjVar(enclave, obj_var_name);
current_debt += xp_debt;
setObjVar(enclave, obj_var_name, current_debt);
return true;
}
else
{
LOG("force_rank", "force_rank.addExperienceDebt -- " + player_name + " is not in the force rank list.");
return false;
}
}
/***********************************************************************
* @brief Spends FRS experience. Does not let the experience total
* go below the minimum for the rank.
*
* @param obj_id player
*
* @return int returns the new xp total, -1 on error
***********************************************************************/
int spendForceRankXP(obj_id player, int amt)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.spendForceRankXP -- player is invalid.");
return -1;
}
if (amt < 0)
{
LOG("force_rank", "force_rank.spendForceRankXP -- illegal amount value: " + amt);
return -1;
}
int current_xp = getExperiencePoints(player, FRS_XP);
int min_xp = getForceRankMinXp(getForceRank(player));
LOG("force_rank", "current_xp ->" + current_xp + " min_xp ->" + min_xp);
if (current_xp - amt < min_xp)
return -1;
else
{
adjustForceRankXP(player, amt * -1);
return getExperiencePoints(player, FRS_XP);
}
}
/***********************************************************************
* @brief Promotes the target within the FRS. Requires the player
* to be authoritative.
*
* @param obj_id player
*
* @return boolean result handler is in msgForceRankPromoted
***********************************************************************/
boolean promoteForceRank(obj_id player)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.promoteForceRank -- player is invalid.");
return false;
}
int council = getCouncilAffiliation(player);
if (council == -1)
{
LOG("force_rank", "force_rank.promoteForceRank -- " + player + " has an invalid council value.");
return false;
}
int current_rank = getForceRank(player);
if (current_rank < 0 || current_rank > 10)
{
LOG("force_rank", "force_rank.promoteForceRank -- attempting to promote " + player + " when his rank is at " + current_rank);
return false;
}
string rank_skill = getForceRankSkill(current_rank + 1, council);
if (rank_skill == null)
{
LOG("force_rank", "force_rank.promoteForceRank -- rank_skill is null for rank " + (current_rank + 1));
return false;
}
_updateForceRankData(player, council, 3, Integer.toString(current_rank), "msgForceRankPromotePlayer", true);
return true;
}
/***********************************************************************
* @brief Demotes the player within the FRS. Requires the player to
* be authoritative.
*
* @param obj_id player
* @param int rank rank to which to demote.
*
* @return boolean
***********************************************************************/
boolean demoteForceRank(obj_id player, int rank)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.demoteForceRank -- player is invalid.");
return false;
}
if (rank < 0 || rank > 10)
{
LOG("force_rank", "force_rank.demoteForceRank -- illegal rank value: " + rank);
return false;
}
int council = getCouncilAffiliation(player);
if (council == -1)
{
LOG("force_rank", "force_rank.demoteForceRank -- " + player + " has an invalid council value.");
return false;
}
int current_rank = getForceRank(player);
if (current_rank < 1 || current_rank > 11)
{
LOG("force_rank", "force_rank.demoteForceRank -- attempting to demote " + player + " when his rank is at " + current_rank);
return false;
}
//LOG("force_rank", "current ->" + current_rank + " rank ->" + rank);
if (rank >= current_rank)
{
LOG("force_rank", "force_rank.demoteForceRank -- attempting to demote " + player + " to a rank that is greater than or equal to his current rank.");
return false;
}
_updateForceRankData(player, council, 4, Integer.toString(rank), "msgForceRankDemotePlayer", true);
return true;
}
/***********************************************************************
* @brief Demotes the player within the FRS. Requires the enclave
* to be authoritative
*
* @param obj_id enclave
* @param string player_name
* @param int rank rank to which to demote
*
* @return boolean
***********************************************************************/
boolean demoteForceRank(obj_id enclave, string player_name, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.demoteForceRank -- enclave is invalid.");
return false;
}
if (player_name == null)
{
LOG("force_rank", "force_rank.demoteForceRank -- player_name is null.");
return false;
}
int council = getCouncilAffiliation(enclave);
if (council == -1)
{
LOG("force_rank", "force_rank.demoteForceRank -- " + enclave + " has an invalid council value.");
return false;
}
_updateForceRankData(enclave, council, 5, player_name + " " + rank, "msgForceRankDemotePlayer", true);
return true;
}
/***********************************************************************
* @brief Removes all cluster data for the enclave and replaces
* it from the current enclave data.
*
* @param obj_id enclave
*
* @return boolean
***********************************************************************/
boolean resetClusterData(obj_id enclave)
{
LOG("force_rank", "force_rank.resetClusterData");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.resetClusterData -- enclave is invalid.");
return false;
}
int council = getCouncilAffiliation(enclave);
if (council == -1)
{
LOG("force_rank", "force_rank.resetClusterData -- " + enclave + " has an invalid council value.");
return false;
}
_updateForceRankData(enclave, council, 8, "", "msgFRSUpdateClusterData", true);
return true;
}
/***********************************************************************
* @brief Changes the name entry specified to the player's current
* name. This should be called after a successful player
* rename.
*
* @param obj_id player
* @param string old_name The player's old name.
*
* @return boolean
***********************************************************************/
boolean renameRankMember(obj_id player, string old_name)
{
if (old_name == null)
{
LOG("force_rank", "force_rank.renameRankMember -- old_name is null.");
return false;
}
int council = getCouncilAffiliation(player);
if (council == -1)
{
LOG("force_rank", "force_rank.renameRankMember -- " + player + " has an invalid council value.");
return false;
}
int current_rank = getForceRank(player);
if (current_rank < 1 || current_rank > 11)
{
LOG("force_rank", "force_rank.renameRankMember -- attempting to demote " + player + " when his rank is at " + current_rank);
return false;
}
_updateForceRankData(player, council, 9, old_name, "msgForceRankRenamePlayer", true);
return true;
}
/***********************************************************************
* @brief Removes a player's skills down to the specified rank.
*
* @param obj_id player
* @param int rank -1 for all skills
*
* @return boolean
***********************************************************************/
boolean removeForceRankSkills(obj_id player, int rank)
{
LOG("force_rank", "force_rank.removeForceRankSkills");
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.removeForceRankSkills -- player is invalid.");
return false;
}
if (rank < -1 || rank > 10)
{
LOG("force_rank", "force_rank.removeForceRankSkills -- invalid value for rank: " + rank);
return false;
}
int current_rank = getForceRank(player);
if (current_rank < 0)
{
LOG("force_rank", "force_rank.removeForceRankSkills -- can't remove skills from a player with a rank of " + current_rank);
return false;
}
int council = getCouncilAffiliation(player);
if (council < 1)
{
LOG("force_rank", "force_rank.removeForceRankSkills -- " + player + " has an invalid council affiliation.");
return false;
}
// set script var to prevent firing the skill revoke trigger for voluntary skill surrendering.
utils.setScriptVar(player, SCRIPT_VAR_SKILL_RESYNC, 1);
for (int i = current_rank; i > rank; i--)
{
string rank_skill = getForceRankSkill(i, council);
LOG("force_rank", "rank_skill[" + i + "]->" + rank_skill);
if (hasSkill(player, rank_skill))
revokeSkill(player, rank_skill);
}
utils.removeScriptVar(player, SCRIPT_VAR_SKILL_RESYNC);
return true;
}
/***********************************************************************
* @brief Resyncs a player's FRS skills based on his existing rank.
*
* @param obj_id player
*
* @return boolean
***********************************************************************/
boolean resyncForceRankSkills(obj_id player)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.removeForceRankSkills -- player is invalid.");
return false;
}
int rank = getForceRank(player);
if (rank < 0 || rank > 11)
{
LOG("force_rank", "force_rank.removeForceRankSkills -- invalid value for rank: " + rank);
return false;
}
int council = getCouncilAffiliation(player);
if (council < 1)
{
LOG("force_rank", "force_rank.resyncForceRankSkills -- " + player + " has an invalid council affiliation.");
return false;
}
// Set this scriptvar so that the lost skill trigger won't assume any skill revocations are a demotion.
utils.setScriptVar(player, SCRIPT_VAR_SKILL_RESYNC, 1);
// Check for skills the player should have. Start at 0 and go to 12, so that prereqs are always met.
for (int i = 0; i < 12; i++)
{
string skill = getForceRankSkill(i, council);
if (skill != null)
{
if (i <= rank)
{
// Player should have this skill
if (!hasSkill(player, skill))
{
grantSkill(player, skill);
CustomerServiceLog("force_rank", "Adding skill " + skill + " to %TU since it should be granted for rank " + rank, player, null);
}
}
}
}
// Check for skills the player shouldn't have. Start and 12 and go to 0, so that prereqs are always met.
for (int i = 11; i >= 0; i--)
{
string skill = getForceRankSkill(i, council);
if (skill != null)
{
if (i > rank)
{
// Player shouldn't have this skill
if (hasSkill(player, skill))
{
revokeSkill(player, skill);
CustomerServiceLog("force_rank", "Removing skill " + skill + " from %TU since it not valid for rank " + rank, player, null);
}
}
}
}
utils.removeScriptVar(player, SCRIPT_VAR_SKILL_RESYNC);
return true;
}
/***********************************************************************
* @brief handles the periodic enclave functions such as updating
* clusterwide data and checking for voting results.
*
* @param obj_id enclave
*
* @return return int -1 if error or the player is not ranked
*********************************************************************/
boolean performEnclaveMaintenance(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.performEnclaveMaintenance -- enclave is invalid.");
return false;
}
// Check to see if it's time for experience maintenance.
if (hasObjVar(enclave, VAR_XP_MAINTENANCE))
{
int last_maintenance = getIntObjVar(enclave, VAR_XP_MAINTENANCE);
if (getGameTime() > last_maintenance)
{
deductXpMaintenance(enclave);
setObjVar(enclave, VAR_XP_MAINTENANCE, getGameTime() + getXpInterval());
}
}
else
setObjVar(enclave, VAR_XP_MAINTENANCE, getGameTime() + getXpInterval());
arena.checkArenaMaintenance(enclave);
checkExperienceDebt(enclave);
checkVotingResults(enclave);
int council = force_rank.getCouncilAffiliation(enclave);
if (council == -1)
{
LOG("force_rank", "enclave_controller.performEnclaveMaintenance -- " + enclave + " does not have a valid council value.");
return false;
}
// Create terminals if needed.
createEnclaveTerminals(enclave);
// update the enclave's data.
int request_id = getClusterWideData(force_rank.CLUSTER_DATA_NAME, force_rank.STRING_CLUSTER_ENCLAVE_NAME + council, false, enclave);
utils.setScriptVar(enclave, force_rank.SCRIPT_VAR_DATA_REQUEST + request_id, 0);
return true;
}
/***********************************************************************
* @brief examines voting data to determine results.
*
* @param obj_id enclave
*
* @return return true
*********************************************************************/
boolean checkVotingResults(obj_id enclave)
{
LOG("force_rank", "force_rank.checkVotingResults");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.checkVotingResults -- enclave is invalid.");
return false;
}
// Loop through the voting data for each rank and check the results.
for (int rank = 1; rank < 12; rank++)
{
// Look at the status of voting for the rank.
int status = getVoteStatus(enclave, rank);
int time = getVoteEndTime(enclave, rank);
if (status == -1 || time == -1)
{
LOG("force_rank", "force_rank.checkVotingResults -- invalid value for status/time :" + status + "/" + time + " for rank " + rank);
continue;
}
string obj_var_base = VAR_VOTING_BASE + rank;
if (!hasObjVar(enclave, obj_var_base) && status != 4)
{
setObjVar(enclave, obj_var_base + ".status", 4);
setObjVar(enclave, obj_var_base + ".time", getGameTime());
continue;
}
boolean time_expired = time < getGameTime();
switch (status)
{
case 1:
{
// Petitioning open
if (time_expired)
{
string[] petitioners = getRankPetitioners(enclave, rank);
if (petitioners == null)
{
// If no one petitioned, we open it up for another round.
int avail_slots = getAvailableRankSlots(enclave, rank);
if (avail_slots > 0)
{
setObjVar(enclave, obj_var_base + ".status", 1);
setObjVar(enclave, obj_var_base + ".time", getGameTime() + getPetitionInterval());
}
else
resetVotingTerminal(enclave, rank);
}
else
{
// If there's more open slots than petitioners, everyone wins.
// If there's only on petitioner, he wins.
int avail_slots = getAvailableRankSlots(enclave, rank);
if (petitioners.length <= avail_slots || petitioners.length == 1)
{
removeObjVar(enclave, obj_var_base + ".petition");
removeObjVar(enclave, obj_var_base + ".time");
removeObjVar(enclave, obj_var_base + ".votes");
//string[] winner_list = {petitioners[0]};
setObjVar(enclave, obj_var_base + ".winner", petitioners);
setObjVar(enclave, obj_var_base + ".status", 3);
setObjVar(enclave, obj_var_base + ".time", getGameTime() + getAcceptanceInterval());
// Send a message to the winners
string_id sub = new string_id(force_rank.STF_FILE, "vote_win_sub");
string_id body = new string_id(force_rank.STF_FILE, "vote_win_body");
for (int i = 0; i < petitioners.length; i++)
utils.sendMail(sub, body, petitioners[i], "Enclave Records");
}
else
{
// Open up voting for the given petitioners.
setObjVar(enclave, obj_var_base + ".status", 2);
setObjVar(enclave, obj_var_base + ".time", getGameTime() + getVoteInterval());
int[] votes = new int[petitioners.length];
Arrays.fill(votes, 0);
setObjVar(enclave, obj_var_base + ".votes", votes);
// make the petitioners enemies of each other
/*
if(getCouncilAffiliation(enclave) == DARK_COUNCIL)
{
startPvPAction(enclave, playerNamesToIds(petitioners), ACTION_CANDIDATE_SUDDEN_DEATH, enclave);
}
*/
// e-mail all eligible voters about the vote
string_id sub = new string_id(force_rank.STF_FILE, "vote_cycle_begun_sub");
string_id body = new string_id(force_rank.STF_FILE, "vote_cycle_begun_body");
string rank_str = localize(new string_id(force_rank.STF_FILE, "rank" + rank));
int vote_interval = getVoteInterval();
string time_str = player_structure.assembleTimeRemaining(player_structure.convertSecondsTime(vote_interval));
prose_package pp = prose.getPackage(body, time_str, rank_str);
sendVoterMail(enclave, rank, sub, pp);
}
}
}
break;
}
case 2:
{
// Voting open
if (time_expired)
{
// Check the votes.
int avail_slots = getAvailableRankSlots(enclave, rank);
string[] petitioners = getRankPetitioners(enclave, rank);
int[] votes = getRankPetitionerVotes(enclave, rank);
/*
// stop the pvp sudden death PvP Action
if(getCouncilAffiliation(enclave) == DARK_COUNCIL)
{
resizeable obj_id[] players_o = new obj_id[0];
string[] lists = {VAR_VICTIMS, VAR_INITIATORS}; // clear actions for which @player is either a victim or an initiator
for(int x = 0; x < petitioners.length; x++)
{
utils.addElement(players_o, getPlayerIdFromFirstName(petitioners[x]));
_clearPvPActionDataForPlayer(players_o[x], lists, ACTION_CANDIDATE_SUDDEN_DEATH, enclave);
}
notifyPlayerOfPvPActionEnd(null, ACTION_CANDIDATE_SUDDEN_DEATH, players_o, players_o, true);
}
*/
// Pick the top vote getters to fill the vacant slots.
if (avail_slots > 0)
{
int[] top_votes = getTopVotes(votes, avail_slots);
votes = getRankPetitionerVotes(enclave, rank);
if (top_votes != null)
{
//resizeable int[] res_votes = getRankPetitionerVotesResizeable(enclave, rank);
resizeable string[] winners = new string[0];
for (int i = 0; i < top_votes.length; i++)
{
int vote_idx = utils.getElementPositionInArray(votes, top_votes[i]);
winners.add(petitioners[vote_idx]);
votes[vote_idx] = -1;
// Send a message to the winners
string_id sub = new string_id(force_rank.STF_FILE, "vote_win_sub");
string_id body = new string_id(force_rank.STF_FILE, "vote_win_body");
utils.sendMail(sub, body, petitioners[vote_idx], "Enclave Records");
CustomerServiceLog("force_rank", petitioners[vote_idx] + " won an open seat in rank " + rank + " with " + top_votes[i] + " votes.");
}
if (winners.size() > 0)
{
// At this point, the winners may accept their positions.
removeObjVar(enclave, obj_var_base + ".petition");
removeObjVar(enclave, obj_var_base + ".votes");
setObjVar(enclave, obj_var_base + ".winner", winners);
setObjVar(enclave, obj_var_base + ".status", 3);
setObjVar(enclave, obj_var_base + ".time", getGameTime() + getAcceptanceInterval());
}
}
else
{
LOG("force_rank", "force_rank.checkVotingResults -- voting failed for rank " + rank + " due to a null top_votes.");
resetVotingTerminal(enclave, rank);
}
}
else
{
// No spots are open now. The top vote getting automatically wins the vote on the next available slot.
int[] top_votes = getTopVotes(votes, 1);
if (top_votes != null)
{
int vote_idx = utils.getElementPositionInArray(votes, top_votes[0]);
removeObjVar(enclave, obj_var_base + ".petition");
removeObjVar(enclave, obj_var_base + ".time");
removeObjVar(enclave, obj_var_base + ".votes");
string[] winner_list = {petitioners[vote_idx]};
setObjVar(enclave, obj_var_base + ".winner", winner_list);
setObjVar(enclave, obj_var_base + ".status", 4);
// Send a message to the winners
string_id sub = new string_id(force_rank.STF_FILE, "vote_win_sub");
string_id body = new string_id(force_rank.STF_FILE, "vote_win_no_slot_body");
utils.sendMail(sub, body, petitioners[vote_idx], "Enclave Records");
}
else
{
LOG("force_rank", "force_rank.checkVotingResults -- voting failed for rank " + rank + " due to a null top_votes.");
resetVotingTerminal(enclave, rank);
}
}
// Eligible votes who miss a vote loose experience.
checkMissedVotes(enclave, rank);
}
break;
}
case 3:
{
// Waiting Acceptance
if (time_expired)
{
// The acceptance period is over. Clear the data and remove all winners.
//LOG("force_rank", "force_rank.checkVotingResults -- reset voting data.");
string[] winners = getVoteWinners(enclave, rank);
//LOG("force_rank", "winners ->" + winners);
if (winners != null)
{
string_id sub = new string_id(force_rank.STF_FILE, "acceptance_expired_sub");
string_id body = new string_id(force_rank.STF_FILE, "acceptance_expired_body");
string rank_str = localize(new string_id(force_rank.STF_FILE, "rank" + rank));
prose_package pp = prose.getPackage(body, rank_str);
for (int i = 0; i < winners.length; i++)
{
utils.sendMail(sub, pp, winners[i], "Enclave Records");
CustomerServiceLog("force_rank", winners[i] + "'s chance to accept a promotion to rank " + rank + " has expired.");
}
}
resetVotingTerminal(enclave, rank);
}
break;
}
case 4:
{
//LOG("force_rank", "!!!!!!!!!!!!!!! voting_closed -->" + rank);
// Voting is closed.
// Check for available slots.
int avail_slots = getAvailableRankSlots(enclave, rank);
if (avail_slots > 0)
{
// Check for a previous vote winners awaiting an open slots. If they exist, reopen
// the acceptance process.
string[] winners = getVoteWinners(enclave, rank);
if (winners != null)
{
setObjVar(enclave, obj_var_base + ".status", 3);
setObjVar(enclave, obj_var_base + ".time", getGameTime() + getAcceptanceInterval());
// Send a message to the winners
string_id sub = new string_id(force_rank.STF_FILE, "vote_seat_available_sub");
string_id body = new string_id(force_rank.STF_FILE, "vote_seat_available_body");
string rank_str = localize(new string_id(force_rank.STF_FILE, "rank" + rank));
prose_package pp = prose.getPackage(body, rank_str);
for (int i = 0; i < winners.length; i++)
utils.sendMail(sub, pp, winners[i], "Enclave Records");
}
else
{
setObjVar(enclave, obj_var_base + ".status", 1);
setObjVar(enclave, obj_var_base + ".time", getGameTime() + getPetitionInterval());
}
}
}
}
}
return true;
}
/***********************************************************************
* @brief examines challenge voting data and determines results.
*
* @param obj_id enclave
*
* @return return true
*********************************************************************/
boolean checkChallengeVotingResults(obj_id enclave)
{
LOG("force_rank", "force_rank.checkChallengeVotingResults");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.checkChallengeVotingResults -- enclave is invalid.");
return false;
}
obj_id terminal = getChallengeVotingTerminal(enclave);
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.checkChallengeVotingResults -- terminal is invalid.");
return false;
}
obj_var_list vote_list = getObjVarList(terminal, VAR_CHAL_VOTING_BASE);
if (vote_list == null)
{
// There are currently no active challenges.
return true;
}
for (int i = 0; i < vote_list.getNumItems(); i++)
{
// Get the list of challenges.
obj_var challenge_objvar = vote_list.getObjVar(i);
if (challenge_objvar == null)
continue;
// The name of the objvar is the challenged player's name.
string name = challenge_objvar.getName();
if (name == null)
continue;
string objvar_name = VAR_CHAL_VOTING_BASE + "." + name;
// Get all of the data.
int rank = getForceRank(enclave, name);
int challenge_rank = getChallengeVoteRank(terminal, name);
int status = getChallengeVoteStatus(terminal, name);
if (status == -1 || status == 3)
{
// This challenge is no longer valid. Remove it.
if (hasObjVar(terminal, objvar_name))
removeObjVar(terminal, objvar_name);
if (hasObjVar(terminal, BATCH_VAR_VOTERS + "." + name))
removeObjVar(terminal, BATCH_VAR_VOTERS + "." + name);
continue;
}
int time = getChallengeVoteEndTime(terminal, name);
boolean time_expired = time < getGameTime();
switch (status)
{
case 1:
{
// Voting Open
if (challenge_rank != rank)
{
// The player is no longer at the rank where the challenge was issued. Cancel it.
removeObjVar(terminal, objvar_name);
if (hasObjVar(terminal, BATCH_VAR_VOTERS + "." + name))
removeObjVar(terminal, BATCH_VAR_VOTERS + "." + name);
// Tell all of the voters about it.
string_id sub = new string_id(force_rank.STF_FILE, "challenge_vote_cancelled_sub");
string_id body = new string_id(force_rank.STF_FILE, "challenge_vote_cancelled_body");
prose_package pp = prose.getPackage(body, name);
sendChallengeVoterMail(enclave, challenge_rank, sub, pp);
continue;
}
if (time_expired)
{
int[] votes = getChallengeVotes(terminal, name);
boolean success = false;
if (votes != null)
{
// Requires at least 2/3 vote for challenge to succeed.
if (votes[0] >= votes[1] * 2)
success = true;
}
if (success)
{
// demote the player challenged.
demoteForceRank(enclave, name, challenge_rank - 1);
// Tell the voting ranks about it.
string_id sub = new string_id(force_rank.STF_FILE, "challenge_vote_success_sub");
string_id body = new string_id(force_rank.STF_FILE, "challenge_vote_success_body");
prose_package pp = prose.getPackage(body, name, Integer.toString(votes[0]), votes[1]);
sendChallengeVoterMail(enclave, challenge_rank, sub, pp);
}
else
{
// The challenge failed. Tell the voting ranks about it.
string_id sub = new string_id(force_rank.STF_FILE, "challenge_vote_fail_sub");
string_id body = new string_id(force_rank.STF_FILE, "challenge_vote_fail_body");
prose_package pp = prose.getPackage(body, name, Integer.toString(votes[0]), votes[1]);
sendChallengeVoterMail(enclave, challenge_rank, sub, pp);
}
setObjVar(terminal, objvar_name + ".status", 2);
setObjVar(terminal, objvar_name + ".time", getGameTime() + 3600);
}
break;
}
case 2:
{
// Voting Closed
if (time_expired)
{
if (hasObjVar(terminal, objvar_name))
removeObjVar(terminal, objvar_name);
if (hasObjVar(terminal, BATCH_VAR_VOTERS + "." + name))
removeObjVar(terminal, BATCH_VAR_VOTERS + "." + name);
}
break;
}
}
}
return true;
}
/***********************************************************************
* @brief determines who missed a vote and imposes experience
* debt for doing so.
*
* @param obj_id enclave
*
* @return return true
*********************************************************************/
boolean checkMissedVotes(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.checkMissedVotes -- enclave is invalid.");
return false;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.checkMissedVotes -- illegal rank value of " + rank);
return false;
}
obj_id terminal = getVotingTerminal(enclave);
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.checkMissedVotes -- can't find the voting terminal for enclave " + enclave);
return false;
}
resizeable string[] voters = utils.getResizeableStringBatchObjVar(terminal, BATCH_VAR_VOTERS + rank);
for (int vote_rank = 1; vote_rank < 12; vote_rank++)
{
// If the vote weight for a given rank is > 0, then that rank was eligible to vote.
if (getVoteWeight(vote_rank, rank) > 0)
{
string[] rank_list = getPlayersInForceRank(enclave, vote_rank);
if (rank_list != null)
{
int xp_debt = (int)(MISSED_VOTE_PENALTY * Math.pow(vote_rank, 2));
for (int i = 0; i < rank_list.length; i++)
{
if (voters != null)
{
// Players not in the voters list are hit with an experience penalty.
if (voters.indexOf(rank_list[i]) != -1)
continue;
}
CustomerServiceLog("force_rank", "Adding experience debt of " + xp_debt + " to " + rank_list[i] + " for missing a vote on rank " + vote_rank);
addExperienceDebt(enclave, rank_list[i], xp_debt);
// Give the player a message about it.
string_id sub = new string_id(force_rank.STF_FILE, "vote_missed_sub");
string_id body = new string_id(force_rank.STF_FILE, "vote_missed_body");
string rank_str = localize(new string_id(force_rank.STF_FILE, "rank" + rank));
prose_package pp = prose.getPackage(body, rank_str, xp_debt);
utils.sendMail(sub, pp, rank_list[i], "Enclave Records");
}
}
}
}
return true;
}
/***********************************************************************
* @brief returns the status of a given rank
*
* @param obj_id enclave
* @param int rank
*
* @return return int -1 on error
*********************************************************************/
int getVoteStatus(obj_id enclave, int rank)
{
// Status Key
// 1: Petitioning Open
// 2: Voting Open
// 3: Waiting Acceptance
// 4: Voting Closed
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getRankVoteStatus -- enclave is invalid.");
return -1;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getRankVoteStatus -- illegal rank value of " + rank);
return -1;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".status";
if (hasObjVar(enclave, obj_var_name))
return getIntObjVar(enclave, obj_var_name);
else
return 4;
}
/***********************************************************************
* @brief returns the end time of the current voting status for a
* given rank
*
* @param obj_id enclave
* @param int rank
*
* @return return int -1 on error or no end time set.
*********************************************************************/
int getVoteEndTime(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getVoteEndTime -- enclave is invalid.");
return -1;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getVoteEndTime -- illegal rank value of " + rank);
return -1;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".time";
if (hasObjVar(enclave, obj_var_name))
return getIntObjVar(enclave, obj_var_name);
else
return 0;
}
/***********************************************************************
* @brief returns whether or not the vote time for a given
* rank has expired
*
* @param obj_id enclave
* @param int rank
*
* @return return boolean false on error
*********************************************************************/
boolean isVoteTimeExpired(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.hasVoteTimeExpired -- enclave is invalid.");
return false;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.hasVoteTimeExpired -- illegal rank value of " + rank);
return false;
}
int time = getVoteEndTime(enclave, rank);
if (time < getGameTime())
return true;
else
return false;
}
/***********************************************************************
* @brief returns the challenge vote status of a given player
*
* @param obj_id terminal
* @param string challenged Player being challenged
*
* @return return int -1 on error
*********************************************************************/
int getChallengeVoteStatus(obj_id terminal, string challenged)
{
// Status key
// 1 Voting Open
// 2 Voting Closed
// 3 Inactive
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.getChallengeVoteStatus -- enclave is invalid.");
return -1;
}
if (challenged == null)
{
LOG("force_rank", "force_rank.getChallengeVoteStatus -- challenged is null.");
return -1;
}
string obj_var_name = VAR_CHAL_VOTING_BASE + "." + challenged + ".status";
if (hasObjVar(terminal, obj_var_name))
return getIntObjVar(terminal, obj_var_name);
else
return 3;
}
/***********************************************************************
* @brief returns the voting end time for a given challenge
*
* @param obj_id terminal
* @param string challenged
*
* @return return int -1 on error or no end time set.
*********************************************************************/
int getChallengeVoteEndTime(obj_id terminal, string challenged)
{
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.getVoteEndTime -- enclave is invalid.");
return -1;
}
if (challenged == null)
{
LOG("force_rank", "force_rank.getChallengeVoteEndTime -- challenged is null.");
return -1;
}
string obj_var_name = VAR_CHAL_VOTING_BASE + "." + challenged + ".time";
if (hasObjVar(terminal, obj_var_name))
return getIntObjVar(terminal, obj_var_name);
else
return 0;
}
/***********************************************************************
* @brief returns whether or not the vote time for a given
* challenge has expired
*
* @param obj_id terminal
* @param string challenged
*
* @return return boolean false on error
*********************************************************************/
boolean isChallengeVoteTimeExpired(obj_id terminal, string challenged)
{
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.isChallengeVoteTimeExpired -- enclave is invalid.");
return false;
}
if (challenged == null)
{
LOG("force_rank", "force_rank.isChallengeVoteTimeExpired -- challenged is null.");
return false;
}
int time = getChallengeVoteEndTime(terminal, challenged);
if (time < getGameTime())
return true;
else
return false;
}
/***********************************************************************
* @brief returns the rank for which this challenge was issued.
*
* @param obj_id terminal
* @param string challenged
*
* @return return int -1 on error
*********************************************************************/
int getChallengeVoteRank(obj_id terminal, string challenged)
{
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.getChallengeVoteRank -- enclave is invalid.");
return -1;
}
if (challenged == null)
{
LOG("force_rank", "force_rank.getChallengeVoteRank -- challenged is null.");
return -1;
}
string obj_var_name = VAR_CHAL_VOTING_BASE + "." + challenged + ".rank";
if (hasObjVar(terminal, obj_var_name))
return getIntObjVar(terminal, obj_var_name);
else
return 0;
}
/***********************************************************************
* @brief returns the votes for a given petitioner
*
* @param obj_id terminal
* @param string challenged
*
* @return return int[] Number of yes/no votes
*********************************************************************/
int[] getChallengeVotes(obj_id terminal, string challenged)
{
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.getChallengeVotes -- terminal is invalid.");
return null;
}
string obj_var_name = VAR_CHAL_VOTING_BASE + "." + challenged + ".votes";
if (hasObjVar(terminal, obj_var_name))
{
int[] votes = getIntArrayObjVar(terminal, obj_var_name);
if (votes.length != 2)
return null;
else
return votes;
}
else
return null;
}
/***********************************************************************
* @brief Returns a list of players being challenged.
*
* @param obj_id terminal
*
* @return return string[] List of players being challenged
* Null on error or no challenges.
*********************************************************************/
string[] getChallengeVoteList(obj_id terminal)
{
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.getChallengeVoteList -- terminal is invalid.");
return null;
}
resizeable string[] names = new string[0];
obj_var_list vote_list = getObjVarList(terminal, VAR_CHAL_VOTING_BASE);
if (vote_list == null)
{
// There are currently no active challenges.
return null;
}
for (int i = 0; i < vote_list.getNumItems(); i++)
{
obj_var challenge_objvar = vote_list.getObjVar(i);
if (challenge_objvar != null)
{
string name = challenge_objvar.getName();
if (name != null)
names.add(name);
}
}
if (names.length > 0)
return names;
else
return null;
}
/***********************************************************************
* @brief Returns the number of active challenges
*
* @param obj_id terminal
*
* @return return int -1 on error
*********************************************************************/
int getNumChallengeVoteList(obj_id terminal)
{
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.getNumChallengeVoteList -- terminal is invalid.");
return -1;
}
obj_var_list vote_list = getObjVarList(terminal, VAR_CHAL_VOTING_BASE);
if (vote_list != null)
return vote_list.getNumItems();
else
return 0;
}
/***********************************************************************
* @brief returns the petitioners of a given rank
*
* @param obj_id enclave
* @param int rank
*
* @return return string[]
*********************************************************************/
string[] getRankPetitioners(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getRankPetitioners -- enclave is invalid.");
return null;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getRankPetitioners -- illegal rank value of " + rank);
return null;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".petition";
if (hasObjVar(enclave, obj_var_name))
return getStringArrayObjVar(enclave, obj_var_name);
else
return null;
}
/***********************************************************************
* @brief returns the petitioners of a given rank
*
* @param obj_id enclave
* @param int rank
*
* @return return string[]
*********************************************************************/
resizeable string[] getRankPetitionersResizeable(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getRankPetitionersResizeable -- enclave is invalid.");
return null;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getRankPetitionersResizeable -- illegal rank value of " + rank);
return null;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".petition";
if (hasObjVar(enclave, obj_var_name))
return getResizeableStringArrayObjVar(enclave, obj_var_name);
else
return null;
}
/***********************************************************************
* @brief returns the votes for a given petitioner
*
* @param obj_id enclave
* @param int rank
*
* @return return int[]
*********************************************************************/
int[] getRankPetitionerVotes(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getRankPetitioners -- enclave is invalid.");
return null;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getRankPetitioners -- illegal rank value of " + rank);
return null;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".votes";
if (hasObjVar(enclave, obj_var_name))
return getIntArrayObjVar(enclave, obj_var_name);
else
return null;
}
/***********************************************************************
* @brief returns the votes for a given petitioner
*
* @param obj_id enclave
* @param int rank
*
* @return return resizeable int[]
*********************************************************************/
resizeable int[] getRankPetitionerVotesResizeable(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getRankPetitionerVotesResizeable -- enclave is invalid.");
return null;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getRankPetitionerVotesResizeable -- illegal rank value of " + rank);
return null;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".votes";
if (hasObjVar(enclave, obj_var_name))
return getResizeableIntArrayObjVar(enclave, obj_var_name);
else
return null;
}
/***********************************************************************
* @brief returns the specified number of top votes
*
* @param resizeable int[]
* @param int winners
*
* @return return int[]
*********************************************************************/
int[] getTopVotes(int[] votes, int winners)
{
if (votes == null)
{
LOG("force_rank", "force_rank.getTopVotes -- votes is null.");
return null;
}
if (winners < 1)
{
LOG("force_rank", "force_rank.getTopVotes -- illegal winners value of " + winners);
return null;
}
if (winners > votes.length)
return votes;
int[] top_votes = new int[winners];
Arrays.sort(votes);
for (int i = 0; i < top_votes.length; i++)
top_votes[i] = votes[votes.length - (i + 1)];
return top_votes;
}
/***********************************************************************
* @brief returns the players who have won a vote but are
* waiting an open slot
*
* @param obj_id enclave
* @param int rank
*
* @return return string null on error or no winner
*********************************************************************/
string[] getVoteWinners(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getVoteWinner -- enclave is invalid.");
return null;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getVoteWinner -- illegal rank value of " + rank);
return null;
}
string obj_var_name = VAR_VOTING_BASE + rank + ".winner";
if (hasObjVar(enclave, obj_var_name))
return getStringArrayObjVar(enclave, obj_var_name);
else
return null;
}
/***********************************************************************
* @brief returns the voting terminal
*
* @param obj_id enclave
*
* @return return obj_id null on error or no terminal
*********************************************************************/
obj_id getVotingTerminal(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getVotingTerminal -- enclave is invalid.");
return null;
}
if (utils.hasScriptVar(enclave, SCRIPT_VAR_VOTE_TERMINAL))
{
obj_id terminal = utils.getObjIdScriptVar(enclave, SCRIPT_VAR_VOTE_TERMINAL);
if (terminal.isAuthoritative())
return terminal;
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief returns the arena terminal
*
* @param obj_id enclave
*
* @return return obj_id null on error or no terminal
*********************************************************************/
obj_id getArenaTerminal(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getArenaTerminal -- enclave is invalid.");
return null;
}
if (utils.hasScriptVar(enclave, arena.VAR_CHALLENGE_TERMINAL))
{
obj_id terminal = utils.getObjIdScriptVar(enclave, arena.VAR_CHALLENGE_TERMINAL);
if (terminal.isAuthoritative())
return terminal;
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief returns the challenge voting terminal
*
* @param obj_id enclave
*
* @return return obj_id null on error or no terminal
*********************************************************************/
obj_id getChallengeVotingTerminal(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getChallengeVotingTerminal -- enclave is invalid.");
return null;
}
if (utils.hasScriptVar(enclave, SCRIPT_VAR_CHAL_VOTE_TERMINAL))
{
obj_id terminal = utils.getObjIdScriptVar(enclave, SCRIPT_VAR_CHAL_VOTE_TERMINAL);
if (terminal.isAuthoritative())
return terminal;
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief clears the voting terminal data for the specified
* rank.
*
* @param obj_id enclave
* @param int rank
*
* @return return boolean
*********************************************************************/
boolean resetVotingTerminal(obj_id enclave, int rank)
{
LOG("force_rank", "force_rank.resetVotingTerminal -- " + VAR_VOTING_BASE + rank);
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.resetVotingTerminal -- enclave is invalid.");
return false;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.resetVotingTerminal -- illegal rank value of " + rank);
return false;
}
obj_id terminal = getVotingTerminal(enclave);
if (!isIdValid(terminal))
{
LOG("force_rank", "force_rank.resetVotingTerminal -- can't find a voting terminal for " + enclave);
return false;
}
removeObjVar(terminal, BATCH_VAR_VOTERS + rank);
removeObjVar(enclave, VAR_VOTING_BASE + rank);
return true;
}
/***********************************************************************
* @brief Imparts the daily experience cost for being a rank
* member.
*
* @param obj_id enclave
*
* @return return boolean
*********************************************************************/
boolean deductXpMaintenance(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.deductXpMaintenance -- enclave is invalid.");
return false;
}
// Each rank member must pay experience at a set interval.
int base_xp_cost = BASE_XP_MAINTENANCE;
for (int rank = 1; rank < 12; rank++)
{
string[] rank_list = getPlayersInForceRank(enclave, rank);
if (rank_list != null)
{
//int xp_cost = base_xp_cost * (int) Math.pow(rank, 1.5);
int xp_cost = base_xp_cost * rank;
for (int i = 0; i < rank_list.length; i++)
{
addExperienceDebt(enclave, rank_list[i], xp_cost);
CustomerServiceLog("force_rank", "Adding experience debt of " + xp_cost + " to " + rank_list[i] + " for regular experience maintenance.");
string_id sub = new string_id(force_rank.STF_FILE, "xp_maintenace_sub");
string_id body = new string_id(force_rank.STF_FILE, "xp_maintenance_body");
prose_package pp = prose.getPackage(body, xp_cost);
utils.sendMail(sub, pp, rank_list[i], "Enclave Records");
}
}
}
return true;
}
/***********************************************************************
* @brief looks over experience debt and demotes players that
* have attained too much of it.
*
* @param obj_id enclave
*
* @return return boolean
*********************************************************************/
boolean checkExperienceDebt(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.checkExperienceDebt -- enclave is invalid.");
return false;
}
for (int i = 1; i < 12; i++)
{
string[] rank_list = getPlayersInForceRank(enclave, i);
if (rank_list != null)
{
int xp_to_demote = 5000 * i;
for (int j = 0; j < rank_list.length; j++)
{
string obj_var_name = VAR_MEMBER_DATA + rank_list[j] + ".xp_debt";
//LOG("force_rank", "obj_var_name ->" + obj_var_name);
if (hasObjVar(enclave, obj_var_name))
{
int xp_debt = getIntObjVar(enclave, obj_var_name);
//LOG("force_rank", "... xp_debt->" + xp_debt + " xp_to_demote ->" + xp_to_demote);
if (xp_debt > xp_to_demote)
{
// The player has accumulated too much debt. Demote him.
if (!demoteForceRank(enclave, rank_list[j], i - 1))
{
LOG("force_rank", "force_rank.checkExperienceDebt -- failed to demote " + rank_list[j] + " due to too much xp debt.");
CustomerServiceLog("force_rank", "Failed to demote " + rank_list[j] + " for too much xp debt");
}
else
{
CustomerServiceLog("force_rank", "Demoting " + rank_list[j] + " for too much xp debt");
// send the player an e-mail.
string_id sub = new string_id(force_rank.STF_FILE, "demote_xp_debt_sub");
string_id body = new string_id(force_rank.STF_FILE, "demote_xp_debt_body");
utils.sendMail(sub, body, rank_list[j], "Enclave Records");
}
}
}
}
}
}
return true;
}
/***********************************************************************
* @brief checks the player's experience debt against the enclave
* and deducts xp if necessary.
*
* @param obj_id player
*
* @return return boolean
*********************************************************************/
boolean requestExperienceDebt(obj_id player)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.requestExperienceDebt -- player is invalid.");
return false;
}
obj_id enclave = getEnclave(player);
if (isIdValid(enclave))
{
dictionary d = new dictionary();
d.put("player", player);
d.put("player_name", getFirstName(player));
messageTo(enclave, "msgRequestExperienceDebt", d, 3.0f, false);
return true;
}
else
return false;
}
/***********************************************************************
* @brief gets a player's experience debt
*
* @param obj_id enclave
* @param string player_name
*
* @return return int -1 on error
*********************************************************************/
int getExperienceDebt(obj_id enclave, string player_name)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getExperienceDebt -- enclave is invalid.");
return -1;
}
if (player_name == null)
{
LOG("force_rank", "force_rank.getExperienceDebt -- player_name is null.");
return -1;
}
string obj_var_name = VAR_MEMBER_DATA + player_name + ".xp_debt";
if (hasObjVar(enclave, obj_var_name))
return getIntObjVar(enclave, obj_var_name);
else
return 0;
}
/***********************************************************************
* @brief validates the player's data against the enclave
* data.
*
* @param obj_id enclave
* @param string player_name
*
* @return return int -1 on error
*********************************************************************/
boolean validateFRSPlayerData(obj_id player)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.validateFRSPlayerData -- player is invalid.");
return false;
}
// Don't validate until the rename is handled.
if (hasObjVar(player, "renamePerformed"))
return false;
int council = getCouncilAffiliation(player);
if (council == -1)
{
LOG("force_rank", "force_rank.validateFRSPlayerData -- " + player + " does not have council value.");
return false;
}
obj_id enclave = getEnclave(player);
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.validateFRSPlayerData -- " + player + " does not have an enclave. Resetting it.");
getEnclaveObjId(player, getCouncilAffiliation(player), "enclaveIdResponse");
return false;
}
LOG("force_rank", "force_rank.validateFRSPlayerData -- player name " + getFirstName(player));
// Get the enclave's data on the player
dictionary d = new dictionary();
d.put("player", player);
d.put("player_name", getFirstName(player));
d.put("player_rank", getForceRank(player));
messageTo(enclave, "msgValidateFRSPlayerData", d, 10.0f, false);
return true;
}
/***********************************************************************
* @brief gets the rank of the specified player.
*
* @param obj_id player
*
* @return return int -1 if error or the player is not ranked
*********************************************************************/
int getForceRank(obj_id player)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.getForceRank -- player is invalid.");
return -1;
}
if (hasObjVar(player, VAR_RANK))
return getIntObjVar(player, VAR_RANK);
else
return -1;
}
/***********************************************************************
* @brief gets the rank of the specified player, using the enclave
*
* @param obj_id enclave
* @param string player_name
*
* @return return int -1 if error or the player is not ranked
*********************************************************************/
int getForceRank(obj_id enclave, string player_name)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getForceRank -- enclave is invalid.");
return -1;
}
if (player_name == null)
{
LOG("force_rank", "force_rank.getForceRank -- enclave is invalid.");
return -1;
}
for (int i = 1; i < 12; i++)
{
resizeable string[] rank_list = getPlayersInForceRankResizeable(enclave, i);
if (rank_list != null)
{
int idx = rank_list.indexOf(player_name);
if (idx != -1)
return i;
}
}
return -1;
}
/***********************************************************************
* @brief returns the tier of a specified rank
*
* @param int rank
*
* @return return int -1 on error
*********************************************************************/
int getForceTier(int rank)
{
if (rank < 0 || rank > 11)
{
LOG("force_rank", "force_rank.getForceTier -- illegal rank value: " + rank);
return -1;
}
if (rank == 0)
return 0;
if (rank > 0 && rank < 5)
return 1;
if (rank > 4 && rank < 8)
return 2;
if (rank > 7 && rank <10)
return 3;
if (rank == 10)
return 4;
if (rank == 11)
return 5;
return -1;
}
/***********************************************************************
* @brief gets the enclave to which the specified player is associated
*
* @param obj_id player
*
* @return return obj_id null on error or player not in FRS
*********************************************************************/
obj_id getEnclave(obj_id player)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.getEnclave -- player is invalid.");
return null;
}
if (hasObjVar(player, VAR_MY_ENCLAVE_ID))
return getObjIdObjVar(player, VAR_MY_ENCLAVE_ID);
else
return null;
}
/***********************************************************************
* @brief gets the council affiliation of the specified player or enclave
*
* @param obj_id player
*
* @return return int -1 if error or not ranked
*********************************************************************/
int getCouncilAffiliation(obj_id object)
{
if (!isIdValid(object))
{
LOG("force_rank", "force_rank.getForceRanking -- object is invalid.");
return -1;
}
if (hasObjVar(object, VAR_COUNCIL))
{
int council = getIntObjVar(object, VAR_COUNCIL);
if (council != DARK_COUNCIL && council != LIGHT_COUNCIL)
return -1;
else
return council;
}
else
return -1;
}
/***********************************************************************
* @brief returns the name of a given council
*
* @param int council
*
* @return return string null if error or no council name
*********************************************************************/
string getCouncilName(int council)
{
if (COUNCIL_NAMES.length < council)
return null;
string name = COUNCIL_NAMES[council];
if (name != null && name.length() > 0)
return name;
else
return null;
}
/***********************************************************************
* @brief Returns the available number of slots for a given rank
*
* @param obj_id enclave
* @param int rank
*
* @return return int -1 if error
*********************************************************************/
int getAvailableRankSlots(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getAvailableRankSlots -- enclave is invalid.");
return -1;
}
int max_slots = getForceRankNumSlots(rank);
if (max_slots > 0)
{
// Get the available slots using the cluster-wide data stuff.
int slots_taken = 0;
string[] rank_list = getPlayersInForceRank(enclave, rank);
if (rank_list != null)
slots_taken = rank_list.length;
return max_slots - slots_taken;
}
else
{
LOG("force_rank", "force_rank.getAvailableRankSlots -- invalid rank value of " + rank);
return -1;
}
}
/***********************************************************************
* @brief returns a faction id from the string
*
* @param string player
*
* @return return int
*********************************************************************/
int getFactionId(string faction)
{
if (faction == null)
{
LOG("force_rank", "force_rank.getFactionId -- faction is null.");
return 0;
}
int faction_num = factions.getFactionNumber(faction);
if (faction_num == -1)
return 0;
int faction_id = dataTableGetInt("datatables/faction/faction.iff", faction_num, "pvpFaction");
return faction_id;
}
/***********************************************************************
* @brief returns the skill associated with a given rank
*
* @param int rank
* @param int council
*
* @return return string, null if error or rank not found
*********************************************************************/
string getForceRankSkill(int rank, int council)
{
if (council != LIGHT_COUNCIL && council != DARK_COUNCIL)
{
LOG("force_rank", "force_rank.getForceRankSkill -- invalid council value of " + council);
return null;
}
string datatable;
if (council == LIGHT_COUNCIL)
datatable = FRS_DATATABLE;
else
datatable = FRS_DARK_DATATABLE;
int index = dataTableSearchColumnForInt(rank, "rank", datatable);
if (index == -1)
{
LOG("force_rank", "force_rank.getForceRankSkill -- faction invalid rank value of " + rank);
return null;
}
string skill = dataTableGetString(datatable, index, "skill");
//LOG("force_rank", "force_rank.getForceRankSkill --- datatable ->" + datatable + " skill ->" + skill + " council ->" + council);
if (skill.length() < 1)
return null;
else
return skill;
}
/***********************************************************************
* @brief returns the rank of a given skill
*
* @param string skill
* @param int council
*
* @return return int; -1 on error or skill not in FRS
*********************************************************************/
int getForceSkillRank(string skill, int council)
{
if (skill == null)
{
LOG("force_rank", "force_rank.getForceSkillRank -- skill is null.");
return -1;
}
if (council != LIGHT_COUNCIL && council != DARK_COUNCIL)
{
LOG("force_rank", "force_rank.getForceSkillRank -- invalid council value of " + council);
return -1;
}
string datatable;
if (council == LIGHT_COUNCIL)
datatable = FRS_DATATABLE;
else
datatable = FRS_DARK_DATATABLE;
int index = dataTableSearchColumnForString(skill, "skill", datatable);
return index;
}
/***********************************************************************
* @brief returns the number of allowed players at a given rank
*
* @param int rank
*
* @return return int, -1 if error or rank not found
*********************************************************************/
int getForceRankNumSlots(int rank)
{
int index = dataTableSearchColumnForInt(rank, "rank", FRS_DATATABLE);
if (index == -1)
{
LOG("force_rank", "force_rank.getForceRankNumSlots -- faction invalid rank value of " + rank);
return -1;
}
int num_slots = dataTableGetInt(FRS_DATATABLE, index, "num_slots");
return num_slots;
}
/***********************************************************************
* @brief returns the minimum experience needed to maintain a rank
*
* @param int rank
*
* @return return int, -1 if error or rank not found
*********************************************************************/
int getForceRankMinXp(int rank)
{
int index = dataTableSearchColumnForInt(rank, "rank", FRS_DATATABLE);
if (index == -1)
{
LOG("force_rank", "force_rank.getForceRankMinXp -- faction invalid rank value of " + rank);
return -1;
}
int min_xp = dataTableGetInt(FRS_DATATABLE, index, "min_xp");
return min_xp;
}
//
// @returns the number of votes that @player has registered on the @enclave
//
int getVotesForPlayer(obj_id player, obj_id enclave)
{
int playerRank = getForceRank(enclave, utils.getRealPlayerFirstName(player));
if(playerRank < 0)
{
return 0;
}
string[] petitioners = getRankPetitioners(enclave, playerRank+1);
int[] votes = getRankPetitionerVotes(enclave, playerRank+1);
if(votes.length != petitioners.length)
{
LOG("force_rank", "force_rank::getVotesForPlayer: -> Votes.length != petitioners.length. Returning zero votes for player " + utils.getRealPlayerFirstName(player));
return 0;
}
string playerName = utils.getRealPlayerFirstName(player);
int idx = utils.getElementPositionInArray(petitioners, playerName);
if(idx < 0)
{
return 0;
}
return votes[idx];
}
//
// sets the votes for @player at @numVotes on the @enclave
//
void setVotesForPlayer(obj_id player, int numVotes, obj_id enclave)
{
if(!isIdValid(player) || player == null)
{
trace.log("force_rank", "force_rank::getVotesForPlayer: -> Can't set votes for null player.", player, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
int playerRank = getForceRank(enclave, utils.getRealPlayerFirstName(player));
if(playerRank < 0)
{
return;
}
resizeable string[] petitioners = getRankPetitionersResizeable(enclave, playerRank+1);
resizeable int[] votes = getRankPetitionerVotesResizeable(enclave, playerRank+1);
if(votes.length != petitioners.length)
{
trace.log("force_rank", "force_rank::getVotesForPlayer: -> Votes.length != petitioners.length. Returning zero votes for player " + utils.getRealPlayerFirstName(player), player, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
string playerName = utils.getRealPlayerFirstName(player);
int idx = utils.getElementPositionInArray(petitioners, playerName);
if(idx > -1)
{
if(numVotes < 1)
{
utils.removeElementAt(petitioners, idx);
utils.removeElementAt(votes, idx);
}
else
{
votes[idx] = numVotes;
}
}
else if(numVotes > 0) // player has no votes set currently... need to set votes.
{
utils.addElement(petitioners, playerName);
utils.addElement(votes, numVotes);
}
setObjVar(enclave, VAR_VOTING_BASE + (playerRank+1) + ".petition", petitioners);
setObjVar(enclave, VAR_VOTING_BASE + (playerRank+1) + ".votes", votes);
return;
}
//
// @ returns all names for everyone listed on the @enclave
//
Vector getAllPlayerNamesInForceRank(obj_id enclave)
{
Vector allNames = new Vector();
for(int h = 1; h < 12; h++)
{
string[] players = getPlayersInForceRank(enclave, h);
if(players == null)
{
continue;
}
allNames = utils.concatArrays(allNames, players);
}
return allNames;
}
//
// gets all players in the force rank @rank by obj_id. if the rank is given as -1, all members will be returned
//
obj_id[] getAllPlayersInForceRank(obj_id enclave, int rank)
{
resizeable obj_id[] playerIds = new obj_id[0];
obj_id player = null;
if(rank >= 0)
{
string[] players = getPlayersInForceRank(enclave, rank);
if(players == null)
{
return playerIds;
}
for(int i = 0; i < players.length; i++)
{
player = getPlayerIdFromFirstName(players[i]);
if(player != null && isIdValid(player))
{
utils.addElement(playerIds, player);
}
}
}
// -1 gets all players in the ranks
else
{
for(int h = 1; h < 12; h++)
{
string[] players = getPlayersInForceRank(enclave, h);
if(players == null)
{
continue;
}
for(int s = 0; s < players.length; s++)
{
player = getPlayerIdFromFirstName(players[s]);
if(player != null && isIdValid(player))
{
utils.addElement(playerIds, player);
}
}
}
}
return playerIds;
}
/***********************************************************************
* @brief returns the vote weight for a given rank voting for
* promotion into the specified rank.
*
* @param int voter_rank
* @param int promotion_rank
*
* @return return int -1 if the rank is not eligible.
*********************************************************************/
int getVoteWeight(int voter_rank, int promotion_rank)
{
if (voter_rank < 1)
return -1;
if (promotion_rank < 1 || promotion_rank > 11)
{
LOG("force_rank", "force_rank.isRankVoteEligible -- invalid promotion_rank value of " + promotion_rank);
return -1;
}
// If of the same rank, votes count double.
if (voter_rank == promotion_rank)
return 2;
// All first tiers can vote for first tier promotions.
if (promotion_rank > 0 && promotion_rank < 5)
{
if (voter_rank > 0 && voter_rank < 5)
return 1;
}
// All second tiers can vote for second tier promotions.
if (promotion_rank > 4 && promotion_rank < 8)
{
if (voter_rank > 4 && voter_rank < 8)
return 1;
}
// All third tiers can vote for third tier promotions.
if (promotion_rank == 8 || promotion_rank == 9)
{
if (voter_rank == 8 || voter_rank == 9)
return 1;
}
// Council members vote for council promotions
if (promotion_rank == 10)
{
if (voter_rank == 11)
return 1;
}
// Council members vote for council leader.
if (promotion_rank == 11)
{
if (voter_rank == 10)
return 1;
}
return -1;
}
/***********************************************************************
* @brief returns the vote weight for a given rank voting for
* no-confidence against the specified rank.
*
* @param int voter_rank
* @param int challenge_rank
*
* @return return int -1 if the rank is not eligible.
*********************************************************************/
int getChallengeVoteWeight(int voter_rank, int challenge_rank)
{
if (voter_rank < 1)
return -1;
if (challenge_rank < 1 || challenge_rank > 11)
{
LOG("force_rank", "force_rank.isRankVoteEligible -- invalid challenge_rank value of " + challenge_rank);
return -1;
}
// Ranks of equal or less that the challenged tier may vote.
int voter_tier = getForceTier(voter_rank);
int challenge_tier = getForceTier(challenge_rank);
if (voter_tier <= challenge_tier)
return 1;
else
return 0;
}
/***********************************************************************
* @brief returns the list of players in a given rank for a given
* enclave. Removes the empty slots.
*
* @param obj_id enclave
* @param int rank
*
* @return return string[] list of player first names, null on error
* or no members
*********************************************************************/
string[] getPlayersInForceRank(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- enclave is invalid.");
return null;
}
string objvar_name = VAR_RANK_BASE + rank;
if (hasObjVar(enclave, objvar_name))
{
string[] rank_list = getStringArrayObjVar(enclave, objvar_name);
// Pull out empty slots
resizeable string[] final_list = new string[0];
for (int i = 0; i < rank_list.length; i++)
{
if (rank_list[i] != null && rank_list[i].length() > 0 && !rank_list[i].equals(EMPTY_SLOT))
final_list = utils.addElement(final_list, rank_list[i]);
}
if (final_list.length > 0)
return final_list;
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief returns the list of players in a given rank for a given
* enclave. Removes the empty slots.
*
* @param obj_id enclave
* @param int rank
*
* @return return resizeable string[] list of player first names, null on error
* or no members
*********************************************************************/
resizeable string[] getPlayersInForceRankResizeable(obj_id enclave, int rank)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- enclave is invalid.");
return null;
}
string objvar_name = VAR_RANK_BASE + rank;
if (hasObjVar(enclave, objvar_name))
{
resizeable string[] rank_list = getResizeableStringArrayObjVar(enclave, objvar_name);
if (rank_list != null)
{
int idx = rank_list.indexOf(EMPTY_SLOT);
while (idx > -1)
{
rank_list.removeElementAt(idx);
idx = rank_list.indexOf(EMPTY_SLOT);
}
}
if (rank_list.size() > 0)
return rank_list;
else
return null;
}
return null;
}
/***********************************************************************
* @brief returns the list of players in a given rank for a given
* council. The information is returned via the clusterwide
* data system. Removes the empty slots
*
* @param source The object requesting the data.
* @param int rank 0 means all ranks
* @param int council
* @param string handler messageHandler to return the data.
*
* @return return boolean data is returned in the specified handler
* under the key "rank_list" or "rank_list#"
* if all requested. "rank_requested" contains
* the value of rank.
*********************************************************************/
boolean getPlayersInForceRank(obj_id source, int rank, int council, string handler)
{
if (!isIdValid(source))
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- source is invalid.");
return false;
}
if (rank < 0 || rank > 11)
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- rank value of " + rank + " is invalid.");
return false;
}
if (handler == null || handler.length() < 1)
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- handler value of " + handler + " is invalid.");
return false;
}
_updateForceRankData(source, council, 1, Integer.toString(rank), handler, false);
return true;
}
/***********************************************************************
* @brief validates whether or not a player is eligible to advance
* to the specified rank.
*
* @param obj_id player
* @param int rank
*
* @return return boolean, false on error or no eligible
*********************************************************************/
boolean isPlayerEligibleForPromotion(obj_id player, int rank)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.isPlayerEligibleForPromotion -- player is invalid.");
return false;
}
if (rank < 0 || rank > 11)
{
LOG("force_rank", "force_rank.isPlayerEligibleForPromotion -- rank value of " + rank + " is invalid.");
return false;
}
int experience = getExperiencePoints(player, FRS_XP);
string skill_name = getForceRankSkill(rank, getCouncilAffiliation(player));
if (skill_name == null)
{
LOG("force_rank", "force_rank.isPlayerEligibleForPromotion -- no skill found for rank " + rank);
return false;
}
LOG("force_rank", "force_rank.isPlayerEligibleForPromotion -- " + skill_name);
if (!skill.hasRequiredSkillsForSkillPurchase(player, skill_name))
return false;
else
return skill.hasRequiredXpForSkillPurchase(player, skill_name);
}
/***********************************************************************
* @brief returns the obj_id of the specified enclave.
*
* @param source The object requesting the data.
* @param int council
* @param string handler messageHandler to return the data.
*
* @return return boolean data is returned in the specified handler
* under the key "enclave"
*********************************************************************/
boolean getEnclaveObjId(obj_id source, int council, string handler)
{
if(!isIdValid(source))
{
LOG("force_rank", "force_rank.getEnclaveObjId -- source is invalid.");
return false;
}
if (handler == null || handler.length() < 1)
{
LOG("force_rank", "force_rank.getEnclaveObjId -- handler value of " + handler + " is invalid.");
return false;
}
_updateForceRankData(source, council, 6, "None", handler, false);
return true;
}
/***********************************************************************
* @brief returns a list of members for a specified rank given the
* clusterwide dictionary. Removes the empty slots
*
* @param dictionary enclave_data clusterwide dictionary
* @param int rank
*
* @return return string[] Returns null on error, empty list on
* all empty slots.
*********************************************************************/
resizeable string[] getRankMembersFromDictionary(dictionary enclave_data, int rank)
{
if (enclave_data == null)
{
LOG("force_rank", "force_rank.getRankMembersFromDictionary -- enclave data is null.");
return null;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.getRankMembersFromDictionary -- rank value of " + rank + " is invalid.");
return null;
}
string key_name = VAR_RANK_BASE + rank + "-";
int slots = MAX_RANK_SLOTS;
resizeable string[] rank_list = new string[0];
for (int i = 0; i < slots; i++)
{
if (enclave_data.containsKey(key_name + i))
{
string name = enclave_data.getString(key_name + i);
if (name != null && name.length() > 0)
rank_list = utils.addElement(rank_list, name);
}
}
return rank_list;
}
/***********************************************************************
* @brief returns the list of top players in the pvp rankings
*
* @param obj_id enclave
*
* @return return boolean list of player first names, null on error
*********************************************************************/
string[] getPvpBoardNames(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getPvpBoardNames -- enclave is invalid.");
return null;
}
if (hasObjVar(enclave, BATCH_VAR_PVPBOARD_NAME))
{
string[] names = utils.getStringBatchObjVar(enclave, BATCH_VAR_PVPBOARD_NAME);
if (names == null)
return null;
// Pull out empty slots
resizeable string[] final_list = new string[0];
for (int i = 0; i < names.length; i++)
{
if (names[i] != null && names[i].length() > 0 && !names[i].equals(EMPTY_SLOT))
final_list = utils.addElement(final_list, names[i]);
}
if (final_list.length > 0)
return final_list;
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief returns the list of top players in the pvp rankings
*
* @param obj_id enclave
*
* @return return string[] list of player first names, null on error
* or no players
*********************************************************************/
int[] getPvpBoardRatings(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getPvpBoardRatings -- enclave is invalid.");
return null;
}
if (hasObjVar(enclave, BATCH_VAR_PVPBOARD_RATING))
{
int[] ratings = utils.getIntBatchObjVar(enclave, BATCH_VAR_PVPBOARD_RATING);
if (ratings == null)
return null;
// Pull out empty slots
resizeable int[] final_list = new string[0];
for (int i = 0; i < ratings.length; i++)
{
if (ratings[i] > 0)
final_list = utils.addElement(final_list, ratings[i]);
}
if (final_list.length > 0)
return final_list;
else
return null;
}
else
return null;
}
/***********************************************************************
* @brief returns the list of top players in the pvp rankings
*
* @param obj_id enclave
*
* @return return int -1 on error or no ranking
*********************************************************************/
int getPvpRankingForPlayer(obj_id enclave, string player_name)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.getPvpRatingForPlayer -- enclave is invalid.");
return -1;
}
if (player_name == null)
{
LOG("force_rank", "force_rank.getPvpRatingForPlayer -- player_name is null.");
return -1;
}
resizeable string[] pvp_board_names = utils.getResizeableStringBatchObjVar(enclave, BATCH_VAR_PVPBOARD_NAME);
return pvp_board_names.indexOf(player_name);
}
/***********************************************************************
* @brief returns the pvp board data for a given council.
* The information is returned via the clusterwide data system.
*
* @param obj_id source Object requesting the data
* @param int council
* @param string handler Handler to which to return the data.
*
* @return return boolean data is returned in the specified handler
* as "board_names" and "board_ratings"
*********************************************************************/
boolean getPvpBoardRatings(obj_id source, int council, string handler)
{
if (!isIdValid(source))
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- source is invalid.");
return false;
}
if (handler == null || handler.length() < 1)
{
LOG("force_rank", "force_rank.getPlayersInForceRank -- handler value of " + handler + " is invalid.");
return false;
}
_updateForceRankData(source, council, 2, Integer.toString(0), handler, false);
return true;
}
/***********************************************************************
* @brief updates the pvp boards with the new data that is specified.
*
* @param obj_id player Player to updated
* @param int rating Player's new rating
* @param int council
* @param string handler Handler to which to return success/fail.
*
* @return return boolean The player's new pvp rank is returned
* in the specified handler as "pvp_rank"
*********************************************************************/
boolean updatePvpBoardData(obj_id player, int rating, int council, string handler)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.updatePvpBoardData -- player is invalid.");
return false;
}
if (handler == null || handler.length() < 1)
{
LOG("force_rank", "force_rank.updatePvpBoardData -- handler value of " + handler + " is invalid.");
return false;
}
_updateForceRankData(player, council, 7, Integer.toString(rating), handler, true);
return true;
}
/***********************************************************************
* @brief Adjusts the pvp board data based on the new player data
* given.
*
* @param obj_id player Player to update
* @param int rating Player's rating
* @param dictionary enclave_data from the clusterwide data system.
*
* @return return dictionary The clusterwide data with the updated boards
* null on no change
*********************************************************************/
dictionary adjustPvpBoardRankings(obj_id player, int player_rating, dictionary enclave_data)
{
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.adjustPvpBoardRankings -- player is invalid.");
return null;
}
if (enclave_data == null)
{
LOG("force_rank", "force_rank.adjustPvpBoardRankings -- enclave_data is null.");
return null;
}
resizeable string[] board_names = new string[0];
resizeable int[] board_ratings = new int[0];
for (int i = 0; i < PVP_BOARD_SIZE; i++)
{
string key_name = BATCH_VAR_PVPBOARD_NAME + i;
string key_rating = BATCH_VAR_PVPBOARD_RATING + i;
if (enclave_data.containsKey(key_name) && enclave_data.containsKey(key_rating))
{
string name = enclave_data.getString(key_name);
int rating = enclave_data.getInt(key_rating);
if (name != null && name.length() > 0 && !name.equals(EMPTY_SLOT) && rating > 0)
{
board_names = utils.addElement(board_names, name);
board_ratings = utils.addElement(board_ratings, rating);
}
}
}
boolean empty_slots = board_names.length < PVP_BOARD_SIZE;
boolean on_board = false;
int current_board_idx = board_names.indexOf(utils.getRealPlayerFirstName(player));
if (current_board_idx != -1)
on_board = true;
// The rankings stay sorted with the highest at 0 and lowest as last element
if (!empty_slots && !on_board)
{
// If the player isn't on the board and has a rating less than the last spot, stop right here.
if (player_rating < board_ratings[board_ratings.length])
return null;
}
// Find the player's new position on the board.
int new_board_idx = -1;
for (int i = 0; i < board_ratings.length; i++)
{
if (board_ratings[i] < player_rating)
{
new_board_idx = i;
break;
}
}
if (new_board_idx == -1)
{
if (!on_board && empty_slots)
{
board_names.add(utils.getRealPlayerFirstName(player));
board_ratings.add(utils.getRealPlayerFirstName(player));
}
else
return null;
}
else
{
if (on_board)
{
if (current_board_idx == new_board_idx)
return null;
// Remove the player from his old position.
board_names.remove(current_board_idx);
board_ratings.remove(current_board_idx);
}
// Add the player to his new position.
board_names.add(new_board_idx, utils.getRealPlayerFirstName(player));
board_ratings.add(new_board_idx, new Integer(player_rating));
}
// Trim the board down to its maximum size.
if (board_names.length > PVP_BOARD_SIZE)
{
board_names.setSize(PVP_BOARD_SIZE);
board_ratings.setSize(PVP_BOARD_SIZE);
}
// Update the dictionary.
for (int i = 0; i < board_names.length; i++)
{
string key_name = BATCH_VAR_PVPBOARD_NAME + i;
string key_rating = BATCH_VAR_PVPBOARD_RATING + i;
enclave_data.put(key_name, board_names[i]);
enclave_data.put(key_rating, board_ratings[i]);
}
return enclave_data;
}
/***********************************************************************
* @brief sends a mail message to everyone in the specified rank
* requires an authoritative enclave.
*
* @param obj_id enclave
* @param int rank
* @param string_id subject
* @param prose_package body
*
* @return return boolean
*********************************************************************/
boolean sendRankMail(obj_id enclave, int rank, string_id subject, prose_package body)
{
LOG("force_rank", "force_rank.sendRankMail -- " + rank);
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.sendRankMail -- enclave is invalid.");
return false;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.sendRankMail -- illegal value for rank: " + rank);
return false;
}
string[] rank_list = getPlayersInForceRank(enclave, rank);
if (rank_list != null)
{
for (int i = 0; i < rank_list.length; i++)
{
LOG("force_rank", "rank_list[" + i + "] ->" + rank_list[i]);
utils.sendMail(subject, body, rank_list[i], "Enclave Records");
}
}
return true;
}
/***********************************************************************
* @brief sends a mail message to everyone qualified to vote in
* the specified rank.
*
* @param obj_id enclave
* @param int rank rank which voting is for.
* @param string_id subject
* @param prose_package body
*
* @return return boolean
*********************************************************************/
boolean sendVoterMail(obj_id enclave, int rank, string_id subject, prose_package body)
{
//LOG("force_rank", "force_rank.sendVoterMail");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.sendVoterMail -- enclave is invalid.");
return false;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.sendVoterMail -- illegal value for rank: " + rank);
return false;
}
// Iterate through all 12 ranks check each to see if it's eligible to vote.
for (int i = 0; i < 12; i++)
{
LOG("force_rank", "vote weight[" + i + "] ->" + getVoteWeight(i, rank));
if (getVoteWeight(i, rank) > 0)
{
sendRankMail(enclave, i, subject, body);
}
}
return true;
}
/***********************************************************************
* @brief sends a mail message to everyone qualified to vote in
* a no-confidence challenge of the specified rank.
*
* @param obj_id enclave
* @param int rank rank which voting is for.
* @param string_id subject
* @param prose_package body
*
* @return return boolean
*********************************************************************/
boolean sendChallengeVoterMail(obj_id enclave, int rank, string_id subject, prose_package body)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.sendChallengeVoterMail -- enclave is invalid.");
return false;
}
if (rank < 1 || rank > 11)
{
LOG("force_rank", "force_rank.sendChallengeVoterMail -- illegal value for rank: " + rank);
return false;
}
for (int i = 0; i < 12; i++)
{
if (getChallengeVoteWeight(i, rank) > 0)
sendRankMail(enclave, i, subject, body);
}
return true;
}
/***********************************************************************
* @brief resets the enclave's data, clearing everything
*
* @param obj_id enclave
*
* @return return boolean
*********************************************************************/
boolean resetEnclaveData(obj_id enclave)
{
LOG("force_rank", "force_rank.resetEnclaveData");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.resetEnclaveData -- enclave is invalid.");
return false;
}
for (int i = 1; i < 12; i++)
{
int slots = force_rank.getForceRankNumSlots(i);
if (slots > 0)
{
string[] rank_list = new string[slots];
Arrays.fill(rank_list, EMPTY_SLOT);
setObjVar(enclave, force_rank.VAR_RANK_BASE + i, rank_list);
}
}
return true;
}
/***********************************************************************
* @brief replaces the enclave's clusterwide data.
*
* @param obj_id enclave
* @param int lock_key if the data is to be locked.
*
* @return return boolean
*********************************************************************/
boolean replaceEnclaveClusterData(obj_id enclave, int lock_key)
{
LOG("force_rank", "force_rank.replaceEnclaveClusterData");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.replaceEnclaveClusterData -- enclave is invalid.");
return false;
}
int council = force_rank.getCouncilAffiliation(enclave);
if (council == -1)
{
LOG("force_rank", "enclave_controller.replaceEnclaveData -- " + enclave + " has an invalid council value.");
return false;
}
if (lock_key < 0)
lock_key = 0;
dictionary enclave_info = new dictionary();
LOG("force_rank", "force_rank.replaceEnclaveClusterData -- 1");
// Add the enclave's obj_id
enclave_info.put(VAR_ENCLAVE, enclave);
// Get the rank info
for (int i = 1; i < 12; i++)
{
// We want to keep the "empty" slots when updating the cluster wide data.
string[] rank_members = getStringArrayObjVar(enclave, VAR_RANK_BASE + i);
if (rank_members != null)
{
for (int j = 0; j < rank_members.length; j++)
{
string key = force_rank.VAR_RANK_BASE + i + "-" + j;
enclave_info.put(key, rank_members[j]);
//LOG("force_rank", "key ->" + key + " member ->" + rank_members[j]);
}
}
}
LOG("force_rank", "force_rank.replaceEnclaveClusterData -- 2");
/*
// Get the leaderboard info
string[] board_names = getPvpBoardNames(enclave);
int[] board_ratings = getPvpBoardRatings(enclave);
if (board_names != null && board_names.length > 0 && board_ratings != null && board_ratings.length > 0)
{
if (board_names.length > board_ratings.length)
{
LOG("force_rank", "enclave_controller.replaceEnclaveData -- PvPBoard array lengths do not match. Resetting board for enclave " + enclave);
removeObjVar(enclave, BATCH_VAR_PVPBOARD_NAME);
removeObjVar(enclave, BATCH_VAR_PVPBOARD_RATING);
}
else
{
for (int i = 0; i < board_names.length; i++)
{
enclave_info.put(BATCH_VAR_PVPBOARD_NAME + i, board_names[i]);
enclave_info.put(BATCH_VAR_PVPBOARD_RATING + i, board_ratings[i]);
//LOG("force_rank", "name ->" + board_names[i] + " rating ->" + board_ratings[i]);
}
}
}
LOG("force_rank", "force_rank.replaceEnclaveClusterData -- 3");
*/
replaceClusterWideData(CLUSTER_DATA_NAME, STRING_CLUSTER_ENCLAVE_NAME + council, enclave_info, false, lock_key);
return true;
}
/***********************************************************************
* @brief writes the latest clusterwide data to the enclave
*
* @param obj_id enclave
* @param dictionary enclave_data Data to write out as given by
* OnClusterWideDataResponse.
*
* @return return boolean
*********************************************************************/
boolean updateEnclaveClusterData(obj_id enclave, dictionary enclave_data)
{
LOG("force_rank", "force_rank.updateEnclaveClusterData");
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.replaceEnclaveData -- enclave is invalid.");
return false;
}
if (enclave_data == null)
{
LOG("force_rank", "force_rank.replaceEnclaveData -- enclave_data is null for " + enclave);
return false;
}
//LOG("force_rank", "data ->" + enclave_data);
// Initialize the rank arrays.
//string[][] ranks = new string[11][MAX_RANK_SLOTS];
Object[] ranks = new Object[11];
for (int i = 0; i < ranks.length; i++)
ranks[i] = new Vector();
// Initialize the PvP Board arrays
string[] pvp_board_name = new string[PVP_BOARD_SIZE];
Arrays.fill(pvp_board_name, EMPTY_SLOT);
int[] pvp_board_rating = new int[PVP_BOARD_SIZE];
// Enumerate through the dictionary and write everything out.
java.util.Enumeration e = enclave_data.keys();
while (e.hasMoreElements())
{
string key_name = (string)(e.nextElement());
if (key_name.length() > 0)
{
//LOG("force_rank", "key_name ->" + key_name);
if (key_name.startsWith(VAR_RANK_BASE))
{
// Rank lists are stored in the format RANK#-slot
java.util.StringTokenizer st = new java.util.StringTokenizer(key_name, "-");
if (st.countTokens() != 2)
continue;
string prefix = st.nextToken();
string slot = st.nextToken();
int slot_number = utils.stringToInt(slot);
if (slot_number < 0)
continue;
// Split the prefix to get the rank #
java.util.StringTokenizer st2 = new java.util.StringTokenizer(prefix, VAR_RANK_BASE);
if (st2.countTokens() != 1)
continue;
string prefix_rank = st2.nextToken();
int rank = utils.stringToInt(prefix_rank);
if (rank < 1)
continue;
//LOG("force_rank", " rank ->" + rank + " slot_number ->" + slot_number);
Vector edit_list = (Vector)(ranks[rank-1]);
edit_list.add(enclave_data.getString(key_name));
}
if (key_name.startsWith(BATCH_VAR_PVPBOARD_NAME))
{
// The PvP board is stored as Name#
java.util.StringTokenizer st = new java.util.StringTokenizer(key_name, BATCH_VAR_PVPBOARD_NAME);
if (st.countTokens() != 1)
continue;
string slot = st.nextToken();
int slot_number = utils.stringToInt(slot);
if (slot_number < 0)
continue;
pvp_board_name[slot_number] = enclave_data.getString(key_name);
pvp_board_rating[slot_number] = enclave_data.getInt(BATCH_VAR_PVPBOARD_RATING + slot);
}
}
}
// Write everything out.
for (int i = 0; i < ranks.length; i++)
{
Object obj_list = ranks[i];
Vector vec_list = (Vector) obj_list;
string[] rank_list = new string[vec_list.size()];
vec_list.toArray(rank_list);
setObjVar(enclave, VAR_RANK_BASE + (i + 1), rank_list);
}
//utils.setBatchObjVar(enclave, BATCH_VAR_PVPBOARD_NAME, pvp_board_name);
//utils.setBatchObjVar(enclave, BATCH_VAR_PVPBOARD_RATING, pvp_board_rating);
// Update the permissions list.
//LOG("force_rank", "force_rank.updateEnclaveClusterData -- updateAllRoomPermissions " + enclave);
//updateAllRoomPermissions(enclave);
return true;
}
/***********************************************************************
* @brief creates a back-up of the ranking data
*
* @param obj_id enclave
*
* @return return boolean
*********************************************************************/
boolean backupEnclaveData(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.backupEnclaveData -- enclave is invalid.");
return false;
}
for (int i = 1; i < 12; i++)
{
string[] rank_list = getStringArrayObjVar(enclave, VAR_RANK_BASE + i);
if (rank_list != null && rank_list.length > 0)
setObjVar(enclave, "bk_" + VAR_RANK_BASE + i, rank_list);
}
// set the new timestamp
setObjVar(enclave, VAR_BACKUP_TIME, getGameTime());
return true;
}
/***********************************************************************
* @brief restores an enclave's data from back-up
*
* @param obj_id enclave
*
* @return return boolean
*********************************************************************/
boolean restoreEnclaveData(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.restoreEnclaveData -- enclave is invalid.");
return false;
}
for (int i = 1; i < 12; i++)
{
string[] rank_list = getStringArrayObjVar(enclave, "bk_" + VAR_RANK_BASE + i);
if (rank_list != null && rank_list.length > 0)
setObjVar(enclave, VAR_RANK_BASE + i, rank_list);
}
return true;
}
/***********************************************************************
* @brief logs the enclaves current data to the customer service log.
*
* @param obj_id enclave
*
* @return return boolean
*********************************************************************/
boolean logEnclaveData(obj_id enclave)
{
if (!isIdValid(enclave))
{
LOG("force_rank", "force_rank.logEnclaveData -- enclave is invalid.");
return false;
}
int council = getCouncilAffiliation(enclave);
if (council == -1)
{
LOG("force_rank", "force_rank.logEnclaveData -- " + enclave + " does not have a council affiliation.");
return false;
}
for (int i = 0; i < 12; i++)
{
string[] rank_list = getPlayersInForceRank(enclave, i);
if (rank_list != null)
{
for (int j = 0; j < rank_list.length; j++)
{
if (rank_list[j] != null)
{
obj_id player = getPlayerIdFromFirstName(rank_list[j]);
CustomerServiceLog("force_rank", COUNCIL_NAMES[council] + " Data: " + rank_list[j] + "(" + player + ") is at rank " + i);
}
}
}
}
return true;
}
/***********************************************************************
* @brief removes the first empty slot in the enclave data dictionary
* for the given rank. This is used to remove extra slots
* that were created to make room for demotions.
*
* @param dictionary enclave_data from the clusterwide data
* @param int rank
*
* @return return dictionary
*********************************************************************/
dictionary removeExtraSlotFromRankList(dictionary enclave_data, int rank)
{
//LOG("force_rank", "!!!!!!!!!force_rank.removeExtraSlotFromRankList!!!!!!!!!!!!!");
if (enclave_data == null)
{
LOG("force_rank", "force_rank.removeEntryFromRankList -- enclave is null.");
return null;
}
int max_slots = getForceRankNumSlots(rank);
if (max_slots < 1)
{
LOG("force_rank", "force_rank.removeEntryFromRankList -- invalid max slot data from " + rank);
return null;
}
resizeable string[] rank_list = getRankMembersFromDictionary(enclave_data, rank);
if (rank_list != null)
{
int slots_to_remove = rank_list.length - max_slots;
int rank_length = rank_list.size();
//LOG("force_rank", "rank_list.length ->" + rank_list.length + " max_slots ->" + max_slots);
//LOG("force_rank", "rank ->" + rank + " slots_to_remove ->" + slots_to_remove);
if (slots_to_remove < 1)
{
LOG("force_rank", "force_rank.removeEntryFromRankList -- there are not slots to remove.");
return null;
}
string key_name = force_rank.VAR_RANK_BASE + rank + "-";
int data_idx = 0;
for (int i = 0; i < rank_list.length; i++)
{
//LOG("force_rank", "rank_list[" + i + "] ->" + rank_list[i] + " data_idx ->" + data_idx + " slots ->" + slots_to_remove);
if (slots_to_remove > 0)
{
if (rank_list[i] == null || rank_list[i].length() < 1 || rank_list[i].equals(EMPTY_SLOT))
{
//rank_list.remove(i);
rank_length--;
slots_to_remove--;
continue;
}
}
//LOG("force_rank", "key ->" + (key_name + data_idx) + " ranklist[" + i +"] ->" + rank_list[i]);
enclave_data.put(key_name + data_idx, rank_list[i]);
data_idx++;
}
// remove the extra keys from the dictionary
for (int i = rank_length; i <= MAX_RANK_SLOTS; i++)
{
string key_remove = force_rank.VAR_RANK_BASE + rank + "-" + i;
if (enclave_data.containsKey(key_remove))
enclave_data.remove(key_remove);
}
return enclave_data;
}
else
{
LOG("force_rank", "force_rank.removeEntryFromRankList -- rank_list is null.");
return null;
}
}
/***********************************************************************
* @brief Grants items to the player for achieving a given rank
*
* @param obj_id player
*
* @return return boolean
*********************************************************************/
boolean grantRankItems(obj_id player, boolean retroactive)
{
/*
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.grantRankItems -- player is invalid.");
return false;
}
int rank = getForceRank(player);
if (rank < 0)
{
LOG("force_rank", "force_rank.grantRankItems -- " + player + " does not have a rank.");
return false;
}
int council = getCouncilAffiliation(player);
if (council < 1)
{
LOG("force_rank", "force_rank.grantRankItems -- " + player + " does not have a council affiliation.");
return false;
}
int index = 0;
if (!retroactive)
{
index = dataTableSearchColumnForInt(rank, "rank", ENCLAVE_REWARDS_DATATABLE);
if (index == -1)
return false;
}
obj_id inv = getObjectInSlot(player, "inventory");
if (!isIdValid(inv))
{
LOG("force_rank", "force_rank.grantRankItems -- " + player + " has an invalid inventory.");
return false;
}
for (int i = index; i < dataTableGetNumRows(ENCLAVE_REWARDS_DATATABLE); i++)
{
dictionary row = dataTableGetRow(ENCLAVE_REWARDS_DATATABLE, i);
int row_rank = row.getInt("rank");
if (retroactive)
{
if (row_rank > rank)
break;
}
else
{
if (row_rank != rank)
break;
}
int row_council = row.getInt("council");
if (council == row_council)
{
string item = row.getString("item");
if (item != null && item.length() > 0)
{
int free_space = getVolumeFree(inv);
if (free_space < 1)
break;
obj_id created_object = createObject(item, inv, "");
if (isIdValid(created_object))
CustomerServiceLog("force_rank", "Granting item " + getTemplateName(created_object) + " (" + created_object + ") to %TU for reaching rank " + rank, player, null);
}
}
}
return true;
*/
return false;
}
boolean grantRankItems(obj_id player)
{
return grantRankItems(player, false);
}
/***********************************************************************
* @brief Performs the effects for an FRS attack
*
* @param obj_id player
* @param obj_id defender
* @param hit_result results
* @param weapon_data weapondat
*
* @return return boolean
*********************************************************************/
boolean performFRSAttack(obj_id player, obj_id defender, hit_result results, weapon_data weapondat)
{
//LOG("force_rank", "force_rank.performFRSAttack");
if (!isIdValid(player))
{
LOG("force_rank", "force_rank.performFRSAttack -- player is invalid.");
return false;
}
if (!isIdValid(defender))
{
LOG("force_rank", "force_rank.performFRSAttack -- defender is invalid.");
return false;
}
if (results == null)
{
LOG("force_rank", "force_rank.performFRSAttack -- results is null.");
return false;
}
if (weapondat == null)
{
LOG("force_rank", "force_rank.performFRSAttack -- weapondat is null.");
return false;
}
if (!isPlayer(player))
return false;
int council = getCouncilAffiliation(player);
if (council < 1)
{
LOG("force_rank", "force_rank.performFRSAttack -- " + player + " has an invalid council affiliation.");
return false;
}
int damage = results.damage;
obj_id weapon_id = weapondat.id;
// Dark FRS powers
if (council == 1)
{
int envy_rating = getEnhancedSkillStatisticModifier(player, "frs_dark_envy");
//LOG("force_rank", "envy_rating ->" + envy_rating);
if (envy_rating > 0)
performFRSAttackEnvy(player, defender, weapon_id, damage, envy_rating);
int suffering_rating = getEnhancedSkillStatisticModifier(player, "frs_dark_suffering");
//LOG("force_rank", "suffering_rating ->" + suffering_rating);
if (suffering_rating > 0)
performFRSAttackSuffering(player, defender, weapon_id, damage, suffering_rating);
}
else
{
// Light FRS powers
int vigilance_rating = getEnhancedSkillStatisticModifier(player, "frs_light_vigilance");
if (vigilance_rating > 0)
performFRSAttackVigilance(player, defender, weapon_id, damage, vigilance_rating);
int wisdom_rating = getEnhancedSkillStatisticModifier(player, "frs_light_wisdom");
if (wisdom_rating > 0)
performFRSAttackWisdom(player, defender, weapon_id, damage, wisdom_rating);
}
return true;
}
/***********************************************************************
* @brief Performs the Envy attack effect. Envy drains force power
* from the defender and gives a little of it to the wielder
*
* @param obj_id player
* @param obj_id defender
* @param obj_id weapon
* @param int damage
* @param int rating
*
* @return return boolean
*********************************************************************/
boolean performFRSAttackEnvy(obj_id player, obj_id defender, obj_id weapon, int damage, int rating)
{
//LOG("force_rank", "1force_rank.performFRSAttackEnvy");
// Envy only works on Jedi
if (!isJedi(player))
return false;
if (damage < 1)
return false;
if (rating > 100)
rating = 100;
// Calculate the drain amount.
int drain = (int)(damage * ((float)rating / 200.0f));
if (drain < 1)
drain = 1;
// Calculate the return amount
int gain = (int)(drain * ((float)rating / 100.0f));
if (gain < 1)
gain = 1;
if (!jedi.hasForcePower(defender, drain))
{
drain = getForcePower(defender);
if (drain == 0)
return false;
}
//LOG("force_rank", "damage ->" + damage + " gain ->" + gain + " drain ->" + drain);
//LOG("force_rank", "Force power ->" + getForcePower(player) + " / " + getForcePower(defender));
alterForcePower(defender, -drain);
alterForcePower(player, gain);
//LOG("force_rank", "Force power ->" + getForcePower(player) + " / " + getForcePower(defender));
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "frs_dark_envy_drain");
pp.actor.set(player);
pp.target.set(defender);
pp.digitInteger = drain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, true, false);
pp.stringId = new string_id("cbt_spam", "frs_dark_envy_gain");
pp.digitInteger = gain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, false, false);
playClientEffectLoc(player, "clienteffect/frs_dark_envy.cef" , getLocation(defender), 1.5f);
return true;
}
/***********************************************************************
* @brief Performs the Suffering attack effect. Suffering debuffs
* a player's secondary and tertiary health and action stats.
*
* @param obj_id player
* @param obj_id defender
* @param obj_id weapon
* @param int damage
* @param int rating
*
* @return return boolean
*********************************************************************/
boolean performFRSAttackSuffering(obj_id player, obj_id defender, obj_id weapon, int damage, int rating)
{
//LOG("force_rank", "force_rank.performFRSAttackSuffering");
if (isJedi(defender))
{
// If the defender still has force power, he isn't affected by this.
if (getForcePower(defender) > 0)
return false;
}
int drain = (int)(damage * ((float)rating / 300.0f));
if (drain < 1)
drain = 1;
int current_val = 0;
int[] attribs = {1, 2, 4, 5};
for (int i = 0; i < attribs.length; i++)
{
int current_attrib = getAttrib(defender, attribs[i]);
if (current_attrib - 1 <= drain)
{
drain = current_attrib - 1;
if (drain < 1)
continue;
}
// If the modifier already exists, add the new one in.
if (hasAttribModifier(defender, "force_rank.suffering_" + attribs[i]))
{
attrib_mod[] mods = getAttribModifiers(defender, attribs[i]);
for (int j = 0; j < mods.length; j++)
{
string name = mods[j].getName();
if (name != null && name.equals("force_rank.suffering_" + attribs[i]))
{
int val = mods[j].getValue();
//LOG("force_rank", "name ->" + name + " val ->" + val);
if (val != 0)
{
removeAttribOrSkillModModifier(defender, "force_rank.suffering_" + attribs[i]);
current_val = Math.abs(val);
}
break;
}
}
}
//LOG("force_rank", "drain ->" + drain + current_val);
addAttribModifier(defender, "force_rank.suffering_" + attribs[i], attribs[i], -(drain + current_val), DEBUFF_DURATION, 0.0f, 0.0f, false, false, false);
}
// Add one buff icon for the collective debuff.
addBuffIcon(defender, "force_rank.suffering", DEBUFF_DURATION);
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "frs_dark_suffering");
pp.actor.set(player);
pp.target.set(defender);
pp.digitInteger = drain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, true, false);
return true;
}
/***********************************************************************
* @brief Performs the Vengeance attack effect. Vengeance causes
* wounds to those that damage the Jedi.
*
* @param obj_id player
* @param obj_id defender
* @param int damage
* @param int rating
*
* @return return boolean
*********************************************************************/
boolean performFRSAttackVengeance(obj_id player, obj_id defender, int damage, int rating)
{
/*
int wound = (int)(damage * ((float)rating / 200.0f));
//LOG("force_rank", "damage ->" + damage + " rating ->" + rating + " wound ->" + wound);
addWound(defender, HEALTH, wound);
addWound(defender, ACTION, wound);
addWound(defender, MIND, wound);
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "frs_dark_vengeance");
pp.actor.set(player);
pp.target.set(defender);
pp.digitInteger = wound;
combat.sendCombatSpamMessageProse(player, defender, pp, true, true, false);
*/
playClientEffectLoc(player, "clienteffect/frs_dark_vengeance.cef" , getLocation(defender), 1.5f);
return true;
}
/***********************************************************************
* @brief Performs the Vigilance attack effect. Vigiliance damages
* the defender's force power.
*
* @param obj_id player
* @param obj_id defender
* @param obj_id weapon
* @param int damage
* @param int rating
*
* @return return boolean
*********************************************************************/
boolean performFRSAttackVigilance(obj_id player, obj_id defender, obj_id weapon, int damage, int rating)
{
//LOG("force_rank", "1force_rank.performFRSAttackVigilance");
// Envy only works on Jedi
if (!isJedi(player))
return false;
if (damage < 1)
return false;
if (rating > 100)
rating = 100;
// Calculate the drain amount.
int drain = (int)(damage * ((float)rating / 100.0f));
if (drain < 1)
drain = 1;
if (!jedi.hasForcePower(defender, drain))
{
drain = getForcePower(defender);
if (drain == 0)
return false;
}
alterForcePower(defender, -drain);
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "frs_light_vigilance");
pp.actor.set(player);
pp.target.set(defender);
pp.digitInteger = drain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, true, false);
playClientEffectLoc(player, "clienteffect/frs_light_vigilance.cef" , getLocation(defender), 1.5f);
return true;
}
/***********************************************************************
* @brief Performs the Wisdom attack effect. Wisdom drains pools
* and adds them to the Jedi.
*
* @param obj_id player
* @param obj_id defender
* @param obj_id weapon
* @param int damage
* @param int rating
*
* @return return boolean
*********************************************************************/
boolean performFRSAttackWisdom(obj_id player, obj_id defender, obj_id weapon, int damage, int rating)
{
//LOG("force_rank", "force_rank.performFRSAttackWisdom");
if (isJedi(defender))
{
// If the defender still has force power, he isn't affected by this.
if (getForcePower(defender) > 0)
return false;
}
int drain = (int)(damage * ((float)rating / 200.0f));
if (drain < 1)
drain = 1;
int gain = (int)(drain * ((float)rating / 100.0f));
if (gain < 1)
gain = 1;
for (int i = 0; i < 3; i++)
{
// drain mod pools from the defender and give them to the Jedi.
addAttribModifier(defender, i*3, -drain, 0.0f, 0.0f, MOD_POOL);
addAttribModifier(player, i*3, gain, 0.0f, 0.0f, MOD_POOL);
}
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "frs_light_wisdom_drain");
pp.actor.set(player);
pp.target.set(defender);
pp.digitInteger = drain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, true, false);
pp.stringId = new string_id("cbt_spam", "frs_light_wisdom_gain");
pp.digitInteger = gain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, false, false);
playClientEffectLoc(player, "clienteffect/frs_light_wisdom.cef" , getLocation(defender), 1.5f);
return true;
}
/***********************************************************************
* @brief Performs the Serenity attack effect. Serenity debuffs
* those that attack the Jedi.
*
* @param obj_id player
* @param obj_id defender
* @param int damage
* @param int rating
*
* @return return boolean
*********************************************************************/
boolean performFRSAttackSerenity(obj_id player, obj_id defender, int damage, int rating)
{
int drain = (int)(damage * ((float)rating / 400.0f));
if (drain < 1)
drain = 1;
int current_val = 0;
int[] attribs = {1, 3, 6};
for (int i = 0; i < attribs.length; i++)
{
int current_attrib = getAttrib(defender, attribs[i]);
if (current_attrib - 1 <= drain)
{
drain = current_attrib - 1;
if (drain < 1)
continue;
}
// If the modifier already exists, add the new one in.
if (hasAttribModifier(defender, "force_rank.serenity_" + attribs[i]))
{
attrib_mod[] mods = getAttribModifiers(defender, attribs[i]);
for (int j = 0; j < mods.length; j++)
{
string name = mods[j].getName();
if (name != null && name.equals("force_rank.serenity_" + attribs[i]))
{
int val = mods[j].getValue();
//LOG("force_rank", "name ->" + name + " val ->" + val);
if (val != 0)
{
removeAttribOrSkillModModifier(defender, "force_rank.serenity_" + attribs[i]);
current_val = Math.abs(val);
}
break;
}
}
}
//LOG("force_rank", "drain ->" + drain + current_val);
addAttribModifier(defender, "force_rank.serenity_" + attribs[i], attribs[i], -(drain + current_val), DEBUFF_DURATION, 0.0f, 0.0f, false, false, false);
}
// Add one buff icon for the collective debuff.
addBuffIcon(defender, "force_rank.serenity", DEBUFF_DURATION);
prose_package pp = new prose_package();
pp.stringId = new string_id("cbt_spam", "frs_light_serenity");
pp.actor.set(player);
pp.target.set(defender);
pp.digitInteger = drain;
combat.sendCombatSpamMessageProse(player, defender, pp, true, true, false);
playClientEffectLoc(player, "clienteffect/frs_light_serenity.cef" , getLocation(defender), 1.5f);
return true;
}
//
// gets called from enclave_controller::msgVictimizedJediDeath as a result of dark jedi being killed (partially) by another dark jedi
// @params is a list of the @@victim, @@totalDamageToVictim and a number of @winnerObjId/@percentContributionFloat pairs
//
void handleCondemnedPlayerDeath(obj_id darkEnclave, dictionary params)
{
trace.log("force_rank", "force_rank::handledCondemnedPlayerDeath: -> Enter method");
if(!params.containsKey("victim") || !params.containsKey("totalDamageToVictim"))
{
trace.log("force_rank", "force_rank::handleCondemnedPlayerDeath: -> Missing vital params 'victim' and 'totalDamageToVictim'. Not validating Dark Jedi PvP ACTION death.", darkEnclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
// grab data from params
obj_id victim = params.getObjId("victim");
params.remove("victim");
int totalDamageTally = params.getInt("totalDamageToVictim");
params.remove("totalDamageToVictim");
java.util.Enumeration pKeys = params.keys();
obj_id[] winners = new obj_id[params.size()];
float[] contributions = new float[winners.length];
int s = 0;
float totalDarkJediDeathContrib = 0;
while(pKeys.hasMoreElements())
{
obj_id key = (obj_id)pKeys.nextElement();
winners[s] = key;
contributions[s] = params.getFloat(key);
totalDarkJediDeathContrib += contributions[s];
s++;
}
// setup data for the winners loop
resizeable obj_id[] suddenDeathWinners = new obj_id[0];
resizeable float[] suddenDeathContribs = new float[0];
boolean suddenDeath = false;
boolean demoteToZero = false;
obj_id curPlayer = null;
float totSDContribs = 0;
dictionary suddenDeathData = getAndValidatePvPActionData(ACTION_CANDIDATE_SUDDEN_DEATH, darkEnclave);
dictionary vendettaData = getAndValidatePvPActionData(ACTION_VENDETTA, darkEnclave);
dictionary banishmentData = getAndValidatePvPActionData(ACTION_BANISHMENT, darkEnclave);
dictionary purgeData = getAndValidatePvPActionData(ACTION_PURGE_COUNCIL, darkEnclave);
// we need to check against sudden death and vendetta data for each winner
for(int i = 0; i < winners.length; i++)
{
curPlayer = winners[i];
// check if this winner is part of sudden death rank
if(suddenDeathData != null)
{
if(bothArePartOfSameSuddenDeathRank(victim, curPlayer, darkEnclave, suddenDeathData))
{
suddenDeath = true; // victim will relinquish any votes + forfeit their petition
utils.addElement(suddenDeathWinners, curPlayer);
utils.addElement(suddenDeathContribs, contributions[i]); // need these to divy up the votes according to contribution
totSDContribs += contributions[i]; // keep a running total of the total contributions by sudden death winners
}
}
// check for vendetta against/from curPlayer. no need to check again if we're already getting demoted to zero though...
if(vendettaData != null && !demoteToZero)
{
if(isPartOfSameVendetta(victim, curPlayer, vendettaData))
{
demoteToZero = true;
}
}
}
// check if we're a banishment victim
if(banishmentData != null && !demoteToZero)
{
if(isPvPActionVictim(victim, banishmentData))
{
demoteToZero = true;
}
}
// and finally check for council purge
if(purgeData != null && !demoteToZero)
{
if(isPvPActionVictim(victim, purgeData))
{
demoteToZero = true;
}
}
// divy up the victim's votes, if necessary
if(suddenDeath)
{
float curContrib = 0.0f;
int victimsVotes = getVotesForPlayer(victim, darkEnclave);
int curWinnerVotes = 0;
if(victimsVotes > 0)
{
setVotesForPlayer(victim, 0, darkEnclave);
_clearPvPActionDataForPlayer(victim, new string[]{VAR_VICTIMS}, ACTION_CANDIDATE_SUDDEN_DEATH, darkEnclave);
sendSystemMessage(victim, new string_id("pvp_rating", "dark_jedi_kill_lost_votes"));
trace.log("force_rank", utils.getRealPlayerFirstName(victim) + " has lost " + victimsVotes + " votes for dying during the voting sudden-death period.", victim, trace.TL_CS_LOG | trace.TL_DEBUG);
int votesGained = 0;
for(int x = 0; x < suddenDeathWinners.length; x++)
{
curContrib = suddenDeathContribs[x] / totSDContribs; // this is the percentage of dmg done in regards total damage done by all sudden death jedi
curWinnerVotes = getVotesForPlayer(suddenDeathWinners[x], darkEnclave);
votesGained = (int)Math.floor((float)victimsVotes * curContrib);
trace.log("force_rank", utils.getRealPlayerFirstName(suddenDeathWinners[x]) + " has gained " + votesGained + " for killing " + utils.getRealPlayerFirstName(victim), suddenDeathWinners[x], trace.TL_CS_LOG| trace.TL_DEBUG);
setVotesForPlayer(suddenDeathWinners[x], curWinnerVotes + votesGained, darkEnclave);
// msg players
prose_package pp = new prose_package();
pp.target.set(utils.getRealPlayerFirstName(victim));
pp.digitInteger = votesGained;
pp.stringId = new string_id("pvp_rating", "dark_jedi_kill_won_votes");
//prose.getPackage(new string_id("force_rank", "dark_jedi_kill_won_votes"), victim, votesGained);
sendSystemMessageProse(suddenDeathWinners[x], pp);
}
}
}
// demote and clear out any outstanding pvp action target/inits.
if(demoteToZero)
{
demoteDeadPlayerToRankZero(victim, darkEnclave);
}
return;
}
//
// teleports @player to a common's cell in the enclave, only if they are currently in an enclave.
// method works out which enclave they are in and which room they need to get kicked to
//
void moveEnclavedPlayerToNeutralCell(obj_id player)
{
if(arena.isPlayerInEnclave(player))
{
location curLoc = getLocation(player);
obj_id curCell = curLoc.cell;
obj_id enclave = getEnclave(player);
obj_id destCell = null;
float x = 0.0f;
float y = 0.0f;
float z = 0.0f;
string cellName = "";
if(curCell != null)
{
if(checkCellPermission(player, curCell, true))
{
// player has permission for current cell. no need to move.
//return;
// commenting return out for now, as you could be in a common cell that you have
// permission to, but you dont have permissions to the cells leading to that portion of the
// common cell.
}
}
if(force_rank.getCouncilAffiliation(player) == force_rank.DARK_COUNCIL)
{
cellName = "antechamber";
x = 0.0f;
y = -43.42f;
z = -31.26f;
}
else // light enclave
{
cellName = "lobby";
x = -0.02f;
y = -19.03f;
z = 35.41f;
}
string[] enclaveRooms = getCellNames(enclave);
if(utils.getElementPositionInArray(enclaveRooms, cellName) > -1)
{
destCell = getCellId(enclave, cellName);
if(isIdValid(destCell))
{
location newloc = new location(x, y, z);
newloc.cell = destCell;
setLocation(player, newloc);
}
}
}
}
//
// @returns either "light" or "dark", depending on the @enclave alignment. the returned string is used by updateRoomPermissions()
// to pull the allowed ranks from the datatable
//
string getEnclaveAligmentString(obj_id enclave)
{
if(DEBUGGING)
{
return "test";
}
int alignmentVal = getCouncilAffiliation(enclave);
if (alignmentVal == -1)
{
trace.log("force_rank", "force_rank.getEnclaveAligmentString -- invalid coucil value on enclave " + enclave, enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return null;
}
string alignment;
if(alignmentVal == force_rank.DARK_COUNCIL)
{
alignment = "dark";
}
else
{
alignment = "light";
}
return alignment;
}
//
// Reads rank permission lists from a datatable and pulls names off of the enclave roster for each
// rank, updating the permission lists for each cell in the enclave. this method is usually called
// after the enclave gets its new data from the cluster data store. This does not alter permissions for commons areas, etc.
// To completely re-do all cell permissions, call refreshAllRoomPermissions.
//
void updateAllRoomPermissions(obj_id enclave)
{
// construct the column name so we can look up permissioned ranks for the individual rooms
string alignment = getEnclaveAligmentString(enclave);
if(alignment == null || alignment.length() < 1)
{
trace.log("force_rank", "...force_rank::updateRoomPermissions -> Error retrieving enclave alignment. Room permissions not updated.", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
string[] commonsAreaCells = dataTableGetStringColumn(JEDI_ROOM_PERMISSIONS_TABLE, alignment + DATA_COLUMN_COMMUNITY_CELLS);
string[] enclaveRooms = getCellNames(enclave);
string columnName = "";
int[] allowedRanks = new int[0];
for(int i = 0; i < enclaveRooms.length; i++)
{
if(utils.getElementPositionInArray(commonsAreaCells, enclaveRooms[i]) > -1)
{
continue;
}
columnName = alignment + "_" + enclaveRooms[i];
allowedRanks = dataTableGetIntColumnNoDefaults(JEDI_ROOM_PERMISSIONS_TABLE, columnName);
if(allowedRanks == null || allowedRanks.length < 1)
{
continue;
}
// make the actual adjustment to the permissions list
adjustPermissionListForRoom(enclave, enclaveRooms[i], allowedRanks);
}
return;
}
resizeable obj_id[] playerNamesToIds(string[] playerNames)
{
resizeable obj_id[] players = new obj_id[0];
obj_id player = null;
for(int i = 0; i < playerNames.length; i++)
{
player = getPlayerIdFromFirstName(playerNames[i]);
if(isIdValid(player) && player != null)
{
utils.addElement(players, player);
}
}
return players;
}
//
// adjusts the permissions list for one room in the @enclave, given the @cellName and an
// integer array describing the @allowedRanks into the given cell
//
void adjustPermissionListForRoom(obj_id enclave, string cellName, int[] allowedRanks)
{
obj_id cellId = getCellId(enclave, cellName);
if(!isIdValid(cellId))
{
trace.log("force_rank", "...enclave_gate_keeper::adjustPermissionsListForRoom -> Bunk cellId for cell " + cellName + ". Permissions list not updated.", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
// clear out allow list for the cell
clearCellAllowList(cellId);
// set new allow list
string[] allowedPlayers = null;
for(int i = 0; i < allowedRanks.length; i++)
{
allowedPlayers = force_rank.getPlayersInForceRank(enclave, allowedRanks[i]);
if(allowedPlayers == null || allowedPlayers.length < 1)
{
continue;
}
for(int x = 0; x < allowedPlayers.length; x++)
{
permissionsAddAllowed(cellId, allowedPlayers[x]);
}
}
return;
}
//
// sets EVERY cell in the @enclave to private and clear all ban/allow lists from the cells
//
void setAllCellsPrivate(obj_id enclave)
{
string[] cellNames = getCellNames(enclave);
obj_id cellId = null;
if (cellNames != null)
{
for(int i = 0; i < cellNames.length; i++)
{
cellId = getCellId(enclave, cellNames[i]);
permissionsMakePrivate(cellId);
clearCellBanList(cellId);
clearCellAllowList(cellId);
}
}
return;
}
//
// clears everyone off of the ban list for a given @cell
//
void clearCellBanList(obj_id cell)
{
string[] banned = permissionsGetBanned(cell);
if(banned == null || banned.length < 1)
{
return;
}
for(int i = 0; i < banned.length; i++)
{
permissionsRemoveBanned(cell, banned[i]);
}
return;
}
//
// whipes everyone off of the allow list for a given @cell
//
void clearCellAllowList(obj_id cell)
{
string[] allowed = permissionsGetAllowed(cell);
if(allowed == null || allowed.length < 1)
{
return;
}
for(int i = 0; i < allowed.length; i++)
{
permissionsRemoveAllowed(cell, allowed[i]);
}
return;
}
//
// reads the JEDI_ROOM_PERMISSIONS_TABLE table for commons room data for the specified @enclave.
// Found under column [alignment]_community_cells, aka DATA_COLUMN_COMMUNITY_CELLS
//
void setCommonsRoomsToPublic(obj_id enclave)
{
// construct the column name so we can look up permissioned ranks for the individual rooms
string alignment = getEnclaveAligmentString(enclave);
if(alignment == null || alignment.length() < 1)
{
trace.log("force_rank", "force_rank::setCommonRoomsToPublic -> Error retrieving enclave alignment. Commons Area cells permissions not updated.", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
string[] commonsAreaCells = dataTableGetStringColumn(JEDI_ROOM_PERMISSIONS_TABLE, alignment + DATA_COLUMN_COMMUNITY_CELLS);
if(commonsAreaCells == null || commonsAreaCells.length < 1)
{
trace.log("force_rank", "force_rank::setCommonsRoomsToPublic -> No commons area cells found for " + alignment + " enclave. All rooms remain private.", enclave, trace.TL_WARNING | trace.TL_DEBUG);
return;
}
obj_id cellId = null;
for(int i = 0; i < commonsAreaCells.length; i++)
{
//LOG("force_rank", "cell ->" + commonsAreaCells[i]);
cellId = getCellId(enclave, commonsAreaCells[i]);
if(!isIdValid(cellId))
{
trace.log("force_rank", "force_rank::setCommonRoomsToPublic -> Bunk Commons Area Cell ID for cell name " + commonsAreaCells[i] + ". Cell not set to public.", enclave, trace.TL_WARNING | trace.TL_DEBUG);
}
permissionsMakePublic(cellId);
}
return;
}
//
// check to see if @item has access permission for @cell
//
boolean checkCellPermission(obj_id item, obj_id cell, boolean silent)
{
if(isGod(item))
{
sendSystemMessageTestingOnly(item, "god access granted to this area");
return true;
}
if(!isMob(item))
{
return true;
}
obj_id enclave = getTopMostContainer(cell);
if(!hasScript(enclave, force_rank.SCRIPT_ENCLAVE_CONTROLLER))
{
trace.log("force_rank", "force_rank::checkCellPermission -- " + enclave + " is not an enclave building.", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
if(!silent)
{
sendSystemMessage(item, new string_id("pvp_rating", "enclave_deny_entry"));
}
return false;
}
string alignment = force_rank.getEnclaveAligmentString(enclave);
string cellName = getCellName(cell);
string columnName = alignment + "_" + cellName;
if(alignment == null || alignment.length() < 1)
{
trace.log("force_rank", "force_rank::checkCellPermission-> Error retrieving enclave alignment.", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
if(!silent)
{
sendSystemMessage(item, new string_id("pvp_rating", "enclave_deny_entry"));
}
return false;
}
if((isIdValid(item)) && (isPlayer(item)) && (force_rank.isForceRanked(item)) && (force_rank.isPlayersEnclave(enclave, item)))
{
string[] commonsAreaCells = dataTableGetStringColumn(force_rank.JEDI_ROOM_PERMISSIONS_TABLE, alignment + force_rank.DATA_COLUMN_COMMUNITY_CELLS);
if(utils.getElementPositionInArray(commonsAreaCells, cellName) > -1)
{
pet_lib.packAllCurrentPets(item, new string_id("pvp_rating", "enclave_deny_pet_entry"));
return true;
}
else
{
int[] allowedRanks = dataTableGetIntColumnNoDefaults(force_rank.JEDI_ROOM_PERMISSIONS_TABLE, columnName);
int rank = force_rank.getForceRank(item);
if(utils.getElementPositionInArray(allowedRanks, rank) >= 0)
{
pet_lib.packAllCurrentPets(item, new string_id("pvp_rating", "enclave_deny_pet_entry"));
return true;
}
}
}
else
{
expelFromBuilding(item);
}
if(!silent)
{
sendSystemMessage(item, new string_id("pvp_rating", "enclave_deny_entry"));
}
return false;
}
// resets all the scripts on the cells for the permission system
void setCellScripts(obj_id enclave)
{
string[] enclaveRooms = getCellNames(enclave);
obj_id cellId = null;
for(int i = 0; i < enclaveRooms.length; i++)
{
cellId = getCellId(enclave, enclaveRooms[i]);
if(!isIdValid(cellId))
{
continue;
}
attachScript(cellId, "systems.gcw.enclave_cell");
}
return;
}
void makeAllCellsPublic(obj_id enclave)
{
string[] enclaveRooms = getCellNames(enclave);
obj_id cellId = null;
for(int i = 0; i < enclaveRooms.length; i++)
{
cellId = getCellId(enclave, enclaveRooms[i]);
if(!isIdValid(cellId))
{
continue;
}
permissionsMakePublic(cellId);
}
}
//
// method should be called when all room permissions, including the public rooms need to be updated.
// method used mainly by maintenance triggers (attach, load, etc)
//
void refreshAllRoomPermissions(obj_id enclave)
{
// make every cell in the enclave private and clear all ban/allow lists
setAllCellsPrivate(enclave);
// make any commons area public, any allow/ban list has already been cleared in the previous call to setAllCellsPrivate
setCommonsRoomsToPublic(enclave);
// set allow lists for ppl in rankings so they can get into the various rooms
updateAllRoomPermissions(enclave);
}
//
// Make @player1 a permanent enemy of @player2 and vice versa, if the flag is @turnOn, otherwise the two players will be peaced
//
void makePlayersPermaEnemies(obj_id player1, obj_id player2)
{
trace.log("force_rank", "Setting PEF for " + player1 + " and " + player2 + " - now enemies.", null, trace.TL_CS_LOG | trace.TL_DEBUG);
pvpSetPermanentPersonalEnemyFlag(player1, player2);
pvpSetPermanentPersonalEnemyFlag(player2, player1);
return;
}
//
// Make @player1 a permanent enemy of @player2 and vice versa, if the flag is @turnOn, otherwise the two players will be peaced
//
void makePlayersPermaFriends(obj_id player1, obj_id player2)
{
trace.log("force_rank", "Making players " + utils.getRealPlayerFirstName(player1) + " and " + utils.getRealPlayerFirstName(player2) + " friends. (not really)", null, trace.TL_DEBUG);
//pvpRemovePermanentPersonalEnemyFlag(player1, player2); // doesn't exist currently
//pvpRemovePermanentPersonalEnemyFlag(player2, player1); // doesn't exist currently
return;
}
//
// make @player an enemy of everyone in @enemyGroup and vice versa
//
void makePlayerEnemyOfGroup(obj_id player, obj_id[] enemyGroup)
{
if(enemyGroup == null)
{
return;
}
for(int i = 0; i < enemyGroup.length; i++)
{
if(player != enemyGroup[i])
{
makePlayersPermaEnemies(player, enemyGroup[i]);
}
}
return;
}
//
// make @player a friend of everyone in @friendGroup and vice versa
//
void makePlayerFriendsWithGroup(obj_id player, obj_id[] friendGroup)
{
if(friendGroup == null)
{
return;
}
for(int i = 0; i < friendGroup.length; i++)
{
if(player != friendGroup[i])
{
makePlayersPermaFriends(player, friendGroup[i]);
}
}
return;
}
//
// make every member in @group1 a permanent enemy of @group2 and vice versa
//
void makePlayerGroupsEnemies(obj_id[] group1, obj_id[] group2)
{
if(group1 == null || group2 == null)
{
return;
}
for(int i = 0; i < group1.length; i++)
{
makePlayerEnemyOfGroup(group1[i], group2);
}
return;
}
//
// just takes the arrays and dumps 'em into a dictionary. save myself some typing.
//
dictionary packageActionData(resizeable obj_id[] initz, resizeable obj_id[] victz, resizeable int[] startz)
{
dictionary d = new dictionary();
if(initz == null || initz.size() < 1 || victz == null || victz.size() < 1 || startz == null || startz.size() < 1)
{
//LOG("force_rank", "force_rank::packageActionData: -> Empty array(s) passed. Passing back empty dictionary.");
//LOG("force_rank", "force_rank::packageActionData: -> initiz.size()=" + initz.size() + ", victz.size()=" + victz.size() + ", startz.size()=" + startz.size());
// else dictionary.java will throw exceptions... bleh.
return d;
}
d.put("initiators", initz);
d.put("victims", victz);
d.put("times", startz);
return d;
}
//
// writes the @initiators and the @victims to the enclave given the @pvpAction of list pair it is (ACTION_VENDETTA, ACTION_BANISHMENT, etc)
//
void setPvPActionData(dictionary data, string pvpAction, obj_id darkEnclave)
{
if(!isIdValid(darkEnclave))
{
trace.log("force_rank", "force_rank::setPvPActionData -> darkEnclave ID not valid. Data not written.", darkEnclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
if(getCouncilAffiliation(darkEnclave) != DARK_COUNCIL)
{
trace.log("force_rank", "force_rank::setPvPActionData -> Non-DarkJedi-Enclave caller. Aborting.", darkEnclave, trace.TL_WARNING | trace.TL_DEBUG);
return;
}
if(data == null)
{
trace.log("force_rank", "force_rank::setPvPActionData -> @data == null. removing all action data for " + pvpAction, darkEnclave, trace.TL_DEBUG);
removeObjVar(darkEnclave, pvpAction);
return;
}
if(validatePvPActionData(data) == null)
{
if(!data.containsKey("victims"))
{
// arrays are just empty not mismatched lengths, etc... we need to remove the data as this indicates all actions odf pcpAction type are done.
trace.log("force_rank", "force_rank::setPvPActionData -> @data has no victim/starter/time data. removing all action data for " + pvpAction + " from enclave. this is means all actions of this type are done.", darkEnclave, trace.TL_DEBUG);
removeObjVar(darkEnclave, pvpAction);
}
else
{
trace.log("force_rank", "force_rank::setPvPActionData: -> pvp action data (" + pvpAction + ") invalid. not set to enclave.", darkEnclave, trace.TL_WARNING | trace.TL_DEBUG);
}
return;
}
obj_id[] inits = data.getObjIdArray("initiators");
obj_id[] victs = data.getObjIdArray("victims");
int[] startTms = data.getIntArray("times");
setObjVar(darkEnclave, pvpAction + VAR_INITIATORS, inits);
setObjVar(darkEnclave, pvpAction + VAR_VICTIMS, victs);
setObjVar(darkEnclave, pvpAction + VAR_START_TIMESTAMPS, startTms);
return;
}
//
// The enclave keeps array pairs for initiators and victims for Vendettas, Banishments and council purges.
// this method pulls those arrays and validates them (makes sure they are at least of the same size)
// should the validation fail, the arrays are returned as nulls. if the arrays do no exist on the enclave
// object, zero length arrays are returned.
//
dictionary getAndValidatePvPActionData(string pvpAction, obj_id darkEnclave)
{
if(getCouncilAffiliation(darkEnclave) != DARK_COUNCIL)
{
trace.log("force_rank", "force_rank::getAndValidatePvPActionData -> Non-DarkJedi-Enclave. Aborting.", darkEnclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return null;
}
if(!isIdValid(darkEnclave))
{
trace.log("force_rank", "force_rank::getAndValidatePvPActionData -> darkEnclave ID not valid.", darkEnclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return null;
}
resizeable obj_id[] initiatorz = new obj_id[0];
if(hasObjVar(darkEnclave, pvpAction + VAR_INITIATORS))
{
initiatorz = getResizeableObjIdArrayObjVar(darkEnclave, pvpAction + VAR_INITIATORS);
}
resizeable obj_id[] victimz = new obj_id[0];
if(hasObjVar(darkEnclave, pvpAction + VAR_VICTIMS))
{
victimz = getResizeableObjIdArrayObjVar(darkEnclave, pvpAction + VAR_VICTIMS);
}
resizeable int[] timez = new int[0];
if(hasObjVar(darkEnclave, pvpAction + VAR_START_TIMESTAMPS))
{
timez = getResizeableIntArrayObjVar(darkEnclave, pvpAction + VAR_START_TIMESTAMPS);
if(timez == null)
{
LOG("force_rank", "Variable " + pvpAction + VAR_START_TIMESTAMPS + " returned a null array!");
}
}
dictionary actionData = packageActionData(initiatorz, victimz, timez);
return validatePvPActionData(actionData);
}
//
// returns @data if valid, or null if not valid of empty
//
dictionary validatePvPActionData(dictionary data)
{
if(data == null)
{
return null;
}
if(!data.containsKey("initiators") || !data.containsKey("victims") || !data.containsKey("times"))
{
return null;
}
obj_id[] inits = data.getObjIdArray("initiators");
obj_id[] victs = data.getObjIdArray("victims");
int[] startTms = data.getIntArray("times");
if(victs == null)
{
return null;
}
int len = victs.length;
if(inits == null || startTms == null || inits.length != len || startTms.length != len)
{
trace.log("force_rank", "force_rank::validatePvPActionData -> Victim/Initiator/TimeStamp arrays have mismatched length. Data not written.", null, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return null;
}
return data;
}
//
// designed to be called when the enclave fires up (onInit). scrubs the data on the enclave and removes any
// expired PvPActions (vendetta, etc, etc), based on the ACTION_*_DURATION vars
//
void deleteExpiredPvPActions(obj_id darkEnclave)
{
resizeable obj_id[] initiatorz = new obj_id[0];
resizeable obj_id[] victimz = new obj_id[0];
resizeable int[] timez = new int[0];
string[] actions = {ACTION_VENDETTA, ACTION_PURGE_COUNCIL, ACTION_BANISHMENT};
int[] durations = {ACTION_VENDETTA_DURATION, ACTION_PURGE_COUNCIL_DURATION, ACTION_BANISHMENT_DURATION};
int now = getGameTime();
for(int i = 0; i < actions.length; i++)
{
dictionary data = getAndValidatePvPActionData(actions[i], darkEnclave);
if(data == null)
{
return;
}
utils.concatArrays(initiatorz, data.getObjIdArray("initiators"));
utils.concatArrays(victimz, data.getObjIdArray("victims"));
utils.concatArrays(timez, data.getIntArray("times"));
int x = 0;
while(x < timez.length)
{
if(now - timez[x] >= durations[x])
{
utils.removeElementAt(timez, x);
utils.removeElementAt(victimz, x);
utils.removeElementAt(initiatorz, x);
// don't increment iterator since we removed an element
// ToDo: Message players to let them know the action has ended. have to do it in email, since this
// method will only run OnInit and no player will be connected
}
else
{
x++;
}
}
dictionary newData = packageActionData(initiatorz, victimz, timez);
// write the data back to the enclave
setPvPActionData(newData, actions[i], darkEnclave);
timez.clear();
victimz.clear();
initiatorz.clear();
}
return;
}
//
// clear out any pvp action that are registered on the @enclave for the @player is a part of. this should only be called as a result
// of dark jedi pvp due to some Pvp action imposed on @player. this method will handle sending out notification messages
//
void demoteDeadPlayerToRankZero(obj_id player, obj_id darkEnclave)
{
resizeable obj_id[] peaceTarget = new obj_id[0];
peaceTarget.add(player);
resizeable obj_id[] recips = new obj_id[0];
utils.concatArrays(recips, getAllPlayersInForceRank(darkEnclave, -1));
demoteForceRank(darkEnclave, utils.getRealPlayerFirstName(player), 0);
notifyPlayerOfPvPActionEnd(null, ACTION_BANISHMENT, peaceTarget, recips, false);
string[] lists = {VAR_VICTIMS, VAR_INITIATORS}; // clear actions for which @player is either a victim or an initiator
string[] actions = {ACTION_PURGE_COUNCIL, ACTION_CANDIDATE_SUDDEN_DEATH, ACTION_BANISHMENT, ACTION_VENDETTA};
for(int i = 0; i < actions.length; i++)
{
_clearPvPActionDataForPlayer(player, lists, actions[i], darkEnclave);
}
removeObjVar(player, VAR_NOTIFY_ENCLAVE_OF_DEATH);
return;
}
//
// will erase any pvp action of type pvpCondition that involve @player.
// @whichLists will need to have VAR_VICTIMS or VAR_INITIATORS or both in it, depending on if you want to clear all the
// pvp conditions that @player is a target of, or to clear all the instances that @player initiated.
//
boolean _clearPvPActionDataForPlayer(obj_id player, string[] whichLists, string pvpAction, obj_id darkEnclave)
{
dictionary data = getAndValidatePvPActionData(pvpAction, darkEnclave);
if(data == null)
{
trace.log("force_rank", "force_rank::_clearPvPActionDataForPlayer: -> Method called but no " + pvpAction + " actions to clear for " + utils.getRealPlayerFirstName(player), player, trace.TL_WARNING | trace.TL_DEBUG);
return false;
}
resizeable obj_id[] inits = new obj_id[0];
utils.concatArrays(inits, data.getObjIdArray("initiators"));
resizeable obj_id[] victs = new obj_id[0];
utils.concatArrays(victs, data.getObjIdArray("victims"));
resizeable int[] startTms = new int[0];
utils.concatArrays(startTms, data.getIntArray("times"));
// grab initial index to see if @player exists at all in @whichList
for(int i = 0; i < whichLists.length; i++)
{
int idx = -1;
if(whichLists[i] == VAR_INITIATORS)
{
idx = utils.getElementPositionInArray(inits, player);
}
else if(whichLists[i] == VAR_VICTIMS)
{
idx = utils.getElementPositionInArray(victs, player);
}
else
{
trace.log("force_rank", "force_rank::clearAllPvPActionsForPlayer passed bad value for @whichList array . Bailing without clearing action status.", player, trace.TL_ERROR_LOG | trace.TL_DEBUG);
continue;
}
while(idx > -1)
{
inits = utils.removeElementAt(inits, idx);
victs = utils.removeElementAt(victs, idx);
startTms = utils.removeElementAt(startTms, idx);
if(whichLists[i] == VAR_INITIATORS)
{
idx = utils.getElementPositionInArray(inits, player);
}
else
{
idx = utils.getElementPositionInArray(victs, player);
}
}
}
dictionary newData = packageActionData(inits, victs, startTms);
// write the data back to the enclave
setPvPActionData(newData, pvpAction, darkEnclave);
return true;
}
//
// returns @true or @false depending on whether or not @player1 & @player2 are part of the same vendetta. !!! @vendettaData is assumed to be valid !!!
//
boolean isPartOfSameVendetta(obj_id player1, obj_id player2, dictionary vendettaData)
{
resizeable obj_id[] initiatorz = new obj_id[0];
utils.concatArrays(initiatorz, vendettaData.getObjIdArray("initiators"));
resizeable obj_id[] victimz = new obj_id[0];
utils.concatArrays(victimz, vendettaData.getObjIdArray("victims"));
// see if player1 is the agressor in any vendetta
int idx = initiatorz.indexOf(player1);
while(idx > -1)
{
if(victimz[idx] == player2)
{
trace.log("force_rating", "force_rank::isPartOfSameVendetta: -> " + utils.getRealPlayerFirstName(player1) + " is same vendetta as " + utils.getRealPlayerFirstName(player2), player1, trace.TL_DEBUG);
return true;
}
// see if player1 has another vendetta registered for some reason
idx = initiatorz.indexOf(player1, idx+1);
}
// see if player1 is the victim of any vendetta
idx = victimz.indexOf(player1);
while(idx > -1)
{
if(initiatorz[idx] == player2)
{
trace.log("force_rating", "force_rank::isPartOfSameVendetta: -> " + utils.getRealPlayerFirstName(player1) + " is same vendetta as " + utils.getRealPlayerFirstName(player2), player1, trace.TL_DEBUG);
return true;
}
// see if player1 has another vendetta registered for some reason
idx = victimz.indexOf(player1, idx+1);
}
return false;
}
//
// @returns true or false depending on whether or not @player has initiated @pvpAction
//
boolean isPvPActionInitiator(obj_id player, dictionary actionData1)
{
obj_id[] initiatorz = actionData1.getObjIdArray("initiators");
// grab initial index to see if @player exists at all in @whichList
if(utils.getElementPositionInArray(initiatorz, player) > -1)
{
return true;
}
return false;
}
//
// @returns true or false depending on whether or not @player has fallen victim @pvpAction !!! @actionData is presumed to be valid !!!
//
boolean isPvPActionVictim(obj_id player, dictionary actionData2)
{
obj_id[] victimz = actionData2.getObjIdArray("victims");
// grab initial index to see if @player exists at all
int idx = utils.getElementPositionInArray(victimz, player);
if(idx > -1)
{
trace.log("force_rank", "force_rank::isPvPActionVictim: -> " + utils.getRealPlayerFirstName(player) + " IS a victim.", player, trace.TL_DEBUG);
return true;
}
trace.log("force_rank", "force_rank::isPvPActionVictim: -> " + utils.getRealPlayerFirstName(player) + " is NOT a victim.", player, trace.TL_DEBUG);
return false;
}
//
// @returns true or false, depending on whether or not @player is part of (either initiator OR victim) of the given @pvpAction
//
boolean isPartOfPvPAction(obj_id player,obj_id darkEnclave, dictionary actionData3)
{
return (isPvPActionInitiator(player, actionData3) || isPvPActionVictim(player, actionData3));
}
//
// @returns true or false if @player1 is part of the same rank as @player2 and they are both registered as being
// part of a ACTION_CANDIDATE_SUDDEN_DEATH pvp action
//
boolean bothArePartOfSameSuddenDeathRank(obj_id player1, obj_id player2, obj_id darkEnclave, dictionary suddenDeathData)
{
if(getForceRank(darkEnclave, utils.getRealPlayerFirstName(player1)) != getForceRank(darkEnclave, utils.getRealPlayerFirstName(player2)))
{
return false;
}
if(isPvPActionVictim(player1, suddenDeathData) && isPvPActionVictim(player2, suddenDeathData))
{
return true;
}
return false;
}
//
// private helper function that adds all council members to the ACTION_PURGE_COUNCIL list
//
boolean _initiateCouncilPurge(obj_id darkEnclave, obj_id purger)
{
obj_id[] members = getAllPlayersInForceRank(darkEnclave, COUNCIL_RANK_NUMBER);
if(members == null)
{
return false;
}
trace.log("force_rank", "force_rank::_initiateCouncilPurge: -> Council rank (" + COUNCIL_RANK_NUMBER + ") has " + members.length + " valid members.", darkEnclave, trace.TL_DEBUG);
if(members.length < 1)
{
trace.log("force_rank", "force_rank::_initiateCouncilPurge: -> Council purge not done as there are no Council members to purge.", purger, trace.TL_WARNING | trace.TL_DEBUG);
return true;
}
// council purges should never overlap due to timing issues, so any existing council purge will be overwritten
resizeable obj_id[] victimz = new obj_id[0];
resizeable obj_id[] initiatorz = new obj_id[0];
resizeable int[] timez = new int[0];
int time = getGameTime();
for(int i = 0; i < members.length; i++)
{
if(members[i] != null/* && isIdValid(members[i])*/)
{
utils.addElement(victimz, members[i]);
utils.addElement(initiatorz, purger);
utils.addElement(timez, time);
}
}
if(victimz.size() > 0)
{
dictionary data = packageActionData(initiatorz, victimz, timez);
setPvPActionData(data, ACTION_PURGE_COUNCIL, darkEnclave);
}
// send notifications to all players
resizeable obj_id[] recips = new obj_id[0];
utils.concatArrays(recips, getAllPlayersInForceRank(darkEnclave, -1));
notifyPlayerOfPvPActionStart(purger, ACTION_PURGE_COUNCIL, victimz, recips, darkEnclave);
return true;
}
//
// @returns true or false depending on wether or not the call was successful
// @initiator will be aded as an initiator and @allVictims as the...victim for the given
// @pvpAction. @allVictims may be null if the pvpAction is ACTION_PURGE_COUNCIL, as the
// @victim parm is ignored for this action since everyone who is currently listed in the
// council will automagically be added as victims.
//
boolean startPvPAction(obj_id initiator, resizeable obj_id[] allVictims, string pvpAction, obj_id darkEnclave)
{
trace.log("force_rank", "force_rank::startPvPAction: -> " + pvpAction + " started by " + initiator, initiator, trace.TL_CS_LOG | trace.TL_DEBUG);
if(pvpAction == ACTION_PURGE_COUNCIL)
{
// _initiateCouncilPurge does the messaging for council purges
return _initiateCouncilPurge(darkEnclave, initiator);
}
dictionary data = getAndValidatePvPActionData(pvpAction, darkEnclave);
if(allVictims == null || allVictims.length < 1)
{
return false;
}
resizeable obj_id[] initiatorz = new obj_id[0];
resizeable obj_id[] victimz = new obj_id[0];
resizeable int[] timez = new int[0];
int time = getGameTime();
if(data != null)
{
utils.concatArrays(initiatorz, data.getObjIdArray("initiators"));
utils.concatArrays(victimz, data.getObjIdArray("victims"));
utils.concatArrays(timez, data.getIntArray("times"));
}
for(int i = 0; i < allVictims.length; i++)
{
utils.addElement(initiatorz, initiator);
utils.addElement(timez, time);
}
utils.concatArrays(victimz, allVictims);
dictionary newData = packageActionData(initiatorz, victimz, timez);
// write the data back to the enclave
setPvPActionData(newData, pvpAction, darkEnclave);
string victimList = "";
for(int i = 0; i < allVictims.length; i++)
{
victimList += "" + allVictims[i] + ",";
}
trace.log("force_rank", "Dark Jedi PvP Action Started: " + pvpAction + ". Initiator: " + initiator + ", Victims: " + victimList, null, trace.TL_CS_LOG | trace.TL_DEBUG);
// notify the targets and initiators that the action has been initiated.
// the actual flagging gets done in the message handler player_force_rank::pvpActionMessage
resizeable obj_id[] recips = new obj_id[0];
if(pvpAction.equals(ACTION_VENDETTA))
{
recips.add(initiator);
recips.add(victimz[0]);
}
else if(pvpAction.equals(ACTION_BANISHMENT))
{
utils.concatArrays(recips, getAllPlayersInForceRank(darkEnclave, -1));
}
else if(pvpAction.equals(ACTION_CANDIDATE_SUDDEN_DEATH))
{
utils.concatArrays(recips, allVictims); // in this case only the victims need to be notified
}
// send the notification messages to recips. Msg recipients will start the PEFs
notifyPlayerOfPvPActionStart(initiator, pvpAction, allVictims, recips, darkEnclave);
return true;
}
//
// @theInitiator -> person who started the @pvpAction, or in case of CANDIDATE_SUDDEN_DEATH, the enclave
// @pvpAction -> the ACTION_* to start
// @actionTargets -> victims of said action.
// @msgRecipients -> people who need to be notified of this action starting, all of which who will make everyone in @actionTargets their enemy
//
void notifyPlayerOfPvPActionStart(obj_id theInitiator, string pvpAction, resizeable obj_id[] actionTargets, resizeable obj_id[] msgRecipients, obj_id darkEnclave)
{
if(msgRecipients == null || msgRecipients.length < 1)
{
trace.log("force_rank", "force_rank::notifyPlayerOfPvPActionStart: -> @msgRecipients null or zero length. No one notified.", theInitiator, trace.TL_DEBUG);
return;
}
dictionary parms = new dictionary();
parms.put("initiator", theInitiator);
parms.put("pvpAction", pvpAction);
parms.put("actionTargets", actionTargets);
parms.put("enclave", darkEnclave);
for(int i = 0; i < msgRecipients.length; i++)
{
messageTo(msgRecipients[i], "msgPvPActionStart", parms, 0, false);
}
return;
}
//
// @killer is the person who ended the @pvpAction due to killing the @actionTargets, or null if @actionTimedOut
// @pvpAction is the ACTION_* that has come to an end
// @actionTargets are the people who need to be peaced as a result of this action ending
//
void notifyPlayerOfPvPActionEnd(obj_id killer, string pvpAction, resizeable obj_id[] peaceTargets, resizeable obj_id[] msgRecipients, boolean actionTimedOut)
{
if(msgRecipients == null || msgRecipients.length < 1 || peaceTargets == null || peaceTargets.length < 1)
{
trace.log("force_rank", "force_rank::notifyPlayerOfPvPActionEnd: -> @msgRecipients null or zero length. No one notified.", killer, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return;
}
dictionary parms = new dictionary();
if(killer != null)
{
parms.put("killer", killer);
}
parms.put("pvpAction", pvpAction);
parms.put("peaceTargets", peaceTargets);
parms.put("actionTimedOut", actionTimedOut);
for(int i = 0; i < msgRecipients.length; i++)
{
messageTo(msgRecipients[i], "msgPvPActionEnd", parms, 0, false);
}
return;
}
//
// returns a list of players that are at war with @player due to a vendetta. !!!@pvpAction is assumed to be valid!!! this::validatePvPActionData
//
obj_id[] getMyVendettaEnemies(dictionary vendettaData, obj_id player)
{
resizeable obj_id[] initiatorz = new obj_id[0];
resizeable obj_id[] victimz = new obj_id[0];
resizeable obj_id[] vEnemies = new obj_id[0];
utils.concatArrays(initiatorz, vendettaData.getObjIdArray("initiators"));
utils.concatArrays(victimz, vendettaData.getObjIdArray("victims"));
// see if player is the agressor in any vendetta
int idx = initiatorz.indexOf(player);
while(idx > -1)
{
utils.addElement(vEnemies, victimz[idx]);
idx = initiatorz.indexOf(player, idx+1);
}
// see if player is the victim of any vendetta
idx = victimz.indexOf(player);
while(idx > -1)
{
utils.addElement(vEnemies, initiatorz[idx]);
idx = victimz.indexOf(player, idx+1);
}
trace.log("force_rating", "force_rank::getMyVendettaEnemies: -> " + utils.getRealPlayerFirstName(player) + " has " + vEnemies.length + " vendettas.", player, trace.TL_DEBUG);
return vEnemies;
}
obj_id[] getMySuddenDeathEnemies(dictionary suddenDeathData, obj_id player, obj_id darkEnclave)
{
resizeable obj_id[] candidateVictims = new obj_id[0];
resizeable obj_id[] enemies = new obj_id[0];
if(!isPvPActionVictim(player, suddenDeathData))
{
return enemies;
}
utils.concatArrays(candidateVictims, suddenDeathData.getObjIdArray("victims"));
int playerRank = getForceRank(darkEnclave, utils.getRealPlayerFirstName(player));
if(playerRank < 1)
{
return new obj_id[0];
}
for(int i = 0; i < candidateVictims.length; i++)
{
if((candidateVictims[i] != player) && (getForceRank(darkEnclave, utils.getRealPlayerFirstName(candidateVictims[i])) == playerRank))
{
utils.addElement(enemies, candidateVictims[i]);
}
}
return enemies;
}
obj_id[] getEnemiesForPvPAction(obj_id player, string pvpAction, obj_id darkEnclave)
{
dictionary data = getAndValidatePvPActionData(pvpAction, darkEnclave);
if(data == null)
{
return new obj_id[0];
}
if(pvpAction.equals(ACTION_VENDETTA))
{
return getMyVendettaEnemies(data, player);
}
if(pvpAction.equals(ACTION_CANDIDATE_SUDDEN_DEATH))
{
return getMySuddenDeathEnemies(data, player, darkEnclave);
}
// left is ACTION_BANISHMENT || ACTION_PURGE_COUNCIL ... all of which are ALL enemies to everyone
return data.getObjIdArray("victims");
}
//
// called by player_force_rank on init to get an updated list of PEFd enemies
//
void requestPEFs(obj_id player)
{
if(!hasObjVar(player, VAR_MY_ENCLAVE_ID))
{
getEnclaveObjId(player, getCouncilAffiliation(player), "enclaveIdResponse");
return;
}
obj_id myEnclave = getObjIdObjVar(player, VAR_MY_ENCLAVE_ID);
if(getForceRank(myEnclave, utils.getRealPlayerFirstName(player)) < 1)
{
return;
}
dictionary parms = new dictionary();
parms.put("sender", player);
messageTo(myEnclave, "PEFSynchRequest", parms, 0, false);
trace.log("force_rank", "force_rank::requestPEFs-> requesting enemy list from enclave", player, trace.TL_DEBUG);
return;
}
//
// @returns a list of players that are considered the enemies of @player given data stored on the @enclave
//
obj_id[] getCurrentDarkJediEnemies(obj_id player, obj_id enclave)
{
resizeable obj_id[] enemies = new obj_id[0];
dictionary banishmentData = getAndValidatePvPActionData(ACTION_BANISHMENT, enclave);
dictionary purgeData = getAndValidatePvPActionData(ACTION_PURGE_COUNCIL, enclave);
// if player is target of either a council purge or a banishment, then ALL other players in the ranks are their enemy
if((purgeData != null && isPvPActionVictim(player, purgeData)) || (banishmentData != null && isPvPActionVictim(player, banishmentData)))
{
trace.log("force_rank", "force_rank::getCurrentDarkJediEnemies: -> " + utils.getRealPlayerFirstName(player) + " is victim of purge/banishment. Returning ALL rank members as enemy.", player, trace.TL_DEBUG);
obj_id[] enemies2 = getAllPlayersInForceRank(enclave, -1);
utils.concatArrays(enemies, enemies2);
}
else
{
trace.log("force_rank", "force_rank::getCurrentDarkJediEnemies: -> " + utils.getRealPlayerFirstName(player) + " is NOT victim of purge/banishment. Checking for specific enemies...", player, trace.TL_DEBUG);
utils.concatArrays(enemies, getEnemiesForPvPAction(player, ACTION_VENDETTA, enclave));
utils.concatArrays(enemies, getEnemiesForPvPAction(player, ACTION_BANISHMENT, enclave));
utils.concatArrays(enemies, getEnemiesForPvPAction(player, ACTION_PURGE_COUNCIL, enclave));
utils.concatArrays(enemies, getEnemiesForPvPAction(player, ACTION_CANDIDATE_SUDDEN_DEATH, enclave));
}
return enemies;
}
//
// convenience method to return @true or @false, depending on whether or not the @player is force ranked
//
boolean isForceRanked(obj_id player)
{
return (getForceRank(player) >= 0);
}
//
// @returns true or false, depending on wether or not the @pet belongs to a factioned player
//
boolean canForceRankedPetEnterEnclave(obj_id pet, obj_id enclave)
{
if(pet_lib.isPet(pet))
{
if(!pet_lib.hasMaster(pet))
{
// not a pet that we can validate.
return false;
}
obj_id master = getMaster(pet); // pet's master has already been validated in previous call to pet_lib.hasMaster
// if the pet's master is force ranked, let it through
return (isForceRanked(master) && (isPlayersEnclave(enclave, master)));
}
return false;
}
//
// @returns true or false, depending on whether or not the @player has access to the @enclave
//
boolean isPlayersEnclave(obj_id enclave, obj_id player)
{
if (getCouncilAffiliation(enclave) == getCouncilAffiliation(player))
return true;
else
return false;
}
//
// @creates terminals for the Enclaves. Returns false on error or no terminals created.
//
boolean createEnclaveTerminals(obj_id enclave)
{
if (!isIdValid(enclave))
{
trace.log("force_rank", "force_rank.createEnclaveTerminals -- enclave is invalid", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return false;
}
if (!hasScript(enclave, force_rank.SCRIPT_ENCLAVE_CONTROLLER))
{
trace.log("force_rank", "force_rank.createEnclaveTerminals -- " + enclave + " is not an enclave building.", enclave, trace.TL_ERROR_LOG | trace.TL_DEBUG);
return false;
}
// Check to see if the enclave already has terminals.
obj_id voting_terminal = getVotingTerminal(enclave);
obj_id arena_terminal = getArenaTerminal(enclave);
obj_id chal_voting_terminal = getChallengeVotingTerminal(enclave);
if (isIdValid(voting_terminal))
{
if (getCouncilAffiliation(enclave) == DARK_COUNCIL)
{
if (isIdValid(arena_terminal))
return false;
}
else
{
if (isIdValid(chal_voting_terminal))
return false;
}
}
// Clean up the old stuff and make new stuff
if (isIdValid(voting_terminal))
destroyObject(voting_terminal);
if (isIdValid(arena_terminal))
destroyObject(arena_terminal);
if (isIdValid(chal_voting_terminal))
destroyObject(chal_voting_terminal);
int numRows = dataTableGetNumRows (JEDI_TERMINAL_DATATABLE);
string area = getCurrentSceneName();
for (int i = 0; i < numRows; i++)
{
dictionary row = dataTableGetRow(JEDI_TERMINAL_DATATABLE, i);
if (row == null)
continue;
if (row.getInt("Council") == getCouncilAffiliation(enclave))
{
float x = row.getFloat("x");
float y = row.getFloat("y");
float z = row.getFloat("z");
float rot = row.getFloat("Rotation");
string cell_name = row.getString("Cell");
if (cell_name == null || cell_name.length() < 1)
{
LOG("force_rank", "force_rank.createEnclaveTerminals -- cell name is null for " + enclave);
continue;
}
string template = row.getString("Template");
if (template == null || cell_name.length() < 1)
{
LOG("force_rank", "force_rank.createEnclaveTerminals -- can't find template " + template + " for " + enclave);
continue;
}
obj_id cell = getCellId(enclave, cell_name);
if (cell == null || cell_name.length() < 1)
{
LOG("force_rank", "force_rank.createEnclaveTerminals -- unknown cell name " + row.getString("Cell") + " for " + enclave);
continue;
}
location loc = new location(x, y, z, area, cell);
obj_id newTerminal = createObjectInCell(template, enclave, cell_name, loc);
LOG("force_rank", "force_rank.createEnclaveTerminals -- creating new terminal " + newTerminal + " for " + enclave);
//LOG("force_rank", "force_rank.createEnclaveTerminals -- terminal: " + newTerminal);
setYaw(newTerminal, rot);
persistObject(newTerminal);
}
}
return true;
}
int getPetitionInterval()
{
string config = getConfigSetting("GameServer", "frsPetitionInterval");
int value = utils.stringToInt(config);
if (value > 0)
return value;
else
return PETITION_INTERVAL;
}
int getVoteInterval()
{
string config = getConfigSetting("GameServer", "frsVoteInterval");
int value = utils.stringToInt(config);
if (value > 0)
return value;
else
return VOTING_INTERVAL;
}
int getAcceptanceInterval()
{
string config = getConfigSetting("GameServer", "frsAcceptanceInterval");
int value = utils.stringToInt(config);
if (value > 0)
return value;
else
return ACCEPTANCE_INTERVAL;
}
int getDemotionInterval()
{
string config = getConfigSetting("GameServer", "frsDemotionInterval");
int value = utils.stringToInt(config);
if (value > 0)
return value;
else
return REQUEST_DEMOTION_DURATION;
}
int getXpInterval()
{
string config = getConfigSetting("GameServer", "frsXpInterval");
int value = utils.stringToInt(config);
if (value > 0)
return value;
else
return XP_MAINTENANCE_INTERVAL;
}
/**** PRIVATE FUNCTIONS ************************************************
/***********************************************************************
* @brief requests an update from the cluster wide data system
*
* @param string player player first name
* @param int council
* @param int rank
* @param boolean lock_data
*
* @return return boolean
*********************************************************************/
boolean _updateForceRankData(obj_id source, int council, int data_mode, string params, string handler, boolean lock_data)
{
// Datamodes *****************
// 0: Enclave data save -- not used with this function
// 1: Request rank member list
// 2: Request pvp board data
// 3: Promote player
// 4: Demote player
// 5: Demote player (enclave authoritative)
// 6: Enclave obj_id
// 7: Update pvp board data.
// 8: Reset cluster data
// 9: Rename rank member
if (!isIdValid(source))
{
LOG("force_rank", "force_rank._updateForceRankData -- source is invalid.");
return false;
}
if (params == null)
{
LOG("force_rank", "force_rank._updateForceRankData -- params is null.");
return false;
}
if (handler == null)
{
LOG("force_rank", "force_rank._updateForceRankData -- handler is null.");
return false;
}
// Update the Clusterwide data.
int request_id = getClusterWideData(force_rank.CLUSTER_DATA_NAME, force_rank.STRING_CLUSTER_ENCLAVE_NAME + council, lock_data, source);
utils.setScriptVar(source, SCRIPT_VAR_DATA_REQUEST + request_id, data_mode);
utils.setScriptVar(source, SCRIPT_VAR_PARAMS_REQUEST + request_id, params);
utils.setScriptVar(source, SCRIPT_VAR_HANDLER_REQUEST + request_id, handler);
if (!hasScript(source, SCRIPT_DATA_HANDLER))
attachScript(source, SCRIPT_DATA_HANDLER);
return true;
}