diff --git a/core/src/com/galvarez/ttw/model/AIDiscoverySystem.java b/core/src/com/galvarez/ttw/model/AIDiscoverySystem.java index 079b2b8..0967dbc 100644 --- a/core/src/com/galvarez/ttw/model/AIDiscoverySystem.java +++ b/core/src/com/galvarez/ttw/model/AIDiscoverySystem.java @@ -32,6 +32,8 @@ public final class AIDiscoverySystem extends EntityProcessingSystem { private ComponentMapper empires; + private DiscoverySystem system; + @SuppressWarnings("unchecked") public AIDiscoverySystem() { super(Aspect.getAspectForAll(AIControlled.class, Discoveries.class, Empire.class)); @@ -45,7 +47,9 @@ protected boolean checkProcessing() { @Override protected void process(Entity e) { Discoveries d = discoveries.get(e); - if (d.next == null) { + + if (d.nextPossible != null) { + // we need to make some discovery Culture culture = empires.get(e).culture; Entry prefered = null; float max = Float.NEGATIVE_INFINITY; @@ -60,7 +64,7 @@ protected void process(Entity e) { if (prefered != null) { log.debug("{} follows {} advice to investigate {} from {}", e.getComponent(Name.class), prefered.getKey(), prefered.getValue().target, prefered.getValue().previous); - d.next = prefered.getValue(); + system.discoverNew(e, d, prefered.getValue()); } Set newPolicies; if (d.last != null && (newPolicies = PoliciesSystem.getPolicies(d.last.target)) != null) { diff --git a/core/src/com/galvarez/ttw/model/DestinationSystem.java b/core/src/com/galvarez/ttw/model/DestinationSystem.java index e8cb16f..c82c7a0 100644 --- a/core/src/com/galvarez/ttw/model/DestinationSystem.java +++ b/core/src/com/galvarez/ttw/model/DestinationSystem.java @@ -178,8 +178,10 @@ else if (treaties.getRelationWith(inf.getMainInfluenceSource(world)) != State.TR */ public List computePath(Entity e, MapPosition target) { Destination dest = destinations.get(e); - List path = astar.aStarSearch(positions.get(e), target,// - p -> !dest.forbiddenTiles.contains(map.getTerrainAt(p)) && map.getEntityAt(p) == null); + MapPosition start = positions.get(e); + List path = astar.aStarSearch(start, target,// + p -> (!dest.forbiddenTiles.contains(map.getTerrainAt(p)) || map.getTerrainAt(start) == map.getTerrainAt(p)) + && map.getEntityAt(p) == null); if (path == null) return null; diff --git a/core/src/com/galvarez/ttw/model/DiplomaticSystem.java b/core/src/com/galvarez/ttw/model/DiplomaticSystem.java index 3a1d2ff..33a3169 100644 --- a/core/src/com/galvarez/ttw/model/DiplomaticSystem.java +++ b/core/src/com/galvarez/ttw/model/DiplomaticSystem.java @@ -23,8 +23,8 @@ import com.artemis.utils.ImmutableBag; import com.galvarez.ttw.model.components.AIControlled; import com.galvarez.ttw.model.components.Diplomacy; -import com.galvarez.ttw.rendering.NotificationsSystem; import com.galvarez.ttw.rendering.IconsSystem.Type; +import com.galvarez.ttw.rendering.NotificationsSystem; import com.galvarez.ttw.rendering.components.Description; import com.galvarez.ttw.rendering.components.Name; import com.galvarez.ttw.screens.overworld.OverworldScreen; @@ -162,6 +162,14 @@ else if (!ai.has(target)) entity.getComponent(Name.class), action.afterYou); } + public void clearRelations(Entity empire, Diplomacy diplo) { + diplo.proposals.clear(); + for (Entity e : diplo.relations.keySet()) { + relations.get(e).relations.remove(empire); + } + diplo.relations.clear(); + } + public Collection getPossibleActions(Diplomacy diplo, Entity target) { Set actions = EnumSet.of(Action.NO_CHANGE); for (Action action : Action.values()) { diff --git a/core/src/com/galvarez/ttw/model/DiscoverySystem.java b/core/src/com/galvarez/ttw/model/DiscoverySystem.java index 50dbbd4..e563df2 100644 --- a/core/src/com/galvarez/ttw/model/DiscoverySystem.java +++ b/core/src/com/galvarez/ttw/model/DiscoverySystem.java @@ -1,7 +1,6 @@ package com.galvarez.ttw.model; import static java.lang.Math.min; -import static java.lang.String.join; import static java.util.stream.Collectors.toList; import java.util.ArrayList; @@ -45,7 +44,6 @@ import com.galvarez.ttw.model.map.Terrain; import com.galvarez.ttw.rendering.IconsSystem.Type; import com.galvarez.ttw.rendering.NotificationsSystem; -import com.galvarez.ttw.rendering.NotificationsSystem.Condition; import com.galvarez.ttw.rendering.components.Description; import com.galvarez.ttw.rendering.components.Name; import com.galvarez.ttw.screens.overworld.OverworldScreen; @@ -159,51 +157,55 @@ protected void inserted(Entity e) { super.inserted(e); Discoveries d = empires.get(e); d.nextPossible = possibleDiscoveries(e, d); - - if (e == screen.player) - notifications.addNotification(screen::discoveryMenu, () -> d.next != null, Type.DISCOVERY, - "No research selected!"); + d.progress = DISCOVERY_THRESHOLD; } @Override protected void processEntities(ImmutableBag entities) { for (Entity entity : entities) { Discoveries discovery = empires.get(entity); - if (discovery.nextPossible == null || discovery.nextPossible.isEmpty()) - discovery.nextPossible = possibleDiscoveries(entity, discovery); - if (discovery.next != null) { + if (discovery.last != null) { if (progressNext(discovery, influences.get(entity))) discoverNext(entity, discovery); - } + else + discovery.nextPossible = null; + } else + discoverNext(entity, discovery); } } private boolean progressNext(Discoveries discovery, InfluenceSource influence) { int progress = discovery.progressPerTurn; - Set terrains = discovery.next.target.terrains; + Set terrains = discovery.last.target.terrains; if (terrains != null && !terrains.isEmpty()) { for (MapPosition pos : influence.influencedTiles) { if (terrains.contains(map.getTerrainAt(pos))) progress += PROGRESS_PER_TILE; } } - discovery.next.progress += progress; - return discovery.next.progress >= DISCOVERY_THRESHOLD; + discovery.progress += progress; + return discovery.progress >= DISCOVERY_THRESHOLD; } private void discoverNext(Entity empire, Discoveries discovery) { - Research next = discovery.next; - Discovery target = next.target; - log.info("{} discovered {} from {}.", empire.getComponent(Name.class), target, next.previous); + discovery.nextPossible = possibleDiscoveries(empire, discovery); + + if (!ai.has(empire) && !discovery.nextPossible.isEmpty()) { + Research last = discovery.last; + notifications.addNotification(screen::askDiscovery, () -> discovery.last != last, Type.DISCOVERY, + "We can make a new discovery!"); + } + } + + /** Called when the next discovery is chosen. */ + public void discoverNew(Entity empire, Discoveries discovery, Research research) { + Discovery target = research.target; + log.info("{} discovered {} from {}.", empire.getComponent(Name.class), target, research.previous); discovery.done.add(target); - discovery.next = null; + discovery.progress = 0; + discovery.nextPossible.clear(); - discovery.nextPossible = possibleDiscoveries(empire, discovery); if (!ai.has(empire)) { - Condition condition = !discovery.nextPossible.isEmpty() ? (() -> discovery.next != null - || discovery.nextPossible.isEmpty()) : null; - notifications.addNotification(screen::discoveryMenu, condition, Type.DISCOVERY, "Discovered %s: %s", target, - target.effects.isEmpty() ? "No effect." : join(", ", effectsStrings(target))); Set policies = PoliciesSystem.getPolicies(target); if (policies != null) { for (Policy policy : policies) @@ -221,7 +223,7 @@ private void discoverNext(Entity empire, Discoveries discovery) { // remove last discovery 2x bonus (to keep only the basic effect) if (discovery.last != null) effects.apply(discovery.last.target.effects, empire, true); - discovery.last = next; + discovery.last = research; // apply new discovery effects.apply(target.effects, empire, false); @@ -337,20 +339,6 @@ private Iterable getNeighbors(Entity empire) { return neighbors.values(); } - public int guessNbTurns(Discoveries discovery, Entity empire, Discovery d) { - InfluenceSource influence = influences.get(empire); - - Set terrains = d.terrains; - int progressPerTurn = discovery.progressPerTurn; - if (terrains != null && !terrains.isEmpty()) { - for (MapPosition pos : influence.influencedTiles) - if (terrains.contains(map.getTerrainAt(pos))) - progressPerTurn += PROGRESS_PER_TILE; - } - - return DISCOVERY_THRESHOLD / progressPerTurn; - } - public List effectsStrings(Discovery d) { List list = effects.toString(d.effects); if (buildings.containsKey(d.name)) diff --git a/core/src/com/galvarez/ttw/model/EffectsSystem.java b/core/src/com/galvarez/ttw/model/EffectsSystem.java index a85b937..7e52b7b 100644 --- a/core/src/com/galvarez/ttw/model/EffectsSystem.java +++ b/core/src/com/galvarez/ttw/model/EffectsSystem.java @@ -95,10 +95,11 @@ private final class MilitaryEffect implements Effect { @Override public void apply(Number value, Entity empire, boolean revert) { ArmyCommand army = armies.get(empire); + int delta = 2 * value.intValue(); if (revert) - army.militaryPower -= 2 * value.intValue(); + army.militaryPower -= delta; else - army.militaryPower += 2 * value.intValue(); + army.militaryPower += delta; } @Override diff --git a/core/src/com/galvarez/ttw/model/InfluenceSystem.java b/core/src/com/galvarez/ttw/model/InfluenceSystem.java index 12aeb82..94190eb 100644 --- a/core/src/com/galvarez/ttw/model/InfluenceSystem.java +++ b/core/src/com/galvarez/ttw/model/InfluenceSystem.java @@ -179,6 +179,7 @@ private void checkInfluencedByOther(InfluenceSource source, Entity empire) { influencer.getComponent(Description.class)); delete(empire); } else { + diplomaticSystem.clearRelations(empire, loser); diplomaticSystem.changeRelation(empire, loser, influencer, relations.get(influencer), Action.SURRENDER); loser.proposals.remove(influencer); diff --git a/core/src/com/galvarez/ttw/model/components/Discoveries.java b/core/src/com/galvarez/ttw/model/components/Discoveries.java index 8ebeb5f..7461acb 100644 --- a/core/src/com/galvarez/ttw/model/components/Discoveries.java +++ b/core/src/com/galvarez/ttw/model/components/Discoveries.java @@ -15,12 +15,13 @@ public final class Discoveries extends Component { /** Increase to speed progress up. */ public int progressPerTurn = 20; + /** Contains possibles discoveries when one is expected. */ public Map nextPossible; - public Research next; - public Research last; + public int progress = 0; + public Discoveries() { } diff --git a/core/src/com/galvarez/ttw/model/components/Research.java b/core/src/com/galvarez/ttw/model/components/Research.java index 79b92f3..1fbfb82 100644 --- a/core/src/com/galvarez/ttw/model/components/Research.java +++ b/core/src/com/galvarez/ttw/model/components/Research.java @@ -15,8 +15,6 @@ public class Research extends Component { public final Discovery target; - public int progress = 0; - public Research(Discovery target, Collection previous) { this.target = target; this.previous = previous; @@ -31,7 +29,7 @@ public Research(Discovery target, Collection previous) { @Override public String toString() { - return target.name + "[" + progress + "% " + factions + "]"; + return target.name + factions; } } diff --git a/core/src/com/galvarez/ttw/rendering/ui/FramedMenu.java b/core/src/com/galvarez/ttw/rendering/ui/FramedMenu.java index 1cd950a..6fe39d7 100644 --- a/core/src/com/galvarez/ttw/rendering/ui/FramedMenu.java +++ b/core/src/com/galvarez/ttw/rendering/ui/FramedMenu.java @@ -282,6 +282,9 @@ public void changed(ChangeEvent event, Actor actor) { * Adds the frame and scrollpane to the specified stage at the specified * location. Sizes the scrollpane to the (estimated) table size, up to a * maximum given in the constructor. + *

+ * If x or y coordinate is negative, center the menu in the corresponding + * dimension. * * @param canEscape if true pressing on ESC key will close the menu */ diff --git a/core/src/com/galvarez/ttw/screens/AskDiscoveryScreen.java b/core/src/com/galvarez/ttw/screens/AskDiscoveryScreen.java new file mode 100644 index 0000000..ce679c4 --- /dev/null +++ b/core/src/com/galvarez/ttw/screens/AskDiscoveryScreen.java @@ -0,0 +1,99 @@ +package com.galvarez.ttw.screens; + +import java.util.Map.Entry; + +import com.artemis.Entity; +import com.artemis.World; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.galvarez.ttw.ThingsThatWereGame; +import com.galvarez.ttw.model.DiscoverySystem; +import com.galvarez.ttw.model.Faction; +import com.galvarez.ttw.model.components.Discoveries; +import com.galvarez.ttw.model.components.Research; +import com.galvarez.ttw.model.data.Discovery; +import com.galvarez.ttw.rendering.ui.FramedMenu; +import com.galvarez.ttw.screens.overworld.OverworldScreen; + +/** + * This screen appears when user tries to pause or escape from the main game + * screen. + * + * @author Guillaume Alvarez + */ +public final class AskDiscoveryScreen extends AbstractPausedScreen { + + private final FramedMenu choices; + + private final Discoveries empire; + + private final DiscoverySystem discoverySystem; + + private final Entity player; + + public AskDiscoveryScreen(ThingsThatWereGame game, World world, SpriteBatch batch, OverworldScreen gameScreen, + Entity player, DiscoverySystem discoverySystem) { + super(game, world, batch, gameScreen); + this.player = player; + this.empire = player.getComponent(Discoveries.class); + this.discoverySystem = discoverySystem; + + choices = new FramedMenu(skin, 800, 600); + } + + @Override + protected void initMenu() { + choices.clear(); + + if (empire.nextPossible == null || empire.nextPossible.isEmpty()) { + // may be displayed from discovery menu + choices.addButton("No discoveries to combine!", this::resumeGame); + } else { + choices.addLabel("Which faction do you choose to make new discoveries?"); + for (Entry next : empire.nextPossible.entrySet()) + choices.addButton(action(next.getKey()), previousString(next.getValue()), () -> newDiscovery(next.getValue()), + true); + + choices.addLabel(" "); + choices.addButton("Choose later...", this::resumeGame); + } + + choices.addToStage(stage, -1, -1, true); + } + + private static String previousString(Research next) { + if (next.previous.isEmpty()) + return "our environment"; + + StringBuilder sb = new StringBuilder(); + for (Discovery previous : next.previous) + sb.append(previous.name).append(", "); + sb.setLength(sb.length() - 2); + return sb.toString(); + } + + private static String action(Faction faction) { + switch (faction) { + case CULTURAL: + return "Cultural faction advises to meditate on "; + case ECONOMIC: + return "Economic faction suggest we pursue profit in "; + case MILITARY: + return "Military faction commands us to investigate "; + default: + throw new IllegalStateException("Unknown faction " + faction); + } + } + + private void newDiscovery(Research next) { + discoverySystem.discoverNew(player, empire, next); + + choices.clear(); + + StringBuilder sb = new StringBuilder("We discovered " + next.target.name + "!"); + for (String effect : discoverySystem.effectsStrings(empire.last.target)) + sb.append("\n - " + effect); + choices.addButton(sb.toString(), this::resumeGame); + + choices.addToStage(stage, -1, -1, true); + } +} diff --git a/core/src/com/galvarez/ttw/screens/DiplomacyMenuScreen.java b/core/src/com/galvarez/ttw/screens/DiplomacyMenuScreen.java index 83fa944..fbe1045 100644 --- a/core/src/com/galvarez/ttw/screens/DiplomacyMenuScreen.java +++ b/core/src/com/galvarez/ttw/screens/DiplomacyMenuScreen.java @@ -73,7 +73,7 @@ protected void initMenu() { float angle = 2f * PI / (player != null ? empires.size() - 1 : empires.size()); float angle1 = 0f; Diplomacy playerDiplo = player != null ? player.getComponent(Diplomacy.class) : null; - for (Entity empire : empires) { + for (Entity empire : playerDiplo != null ? playerDiplo.relations.keySet() : empires) { if (empire != player) { FramedMenu menu = new FramedMenu(skin, maxWidth, 128); menu.addLabel(empire.getComponent(Name.class).name); diff --git a/core/src/com/galvarez/ttw/screens/DiscoveryMenuScreen.java b/core/src/com/galvarez/ttw/screens/DiscoveryMenuScreen.java index 54e2606..ed8c75c 100644 --- a/core/src/com/galvarez/ttw/screens/DiscoveryMenuScreen.java +++ b/core/src/com/galvarez/ttw/screens/DiscoveryMenuScreen.java @@ -3,14 +3,11 @@ import static java.lang.Math.max; import static java.lang.String.format; -import java.util.Map.Entry; - import com.artemis.Entity; import com.artemis.World; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.galvarez.ttw.ThingsThatWereGame; import com.galvarez.ttw.model.DiscoverySystem; -import com.galvarez.ttw.model.Faction; import com.galvarez.ttw.model.components.Discoveries; import com.galvarez.ttw.model.components.InfluenceSource; import com.galvarez.ttw.model.components.Research; @@ -35,12 +32,9 @@ public final class DiscoveryMenuScreen extends AbstractPausedScreen next : empire.nextPossible.entrySet()) - discoveryChoices.addButton( - action(next.getKey()), - previousString(next.getValue()) + " (~" - + discoverySystem.guessNbTurns(empire, entity, next.getValue().target) + " turns)", // - new Runnable() { - @Override - public void run() { - empire.next = next.getValue(); - resumeGame(); - } - }, true); - } - } + discoveryChoices.addButton("Progress toward next discovery: " + empire.progress + "% (+" + empire.progressPerTurn + + "%/turn)", gameScreen::askDiscovery); + discoveryChoices.addLabel(" "); discoveryChoices.addToStage(stage, 30, terrains.getY() - 30, false); } - private static String action(Faction faction) { - switch (faction) { - case CULTURAL: - return "Cultural faction advises to meditate on "; - case ECONOMIC: - return "Economic faction recommends we pursue profit in "; - case MILITARY: - return "Military faction commands us to investigate "; - default: - throw new IllegalStateException("Unknown faction " + faction); - } - } - private static String previousString(Research next) { if (next.previous.isEmpty()) return "our environment"; @@ -130,8 +90,4 @@ private static String previousString(Research next) { return sb.toString(); } - private void changeResearch() { - empire.next = null; - initMenu(); - } } diff --git a/core/src/com/galvarez/ttw/screens/overworld/MenuBuilder.java b/core/src/com/galvarez/ttw/screens/overworld/MenuBuilder.java index 7242b2d..d360217 100644 --- a/core/src/com/galvarez/ttw/screens/overworld/MenuBuilder.java +++ b/core/src/com/galvarez/ttw/screens/overworld/MenuBuilder.java @@ -158,8 +158,7 @@ public void buildEmpireMenu() { // here present a sub-menu to see current discovery and be able to change it Discoveries discoveries = screen.player.getComponent(Discoveries.class); - empireMenu.addButton("Discovery " - + (discoveries != null && discoveries.next != null ? "(" + discoveries.next.progress + "%)" : "(NONE)"), + empireMenu.addButton("Discovery " + (discoveries != null ? "(" + discoveries.progress + "%)" : "(NONE)"), screen::discoveryMenu); // here present a new screen to choose policies diff --git a/core/src/com/galvarez/ttw/screens/overworld/OverworldScreen.java b/core/src/com/galvarez/ttw/screens/overworld/OverworldScreen.java index c9fcacf..1a7adec 100644 --- a/core/src/com/galvarez/ttw/screens/overworld/OverworldScreen.java +++ b/core/src/com/galvarez/ttw/screens/overworld/OverworldScreen.java @@ -58,6 +58,7 @@ import com.galvarez.ttw.rendering.map.MapRenderer; import com.galvarez.ttw.screens.AbstractScreen; import com.galvarez.ttw.screens.ArmiesMenuScreen; +import com.galvarez.ttw.screens.AskDiscoveryScreen; import com.galvarez.ttw.screens.DiplomacyMenuScreen; import com.galvarez.ttw.screens.DiscoveryMenuScreen; import com.galvarez.ttw.screens.PauseMenuScreen; @@ -148,6 +149,8 @@ public final class OverworldScreen extends AbstractScreen { private final DiscoveryMenuScreen discoveryScreen; + private final AskDiscoveryScreen askDiscoveryScreen; + private final PoliciesMenuScreen policiesScreen; private final ScoresMenuScreen scoresScreen; @@ -230,6 +233,7 @@ public OverworldScreen(ThingsThatWereGame game, SpriteBatch batch, World world, pauseScreen = new PauseMenuScreen(game, world, batch, this); diplomacyScreen = new DiplomacyMenuScreen(game, world, batch, this, empires, player, diplomaticSystem); discoveryScreen = new DiscoveryMenuScreen(game, world, batch, this, player, discoverySystem); + askDiscoveryScreen = new AskDiscoveryScreen(game, world, batch, this, player, discoverySystem); policiesScreen = new PoliciesMenuScreen(game, world, batch, this, player, policiesSystem, effectsSystem, revoltSystem); scoresScreen = new ScoresMenuScreen(game, world, batch, this, scoreSystem); @@ -338,7 +342,7 @@ private Entity createEmpire(String name, Empire empire) { if (map.isOnMap(p)) { Influence inf = map.getInfluenceAt(p); inf.setInfluence(entity, inf.getMaxInfluence()); - source.influencedTiles.add(p); + source.influencedTiles.add(p); } } log.info("Created {} for empire {}", name, empire); @@ -460,6 +464,10 @@ public void discoveryMenu() { game.setScreen(discoveryScreen); } + public void askDiscovery() { + game.setScreen(askDiscoveryScreen); + } + public void armiesMenu() { game.setScreen(armiesScreen); }