Prototype unit cap mechanic

This commit is contained in:
Anuken
2020-05-12 21:34:27 -04:00
parent 2990013b8e
commit 6a22d45320
13 changed files with 84 additions and 145 deletions

View File

@@ -591,6 +591,7 @@ bar.poweramount = Power: {0}
bar.poweroutput = Power Output: {0} bar.poweroutput = Power Output: {0}
bar.items = Items: {0} bar.items = Items: {0}
bar.capacity = Capacity: {0} bar.capacity = Capacity: {0}
bar.units = Units: {0}/{1}
bar.liquid = Liquid bar.liquid = Liquid
bar.heat = Heat bar.heat = Heat
bar.power = Power bar.power = Power

View File

@@ -39,8 +39,10 @@ public class BlockIndexer{
private ObjectSet<Item> allOres = new ObjectSet<>(); private ObjectSet<Item> allOres = new ObjectSet<>();
/** Stores teams that are present here as tiles. */ /** Stores teams that are present here as tiles. */
private Array<Team> activeTeams = new Array<>(); private Array<Team> activeTeams = new Array<>();
/** Maps teams to a map of flagged tiles by type. */ /** Maps teams to a map of flagged tiles by flag. */
private TileArray[][] flagMap = new TileArray[Team.all().length][BlockFlag.all.length]; private TileArray[][] flagMap = new TileArray[Team.all().length][BlockFlag.all.length];
/** Max units by team. */
private int[] unitCaps = new int[Team.all().length];
/** Maps tile positions to their last known tile index data. */ /** Maps tile positions to their last known tile index data. */
private IntMap<TileIndex> typeMap = new IntMap<>(); private IntMap<TileIndex> typeMap = new IntMap<>();
/** Empty set used for returning. */ /** Empty set used for returning. */
@@ -55,6 +57,10 @@ public class BlockIndexer{
for(BlockFlag flag : index.flags){ for(BlockFlag flag : index.flags){
getFlagged(index.team)[flag.ordinal()].remove(event.tile); getFlagged(index.team)[flag.ordinal()].remove(event.tile);
} }
if(index.flags.contains(BlockFlag.unitModifier)){
updateCap(index.team);
}
} }
process(event.tile); process(event.tile);
updateQuadrant(event.tile); updateQuadrant(event.tile);
@@ -65,6 +71,7 @@ public class BlockIndexer{
scanOres.addAll(Item.getAllOres()); scanOres.addAll(Item.getAllOres());
damagedTiles = new TileArray[Team.all().length]; damagedTiles = new TileArray[Team.all().length];
flagMap = new TileArray[Team.all().length][BlockFlag.all.length]; flagMap = new TileArray[Team.all().length][BlockFlag.all.length];
unitCaps = new int[Team.all().length];
for(int i = 0; i < flagMap.length; i++){ for(int i = 0; i < flagMap.length; i++){
for(int j = 0; j < BlockFlag.all.length; j++){ for(int j = 0; j < BlockFlag.all.length; j++){
@@ -296,6 +303,19 @@ public class BlockIndexer{
return null; return null;
} }
/** @return extra unit cap of a team. This is added onto the base value. */
public int getExtraUnits(Team team){
return unitCaps[team.id];
}
private void updateCap(Team team){
TileArray capped = getFlagged(team)[BlockFlag.unitModifier.ordinal()];
unitCaps[team.id] = 0;
for(Tile capper : capped){
unitCaps[team.id] += capper.block().unitCapModifier;
}
}
private void process(Tile tile){ private void process(Tile tile){
if(tile.block().flags.size() > 0 && tile.team() != Team.derelict){ if(tile.block().flags.size() > 0 && tile.team() != Team.derelict){
TileArray[] map = getFlagged(tile.team()); TileArray[] map = getFlagged(tile.team());
@@ -308,6 +328,11 @@ public class BlockIndexer{
map[flag.ordinal()] = arr; map[flag.ordinal()] = arr;
} }
if(tile.block().flags.contains(BlockFlag.unitModifier)){
updateCap(tile.team());
}
typeMap.put(tile.pos(), new TileIndex(tile.block().flags, tile.team())); typeMap.put(tile.pos(), new TileIndex(tile.block().flags, tile.team()));
} }
if(!activeTeams.contains(tile.team())){ if(!activeTeams.contains(tile.team())){

View File

@@ -11,6 +11,7 @@ import mindustry.gen.*;
public class TeamIndexProcess implements AsyncProcess{ public class TeamIndexProcess implements AsyncProcess{
private QuadTree<Unitc>[] trees = new QuadTree[Team.all().length]; private QuadTree<Unitc>[] trees = new QuadTree[Team.all().length];
private Array<Team> active = new Array<>(); private Array<Team> active = new Array<>();
private int[] counts = new int[Team.all().length];
public QuadTree<Unitc> tree(Team team){ public QuadTree<Unitc> tree(Team team){
if(trees[team.uid] == null) trees[team.uid] = new QuadTree<>(Vars.world.getQuadBounds(new Rect())); if(trees[team.uid] == null) trees[team.uid] = new QuadTree<>(Vars.world.getQuadBounds(new Rect()));
@@ -18,9 +19,18 @@ public class TeamIndexProcess implements AsyncProcess{
return trees[team.uid]; return trees[team.uid];
} }
public int count(Team team){
return counts[team.id];
}
public void updateCount(Team team, int amount){
counts[team.id] += amount;
}
@Override @Override
public void reset(){ public void reset(){
active.clear(); active.clear();
counts = new int[Team.all().length];
trees = new QuadTree[Team.all().length]; trees = new QuadTree[Team.all().length];
} }
@@ -38,8 +48,13 @@ public class TeamIndexProcess implements AsyncProcess{
} }
} }
for(Team team : active){
counts[team.id] = 0;
}
for(Unitc unit : Groups.unit){ for(Unitc unit : Groups.unit){
tree(unit.team()).insert(unit); tree(unit.team()).insert(unit);
counts[unit.team().id] ++;
} }
} }

View File

@@ -293,7 +293,10 @@ public class NetServer implements ApplicationListener{
}); });
clientCommands.<Playerc>register("t", "<message...>", "Send a message only to your teammates.", (args, player) -> { clientCommands.<Playerc>register("t", "<message...>", "Send a message only to your teammates.", (args, player) -> {
Groups.player.each(p -> p.team() == player.team(), o -> o.sendMessage(args[0], player, "[#" + player.team().color.toString() + "]<T>" + NetClient.colorizeName(player.id(), player.name()))); String message = admins.filterMessage(player, args[0]);
if(message != null){
Groups.player.each(p -> p.team() == player.team(), o -> o.sendMessage(message, player, "[#" + player.team().color.toString() + "]<T>" + NetClient.colorizeName(player.id(), player.name())));
}
}); });
//duration of a a kick in seconds //duration of a a kick in seconds

View File

@@ -15,6 +15,15 @@ public class Units{
private static float cdist; private static float cdist;
private static boolean boolResult; private static boolean boolResult;
/** @return whether a new instance of a unit of this team can be created. */
public static boolean canCreate(Team team){
return teamIndex.count(team) < getCap(team);
}
public static int getCap(Team team){
return state.rules.unitCap + indexer.getExtraUnits(team);
}
/** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/ /** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/
public static boolean canInteract(Playerc player, Tilec tile){ public static boolean canInteract(Playerc player, Tilec tile){
return player == null || tile == null || tile.interactable(player.team()); return player == null || tile == null || tile.interactable(player.team());

View File

@@ -115,6 +115,16 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
type(this.type); type(this.type);
} }
@Override
public void add(){
teamIndex.updateCount(team(), 1);
}
@Override
public void remove(){
teamIndex.updateCount(team(), -1);
}
@Override @Override
public void update(){ public void update(){
drag(type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f)); drag(type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f));

View File

@@ -58,6 +58,8 @@ public class Rules{
public float bossWaveMultiplier = 3f; public float bossWaveMultiplier = 3f;
/** How many times longer a launch wave takes. */ /** How many times longer a launch wave takes. */
public float launchWaveMultiplier = 2f; public float launchWaveMultiplier = 2f;
/** Base unit cap. Can still be increased by blocks. */
public int unitCap = 10;
/** Sector for saves that have them.*/ /** Sector for saves that have them.*/
public @Nullable Sector sector; public @Nullable Sector sector;
/** Region that save is on. Indicates campaign. TODO not implemented. */ /** Region that save is on. Indicates campaign. TODO not implemented. */

View File

@@ -106,6 +106,9 @@ public class Block extends UnlockableContent{
public EnumSet<BlockFlag> flags = EnumSet.of(); public EnumSet<BlockFlag> flags = EnumSet.of();
/** Targeting priority of this block, as seen by enemies.*/ /** Targeting priority of this block, as seen by enemies.*/
public TargetPriority priority = TargetPriority.base; public TargetPriority priority = TargetPriority.base;
/** How much this block affects the unit cap by.
* The block flags must contain unitModifier in order for this to work. */
public int unitCapModifier = 0;
/** Whether the block can be tapped and selected to configure. */ /** Whether the block can be tapped and selected to configure. */
public boolean configurable; public boolean configurable;
/** Whether this block consumes touchDown events when tapped. */ /** Whether this block consumes touchDown events when tapped. */

View File

@@ -8,6 +8,7 @@ import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
@@ -28,7 +29,8 @@ public class CoreBlock extends StorageBlock{
solid = true; solid = true;
update = true; update = true;
hasItems = true; hasItems = true;
flags = EnumSet.of(BlockFlag.core, BlockFlag.producer); flags = EnumSet.of(BlockFlag.core, BlockFlag.producer, BlockFlag.unitModifier);
unitCapModifier = 30;
activeSound = Sounds.respawning; activeSound = Sounds.respawning;
activeSoundVolume = 1f; activeSoundVolume = 1f;
} }
@@ -59,6 +61,13 @@ public class CoreBlock extends StorageBlock{
() -> Pal.items, () -> Pal.items,
() -> e.items().total() / (float)(((CoreEntity)e).storageCapacity * content.items().count(i -> i.type == ItemType.material)) () -> e.items().total() / (float)(((CoreEntity)e).storageCapacity * content.items().count(i -> i.type == ItemType.material))
)); ));
bars.add("units", e ->
new Bar(
() -> Core.bundle.format("bar.units", teamIndex.count(e.team()), Units.getCap(e.team())),
() -> Pal.power,
() -> (float)teamIndex.count(e.team()) / Units.getCap(e.team())
));
} }
@Override @Override

View File

@@ -1,134 +0,0 @@
package mindustry.world.blocks.units;
import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.scene.style.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.ai.BlockIndexer.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
public class CommandCenter extends Block{
protected TextureRegionDrawable[] commandRegions = new TextureRegionDrawable[UnitCommand.all.length];
protected Color topColor = Pal.command;
protected Color bottomColor = Color.valueOf("5e5e5e");
protected Effect effect = Fx.commandSend;
public CommandCenter(String name){
super(name);
flags = EnumSet.of(BlockFlag.comandCenter);
destructible = true;
solid = true;
configurable = true;
config(Integer.class, (tile, value) -> {
UnitCommand command = UnitCommand.all[value];
((CommandCenter)tile.block()).effect.at(tile);
for(Tile center : indexer.getAllied(tile.team(), BlockFlag.comandCenter)){
if(center.block() instanceof CommandCenter){
CommandCenterEntity entity = center.ent();
entity.command = command;
}
}
Groups.unit.each(t -> t.team() == tile.team(), u -> u.controller().command(command));
Events.fire(new CommandIssueEvent(tile, command));
});
}
@Override
public void load(){
super.load();
if(ui != null){
for(UnitCommand cmd : UnitCommand.all){
commandRegions[cmd.ordinal()] = ui.getIcon("command" + Strings.capitalize(cmd.name()));
}
}
}
public class CommandCenterEntity extends TileEntity{
public UnitCommand command = UnitCommand.attack;
@Override
public void draw(){
super.draw();
float size = 6f;
Draw.color(bottomColor);
Draw.rect(commandRegions[command.ordinal()].getRegion(), x, y - 1, size, size);
Draw.color(topColor);
Draw.rect(commandRegions[command.ordinal()].getRegion(), x, y, size, size);
Draw.color();
}
@Override
public void buildConfiguration(Table table){
ButtonGroup<ImageButton> group = new ButtonGroup<>();
Table buttons = new Table();
for(UnitCommand cmd : UnitCommand.all){
buttons.button(commandRegions[cmd.ordinal()], Styles.clearToggleTransi, () -> configure(cmd.ordinal()))
.size(44).group(group).update(b -> b.setChecked(command == cmd));
}
table.add(buttons);
table.row();
table.label(() -> command.localized()).style(Styles.outlineLabel).center().growX().get().setAlignment(Align.center);
}
@Override
public void placed(){
super.placed();
TileArray set = indexer.getAllied(team, BlockFlag.comandCenter);
if(set.size() > 0){
CommandCenterEntity oe = set.first().ent();
command = oe.command;
}
}
@Override
public void onRemoved(){
super.onRemoved();
TileArray set = indexer.getAllied(team, BlockFlag.comandCenter);
if(set.size() == 1){
Groups.unit.each(t -> t.team() == team, u -> u.controller().command(UnitCommand.all[0]));
}
}
@Override
public Integer config(){
return command.ordinal();
}
@Override
public void write(Writes write){
super.write(write);
write.b(command.ordinal());
}
@Override
public void read(Reads read, byte revision){
super.read(read, revision);
command = UnitCommand.all[read.b()];
}
}
}

View File

@@ -220,7 +220,7 @@ public class UnitFactory extends Block{
if(currentPlan != -1){ if(currentPlan != -1){
UnitPlan plan = plans[currentPlan]; UnitPlan plan = plans[currentPlan];
if(progress >= plan.time/* && !Units.anyEntities(tile, !plan.unit.flying)*/){ if(progress >= plan.time/* && !Units.anyEntities(tile, !plan.unit.flying)*/ && Units.canCreate(team)){
progress = 0f; progress = 0f;
Call.onUnitFactorySpawn(tile); Call.onUnitFactorySpawn(tile);

View File

@@ -4,18 +4,14 @@ package mindustry.world.meta;
public enum BlockFlag{ public enum BlockFlag{
/** Enemy core; primary target for all units. */ /** Enemy core; primary target for all units. */
core, core,
/** Rally point for units.*/
rally,
/** Producer of important goods. */ /** Producer of important goods. */
producer, producer,
/** A turret. */ /** A turret. */
turret, turret,
/** Only the command center block.*/
comandCenter,
/** Repair point. */ /** Repair point. */
repair, repair,
/** Upgrade pad. */ /** Any block that boosts unit capacity. */
mechPad; unitModifier;
public final static BlockFlag[] all = values(); public final static BlockFlag[] all = values();
} }

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=a9ac74c4165c71b4a2cddffe2d560717b9698d15 archash=64304225a74ee3e2c2bd97fd1f23dc4042ba29e2