package net.mostlyoriginal.game.system.ui;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Wire;
import com.artemis.systems.EntityProcessingSystem;
import com.artemis.utils.EntityBuilder;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import net.mostlyoriginal.api.component.basic.Pos;
import net.mostlyoriginal.api.component.graphics.Anim;
import net.mostlyoriginal.api.component.graphics.Renderable;
import net.mostlyoriginal.api.event.common.EventManager;
import net.mostlyoriginal.api.utils.reference.SafeEntityReference;
import net.mostlyoriginal.game.G;
import net.mostlyoriginal.game.component.ship.ShipComponent;
import net.mostlyoriginal.game.component.ui.Button;
import net.mostlyoriginal.game.component.ui.ButtonListener;
import net.mostlyoriginal.game.component.ui.Clickable;
import net.mostlyoriginal.game.manager.AssetSystem;
import net.mostlyoriginal.game.manager.EntityFactorySystem;
import net.mostlyoriginal.game.system.event.SelectConstructionEvent;
import net.mostlyoriginal.game.system.event.StartConstructionEvent;
import net.mostlyoriginal.game.system.ship.HullSystem;
import net.mostlyoriginal.game.system.ship.InventorySystem;
import net.mostlyoriginal.game.system.ship.ShipComponentSystem;
import net.mostlyoriginal.game.system.ship.TravelSimulationSystem;
import net.mostlyoriginal.game.system.tutorial.TutorialSystem;
import java.util.HashMap;
/**
* @author Daan van Yperen
*/
@Wire
public class ConstructionSystem extends EntityProcessingSystem {
public static final int MARGIN_RIGHT = -140;
EntityFactorySystem efs;
private TravelSimulationSystem travelSimulationSystem;
private DilemmaSystem dilemmaSystem;
private ShipComponent.Type selected;
protected ComponentMapper<Anim> mAnim;
protected ComponentMapper<ShipComponent> mShipComponent;
protected ComponentMapper<Clickable> mClickable;
protected ComponentMapper<Button> mButton;
private InventorySystem inventorySystem;
private HullSystem hullSystem;
private AssetSystem assetSystem;
private TutorialSystem tutorialSystem;
public final HashMap<ShipComponent.Type, Entity> constructionButton = new HashMap<>();
private EventManager em;
public ConstructionSystem() {
super(Aspect.getAspectForAll(ShipComponent.class, Clickable.class, Anim.class));
}
@Override
protected void initialize() {
super.initialize();
// list all buildable structures.
createConstructionButtons();
}
@Override
protected void process(Entity e) {
// Building is restricted to hull parts.
final ShipComponent shipComponent = mShipComponent.get(e);
if ( shipComponent.type == ShipComponent.Type.HULL)
{
// show building indicator while placing.
final boolean validDestination = canAttachTo(selected, e);
final Anim anim = mAnim.get(e);
anim.id2 = validDestination ? "c-indicator" : null;
// start construction when clicked.
final Clickable clickable = mClickable.get(e);
if ( clickable.state == Clickable.ClickState.CLICKED && validDestination )
{
startConstruction(e, selected);
// continue placement as long as control is pressed.
if ( !Gdx.input.isKeyPressed(Input.Keys.CONTROL_LEFT ) && !Gdx.input.isKeyPressed(Input.Keys.CONTROL_RIGHT ) ) stopConstructionmode();
}
}
}
/** Finish construction of passed ship component. */
public void complete(Entity entity) {
if (entity != null) {
final ShipComponent c = mShipComponent.get(entity);
if (c.state == ShipComponent.State.UNDER_CONSTRUCTION) {
c.state = ShipComponent.State.CONSTRUCTED;
switch (c.type) {
case HULL:
break;
case BUNKS:
break;
case MEDBAY:
inventorySystem.alter(InventorySystem.Resource.BIOGEL_STORAGE, 1);
break;
case HYDROPONICS:
break;
case STORAGEPOD:
inventorySystem.alter(InventorySystem.Resource.STORAGE, 1);
break;
case ENGINE:
efs.createEngineFlame(c.gridX - 3, c.gridY);
inventorySystem.alter(InventorySystem.Resource.THRUST, 1);
break;
case RAMSCOOP:
break;
}
}
}
}
/** Return if locale is valid. */
private boolean canAttachTo(ShipComponent.Type type, Entity destination) {
final Anim anim = mAnim.get(destination);
final ShipComponent shipComponent = mShipComponent.get(destination);
if ( anim == null || shipComponent == null ) return false;
// don't allow expanding at the borders so the hull doesn't break.
if ( shipComponent.gridX <= 0 ||shipComponent.gridY <= 0 || shipComponent.gridX >= ShipComponentSystem.MAX_X-1 || shipComponent.gridY >= ShipComponentSystem.MAX_Y -1 )
return false;
// only allow engine on left facing hull.
if ( type == ShipComponent.Type.ENGINE && (!"hull-3".equals(anim.id) && !"hull-3-building".equals(anim.id)) ) return false;
// only allow ramscoop on right facing hull.
if ( type == ShipComponent.Type.RAMSCOOP && (!"hull-4".equals(anim.id) && !"hull-4-building".equals(anim.id)) ) return false;
return type != null;
}
public void stopConstructionmode() {
selected=null;
}
/** Activate shipcomponent! */
private void startConstruction(Entity e, ShipComponent.Type selected) {
if ( selected != null && e != null && mAnim.has(e) && mShipComponent.has(e) ) {
assetSystem.playSfx("snd-click");
final ShipComponent shipComponent = mShipComponent.get(e);
shipComponent.type = selected;
shipComponent.state = ShipComponent.State.UNDER_CONSTRUCTION;
shipComponent.constructionManyearsRemaining = selected.buildManYears;
mAnim.get(e).id = selected.animId;
hullSystem.dirty();
// inform other systems (like tutorial).
em.dispatch(new StartConstructionEvent(selected));
}
}
private void createConstructionButtons() {
int index = 0;
for (ShipComponent.Type structure : ShipComponent.Type.values()) {
if (structure.buildable) {
int x = G.SCREEN_WIDTH + MARGIN_RIGHT - (index + 1) * 18;
int y = 7;
final Entity button = efs.createButton(x, y, 15, 15, "btn-construct", new ToolSelectButton(structure), null);
constructionButton.put(structure, button);
Button button1 = mButton.get(button);
button1.color = Color.WHITE;
button1.hint = structure.label;
button1.hideIfDisabled =true;
button1.transientIcon = new SafeEntityReference(new EntityBuilder(world).with(
new Pos(x + 4, y + 5),
new Anim(structure.animId),
new Renderable(4000)).build());
// add icon over button. @todo merge with button logic.
index++;
}
}
}
private void startPlacing(ShipComponent.Type selected) {
this.selected = selected;
// inform other systems (like tutorial).
em.dispatch(new SelectConstructionEvent(selected));
}
private class ToolSelectButton extends ButtonListener {
private final ShipComponent.Type structure;
private ToolSelectButton(ShipComponent.Type structure) {
this.structure = structure;
}
@Override
public void run() {
startPlacing(this.structure);
}
@Override
public boolean enabled() {
// we don't want to allow building while busy!.
return !travelSimulationSystem.isTraveling() && !dilemmaSystem.isDilemmaActive();
}
}
}