diff --git a/scripts/commands/generic/cmdPVP.js b/scripts/commands/generic/cmdPVP.js new file mode 100644 index 000000000..9299b413f --- /dev/null +++ b/scripts/commands/generic/cmdPVP.js @@ -0,0 +1,30 @@ +var execute = function(galManager, player, target, args) { + var creature = player.getCreatureObject(); + var PvpFaction = Java.type("resources.PvpFaction"); + var FactionIntent = Java.type("intents.FactionIntent"); + var FactionIntentType = Java.type("intents.FactionIntent.FactionIntentType"); + var ChatSystemMessage = Java.type("network.packets.swg.zone.chat.ChatSystemMessage"); + var SystemChatType = Java.type("network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType"); + var intent = null; + + // Ziggy was using this to test until recruiters are enabled. + + if (args.length > 0) { + if (args.indexOf("imperial") > -1) { + intent = new FactionIntent(creature, PvpFaction.IMPERIAL); + } + else if (args.indexOf("rebel") > -1) { + intent = new FactionIntent(creature, PvpFaction.REBEL); + } + else { + intent = new FactionIntent(creature, PvpFaction.NEUTRAL); + } + intent.broadcast(); + } else if (creature.getPvpFaction() != PvpFaction.NEUTRAL) { + intent = new FactionIntent(creature, FactionIntentType.STATUSUPDATE); + intent.broadcast(); + } else { + creature.getOwner().sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, "@faction_recruiter:not_aligned")); + } + +}; \ No newline at end of file diff --git a/src/intents/FactionIntent.java b/src/intents/FactionIntent.java new file mode 100644 index 000000000..ae465b6e0 --- /dev/null +++ b/src/intents/FactionIntent.java @@ -0,0 +1,47 @@ +package intents; + +import resources.PvpFaction; +import resources.control.Intent; +import resources.objects.tangible.TangibleObject; + +public class FactionIntent extends Intent { + + public static final String TYPE = "FactionIntent"; + private TangibleObject target; + private PvpFaction newFaction; + private FactionIntentType updateType; + + private FactionIntent(TangibleObject target) { + super(TYPE); + this.target = target; + } + + public FactionIntent(TangibleObject target, FactionIntentType updateType) { + this(target); + this.updateType = updateType; + } + + public FactionIntent(TangibleObject target, PvpFaction newFaction) { + this(target, FactionIntentType.FACTIONUPDATE); + this.newFaction = newFaction; + } + + public TangibleObject getTarget() { + return target; + } + + public PvpFaction getNewFaction() { + return newFaction; + } + + public FactionIntentType getUpdateType() { + return updateType; + } + + public enum FactionIntentType { + FLAGUPDATE, + STATUSUPDATE, + FACTIONUPDATE // Is automatically set in the correct constructor, don't use manually. + } + +} \ No newline at end of file diff --git a/src/main/ProjectSWG.java b/src/main/ProjectSWG.java index 2510a3b07..48eeb11e7 100644 --- a/src/main/ProjectSWG.java +++ b/src/main/ProjectSWG.java @@ -182,4 +182,4 @@ public class ProjectSWG { } -} +} \ No newline at end of file diff --git a/src/network/packets/swg/zone/UpdatePvpStatusMessage.java b/src/network/packets/swg/zone/UpdatePvpStatusMessage.java index 3edf08064..cba28afe7 100644 --- a/src/network/packets/swg/zone/UpdatePvpStatusMessage.java +++ b/src/network/packets/swg/zone/UpdatePvpStatusMessage.java @@ -30,21 +30,14 @@ package network.packets.swg.zone; import network.packets.swg.SWGPacket; import java.nio.ByteBuffer; +import java.util.EnumSet; + +import resources.PvpFlag; public class UpdatePvpStatusMessage extends SWGPacket { public static final int CRC = getCrc("UpdatePvpStatusMessage"); - - public static final int ATTACKABLE = 1; - public static final int AGGRESSIVE = 2; - public static final int OVERT = 4; - public static final int TEF = 8; - public static final int PLAYER = 16; - public static final int ENEMY = 32; - public static final int GOING_OVERT = 64; // purple/blue blink - public static final int GOING_COVERT = 128; // green blink - public static final int DUEL = 256; - private int flag = 16; + private PvpFlag flag = PvpFlag.PLAYER; private int playerFaction = 0; private long objId = 0; @@ -52,7 +45,7 @@ public class UpdatePvpStatusMessage extends SWGPacket { } - public UpdatePvpStatusMessage(int playerType, int flag, long objId) { + public UpdatePvpStatusMessage(PvpFlag playerType, int flag, long objId) { this.flag = playerType; this.playerFaction = flag; this.objId = objId; @@ -61,7 +54,13 @@ public class UpdatePvpStatusMessage extends SWGPacket { public void decode(ByteBuffer data) { if (!super.decode(data, CRC)) return; - flag = getInt(data); + EnumSet flags = PvpFlag.getFlags(getInt(data)); + PvpFlag tempFlag = flags.iterator().next(); + + if (tempFlag!= null) + flag = flags.iterator().next(); + else + flag = PvpFlag.PLAYER; playerFaction = getInt(data); objId = getLong(data); } @@ -71,7 +70,7 @@ public class UpdatePvpStatusMessage extends SWGPacket { ByteBuffer data = ByteBuffer.allocate(length); addShort(data, 4); addInt( data, CRC); - addInt( data, flag); + addInt( data, flag.getBitmask()); addInt( data, playerFaction); addLong( data, objId); return data; @@ -79,6 +78,6 @@ public class UpdatePvpStatusMessage extends SWGPacket { public long getObjectId() { return objId; } public int getPlayerFaction() { return playerFaction; } - public int getPlayerType() { return flag; } + public PvpFlag getPlayerType() { return flag; } -} +} \ No newline at end of file diff --git a/src/resources/PvpFaction.java b/src/resources/PvpFaction.java new file mode 100644 index 000000000..3e017f0e1 --- /dev/null +++ b/src/resources/PvpFaction.java @@ -0,0 +1,21 @@ +package resources; + +import resources.common.CRC; + +public enum PvpFaction { + + NEUTRAL(0), + IMPERIAL(CRC.getCrc("imperial")), + REBEL(CRC.getCrc("rebel")); + + private int crc; + + PvpFaction(int crc) { + this.crc = crc; + } + + public int getCrc() { + return crc; + } + +} \ No newline at end of file diff --git a/src/resources/PvpFlag.java b/src/resources/PvpFlag.java new file mode 100644 index 000000000..6cb759df7 --- /dev/null +++ b/src/resources/PvpFlag.java @@ -0,0 +1,35 @@ +package resources; + +import java.util.EnumSet; + +public enum PvpFlag { + + ATTACKABLE(1<<0), + AGGRESSIVE(1<<1), + OVERT(1<<2), + TEF(1<<3), + PLAYER(1<<4), + ENEMY(1<<5), + GOING_OVERT(1<<6), + GOING_COVERT(1<<7), + DUEL(1<<8); + + private int bitmask; + + PvpFlag(int bitmask) { + this.bitmask = bitmask; + } + + public int getBitmask() { + return bitmask; + } + public static EnumSet getFlags(int bits) { + EnumSet states = EnumSet.noneOf(PvpFlag.class); + for (PvpFlag state : values()) { + if ((state.getBitmask() & bits) != 0) + states.add(state); + } + return states; + } + +} \ No newline at end of file diff --git a/src/resources/PvpStatus.java b/src/resources/PvpStatus.java new file mode 100644 index 000000000..bde504fc8 --- /dev/null +++ b/src/resources/PvpStatus.java @@ -0,0 +1,19 @@ +package resources; + +public enum PvpStatus { + + ONLEAVE(0), + COMBATANT(1), + SPECIALFORCES(2); + + private int value; + + PvpStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + +} \ No newline at end of file diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 851e74bf3..ccad83987 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -36,6 +36,7 @@ import network.packets.swg.zone.baselines.Baseline.BaselineType; import network.packets.swg.zone.object_controller.PostureUpdate; import resources.HologramColour; import resources.Posture; +import resources.PvpFlag; import resources.Race; import resources.collections.SWGList; import resources.collections.SWGMap; @@ -780,7 +781,7 @@ public class CreatureObject extends TangibleObject { target.sendPacket(new UpdatePostureMessage(posture.getId(), getObjectId())); if (getOwner() != null && target != getOwner()) { - target.sendPacket(new UpdatePvpStatusMessage(UpdatePvpStatusMessage.PLAYER, 0, getObjectId())); + target.sendPacket(new UpdatePvpStatusMessage(PvpFlag.PLAYER, 0, getObjectId())); } } diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index 235aa7720..5f0a637da 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -27,7 +27,12 @@ ***********************************************************************************/ package resources.objects.tangible; +import intents.FactionIntent; +import intents.FactionIntent.FactionIntentType; import network.packets.swg.zone.baselines.Baseline.BaselineType; +import resources.PvpFaction; +import resources.PvpFlag; +import resources.PvpStatus; import resources.network.BaselineBuilder; import resources.objects.SWGObject; import resources.player.Player; @@ -43,8 +48,8 @@ public class TangibleObject extends SWGObject { private boolean inCombat = false; private int condition = 0; private int pvpFlags = 0; - private int pvpType = 0; - private int pvpFactionId = 0; + private PvpStatus pvpStatus = PvpStatus.COMBATANT; + private PvpFaction pvpFaction = PvpFaction.NEUTRAL; private boolean visibleGmOnly = false; private byte [] objectEffects = new byte[0]; private int optionFlags = 0; @@ -82,18 +87,48 @@ public class TangibleObject extends SWGObject { return condition; } + public void setPvpFlags(PvpFlag... pvpFlags) { + for(PvpFlag pvpFlag : pvpFlags) + this.pvpFlags |= pvpFlag.getBitmask(); + + new FactionIntent(this, FactionIntentType.FLAGUPDATE).broadcast(); + } + + public void clearPvpFlags(PvpFlag... pvpFlags) { + for(PvpFlag pvpFlag : pvpFlags) + this.pvpFlags &= ~pvpFlag.getBitmask(); + + new FactionIntent(this, FactionIntentType.FLAGUPDATE).broadcast(); + } + + public boolean hasPvpFlag(PvpFlag pvpFlag) { + return (pvpFlags & pvpFlag.getBitmask()) != 0; + } + + public PvpStatus getPvpStatus() { + return pvpStatus; + } + + public void setPvpStatus(PvpStatus pvpStatus) { + this.pvpStatus = pvpStatus; + + sendDelta(3, 5, pvpStatus.getValue()); + } + + public PvpFaction getPvpFaction() { + return pvpFaction; + } + + public void setPvpFaction(PvpFaction pvpFaction) { + this.pvpFaction = pvpFaction; + + sendDelta(3, 4, pvpFaction.getCrc()); + } + public int getPvpFlags() { return pvpFlags; } - public int getPvpType() { - return pvpType; - } - - public int getPvpFactionId() { - return pvpFactionId; - } - public boolean isVisibleGmOnly() { return visibleGmOnly; } @@ -126,18 +161,6 @@ public class TangibleObject extends SWGObject { this.condition = condition; } - public void setPvpFlags(int pvpFlags) { - this.pvpFlags = pvpFlags; - } - - public void setPvpType(int pvpType) { - this.pvpType = pvpType; - } - - public void setPvpFactionId(int pvpFactionId) { - this.pvpFactionId = pvpFactionId; - } - public void setVisibleGmOnly(boolean visibleGmOnly) { this.visibleGmOnly = visibleGmOnly; } @@ -198,8 +221,8 @@ public class TangibleObject extends SWGObject { public void createBaseline3(Player target, BaselineBuilder bb) { super.createBaseline3(target, bb); // 4 variables - BASE3 (4) - bb.addInt(0); // Faction - 4 - bb.addInt(0); // Faction Status - 5 + bb.addInt(pvpFaction.getCrc()); // Faction - 4 + bb.addInt(pvpStatus.getValue()); // Faction Status - 5 bb.addArray(appearanceData); // - 6 bb.addInt(0); // Component customization (Set, Integer) - 7 bb.addInt(0); //updates @@ -243,4 +266,12 @@ public class TangibleObject extends SWGObject { bb.incrementOperandCount(2); } -} + + @Override + protected void sendBaselines(Player target) { + super.sendBaselines(target); + + new FactionIntent(this, FactionIntentType.FLAGUPDATE).broadcast(); + } + +} \ No newline at end of file diff --git a/src/resources/radial/RadialItem.java b/src/resources/radial/RadialItem.java index 5551fa5db..221f9d83e 100644 --- a/src/resources/radial/RadialItem.java +++ b/src/resources/radial/RadialItem.java @@ -4,127 +4,329 @@ import java.util.Hashtable; import java.util.Map; public enum RadialItem { - UNKNOWN (""), - COMBAT_TARGET (""), - COMBAT_UNTARGET (""), - COMBAT_ATTACK (""), - COMBAT_PEACE (""), - COMBAT_DUEL (""), - COMBAT_DEATH_BLOW (""), - EXAMINE (""), - EXAMINE_CHARACTERSHEET (""), - TRADE_START (""), - TRADE_ACCEPT (""), - ITEM_PICKUP (""), - ITEM_EQUIP (""), - ITEM_UNEQUIP (""), - ITEM_DROP (""), - ITEM_DESTROY (""), - ITEM_TOKEN (""), - ITEM_OPEN (""), - ITEM_OPEN_NEW_WINDOW (""), - ITEM_ACTIVATE (""), - ITEM_DEACTIVATE (""), - ITEM_USE (""), - ITEM_USE_SELF (""), - ITEM_USE_OTHER (""), - ITEM_SIT (""), - ITEM_MAIL (""), - CONVERSE_START (""), - CONVERSE_RESPOND (""), - CONVERSE_RESPONSE (""), - CONVERSE_STOP (""), - CRAFT_OPTIONS (""), - CRAFT_START (""), - CRAFT_HOPPER_INPUT (""), - CRAFT_HOPPER_OUTPUT (""), - TERMINAL_MISSION_LIST (""), - MISSION_DETAILS (""), - LOOT (""), - LOOT_ALL (""), - GROUP_INVITE (""), - GROUP_JOIN (""), - GROUP_LEAVE (""), - GROUP_KICK (""), - GROUP_DISBAND (""), - GROUP_DECLINE (""), - EXTRACT_OBJECT (""), - PET_CALL (""), - TERMINAL_AUCTION_USE (""), - CREATURE_FOLLOW (""), - CREATURE_STOP_FOLLOW (""), - SPLIT (""), - IMAGEDESIGN (""), - SET_NAME (""), - ITEM_ROTATE (""), - ITEM_ROTATE_RIGHT (""), - ITEM_ROTATE_LEFT (""), - ITEM_MOVE (""), - ITEM_MOVE_FORWARD (""), - ITEM_MOVE_BACK (""), - ITEM_MOVE_UP (""), - ITEM_MOVE_DOWN (""), - PET_STORE (""), - VEHICLE_GENERATE (""), - VEHICLE_STORE (""), - MISSION_ABORT (""), - MISSION_END_DUTY (""), - SHIP_MANAGE_COMPONENTS (""), - WAYPOINT_AUTOPILOT (""), - PROGRAM_DROID (""), - VEHICLE_OFFER_RIDE (""), - ITEM_PUBLIC_CONTAINER_USE1 (""), - COLLECTIONS (""), - GROUP_MASTER_LOOTER (""), - GROUP_MAKE_LEADER (""), - GROUP_LOOT (""), - ITEM_ROTATE_FORWARD (""), - ITEM_ROTATE_BACKWARD (""), - ITEM_ROTATE_CLOCKWISE (""), - ITEM_ROTATE_COUNTERCLOCKWISE (""), - ITEM_ROTATE_RANDOM (""), - ITEM_ROTATE_RANDOM_YAW (""), - ITEM_ROTATE_RANDOM_PITCH (""), - ITEM_ROTATE_RANDOM_ROLL (""), - ITEM_ROTATE_RESET (""), - ITEM_ROTATE_COPY (""), - ITEM_MOVE_COPY_LOCATION (""), - ITEM_MOVE_COPY_HEIGHT (""), - GROUP_TELL (""), - ITEM_WP_SETCOLOR (""), - ITEM_WP_SETCOLOR_BLUE (""), - ITEM_WP_SETCOLOR_GREEN (""), - ITEM_WP_SETCOLOR_ORANGE (""), - ITEM_WP_SETCOLOR_YELLOW (""), - ITEM_WP_SETCOLOR_PURPLE (""), - ITEM_WP_SETCOLOR_WHITE (""), - ITEM_MOVE_LEFT (""), - ITEM_MOVE_RIGHT (""), - ROTATE_APPLY (""), - ROTATE_RESET (""), - WINDOW_LOCK (""), - WINDOW_UNLOCK (""), - GROUP_CREATE_PICKUP_POINT (""), - GROUP_USE_PICKUP_POINT (""), - GROUP_USE_PICKUP_POINT_NOCAMP (""), - VOICE_SHORTLIST_REMOVE (""), - VOICE_INVITE (""), - VOICE_KICK (""), - ITEM_EQUIP_APPEARANCE (""), - ITEM_UNEQUIP_APPEARANCE (""), - OPEN_STORYTELLER_RECIPE (""), - CLIENT_MENU_LAST (""), - SERVER_MENU1 (""), - SERVER_MENU2 (""), - SERVER_PET_MOUNT (""), - SERVER_VEHICLE_ENTER_EXIT (""), - BANK_TRANSFER ("@sui:bank_credits"), - BANK_ITEMS ("@sui:bank_items"), - BANK_WITHDRAW_ALL ("@sui:bank_withdrawall"), - BANK_DEPOSIT_ALL ("@sui:bank_depositall"), - BANK_RESERVE ("@sui:bank_galactic_reserve"), - BANK_RESERVE_WITHDRAW ("@sui:bank_galactic_reserve_withdraw"), - BANK_RESERVE_DEPOSIT ("@sui:bank_galactic_reserve_deposit"); + UNKNOWN (""), + COMBAT_TARGET (""), + COMBAT_UNTARGET (""), + COMBAT_ATTACK (""), + COMBAT_PEACE (""), + COMBAT_DUEL (""), + COMBAT_DEATH_BLOW (""), + EXAMINE (""), + EXAMINE_CHARACTERSHEET (""), + TRADE_START (""), + TRADE_ACCEPT (""), + ITEM_PICKUP (""), + ITEM_EQUIP (""), + ITEM_UNEQUIP (""), + ITEM_DROP (""), + ITEM_DESTROY (""), + ITEM_TOKEN (""), + ITEM_OPEN (""), + ITEM_OPEN_NEW_WINDOW (""), + ITEM_ACTIVATE (""), + ITEM_DEACTIVATE (""), + ITEM_USE (""), + ITEM_USE_SELF (""), + ITEM_USE_OTHER (""), + ITEM_SIT (""), + ITEM_MAIL (""), + CONVERSE_START (""), + CONVERSE_RESPOND (""), + CONVERSE_RESPONSE (""), + CONVERSE_STOP (""), + CRAFT_OPTIONS (""), + CRAFT_START (""), + CRAFT_HOPPER_INPUT (""), + CRAFT_HOPPER_OUTPUT (""), + MISSION_TERMINAL_LIST (""), + MISSION_DETAILS (""), + LOOT (""), + LOOT_ALL (""), + GROUP_INVITE (""), + GROUP_JOIN (""), + GROUP_LEAVE (""), + GROUP_KICK (""), + GROUP_DISBAND (""), + GROUP_DECLINE (""), + EXTRACT_OBJECT (""), + PET_CALL (""), + TERMINAL_AUCTION_USE (""), + CREATURE_FOLLOW (""), + CREATURE_STOP_FOLLOW (""), + SPLIT (""), + IMAGEDESIGN (""), + SET_NAME (""), + ITEM_ROTATE (""), + ITEM_ROTATE_LEFT (""), + ITEM_MOVE (""), + ITEM_MOVE_FORWARD (""), + ITEM_MOVE_BACK (""), + ITEM_MOVE_UP (""), + ITEM_MOVE_DOWN (""), + PET_STORE (""), + VEHICLE_GENERATE (""), + VEHICLE_STORE (""), + MISSION_ABORT (""), + MISSION_END_DUTY (""), + SHIP_MANAGE_COMPONENTS (""), + WAYPOINT_AUTOPILOT (""), + PROGRAM_DROID (""), + VEHICLE_OFFER_RIDE (""), + ITEM_PUBLIC_CONTAINER_USE1 (""), + COLLECTIONS (""), + GROUP_MASTER_LOOTER (""), + GROUP_MAKE_LEADER (""), + GROUP_LOOT (""), + ITEM_ROTATE_BACKWARD (""), + ITEM_ROTATE_COUNTERCLOCKWISE (""), + ITEM_ROTATE_RANDOM (""), + ITEM_ROTATE_RANDOM_YAW (""), + ITEM_ROTATE_RANDOM_PITCH (""), + ITEM_ROTATE_RANDOM_ROLL (""), + ITEM_ROTATE_RESET (""), + ITEM_ROTATE_COPY (""), + ITEM_MOVE_COPY_LOCATION (""), + ITEM_MOVE_COPY_HEIGHT (""), + GROUP_TELL (""), + ITEM_WP_SETCOLOR (""), + ITEM_WP_SETCOLOR_BLUE (""), + ITEM_WP_SETCOLOR_GREEN (""), + ITEM_WP_SETCOLOR_ORANGE (""), + ITEM_WP_SETCOLOR_YELLOW (""), + ITEM_WP_SETCOLOR_PURPLE (""), + ITEM_WP_SETCOLOR_WHITE (""), + ITEM_MOVE_LEFT (""), + ITEM_MOVE_RIGHT (""), + ROTATE_APPLY (""), + ROTATE_RESET (""), + WINDOW_LOCK (""), + WINDOW_UNLOCK (""), + GROUP_CREATE_PICKUP_POINT (""), + GROUP_USE_PICKUP_POINT (""), + GROUP_USE_PICKUP_POINT_NOCAMP (""), + VOICE_SHORTLIST_REMOVE (""), + VOICE_INVITE (""), + VOICE_KICK (""), + ITEM_EQUIP_APPEARANCE (""), + ITEM_UNEQUIP_APPEARANCE (""), + OPEN_STORYTELLER_RECIPE (""), + SERVER_DIVIDER (""), + SERVER_MENU1 (""), + SERVER_MENU2 (""), + SERVER_MENU3 (""), + SERVER_MENU4 (""), + SERVER_MENU5 (""), + SERVER_MENU6 (""), + SERVER_MENU7 (""), + SERVER_MENU8 (""), + SERVER_MENU9 (""), + SERVER_MENU10 (""), + SERVER_MENU11 (""), + SERVER_MENU12 (""), + SERVER_MENU13 (""), + SERVER_MENU14 (""), + SERVER_MENU15 (""), + SERVER_MENU16 (""), + SERVER_MENU17 (""), + SERVER_MENU18 (""), + SERVER_MENU19 (""), + SERVER_MENU20 (""), + SERVER_MENU21 (""), + SERVER_MENU22 (""), + SERVER_MENU23 (""), + SERVER_MENU24 (""), + SERVER_MENU25 (""), + SERVER_MENU26 (""), + SERVER_MENU27 (""), + SERVER_MENU28 (""), + SERVER_MENU29 (""), + SERVER_MENU30 (""), + SERVER_MENU31 (""), + SERVER_MENU32 (""), + SERVER_MENU33 (""), + SERVER_MENU34 (""), + SERVER_MENU35 (""), + SERVER_MENU36 (""), + SERVER_MENU37 (""), + SERVER_MENU38 (""), + SERVER_MENU39 (""), + SERVER_MENU40 (""), + SERVER_MENU41 (""), + SERVER_MENU42 (""), + SERVER_MENU43 (""), + SERVER_MENU44 (""), + SERVER_MENU45 (""), + SERVER_MENU46 (""), + SERVER_MENU47 (""), + SERVER_MENU48 (""), + SERVER_MENU49 (""), + SERVER_MENU50 (""), + SERVER_HARVESTER_MANAGE (""), + SERVER_HOUSE_MANAGE (""), + SERVER_FACTION_HALL_MANAGE (""), + SERVER_HUE (""), + SERVER_OBSERVE (""), + SERVER_STOP_OBSERVING (""), + SERVER_TRAVEL_OPTIONS (""), + SERVER_BAZAAR_OPTIONS (""), + SERVER_SHIPPING_OPTIONS (""), + SERVER_HEAL_WOUND (""), + SERVER_HEAL_WOUND_HEALTH (""), + SERVER_HEAL_WOUND_ACTION (""), + SERVER_HEAL_WOUND_STRENGTH (""), + SERVER_HEAL_WOUND_CONSTITUTION (""), + SERVER_HEAL_WOUND_QUICKNESS (""), + SERVER_HEAL_WOUND_STAMINA (""), + SERVER_HEAL_DAMAGE (""), + SERVER_HEAL_STATE (""), + SERVER_HEAL_STATE_STUNNED (""), + SERVER_HEAL_STATE_BLINDED (""), + SERVER_HEAL_STATE_DIZZY (""), + SERVER_HEAL_STATE_INTIMIDATED (""), + SERVER_HEAL_ENHANCE (""), + SERVER_HEAL_ENHANCE_HEALTH (""), + SERVER_HEAL_ENHANCE_ACTION (""), + SERVER_HEAL_ENHANCE_STRENGTH (""), + SERVER_HEAL_ENHANCE_CONSTITUTION (""), + SERVER_HEAL_ENHANCE_QUICKNESS (""), + SERVER_HEAL_ENHANCE_STAMINA (""), + SERVER_HEAL_FIRSTAID (""), + SERVER_HEAL_CURE_POISON (""), + SERVER_HEAL_CURE_DISEASE (""), + SERVER_HEAL_APPLY_POISON (""), + SERVER_HEAL_APPLY_DISEASE (""), + SERVER_HARVEST_CORPSE (""), + SERVER_PERFORMANCE_LISTEN (""), + SERVER_PERFORMANCE_WATCH (""), + SERVER_PERFORMANCE_LISTEN_STOP (""), + SERVER_PERFORMANCE_WATCH_STOP (""), + SERVER_TERMINAL_PERMISSIONS (""), + SERVER_TERMINAL_MANAGEMENT (""), + SERVER_TERMINAL_PERMISSIONS_ENTER (""), + SERVER_TERMINAL_PERMISSIONS_BANNED (""), + SERVER_TERMINAL_PERMISSIONS_ADMIN (""), + SERVER_TERMINAL_PERMISSIONS_VENDOR (""), + SERVER_TERMINAL_PERMISSIONS_HOPPER (""), + SERVER_TERMINAL_MANAGEMENT_STATUS (""), + SERVER_TERMINAL_MANAGEMENT_PRIVACY (""), + SERVER_TERMINAL_MANAGEMENT_TRANSFER (""), + SERVER_TERMINAL_MANAGEMENT_RESIDENCE (""), + SERVER_TERMINAL_MANAGEMENT_DESTROY (""), + SERVER_TERMINAL_MANAGEMENT_PAY (""), + SERVER_TERMINAL_CREATE_VENDOR (""), + SERVER_GIVE_VENDOR_MAINTENANCE (""), + SERVER_ITEM_OPTIONS (""), + SERVER_SURVEY_TOOL_RANGE (""), + SERVER_SURVEY_TOOL_RESOLUTION (""), + SERVER_SURVEY_TOOL_CLASS (""), + SERVER_PROBE_DROID_TRACK_TARGET (""), + SERVER_PROBE_DROID_FIND_TARGET (""), + SERVER_PROBE_DROID_ACTIVATE (""), + SERVER_PROBE_DROID_BUY (""), + SERVER_TEACH (""), + PET_COMMAND (""), + PET_FOLLOW (""), + PET_STAY (""), + PET_GUARD (""), + PET_FRIEND (""), + PET_ATTACK (""), + PET_PATROL (""), + PET_GET_PATROL_POINT (""), + PET_CLEAR_PATROL_POINTS (""), + PET_ASSUME_FORMATION_1 (""), + PET_ASSUME_FORMATION_2 (""), + PET_TRANSFER (""), + PET_RELEASE (""), + PET_TRICK_1 (""), + PET_TRICK_2 (""), + PET_TRICK_3 (""), + PET_TRICK_4 (""), + PET_GROUP (""), + PET_TAME (""), + PET_FEED (""), + PET_SPECIAL_ATTACK_ONE (""), + PET_SPECIAL_ATTACK_TWO (""), + PET_RANGED_ATTACK (""), + DICE_ROLL (""), + DICE_TWO_FACE (""), + DICE_THREE_FACE (""), + DICE_FOUR_FACE (""), + DICE_FIVE_FACE (""), + DICE_SIX_FACE (""), + DICE_SEVEN_FACE (""), + DICE_EIGHT_FACE (""), + DICE_COUNT_ONE (""), + DICE_COUNT_TWO (""), + DICE_COUNT_THREE (""), + DICE_COUNT_FOUR (""), + CREATE_BALLOT (""), + VOTE (""), + BOMBING_RUN (""), + SELF_DESTRUCT (""), + THIRTY_SEC (""), + FIFTEEN_SEC (""), + SERVER_CAMP_DISBAND (""), + SERVER_CAMP_ASSUME_OWNERSHIP (""), + SERVER_PROBE_DROID_PROGRAM (""), + SERVER_GUILD_CREATE ("@guild:menu_create"), + SERVER_GUILD_INFO (""), + SERVER_GUILD_MEMBERS (""), + SERVER_GUILD_SPONSORED (""), + SERVER_GUILD_ENEMIES (""), + SERVER_GUILD_SPONSOR (""), + SERVER_GUILD_DISBAND (""), + SERVER_GUILD_NAMECHANGE (""), + SERVER_GUILD_GUILD_MANAGEMENT (""), + SERVER_GUILD_MEMBER_MANAGEMENT (""), + SERVER_MANF_HOPPER_INPUT (""), + SERVER_MANF_HOPPER_OUTPUT (""), + SERVER_MANF_STATION_SCHEMATIC (""), + ELEVATOR_UP (""), + ELEVATOR_DOWN (""), + SERVER_PET_OPEN (""), + SERVER_PET_DPAD (""), + SERVER_MED_TOOL_DIAGNOSE (""), + SERVER_MED_TOOL_TENDWOUND (""), + SERVER_MED_TOOL_TENDDAMAGE (""), + SERVER_PET_DISMOUNT (""), + SERVER_PET_TRAIN_MOUNT (""), + SERVER_VEHICLE_ENTER (""), + SERVER_VEHICLE_EXIT (""), + OPEN_NAVICOMP_DPAD (""), + INIT_NAVICOMP_DPAD (""), + CITY_STATUS (""), + CITY_CITIZENS (""), + CITY_STRUCTURES (""), + CITY_TREASURY (""), + CITY_MANAGEMENT (""), + CITY_NAME (""), + CITY_MILITIA (""), + CITY_TAXES (""), + CITY_TREASURY_DEPOSIT (""), + CITY_TREASURY_WITHDRAW (""), + CITY_REGISTER (""), + CITY_RANK (""), + CITY_ADMIN_1 (""), + CITY_ADMIN_2 (""), + CITY_ADMIN_3 (""), + CITY_ADMIN_4 (""), + CITY_ADMIN_5 (""), + CITY_ADMIN_6 (""), + MEMORY_CHIP_PROGRAM (""), + MEMORY_CHIP_TRANSFER (""), + MEMORY_CHIP_ANALYZE (""), + EQUIP_DROID_ON_SHIP (""), + BIO_LINK (""), + LANDMINE_DISARM (""), + LANDMINE_REVERSE_TRIGGER (""), + REWARD_TRADE_IN (""), + BANK_TRANSFER ("@sui:bank_credits"), + BANK_ITEMS ("@sui:bank_items"), + BANK_WITHDRAW_ALL ("@sui:bank_withdrawall"), + BANK_DEPOSIT_ALL ("@sui:bank_depositall"), + BANK_RESERVE ("@sui:bank_galactic_reserve"), + BANK_RESERVE_WITHDRAW ("@sui:bank_galactic_reserve_withdraw"), + BANK_RESERVE_DEPOSIT ("@sui:bank_galactic_reserve_deposit"); private static final Map INT_TO_ITEM = new Hashtable<>(values().length); private int id; diff --git a/src/resources/spawn/SpawnerType.java b/src/resources/spawn/SpawnerType.java index 4c2d08627..17b15f587 100644 --- a/src/resources/spawn/SpawnerType.java +++ b/src/resources/spawn/SpawnerType.java @@ -55,7 +55,9 @@ public enum SpawnerType { OUT_SCIENTIST("object/tangible/spawning/event/shared_outbreak_dungeon_scientist_spawner.iff"), OUT_GAMMA("object/tangible/spawning/event/shared_outbreak_gamma_survivor_spawner.iff"), OUT_HIDDEN("object/tangible/spawning/event/shared_outbreak_hidden_content_spawner.iff"), - WOD_HERB("object/tangible/spawning/event/shared_wod_themepark_herb_spawner.iff"); + WOD_HERB("object/tangible/spawning/event/shared_wod_themepark_herb_spawner.iff"), + UNCHECKED("object/tangible/npe/shared_npe_gamma_shuttle.iff"), + CHECKED("object/tangible/storyteller/prop/shared_pr_droid_lottery.iff"); private String objectTemplate; @@ -67,4 +69,4 @@ public enum SpawnerType { return objectTemplate; } -} +} \ No newline at end of file diff --git a/src/services/faction/FactionService.java b/src/services/faction/FactionService.java new file mode 100644 index 000000000..bbc3502f4 --- /dev/null +++ b/src/services/faction/FactionService.java @@ -0,0 +1,208 @@ +package services.faction; + +import java.util.EnumSet; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import network.packets.swg.zone.UpdatePvpStatusMessage; +import network.packets.swg.zone.chat.ChatSystemMessage; +import network.packets.swg.zone.chat.ChatSystemMessage.SystemChatType; +import intents.FactionIntent; +import resources.PvpFaction; +import resources.PvpFlag; +import resources.PvpStatus; +import resources.control.Intent; +import resources.control.Service; +import resources.objects.SWGObject; +import resources.objects.creature.CreatureObject; +import resources.objects.tangible.TangibleObject; + +public final class FactionService extends Service { + + private ScheduledExecutorService executor; + + public FactionService() { + + } + + @Override + public boolean initialize() { + registerForIntent(FactionIntent.TYPE); + executor = Executors.newSingleThreadScheduledExecutor(); + return super.initialize(); + } + + @Override + public void onIntentReceived(Intent i) { + if(i instanceof FactionIntent) { + FactionIntent fi = (FactionIntent) i; + + switch(fi.getUpdateType()) { + case FACTIONUPDATE: + handleTypeChange(fi); + break; + case STATUSUPDATE: + handleStatusChange(fi); + break; + case FLAGUPDATE: + handleFlagChange(fi.getTarget()); + break; + } + } + } + + @Override + public boolean terminate() { + executor.shutdownNow(); + boolean success = false; + try { + success = executor.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + return super.terminate() && success; + } + + private void sendSystemMessage(TangibleObject target, String message) { + target.getOwner().sendPacket(new ChatSystemMessage(SystemChatType.SCREEN_AND_CHAT, message)); + } + + private String getBeginMessage(PvpStatus currentStatus, PvpStatus targetStatus) { + String message = "@faction_recruiter:"; + + if(currentStatus == PvpStatus.ONLEAVE && targetStatus == PvpStatus.COMBATANT) + message += "on_leave_to_covert"; + else if(currentStatus == PvpStatus.COMBATANT && targetStatus == PvpStatus.SPECIALFORCES) + message += "covert_to_overt"; + else if(currentStatus == PvpStatus.SPECIALFORCES && targetStatus == PvpStatus.COMBATANT) + message += "overt_to_covert"; + + return message; + } + + private String getCompletionMessage(PvpStatus currentStatus, PvpStatus targetStatus) { + String message = "@faction_recruiter:"; + + if((currentStatus == PvpStatus.ONLEAVE || currentStatus == PvpStatus.SPECIALFORCES) && targetStatus == PvpStatus.COMBATANT) + message += "covert_complete"; + else if(currentStatus == PvpStatus.COMBATANT && targetStatus == PvpStatus.SPECIALFORCES) + message += "overt_complete"; + else if(currentStatus == PvpStatus.COMBATANT && targetStatus == PvpStatus.ONLEAVE ) + message += "on_leave_complete"; + + return message; + } + + private long getDelay(PvpStatus currentStatus, PvpStatus targetStatus) { + long delay = 0; + + if(currentStatus == PvpStatus.ONLEAVE && targetStatus == PvpStatus.COMBATANT) + delay = 1; + else if(currentStatus == PvpStatus.COMBATANT && targetStatus == PvpStatus.SPECIALFORCES) + delay = 30; + else if(currentStatus == PvpStatus.SPECIALFORCES && targetStatus == PvpStatus.COMBATANT) + delay = 300; + + return delay; + } + + private void handleTypeChange(FactionIntent fi) { + TangibleObject target = fi.getTarget(); + PvpFaction newFaction = fi.getNewFaction(); + + target.setPvpFaction(newFaction); + target.setPvpStatus(PvpStatus.COMBATANT); + + handleFlagChange(target); // We don't want to remain attackable if we leave our current faction. + + if(target instanceof CreatureObject) { + int rank; + + if(newFaction != PvpFaction.NEUTRAL) + rank = 1; // We're given rank 1 upon joining a PvP faction + else + rank = 0; // Neutrals have no ranks + + ((CreatureObject) target).setFactionRank((byte) rank); + } + } + + private void handleStatusChange(FactionIntent fi) { + final PvpFlag pvpFlag; + final TangibleObject target = fi.getTarget(); + final PvpStatus currentStatus = target.getPvpStatus(); + final PvpStatus targetStatus; + + if(target.hasPvpFlag(PvpFlag.GOING_COVERT) || target.hasPvpFlag(PvpFlag.GOING_OVERT)) { + sendSystemMessage(target, "@faction_recruiter:pvp_status_changing"); + } else { + if(currentStatus == PvpStatus.COMBATANT) { + pvpFlag = PvpFlag.GOING_OVERT; + targetStatus = PvpStatus.SPECIALFORCES; + } else { // Covers both ONLEAVE and SPECIALFORCES + pvpFlag = PvpFlag.GOING_COVERT; + targetStatus = PvpStatus.COMBATANT; + } + + target.setPvpFlags(pvpFlag); + sendSystemMessage(target, getBeginMessage(currentStatus, targetStatus)); + executor.schedule(new Runnable() { + @Override + public void run() { + target.setPvpStatus(targetStatus); + target.getOwner().sendPacket(new ChatSystemMessage( + SystemChatType.SCREEN_AND_CHAT, + getCompletionMessage(currentStatus, targetStatus))); + target.clearPvpFlags(pvpFlag); + } + }, getDelay(currentStatus, targetStatus), TimeUnit.SECONDS); + } + } + + private void handleFlagChange(TangibleObject object) { + + for(SWGObject observer : object.getObservers()) { + if(observer instanceof TangibleObject) { + UpdatePvpStatusMessage objectPacket, targetPacket; + TangibleObject tano = (TangibleObject) observer; + int objectBitmask = object.getPvpFlags(); + int targetBitmask = 0; + int pvpBitmask = 0; + boolean enemies = false; + + // They CAN be enemies if they're not from the same faction and neither of them are neutral + if(object.getPvpFaction() != tano.getPvpFaction() && tano.getPvpFaction() != PvpFaction.NEUTRAL) { + System.out.println(object.getName() + " and " + tano.getName() + " CAN be enemies."); + if(object.getPvpStatus() == PvpStatus.SPECIALFORCES && tano.getPvpStatus() == PvpStatus.SPECIALFORCES) { + pvpBitmask |= PvpFlag.AGGRESSIVE.getBitmask() | PvpFlag.ATTACKABLE.getBitmask(); + enemies = true; + } + } + + objectBitmask |= pvpBitmask; + EnumSet objectFlags = PvpFlag.getFlags(objectBitmask); + PvpFlag objectTempFlag = objectFlags.iterator().next(); + if (objectTempFlag != null) { + objectPacket = new UpdatePvpStatusMessage(objectTempFlag, object.getPvpFaction().getCrc(), object.getObjectId()); + } else { + objectPacket = new UpdatePvpStatusMessage(PvpFlag.PLAYER, object.getPvpFaction().getCrc(), object.getObjectId()); + } + targetBitmask = tano.getPvpFlags(); + targetBitmask |= pvpBitmask; + EnumSet targetFlags = PvpFlag.getFlags(targetBitmask); + PvpFlag targetTempFlag = targetFlags.iterator().next(); + if (targetTempFlag != null) { + targetPacket = new UpdatePvpStatusMessage(targetTempFlag, tano.getPvpFaction().getCrc(), tano.getObjectId()); + } else { + targetPacket = new UpdatePvpStatusMessage(PvpFlag.PLAYER, object.getPvpFaction().getCrc(), object.getObjectId()); + } + if(!enemies || enemies && !object.hasPvpFlag(PvpFlag.GOING_OVERT) || enemies && object.hasPvpFlag(PvpFlag.GOING_COVERT) ) + tano.sendSelf(objectPacket); + + object.sendSelf(objectPacket, targetPacket); + } + } + } + +} \ No newline at end of file diff --git a/src/services/galaxy/ConnectionService.java b/src/services/galaxy/ConnectionService.java index 2e660532b..d13c47336 100644 --- a/src/services/galaxy/ConnectionService.java +++ b/src/services/galaxy/ConnectionService.java @@ -32,6 +32,18 @@ import intents.network.CloseConnectionIntent; import intents.network.ForceDisconnectIntent; import intents.network.GalacticPacketIntent; import intents.player.ZonePlayerSwapIntent; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import main.ProjectSWG; import network.packets.soe.Disconnect; import network.packets.soe.Disconnect.DisconnectReason; import network.packets.swg.zone.HeartBeat; @@ -44,20 +56,15 @@ import resources.player.PlayerEvent; import resources.player.PlayerFlags; import resources.player.PlayerState; import resources.server_info.Log; +import resources.server_info.RelationalDatabase; import utilities.ThreadUtilities; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - public class ConnectionService extends Service { private static final double LD_THRESHOLD = TimeUnit.MINUTES.toMillis(3); // Time since last packet private static final double DISAPPEAR_THRESHOLD = TimeUnit.MINUTES.toMillis(2); // Time after the LD + private static final String incrementPopulation = "UPDATE galaxies SET population = population + 1 WHERE id = ?"; + private static final String decrementPopulation = "UPDATE galaxies SET population = population - 1 WHERE id = ?"; private final ScheduledExecutorService updateService; private final Runnable updateRunnable; @@ -140,9 +147,17 @@ public class ConnectionService extends Service { } private void onPlayerEventIntent(PlayerEventIntent pei) { + RelationalDatabase db = this.getLocalDatabase(); switch (pei.getEvent()) { case PE_FIRST_ZONE: { - Player p = pei.getPlayer(); + Player p = pei.getPlayer(); + try(PreparedStatement updateStatement = db.prepareStatement(ConnectionService.incrementPopulation)) { + updateStatement.setInt(1, ProjectSWG.getGalaxyId()); + updateStatement.executeUpdate(); + } catch (SQLException e) { + Log.e("ConnectionService", "SQLException occured when trying to increase population value."); + e.printStackTrace(); + } synchronized (zonedInPlayers) { zonedInPlayers.add(p); } @@ -152,6 +167,13 @@ public class ConnectionService extends Service { clearPlayerFlag(pei.getPlayer(), pei.getEvent(), PlayerFlags.LD); break; case PE_LOGGED_OUT: + try (PreparedStatement updateStatement = db.prepareStatement(ConnectionService.decrementPopulation)) { + updateStatement.setInt(1, ProjectSWG.getGalaxyId()); + updateStatement.executeUpdate(); + } catch (SQLException e) { + Log.e("ConnectionService", "SQLException occured when trying to decrease population value."); + e.printStackTrace(); + } setPlayerFlag(pei.getPlayer(), pei.getEvent(), PlayerFlags.LD); break; default: diff --git a/src/services/galaxy/GalacticManager.java b/src/services/galaxy/GalacticManager.java index 0ad5d8adc..8adaba00e 100644 --- a/src/services/galaxy/GalacticManager.java +++ b/src/services/galaxy/GalacticManager.java @@ -27,12 +27,18 @@ ***********************************************************************************/ package services.galaxy; +import java.sql.PreparedStatement; +import java.sql.SQLException; + import intents.GalacticIntent; import intents.network.GalacticPacketIntent; import intents.network.InboundPacketIntent; import resources.Galaxy; import resources.control.Intent; import resources.control.Manager; +import resources.server_info.DataManager; +import resources.server_info.Log; +import resources.server_info.RelationalDatabase; import services.chat.ChatManager; import services.objects.ObjectManager; import services.player.PlayerManager; @@ -40,6 +46,7 @@ import services.player.PlayerManager; public class GalacticManager extends Manager { private final Object prevPacketIntentMutex = new Object(); + private final static String resetPopulationSQL = "UPDATE galaxies SET population = 0 WHERE id = ?"; private ObjectManager objectManager; private PlayerManager playerManager; @@ -68,6 +75,7 @@ public class GalacticManager extends Manager { @Override public boolean initialize() { registerForIntent(InboundPacketIntent.TYPE); + resetPopulationCount(); return super.initialize(); } @@ -115,5 +123,15 @@ public class GalacticManager extends Manager { i.setGalacticManager(this); i.setGalaxy(galaxy); } + private void resetPopulationCount() { + RelationalDatabase db = DataManager.getInstance().getLocalDatabase(); + try(PreparedStatement resetPopulation = db.prepareStatement(GalacticManager.resetPopulationSQL)) { + resetPopulation.setInt(1, galaxy.getId()); + resetPopulation.executeUpdate(); + } catch (SQLException e) { + Log.e("ProjectSWG", "SQLException occured when trying to reset population value."); + e.printStackTrace(); + } + } } diff --git a/src/services/galaxy/GameManager.java b/src/services/galaxy/GameManager.java index d208f42a7..a0b7747da 100644 --- a/src/services/galaxy/GameManager.java +++ b/src/services/galaxy/GameManager.java @@ -29,6 +29,7 @@ package services.galaxy; import resources.control.Manager; import services.commands.CommandService; +import services.faction.FactionService; import services.galaxy.terminals.TerminalService; import services.sui.SuiService; @@ -39,6 +40,7 @@ public class GameManager extends Manager { private final SuiService suiService; private final WeatherService weatherService; private final TerminalService terminalManager; + private final FactionService factionService; public GameManager() { commandService = new CommandService(); @@ -46,11 +48,13 @@ public class GameManager extends Manager { suiService = new SuiService(); weatherService = new WeatherService(); terminalManager = new TerminalService(); + factionService = new FactionService(); addChildService(commandService); addChildService(connectionService); addChildService(suiService); addChildService(weatherService); addChildService(terminalManager); + addChildService(factionService); } } diff --git a/src/services/player/CharacterCreationService.java b/src/services/player/CharacterCreationService.java index ca16c244f..96967c608 100644 --- a/src/services/player/CharacterCreationService.java +++ b/src/services/player/CharacterCreationService.java @@ -51,6 +51,7 @@ import network.packets.swg.login.creation.RandomNameResponse; import network.packets.swg.login.creation.ClientVerifyAndLockNameResponse.ErrorMessage; import network.packets.swg.login.creation.CreateCharacterFailure.NameFailureReason; import resources.Location; +import resources.PvpFlag; import resources.Race; import resources.Terrain; import resources.client_info.ClientFactory; @@ -326,7 +327,7 @@ public class CharacterCreationService extends Service { creatureObj.setAppearanceData(create.getCharCustomization()); creatureObj.setHeight(create.getHeight()); creatureObj.setName(create.getName()); - creatureObj.setPvpType(20); + creatureObj.setPvpFlags(PvpFlag.PLAYER, PvpFlag.OVERT); creatureObj.getSkills().add("species_" + creatureObj.getRace().getSpecies()); creatureObj.addObject(inventory); // slot = inventory