Bannable units / Show tech tree icon for unresearched units

This commit is contained in:
Anuken
2021-08-05 23:01:58 -04:00
parent 6fdbe1d5f0
commit 4fa04b9e23
9 changed files with 137 additions and 84 deletions

View File

@@ -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. */

View File

@@ -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(){

View File

@@ -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

View File

@@ -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);

View File

@@ -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>{

View File

@@ -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);
}
}

View File

@@ -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){

View File

@@ -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;