Unit control mode
This commit is contained in:
@@ -115,49 +115,53 @@ public class DesktopInput extends InputHandler{
|
||||
drawSelection(schemX, schemY, cursorX, cursorY, Vars.maxSchematicSize);
|
||||
}
|
||||
|
||||
//draw command overlay UI
|
||||
if(commandMode){
|
||||
|
||||
for(Unit unit : selectedUnits){
|
||||
CommandAI ai = (CommandAI)unit.controller();
|
||||
//draw target line
|
||||
if(ai.targetPos != null){
|
||||
Position lineDest = ai.attackTarget != null ? ai.attackTarget : ai.targetPos;
|
||||
//draw command overlay UI
|
||||
|
||||
Tmp.v1.set(lineDest).sub(unit).setLength(unit.hitSize / 2f);
|
||||
Tmp.v2.set(Tmp.v1).scl(-1f).setLength(3.5f);
|
||||
for(Unit unit : selectedUnits){
|
||||
CommandAI ai = (CommandAI)unit.controller();
|
||||
//draw target line
|
||||
if(ai.targetPos != null){
|
||||
Position lineDest = ai.attackTarget != null ? ai.attackTarget : ai.targetPos;
|
||||
|
||||
Drawf.line(Pal.accent, unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, lineDest.getX() + Tmp.v2.x, lineDest.getY() + Tmp.v2.y);
|
||||
Tmp.v1.set(lineDest).sub(unit).setLength(unit.hitSize / 2f);
|
||||
Tmp.v2.set(Tmp.v1).scl(-1f).setLength(3.5f);
|
||||
|
||||
if(ai.attackTarget == null){
|
||||
Drawf.square(lineDest.getX(), lineDest.getY(), 3.5f);
|
||||
Drawf.line(Pal.accent, unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, lineDest.getX() + Tmp.v2.x, lineDest.getY() + Tmp.v2.y);
|
||||
|
||||
if(ai.attackTarget == null){
|
||||
Drawf.square(lineDest.getX(), lineDest.getY(), 3.5f);
|
||||
}
|
||||
}
|
||||
|
||||
Drawf.square(unit.x, unit.y, unit.hitSize / 1.4f + 1f);
|
||||
|
||||
if(ai.attackTarget != null){
|
||||
Drawf.target(ai.attackTarget.getX(), ai.attackTarget.getY(), 6f, Pal.remove);
|
||||
}
|
||||
}
|
||||
|
||||
Drawf.square(unit.x, unit.y, unit.hitSize / 1.4f + 1f);
|
||||
if(commandMode && !commandRect){
|
||||
Unit sel = selectedCommandUnit(input.mouseWorldX(), input.mouseWorldY());
|
||||
|
||||
if(ai.attackTarget != null){
|
||||
Drawf.target(ai.attackTarget.getX(), ai.attackTarget.getY(), 6f, Pal.remove);
|
||||
if(sel != null && !(!multiSelect() && selectedUnits.size == 1 && selectedUnits.contains(sel))){
|
||||
drawCommand(sel);
|
||||
}
|
||||
}
|
||||
|
||||
if(commandRect){
|
||||
float x2 = input.mouseWorldX(), y2 = input.mouseWorldY();
|
||||
var units = selectedCommandUnits(commandRectX, commandRectY, x2 - commandRectX, y2 - commandRectY);
|
||||
for(var unit : units){
|
||||
drawCommand(unit);
|
||||
}
|
||||
|
||||
Draw.color(Pal.accent, 0.3f);
|
||||
Fill.crect(commandRectX, commandRectY, x2 - commandRectX, y2 - commandRectY);
|
||||
}
|
||||
}
|
||||
|
||||
if(commandMode && !commandRect){
|
||||
Unit sel = selectedCommandUnit(input.mouseWorldX(), input.mouseWorldY());
|
||||
|
||||
if(sel != null && !(!multiSelect() && selectedUnits.size == 1 && selectedUnits.contains(sel))){
|
||||
drawCommand(sel);
|
||||
}
|
||||
}
|
||||
|
||||
if(commandRect){
|
||||
float x2 = input.mouseWorldX(), y2 = input.mouseWorldY();
|
||||
var units = selectedCommandUnits(commandRectX, commandRectY, x2 - commandRectX, y2 - commandRectY);
|
||||
for(var unit : units){
|
||||
drawCommand(unit);
|
||||
}
|
||||
|
||||
Draw.color(Pal.accent, 0.3f);
|
||||
Fill.crect(commandRectX, commandRectY, x2 - commandRectX, y2 - commandRectY);
|
||||
}
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
@@ -271,12 +275,19 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
}
|
||||
|
||||
commandMode = input.keyDown(Binding.commandMode) && !locked && state.rules.unitCommand && block == null;
|
||||
shouldShoot = !scene.hasMouse() && !locked;
|
||||
|
||||
if(!locked && state.rules.unitCommand && block == null){
|
||||
if(input.keyTap(Binding.commandMode)){
|
||||
commandMode = !commandMode;
|
||||
}
|
||||
}else{
|
||||
commandMode = false;
|
||||
}
|
||||
|
||||
//TODO should selected units be cleared out of command mode?
|
||||
if(!commandMode){
|
||||
selectedUnits.clear();
|
||||
//selectedUnits.clear();
|
||||
}
|
||||
|
||||
//validate commanding units
|
||||
@@ -549,7 +560,8 @@ public class DesktopInput extends InputHandler{
|
||||
if(multiSelect()){
|
||||
//tiny brain method of unique addition
|
||||
selectedUnits.removeAll(units);
|
||||
}else if(units.size > 0){
|
||||
}else{
|
||||
//nothing selected, clear units
|
||||
selectedUnits.clear();
|
||||
}
|
||||
selectedUnits.addAll(units);
|
||||
@@ -673,7 +685,7 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
//TODO when shift is held? ctrl?
|
||||
public boolean multiSelect(){
|
||||
return false;
|
||||
}
|
||||
@@ -684,37 +696,49 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
tappedOne = true;
|
||||
|
||||
Unit unit = selectedCommandUnit(input.mouseWorldX(), input.mouseWorldY());
|
||||
if(unit != null){
|
||||
if(!multiSelect()){
|
||||
selectedUnits.clear();
|
||||
selectedUnits.add(unit);
|
||||
}else{
|
||||
if(selectedUnits.contains(unit)){
|
||||
selectedUnits.remove(unit);
|
||||
}else{
|
||||
//click: select a single unit
|
||||
if(button == KeyCode.mouseLeft){
|
||||
Unit unit = selectedCommandUnit(input.mouseWorldX(), input.mouseWorldY());
|
||||
if(unit != null){
|
||||
if(!multiSelect()){
|
||||
selectedUnits.clear();
|
||||
selectedUnits.add(unit);
|
||||
}else{
|
||||
if(selectedUnits.contains(unit)){
|
||||
selectedUnits.remove(unit);
|
||||
}else{
|
||||
selectedUnits.add(unit);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
//deselect
|
||||
selectedUnits.clear();
|
||||
}
|
||||
}else if(selectedUnits.size > 0){
|
||||
//move to location - TODO right click instead?
|
||||
Vec2 target = input.mouseWorld().cpy();
|
||||
}else if(button == KeyCode.mouseRight){
|
||||
//right click: move to position
|
||||
|
||||
Teamc attack = world.buildWorld(target.x, target.y);
|
||||
if(selectedUnits.size > 0){
|
||||
//move to location - TODO right click instead?
|
||||
Vec2 target = input.mouseWorld().cpy();
|
||||
|
||||
Teamc attack = world.buildWorld(target.x, target.y);
|
||||
|
||||
if(attack == null || attack.team() == player.team()){
|
||||
attack = selectedEnemyUnit(target.x, target.y);
|
||||
}
|
||||
|
||||
int[] ids = new int[selectedUnits.size];
|
||||
for(int i = 0; i < ids.length; i++){
|
||||
ids[i] = selectedUnits.get(i).id;
|
||||
}
|
||||
|
||||
Call.commandUnits(player, ids, attack instanceof Building b ? b : null, attack instanceof Unit u ? u : null, target);
|
||||
|
||||
if(attack == null || attack.team() == player.team()){
|
||||
attack = selectedEnemyUnit(target.x, target.y);
|
||||
}
|
||||
|
||||
int[] ids = new int[selectedUnits.size];
|
||||
for(int i = 0; i < ids.length; i++){
|
||||
ids[i] = selectedUnits.get(i).id;
|
||||
}
|
||||
|
||||
Call.commandUnits(player, ids, attack instanceof Building b ? b : null, attack instanceof Unit u ? u : null, target);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
return super.tap(x, y, count, button);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ public class ItemImage extends Stack{
|
||||
|
||||
add(new Table(t -> {
|
||||
t.left().bottom();
|
||||
//TODO outline? .style(Styles.outlineLabel)
|
||||
t.add(amount > 1000 ? UI.formatAmount(amount) : amount + "");
|
||||
t.pack();
|
||||
}));
|
||||
|
||||
@@ -42,9 +42,10 @@ public class PlacementFragment extends Fragment{
|
||||
Object lastDisplayState;
|
||||
Team lastTeam;
|
||||
boolean wasHovered;
|
||||
Table blockTable, toggler, topTable;
|
||||
Table blockTable, toggler, topTable, blockCatTable, commandTable;
|
||||
Stack mainStack;
|
||||
ScrollPane blockPane;
|
||||
boolean blockSelectEnd;
|
||||
boolean blockSelectEnd, wasCommandMode;
|
||||
int blockSelectSeq;
|
||||
long blockSelectSeqMillis;
|
||||
Binding[] blockSelect = {
|
||||
@@ -366,68 +367,136 @@ public class PlacementFragment extends Fragment{
|
||||
hovered.display(topTable);
|
||||
}
|
||||
});
|
||||
}).colspan(3).fillX().visible(this::hasInfoBox).touchable(Touchable.enabled);
|
||||
frame.row();
|
||||
frame.image().color(Pal.gray).colspan(3).height(4).growX();
|
||||
frame.row();
|
||||
frame.table(Tex.pane2, blocksSelect -> {
|
||||
blocksSelect.margin(4).marginTop(0);
|
||||
blockPane = blocksSelect.pane(blocks -> blockTable = blocks).height(194f).update(pane -> {
|
||||
if(pane.hasScroll()){
|
||||
Element result = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(result == null || !result.isDescendantOf(pane)){
|
||||
Core.scene.setScrollFocus(null);
|
||||
}
|
||||
}
|
||||
}).grow().get();
|
||||
blockPane.setStyle(Styles.smallPane);
|
||||
blocksSelect.row();
|
||||
blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
frame.table(categories -> {
|
||||
categories.bottom();
|
||||
categories.add(new Image(Styles.black6){
|
||||
@Override
|
||||
public void draw(){
|
||||
if(height <= Scl.scl(3f)) return;
|
||||
getDrawable().draw(x, y, width, height - Scl.scl(3f));
|
||||
}
|
||||
}).colspan(2).growX().growY().padTop(-3f).row();
|
||||
categories.defaults().size(50f);
|
||||
}).colspan(3).fillX().visible(this::hasInfoBox).touchable(Touchable.enabled).row();
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
frame.image().color(Pal.gray).colspan(3).height(4).growX().row();
|
||||
|
||||
//update category empty values
|
||||
for(Category cat : Category.all){
|
||||
Seq<Block> blocks = getUnlockedByCategory(cat);
|
||||
categoryEmpty[cat.ordinal()] = blocks.isEmpty();
|
||||
blockCatTable = new Table();
|
||||
commandTable = new Table(Tex.pane2);
|
||||
mainStack = new Stack();
|
||||
|
||||
mainStack.update(() -> {
|
||||
if(control.input.commandMode != wasCommandMode){
|
||||
mainStack.clearChildren();
|
||||
mainStack.addChild(control.input.commandMode ? commandTable : blockCatTable);
|
||||
wasCommandMode = control.input.commandMode;
|
||||
|
||||
//hacky, but forces command table to be same width as blocks
|
||||
if(wasCommandMode){
|
||||
commandTable.getCells().peek().width(blockCatTable.getWidth());
|
||||
}
|
||||
}
|
||||
|
||||
boolean needsAssign = categoryEmpty[currentCategory.ordinal()];
|
||||
});
|
||||
|
||||
int f = 0;
|
||||
for(Category cat : getCategories()){
|
||||
if(f++ % 2 == 0) categories.row();
|
||||
frame.add(mainStack).colspan(3).fill();
|
||||
|
||||
if(categoryEmpty[cat.ordinal()]){
|
||||
categories.image(Styles.black6);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(needsAssign){
|
||||
currentCategory = cat;
|
||||
needsAssign = false;
|
||||
}
|
||||
//commandTable: commanded units
|
||||
{
|
||||
commandTable.touchable = Touchable.enabled;
|
||||
commandTable.add("[accent]Command Mode").fill().center().labelAlign(Align.center).row();
|
||||
commandTable.image().color(Pal.accent).growX().pad(20f).padTop(0f).padBottom(4f).row();
|
||||
commandTable.table(u -> {
|
||||
u.left();
|
||||
int[] curCount = {0};
|
||||
|
||||
categories.button(ui.getIcon(cat.name()), Styles.clearToggleTransi, () -> {
|
||||
currentCategory = cat;
|
||||
if(control.input.block != null){
|
||||
control.input.block = getSelectedBlock(currentCategory);
|
||||
Runnable rebuildCommand = () -> {
|
||||
u.clearChildren();
|
||||
var units = control.input.selectedUnits;
|
||||
if(units.size > 0){
|
||||
int[] counts = new int[content.units().size];
|
||||
for(var unit : units){
|
||||
counts[unit.type.id] ++;
|
||||
}
|
||||
int col = 0;
|
||||
for(int i = 0; i < counts.length; i++){
|
||||
if(counts[i] > 0){
|
||||
var type = content.unit(i);
|
||||
u.add(new ItemImage(type.uiIcon, counts[i])).tooltip(type.localizedName).pad(4);
|
||||
|
||||
if(++col % 7 == 0){
|
||||
u.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
u.add("[no units]").color(Color.lightGray).growX().center().labelAlign(Align.center).pad(6);
|
||||
}
|
||||
rebuildCategory.run();
|
||||
}).group(group).update(i -> i.setChecked(currentCategory == cat)).name("category-" + cat.name());
|
||||
}
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
};
|
||||
|
||||
u.update(() -> {
|
||||
int size = control.input.selectedUnits.size;
|
||||
if(curCount[0] != size){
|
||||
curCount[0] = size;
|
||||
rebuildCommand.run();
|
||||
}
|
||||
});
|
||||
rebuildCommand.run();
|
||||
}).grow();
|
||||
}
|
||||
|
||||
//blockCatTable: all blocks | all categories
|
||||
{
|
||||
blockCatTable.table(Tex.pane2, blocksSelect -> {
|
||||
blocksSelect.margin(4).marginTop(0);
|
||||
blockPane = blocksSelect.pane(blocks -> blockTable = blocks).height(194f).update(pane -> {
|
||||
if(pane.hasScroll()){
|
||||
Element result = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true);
|
||||
if(result == null || !result.isDescendantOf(pane)){
|
||||
Core.scene.setScrollFocus(null);
|
||||
}
|
||||
}
|
||||
}).grow().get();
|
||||
blockPane.setStyle(Styles.smallPane);
|
||||
blocksSelect.row();
|
||||
blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
blockCatTable.table(categories -> {
|
||||
categories.bottom();
|
||||
categories.add(new Image(Styles.black6){
|
||||
@Override
|
||||
public void draw(){
|
||||
if(height <= Scl.scl(3f)) return;
|
||||
getDrawable().draw(x, y, width, height - Scl.scl(3f));
|
||||
}
|
||||
}).colspan(2).growX().growY().padTop(-3f).row();
|
||||
categories.defaults().size(50f);
|
||||
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
|
||||
//update category empty values
|
||||
for(Category cat : Category.all){
|
||||
Seq<Block> blocks = getUnlockedByCategory(cat);
|
||||
categoryEmpty[cat.ordinal()] = blocks.isEmpty();
|
||||
}
|
||||
|
||||
boolean needsAssign = categoryEmpty[currentCategory.ordinal()];
|
||||
|
||||
int f = 0;
|
||||
for(Category cat : getCategories()){
|
||||
if(f++ % 2 == 0) categories.row();
|
||||
|
||||
if(categoryEmpty[cat.ordinal()]){
|
||||
categories.image(Styles.black6);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(needsAssign){
|
||||
currentCategory = cat;
|
||||
needsAssign = false;
|
||||
}
|
||||
|
||||
categories.button(ui.getIcon(cat.name()), Styles.clearToggleTransi, () -> {
|
||||
currentCategory = cat;
|
||||
if(control.input.block != null){
|
||||
control.input.block = getSelectedBlock(currentCategory);
|
||||
}
|
||||
rebuildCategory.run();
|
||||
}).group(group).update(i -> i.setChecked(currentCategory == cat)).name("category-" + cat.name());
|
||||
}
|
||||
}).fillY().bottom().touchable(Touchable.enabled);
|
||||
}
|
||||
|
||||
mainStack.add(blockCatTable);
|
||||
|
||||
rebuildCategory.run();
|
||||
frame.update(() -> {
|
||||
|
||||
Reference in New Issue
Block a user