/** * Copyright (C)2000-2002 Sony Online Entertainment Inc. * All Rights Reserved * * Title: group.scriptlib * Description: library of player group related functions * @author $Author: rpalacio $ * @version $Revision: $ */ /***** INCLUDES ********************************************************/ include library.sui; include library.utils; include library.prose; include library.planetary_map; include library.missions; /***** CONSTANTS *******************************************************/ const string SCRIPT_GROUP_OBJECT = "grouping.group_object"; const string SCRIPT_GROUP_MEMBER = "grouping.group_member"; const string GROUP_STF = "group"; //NOTIFY PROSE STRING_ID DEFINES const string_id PROSE_NOTIFY_UNKNOWN = new string_id("group","notify_unknown"); const string_id PROSE_NOTIFY_COIN_LOOT_INT = new string_id("group","notify_coin_loot_int"); const string_id PROSE_NOTIFY_COIN_LOOT_STRING = new string_id("group","notify_coin_loot_string"); const string_id PROSE_NOTIFY_PARTIAL_COIN_LOOT = new string_id ("group", "notify_partial_coin_loot_int"); const string_id PROSE_NOTIFY_ITEM_LOOT = new string_id("group","notify_item_loot"); const string_id PROSE_NOTIFY_PARTIAL_LOOT = new string_id("group","notify_partial_loot"); const string_id PROSE_NOTIFY_NO_LOOT = new string_id("group","notify_no_loot"); const string_id PROSE_NOTIFY_ERROR_LOOT = new string_id("group","notify_error_loot"); const string_id PROSE_NOTIFY_SINGLE_LOOT = new string_id("group","notify_single_loot"); const string_id PROSE_NOTIFY_HARVEST_CORPSE = new string_id("group","notify_harvest_corpse"); const string_id PROSE_NOTIFY_INCAP = new string_id("group","notify_incap"); const string_id PROSE_NOTIFY_DEATH = new string_id("group","notify_death"); const string_id PROSE_NOTIFY_CLONED = new string_id("group","notify_cloned"); const string_id PROSE_NOTIFY_CLONED_CITY = new string_id("group","notify_cloned_city"); const string_id PROSE_NOTIFY_OPTION_ON = new string_id("group","notify_option_on"); const string_id PROSE_NOTIFY_OPTION_OFF = new string_id("group","notify_option_off"); const string_id PROSE_SPLIT_COINS_SELF = new string_id("group","prose_split_coins_self"); const string_id PROSE_SPLIT_COINS_MISSION = new string_id("group","prose_split_coins_mission"); const float SPLIT_RANGE = 200f; const string HANDLER_SPLIT_SUCCESS = "handleSplitSuccess"; const string HANDLER_SPLIT_FAILURE = "handleSplitFailure"; const int FREE_FOR_ALL = 0; const int MASTER_LOOTER = 1; const int LOTTERY = 2; const int RANDOM = 3; /***** FUNCTIONS *******************************************************/ /***** GROUP CHAT *******************************************************/ string getGroupChatRoomName(obj_id gid) { if ( !isIdValid(gid) ) return null; return ( getGameChatCode() + "." + getGalaxyName() + ".group." + gid + ".GroupChat" ); } void sendGroupChatMessage(obj_id gid, prose_package msg) { string oobPP = packOutOfBandProsePackage(null, msg); string gRoom = getGroupChatRoomName(gid); chatSendToRoom(gRoom, null, oobPP); /* //TEMP DEBUG BLOCK obj_id[] members = getGroupMemberIds(gid); if ( members != null && members.length > 0 ) { for ( int i = 0; i < members.length; i++ ) { if ( members[i] != msg.actor.id ) sendSystemMessageProse(members[i], msg); } } */ } /***** UTILITY *******************************************************/ boolean isGroupObject(obj_id gid) { if ( isIdValid(gid) ) return ( getGameObjectType(gid) == GOT_group ); return false; } boolean isGrouped(obj_id target) { if ( isIdValid(target) ) return isIdValid(getGroupObject(target)); return false; } boolean inSameGroup(obj_id target1, obj_id target2) { if ( !isIdValid(target1) || !isIdValid(target2) ) return false; if ( target1 == target2 ) return true; if(beast_lib.isBeastMaster(target1)) { obj_id beast = beast_lib.getBeastOnPlayer(target1); if(beast == target2) return true; } if(beast_lib.isBeastMaster(target2)) { obj_id beast = beast_lib.getBeastOnPlayer(target2); if(beast == target1) return true; } obj_id gid1 = getGroupObject(target1); obj_id gid2 = getGroupObject(target2); if ( !isIdValid(gid1) ) { if(beast_lib.isBeast(target1)) { target1 = getMaster(target1); if ( target1 == target2 ) return true; gid1 = getGroupObject(target1); if( !isIdValid(gid1) ) return false; } else { return false; } } if ( !isIdValid(gid2) ) { if(beast_lib.isBeast(target2)) { target2 = getMaster(target2); if ( target1 == target2 ) return true; gid2 = getGroupObject(target2); if( !isIdValid(gid2) ) return false; } else return false; } return ( gid1 == gid2 ); } obj_id getLeader(obj_id target) { if ( isIdValid(target) ) { obj_id gid = null; if ( isGroupObject(target) ) gid = target; else gid = getGroupObject(target); if ( isIdValid(gid) ) return getGroupLeaderId(gid); } return null; } boolean isLeader(obj_id target) { if ( isIdValid(target) ) { obj_id gid = getGroupObject(target); if ( isIdValid(gid) ) return ( getGroupLeaderId(gid) == target ); } return false; } void changeLeader(obj_id self) { obj_id groupid = getGroupObject(self); if(isIdValid(groupid) && isLeader(self)) { obj_id [] members = getGroupMemberIds(groupid); if(members != null && members.length > 0) { boolean found = false; for(int i = 0, j = members.length; i < j && !found; i++) { if(!isIdValid(members[i])) { continue; } if(members[i] != self) { found = true; queueCommand(self, ##"makeLeader", members[i], "", COMMAND_PRIORITY_FRONT); } } } } } void leaveGroup(obj_id player) { changeLeader(player); queueCommand(player, ##"leaveGroup", player, "", COMMAND_PRIORITY_FRONT); } boolean isMixedFactionGroup(obj_id groupId) { if(!isIdValid(groupId)) { return false; } obj_id [] members = getGroupMemberIds(groupId); if(members != null && members.length > 0) { int faction = factions.FACTION_FLAG_UNKNOWN; for(int i = 0, j = members.length; i < j; i++) { if(!isIdValid(members[i]) || !exists(members[i])) { continue; } // Initialize the group's faction if(faction == factions.FACTION_FLAG_UNKNOWN) { faction = factions.getFactionFlag(members[i]); } // Compare members versus the first faction found if(faction != factions.getFactionFlag(members[i])) { return true; } } } return false; } string getCreatureGroupName(obj_id target) { if ( isIdValid(target) ) { obj_id gid = getGroupObject(target); if ( isIdValid(gid) ) return getGroupName(gid); } return null; } /***** MEMBER UTILITY *******************************************************/ Vector getPCMembersInRange(obj_id actor, float range) { if ( !isIdValid(actor) || !exists(actor) || !actor.isLoaded() ) return null; obj_id gid = getGroupObject(actor); if ( !isIdValid(gid) ) return null; resizeable obj_id[] targets = new obj_id[0]; obj_id[] members = getGroupMemberIds(gid); if ( members != null && members.length > 0 ) { location here = getWorldLocation(actor); for ( int i = 0; i < members.length; i++ ) { obj_id member = members[i]; if ( isIdValid(member) && member.isLoaded() && isPlayer(member) ) { location there = getWorldLocation(member); if ( getDistance(here, there) <= range ) targets = utils.addElement(targets, member); } } } return targets; } Vector getPCMembersInRange() { return getPCMembersInRange(getSelf()); } Vector getPCMembersInRange(float range) { return getPCMembersInRange(getSelf(), range); } Vector getPCMembersInRange(obj_id actor) { return getPCMembersInRange(actor, 200f); } /***** NOTIFICATIONS *******************************************************/ void notifyCoinLoot(obj_id gid, obj_id actor, obj_id target, int amt) { if ( !isIdValid(gid) || !isIdValid(actor) || !isIdValid(target) ) return; if ( amt < 1 ) return; prose_package ppCoinLoot = prose.getPackage(PROSE_NOTIFY_COIN_LOOT_INT, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), null, null, null, amt, 0.0f); sendGroupChatMessage(gid, ppCoinLoot); } void notifyCoinLootFail(obj_id gid, obj_id actor, obj_id target, int amt) { if ( !isIdValid(gid) || !isIdValid(actor) || !isIdValid(target) ) return; if ( amt < 1 ) return; int remainder = getCashBalance(target); prose_package ppPartialCoinLoot = prose.getPackage(PROSE_NOTIFY_PARTIAL_COIN_LOOT, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), null, null, null, amt, 0.0f); sendGroupChatMessage(gid, ppPartialCoinLoot); sendSystemMessageProse(actor, ppPartialCoinLoot); } void notifyItemLoot(obj_id gid, obj_id actor, obj_id target, obj_id item) { if ( !isIdValid(gid)) { return; } if ( !isIdValid(actor)) { return; } if (!isIdValid(target) ) { return; } if (!isIdValid(item) ) { return; } prose_package ppSingleLoot = prose.getPackage(PROSE_NOTIFY_SINGLE_LOOT, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), item, getAssignedName(item), getNameStringId(item), 0, 0.0f); obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(gid); for (int x = 0; x < objMembersWhoExist.length; x ++) { sendSystemMessageProse (objMembersWhoExist[x], ppSingleLoot); } } void notifyItemLoot(obj_id gid, obj_id actor, obj_id target, obj_id[] items, int leftCount) { if ( !isIdValid(gid) || !isIdValid(actor) || !isIdValid(target) ) return; if ( items == null || items.length == 0 ) { prose_package ppNoLoot = prose.getPackage(PROSE_NOTIFY_NO_LOOT, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), null, null, null, leftCount, 0.0f); sendSystemMessageProse (gid, ppNoLoot); } else { int cnt = items.length; prose_package ppItemLoot = prose.getPackage(PROSE_NOTIFY_ITEM_LOOT, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), null, null, null, cnt, 0.0f); sendSystemMessageProse (gid, ppItemLoot); for ( int i = 0; i < items.length; i++ ) notifyItemLoot(gid, actor, target, items[i]); } if ( leftCount > 0 ) { prose_package ppNoLoot = prose.getPackage(PROSE_NOTIFY_PARTIAL_LOOT, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), null, null, null, leftCount, 0.0f); sendSystemMessageProse (gid, ppNoLoot); } } void notifyItemLoot(obj_id gid, obj_id actor, obj_id target, obj_id[] items) { notifyItemLoot(gid, actor, target, items, 0); } void notifyHarvest(obj_id gid, obj_id actor, obj_id target, string rType, int amt) { if ( !isIdValid(gid) || !isIdValid(actor) || !isIdValid(target) ) return; if ( rType == null || rType.equals("") ) return; if ( amt < 1 ) return; prose_package ppHarvest = prose.getPackage(PROSE_NOTIFY_HARVEST_CORPSE, actor, getName(actor), null, target, getAssignedName(target), getNameStringId(target), null, rType, null, amt, 0.0f); sendGroupChatMessage(gid, ppHarvest); } void notifyIncapacitation(obj_id gid, obj_id actor) { if ( !isIdValid(gid) || !isIdValid(actor) ) return; prose_package ppIncap = prose.getPackage(PROSE_NOTIFY_INCAP, actor, getName(actor), null, null, null, null, null, null, null, 0, 0.0f); sendGroupChatMessage(gid, ppIncap); } void notifyDeath(obj_id gid, obj_id actor) { if ( !isIdValid(gid) || !isIdValid(actor) ) return; prose_package ppDeath = prose.getPackage(PROSE_NOTIFY_DEATH, null, getAssignedName(actor), null, null, null, null, null, null, null, 0, 0.0f); sendGroupChatMessage(gid, ppDeath); } void notifyCloned(obj_id gid, obj_id actor) { if ( !isIdValid(gid) || !isIdValid(actor) ) return; location there = getWorldLocation(actor); if ( there != null ) { string cityName = planetary_map.getCityRegionName(there); if ( cityName != null && !cityName.equals("") ) { prose_package ppClonedCity = prose.getPackage(PROSE_NOTIFY_CLONED_CITY, null, getAssignedName(actor), null, null, null, null, null, cityName, null, 0, 0.0f); sendGroupChatMessage(gid, ppClonedCity); return; } } prose_package ppCloned = prose.getPackage(PROSE_NOTIFY_CLONED, actor, getName(actor), null, null, null, null, null, null, null, 0, 0.0f); sendGroupChatMessage(gid, ppCloned); } /***** COMMANDS *******************************************************/ void splitCoins(int amt, dictionary params) { obj_id actor = getSelf(); if ( !isIdValid(actor) || amt < 1 ) return; obj_id gid = getGroupObject(actor); if ( !isIdValid(gid) ) return; if ( params == null ) params = new dictionary(); int totalDividends = 0; resizeable obj_id[] targets = getPCMembersInRange(SPLIT_RANGE); if ( targets != null && targets.length > 0 ) { int dividend = (int)(amt/targets.length); params.put("target", actor); params.put("amt", dividend); if (isDepositSafe(targets, dividend))// check for trial players in the group. { for ( int i = 0; i < targets.length; i++ ) { if ( targets[i] != actor ) { messageTo(targets[i], "handleRequestSplitShare", params, 0, false); totalDividends += dividend; } } } else { int placeHolder = amt; int toPay = 0; obj_id[] safeMoney = getSafeMoney(targets, dividend);// non trial accounts obj_id[] lowMoney = getUnsafeMoney(targets, dividend);// trial accounts if (lowMoney.length > 0 && lowMoney != null)// pay trial members first { for (int j=0;j 0)// check to prevent dividing by zero. remainder = (int) (placeHolder/safeMoney.length); else remainder = placeHolder; params.put("amt", remainder); if (safeMoney.length > 0 && safeMoney != null) { for (int k=0;k 0 ) { int dividend = (int)(amt/targets.length); params.put("target", actor); params.put("amt", dividend); if (isDepositSafe(targets, dividend))// check for trial players in group { if ( targets != null && targets.length > 0 ) { for ( int i = 0; i < targets.length; i++ ) { if ( targets[i] != actor ) messageTo(targets[i], "handleRequestPayoutShare", params, 0, false); else messageTo(actor, HANDLER_SPLIT_SUCCESS, params, 0, false); } } } else { int toPay = 0; int placeHolder = amt; obj_id[] safeMoney = getSafeMoney(targets, dividend);// non trial accounts obj_id[] lowMoney = getUnsafeMoney(targets, dividend);// trial accounts if (lowMoney != null && lowMoney.length > 0) { for ( int i = 0; i < lowMoney.length; i++ ) { toPay = getSafeDifference(targets[i], dividend);// get valid ammount under the cap if ( lowMoney[i] != actor )// don't pay yourself { params.put("amt", toPay);// dynamic update share placeHolder -= toPay;// subtract from the total. messageTo(lowMoney[i], "handleRequestPayoutShare", params, 0, false); } } } int remainder = 0; if (safeMoney.length > 0)// check to avoid dividing by zero remainder = (int) placeHolder/safeMoney.length; else remainder = (int) placeHolder; params.put("amt", remainder); //player notifies himself how much their share is. Ammount will be valid since it is <= than what was granted. messageTo(actor, HANDLER_SPLIT_SUCCESS, params, 0, false); if ( safeMoney != null && safeMoney.length > 0) { for (int k = 0; k< safeMoney.length;k++)// pay regular members their share. { if (safeMoney[k] != actor) { messageTo(safeMoney[k], "handleRequestPayoutShare", params, 0, false); } } } } } } void splitBank(int amt) { splitBank(amt, null); } boolean isDepositSafe(resizeable obj_id[] members, int money) { for (int i=0;i 50000) return false; } } return true; } obj_id[] getSafeMoney(resizeable obj_id[] members, int money) { resizeable obj_id[] returnArray = new obj_id[]; for (int i=0;i 50000) { return safe; } else { return money; } } else { return money; } } /***** GROUP UTILITY *******************************************************/ boolean systemPayoutToGroup(string acct, obj_id player, int amt, string reason, string returnHandler, dictionary params) { return systemPayoutToGroupInternal(acct, player, amt, reason, null, returnHandler, 0.0f, params); } boolean systemPayoutToGroup(string acct, obj_id player, int amt, string_id reasonId, string returnHandler, dictionary params) { return systemPayoutToGroupInternal(acct, player, amt, null, reasonId, returnHandler, 0.0f, params); } boolean systemPayoutToGroup(string acct, obj_id player, int amt, string_id reasonId, string returnHandler, float divisor, dictionary params) { return systemPayoutToGroupInternal(acct, player, amt, null, reasonId, returnHandler, divisor, params); } boolean systemPayoutToGroupInternal(string acct, obj_id player, int amt, string reason, string_id reasonId, string returnHandler, float divisor, dictionary params) { return systemPayoutToGroupInternal(acct, player, amt, null, reasonId, returnHandler, divisor, params, obj_id.NULL_ID); } boolean systemPayoutToGroupInternal(string acct, obj_id player, int amt, string reason, string_id reasonId, string returnHandler, float divisor, dictionary params, obj_id objMissionData) { if ( acct == null || acct.equals("") ) return false; if ( !isIdValid(player) ) return false; if ( amt < 1 ) return false; if ( returnHandler == null || returnHandler.equals("") ) return false; if ( params == null ) params = new dictionary(); obj_id gid = getGroupObject(player); if ( !isIdValid(gid) ) return false; obj_id self = getSelf(); params.put("msg.id", self); params.put("msg.handler", returnHandler); if ( reason != null && !reason.equals("") ) params.put("reason", reason); if ( reasonId != null ) params.put("reasonId", reasonId); params.put(money.DICT_ACCT_NAME, acct); params.put(money.DICT_AMOUNT, amt); LOG("NewMission", "Payout of " + amt); if ( acct != null && !acct.equals("") && amt > 0 ) { LOG("NewMission", "Distribute " + amt); boolean allReceived = distributeMoneyToGroup(player, amt, SPLIT_RANGE, acct, divisor, params, objMissionData); string_id partialPayment = new string_id("mission/mission_generic", "group_too_far"); if ( reasonId == null ) { CustomerServiceLog("Mission", "We transferred " + amt + " credits to a group, but there was no message to tell them that", player); } else { obj_id[] gmembers = group.getGroupMemberIds(gid); if (gmembers != null && gmembers.length > 0) { for (int i = 0; i < gmembers.length; ++i) { sendSystemMessage(gmembers[i], reasonId); if (!allReceived) { sendSystemMessage(gmembers[i], partialPayment); } } } } } return true; } boolean distributeMoneyToGroup(obj_id player, int amt, float range, string acct, float divisorInput, dictionary params) { return distributeMoneyToGroup(player, amt, range, acct, divisorInput, params, obj_id.NULL_ID); } boolean distributeMoneyToGroup(obj_id player, int amt, float range, string acct, float divisorInput, dictionary params, obj_id objMissionData) { if ( amt < 1 ) return false; obj_id groupObject = getGroupObject(player); if ( !isIdValid(groupObject) ) return false; if ( params == null ) params = new dictionary(); //if we have a mission level we are a destroy mission int missionLevel = params.getInt("intPlayerDifficulty"); //LOG("NewMission", "missionLevel: " + missionLevel ); resizeable obj_id[] targets = getPCMembersInRange(player, range); if ( targets != null && targets.length > 0) { float divisor = divisorInput; if (divisor < 1.0f) { divisor = targets.length; } string_id ppString = PROSE_SPLIT_COINS_SELF; for ( int i = 0; i < targets.length; i++ ) { if(missions.isDestroyMission(objMissionData)) { //scale the reward based on group makeup if (targets.length > 1) divisor = missions.alterMissionPayoutDivisor(targets[i], divisor, missionLevel); //increment daily count missions.incrementDaily(targets[i]); ppString = PROSE_SPLIT_COINS_MISSION; } int payout = amt/((int)divisor); transferBankCreditsFromNamedAccount(acct, targets[i], payout, "succ", "noHandler", params); prose_package ppSplit = prose.getPackage(ppString, null, Integer.toString(amt), null, null, Integer.toString(payout), null, null, null, null, 0, 0.0f); sendSystemMessageProse(targets[i], ppSplit); //LOG("NewMission", "Distribution:" + targets[i] + " " + amt + "/" + divisor + "=" + payout ); } } //LOG("NewMission", "Group Members: " + getGroupSize(groupObject) + " :::Targets: " + targets.length ); return (targets.length >= getGroupSize(groupObject)); } void destroyGroupWaypoint(obj_id player) { // support function for destroying the group waypoint. // This also removes the 'groupWaypoint' objvar obj_id groupWaypoint = getObjIdObjVar(player, "groupWaypoint"); if(isIdValid(groupWaypoint)) { destroyWaypointInDatapad(groupWaypoint, player); removeObjVar(player, "groupWaypoint"); } } boolean distributeMissionXpToGroup(obj_id player, float range, obj_id objMissionData) { obj_id groupObject = getGroupObject(player); if (!isIdValid(groupObject)) return false; if (!isIdValid(objMissionData)) return false; //if we have a mission level we are a destroy mission int missionLevel = getIntObjVar(objMissionData, "intPlayerDifficulty"); //LOG("NewMission", "missionLevel: " + missionLevel ); resizeable obj_id[] targets = getPCMembersInRange(player, range); if ( targets != null && targets.length > 0) { for ( int i = 0; i < targets.length; i++ ) { if(missions.isDestroyMission(objMissionData) && missions.canEarnDailyMissionXp(targets[i])) xp.grantMissionXp(targets[i], missionLevel); } } //LOG("NewMission", "Group Members XP: " + getGroupSize(groupObject) + " :::Targets: " + targets.length ); return (targets.length >= getGroupSize(groupObject)); }