From f10b112161e2ef92aa77fcd144cefa3b09198a2a Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 17 Feb 2022 11:47:42 -0500 Subject: [PATCH] v1.2.0: added right click menu functionality to the game environment --- .../scenes/CellSelector.java | 32 ++-- .../scenes/GameScene.java | 178 ++++++++++++++---- .../ui/RightClickMenu.java | 5 + .../windows/WndInfoCell.java | 87 ++++++--- 4 files changed, 230 insertions(+), 72 deletions(-) diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java index 17c3c265f..bc41453ab 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/CellSelector.java @@ -90,7 +90,7 @@ public class CellSelector extends ScrollArea { if (Dungeon.hero.sprite != null && Dungeon.hero.sprite.overlapsPoint( p.x, p.y )){ PointF c = DungeonTilemap.tileCenterToWorld(Dungeon.hero.pos); if (Math.abs(p.x - c.x) <= 12 && Math.abs(p.y - c.y) <= 12) { - select(Dungeon.hero.pos); + select(Dungeon.hero.pos, event.button); return; } } @@ -100,7 +100,7 @@ public class CellSelector extends ScrollArea { if (mob.sprite != null && mob.sprite.overlapsPoint( p.x, p.y )){ PointF c = DungeonTilemap.tileCenterToWorld(mob.pos); if (Math.abs(p.x - c.x) <= 12 && Math.abs(p.y - c.y) <= 12) { - select(mob.pos); + select(mob.pos, event.button); return; } } @@ -111,7 +111,7 @@ public class CellSelector extends ScrollArea { if (heap.sprite != null && heap.sprite.overlapsPoint( p.x, p.y)){ PointF c = DungeonTilemap.tileCenterToWorld(heap.pos); if (Math.abs(p.x - c.x) <= 12 && Math.abs(p.y - c.y) <= 12) { - select(heap.pos); + select(heap.pos, event.button); return; } } @@ -120,7 +120,7 @@ public class CellSelector extends ScrollArea { select( ((DungeonTilemap)target).screenToTile( (int) event.current.x, (int) event.current.y, - true ) ); + true ), event.button ); } } @@ -142,11 +142,18 @@ public class CellSelector extends ScrollArea { return value; } - public void select( int cell ) { + public void select( int cell, int button ) { if (enabled && Dungeon.hero.ready && !GameScene.InterfaceBlockingHero() && listener != null && cell != -1) { - - listener.onSelect( cell ); + + switch (button){ + default: + listener.onSelect( cell ); + break; + case PointerEvent.RIGHT: + listener.onRightClick( cell ); + break; + } GameScene.ready(); } else { @@ -285,7 +292,7 @@ public class CellSelector extends ScrollArea { // this is to make it easier to move 1 or 2 steps without overshooting CharSprite.setMoveInterval( CharSprite.DEFAULT_MOVE_INTERVAL + Math.max(0, 0.05f - heldTurns *0.025f)); - select(cell); + select(cell, PointerEvent.LEFT); return true; } else { @@ -342,8 +349,11 @@ public class CellSelector extends ScrollArea { KeyEvent.removeKeyListener( keyListener ); } - public interface Listener { - void onSelect( Integer cell ); - String prompt(); + public static abstract class Listener { + public abstract void onSelect( Integer cell ); + + public void onRightClick( Integer cell ){} //do nothing by default + + public abstract String prompt(); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java index f38ab9aea..2624052d5 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/scenes/GameScene.java @@ -33,6 +33,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.Char; import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ChampionEnemy; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DemonSpawner; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; @@ -87,6 +88,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.LootIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.MenuPane; import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton; import com.shatteredpixel.shatteredpixeldungeon.ui.ResumeIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.RightClickMenu; import com.shatteredpixel.shatteredpixeldungeon.ui.StatusPane; import com.shatteredpixel.shatteredpixeldungeon.ui.Tag; import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator; @@ -107,10 +109,12 @@ import com.shatteredpixel.shatteredpixeldungeon.windows.WndOptions; import com.shatteredpixel.shatteredpixeldungeon.windows.WndResurrect; import com.shatteredpixel.shatteredpixeldungeon.windows.WndStory; import com.watabou.glwrap.Blending; +import com.watabou.input.PointerEvent; import com.watabou.noosa.Camera; import com.watabou.noosa.Game; import com.watabou.noosa.Gizmo; import com.watabou.noosa.Group; +import com.watabou.noosa.Image; import com.watabou.noosa.NoosaScript; import com.watabou.noosa.NoosaScriptNoLighting; import com.watabou.noosa.SkinnedBlock; @@ -121,6 +125,7 @@ import com.watabou.noosa.particles.Emitter; import com.watabou.utils.DeviceCompat; import com.watabou.utils.GameMath; import com.watabou.utils.Point; +import com.watabou.utils.PointF; import com.watabou.utils.Random; import com.watabou.utils.RectF; @@ -1194,7 +1199,7 @@ public class GameScene extends PixelScene { } public static void handleCell( int cell ) { - cellSelector.select( cell ); + cellSelector.select( cell, PointerEvent.LEFT ); } public static void selectCell( CellSelector.Listener listener ) { @@ -1272,49 +1277,19 @@ public class GameScene extends PixelScene { return; } - ArrayList names = new ArrayList<>(); - final ArrayList objects = new ArrayList<>(); - - if (cell == Dungeon.hero.pos) { - objects.add(Dungeon.hero); - names.add(Dungeon.hero.className().toUpperCase(Locale.ENGLISH)); - } else { - if (Dungeon.level.heroFOV[cell]) { - Mob mob = (Mob) Actor.findChar(cell); - if (mob != null) { - objects.add(mob); - names.add(Messages.titleCase( mob.name() )); - } - } - } - - Heap heap = Dungeon.level.heaps.get(cell); - if (heap != null && heap.seen) { - objects.add(heap); - names.add(Messages.titleCase( heap.toString() )); - } - - Plant plant = Dungeon.level.plants.get( cell ); - if (plant != null) { - objects.add(plant); - names.add(Messages.titleCase( plant.plantName )); - } - - Trap trap = Dungeon.level.traps.get( cell ); - if (trap != null && trap.visible) { - objects.add(trap); - names.add(Messages.titleCase( trap.name() )); - } + ArrayList objects = getObjectsAtCell(cell); if (objects.isEmpty()) { GameScene.show(new WndInfoCell(cell)); } else if (objects.size() == 1){ examineObject(objects.get(0)); } else { + String[] names = getObjectNames(objects).toArray(new String[0]); + GameScene.show(new WndOptions(Icons.get(Icons.INFO), Messages.get(GameScene.class, "choose_examine"), Messages.get(GameScene.class, "multiple_examine"), - names.toArray(new String[names.size()])){ + names){ @Override protected void onSelect(int index) { examineObject(objects.get(index)); @@ -1324,6 +1299,41 @@ public class GameScene extends PixelScene { } } + private static ArrayList getObjectsAtCell( int cell ){ + ArrayList objects = new ArrayList<>(); + + if (cell == Dungeon.hero.pos) { + objects.add(Dungeon.hero); + + } else if (Dungeon.level.heroFOV[cell]) { + Mob mob = (Mob) Actor.findChar(cell); + if (mob != null) objects.add(mob); + } + + Heap heap = Dungeon.level.heaps.get(cell); + if (heap != null && heap.seen) objects.add(heap); + + Plant plant = Dungeon.level.plants.get( cell ); + if (plant != null) objects.add(plant); + + Trap trap = Dungeon.level.traps.get( cell ); + if (trap != null && trap.visible) objects.add(trap); + + return objects; + } + + private static ArrayList getObjectNames( ArrayList objects ){ + ArrayList names = new ArrayList<>(); + for (Object obj : objects){ + if (obj instanceof Hero) names.add(((Hero) obj).className().toUpperCase(Locale.ENGLISH)); + else if (obj instanceof Mob) names.add(Messages.titleCase( ((Mob)obj).name() )); + else if (obj instanceof Heap) names.add(Messages.titleCase( ((Heap)obj).toString() )); + else if (obj instanceof Plant) names.add(Messages.titleCase( ((Plant) obj).plantName )); + else if (obj instanceof Trap) names.add(Messages.titleCase( ((Trap) obj).name() )); + } + return names; + } + public static void examineObject(Object o){ if (o == Dungeon.hero){ GameScene.show( new WndHero() ); @@ -1352,6 +1362,104 @@ public class GameScene extends PixelScene { Dungeon.hero.next(); } } + + @Override + public void onRightClick(Integer cell) { + if (cell == null + || cell < 0 + || cell > Dungeon.level.length() + || (!Dungeon.level.visited[cell] && !Dungeon.level.mapped[cell])) { + return; + } + + ArrayList objects = getObjectsAtCell(cell); + ArrayList textLines = getObjectNames(objects); + + //determine title and image + String title = null; + Image image = null; + if (objects.isEmpty()) { + title = WndInfoCell.cellName(cell); + image = WndInfoCell.cellImage(cell); + } else if (objects.size() > 1){ + title = "Multiple Objects"; + image = Icons.get(Icons.INFO); + } else if (objects.get(0) instanceof Mob) { + title = textLines.remove(0); + image = new Image(((Mob) objects.get(0)).sprite); + } else if (objects.get(0) instanceof Heap) { + title = textLines.remove(0); + image = new ItemSprite((Heap) objects.get(0)); + } else if (objects.get(0) instanceof Plant) { + title = textLines.remove(0); + image = TerrainFeaturesTilemap.tile(cell, Dungeon.level.map[cell]); + } else if (objects.get(0) instanceof Trap) { + title = textLines.remove(0); + image = TerrainFeaturesTilemap.tile(cell, Dungeon.level.map[cell]); + } + + //determine first text line + if (objects.isEmpty()) { + textLines.add(0, "Go Here"); + } else if (objects.get(0) instanceof Mob) { + if (((Mob) objects.get(0)).alignment != Char.Alignment.ENEMY) { + textLines.add(0, "Interact"); + } else { + textLines.add(0, "Attack"); + } + } else if (objects.get(0) instanceof Heap) { + switch (((Heap) objects.get(0)).type) { + case HEAP: + textLines.add(0, "Pick Up"); + break; + case FOR_SALE: + textLines.add(0, "Purchase"); + break; + default: + textLines.add(0, "Interact"); + break; + } + } else if (objects.get(0) instanceof Plant) { + textLines.add(0, "Trample"); + } else if (objects.get(0) instanceof Trap) { + textLines.add(0, "Interact"); + } + + //final text formatting + if (objects.size() > 1){ + textLines.add(0, "_" + textLines.remove(0) + ":_ " + textLines.get(0)); + for (int i = 1; i < textLines.size(); i++){ + textLines.add(i, "_Examine:_ " + textLines.remove(i)); + } + } else { + textLines.add(0, "_" + textLines.remove(0) + "_"); + textLines.add(1, "_Examine_"); + } + + RightClickMenu menu = new RightClickMenu(image, + title, + textLines.toArray(new String[0])){ + @Override + public void onSelect(int index) { + if (index == 0){ + handleCell(cell); + } else { + if (objects.size() == 0){ + GameScene.show(new WndInfoCell(cell)); + } else { + examineObject(objects.get(index-1)); + } + } + } + }; + scene.addToFront(menu); + menu.camera = PixelScene.uiCamera; + PointF mousePos = PointerEvent.currentHoverPos(); + mousePos = menu.camera.screenToCamera((int)mousePos.x, (int)mousePos.y); + menu.setPos(mousePos.x-3, mousePos.y-3); + + } + @Override public String prompt() { return null; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RightClickMenu.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RightClickMenu.java index 8d344de2f..681592c6e 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RightClickMenu.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/RightClickMenu.java @@ -126,6 +126,11 @@ public class RightClickMenu extends Component { height += 13*buttons.length; width = icon.width + 2 + titleText.width()+bg.marginVer(); + for (RedButton button : buttons){ + if (width < button.reqWidth()+bg.marginHor()){ + width = button.reqWidth()+bg.marginHor(); + } + } if (x + width > (camera.width + camera.scroll.x)){ x -= (x + width - (camera.width + camera.scroll.x)); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoCell.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoCell.java index b72a9e759..91e01d207 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoCell.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndInfoCell.java @@ -38,11 +38,8 @@ public class WndInfoCell extends Window { private static final float GAP = 2; private static final int WIDTH = 120; - - public WndInfoCell( int cell ) { - - super(); - + + public static Image cellImage( int cell ){ int tile = Dungeon.level.map[cell]; if (Dungeon.level.water[cell]) { tile = Terrain.WATER; @@ -50,7 +47,6 @@ public class WndInfoCell extends Window { tile = Terrain.CHASM; } - CustomTilemap customTile = null; Image customImage = null; int x = cell % Dungeon.level.width(); int y = cell / Dungeon.level.width(); @@ -58,6 +54,60 @@ public class WndInfoCell extends Window { if ((x >= i.tileX && x < i.tileX+i.tileW) && (y >= i.tileY && y < i.tileY+i.tileH)){ if ((customImage = i.image(x - i.tileX, y - i.tileY)) != null) { + break; + } + } + } + + if (customImage != null){ + return customImage; + } else { + + if (tile == Terrain.WATER) { + Image water = new Image(Dungeon.level.waterTex()); + water.frame(0, 0, DungeonTilemap.SIZE, DungeonTilemap.SIZE); + return water; + } else { + return DungeonTerrainTilemap.tile(cell, tile); + } + } + } + + public static String cellName( int cell ){ + + CustomTilemap customTile = null; + int x = cell % Dungeon.level.width(); + int y = cell / Dungeon.level.width(); + for (CustomTilemap i : Dungeon.level.customTiles){ + if ((x >= i.tileX && x < i.tileX+i.tileW) && + (y >= i.tileY && y < i.tileY+i.tileH)){ + if (i.image(x - i.tileX, y - i.tileY) != null) { + x -= i.tileX; + y -= i.tileY; + customTile = i; + break; + } + } + } + + if (customTile != null && customTile.name(x, y) != null){ + return customTile.name(x, y); + } else { + return Dungeon.level.tileName(Dungeon.level.map[cell]); + } + } + + public WndInfoCell( int cell ) { + + super(); + + CustomTilemap customTile = null; + int x = cell % Dungeon.level.width(); + int y = cell / Dungeon.level.width(); + for (CustomTilemap i : Dungeon.level.customTiles){ + if ((x >= i.tileX && x < i.tileX+i.tileW) && + (y >= i.tileY && y < i.tileY+i.tileH)){ + if (i.image(x - i.tileX, y - i.tileY) != null) { x -= i.tileX; y -= i.tileY; customTile = i; @@ -70,35 +120,20 @@ public class WndInfoCell extends Window { String desc = ""; IconTitle titlebar = new IconTitle(); + titlebar.icon(cellImage(cell)); + titlebar.label(cellName(cell)); + if (customTile != null){ - titlebar.icon(customImage); - - String customName = customTile.name(x, y); - if (customName != null) { - titlebar.label(customName); - } else { - titlebar.label(Dungeon.level.tileName(tile)); - } - String customDesc = customTile.desc(x, y); if (customDesc != null) { desc += customDesc; } else { - desc += Dungeon.level.tileDesc(tile); + desc += Dungeon.level.tileDesc(Dungeon.level.map[cell]); } } else { - if (tile == Terrain.WATER) { - Image water = new Image(Dungeon.level.waterTex()); - water.frame(0, 0, DungeonTilemap.SIZE, DungeonTilemap.SIZE); - titlebar.icon(water); - } else { - titlebar.icon(DungeonTerrainTilemap.tile( cell, tile )); - } - titlebar.label(Dungeon.level.tileName(tile)); - desc += Dungeon.level.tileDesc(tile); - + desc += Dungeon.level.tileDesc(Dungeon.level.map[cell]); } titlebar.setRect(0, 0, WIDTH, 0); add(titlebar);