/******************************************************************************************************************************************** * Title: force_rank.scriptlib * Description: Support functions for the Force Ranking System **********************************************************************/ /***** 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); // UPDATE 11/14/14: No need for persisting objects anymore. //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; }