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.managers.GroupManager;
import com.artemis.systems.EntityProcessingSystem;
import com.artemis.utils.EntityBuilder;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Json;
import net.mostlyoriginal.api.component.basic.Bounds;
import net.mostlyoriginal.api.component.basic.Pos;
import net.mostlyoriginal.api.component.graphics.Renderable;
import net.mostlyoriginal.api.utils.EntityUtil;
import net.mostlyoriginal.api.utils.GdxUtil;
import net.mostlyoriginal.game.G;
import net.mostlyoriginal.game.MyGame;
import net.mostlyoriginal.game.component.ship.CrewMember;
import net.mostlyoriginal.game.component.ui.*;
import net.mostlyoriginal.game.manager.EntityFactorySystem;
import net.mostlyoriginal.game.system.ship.*;
import net.mostlyoriginal.game.system.tutorial.TutorialSystem;
import java.util.*;
/**
* Responsible for serving and processing dilemmas.
*
* @author Daan van Yperen
*/
@Wire
public class DilemmaSystem extends EntityProcessingSystem {
private DilemmaLibrary dilemmaLibrary;
public static final String DILEMMA_GROUP = "dilemma";
public static final int ROW_HEIGHT = 9;
EntityFactorySystem efs;
public static final Color COLOR_DILEMMA = Color.valueOf("6AD7ED");
public static final String COLOR_RAW_BRIGHT = "E7E045";
public static final String COLOR_RAW_DIMMED = "FDF1AA";
private boolean dilemmaActive;
private GroupManager groupManager;
private InventorySystem inventorySystem;
private ProductionSimulationSystem productionSimulationSystem;
private ConstructionSystem constructionSystem;
protected ShipComponentSystem shipComponentSystem;
protected ComponentMapper<CrewMember> mCrewMember;
private CrewSystem crewSystem;
private LifesupportSimulationSystem lifesupportSimulationSystem;
private TutorialSystem tutorialSystem;
public DilemmaSystem() {
super(Aspect.getAspectForAll(Pos.class, DilemmaChoice.class));
}
public Entity createLabel(int x, int y, Color color, String text) {
return new EntityBuilder(world).with(
new Pos(x, y),
new Renderable(),
new Label(text),
GdxUtil.convert(color)
).group(DILEMMA_GROUP).build();
}
private Entity createOption(int x, int y, String text, ButtonListener listener) {
return new EntityBuilder(world).with(
new Pos(x, y),
new Label(text),
new Renderable(),
new Bounds(0, -8, text.length() * 8, 0),
new Clickable(),
new net.mostlyoriginal.api.component.graphics.Color(),
new Button(COLOR_RAW_DIMMED, COLOR_RAW_BRIGHT, "FFFFFF", listener)
)
.group(DILEMMA_GROUP).build();
}
public boolean isDilemmaActive() {
return dilemmaActive;
}
@Override
protected void initialize() {
super.initialize();
loadDilemmas();
startDilemma("START_TUTORIAL");
}
private void loadDilemmas() {
final Json json = new Json();
dilemmaLibrary = json.fromJson(DilemmaLibrary.class, Gdx.files.internal("dilemma.json"));
dilemmaLibrary.assignToGroups();
}
private void startDilemma(String dilemmaId )
{
Dilemma dilemma = dilemmaLibrary.getById(dilemmaId);
if ( dilemma == null ) {
throw new RuntimeException("Missing dilemma " + dilemmaId);
}
startDilemma(dilemma);
}
private Dilemma startDilemma(Dilemma dilemma) {
if (!dilemmaActive)
{
constructionSystem.stopConstructionmode();
int row = Math.max(4,dilemma.choices.length + dilemma.text.length);
final Entity globalCrewMember = dilemma.crew != null ? getCrewWithAbility(dilemma.crew) : null;
// abort if we lack required crew.
if ( dilemma.crew != null && globalCrewMember == null )
return null;
dilemmaActive = true;
for (String text : dilemma.text) {
createLabel(10, 10 + ROW_HEIGHT * row, COLOR_DILEMMA, replaceKeywords(text, globalCrewMember));
row--;
}
for (Dilemma.Choice choice : dilemma.choices) {
final Entity crewMember = choice.crew != null ? getCrewWithAbility(choice.crew) : globalCrewMember;
// random chance of succes, if no failure options defined, always failure.
final String[] choices = (choice.failure == null) || (MathUtils.random(0, 100) < 100-choice.risk) ? choice.success : choice.failure;
if ( (choice.crew == null) || crewMember != null ) {
createOption(10, 10 + ROW_HEIGHT * row, replaceKeywords("[" + choice.label[MathUtils.random(0, choice.label.length - 1)] + "]", crewMember), new DilemmaListener(choices, crewMember));
}
row--;
}
}
return dilemma;
}
private String replaceKeywords(String text, Entity crew) {
if ( crew != null ) {
CrewMember member = mCrewMember.get(crew);
if ( member != null ) {
text = text.replaceAll("\\{NAME\\}", member.name)
.replaceAll("\\{HIS\\}", "his")
.replaceAll("\\{HIM\\}", "him");
}
}
return text;
}
private Entity getCrewWithAbility(String ability) {
return crewSystem.randomWith(CrewMember.Ability.valueOf(ability));
}
/** Remove active dilemma from screen. */
private void stopDilemma() {
EntityUtil.safeDeleteAll(groupManager.getEntities(DILEMMA_GROUP));
dilemmaActive = false;
}
@Override
protected void process(Entity e) {
}
/** Spawn a dilemma, with a bias towards positive dilemmas. */
public void randomDilemma() {
randomDilemma(60);
}
private void randomDilemma(int positiveChance) {
if ( MathUtils.random(0, 99) < positiveChance) {
startRandomDilemmaFromGroup("positive");
} else {
startRandomDilemmaFromGroup("negative");
}
}
/** player is look for a fight, the odds are against him! */
public void scanDilemma() {
randomDilemma(40);
}
private void displayScore() {
Label score = new Label("Scored "+shipComponentSystem.shipValue()+" points");
score.scale=2;
new EntityBuilder(world).with(new Renderable(10000), new Pos(G.SCREEN_WIDTH/2 - 4*score.text.length(), G.SCREEN_HEIGHT/2), score).build();
}
/** Victory! :D */
public void victoryDilemma() {
displayScore();
startDilemma("VICTORY");
}
/** Out of gas. :( */
public void outOfFuelDilemma() {
startDilemma("OUT_OF_FUEL");
}
/** Drats. Those brainslugs. */
public void brainslugTakeoverDilemma() {
startDilemma("BRAINSLUGS_DOMINATE");
}
/** No pilots remain. :( */
public void noPilotsDilemma() {
startDilemma("NO_PILOTS_REMAIN");
}
/** Pick difficulty. */
public void afterTutorialDilemma() {
startDilemma("AFTER_TUTORIAL");
}
private void startRandomDilemmaFromGroup(String group) {
List<Dilemma> dilemmas = dilemmaLibrary.getGroup(group);
Dilemma dilemma = null;
while ( dilemma == null ) {
dilemma = dilemmas.get(MathUtils.random(0, dilemmas.size()-1));
if ( dilemma != null ) {
dilemma = startDilemma(dilemma);
// if startdilemma fails, it returns NULL and we will search again.
}
}
}
/** Just closes dilemma, no action */
private class CloseDilemmaListener extends ButtonListener {
@Override
public void run() {
stopDilemma();
}
}
public final String[] DEFAULT_ACTION = new String[]{"CLOSE"};
private class DilemmaListener extends ButtonListener {
private String[] actions;
private final Entity crewMember;
public DilemmaListener(String[] actions, Entity crewMember) {
super();
this.actions = actions;
this.crewMember = crewMember;
this.actions = actions == null || actions.length == 0 ? DEFAULT_ACTION : actions;
}
@Override
public void run() {
super.run();
// run all success.
for (String action : actions) {
triggerAction(action, crewMember);
}
}
}
/** Trigger hardcodede action indicated by string. If not exists, assume we are starting a dilemma. */
private void triggerAction(String action, Entity crewMember) {
stopDilemma();
switch ( action )
{
case "CLOSE" :
break;
case "RESTART":
restartGame();
break;
case "NEXT_TUTORIAL_STEP":
if ( dilemmaLibrary.getById("TEST") != null ) {
startDilemma("TEST");
} else
tutorialSystem.activateNextStep();
break;
case "INFECT":
lifesupportSimulationSystem.changeState(crewMember, CrewMember.Effect.BRAINSLUG);
break;
case "KILL":
lifesupportSimulationSystem.changeState(crewMember, CrewMember.Effect.DEAD);
break;
case "FUEL":
// spawn fuel.
productionSimulationSystem.spawnCollectibleRandomlyOnShip(InventorySystem.Resource.FUEL);
break;
case "FOOD":
// spawn food
productionSimulationSystem.spawnCollectibleRandomlyOnShip(InventorySystem.Resource.FOOD);
break;
case "CREW":
// spawn crew.
productionSimulationSystem.spawnCollectibleRandomlyOnShip(InventorySystem.Resource.CREWMEMBER);
break;
case "BIOGEL":
// spawn biogel
productionSimulationSystem.spawnCollectibleRandomlyOnShip(InventorySystem.Resource.BIOGEL);
break;
case "-FUEL":
// subtract fuel
inventorySystem.alter(InventorySystem.Resource.FUEL,-1);
break;
case "-FOOD":
// subtract food
inventorySystem.alter(InventorySystem.Resource.FOOD,-1);
break;
case "-CREW":
// subtract crew
inventorySystem.alter(InventorySystem.Resource.CREWMEMBER,-1);
break;
case "-BIOGEL":
// subtract biogel
inventorySystem.alter(InventorySystem.Resource.BIOGEL,-1);
break;
case "ENABLE_ENGAGE":
efs.createEngageButton();
break;
case "ENABLE_SCAN":
efs.createScanButton();
break;
default:
startDilemma(action);
break;
}
}
private static void restartGame() {
MyGame.getInstance().restart();
}
}