diff --git a/src/main/java/nomadrealms/context/game/GameState.java b/src/main/java/nomadrealms/context/game/GameState.java index b0a85c3a..e8425cff 100644 --- a/src/main/java/nomadrealms/context/game/GameState.java +++ b/src/main/java/nomadrealms/context/game/GameState.java @@ -56,6 +56,10 @@ public GameState(String name, Queue uiEventChannel, MapGenerationStr world = new World(this, mapGenerationStrategy); } + public World world() { + return world; + } + public void render(RenderingEnvironment re) { re.camera.update(); world.renderMap(re); diff --git a/src/main/java/nomadrealms/context/game/actor/HasTooltip.java b/src/main/java/nomadrealms/context/game/actor/HasTooltip.java index cd8311de..1d0efcc6 100644 --- a/src/main/java/nomadrealms/context/game/actor/HasTooltip.java +++ b/src/main/java/nomadrealms/context/game/actor/HasTooltip.java @@ -1,10 +1,9 @@ package nomadrealms.context.game.actor; -import nomadrealms.context.game.event.Target; import nomadrealms.render.ui.content.UIContent; import nomadrealms.render.ui.custom.tooltip.TooltipDeterminer; -public interface HasTooltip extends Target { +public interface HasTooltip { /** * Double dispatch method for creating the tooltip. diff --git a/src/main/java/nomadrealms/context/game/card/GameCard.java b/src/main/java/nomadrealms/context/game/card/GameCard.java index 99359604..b32d2eee 100644 --- a/src/main/java/nomadrealms/context/game/card/GameCard.java +++ b/src/main/java/nomadrealms/context/game/card/GameCard.java @@ -5,6 +5,7 @@ import static nomadrealms.context.game.card.target.TargetType.NONE; import nomadrealms.context.game.actor.structure.factory.StructureType; +import nomadrealms.context.game.card.condition.EmptyCondition; import nomadrealms.context.game.card.expression.AndExpression; import nomadrealms.context.game.card.expression.BuryAnySeedExpression; import nomadrealms.context.game.card.expression.CardExpression; @@ -21,16 +22,19 @@ import nomadrealms.context.game.card.expression.TeleportNoTargetExpression; import nomadrealms.context.game.card.query.actor.ActorsOnTilesQuery; import nomadrealms.context.game.card.query.actor.SelfQuery; +import nomadrealms.context.game.card.query.actor.TargetQuery; +import nomadrealms.context.game.card.query.actor.TargetTypeCast; import nomadrealms.context.game.card.query.card.LastResolvedCardQuery; import nomadrealms.context.game.card.query.tile.PreviousTileQuery; import nomadrealms.context.game.card.query.tile.TilesInRadiusQuery; import nomadrealms.context.game.card.target.TargetingInfo; +import nomadrealms.context.game.world.map.area.Tile; import nomadrealms.context.game.world.map.tile.factory.TileType; import nomadrealms.render.particle.spawner.ParticleSpawner; /** - * An enum of all the cards that can be played in the game. Each card has a - * title, description, expression, and targeting info. + * An enum of all the cards that can be played in the game. Each card has a title, description, expression, and + * targeting info. * * @author Lunkle */ @@ -41,7 +45,8 @@ public enum GameCard implements Card { "move", "Move to target hexagon", new MoveExpression(10), - new TargetingInfo(HEXAGON, 1)), + new TargetingInfo(HEXAGON, 1, + new EmptyCondition(new ActorsOnTilesQuery(new TargetTypeCast(new TargetQuery()))))), ATTACK( "Attack", "big_punch", @@ -53,7 +58,8 @@ public enum GameCard implements Card { "move", "Move to target hexagon.", new MoveExpression(10), - new TargetingInfo(HEXAGON, 2)), + new TargetingInfo(HEXAGON, 2, + new EmptyCondition(new ActorsOnTilesQuery(new TargetTypeCast(new TargetQuery()))))), UNSTABLE_TELEPORT( "Unstable Teleport", "teleport", @@ -130,7 +136,7 @@ public enum GameCard implements Card { private final TargetingInfo targetingInfo; private GameCard(String name, String artwork, String description, CardExpression expression, - TargetingInfo targetingInfo) { + TargetingInfo targetingInfo) { this.title = name; this.artwork = artwork; this.description = description; @@ -139,7 +145,7 @@ private GameCard(String name, String artwork, String description, CardExpression } private GameCard(String name, String artwork, String description, CardExpression expression, ParticleSpawner onResolve, - TargetingInfo targetingInfo) { + TargetingInfo targetingInfo) { this.title = name; this.artwork = artwork; this.description = description; diff --git a/src/main/java/nomadrealms/context/game/card/condition/Condition.java b/src/main/java/nomadrealms/context/game/card/condition/Condition.java new file mode 100644 index 00000000..1ff2bbb5 --- /dev/null +++ b/src/main/java/nomadrealms/context/game/card/condition/Condition.java @@ -0,0 +1,11 @@ +package nomadrealms.context.game.card.condition; + +import nomadrealms.context.game.actor.cardplayer.CardPlayer; +import nomadrealms.context.game.event.Target; +import nomadrealms.context.game.world.World; + +public interface Condition { + + public boolean test(World world, Target target, CardPlayer source); + +} diff --git a/src/main/java/nomadrealms/context/game/card/condition/EmptyCondition.java b/src/main/java/nomadrealms/context/game/card/condition/EmptyCondition.java new file mode 100644 index 00000000..1556f5f5 --- /dev/null +++ b/src/main/java/nomadrealms/context/game/card/condition/EmptyCondition.java @@ -0,0 +1,20 @@ +package nomadrealms.context.game.card.condition; + +import nomadrealms.context.game.actor.cardplayer.CardPlayer; +import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; +import nomadrealms.context.game.world.World; + +public class EmptyCondition implements Condition { + + private final Query query; + + public EmptyCondition(Query query) { + this.query = query; + } + + public boolean test(World world, Target target, CardPlayer source) { + return query.find(world, source, target).isEmpty(); + } + +} diff --git a/src/main/java/nomadrealms/context/game/card/condition/NotCondition.java b/src/main/java/nomadrealms/context/game/card/condition/NotCondition.java new file mode 100644 index 00000000..369fb095 --- /dev/null +++ b/src/main/java/nomadrealms/context/game/card/condition/NotCondition.java @@ -0,0 +1,19 @@ +package nomadrealms.context.game.card.condition; + +import nomadrealms.context.game.actor.cardplayer.CardPlayer; +import nomadrealms.context.game.event.Target; +import nomadrealms.context.game.world.World; + +public class NotCondition implements Condition { + + private final Condition condition; + + public NotCondition(Condition condition) { + this.condition = condition; + } + + public boolean test(World world, Target target, CardPlayer source) { + return !condition.test(world, target, source); + } + +} diff --git a/src/main/java/nomadrealms/context/game/card/expression/DamageActorsExpression.java b/src/main/java/nomadrealms/context/game/card/expression/DamageActorsExpression.java index 10ed88c9..e5247e86 100644 --- a/src/main/java/nomadrealms/context/game/card/expression/DamageActorsExpression.java +++ b/src/main/java/nomadrealms/context/game/card/expression/DamageActorsExpression.java @@ -23,7 +23,7 @@ public DamageActorsExpression(Query actors, int amount) { @Override public List effects(World world, Target target, CardPlayer source) { - List result = actors.find(world, source); + List result = actors.find(world, source, target); return result.stream() .map(actor -> new DamageEffect(actor, source, amount)) .collect(Collectors.toList()); diff --git a/src/main/java/nomadrealms/context/game/card/expression/SurfaceCardExpression.java b/src/main/java/nomadrealms/context/game/card/expression/SurfaceCardExpression.java index 9c648248..fb1c385f 100644 --- a/src/main/java/nomadrealms/context/game/card/expression/SurfaceCardExpression.java +++ b/src/main/java/nomadrealms/context/game/card/expression/SurfaceCardExpression.java @@ -24,7 +24,7 @@ public SurfaceCardExpression(Query query, int delay) { @Override public List effects(World world, Target target, CardPlayer source) { - List cards = query.find(world, source); + List cards = query.find(world, source, target); return singletonList(new SurfaceCardEffect(cards, source)); } diff --git a/src/main/java/nomadrealms/context/game/card/expression/TeleportNoTargetExpression.java b/src/main/java/nomadrealms/context/game/card/expression/TeleportNoTargetExpression.java index c63f7841..6d6b84c2 100644 --- a/src/main/java/nomadrealms/context/game/card/expression/TeleportNoTargetExpression.java +++ b/src/main/java/nomadrealms/context/game/card/expression/TeleportNoTargetExpression.java @@ -25,7 +25,7 @@ public TeleportNoTargetExpression(Query tile, int delay) { @Override public List effects(World world, Target target, CardPlayer source) { - List tiles = tile.find(world, source); + List tiles = tile.find(world, source, target); if (tiles.isEmpty()) { return emptyList(); } diff --git a/src/main/java/nomadrealms/context/game/card/query/Query.java b/src/main/java/nomadrealms/context/game/card/query/Query.java index c1ebdfce..1eeb8e61 100644 --- a/src/main/java/nomadrealms/context/game/card/query/Query.java +++ b/src/main/java/nomadrealms/context/game/card/query/Query.java @@ -3,6 +3,7 @@ import java.util.List; import nomadrealms.context.game.actor.cardplayer.CardPlayer; +import nomadrealms.context.game.event.Target; import nomadrealms.context.game.world.World; /** @@ -13,6 +14,6 @@ */ public interface Query { - public List find(World world, CardPlayer source); + public List find(World world, CardPlayer source, Target target); } diff --git a/src/main/java/nomadrealms/context/game/card/query/actor/ActorsOnTilesQuery.java b/src/main/java/nomadrealms/context/game/card/query/actor/ActorsOnTilesQuery.java index ddd43264..a6870dbc 100644 --- a/src/main/java/nomadrealms/context/game/card/query/actor/ActorsOnTilesQuery.java +++ b/src/main/java/nomadrealms/context/game/card/query/actor/ActorsOnTilesQuery.java @@ -3,11 +3,13 @@ import static java.util.stream.Collectors.toList; import java.util.List; +import java.util.Objects; import java.util.stream.Stream; import nomadrealms.context.game.actor.Actor; import nomadrealms.context.game.actor.cardplayer.CardPlayer; import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; import nomadrealms.context.game.world.World; import nomadrealms.context.game.world.map.area.Tile; @@ -26,13 +28,11 @@ public ActorsOnTilesQuery(Query tileQuery) { } @Override - public List find(World world, CardPlayer source) { - List tiles = tileQuery.find(world, source); - // TODO: Tiles need to store the actors on them for efficiency. Once we have that, we can optimize this. - Stream stream = world.actors.stream() - .filter(CardPlayer.class::isInstance) - .map(CardPlayer.class::cast) - .filter(actor -> tiles.contains(actor.tile())); + public List find(World world, CardPlayer source, Target target) { + List tiles = tileQuery.find(world, source, target); + Stream stream = tiles.stream() + .map(Tile::actor) + .filter(Objects::nonNull); if (excludeSource) { stream = stream.filter(actor -> actor != source); } diff --git a/src/main/java/nomadrealms/context/game/card/query/actor/SelfQuery.java b/src/main/java/nomadrealms/context/game/card/query/actor/SelfQuery.java index c315e0e5..5b8dd487 100644 --- a/src/main/java/nomadrealms/context/game/card/query/actor/SelfQuery.java +++ b/src/main/java/nomadrealms/context/game/card/query/actor/SelfQuery.java @@ -6,6 +6,7 @@ import nomadrealms.context.game.actor.cardplayer.CardPlayer; import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; import nomadrealms.context.game.world.World; /** @@ -17,7 +18,7 @@ public class SelfQuery implements Query { @Override - public List find(World world, CardPlayer source) { + public List find(World world, CardPlayer source, Target target) { return singletonList(source); } diff --git a/src/main/java/nomadrealms/context/game/card/query/actor/TargetQuery.java b/src/main/java/nomadrealms/context/game/card/query/actor/TargetQuery.java new file mode 100644 index 00000000..4a692e88 --- /dev/null +++ b/src/main/java/nomadrealms/context/game/card/query/actor/TargetQuery.java @@ -0,0 +1,25 @@ +package nomadrealms.context.game.card.query.actor; + +import static java.util.Collections.singletonList; + +import java.util.List; + +import nomadrealms.context.game.actor.cardplayer.CardPlayer; +import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; +import nomadrealms.context.game.world.World; + +/** + * A query expression that can be used by card expressions and intents to find {@link CardPlayer CardPlayers} in the + * game world. + * + * @author Lunkle + */ +public class TargetQuery implements Query { + + @Override + public List find(World world, CardPlayer source, Target target) { + return singletonList(target); + } + +} \ No newline at end of file diff --git a/src/main/java/nomadrealms/context/game/card/query/actor/TargetTypeCast.java b/src/main/java/nomadrealms/context/game/card/query/actor/TargetTypeCast.java new file mode 100644 index 00000000..5c40b3a1 --- /dev/null +++ b/src/main/java/nomadrealms/context/game/card/query/actor/TargetTypeCast.java @@ -0,0 +1,25 @@ +package nomadrealms.context.game.card.query.actor; + +import static java.util.stream.Collectors.toList; + +import java.util.List; + +import nomadrealms.context.game.actor.cardplayer.CardPlayer; +import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; +import nomadrealms.context.game.world.World; + +public class TargetTypeCast implements Query { + + private final Query query; + + public TargetTypeCast(Query query) { + this.query = query; + } + + @Override + public List find(World world, CardPlayer source, Target target) { + return query.find(world, source, target).stream().map(t -> (T) t).collect(toList()); + } + +} diff --git a/src/main/java/nomadrealms/context/game/card/query/card/LastResolvedCardQuery.java b/src/main/java/nomadrealms/context/game/card/query/card/LastResolvedCardQuery.java index fe58f119..4fcbada0 100644 --- a/src/main/java/nomadrealms/context/game/card/query/card/LastResolvedCardQuery.java +++ b/src/main/java/nomadrealms/context/game/card/query/card/LastResolvedCardQuery.java @@ -8,6 +8,7 @@ import nomadrealms.context.game.actor.cardplayer.CardPlayer; import nomadrealms.context.game.card.WorldCard; import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; import nomadrealms.context.game.world.World; /** @@ -25,8 +26,8 @@ public LastResolvedCardQuery(Query player) { } @Override - public List find(World world, CardPlayer source) { - return player.find(world, source).stream() + public List find(World world, CardPlayer source, Target target) { + return player.find(world, source, target).stream() .map(CardPlayer::lastResolvedCard) .filter(Objects::nonNull) .collect(toList()); diff --git a/src/main/java/nomadrealms/context/game/card/query/tile/PreviousTileQuery.java b/src/main/java/nomadrealms/context/game/card/query/tile/PreviousTileQuery.java index 2ffb4ed5..ddeef951 100644 --- a/src/main/java/nomadrealms/context/game/card/query/tile/PreviousTileQuery.java +++ b/src/main/java/nomadrealms/context/game/card/query/tile/PreviousTileQuery.java @@ -7,12 +7,12 @@ import nomadrealms.context.game.actor.cardplayer.CardPlayer; import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; import nomadrealms.context.game.world.World; import nomadrealms.context.game.world.map.area.Tile; /** - * A query expression that can be used by card expressions and intents to find {@link Tile Tiles} in the game - * world. + * A query expression that can be used by card expressions and intents to find {@link Tile Tiles} in the game world. * * @author Lunkle */ @@ -25,8 +25,8 @@ public PreviousTileQuery(Query player) { } @Override - public List find(World world, CardPlayer source) { - return player.find(world, source).stream() + public List find(World world, CardPlayer source, Target target) { + return player.find(world, source, target).stream() .map(CardPlayer::previousTile) .filter(Objects::nonNull) .collect(toList()); diff --git a/src/main/java/nomadrealms/context/game/card/query/tile/TilesInRadiusQuery.java b/src/main/java/nomadrealms/context/game/card/query/tile/TilesInRadiusQuery.java index 469c4a4d..3ebc4b55 100644 --- a/src/main/java/nomadrealms/context/game/card/query/tile/TilesInRadiusQuery.java +++ b/src/main/java/nomadrealms/context/game/card/query/tile/TilesInRadiusQuery.java @@ -11,6 +11,7 @@ import nomadrealms.context.game.actor.cardplayer.CardPlayer; import nomadrealms.context.game.card.query.Query; +import nomadrealms.context.game.event.Target; import nomadrealms.context.game.world.World; import nomadrealms.context.game.world.map.area.Tile; @@ -23,7 +24,7 @@ public TilesInRadiusQuery(int radius) { } @Override - public List find(World world, CardPlayer source) { + public List find(World world, CardPlayer source, Target target) { Tile startTile = source.tile(); if (startTile == null) { return emptyList(); diff --git a/src/main/java/nomadrealms/context/game/card/target/TargetingInfo.java b/src/main/java/nomadrealms/context/game/card/target/TargetingInfo.java index 94a25965..5711419c 100644 --- a/src/main/java/nomadrealms/context/game/card/target/TargetingInfo.java +++ b/src/main/java/nomadrealms/context/game/card/target/TargetingInfo.java @@ -1,13 +1,20 @@ package nomadrealms.context.game.card.target; +import java.util.Arrays; +import java.util.List; + +import nomadrealms.context.game.card.condition.Condition; + public class TargetingInfo { - private TargetType targetType; - private int range; + private final TargetType targetType; + private final int range; + private final List conditions; - public TargetingInfo(TargetType targetType, int range) { + public TargetingInfo(TargetType targetType, int range, Condition... conditions) { this.targetType = targetType; this.range = range; + this.conditions = Arrays.asList(conditions); } public TargetType targetType() { @@ -18,4 +25,8 @@ public int range() { return range; } + public List conditions() { + return conditions; + } + } diff --git a/src/main/java/nomadrealms/context/game/world/map/generation/overworld/structure/StructureGenerationStep.java b/src/main/java/nomadrealms/context/game/world/map/generation/overworld/structure/StructureGenerationStep.java index ef7fcd44..ef28563f 100644 --- a/src/main/java/nomadrealms/context/game/world/map/generation/overworld/structure/StructureGenerationStep.java +++ b/src/main/java/nomadrealms/context/game/world/map/generation/overworld/structure/StructureGenerationStep.java @@ -41,7 +41,6 @@ public StructureGenerationStep(Zone zone, MapGenerationStrategy strategy) { @Override public void generate(Zone[][] surrounding, MapGenerationStrategy strategy) { - System.out.println("Generating structures..."); for (ChunkCoordinate[] chunkRow : zone.coord().chunkCoordinates()) { for (ChunkCoordinate chunk : chunkRow) { for (TileCoordinate[] tileRow : chunk.tileCoordinates()) { diff --git a/src/main/java/nomadrealms/render/ui/custom/card/DeckTab.java b/src/main/java/nomadrealms/render/ui/custom/card/DeckTab.java index 724289e3..fd5118cb 100644 --- a/src/main/java/nomadrealms/render/ui/custom/card/DeckTab.java +++ b/src/main/java/nomadrealms/render/ui/custom/card/DeckTab.java @@ -129,7 +129,7 @@ private void addCallbacks(InputCallbackRegistry registry) { (event) -> { if (selectedCard != null) { if (selectedCard.position().x().get() < constraintBox.x().get() && (targetingArrow.target() == null ^ selectedCard.needsTarget())) { - owner.addNextPlay(new CardPlayedEvent(selectedCard.card(), owner, targetingArrow.target)); + owner.addNextPlay(new CardPlayedEvent(selectedCard.card(), owner, targetingArrow.target())); selectedCard.physics().pauseRestoration = true; } else { selectedCard.physics().targetTransform(selectedCardOriginalTransform); @@ -138,7 +138,7 @@ private void addCallbacks(InputCallbackRegistry registry) { } selectedCard = null; targetingArrow.origin(null); - targetingArrow.target = null; + targetingArrow.target(null); }); } diff --git a/src/main/java/nomadrealms/render/ui/custom/card/TargetingArrow.java b/src/main/java/nomadrealms/render/ui/custom/card/TargetingArrow.java index 4ff7701d..bbf2d3aa 100644 --- a/src/main/java/nomadrealms/render/ui/custom/card/TargetingArrow.java +++ b/src/main/java/nomadrealms/render/ui/custom/card/TargetingArrow.java @@ -14,10 +14,12 @@ import engine.visuals.lwjgl.GLContext; import engine.visuals.lwjgl.render.meta.DrawFunction; import nomadrealms.context.game.GameState; +import nomadrealms.context.game.actor.cardplayer.CardPlayer; import nomadrealms.context.game.card.UICard; import nomadrealms.context.game.card.target.TargetType; import nomadrealms.context.game.card.target.TargetingInfo; import nomadrealms.context.game.event.Target; +import nomadrealms.context.game.world.World; import nomadrealms.context.game.world.map.area.Tile; import nomadrealms.render.RenderingEnvironment; import nomadrealms.render.ui.UI; @@ -25,10 +27,10 @@ public class TargetingArrow implements UI { - UICard origin; - Mouse mouse; - TargetingInfo info; - Target target; + private UICard origin; + private Mouse mouse; + private TargetingInfo info; + private Target target; GameState state; @@ -46,7 +48,7 @@ public void render(RenderingEnvironment re) { if (info.targetType() == TargetType.HEXAGON) { target = tile; - if (target == null) { + if (!checkConditions(info, state.world(), target, state.world().nomad)) { return; } re.defaultShaderProgram @@ -63,7 +65,7 @@ public void render(RenderingEnvironment re) { } if (info.targetType() == TargetType.CARD_PLAYER) { target = tile.actor(); - if (target == null) { + if (target == null || !checkConditions(info, state.world(), target, state.world().nomad)) { return; } re.defaultShaderProgram @@ -87,6 +89,20 @@ public void render(RenderingEnvironment re) { ); } + private boolean checkConditions(TargetingInfo info, World world, Target target, CardPlayer source) { + return info.conditions().stream().allMatch(c -> c.test(world, target, source)); + } + + private Matrix4f lineTransform(GLContext glContext, Vector2f point1, Vector2f point2) { + float angle = (float) Math.atan2(point2.y() - point1.y(), point2.x() - point1.x()); + return screenToPixel(glContext) + .translate(point1.x(), point1.y()) + .scale(new Vector3f(1, 1, 0f)) // Flatten the z-axis to avoid clipping + .rotate(angle, new Vector3f(0, 0, 1)) + .translate(0, -5, 0) + .scale(point1.sub(point2).length(), 3); + } + public TargetingArrow origin(UICard origin) { this.origin = origin; return this; @@ -108,17 +124,12 @@ public TargetingArrow info(TargetingInfo targetingInfo) { return this; } - private Matrix4f lineTransform(GLContext glContext, Vector2f point1, Vector2f point2) { - float angle = (float) Math.atan2(point2.y() - point1.y(), point2.x() - point1.x()); - return screenToPixel(glContext) - .translate(point1.x(), point1.y()) - .scale(new Vector3f(1, 1, 0f)) // Flatten the z-axis to avoid clipping - .rotate(angle, new Vector3f(0, 0, 1)) - .translate(0, -5, 0) - .scale(point1.sub(point2).length(), 3); - } - public Target target() { return target; } + + public void target(Target target) { + this.target = target; + } + }