From a8deeecd08a9a5609e790403cb2fc175c4d075ae Mon Sep 17 00:00:00 2001 From: Retera Date: Sat, 12 Jun 2021 11:33:55 -0400 Subject: [PATCH] Working towards multi unit select --- .../warsmash/util/WarsmashConstants.java | 1 + .../viewer5/handlers/w3x/ui/MeleeUI.java | 182 ++++++++++++------ 2 files changed, 124 insertions(+), 59 deletions(-) diff --git a/core/src/com/etheller/warsmash/util/WarsmashConstants.java b/core/src/com/etheller/warsmash/util/WarsmashConstants.java index 6b2e4ab..a00848b 100644 --- a/core/src/com/etheller/warsmash/util/WarsmashConstants.java +++ b/core/src/com/etheller/warsmash/util/WarsmashConstants.java @@ -12,6 +12,7 @@ public class WarsmashConstants { public static final int PORT_NUMBER = 6115; public static final float BUILDING_CONSTRUCT_START_LIFE = 0.1f; public static final int BUILD_QUEUE_SIZE = 7; + public static final int MAX_SELECTION_SIZE = 12; // It looks like in Patch 1.22, "Particle" in video settings will change this // factor: // Low - unknown ? diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java index 4cb0d2d..9b36d00 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/ui/MeleeUI.java @@ -215,6 +215,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma private SimpleStatusBarFrame simpleBuildingBuildTimeIndicator; private final QueueIcon[] queueIconFrames = new QueueIcon[WarsmashConstants.BUILD_QUEUE_SIZE]; private QueueIcon selectWorkerInsideFrame; + private final QueueIcon[] selectedUnitFrames = new QueueIcon[WarsmashConstants.MAX_SELECTION_SIZE]; private UIFrame attack1Icon; private TextureFrame attack1IconBackdrop; @@ -286,7 +287,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma private MeleeUIAbilityActivationReceiver meleeUIAbilityActivationReceiver; private MdxModel waypointModel; private final List waypointModelInstances = new ArrayList<>(); - private List selectedUnits; + private List selectedUnits = Collections.emptyList(); private Set dragSelectPreviewUnits = new HashSet<>(); private Set dragSelectPreviewUnitsUpcoming = new HashSet<>(); private BitmapFont textTagFont; @@ -690,7 +691,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } this.selectWorkerInsideFrame = new QueueIcon("SmashBuildQueueWorkerIcon", this.smashSimpleInfoPanel, this, 1); final TextureFrame selectWorkerInsideIconFrameBackdrop = new TextureFrame("SmashBuildQueueWorkerIconBackdrop", - this.queueIconFrames[0], false, new Vector4Definition(0, 1, 0, 1)); + this.selectWorkerInsideFrame, false, new Vector4Definition(0, 1, 0, 1)); this.selectWorkerInsideFrame.set(selectWorkerInsideIconFrameBackdrop); selectWorkerInsideIconFrameBackdrop .addSetPoint(new SetPoint(FramePoint.CENTER, this.selectWorkerInsideFrame, FramePoint.CENTER, 0, 0)); @@ -702,6 +703,28 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma selectWorkerInsideIconFrameBackdrop.setHeight(frontQueueIconWidth); this.rootFrame.add(this.selectWorkerInsideFrame); + for (int i = 0; i < this.selectedUnitFrames.length; i++) { + this.selectedUnitFrames[i] = new QueueIcon("SmashMultiSelectUnitIcon", this.smashSimpleInfoPanel, this, i); + final TextureFrame multiSelectUnitIconFrameBackdrop = new TextureFrame("SmashMultiSelectUnitIconBackdrop", + this.selectedUnitFrames[i], false, new Vector4Definition(0, 1, 0, 1)); + final TextureFrame selectedSubgroupHighlightBackdrop = new TextureFrame("SmashMultiSelectUnitIconBackdrop", + this.selectedUnitFrames[i], false, new Vector4Definition(0, 1, 0, 1)); + this.selectedUnitFrames[i].set(multiSelectUnitIconFrameBackdrop); + multiSelectUnitIconFrameBackdrop + .addSetPoint(new SetPoint(FramePoint.CENTER, this.selectedUnitFrames[i], FramePoint.CENTER, 0, 0)); + final int halfSelectionMaxSize = this.selectedUnitFrames.length / 2; + this.selectedUnitFrames[i] + .addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.smashSimpleInfoPanel, FramePoint.TOPLEFT, + (frontQueueIconWidth * .10f) + (frontQueueIconWidth * 1.10f * (i % halfSelectionMaxSize)), + (frontQueueIconWidth * -.5f) - (frontQueueIconWidth * 1.5f * (i / halfSelectionMaxSize)))); + this.selectedUnitFrames[i].setWidth(frontQueueIconWidth); + this.selectedUnitFrames[i].setHeight(frontQueueIconWidth); + multiSelectUnitIconFrameBackdrop.setWidth(frontQueueIconWidth); + multiSelectUnitIconFrameBackdrop.setHeight(frontQueueIconWidth); + this.rootFrame.add(this.selectedUnitFrames[i]); + this.selectedUnitFrames[i].setVisible(false); + } + this.smashAttack1IconWrapper = (SimpleFrame) this.rootFrame.createSimpleFrame("SmashSimpleInfoPanelIconDamage", this.simpleInfoPanelUnitDetail, 0); this.smashAttack1IconWrapper.addSetPoint(new SetPoint(FramePoint.TOPLEFT, this.simpleInfoPanelUnitDetail, @@ -1823,6 +1846,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma this.rallyPointInstance.detach(); this.inventoryCover.setVisible(true); this.inventoryBarFrame.setVisible(false); + for (final QueueIcon iconFrame : this.selectedUnitFrames) { + iconFrame.setVisible(false); + } repositionWaypointFlags(null); } else { @@ -1943,8 +1969,14 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma else { this.rootFrame.setText(this.unitManaText, ""); } + final boolean multiSelect = this.selectedUnits.size() > 1; repositionRallyPoint(simulationUnit); repositionWaypointFlags(simulationUnit); + if (!multiSelect) { + for (int i = 0; i < this.selectedUnitFrames.length; i++) { + this.selectedUnitFrames[i].setVisible(false); + } + } if ((simulationUnit.getBuildQueue()[0] != null) && (simulationUnit.getPlayerIndex() == this.war3MapViewer.getLocalPlayerIndex())) { for (int i = 0; i < this.queueIconFrames.length; i++) { @@ -1973,7 +2005,7 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } } } - this.simpleInfoPanelBuildingDetail.setVisible(true); + this.simpleInfoPanelBuildingDetail.setVisible(!multiSelect); this.simpleInfoPanelUnitDetail.setVisible(false); this.rootFrame.setText(this.simpleBuildingNameValue, simulationUnit.getUnitType().getName()); this.rootFrame.setText(this.simpleBuildingDescriptionValue, ""); @@ -1995,12 +2027,35 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma this.heroInfoPanel.setVisible(false); this.selectWorkerInsideFrame.setVisible(false); } + else if (multiSelect) { + for (int i = 0; i < this.selectedUnitFrames.length; i++) { + final boolean useIcon = i < this.selectedUnits.size(); + this.selectedUnitFrames[i].setVisible(useIcon); + if (useIcon) { + final CUnitType unitType = this.selectedUnits.get(i).getSimulationUnit().getUnitType(); + final IconUI unitUI = this.war3MapViewer.getAbilityDataUI().getUnitUI(unitType.getTypeId()); + this.selectedUnitFrames[i].setTexture(unitUI.getIcon()); + this.selectedUnitFrames[i].setToolTip(unitUI.getToolTip()); + this.selectedUnitFrames[i].setUberTip(unitUI.getUberTip()); + } + } + this.simpleInfoPanelBuildingDetail.setVisible(false); + this.simpleInfoPanelUnitDetail.setVisible(false); + this.simpleBuildingBuildTimeIndicator.setVisible(false); + this.simpleBuildTimeIndicator.setVisible(false); + this.simpleHeroLevelBar.setVisible(false); + this.attack1Icon.setVisible(false); + this.attack2Icon.setVisible(false); + this.armorIcon.setVisible(false); + this.heroInfoPanel.setVisible(false); + this.selectWorkerInsideFrame.setVisible(false); + } else { for (final QueueIcon queueIconFrame : this.queueIconFrames) { queueIconFrame.setVisible(false); } this.simpleInfoPanelBuildingDetail.setVisible(false); - this.simpleInfoPanelUnitDetail.setVisible(true); + this.simpleInfoPanelUnitDetail.setVisible(!multiSelect); final String unitTypeName = simulationUnit.getUnitType().getName(); final boolean anyAttacks = simulationUnit.getAttacks().size() > 0; @@ -2106,59 +2161,6 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } this.simpleHeroLevelBar.setVisible(false); } - final CAbilityInventory inventory = simulationUnit.getInventoryData(); - this.inventoryCover.setVisible(inventory == null); - if (inventory != null) { - this.inventoryBarFrame.setVisible(true); - int index = 0; - for (int i = 0; i < INVENTORY_HEIGHT; i++) { - for (int j = 0; j < INVENTORY_WIDTH; j++) { - final CommandCardIcon inventoryIcon = this.inventoryIcons[i][j]; - final CItem item = inventory.getItemInSlot(index); - if (item != null) { - final ItemUI itemUI = this.war3MapViewer.getAbilityDataUI().getItemUI(item.getTypeId()); - final IconUI iconUI = itemUI.getIconUI(); - final CItemType itemType = item.getItemType(); - // TODO: below we set menu=false, this is bad, item should be based on item abil - final boolean activelyUsed = itemType.isActivelyUsed(); - final boolean pawnable = itemType.isPawnable(); - final String uberTip = iconUI.getUberTip(); - this.recycleStringBuilder.setLength(0); - if (pawnable) { - this.recycleStringBuilder - .append(this.rootFrame.getTemplates().getDecoratedString("ITEM_PAWN_TOOLTIP")); - this.recycleStringBuilder.append("|n"); - } - if (activelyUsed) { - this.recycleStringBuilder - .append(this.rootFrame.getTemplates().getDecoratedString("ITEM_USE_TOOLTIP")); - this.recycleStringBuilder.append("|n"); - } - this.recycleStringBuilder.append(uberTip); - inventoryIcon.setCommandButtonData(iconUI.getIcon(), 0, - activelyUsed ? itemType.getCooldownGroup().getValue() : 0, index + 1, activelyUsed, - false, false, itemUI.getName(), this.recycleStringBuilder.toString(), - itemType.getGoldCost(), itemType.getLumberCost(), 0); - } - else { - if (index >= inventory.getItemCapacity()) { - inventoryIcon.setCommandButtonData(this.consoleInventoryNoCapacityTexture, 0, 0, 0, - false, false, false, null, null, 0, 0, 0); - } - else { - if (this.draggingItem != null) { - inventoryIcon.setCommandButtonData(null, 0, 0, index + 1, true, false, false, null, - null, 0, 0, 0); - } - else { - inventoryIcon.clear(); - } - } - } - index++; - } - } - } localArmorIcon.setVisible(!constructing); this.simpleBuildTimeIndicator.setVisible(constructing); @@ -2208,6 +2210,59 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } this.rootFrame.setText(localArmorInfoPanelIconValue, defenseDisplayString); } + final CAbilityInventory inventory = simulationUnit.getInventoryData(); + this.inventoryCover.setVisible(inventory == null); + if (inventory != null) { + this.inventoryBarFrame.setVisible(true); + int index = 0; + for (int i = 0; i < INVENTORY_HEIGHT; i++) { + for (int j = 0; j < INVENTORY_WIDTH; j++) { + final CommandCardIcon inventoryIcon = this.inventoryIcons[i][j]; + final CItem item = inventory.getItemInSlot(index); + if (item != null) { + final ItemUI itemUI = this.war3MapViewer.getAbilityDataUI().getItemUI(item.getTypeId()); + final IconUI iconUI = itemUI.getIconUI(); + final CItemType itemType = item.getItemType(); + // TODO: below we set menu=false, this is bad, item should be based on item abil + final boolean activelyUsed = itemType.isActivelyUsed(); + final boolean pawnable = itemType.isPawnable(); + final String uberTip = iconUI.getUberTip(); + this.recycleStringBuilder.setLength(0); + if (pawnable) { + this.recycleStringBuilder + .append(this.rootFrame.getTemplates().getDecoratedString("ITEM_PAWN_TOOLTIP")); + this.recycleStringBuilder.append("|n"); + } + if (activelyUsed) { + this.recycleStringBuilder + .append(this.rootFrame.getTemplates().getDecoratedString("ITEM_USE_TOOLTIP")); + this.recycleStringBuilder.append("|n"); + } + this.recycleStringBuilder.append(uberTip); + inventoryIcon.setCommandButtonData(iconUI.getIcon(), 0, + activelyUsed ? itemType.getCooldownGroup().getValue() : 0, index + 1, activelyUsed, + false, false, itemUI.getName(), this.recycleStringBuilder.toString(), + itemType.getGoldCost(), itemType.getLumberCost(), 0); + } + else { + if (index >= inventory.getItemCapacity()) { + inventoryIcon.setCommandButtonData(this.consoleInventoryNoCapacityTexture, 0, 0, 0, false, + false, false, null, null, 0, 0, 0); + } + else { + if (this.draggingItem != null) { + inventoryIcon.setCommandButtonData(null, 0, 0, index + 1, true, false, false, null, + null, 0, 0, 0); + } + else { + inventoryIcon.clear(); + } + } + } + index++; + } + } + } clearAndRepopulateCommandCard(); } @@ -2317,7 +2372,9 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma @Override public void lifeChanged() { if (this.selectedUnit.getSimulationUnit().isDead()) { - final List newSelection = Arrays.asList(this.selectedUnit.getPreferredSelectionReplacement()); + final RenderUnit preferredSelectionReplacement = this.selectedUnit.getPreferredSelectionReplacement(); + final List newSelection = preferredSelectionReplacement == null ? Collections.emptyList() + : Arrays.asList(preferredSelectionReplacement); selectWidgets(newSelection); this.war3MapViewer.doSelectUnit(newSelection); } @@ -2676,10 +2733,17 @@ public class MeleeUI implements CUnitStateListener, CommandButtonListener, Comma } private void selectUnits(final List selectedUnits) { + final List prevSelectedUnits = this.selectedUnits; this.selectedUnits = selectedUnits; if (!selectedUnits.isEmpty()) { final RenderUnit unit = selectedUnits.get(0); - final boolean selectionChanged = getSelectedUnit() != unit; + boolean selectionChanged = (unit != this.selectedUnit) + || (prevSelectedUnits.size() != selectedUnits.size()); + for (int i = 0; (i < prevSelectedUnits.size()) && (i < selectedUnits.size()); i++) { + if (prevSelectedUnits.get(i) != selectedUnits.get(i)) { + selectionChanged = true; + } + } boolean playedNewSound = false; if (selectionChanged) { this.selectedSoundCount = 0;