From afa4a0467e90e495de50999a5268df5603f35dfc Mon Sep 17 00:00:00 2001 From: Jules Date: Wed, 22 Feb 2023 23:56:51 +0100 Subject: [PATCH] Final commit for combat mode --- .../mmocore/command/PvpModeCommand.java | 6 +- .../region/pvpmode/MMOCoreFlagHandler.java | 63 ++++++++ .../comp/region/pvpmode/PvPFlagHandler.java | 59 +++++++ .../comp/region/pvpmode/PvPModeHandler.java | 70 +++------ .../comp/region/pvpmode/PvPModeListener.java | 72 +++++++-- .../mmocore/manager/ConfigManager.java | 10 +- .../Indyuce/mmocore/player/CombatHandler.java | 21 ++- MMOCore-Dist/src/main/resources/config.yml | 9 +- .../src/main/resources/default/messages.yml | 145 +++++++++--------- 9 files changed, 303 insertions(+), 152 deletions(-) create mode 100644 MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/MMOCoreFlagHandler.java create mode 100644 MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPFlagHandler.java diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/PvpModeCommand.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/PvpModeCommand.java index 44cb6c3b..029c6917 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/PvpModeCommand.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/PvpModeCommand.java @@ -44,13 +44,13 @@ public class PvpModeCommand extends RegisteredCommand { // Toggling on when in PVP region if (playerData.getCombat().isInPvpMode() && MythicLib.plugin.getFlags().isFlagAllowed(playerData.getPlayer(), CustomFlag.PVP_MODE)) { - playerData.getCombat().preventPvp(); + playerData.getCombat().setInvulnerable(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeCommand); MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.toggle.on-invulnerable", "time", - MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerability)).send(playerData.getPlayer()); + MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeCommand)).send(playerData.getPlayer()); // Just send message otherwise } else - MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.toggle." + (playerData.getCombat().isInPvpMode() ? "on" : "off")).send((Player) sender); + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.toggle." + (playerData.getCombat().isInPvpMode() ? "on" : "off") + "-safe").send((Player) sender); return true; } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/MMOCoreFlagHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/MMOCoreFlagHandler.java new file mode 100644 index 00000000..c9659376 --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/MMOCoreFlagHandler.java @@ -0,0 +1,63 @@ +package net.Indyuce.mmocore.comp.region.pvpmode; + +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import com.sk89q.worldguard.session.handler.FlagValueChangeHandler; +import net.Indyuce.mmocore.api.player.PlayerData; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public abstract class MMOCoreFlagHandler extends FlagValueChangeHandler { + + @NotNull + protected PlayerData playerData; + + protected long lastMessage; + + protected static final long MESSAGE_TIMEOUT = 3 * 1000; + + public MMOCoreFlagHandler(Session session, Flag flag) { + super(session, flag); + } + + /** + * Triggered when WorldGuard initializes the value for the first time, + * on player login or world change for instance. + */ + @Override + protected void onInitialValue(LocalPlayer player, ApplicableRegionSet set, StateFlag.State value) { + try { + playerData = PlayerData.get(player.getUniqueId()); + } catch (Exception exception) { + // Citizens. + } + } + + public abstract StateFlag.State getDefaultState(); + + /** + * Triggered when WorldGuard does not find a region setting the value of the flag. + * In that case, put PvP mode to its default setting that is OFF. + */ + @Override + protected boolean onAbsentValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, StateFlag.State lastValue, MoveType moveType) { + return onSetValue(player, from, to, toSet, getDefaultState(), lastValue, moveType); + } + + protected boolean isInvalid() { + return playerData == null; + } + + protected boolean toBoolean(@Nullable StateFlag.State state) { + return state == StateFlag.State.ALLOW; + } + + protected boolean canSendMessage() { + return System.currentTimeMillis() > lastMessage + MESSAGE_TIMEOUT; + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPFlagHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPFlagHandler.java new file mode 100644 index 00000000..fb03ceed --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPFlagHandler.java @@ -0,0 +1,59 @@ +package net.Indyuce.mmocore.comp.region.pvpmode; + +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.flags.StateFlag.State; +import com.sk89q.worldguard.session.MoveType; +import com.sk89q.worldguard.session.Session; +import io.lumine.mythic.lib.MythicLib; +import net.Indyuce.mmocore.MMOCore; + +public class PvPFlagHandler extends MMOCoreFlagHandler { + + public static final Factory FACTORY = new Factory() { + + @Override + public PvPFlagHandler create(Session session) { + return new PvPFlagHandler(session, Flags.PVP); + } + }; + + public PvPFlagHandler(Session session, StateFlag flag) { + super(session, flag); + } + + @Override + public State getDefaultState() { + return State.ALLOW; + } + + /** + * Triggered when a player changes region and finds a new value for that flag. + * In that case, apply the new setting and display messages if needed. + */ + @Override + protected boolean onSetValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, State currentValue, State lastValue, MoveType moveType) { + if (isInvalid()) + return true; + + boolean newPvp = toBoolean(currentValue); + boolean lastPvp = toBoolean(lastValue); + + if (newPvp && !lastPvp) { + + // Apply invulnerability + playerData.getCombat().setInvulnerable(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeRegionChange); + + // Send message + if (canSendMessage()) { + lastMessage = System.currentTimeMillis(); + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.enter.pvp-mode-on", "time", + MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeRegionChange)).send(playerData.getPlayer()); + } + } + return true; + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeHandler.java index f5c36407..05dd6a93 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeHandler.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeHandler.java @@ -3,33 +3,23 @@ package net.Indyuce.mmocore.comp.region.pvpmode; import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.flags.StateFlag.State; import com.sk89q.worldguard.session.MoveType; import com.sk89q.worldguard.session.Session; -import com.sk89q.worldguard.session.handler.FlagValueChangeHandler; import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.comp.flags.CustomFlag; import io.lumine.mythic.lib.comp.flags.WorldGuardFlags; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.command.PvpModeCommand; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; -public class PvPModeHandler extends FlagValueChangeHandler { - - @NotNull - private PlayerData playerData; - - private long lastMessage; - - private static final long MESSAGE_TIMEOUT = 3 * 1000; +public class PvPModeHandler extends MMOCoreFlagHandler { public static final Factory FACTORY = new Factory() { - public final WorldGuardFlags wgFlags = Objects.requireNonNull(MythicLib.plugin.getFlags().getHandler(WorldGuardFlags.class), "Could not reach ML compatibility class for WG"); + final WorldGuardFlags wgFlags = Objects.requireNonNull(MythicLib.plugin.getFlags().getHandler(WorldGuardFlags.class), "Could not reach ML compatibility class for WG"); @Override public PvPModeHandler create(Session session) { @@ -41,41 +31,23 @@ public class PvPModeHandler extends FlagValueChangeHandler { super(session, flag); } - /** - * Triggered when WorldGuard initializes the value for the first time, - * on player login or world change for instance. - */ @Override - protected void onInitialValue(LocalPlayer player, ApplicableRegionSet set, State value) { - try { - playerData = PlayerData.get(player.getUniqueId()); - } catch (Exception exception) { - // Citizens. - } + public State getDefaultState() { + return State.ALLOW; } - /** - * Triggered when WorldGuard does not find a region setting the value of the flag. - * In that case, put PvP mode to its default setting that is OFF. - */ - @Override - protected boolean onAbsentValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, StateFlag.State lastValue, MoveType moveType) { - return onSetValue(player, from, to, toSet, DEFAULT_STATE, lastValue, moveType); - } - - public static final StateFlag.State DEFAULT_STATE = StateFlag.State.DENY; - /** * Triggered when a player changes region and finds a new value for that flag. * In that case, apply the new setting and display messages if needed. */ @Override protected boolean onSetValue(LocalPlayer player, Location from, Location to, ApplicableRegionSet toSet, StateFlag.State currentValue, StateFlag.State lastValue, MoveType moveType) { - boolean newPvpMode = toBoolean(currentValue); - boolean lastPvpMode = toBoolean(lastValue); if (isInvalid()) return true; + boolean newPvpMode = toBoolean(currentValue); + boolean lastPvpMode = toBoolean(lastValue); + if (!newPvpMode && lastPvpMode) { // Apply cooldown @@ -83,10 +55,16 @@ public class PvPModeHandler extends FlagValueChangeHandler { // Send message if (canSendMessage()) { - final String msgPath = (playerData.getCombat().isInPvpMode() && !playerData.getCombat().canQuitPvpMode()) ? "allowed" : "denied"; + + // Leave combat when joining safe zone + final boolean pvpFlag = toSet.queryState(null, Flags.PVP) != StateFlag.State.DENY; + if (playerData.getCombat().isInPvpMode() && !pvpFlag) + playerData.getCombat().close(); + + final boolean pvpEnabled = playerData.getCombat().isInPvpMode() && !playerData.getCombat().canQuitPvpMode() && pvpFlag; lastMessage = System.currentTimeMillis(); final double remaining = (playerData.getCombat().getLastHit() + MMOCore.plugin.configManager.pvpModeCombatTimeout * 1000.0D - System.currentTimeMillis()) / 1000.0D; - MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.leave.pvp-" + msgPath, "remaining", + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.leave.pvp-" + (pvpEnabled ? "allowed" : "denied"), "remaining", (MythicLib.plugin.getMMOConfig()).decimal.format(remaining)).send(playerData.getPlayer()); } } else if (newPvpMode && !lastPvpMode) { @@ -97,27 +75,15 @@ public class PvPModeHandler extends FlagValueChangeHandler { // Apply invulnerability final boolean applyInvulnerability = playerData.getCombat().isInPvpMode() && playerData.getCombat().canQuitPvpMode(); if (applyInvulnerability) - playerData.getCombat().preventPvp(); + playerData.getCombat().setInvulnerable(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeRegionChange); // Send message if (canSendMessage()) { lastMessage = System.currentTimeMillis(); MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.enter.pvp-mode-" + (applyInvulnerability ? "on" : "off"), "time", - MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerability)).send(playerData.getPlayer()); + MythicLib.plugin.getMMOConfig().decimal.format(MMOCore.plugin.configManager.pvpModeInvulnerabilityTimeRegionChange)).send(playerData.getPlayer()); } } return true; } - - private boolean isInvalid() { - return playerData == null; - } - - private boolean toBoolean(@Nullable State state) { - return state == State.ALLOW; - } - - private boolean canSendMessage() { - return System.currentTimeMillis() > lastMessage + MESSAGE_TIMEOUT; - } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeListener.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeListener.java index 497e291f..49dda041 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeListener.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/region/pvpmode/PvPModeListener.java @@ -1,42 +1,80 @@ package net.Indyuce.mmocore.comp.region.pvpmode; import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.bukkit.protection.events.DisallowedPVPEvent; +import com.sk89q.worldguard.session.handler.Handler; import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.comp.flags.CustomFlag; -import io.lumine.mythic.lib.comp.interaction.InteractionType; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; import org.apache.commons.lang.Validate; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; + +import javax.annotation.Nullable; public class PvPModeListener implements Listener { public PvPModeListener() { - Validate.isTrue(WorldGuard.getInstance().getPlatform().getSessionManager().registerHandler(PvPModeHandler.FACTORY, null), "Could not register WG handler for PvP mode"); + Validate.isTrue(registerHandler(PvPModeHandler.FACTORY), "Could not register WG handler for PvP mode"); + if (MMOCore.plugin.getConfig().getBoolean("pvp_mode.invulnerability.apply_to_pvp_flag")) + Validate.isTrue(registerHandler(PvPFlagHandler.FACTORY), "Could not register WG handler for PvP"); } + private boolean registerHandler(Handler.Factory factory) { + return WorldGuard.getInstance().getPlatform().getSessionManager().registerHandler(factory, null); + } + + /** + * Runs after MythicLib interaction checks. This listener + * takes care of PVP inside of PvP-mode regions. + */ @EventHandler(ignoreCancelled = true) - public void unblockPvp(DisallowedPVPEvent event) { - PlayerData defender, attacker; - if (!(attacker = PlayerData.get(event.getAttacker())).getCombat().isInPvpMode() || !(defender = PlayerData.get(event.getDefender())).getCombat().isInPvpMode()) + public void a(EntityDamageByEntityEvent event) { + if (!UtilityMethods.isRealPlayer(event.getEntity())) return; - // If defender is out of combat - if (!defender.getCombat().canPvp()) + final @Nullable Player source = UtilityMethods.getPlayerDamager(event); + if (source == null) return; - // If attacker cannot deal damage yet - if (!MMOCore.plugin.configManager.pvpModeInvulnerabilityCanDamage && !attacker.getCombat().canPvp()) - return; - - // Defender is still fighting and cannot leave PvP mode - if (!defender.getCombat().canQuitPvpMode()) + // Check for target's invulnerability BEFORE pvp-mode flag because it can also + // happen when the option pvp_mode.invulnerability.apply_to_pvp_flag is on + final Player target = (Player) event.getEntity(); + final PlayerData targetData = PlayerData.get(target); + if (targetData.getCombat().isInvulnerable()) { + final long left = targetData.getCombat().getInvulnerableTill() - System.currentTimeMillis(); + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.invulnerable-target", + "left", MythicLib.plugin.getMMOConfig().decimal.format(left / 1000d)).send(source); event.setCancelled(true); + return; + } - // Enable PvP if accepted - else if (MythicLib.plugin.getFlags().isFlagAllowed(event.getDefender().getLocation(), CustomFlag.PVP_MODE) && - MythicLib.plugin.getEntities().checkPvpInteractionRules(event.getAttacker(), event.getDefender(), InteractionType.OFFENSE_ACTION, true)) + // If attacker is still invulnerable and cannot deal damage + final PlayerData sourceData = PlayerData.get(source); + if (!MMOCore.plugin.configManager.pvpModeInvulnerabilityCanDamage && sourceData.getCombat().isInvulnerable()) { + final long left = sourceData.getCombat().getInvulnerableTill() - System.currentTimeMillis(); + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.invulnerable-self", + "left", MythicLib.plugin.getMMOConfig().decimal.format(left / 1000d)).send(source); event.setCancelled(true); + return; + } + + // Checks for PvP mode on target location + if (!MythicLib.plugin.getFlags().isFlagAllowed(target.getLocation(), CustomFlag.PVP_MODE)) + return; + + // Defender has not enabled PvP mode + if (!targetData.getCombat().isInPvpMode()) { + event.setCancelled(true); + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.pvp-mode-disabled-target").send(source); + } + + // Attacker has not enabled PvP mode + else if (!sourceData.getCombat().isInPvpMode()) { + event.setCancelled(true); + MMOCore.plugin.configManager.getSimpleMessage("pvp-mode.cannot-hit.pvp-mode-disabled-self").send(source); + } } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java index 9e8858d4..6ef35a04 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java @@ -27,12 +27,13 @@ import java.util.logging.Level; public class ConfigManager { public final CommandVerbose commandVerbose = new CommandVerbose(); - public boolean overrideVanillaExp, canCreativeCast, passiveSkillNeedBound, cobbleGeneratorXP, saveDefaultClassInfo, attributesAsClassInfo, splitProfessionExp, disableQuestBossBar, pvpModeEnabled, pvpModeInvulnerabilityCanDamage; + public boolean overrideVanillaExp, canCreativeCast, passiveSkillNeedBound, cobbleGeneratorXP, saveDefaultClassInfo, attributesAsClassInfo, splitProfessionExp, disableQuestBossBar, + pvpModeEnabled, pvpModeInvulnerabilityCanDamage; public String partyChatPrefix, noSkillBoundPlaceholder; public ChatColor staminaFull, staminaHalf, staminaEmpty; public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown; - public double lootChestsChanceWeight, dropItemsChanceWeight, fishingDropsChanceWeight, partyMaxExpSplitRange, pvpModeToggleOnCooldown, pvpModeToggleOffCooldown, pvpModeCombatCooldown, pvpModeCombatTimeout, pvpModeInvulnerability, - pvpModeRegionEnterCooldown, pvpModeRegionLeaveCooldown; + public double lootChestsChanceWeight, dropItemsChanceWeight, fishingDropsChanceWeight, partyMaxExpSplitRange, pvpModeToggleOnCooldown, pvpModeToggleOffCooldown, pvpModeCombatCooldown, + pvpModeCombatTimeout, pvpModeInvulnerabilityTimeRegionChange, pvpModeInvulnerabilityTimeCommand, pvpModeRegionEnterCooldown, pvpModeRegionLeaveCooldown; public int maxPartyLevelDifference, maxBoundActiveSkills, maxBoundPassiveSkills; public final List combatLogDamageCauses = new ArrayList<>(); @@ -140,7 +141,8 @@ public class ConfigManager { pvpModeRegionEnterCooldown = config.getDouble("pvp_mode.cooldown.region_enter"); pvpModeRegionLeaveCooldown = config.getDouble("pvp_mode.cooldown.region_leave"); pvpModeCombatTimeout = config.getDouble("pvp_mode.combat_timeout"); - pvpModeInvulnerability = config.getDouble("pvp_mode.invulnerability.time"); + pvpModeInvulnerabilityTimeCommand = config.getDouble("pvp_mode.invulnerability.time.command"); + pvpModeInvulnerabilityTimeRegionChange = config.getDouble("pvp_mode.invulnerability.time.region_change"); pvpModeInvulnerabilityCanDamage = config.getBoolean("pvp_mode.invulnerability.can_damage"); // Resources diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/CombatHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/CombatHandler.java index 2879ff46..bac97f04 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/CombatHandler.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/player/CombatHandler.java @@ -14,7 +14,7 @@ public class CombatHandler implements Closable { private final PlayerData player; private final long firstHit = System.currentTimeMillis(); - private long lastHit = System.currentTimeMillis(), lastToggle; + private long lastHit = System.currentTimeMillis(), invulnerableTill; private boolean pvpMode; @@ -27,7 +27,7 @@ public class CombatHandler implements Closable { public void update() { lastHit = System.currentTimeMillis(); - lastToggle = 0; + invulnerableTill = 0; player.getMMOPlayerData().getCooldownMap().applyCooldown(PvpModeCommand.COOLDOWN_KEY, MMOCore.plugin.configManager.pvpModeCombatCooldown); // Simply refreshing @@ -58,6 +58,10 @@ public class CombatHandler implements Closable { return firstHit; } + public long getInvulnerableTill() { + return invulnerableTill; + } + /** * Simply checks if there is a scheduled task. * @@ -74,12 +78,12 @@ public class CombatHandler implements Closable { * * @return If the player is inert i.e if he CAN hit/take damage */ - public boolean canPvp() { - return System.currentTimeMillis() > lastToggle + MMOCore.plugin.configManager.pvpModeInvulnerability * 1000; + public boolean isInvulnerable() { + return System.currentTimeMillis() < invulnerableTill; } - public void preventPvp() { - lastToggle = System.currentTimeMillis(); + public void setInvulnerable(double time) { + invulnerableTill = System.currentTimeMillis() + (long) (time * 1000); } public boolean canQuitPvpMode() { @@ -108,5 +112,10 @@ public class CombatHandler implements Closable { public void close() { if (isInCombat()) quit(true); + + // Necessary steps when entering a town. + lastHit = 0; + invulnerableTill = 0; + player.getMMOPlayerData().getCooldownMap().resetCooldown(PvpModeCommand.COOLDOWN_KEY); } } diff --git a/MMOCore-Dist/src/main/resources/config.yml b/MMOCore-Dist/src/main/resources/config.yml index 78fbf155..984f3cc2 100644 --- a/MMOCore-Dist/src/main/resources/config.yml +++ b/MMOCore-Dist/src/main/resources/config.yml @@ -303,12 +303,19 @@ pvp_mode: # - entering a PvP region with PvP mode turned on. # - using the /pvpmode command inside of a PvP region. invulnerability: - time: 60 + time: + region_change: 60 + command: 30 # When enabled, players can damage other players # to end this invulnerable time period. can_damage: false + # When enabled, leaving a no-PVP zone and entering a PVP zone + # will apply the SAME invulnerability time. + # Requires /reload when changed + apply_to_pvp_flag: false + cooldown: # Cooldown before being able to use the /pvpmode diff --git a/MMOCore-Dist/src/main/resources/default/messages.yml b/MMOCore-Dist/src/main/resources/default/messages.yml index e6ec39c2..84864417 100644 --- a/MMOCore-Dist/src/main/resources/default/messages.yml +++ b/MMOCore-Dist/src/main/resources/default/messages.yml @@ -1,51 +1,58 @@ # Level & Experience level-up: -- '' -- '&eCongratulations, you reached level &6{level}&e!' -- '&eUse &6/p &eto see your new statistics!' -- '' + - '' + - '&eCongratulations, you reached level &6{level}&e!' + - '&eUse &6/p &eto see your new statistics!' + - '' profession-level-up: -- '&eYou are now level &6{level}&e in &6{profession}&e!' + - '&eYou are now level &6{level}&e in &6{profession}&e!' exp-notification: '%&f{profession} &e{progress} &e{ratio}%' exp-hologram: '&e+{exp} EXP!' class-select: '&eYou are now a &6{class}&e!' already-on-class: '&cYou are already a {class}.' death-exp-loss: -- '' -- '&4You died and lost {loss} experience.' -- '' + - '' + - '&4You died and lost {loss} experience.' + - '' # General not-enough-perms: '&cYou do not have enough permissions.' # Experience boosters booster-main: -- '&e' -- '&eA &6{multiplier}x&e EXP multiplier is now active!' -- '&e' + - '&e' + - '&eA &6{multiplier}x&e EXP multiplier is now active!' + - '&e' booster-skill: -- '&e' -- '&eA &6{multiplier}x&e &6{profession} &eEXP multiplier is now active!' -- '&e' + - '&e' + - '&eA &6{multiplier}x&e &6{profession} &eEXP multiplier is now active!' + - '&e' booster-expired: '&cExpired!' # PvP Mode pvp-mode: - cooldown: '&cPlease wait {remaining} seconds to use this command again.' + cooldown: '&cPlease wait {remaining} seconds to use this command again.' - # When using /pvpmode - toggle: - on: '&aPvP Mode on.' - on-invulnerable: '&aPvP Mode on. You are now invulnerable for {time} seconds.' - off: '&cPvP Mode off.' + # When you cannot hit another player + cannot-hit: + pvp-mode-disabled-target: '&cThis player has not toggled on PvP.' + pvp-mode-disabled-self: '&cYou have not toggled on PvP.' + invulnerable-self: '&cYou are still out of combat for {left} seconds.' + invulnerable-target: '&cThis player is out of combat for {left} seconds.' - # Entering/leaving regions with specific flag value - leave: - pvp-allowed: '&cYou left a PVP zone but are still vulnerable for {remaining} seconds!' - pvp-denied: '&cYou left the PVP zone.' - enter: - pvp-mode-on: '&aYou entered a PVP zone and gained invulnerability for {time} seconds!' - pvp-mode-off: '&aYou entered a PVP zone. You may use /pvpmode to fight other players.' + # When using /pvpmode + toggle: + on-safe: '&aYou will now be able to fight other players in dedicated areas.' + on-invulnerable: '&aYou will be able to fight other players in {time} seconds.' + off-safe: '&cYou can no longer fight other players.' + + # Entering/leaving regions + leave: + pvp-allowed: '&cYou left a PVP zone but are still vulnerable for {remaining} seconds!' + pvp-denied: '&cYou left the PVP zone.' + enter: + pvp-mode-on: '&aYou entered a PVP zone and gained invulnerability for {time} seconds!' + pvp-mode-off: '&aYou entered a PVP zone. You may use /pvpmode to fight other players.' # Fishing Profession caught-fish: '&cYou caught a fish!' @@ -54,32 +61,32 @@ fish-out-water-crit: '&aCritical Fish!' # Player Input player-input: - anvil: - friend-request: 'Friend name..' - party-invite: 'Player name..' - guild-invite: 'Player name..' - guild-creation-tag: 'Guild tag..' - guild-creation-name: 'Guild name..' - chat: - friend-request: '&eWrite in the chat the player name.' - party-invite: '&eWrite in the chat the player you want to invite.' - guild-invite: '&eWrite in the chat the player you want to invite.' - guild-creation-tag: '&eWrite in the chat the TAG of the Guild you want to create.' - guild-creation-name: '&eWrite in the chat the name of the Guild you want to create.' - cancel: '&eWrite &c''cancel'' &eto cancel.' + anvil: + friend-request: 'Friend name..' + party-invite: 'Player name..' + guild-invite: 'Player name..' + guild-creation-tag: 'Guild tag..' + guild-creation-name: 'Guild name..' + chat: + friend-request: '&eWrite in the chat the player name.' + party-invite: '&eWrite in the chat the player you want to invite.' + guild-invite: '&eWrite in the chat the player you want to invite.' + guild-creation-tag: '&eWrite in the chat the TAG of the Guild you want to create.' + guild-creation-name: '&eWrite in the chat the name of the Guild you want to create.' + cancel: '&eWrite &c''cancel'' &eto cancel.' # Spell Casting casting: - action-bar: - ready: '&6[{index}] &a&l{skill}' - on-cooldown: '&6[{index}] &c&l{skill} &6(&c{cooldown}&6)' - no-mana: '&6[{index}] &9&l{skill}' - no-stamina: '&6[{index}] &9&l{skill}' - split: '&7 &7 - &7 ' - no-longer: '%&cYou cancelled skill casting.' - no-mana: '&cYou do not have enough {mana}, {mana-required} more required!' - no-stamina: '&cYou do not have enough stamina!' - on-cooldown: '&cThis skill is on a {cooldown}s cooldown.' + action-bar: + ready: '&6[{index}] &a&l{skill}' + on-cooldown: '&6[{index}] &c&l{skill} &6(&c{cooldown}&6)' + no-mana: '&6[{index}] &9&l{skill}' + no-stamina: '&6[{index}] &9&l{skill}' + split: '&7 &7 - &7 ' + no-longer: '%&cYou cancelled skill casting.' + no-mana: '&cYou do not have enough {mana}, {mana-required} more required!' + no-stamina: '&cYou do not have enough stamina!' + on-cooldown: '&cThis skill is on a {cooldown}s cooldown.' # Combat Log now-in-combat: '%&cYou are now in combat!' @@ -118,20 +125,20 @@ friend-request-cooldown: '&cPlease wait {cooldown}.' cant-request-to-yourself: '&cYou can''t send a request to yourself.' already-friends: '&cYou are already friends with {player}.' friend-request: -- '{"text":""}' -- '{"text":"&6{player} &ejust sent you a friend request!"}' -- '[{"text":" ","hoverEvent":{}},{"text":"&8[&a&lACCEPT&8]","clickEvent":{"action":"run_command","value":"/friends accept {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to accept!"}},{"text":"&r ","hoverEvent":{}},{"text":"&8[&c&lDENY&8]","clickEvent":{"action":"run_command","value":"/friends deny {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to deny."}}]' -- '{"text":""}' + - '{"text":""}' + - '{"text":"&6{player} &ejust sent you a friend request!"}' + - '[{"text":" ","hoverEvent":{}},{"text":"&8[&a&lACCEPT&8]","clickEvent":{"action":"run_command","value":"/friends accept {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to accept!"}},{"text":"&r ","hoverEvent":{}},{"text":"&8[&c&lDENY&8]","clickEvent":{"action":"run_command","value":"/friends deny {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to deny."}}]' + - '{"text":""}' # Parties party-chat: '&5[Party] {player}: {message}' sent-party-invite: '&eYou sent a party invite to &6{player}&e.' already-in-party: '&c{player} is already in your party.' party-invite: -- '{"text":""}' -- '{"text":"&6{player} &ehas invited you to their party!"}' -- '[{"text":" "},{"text":"&8[&a&lACCEPT&8]","clickEvent":{"action":"run_command","value":"/party accept {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to accept!"}},{"text":"&r "},{"text":"&8[&c&lDENY&8]","clickEvent":{"action":"run_command","value":"/party deny {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to deny."}}]' -- '{"text":""}' + - '{"text":""}' + - '{"text":"&6{player} &ehas invited you to their party!"}' + - '[{"text":" "},{"text":"&8[&a&lACCEPT&8]","clickEvent":{"action":"run_command","value":"/party accept {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to accept!"}},{"text":"&r "},{"text":"&8[&c&lDENY&8]","clickEvent":{"action":"run_command","value":"/party deny {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to deny."}}]' + - '{"text":""}' party-is-full: '&cSorry, your party is full.' party-joined: '&eYou successfully joined &6{owner}&e''s party.' party-joined-other: '&6{player}&e joined your party!' @@ -145,10 +152,10 @@ guild-chat: '&a[{tag}] {player}: {message}' sent-guild-invite: '&eYou sent a guild invite to &6{player}&e.' already-in-guild: '&c{player} is already in your guild.' guild-invite: -- '{"text":""}' -- '{"text":"&6{player} &ehas invited you to their guild!"}' -- '[{"text":" "},{"text":"&8[&a&lACCEPT&8]","clickEvent":{"action":"run_command","value":"/guild accept {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to accept!"}},{"text":"&r "},{"text":"&8[&c&lDENY&8]","clickEvent":{"action":"run_command","value":"/guild deny {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to deny."}}]' -- '{"text":""}' + - '{"text":""}' + - '{"text":"&6{player} &ehas invited you to their guild!"}' + - '[{"text":" "},{"text":"&8[&a&lACCEPT&8]","clickEvent":{"action":"run_command","value":"/guild accept {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to accept!"}},{"text":"&r "},{"text":"&8[&c&lDENY&8]","clickEvent":{"action":"run_command","value":"/guild deny {uuid}"},"hoverEvent":{"action":"show_text","value":"&eClick to deny."}}]' + - '{"text":""}' #guild-is-full: '&cSorry, your guild is full.' -Unused right now guild-joined: '&eYou successfully joined &6{owner}&e''s guild.' guild-joined-other: '&6{player}&e joined your guild!' @@ -156,11 +163,11 @@ transfer-guild-ownership: '&eYou were transfered the guild ownership.' kick-from-guild: '&eYou successfully kicked &6{player}&e from the guild.' guild-invite-cooldown: '&cPlease wait {cooldown} before inviting {player}.' guild-creation: - failed: "&cCouldn't create guild: {reason}" - reasons: - invalid-characters: "&eInvalid character(s)!" - invalid-length: "&eThe length must be between {min} and {max}!" - already-exists: "&eThat guild tag already exists!" + failed: "&cCouldn't create guild: {reason}" + reasons: + invalid-characters: "&eInvalid character(s)!" + invalid-length: "&eThe length must be between {min} and {max}!" + already-exists: "&eThat guild tag already exists!" # Quests already-on-quest: '&cYou are already on a quest.' @@ -181,9 +188,9 @@ attribute-level-up: '&eYou successfully leveled up your &6{attribute}&e.' # {lev # Class selection cant-choose-new-class: - - '&cYou need one class point to perform this action.' + - '&cYou need one class point to perform this action.' no-permission-for-class: - - "&cYou don't have the permission to choose this class." + - "&cYou don't have the permission to choose this class." # Skills no-class-skill: '&cYour class has no skill.'