DEATH AND DESTRUCTION

This commit is contained in:
Anuken
2022-02-15 16:46:32 -05:00
parent 3babe7686b
commit c324f2124b
135 changed files with 704 additions and 2080 deletions

View File

@@ -442,7 +442,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public void consume(){
for(Consume cons : block.consumes.all){
for(Consume cons : block.consumers){
cons.trigger(self());
}
}
@@ -465,7 +465,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public float efficiency(){
//disabled -> 0 efficiency
if(!enabled) return 0;
return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f;
return power != null && (block.consPower != null && !block.consPower.buffered) ? power.status : 1f;
}
/**
@@ -702,11 +702,11 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public boolean acceptItem(Building source, Item item){
return block.consumes.consumesItem(item) && items.get(item) < getMaximumAccepted(item);
return block.consumesItem(item) && items.get(item) < getMaximumAccepted(item);
}
public boolean acceptLiquid(Building source, Liquid liquid){
return block.hasLiquids && block.consumes.liquidfilters.get(liquid.id);
return block.hasLiquids && block.consumesLiquid(liquid);
}
public void handleLiquid(Building source, Liquid liquid, float amount){
@@ -791,7 +791,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
liquids.remove(liquid, flow);
return flow;
//handle reactions between different liquid types ▼
}else if(!next.block.consumes.consumesLiquid(liquid) && next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){
}else if(!next.block.consumesLiquid(liquid) && next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){
//TODO !IMPORTANT! uses current(), which is 1) wrong for multi-liquid blocks and 2) causes unwanted reactions, e.g. hydrogen + slag in pump
//TODO these are incorrect effect positions
float fx = (x + next.x) / 2f, fy = (y + next.y) / 2f;
@@ -1043,7 +1043,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public void drawStatus(){
if(block.enableDrawStatus && block.consumes.any()){
if(block.enableDrawStatus && block.consumers.length > 0){
float multiplier = block.size > 1 ? 1 : 0.64f;
float brcx = x + (block.size * tilesize / 2f) - (tilesize * multiplier / 2f);
float brcy = y - (block.size * tilesize / 2f) + (tilesize * multiplier / 2f);
@@ -1249,8 +1249,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
explosiveness += liquids.sum((liquid, amount) -> liquid.explosiveness * amount / 2f);
}
if(block.consumes.hasPower() && block.consumes.getPower().buffered){
power += this.power.status * block.consumes.getPower().capacity;
if(block.consPower != null && block.consPower.buffered){
power += this.power.status * block.consPower.capacity;
}
if(block.hasLiquids && state.rules.damageExplosions){
@@ -1397,14 +1397,14 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void displayConsumption(Table table){
table.left();
for(Consume cons : block.consumes.all){
if(cons.isOptional() && cons.isBoost()) continue;
for(Consume cons : block.consumers){
if(cons.optional && cons.booster) continue;
cons.build(self(), table);
}
}
public void displayBars(Table table){
for(Func<Building, Bar> bar : block.bars.list()){
for(Func<Building, Bar> bar : block.listBars()){
table.add(bar.get(self())).growX();
table.row();
}
@@ -1521,7 +1521,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
//TODO can lead to ghost graphs?
power.graph = new PowerGraph();
power.links.clear();
if(block.consumes.hasPower() && !block.consumes.getPower().buffered){
if(block.consPower != null && !block.consPower.buffered){
power.status = 0f;
}
}
@@ -1590,18 +1590,18 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
consOptionalValid = true;
boolean docons = shouldConsume() && productionValid();
for(Consume cons : block.consumes.all){
if(cons.isOptional()) continue;
for(Consume cons : block.consumers){
if(cons.optional) continue;
if(docons && cons.isUpdate() && prevValid && cons.valid(self())){
if(docons && cons.update && prevValid && cons.valid(self())){
cons.update(self());
}
consValid &= cons.valid(self());
}
for(Consume cons : block.consumes.optionals){
if(docons && cons.isUpdate() && prevValid && cons.valid(self())){
for(Consume cons : block.optionalConsumers){
if(docons && cons.update && prevValid && cons.valid(self())){
cons.update(self());
}
@@ -1693,10 +1693,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
case totalItems -> items == null ? 0 : items.total();
//TODO will give wildly fluctuating amounts due to switching of current() for multi-liquid blocks. totalLiquids is inherently bad design, but unfortunately it is useful for conduits/tanks
case totalLiquids -> liquids == null ? 0 : liquids.currentAmount();
case totalPower -> power == null || !block.consumes.hasPower() ? 0 : power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
case totalPower -> power == null || block.consPower == null ? 0 : power.status * (block.consPower.buffered ? block.consPower.capacity : 1f);
case itemCapacity -> block.hasItems ? block.itemCapacity : 0;
case liquidCapacity -> block.hasLiquids ? block.liquidCapacity : 0;
case powerCapacity -> block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f;
case powerCapacity -> block.consPower != null ? block.consPower.capacity : 0f;
case powerNetIn -> power == null ? 0 : power.graph.getLastScaledPowerIn() * 60;
case powerNetOut -> power == null ? 0 : power.graph.getLastScaledPowerOut() * 60;
case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored();

View File

@@ -1,129 +0,0 @@
package mindustry.entities.comp;
import arc.func.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.ai.formations.*;
import mindustry.ai.types.*;
import mindustry.annotations.Annotations.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;
/**
* A unit that can command other units.
* @deprecated This mechanic is likely to be removed or completely reworked in the future.
* */
@Deprecated
@Component
abstract class CommanderComp implements Entityc, Posc{
private static final Seq<FormationMember> members = new Seq<>();
private static final Seq<Unit> units = new Seq<>();
@Import float x, y, rotation, hitSize;
@Import Team team;
@Import UnitType type;
transient @Nullable Formation formation;
transient Seq<Unit> controlling = new Seq<>(10);
/** minimum speed of any unit in the formation. */
transient float minFormationSpeed;
public void update(){
if(controlling.isEmpty() && !Vars.net.client()){
formation = null;
}
if(formation != null){
formation.anchor.set(x, y, 0);
formation.updateSlots();
controlling.removeAll(u -> u.dead || !(u.controller() instanceof FormationAI ai && ai.leader == self()));
}
}
public void remove(){
clearCommand();
}
public void killed(){
clearCommand();
}
//make sure to reset command state when the controller is switched
public void controller(UnitController next){
clearCommand();
}
void commandNearby(FormationPattern pattern){
commandNearby(pattern, u -> true);
}
void commandNearby(FormationPattern pattern, Boolf<Unit> include){
Formation formation = new Formation(new Vec3(x, y, rotation), pattern);
formation.slotAssignmentStrategy = new DistanceAssignmentStrategy(pattern);
units.clear();
Units.nearby(team, x, y, type.commandRadius, u -> {
if(u.isAI() && include.get(u) && u != self() && u.type.flying == type.flying && u.hitSize <= hitSize * 1.1f && u.type.playerControllable){
units.add(u);
}
});
if(units.isEmpty()) return;
//sort by hitbox size, then by distance
units.sort(Structs.comps(Structs.comparingFloat(u -> -u.hitSize), Structs.comparingFloat(u -> u.dst2(this))));
units.truncate(type.commandLimit);
command(formation, units);
}
void command(Formation formation, Seq<Unit> units){
clearCommand();
units.shuffle();
float spacing = hitSize * 0.9f;
minFormationSpeed = type.speed;
controlling.addAll(units);
for(Unit unit : units){
FormationAI ai;
unit.controller(ai = new FormationAI(self(), formation));
spacing = Math.max(spacing, ai.formationSize());
minFormationSpeed = Math.min(minFormationSpeed, unit.type.speed);
}
this.formation = formation;
//update formation spacing based on max size
formation.pattern.spacing = spacing;
members.clear();
for(Unitc u : units){
members.add((FormationAI)u.controller());
}
//TODO doesn't handle units that don't fit a formation
formation.addMembers(members);
}
boolean isCommanding(){
return formation != null;
}
void clearCommand(){
//reset controlled units
for(Unit unit : controlling){
if(unit.controller().isBeingControlled(self())){
unit.controller(unit.type.createController(unit));
}
}
controlling.clear();
formation = null;
}
}

View File

@@ -124,12 +124,8 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
unit.aim(mouseX, mouseY);
//this is only necessary when the thing being controlled isn't synced
unit.controlWeapons(shooting, shooting);
//save previous formation to prevent reset
var formation = unit.formation;
//extra precaution, necessary for non-synced things
unit.controller(this);
//keep previous formation
unit.formation = formation;
}
@Override

View File

@@ -1,7 +1,6 @@
package mindustry.entities.comp;
import arc.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
@@ -32,10 +31,10 @@ import static mindustry.Vars.*;
import static mindustry.logic.GlobalConstants.*;
@Component(base = true)
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc, Builderc{
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable, Ranged, Minerc, Builderc{
@Import boolean hovering, dead, disarmed;
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed, dragMultiplier;
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, dragMultiplier;
@Import Team team;
@Import int id;
@Import @Nullable Tile mineTile;
@@ -120,14 +119,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
public float speed(){
float strafePenalty = isGrounded() || !isPlayer() ? 1f : Mathf.lerp(1f, type.strafePenalty, Angles.angleDist(vel().angle(), rotation) / 180f);
float boost = Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, elevation);
//limit speed to minimum formation speed to preserve formation
return (isCommanding() ? minFormationSpeed * 0.98f : type.speed) * strafePenalty * boost * floorSpeedMultiplier();
}
/** Iterates through this unit and everything it is controlling. */
public void eachGroup(Cons<Unit> cons){
cons.get(self());
controlling().each(cons);
return type.speed * strafePenalty * boost * floorSpeedMultiplier();
}
/** @return where the unit wants to look at. */
@@ -185,9 +177,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case controlled -> !isValid() ? 0 :
controller instanceof LogicAI ? ctrlProcessor :
controller instanceof Player ? ctrlPlayer :
controller instanceof FormationAI ? ctrlFormation :
0;
case commanded -> controller instanceof FormationAI && isValid() ? 1 : 0;
case payloadCount -> ((Object)this) instanceof Payloadc pay ? pay.payloads().size : 0;
case size -> hitSize / tilesize;
case color -> Color.toDoubleBits(team.color.r, team.color.g, team.color.b, 1f);
@@ -201,7 +191,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case type -> type;
case name -> controller instanceof Player p ? p.name : null;
case firstItem -> stack().amount == 0 ? null : item();
case controller -> !isValid() ? null : controller instanceof LogicAI log ? log.controller : controller instanceof FormationAI form ? form.leader : this;
case controller -> !isValid() ? null : controller instanceof LogicAI log ? log.controller : this;
case payloadType -> ((Object)this) instanceof Payloadc pay ?
(pay.payloads().isEmpty() ? null :
pay.payloads().peek() instanceof UnitPayload p1 ? p1.unit.type :
@@ -559,12 +549,11 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
remove();
}
/** @return name of direct or indirect player controller. */
/** @return name of direct or indirect player controller. TODO comamnd support*/
@Override
public @Nullable String getControllerName(){
if(isPlayer()) return getPlayer().name;
if(controller instanceof LogicAI ai && ai.controller != null) return ai.controller.lastAccessed;
if(controller instanceof FormationAI ai && ai.leader != null && ai.leader.isPlayer()) return ai.leader.getPlayer().name;
return null;
}