/*******************************************************************************
* Copyright 2014 Tob
*
* 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.traitcontainer.traits.defaultraits.activate.AreaAirDropTrait;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.FallingBlock;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.world.ChunkUnloadEvent;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.BlockIterator;
import de.tobiyas.racesandclasses.RacesAndClasses;
import de.tobiyas.racesandclasses.playermanagement.player.RaCPlayer;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.TraitResults;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.annotations.configuration.TraitConfigurationField;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.annotations.configuration.TraitConfigurationNeeded;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.annotations.configuration.TraitEventsUsed;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.annotations.configuration.TraitInfos;
import de.tobiyas.racesandclasses.traitcontainer.interfaces.markerinterfaces.Trait;
import de.tobiyas.racesandclasses.traitcontainer.traits.magic.AbstractMagicSpellTrait;
import de.tobiyas.racesandclasses.util.damage.PreEntityDamageEvent;
import de.tobiyas.racesandclasses.util.entitysearch.SearchEntity;
import de.tobiyas.racesandclasses.util.friend.EnemyChecker;
import de.tobiyas.racesandclasses.util.traitutil.TraitConfiguration;
import de.tobiyas.racesandclasses.util.traitutil.TraitConfigurationFailedException;
import de.tobiyas.racesandclasses.vollotile.ParticleContainer;
import de.tobiyas.racesandclasses.vollotile.Vollotile;
public class AreaAirDropTrait extends AbstractMagicSpellTrait implements Listener {
/**
* The Damage to do.
*/
protected double damage = 1;
protected DamageCause cause = DamageCause.FIRE;
protected int rainRange = 10;
protected int explosionRange = 2;
protected int amount = 5;
protected int aboveTarget = 15;
protected Material mat = Material.TNT;
protected int matDamageValue = 0;
protected ParticleContainer particles = null;
protected ParticleContainer particlesFromSelf = null;
public AreaAirDropTrait() {
Bukkit.getPluginManager().registerEvents(this, (Plugin)RacesAndClasses.getPlugin());
}
@Override
public String getName() {
return "AreaAirDropTrait";
}
@TraitConfigurationNeeded( fields = {
@TraitConfigurationField(fieldName = "damage", classToExpect = Double.class, optional = false),
@TraitConfigurationField(fieldName = "cause", classToExpect = String.class, optional = true),
@TraitConfigurationField(fieldName = "rainRange", classToExpect = Integer.class, optional = true),
@TraitConfigurationField(fieldName = "explosionRange", classToExpect = Integer.class, optional = true),
@TraitConfigurationField(fieldName = "amount", classToExpect = Integer.class, optional = true),
@TraitConfigurationField(fieldName = "aboveTarget", classToExpect = Integer.class, optional = true),
@TraitConfigurationField(fieldName = "material", classToExpect = Material.class, optional = true),
@TraitConfigurationField(fieldName = "materialDamageValue", classToExpect = Integer.class, optional = true),
@TraitConfigurationField(fieldName = "particle", classToExpect = String.class, optional = true),
@TraitConfigurationField(fieldName = "particleFromSelf", classToExpect = String.class, optional = true),
})
@Override
public void setConfiguration(TraitConfiguration configMap) throws TraitConfigurationFailedException {
super.setConfiguration(configMap);
if(configMap.containsKey("rainRange")){
rainRange = configMap.getAsInt("rainRange");
}
if(configMap.containsKey("explosionRange")){
explosionRange = configMap.getAsInt("explosionRange");
}
if(configMap.containsKey("amount")){
amount = configMap.getAsInt("amount");
}
if(configMap.containsKey("aboveTarget")){
aboveTarget = configMap.getAsInt("aboveTarget");
}
if(configMap.containsKey("material")){
mat = configMap.getAsMaterial("material");
if(!mat.isBlock()) mat = Material.GLOWSTONE;
}
if(configMap.containsKey("materialDamageValue")){
matDamageValue = configMap.getAsInt("materialDamageValue");
}
if(configMap.containsKey("damage")){
damage = configMap.getAsDouble("damage");
}
if(configMap.containsKey("cause")){
String stringCause = configMap.getAsString("cause");
DamageCause realCause = DamageCause.FIRE;
try{ realCause = DamageCause.valueOf(stringCause.toUpperCase()); }catch(Throwable exp){}
cause = realCause;
}
if(configMap.containsKey("particle")){
particles = configMap.getAsParticleContainer("particle");
}
if(configMap.containsKey("particleFromSelf")){
particlesFromSelf = configMap.getAsParticleContainer("particleFromSelf");
}
}
public static List<String> getHelpForTrait(){
List<String> helpList = new LinkedList<String>();
helpList.add(ChatColor.YELLOW + "This Trait Does an AOE and hits everyone in range.");
return helpList;
}
@TraitInfos(category = "activate", traitName = "AreaAirDropTrait", visible = true)
@Override
public void importTrait() {
}
@Override
public boolean isBetterThan(Trait trait) {
return false;
}
@TraitEventsUsed(registerdClasses = {})
@Override
public void generalInit() {
}
@Override
protected String getPrettyConfigIntern() {
return "Does damage on Stuff around.";
}
private final String DELETE_ON_DROP = "DELETE_ON_DROP";
private Location getLookLocation(RaCPlayer player){
BlockIterator blockIt = new BlockIterator(player.getPlayer());
int i = 0;
Location backup = null;
Block current = blockIt.next();
while(blockIt.hasNext()){
current = blockIt.next();
if(current.getType() != Material.AIR) return current.getLocation();
i++;
if(i == 10) backup = current.getLocation();
if(i > 200) return backup;
}
return current.getLocation();
}
@EventHandler
public void chunkUnload(ChunkUnloadEvent event){
for(Entity entity : Arrays.asList(event.getChunk().getEntities())){
if(entity.hasMetadata(DELETE_ON_DROP)) entity.remove();
}
}
@EventHandler
public void fallingBlockTransform(EntityChangeBlockEvent event){
if(event.isCancelled()) return; //already handled!
if(event.getEntity().hasMetadata(DELETE_ON_DROP)) {
RaCPlayer player = (RaCPlayer) event.getEntity().getMetadata(DELETE_ON_DROP).get(0).value();
if(player == null || !player.getTraits().contains(this)) return; //not the player's trait.
//here we are sure this belongs to us!
event.getEntity().remove();
event.setCancelled(true);
if(particles != null) Vollotile.get().sendOwnParticleEffectToAll(particles, event.getBlock().getLocation());
//We got an exploded Block here!
List<Entity> around = SearchEntity.inCircleAround(event.getEntity(), explosionRange);
for(Entity entity : around){
if(!EnemyChecker.areAllies(player.getPlayer(), entity)){
explosionHitOnTarget(player, entity);
}
}
}
}
public void explosionHitOnTarget(RaCPlayer damager, Entity targetEntity){
if(!(targetEntity instanceof LivingEntity)) return;
if(damager.getPlayer() == targetEntity) return; //cant hurt yourself.
double modDamage = modifyToPlayer(damager, this.damage, "damage");
LivingEntity target = (LivingEntity) targetEntity;
double damage = PreEntityDamageEvent.getRealDamage(damager.getPlayer(), target, DamageCause.CONTACT, modDamage);
if(damage <= 0) return;
target.setNoDamageTicks(0);
de.tobiyas.racesandclasses.util.bukkit.versioning.compatibility.CompatibilityModifier.LivingEntity
.safeDamageEntityByEntity((LivingEntity) target, damager.getPlayer(), damage);
target.setNoDamageTicks(20);
if(particles != null) Vollotile.get().sendOwnParticleEffectToAll(particles, target.getEyeLocation());
}
private List<Location> getRandomLocations(RaCPlayer player, Location loc){
List<Location> locs = new LinkedList<Location>();
if(rainRange <= 0) rainRange = 5;
Random rand = new Random();
int i = 0;
int modAmount = modifyToPlayer(player, this.amount, "amount");
while(locs.size() < modAmount){
double xOffset = (rand.nextDouble() * rainRange * 2) - (rainRange);
double zOffset = (rand.nextDouble() * rainRange * 2) - (rainRange);
Location newLocation = loc.clone().add(xOffset, 0, zOffset);
if(newLocation.distanceSquared(loc) <= rainRange * rainRange) locs.add(newLocation);
i++;
if(i>200) return locs; //safe out.
}
return locs;
}
@Override
protected void magicSpellTriggered(RaCPlayer player, TraitResults result) {
Location lookLocation = getLookLocation(player);
//middle point.
Location middle = lookLocation.clone().add(0, aboveTarget, 0);
List<Location> spawnLocs = getRandomLocations(player, middle);
for(Location loc : spawnLocs){
if(loc.getBlock().getType() != Material.AIR) continue;
@SuppressWarnings("deprecation")
FallingBlock entity = loc.getWorld().spawnFallingBlock(loc, mat.getId(), (byte)matDamageValue);
entity.setDropItem(false);
entity.setMetadata(DELETE_ON_DROP, new FixedMetadataValue((Plugin) RacesAndClasses.getPlugin(), player));
}
if(particlesFromSelf != null) Vollotile.get()
.sendOwnParticleEffectToAll(particlesFromSelf, player.getPlayer().getLocation());
result.copyFrom(TraitResults.True());
}
}