package propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.bomb;
import java.awt.Point;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import propra2012.gruppe33.bomberman.GameConstants;
import propra2012.gruppe33.bomberman.GameRoutines;
import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.CollectableItem;
import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.ItemSpawner;
import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.spawners.SpawnDead;
import propra2012.gruppe33.bomberman.graphics.rendering.scenegraph.grid.items.spawners.SpawnExplosion;
import com.indyforge.foxnet.rmi.pattern.change.AdminSessionServer;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.Entity;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.GraphicsEntity;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.RenderedImage;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.Scene;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.SceneProcessor;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.math.Grid;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.network.entity.DetachEntityChange;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.network.entity.OneToMany;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.network.sound.PlaySound;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.timeout.DetachOnTimeout;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.timeout.Timeout;
import com.indyforge.twod.engine.graphics.rendering.scenegraph.transform.TransformMotor;
/**
*
* @author Christopher Probst
*
*/
public final class Bomb extends OneToMany<GraphicsEntity, BombDesc> implements
GameConstants {
/**
*
*/
private static final long serialVersionUID = 1L;
/*
* (non-Javadoc)
*
* @see
* com.indyforge.twod.engine.graphics.rendering.scenegraph.network.entity
* .OneToMany
* #apply(com.indyforge.twod.engine.graphics.rendering.scenegraph.Entity,
* java.lang.Object)
*/
@Override
protected void apply(final GraphicsEntity entity, BombDesc value) {
// Get scene
final Scene scene = entity.findScene();
// Get the bomb
final CollectableItem bomb = value.item();
// Create a new bomb image
RenderedImage bombImage = new RenderedImage(
scene.imageProp(GameRoutines.itemToAsset(bomb))).centered(true);
// Use the same reg key
bombImage.registrationKey(value.itemEntity());
// Scale a bit
bombImage.scale().set(BOMB_SCALE);
// Set bomb order + tag
bombImage.index(ITEM_INDEX).tag(BOMB_TAG);
// Add a type prop
bombImage.addTypeProp(value);
// Scale velocity...
bombImage.attach(new TransformMotor()
.scaleVelocity(BOMB_SCALE_VELOCITY));
// Attach to the node
entity.attach(bombImage);
/*
* The server handles the destruction of the bomb!
*/
if (scene.processor().hasAdminSessionServer()) {
// Detach after the given delay!
bombImage.attach(new Timeout(value.delay())
.attach(new DetachOnTimeout()));
/*
* Handle the destruction!
*/
bombImage.attach(new Entity() {
/**
*
*/
private static final long serialVersionUID = 1L;
/*
* (non-Javadoc)
*
* @see
* com.indyforge.twod.engine.graphics.rendering.scenegraph.Entity
* #
* onParentDetached(com.indyforge.twod.engine.graphics.rendering
* .scenegraph.Entity,
* com.indyforge.twod.engine.graphics.rendering
* .scenegraph.Entity)
*/
@SuppressWarnings("unchecked")
@Override
protected void onParentDetached(Entity parent, Entity child) {
super.onParentDetached(parent, child);
// Get the server instance
AdminSessionServer<SceneProcessor> server = scene
.processor().adminSessionServer();
// Lookup player entity
Entity playerEntity = scene.registry()
.get(value().player());
// Bombspawner valid ??
if (playerEntity != null) {
// Respawn bomb
ItemSpawner sp = playerEntity
.typeProp(ItemSpawner.class);
// Increase the bomb count
sp.addItems(bomb, 1, false);
}
// Lookup grid
Grid grid = entity.parent().typeProp(Grid.class);
// Calc the explosion range
List<Point> points = GameRoutines.bombRange(entity,
GameRoutines.EXP_RANGE_FILTER, value().range());
// Used to detach entities
DetachEntityChange entityDetacher = new DetachEntityChange();
// Destroy the bomb image
entityDetacher.entities().add(value().itemEntity());
// The ids of the bombs will be stored here
List<UUID> destroyedFields = new ArrayList<UUID>(points
.size());
/*
* For all affected fields...
*/
for (Point point : points) {
// Get the node
Entity node = entity.parent()
.childAt(grid.index(point));
// Add the reg key of the node!
destroyedFields.add(node.registrationKey());
// Destroy breakable objects on both sides!
for (Entity ptr : node) {
// If BREAKABLE or BOMB ...
if (ptr.tagged(BREAKABLE_TAG)) {
// Simply detach from the scenegraph
entityDetacher.entities().add(
ptr.registrationKey());
} else if (ptr.tagged(BOMB_TAG)) {
/*
* Recursive bomb management!
*/
ptr.detach();
} else if (ptr.tagged(PLAYER_TAG)) {
boolean shield = false;
/*
* Search the entity for a shield.
*/
for (Entity subChild : ptr) {
if (subChild.tagged(SHIELD_TAG)) {
shield = true;
entityDetacher.entities().add(
subChild.registrationKey());
break;
}
}
// Had the player a shield ?
if (!shield) {
// Create new player kill
SpawnDead playerKill = new SpawnDead();
// Use the active player
playerKill.entities().add(
ptr.registrationKey());
// Queue the kill
server.composite().queueChange(playerKill,
true);
// Get player list
List<UUID> players = (List<UUID>) scene
.prop(PLAYERS_KEY);
// Remove from player list directly!
players.remove(ptr.registrationKey());
}
}
}
}
/*
* Detach destroyed objects.
*/
server.composite().queueChange(entityDetacher, true);
/*
* Spawn explosions!
*/
server.composite().queueChange(
new SpawnExplosion(destroyedFields), true);
/*
* Play a single sound on each client.
*/
server.broadcast().queueChange(
new PlaySound(GameConstants.EXP_SOUND), true);
}
});
}
}
public Bomb() {
}
public Bomb(List<UUID> registrationKeys) {
super(registrationKeys);
}
}