package me.vudu.Conflict.Blocks;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import me.vudu.Conflict.ConflictPlugin;
import me.vudu.Conflict.util.BlockLocation;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.plugin.Plugin;
import org.getspout.spoutapi.SpoutManager;
import org.getspout.spoutapi.block.SpoutBlock;
import org.getspout.spoutapi.block.design.Texture;
import org.getspout.spoutapi.inventory.SpoutItemStack;
import org.getspout.spoutapi.material.block.GenericCubeCustomBlock;
import org.getspout.spoutapi.player.SpoutPlayer;
public class ArtifactBlock extends GenericCubeCustomBlock{
/**
* State = 1,2,3 f�r das Level
*/
private int stage;
/**
* grow = 1,2,3,4,5 f�r die Wachstumstufen
*/
private int grow;
/**
* Zeit in ms, die ein Block braucht, um die n�chste stage zu erreichen
*/
public long timeForGrow;
/**
* Container zum Speichern der Zeitstempel
*/
public ConcurrentHashMap<BlockLocation, Long> timestamps;
/**
* speichert die Blocklocation, falls versucht wird, ein Artefakt Level 5 zu platzieren, damit dieses sofort wieder breaked ohne extras zu droppen
*/
private BlockLocation dontPlace;
/**
* erzeugt eine neue ArtefaktBlock-Art
* @param plugin zugeh�riges Plugin
* @param stage Level des Artefakts
* @param grow WachstumsStufe
*/
public ArtifactBlock(Plugin plugin, int stage, int grow) {
super(plugin, "ArtifactBlock0"+Integer.toString(stage)+"_0"+Integer.toString(grow), ConflictPlugin.ARTIFACTBLOCKID, "", 16);
this.getBlockDesign().setTexture(plugin, new Texture(plugin, "http://tossat.de/~mcbukkit/images/step"+stage+"_"+grow+".png", 16, 16, 16));
this.stage = stage;
this.grow = grow;
this.setHardness(ConflictPlugin.artBlockHardness);
this.timeForGrow=1000*ConflictPlugin.blockGrowTime;
ConflictPlugin.allArtifacts.add(this);
this.timestamps = new ConcurrentHashMap<BlockLocation, Long>(20);
//dropt Blume, wenn vor Level 5 abgebaut
if(this.grow<5){
this.setItemDrop(new SpoutItemStack(37, 0, (short) 0));
}
}
/**
* level 5?
* @return true, wenn level 5, false sonst
*/
public boolean is5(){
return this.grow == 5 ? true:false;
}
/**
* nicht benutzt
*/
public void onNeighborBlockChange(World world, int x, int y, int z, int changedId) { }
/**
* wird aufgereufen, wenn Bl�cke nicht von einem Spieler gestezt werden (automatisch)
* setzt den Timestamp (wird f�r Wachstum gebraucht) beim Platzieren
*/
public void onBlockPlace(World world, int x, int y, int z) {
BlockLocation bll = new BlockLocation(world.getName(),x,y,z);
Long overflow = ConflictPlugin.timestampOverflows.get(bll);
overflow = (overflow == null) ? 0 : overflow;
initTimestamp(world.getBlockAt(x, y, z), System.currentTimeMillis()-overflow);
ConflictPlugin.timestampOverflows.remove(bll);
if(null!= this.dontPlace){
BlockLocation bl = new BlockLocation(world.getName(),x,y,z);
if(this.dontPlace.equals(bl)){
SpoutItemStack temp = new SpoutItemStack(new SpoutItemStack(37, 0, (short) 0));
if(this.stage==1){
temp = new SpoutItemStack(ConflictPlugin.art_1_5);
}
if(this.stage==2){
temp = new SpoutItemStack(ConflictPlugin.art_2_5);
}
if(this.stage==3){
temp = new SpoutItemStack(ConflictPlugin.art_3_5);
}
world.getBlockAt(x, y, z).breakNaturally(ConflictPlugin.drops[0]);
world.dropItem(world.getBlockAt(x, y, z).getLocation(), temp);
onBlockDestroyed(world, x, y, z);
this.dontPlace=null;
}
}
}
/**
* wird aufgerufen, wenn ein Spieler diesen Block setzt
* setzt den Timestamp (wird f�r Wachstum gebraucht) beim Platzieren
* benachrichtigt ausserdem alle Spieler dar�ber dass ein ArtefaktBlock der Stufe X von Team Y gebaut wurde
*/
public void onBlockPlace(World world, int x, int y, int z, LivingEntity living) {
SpoutPlayer player = (SpoutPlayer) living;
//Artefakt Lvl 5 d�rfen nicht wieder platziert werden
if(this.is5()){
this.dontPlace = new BlockLocation(world.getName(), x, y, z);
return;
}
//Nachricht, dass Artefakt gebaut wurde
Location l = world.getBlockAt(x, y, z).getLocation();
Block below = world.getBlockAt(x, y-1, z);
String team = ConflictPlugin.playerIsInTeam((SpoutPlayer) living);
ArrayList<BlockLocation> base = team.equals("red") ? ConflictPlugin.baseBlocksRed : ConflictPlugin.baseBlocksBlue;
if(ConflictPlugin.getDistanceToBase(world, l, team)<= 2){
if(below instanceof SpoutBlock && below.getTypeId()==ConflictPlugin.BASEBLOCKID){
for(BlockLocation l2 : base){
if(ConflictPlugin.compareLocaction(l2, below.getLocation())){
Bukkit.getServer().broadcastMessage("Team "+team+" placed an artifact of stage "+Integer.toString(this.stage));
for(SpoutPlayer p : ConflictPlugin.players){
p.sendNotification("Artefakt gebaut", "Team "+team+": Stufe "+Integer.toString(this.stage), Material.RECORD_3, (short)0, 10000);
}
if(this.stage==1){
ConflictPlugin.totalArt1.put(player.getName(),1+ ConflictPlugin.totalArt1.get(player.getName()));
}
if(this.stage==2){
ConflictPlugin.totalArt2.put(player.getName(), 1+ ConflictPlugin.totalArt2.get(player.getName()));
}
}
}
}
}
}
/**
* entfernt den Timestamp-eintag aus der Liste
*/
public void onBlockDestroyed(World world, int x, int y, int z) {
for(BlockLocation bl: this.timestamps.keySet()){
if(bl.equals(new BlockLocation(world.getName(), x, y, z))){
removeTimestamp(bl);
}
}
}
/**
* falls true, dann kann man darauf nicht bauen, sondern damit interagieren
*/
public boolean onBlockInteract(World world, int x, int y, int z, SpoutPlayer player) {
return true;
}
/**
* nicht benutzt
*/
public void onEntityMoveAt(World world, int x, int y, int z, Entity entity) { }
/**
* wird aufgerufen, wenndas Artefakt angeklickt wird
* ruft artifactClicked auf, sofern Spieler das eigene Artefakt anklicken
*/
public void onBlockClicked(World world, int x, int y, int z, SpoutPlayer player) {
//nur wenn Redstonelamp in der hand
if (player.getItemInHand().getTypeId()!=75 && player.getItemInHand().getTypeId()!=76){
return;
}
if(ConflictPlugin.playerIsInTeam(player).equals("red")){
Location l = world.getBlockAt(x, y, z).getLocation();
if(ConflictPlugin.getDistanceToBase(world, l, "red")<= 2){
artifactClicked(world, x, y, z, player);
}
}
if(ConflictPlugin.playerIsInTeam(player).equals("blue")){
Location l = world.getBlockAt(x, y, z).getLocation();
if(ConflictPlugin.getDistanceToBase(world, l, "blue")<= 2){
artifactClicked(world, x, y, z, player);
}
}
}
/**
* wird aufgerufen, wenn das Artefakt angeklickt wird
* @param world
* @param x
* @param y
* @param z
* @param player
*/
private void artifactClicked(World world, int x, int y, int z, SpoutPlayer player){
BlockLocation bl = new BlockLocation(world.getBlockAt(x, y, z).getLocation());
if(this.stage==3){
player.sendMessage("Artefakte der Stufe 3 k�nnen nicht beschleunigt werden");
return;
}
if(this.grow==5){
return;
}
if(player.getLevel()>= ConflictPlugin.artSpeedupMax){
speedup(bl, ConflictPlugin.artSpeedupMax);
player.setLevel(player.getLevel()-ConflictPlugin.artSpeedupMax);
}else{
speedup(bl, player.getLevel());
player.setLevel(0);
}
}
/**
* updatet den Timestamp nach einem Server-neustart
* @param serverClose Timestamp des Server-schlie�ens
* @param serverOpen Timestamp des Server-Wiederer�ffnens
*/
public void updateTimestamps(long serverClose, long serverOpen){
if(serverClose>0){
synchronized (this.timestamps){
for(Entry<BlockLocation, Long> entry :this.timestamps.entrySet()){
Bukkit.getLogger().log(Level.INFO, "updating TS from "+Long.toString(entry.getValue())+" to "+Long.toString(entry.getValue()+(serverOpen-serverClose )));
entry.setValue(entry.getValue()+(serverOpen-serverClose ));
}
}
}
}
/**
* f�gt einen Timestamp-Eintrag hinzu
* @param block Block, der gebaut wurde
* @param timestamp zugeh�riger Timestamp
*/
private void initTimestamp(org.bukkit.block.Block block, long timestamp){
synchronized (this.timestamps){
BlockLocation key = new BlockLocation(block.getLocation());
if(!(this.timestamps.containsKey(key))){
this.timestamps.put(key, timestamp);
}
}
}
/**
* entfernt den zugeh�rigen Timestamp
* @param block Block der entfernt wurde
*/
private void removeTimestamp(BlockLocation bl){
synchronized (this.timestamps){
if(null== this.timestamps.remove(bl)){
Bukkit.getLogger().log(Level.INFO, "REMOVING TS FAILED: "+ bl.toString());
}
}
}
/**
* �berpr�ft, ob ein Block 'reif' f�r die n�chste Stufe ist
*/
public void checkTimestamp(){
synchronized (this.timestamps){
if(null!= this.timestamps.keySet()){
for(BlockLocation bl : this.timestamps.keySet()){
if(System.currentTimeMillis() >= timestamps.get(bl).longValue()+this.timeForGrow){
long overflow = System.currentTimeMillis() - (timestamps.get(bl).longValue()+this.timeForGrow);
ConflictPlugin.timestampOverflows.put(bl, overflow);
grow(bl);
}
}
}
}
}
/**
* beschleunigt das Wachsen eines Artefaktes
* nach der Formel 10s * level*level +0.5*level
* @param bl BlockLocation des Artefakts
* @param levels investierte Level
*/
private void speedup(BlockLocation bl, int levels){
long seconds = (long) (20/stage* (levels*levels)); //TODO remove, when EXP is gained linearly in MC 1.3
long l = 0;
for(BlockLocation bll : this.timestamps.keySet()){
if(bl.equals(bll)){
l = this.timestamps.get(bll);
this.timestamps.put(bll, l-1000*seconds);
return;
}
}
}
/**
* l�sst einen Block wachsen, also ersetzt ihn durch eine Instanz der n�chsten Stufe
* oder falls h�chstes Level und Stufe checkt Siegbedingnung
* @param block wachsender Block
*/
private void grow(BlockLocation bl){
org.bukkit.block.Block block = Bukkit.getWorld(bl.getWorld()).getBlockAt(bl.getX(), bl.getY(), bl.getZ());
removeTimestamp(bl);
//Hier steht nun ein fertiges Arteakt (kann abgebaut werden)
if(this.grow==4){
ConflictPlugin.is5Locations.put(bl, true);
if(stage==3){
ConflictPlugin.checkWin(block);
}
}
if(this.grow<5){
switch (stage) {
case 1:
SpoutManager.getMaterialManager().overrideBlock(block, ConflictPlugin.artifact1Grow.get(new Integer(this.grow+1)));
break;
case 2:
SpoutManager.getMaterialManager().overrideBlock(block, ConflictPlugin.artifact2Grow.get(new Integer(this.grow+1)));
break;
case 3:
SpoutManager.getMaterialManager().overrideBlock(block, ConflictPlugin.artifact3Grow.get(new Integer(this.grow+1)));
break;
default:
break;
}
//ausgewachsen
}
}
}