Bannable units / Show tech tree icon for unresearched units
This commit is contained in:
@@ -94,6 +94,8 @@ public class Rules{
|
||||
public Seq<WeatherEntry> weather = new Seq<>(1);
|
||||
/** Blocks that cannot be placed. */
|
||||
public ObjectSet<Block> bannedBlocks = new ObjectSet<>();
|
||||
/** Units that cannot be built. */
|
||||
public ObjectSet<UnitType> bannedUnits = new ObjectSet<>();
|
||||
/** Reveals blocks normally hidden by build visibility. */
|
||||
public ObjectSet<Block> revealedBlocks = new ObjectSet<>();
|
||||
/** Unlocked content names. Only used in multiplayer when the campaign is enabled. */
|
||||
|
||||
@@ -40,11 +40,7 @@ public class MinimapRenderer{
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(BuildTeamChangeEvent.class, event -> {
|
||||
if(!ui.editor.isShown()){
|
||||
update(event.build.tile);
|
||||
}
|
||||
});
|
||||
Events.on(BuildTeamChangeEvent.class, event -> update(event.build.tile));
|
||||
}
|
||||
|
||||
public Pixmap getPixmap(){
|
||||
|
||||
@@ -233,6 +233,10 @@ public class UnitType extends UnlockableContent{
|
||||
return (envEnabled & env) != 0 && (envDisabled & env) == 0 && (envRequired == 0 || (envRequired & env) == envRequired);
|
||||
}
|
||||
|
||||
public boolean isBanned(){
|
||||
return state.rules.bannedUnits.contains(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getDependencies(Cons<UnlockableContent> cons){
|
||||
//units require reconstructors being researched
|
||||
|
||||
@@ -28,87 +28,93 @@ public class CustomRulesDialog extends BaseDialog{
|
||||
private Table main;
|
||||
private Prov<Rules> resetter;
|
||||
private LoadoutDialog loadoutDialog;
|
||||
private BaseDialog banDialog;
|
||||
|
||||
public CustomRulesDialog(){
|
||||
super("@mode.custom");
|
||||
|
||||
loadoutDialog = new LoadoutDialog();
|
||||
banDialog = new BaseDialog("@bannedblocks");
|
||||
banDialog.addCloseButton();
|
||||
|
||||
banDialog.shown(this::rebuildBanned);
|
||||
banDialog.buttons.button("@addall", Icon.add, () -> {
|
||||
rules.bannedBlocks.addAll(content.blocks().select(Block::canBeBuilt));
|
||||
rebuildBanned();
|
||||
}).size(180, 64f);
|
||||
|
||||
banDialog.buttons.button("@clear", Icon.trash, () -> {
|
||||
rules.bannedBlocks.clear();
|
||||
rebuildBanned();
|
||||
}).size(180, 64f);
|
||||
|
||||
setFillParent(true);
|
||||
shown(this::setup);
|
||||
addCloseButton();
|
||||
}
|
||||
|
||||
private void rebuildBanned(){
|
||||
float previousScroll = banDialog.cont.getChildren().isEmpty() ? 0f : ((ScrollPane)banDialog.cont.getChildren().first()).getScrollY();
|
||||
banDialog.cont.clear();
|
||||
banDialog.cont.pane(t -> {
|
||||
t.margin(10f);
|
||||
private <T extends UnlockableContent> void showBanned(String title, ContentType type, ObjectSet<T> set, Boolf<T> pred){
|
||||
BaseDialog bd = new BaseDialog(title);
|
||||
bd.addCloseButton();
|
||||
|
||||
if(rules.bannedBlocks.isEmpty()){
|
||||
t.add("@empty");
|
||||
}
|
||||
Runnable[] rebuild = {null};
|
||||
|
||||
Seq<Block> array = Seq.with(rules.bannedBlocks);
|
||||
array.sort();
|
||||
rebuild[0] = () -> {
|
||||
float previousScroll = bd.cont.getChildren().isEmpty() ? 0f : ((ScrollPane)bd.cont.getChildren().first()).getScrollY();
|
||||
bd.cont.clear();
|
||||
bd.cont.pane(t -> {
|
||||
t.margin(10f);
|
||||
|
||||
int cols = mobile && Core.graphics.isPortrait() ? 1 : mobile ? 2 : 3;
|
||||
int i = 0;
|
||||
|
||||
for(Block block : array){
|
||||
t.table(Tex.underline, b -> {
|
||||
b.left().margin(4f);
|
||||
b.image(block.uiIcon).size(iconMed).padRight(3);
|
||||
b.add(block.localizedName).color(Color.lightGray).padLeft(3).growX().left().wrap();
|
||||
|
||||
b.button(Icon.cancel, Styles.clearPartiali, () -> {
|
||||
rules.bannedBlocks.remove(block);
|
||||
rebuildBanned();
|
||||
}).size(70f).pad(-4f).padLeft(0f);
|
||||
}).size(300f, 70f).padRight(5);
|
||||
|
||||
if(++i % cols == 0){
|
||||
t.row();
|
||||
if(set.isEmpty()){
|
||||
t.add("@empty");
|
||||
}
|
||||
}
|
||||
}).get().setScrollYForce(previousScroll);
|
||||
banDialog.cont.row();
|
||||
banDialog.cont.button("@add", Icon.add, () -> {
|
||||
BaseDialog dialog = new BaseDialog("@add");
|
||||
dialog.cont.pane(t -> {
|
||||
t.left().margin(14f);
|
||||
int[] i = {0};
|
||||
content.blocks().each(b -> !rules.bannedBlocks.contains(b) && b.canBeBuilt(), b -> {
|
||||
int cols = mobile && Core.graphics.isPortrait() ? 4 : 12;
|
||||
t.button(new TextureRegionDrawable(b.uiIcon), Styles.cleari, iconMed, () -> {
|
||||
rules.bannedBlocks.add(b);
|
||||
rebuildBanned();
|
||||
dialog.hide();
|
||||
}).size(60f);
|
||||
|
||||
if(++i[0] % cols == 0){
|
||||
Seq<T> array = set.asArray();
|
||||
array.sort();
|
||||
|
||||
int cols = mobile && Core.graphics.isPortrait() ? 1 : mobile ? 2 : 3;
|
||||
int i = 0;
|
||||
|
||||
for(T con : array){
|
||||
t.table(Tex.underline, b -> {
|
||||
b.left().margin(4f);
|
||||
b.image(con.uiIcon).size(iconMed).padRight(3);
|
||||
b.add(con.localizedName).color(Color.lightGray).padLeft(3).growX().left().wrap();
|
||||
|
||||
b.button(Icon.cancel, Styles.clearPartiali, () -> {
|
||||
set.remove(con);
|
||||
rebuild[0].run();
|
||||
}).size(70f).pad(-4f).padLeft(0f);
|
||||
}).size(300f, 70f).padRight(5);
|
||||
|
||||
if(++i % cols == 0){
|
||||
t.row();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}).get().setScrollYForce(previousScroll);
|
||||
bd.cont.row();
|
||||
bd.cont.button("@add", Icon.add, () -> {
|
||||
BaseDialog dialog = new BaseDialog("@add");
|
||||
dialog.cont.pane(t -> {
|
||||
t.left().margin(14f);
|
||||
int[] i = {0};
|
||||
content.<T>getBy(type).each(b -> !set.contains(b) && pred.get(b), b -> {
|
||||
int cols = mobile && Core.graphics.isPortrait() ? 4 : 12;
|
||||
t.button(new TextureRegionDrawable(b.uiIcon), Styles.cleari, iconMed, () -> {
|
||||
set.add(b);
|
||||
rebuild[0].run();
|
||||
dialog.hide();
|
||||
}).size(60f);
|
||||
|
||||
dialog.addCloseButton();
|
||||
dialog.show();
|
||||
}).size(300f, 64f);
|
||||
if(++i[0] % cols == 0){
|
||||
t.row();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
dialog.addCloseButton();
|
||||
dialog.show();
|
||||
}).size(300f, 64f);
|
||||
};
|
||||
|
||||
bd.shown(rebuild[0]);
|
||||
bd.buttons.button("@addall", Icon.add, () -> {
|
||||
set.addAll(content.<T>getBy(type).select(pred));
|
||||
rebuild[0].run();
|
||||
}).size(180, 64f);
|
||||
|
||||
bd.buttons.button("@clear", Icon.trash, () -> {
|
||||
set.clear();
|
||||
rebuild[0].run();
|
||||
}).size(180, 64f);
|
||||
|
||||
bd.show();
|
||||
}
|
||||
|
||||
public void show(Rules rules, Prov<Rules> resetter){
|
||||
@@ -157,7 +163,7 @@ public class CustomRulesDialog extends BaseDialog{
|
||||
)).left().width(300f);
|
||||
main.row();
|
||||
|
||||
main.button("@bannedblocks", banDialog::show).left().width(300f);
|
||||
main.button("@bannedblocks", () -> showBanned("@bannedblocks", ContentType.block, rules.bannedBlocks, Block::canBeBuilt)).left().width(300f);
|
||||
main.row();
|
||||
|
||||
title("@rules.title.unit");
|
||||
@@ -167,6 +173,9 @@ public class CustomRulesDialog extends BaseDialog{
|
||||
number("@rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
|
||||
number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier, 0.001f, 50f);
|
||||
|
||||
main.button("@bannedunits", () -> showBanned("@bannedunits", ContentType.unit, rules.bannedUnits, u -> !u.isHidden())).left().width(300f);
|
||||
main.row();
|
||||
|
||||
title("@rules.title.enemy");
|
||||
check("@rules.attack", b -> rules.attackMode = b, () -> rules.attackMode);
|
||||
check("@rules.buildai", b -> rules.teams.get(rules.waveTeam).ai = rules.teams.get(rules.waveTeam).infiniteResources = b, () -> rules.teams.get(rules.waveTeam).ai);
|
||||
|
||||
@@ -71,11 +71,11 @@ public class PayloadSource extends PayloadBlock{
|
||||
}
|
||||
|
||||
public boolean canProduce(Block b){
|
||||
return b.isVisible() && b.size < size && !(b instanceof CoreBlock);
|
||||
return b.isVisible() && b.size < size && !(b instanceof CoreBlock) && !state.rules.bannedBlocks.contains(b);
|
||||
}
|
||||
|
||||
public boolean canProduce(UnitType t){
|
||||
return !t.isHidden();
|
||||
return !t.isHidden() && !t.isBanned();
|
||||
}
|
||||
|
||||
public class PayloadSourceBuild extends PayloadBlockBuild<Payload>{
|
||||
|
||||
@@ -4,6 +4,7 @@ import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.*;
|
||||
@@ -13,16 +14,31 @@ import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class UnitPayload implements Payload{
|
||||
public static final float deactiveDuration = 40f;
|
||||
public static final float overlayDuration = 40f;
|
||||
|
||||
public Unit unit;
|
||||
public float deactiveTime = 0f;
|
||||
public float overlayTime = 0f;
|
||||
public @Nullable TextureRegion overlayRegion;
|
||||
|
||||
public UnitPayload(Unit unit){
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
/** Flashes a red overlay region. */
|
||||
public void showOverlay(TextureRegion icon){
|
||||
overlayRegion = icon;
|
||||
overlayTime = 1f;
|
||||
}
|
||||
|
||||
/** Flashes a red overlay region. */
|
||||
public void showOverlay(TextureRegionDrawable icon){
|
||||
if(icon == null || headless) return;
|
||||
showOverlay(icon.getRegion());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Writes write){
|
||||
write.b(payloadUnit);
|
||||
@@ -62,7 +78,8 @@ public class UnitPayload implements Payload{
|
||||
if(unit.type == null) return true;
|
||||
|
||||
if(!Units.canCreate(unit.team, unit.type)){
|
||||
deactiveTime = 1f;
|
||||
overlayTime = 1f;
|
||||
overlayRegion = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -103,16 +120,17 @@ public class UnitPayload implements Payload{
|
||||
unit.type.drawCell(unit);
|
||||
|
||||
//draw warning
|
||||
if(deactiveTime > 0){
|
||||
if(overlayTime > 0){
|
||||
var region = overlayRegion == null ? Icon.warning.getRegion() : overlayRegion;
|
||||
Draw.color(Color.scarlet);
|
||||
Draw.alpha(0.8f * Interp.exp5Out.apply(deactiveTime));
|
||||
Draw.alpha(0.8f * Interp.exp5Out.apply(overlayTime));
|
||||
|
||||
float size = 8f;
|
||||
Draw.rect(Icon.warning.getRegion(), unit.x, unit.y, size, size);
|
||||
Draw.rect(region, unit.x, unit.y, size, size);
|
||||
|
||||
Draw.reset();
|
||||
|
||||
deactiveTime = Math.max(deactiveTime - Time.delta/deactiveDuration, 0f);
|
||||
overlayTime = Math.max(overlayTime - Time.delta/overlayDuration, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,11 +116,28 @@ public class Reconstructor extends UnitBlock{
|
||||
|
||||
@Override
|
||||
public boolean acceptPayload(Building source, Payload payload){
|
||||
return this.payload == null
|
||||
&& (this.enabled || source == this)
|
||||
&& relativeTo(source) != rotation
|
||||
&& payload instanceof UnitPayload pay
|
||||
&& hasUpgrade(pay.unit.type);
|
||||
if(!(this.payload == null
|
||||
&& (this.enabled || source == this)
|
||||
&& relativeTo(source) != rotation
|
||||
&& payload instanceof UnitPayload pay)){
|
||||
return false;
|
||||
}
|
||||
|
||||
var upgrade = upgrade(pay.unit.type);
|
||||
|
||||
if(upgrade != null){
|
||||
if(!upgrade.unlockedNow()){
|
||||
//flash "not researched"
|
||||
pay.showOverlay(Icon.tree);
|
||||
}
|
||||
|
||||
if(upgrade.isBanned()){
|
||||
//flash an X, meaning 'banned'
|
||||
pay.showOverlay(Icon.cancel);
|
||||
}
|
||||
}
|
||||
|
||||
return upgrade != null && upgrade.unlockedNow() && !upgrade.isBanned();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -224,7 +241,7 @@ public class Reconstructor extends UnitBlock{
|
||||
|
||||
public boolean hasUpgrade(UnitType type){
|
||||
UnitType t = upgrade(type);
|
||||
return t != null && t.unlockedNow();
|
||||
return t != null && t.unlockedNow() && !type.isBanned();
|
||||
}
|
||||
|
||||
public UnitType upgrade(UnitType type){
|
||||
|
||||
@@ -149,7 +149,7 @@ public class UnitFactory extends UnitBlock{
|
||||
|
||||
@Override
|
||||
public void buildConfiguration(Table table){
|
||||
Seq<UnitType> units = Seq.with(plans).map(u -> u.unit).filter(u -> u.unlockedNow());
|
||||
Seq<UnitType> units = Seq.with(plans).map(u -> u.unit).filter(u -> u.unlockedNow() && !u.isBanned());
|
||||
|
||||
if(units.any()){
|
||||
ItemSelection.buildTable(table, units, () -> currentPlan == -1 ? null : plans.get(currentPlan).unit, unit -> configure(plans.indexOf(u -> u.unit == unit)));
|
||||
@@ -225,6 +225,12 @@ public class UnitFactory extends UnitBlock{
|
||||
if(currentPlan != -1 && payload == null){
|
||||
UnitPlan plan = plans.get(currentPlan);
|
||||
|
||||
//make sure to reset plan when the unit got banned after placement
|
||||
if(plan.unit.isBanned()){
|
||||
currentPlan = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(progress >= plan.time && consValid()){
|
||||
progress %= 1f;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user