/******************************************************************************* * Copyright 2014 Tobias Welther * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package de.tobiyas.racesandclasses.entitystatusmanager.stun; import static de.tobiyas.racesandclasses.translation.languages.Keys.stun_ended; import static de.tobiyas.racesandclasses.translation.languages.Keys.stun_message; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; import de.tobiyas.racesandclasses.RacesAndClasses; import de.tobiyas.racesandclasses.APIs.LanguageAPI; import de.tobiyas.racesandclasses.configuration.statusimun.StatusEffect; import de.tobiyas.racesandclasses.eventprocessing.events.stun.PlayerStunnedEvent; import de.tobiyas.racesandclasses.util.friend.EnemyChecker; import de.tobiyas.util.schedule.DebugBukkitRunnable; import de.tobiyas.util.vollotile.VollotileCodeManager; public class StunManager { private final int TICK_TIME = 1; /** * The Map containing all Stuns. */ private Map<Entity, StunOptions> stunTimes = new ConcurrentHashMap<Entity, StunOptions>(); /** * The Map of StunImmun */ private Map<Entity, StunReduceContainer> stunReduces = new ConcurrentHashMap<Entity, StunReduceContainer>(); /** * The Bukkit taskID for the StunDecreaser. */ private BukkitTask bukkitTask = null; /** * The Plugin to call stuff on. */ private final RacesAndClasses plugin; /** * Creates the Stun Manager with all stuff. */ public StunManager() { plugin = RacesAndClasses.getPlugin(); } /** * Inits the StunManager and starts the Decreasing task. */ public void init(){ if(bukkitTask == null){ bukkitTask = new DebugBukkitRunnable("StunManagerTick"){ @Override protected void runIntern() { Iterator<Map.Entry<Entity, StunOptions>> stunIt = stunTimes.entrySet().iterator(); while (stunIt.hasNext()){ Map.Entry<Entity, StunOptions> entry = stunIt.next(); StunOptions options = entry.getValue(); Entity entity = entry.getKey(); int newValue = options.timeRemaining - 1; if(newValue < 0 || entity.isDead()){ stunIt.remove(); notifyStunOver(entity); if(entity instanceof Player){ sendStunEndMessage((Player) entity); } }else{ options.timeRemaining = newValue; double distanceStun = options.stunLocation.distance(entity.getLocation()); if(distanceStun > 0.2){ entity.teleport(options.stunLocation); } if(entity instanceof LivingEntity){ if(newValue % 10 == 0){ //every 1/2 second. playStunEffect(entity); } } } } } }.runTaskTimer(plugin, 20, TICK_TIME); new DebugBukkitRunnable("StunManagerRemoveOld"){ @Override protected void runIntern() { Iterator<Map.Entry<Entity, StunReduceContainer>> stunReduceIt = stunReduces.entrySet().iterator(); while(stunReduceIt.hasNext()){ Map.Entry<Entity,StunReduceContainer> entry = stunReduceIt.next(); if(!entry.getKey().isValid()){ entry.getValue().stop(); stunReduceIt.remove(); } } } }.runTaskTimer(RacesAndClasses.getPlugin(), 20, 20); } } /** * Sends the player a stun ended message * * @param entity */ protected void sendStunEndMessage(Player entity) { LanguageAPI.sendTranslatedMessage((Player)entity, stun_ended); } /** * Plays a StunEffect on the Location of the Player. * * @param eyeLocation to play effect. */ protected void playStunEffect(Entity stunnedEntity) { List<Entity> near = stunnedEntity.getNearbyEntities(50, 50, 50); for(Entity entity : near){ if(entity instanceof Player){ VollotileCodeManager.getVollotileCode().playCriticalHitEffect((Player)entity, stunnedEntity); } } } /** * Deinits the StunManager. */ public void deinit(){ if(bukkitTask != null){ bukkitTask.cancel(); } } /** * Returns the Rest stun time of the Entity. * * @param entity to get from * * @return time left in ticks or -1 if NOT stunned. */ public int getRestStunTime(Entity entity){ if(entity == null){ return -1; } if(!isStunned(entity)){ return -1; } int time = stunTimes.get(entity).timeRemaining; return time; } /** * Stuns an Entity for x ticks. * * @param entity to stun * @param time to stun * * @return if it worked. */ public boolean stunEntity(Entity stunner, Entity entity, int time){ if(entity == null || time <= 0) return false; //Check if imun: if(isImun(entity)) return false; StunReduceContainer container = stunReduces.get(entity); if(container == null) { container = new StunReduceContainer(entity); stunReduces.put(entity, container); } time = container.getReducedTicks(time); int restTime = getRestStunTime(entity); if(restTime > time){ return false; }else{ //Check for canceled Damage. This indicates Imun. if(stunner != null){ if(EnemyChecker.areAllies(stunner, entity)) return false; } if(entity instanceof Player){ PlayerStunnedEvent event = new PlayerStunnedEvent((Player)entity, time); plugin.fireEventToBukkit(event); if(event.isCancelled() || event.getTimeInTicks() <= 0) return false; time = event.getTimeInTicks(); } StunOptions stunOptions = new StunOptions(); stunOptions.stunLocation = entity.getLocation(); stunOptions.timeRemaining = time / TICK_TIME; stunTimes.put(entity, stunOptions); //stun reduce notification. container.notifyStun(); if(entity instanceof Player){ int timeInSeconds = time / 20; LanguageAPI.sendTranslatedMessage((Player)entity, stun_message, "time", String.valueOf(timeInSeconds)); } return true; } } /** * If the entity is imun against stun. * @param entity to check. * @return true if imun. */ private boolean isImun(Entity entity){ if(entity == null) return false; String name = entity.getCustomName(); return plugin.getConfigManager().getStatusImunManager().isImun(name, StatusEffect.STUN); } /** * Removes all Stun effects from the entity. * * @param entity to unStun. * @return true if worked, false otherwise. */ public boolean removeStun(Entity entity){ if(entity == null){ return false; } if(!isStunned(entity)){ return false; } stunTimes.remove(entity); notifyStunOver(entity); return true; } /** * Returns if the Entity is stunned. * * @param entity to check * * @return true if stunned, false otherwise. */ public boolean isStunned(Entity entity){ return stunTimes.containsKey(entity); } private void notifyStunOver(Entity entity){ //stun reduce notification. StunReduceContainer container = stunReduces.get(entity); if(container == null) { container = new StunReduceContainer(entity); stunReduces.put(entity, container); } container.notifyStunStop(); } private class StunOptions{ private Location stunLocation; private int timeRemaining; } }