Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13969bdd29 | ||
|
|
a3f5583326 | ||
|
|
f137c11c6c | ||
|
|
8d6afbd80d | ||
|
|
c46fa206f6 | ||
|
|
e8da206389 | ||
|
|
b2b8cf2357 | ||
|
|
a4fd88a440 | ||
|
|
a1624f61ae | ||
|
|
5ee26fc3f4 | ||
|
|
93ffb66e59 |
Binary file not shown.
@@ -95,7 +95,7 @@ public class WaveSpawner{
|
|||||||
|
|
||||||
Time.run(Math.min(i * 5, 60 * 2), () -> shockwave(unit));
|
Time.run(Math.min(i * 5, 60 * 2), () -> shockwave(unit));
|
||||||
}
|
}
|
||||||
Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize));
|
Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize, state.rules.dropZoneRadius));
|
||||||
//would be interesting to see player structures survive this without hacks
|
//would be interesting to see player structures survive this without hacks
|
||||||
Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, state.rules.dropZoneRadius, 99999999f, true));
|
Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, state.rules.dropZoneRadius, 99999999f, true));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -862,6 +862,7 @@ public class Blocks implements ContentList{
|
|||||||
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 150, Items.silicon, 250));
|
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 150, Items.silicon, 250));
|
||||||
size = 3;
|
size = 3;
|
||||||
consumes.item(Items.phasefabric).boost();
|
consumes.item(Items.phasefabric).boost();
|
||||||
|
consumes.power(3f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
shockMine = new ShockMine("shock-mine"){{
|
shockMine = new ShockMine("shock-mine"){{
|
||||||
@@ -935,6 +936,7 @@ public class Blocks implements ContentList{
|
|||||||
itemCapacity = 120;
|
itemCapacity = 120;
|
||||||
reloadTime = 200f;
|
reloadTime = 200f;
|
||||||
range = 440f;
|
range = 440f;
|
||||||
|
consumes.power(2f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
@@ -1029,13 +1031,13 @@ public class Blocks implements ContentList{
|
|||||||
|
|
||||||
battery = new Battery("battery"){{
|
battery = new Battery("battery"){{
|
||||||
requirements(Category.power, ItemStack.with(Items.copper, 8, Items.lead, 40));
|
requirements(Category.power, ItemStack.with(Items.copper, 8, Items.lead, 40));
|
||||||
consumes.powerBuffered(4000f, 1f);
|
consumes.powerBuffered(4000f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
batteryLarge = new Battery("battery-large"){{
|
batteryLarge = new Battery("battery-large"){{
|
||||||
requirements(Category.power, ItemStack.with(Items.titanium, 40, Items.lead, 80, Items.silicon, 40));
|
requirements(Category.power, ItemStack.with(Items.titanium, 40, Items.lead, 80, Items.silicon, 40));
|
||||||
size = 3;
|
size = 3;
|
||||||
consumes.powerBuffered(50000f, 1f);
|
consumes.powerBuffered(50000f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
combustionGenerator = new BurnerGenerator("combustion-generator"){{
|
combustionGenerator = new BurnerGenerator("combustion-generator"){{
|
||||||
@@ -1375,8 +1377,7 @@ public class Blocks implements ContentList{
|
|||||||
recoil = 2f;
|
recoil = 2f;
|
||||||
reload = 90f;
|
reload = 90f;
|
||||||
cooldown = 0.03f;
|
cooldown = 0.03f;
|
||||||
powerUsed = 1 / 3f;
|
powerUse = 2.5f;
|
||||||
consumes.powerBuffered(600f);
|
|
||||||
shootShake = 2f;
|
shootShake = 2f;
|
||||||
shootEffect = Fx.lancerLaserShoot;
|
shootEffect = Fx.lancerLaserShoot;
|
||||||
smokeEffect = Fx.lancerLaserShootSmoke;
|
smokeEffect = Fx.lancerLaserShootSmoke;
|
||||||
@@ -1394,9 +1395,8 @@ public class Blocks implements ContentList{
|
|||||||
reload = 24f;
|
reload = 24f;
|
||||||
shootCone = 40f;
|
shootCone = 40f;
|
||||||
rotatespeed = 8f;
|
rotatespeed = 8f;
|
||||||
powerUsed = 1f / 2f;
|
powerUse = 0.9f;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
consumes.powerBuffered(60f, 60f);
|
|
||||||
range = 95f;
|
range = 95f;
|
||||||
shootEffect = Fx.lightningShoot;
|
shootEffect = Fx.lightningShoot;
|
||||||
heatColor = Color.RED;
|
heatColor = Color.RED;
|
||||||
@@ -1540,10 +1540,9 @@ public class Blocks implements ContentList{
|
|||||||
reload = 50f;
|
reload = 50f;
|
||||||
firingMoveFract = 0.5f;
|
firingMoveFract = 0.5f;
|
||||||
shootDuration = 220f;
|
shootDuration = 220f;
|
||||||
powerUsed = 1f / 2f;
|
powerUse = 10f;
|
||||||
|
|
||||||
health = 200 * size * size;
|
health = 200 * size * size;
|
||||||
consumes.powerBuffered(1200f);
|
|
||||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.5f)).update(false);
|
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.5f)).update(false);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
@@ -1637,6 +1636,7 @@ public class Blocks implements ContentList{
|
|||||||
repairPoint = new RepairPoint("repair-point"){{
|
repairPoint = new RepairPoint("repair-point"){{
|
||||||
requirements(Category.units, ItemStack.with(Items.lead, 30, Items.copper, 30, Items.silicon, 30));
|
requirements(Category.units, ItemStack.with(Items.lead, 30, Items.copper, 30, Items.silicon, 30));
|
||||||
repairSpeed = 0.1f;
|
repairSpeed = 0.1f;
|
||||||
|
powerUse = 1f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
@@ -1646,49 +1646,49 @@ public class Blocks implements ContentList{
|
|||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 200, Items.graphite, 100, Items.copper, 150));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 200, Items.graphite, 100, Items.copper, 150));
|
||||||
mech = Mechs.alpha;
|
mech = Mechs.alpha;
|
||||||
size = 2;
|
size = 2;
|
||||||
consumes.powerBuffered(50f);
|
consumes.power(0.5f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
deltaPad = new MechPad("delta-mech-pad"){{
|
deltaPad = new MechPad("delta-mech-pad"){{
|
||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 350, Items.titanium, 350, Items.copper, 400, Items.silicon, 450, Items.thorium, 300));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 350, Items.titanium, 350, Items.copper, 400, Items.silicon, 450, Items.thorium, 300));
|
||||||
mech = Mechs.delta;
|
mech = Mechs.delta;
|
||||||
size = 2;
|
size = 2;
|
||||||
consumes.powerBuffered(70f);
|
consumes.power(0.7f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
tauPad = new MechPad("tau-mech-pad"){{
|
tauPad = new MechPad("tau-mech-pad"){{
|
||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 250, Items.titanium, 250, Items.copper, 250, Items.silicon, 250));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 250, Items.titanium, 250, Items.copper, 250, Items.silicon, 250));
|
||||||
mech = Mechs.tau;
|
mech = Mechs.tau;
|
||||||
size = 2;
|
size = 2;
|
||||||
consumes.powerBuffered(100f);
|
consumes.power(1f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
omegaPad = new MechPad("omega-mech-pad"){{
|
omegaPad = new MechPad("omega-mech-pad"){{
|
||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 450, Items.graphite, 550, Items.silicon, 650, Items.thorium, 600, Items.surgealloy, 240));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 450, Items.graphite, 550, Items.silicon, 650, Items.thorium, 600, Items.surgealloy, 240));
|
||||||
mech = Mechs.omega;
|
mech = Mechs.omega;
|
||||||
size = 3;
|
size = 3;
|
||||||
consumes.powerBuffered(120f);
|
consumes.power(1.2f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
javelinPad = new MechPad("javelin-ship-pad"){{
|
javelinPad = new MechPad("javelin-ship-pad"){{
|
||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 350, Items.silicon, 450, Items.titanium, 500, Items.plastanium, 400, Items.phasefabric, 200));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 350, Items.silicon, 450, Items.titanium, 500, Items.plastanium, 400, Items.phasefabric, 200));
|
||||||
mech = Mechs.javelin;
|
mech = Mechs.javelin;
|
||||||
size = 2;
|
size = 2;
|
||||||
consumes.powerBuffered(80f);
|
consumes.power(0.8f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
tridentPad = new MechPad("trident-ship-pad"){{
|
tridentPad = new MechPad("trident-ship-pad"){{
|
||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 250, Items.copper, 250, Items.silicon, 250, Items.titanium, 300, Items.plastanium, 200));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 250, Items.copper, 250, Items.silicon, 250, Items.titanium, 300, Items.plastanium, 200));
|
||||||
mech = Mechs.trident;
|
mech = Mechs.trident;
|
||||||
size = 2;
|
size = 2;
|
||||||
consumes.powerBuffered(100f);
|
consumes.power(1f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
glaivePad = new MechPad("glaive-ship-pad"){{
|
glaivePad = new MechPad("glaive-ship-pad"){{
|
||||||
requirements(Category.upgrade, ItemStack.with(Items.lead, 450, Items.silicon, 650, Items.titanium, 700, Items.plastanium, 600, Items.surgealloy, 200));
|
requirements(Category.upgrade, ItemStack.with(Items.lead, 450, Items.silicon, 650, Items.titanium, 700, Items.plastanium, 600, Items.surgealloy, 200));
|
||||||
mech = Mechs.glaive;
|
mech = Mechs.glaive;
|
||||||
size = 3;
|
size = 3;
|
||||||
consumes.powerBuffered(120f);
|
consumes.power(1.2f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|||||||
@@ -583,7 +583,7 @@ public class Fx implements ContentList{
|
|||||||
spawnShockwave = new Effect(20f, 400f, e -> {
|
spawnShockwave = new Effect(20f, 400f, e -> {
|
||||||
Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin());
|
Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin());
|
||||||
Lines.stroke(e.fout() * 3f + 0.5f);
|
Lines.stroke(e.fout() * 3f + 0.5f);
|
||||||
Lines.poly(e.x, e.y, 60, e.fin() * 450f);
|
Lines.poly(e.x, e.y, 60, e.fin() * (e.rotation + 50f));
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -416,8 +416,6 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
Draw.color(0f, 0f, 0f, 0.3f * (textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime));
|
Draw.color(0f, 0f, 0f, 0.3f * (textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime));
|
||||||
Fill.rect(x, y + textHeight + layout.height - layout.height/2f, layout.width + 2, layout.height + 3);
|
Fill.rect(x, y + textHeight + layout.height - layout.height/2f, layout.width + 2, layout.height + 3);
|
||||||
font.draw(text, x - width/2f, y + textHeight + layout.height, width, Align.center, true);
|
font.draw(text, x - width/2f, y + textHeight + layout.height, width, Align.center, true);
|
||||||
|
|
||||||
textFadeTime -= Time.delta() / (60 * 5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
@@ -494,6 +492,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
hitTime -= Time.delta();
|
hitTime -= Time.delta();
|
||||||
|
textFadeTime -= Time.delta() / (60 * 5);
|
||||||
|
|
||||||
if(Float.isNaN(x) || Float.isNaN(y)){
|
if(Float.isNaN(x) || Float.isNaN(y)){
|
||||||
velocity.set(0f, 0f);
|
velocity.set(0f, 0f);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class UnitDrops{
|
|||||||
|
|
||||||
TileEntity core = unit.getClosestEnemyCore();
|
TileEntity core = unit.getClosestEnemyCore();
|
||||||
|
|
||||||
if(core == null){
|
if(core == null || core.dst(unit) > Vars.mineTransferRange){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,8 +37,9 @@ public class UnitDrops{
|
|||||||
if(Mathf.chance(0.03)){
|
if(Mathf.chance(0.03)){
|
||||||
int amount = Mathf.random(20, 40);
|
int amount = Mathf.random(20, 40);
|
||||||
amount = core.tile.block().acceptStack(item, amount, core.tile, null);
|
amount = core.tile.block().acceptStack(item, amount, core.tile, null);
|
||||||
if(amount > 0)
|
if(amount > 0){
|
||||||
Call.transferItemTo(item, amount, unit.x + Mathf.range(2f), unit.y + Mathf.range(2f), core.tile);
|
Call.transferItemTo(item, amount, unit.x + Mathf.range(2f), unit.y + Mathf.range(2f), core.tile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,6 @@ public class DefaultWaves{
|
|||||||
begin = 16;
|
begin = 16;
|
||||||
unitScaling = 1;
|
unitScaling = 1;
|
||||||
spacing = 2;
|
spacing = 2;
|
||||||
|
|
||||||
max = 12;
|
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(UnitTypes.dagger){{
|
new SpawnGroup(UnitTypes.dagger){{
|
||||||
@@ -119,8 +117,7 @@ public class DefaultWaves{
|
|||||||
begin = 40;
|
begin = 40;
|
||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
spacing = 2;
|
spacing = 2;
|
||||||
unitScaling = 3;
|
unitScaling = 2;
|
||||||
max = 8;
|
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(UnitTypes.wraith){{
|
new SpawnGroup(UnitTypes.wraith){{
|
||||||
@@ -129,7 +126,6 @@ public class DefaultWaves{
|
|||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 5;
|
spacing = 5;
|
||||||
effect = StatusEffects.overdrive;
|
effect = StatusEffects.overdrive;
|
||||||
max = 8;
|
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(UnitTypes.revenant){{
|
new SpawnGroup(UnitTypes.revenant){{
|
||||||
@@ -137,7 +133,7 @@ public class DefaultWaves{
|
|||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 5;
|
spacing = 5;
|
||||||
max = 8;
|
max = 16;
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(UnitTypes.ghoul){{
|
new SpawnGroup(UnitTypes.ghoul){{
|
||||||
@@ -145,7 +141,6 @@ public class DefaultWaves{
|
|||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 4;
|
spacing = 4;
|
||||||
max = 8;
|
|
||||||
}},
|
}},
|
||||||
|
|
||||||
new SpawnGroup(UnitTypes.eruptor){{
|
new SpawnGroup(UnitTypes.eruptor){{
|
||||||
@@ -181,7 +176,6 @@ public class DefaultWaves{
|
|||||||
unitAmount = 2;
|
unitAmount = 2;
|
||||||
unitScaling = 3;
|
unitScaling = 3;
|
||||||
spacing = 4;
|
spacing = 4;
|
||||||
max = 8;
|
|
||||||
}}
|
}}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.anuke.arc.graphics.g2d.Lines;
|
|||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.math.geom.Geometry;
|
import io.anuke.arc.math.geom.Geometry;
|
||||||
import io.anuke.arc.math.geom.Point2;
|
import io.anuke.arc.math.geom.Point2;
|
||||||
|
import io.anuke.arc.scene.ui.TextField;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.graphics.Pal;
|
import io.anuke.mindustry.graphics.Pal;
|
||||||
@@ -17,6 +18,7 @@ import io.anuke.mindustry.net.Net;
|
|||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
|
import static io.anuke.arc.Core.scene;
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
import static io.anuke.mindustry.input.PlaceMode.*;
|
import static io.anuke.mindustry.input.PlaceMode.*;
|
||||||
|
|
||||||
@@ -130,7 +132,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
player.isShooting = false;
|
player.isShooting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !ui.chatfrag.chatOpen()){
|
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
|
||||||
if(!ui.minimap.isShown()){
|
if(!ui.minimap.isShown()){
|
||||||
ui.minimap.show();
|
ui.minimap.show();
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -214,12 +214,13 @@ public class TypeIO{
|
|||||||
|
|
||||||
@WriteClass(Liquid.class)
|
@WriteClass(Liquid.class)
|
||||||
public static void writeLiquid(ByteBuffer buffer, Liquid liquid){
|
public static void writeLiquid(ByteBuffer buffer, Liquid liquid){
|
||||||
buffer.put(liquid.id);
|
buffer.put(liquid == null ? -1 : liquid.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ReadClass(Liquid.class)
|
@ReadClass(Liquid.class)
|
||||||
public static Liquid readLiquid(ByteBuffer buffer){
|
public static Liquid readLiquid(ByteBuffer buffer){
|
||||||
return content.liquid(buffer.get());
|
byte id = buffer.get();
|
||||||
|
return id == -1 ? null : content.liquid(buffer.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@WriteClass(BulletType.class)
|
@WriteClass(BulletType.class)
|
||||||
|
|||||||
@@ -328,6 +328,10 @@ public class Block extends BlockStorage{
|
|||||||
setBars();
|
setBars();
|
||||||
|
|
||||||
consumes.init();
|
consumes.init();
|
||||||
|
|
||||||
|
if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){
|
||||||
|
throw new IllegalArgumentException("Consumer using buffered power: " + name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -433,8 +437,8 @@ public class Block extends BlockStorage{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(hasPower && consumes.hasPower()){
|
if(hasPower && consumes.hasPower()){
|
||||||
boolean buffered = consumes.getPower().isBuffered;
|
boolean buffered = consumes.getPower().buffered;
|
||||||
float capacity = consumes.getPower().powerCapacity;
|
float capacity = consumes.getPower().capacity;
|
||||||
|
|
||||||
bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power.satisfaction * capacity) ? "<ERROR>" : (int)(entity.power.satisfaction * capacity)) :
|
bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power.satisfaction * capacity) ? "<ERROR>" : (int)(entity.power.satisfaction * capacity)) :
|
||||||
Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> entity.power.satisfaction));
|
Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> entity.power.satisfaction));
|
||||||
@@ -488,8 +492,8 @@ public class Block extends BlockStorage{
|
|||||||
explosiveness += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 2f);
|
explosiveness += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(consumes.hasPower() && consumes.getPower().isBuffered){
|
if(consumes.hasPower() && consumes.getPower().buffered){
|
||||||
power += tile.entity.power.satisfaction * consumes.getPower().powerCapacity;
|
power += tile.entity.power.satisfaction * consumes.getPower().capacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hasLiquids){
|
if(hasLiquids){
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ public class ForceProjector extends Block{
|
|||||||
protected float cooldownBrokenBase = 0.35f;
|
protected float cooldownBrokenBase = 0.35f;
|
||||||
protected float basePowerDraw = 0.2f;
|
protected float basePowerDraw = 0.2f;
|
||||||
protected float powerDamage = 0.1f;
|
protected float powerDamage = 0.1f;
|
||||||
protected final ConsumeForceProjectorPower consumePower;
|
|
||||||
protected TextureRegion topRegion;
|
protected TextureRegion topRegion;
|
||||||
|
|
||||||
private static Tile paramTile;
|
private static Tile paramTile;
|
||||||
@@ -45,13 +44,7 @@ public class ForceProjector extends Block{
|
|||||||
if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && paramBlock.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){
|
if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && paramBlock.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){
|
||||||
trait.absorb();
|
trait.absorb();
|
||||||
Effects.effect(Fx.absorb, trait);
|
Effects.effect(Fx.absorb, trait);
|
||||||
float relativeDamagePowerDraw = trait.getShieldDamage() * paramBlock.powerDamage / paramBlock.consumePower.powerCapacity;
|
|
||||||
paramEntity.hit = 1f;
|
paramEntity.hit = 1f;
|
||||||
|
|
||||||
paramEntity.power.satisfaction -= Math.min(relativeDamagePowerDraw, paramEntity.power.satisfaction);
|
|
||||||
if(paramEntity.power.satisfaction <= 0.0001f){
|
|
||||||
paramEntity.buildup += trait.getShieldDamage() * paramEntity.warmup * 2f;
|
|
||||||
}
|
|
||||||
paramEntity.buildup += trait.getShieldDamage() * paramEntity.warmup;
|
paramEntity.buildup += trait.getShieldDamage() * paramEntity.warmup;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -65,8 +58,6 @@ public class ForceProjector extends Block{
|
|||||||
hasLiquids = true;
|
hasLiquids = true;
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).boost().update(false);
|
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).boost().update(false);
|
||||||
consumePower = new ConsumeForceProjectorPower(60f, 60f);
|
|
||||||
consumes.add(consumePower);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -126,10 +117,7 @@ public class ForceProjector extends Block{
|
|||||||
// - There is not enough base power in the buffer => Draw all power and break shield
|
// - There is not enough base power in the buffer => Draw all power and break shield
|
||||||
// - The generator is in the AI base and uses cheat mode => Only draw power from shots being absorbed
|
// - The generator is in the AI base and uses cheat mode => Only draw power from shots being absorbed
|
||||||
|
|
||||||
float relativePowerDraw = 0.0f;
|
float relativePowerDraw = cheat ? 0f : 1f;
|
||||||
if(!cheat){
|
|
||||||
relativePowerDraw = basePowerDraw / consumePower.powerCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entity.power.satisfaction < relativePowerDraw){
|
if(entity.power.satisfaction < relativePowerDraw){
|
||||||
entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f);
|
entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f);
|
||||||
@@ -139,7 +127,6 @@ public class ForceProjector extends Block{
|
|||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f);
|
entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f);
|
||||||
entity.power.satisfaction -= Math.min(entity.power.satisfaction, relativePowerDraw * Time.delta());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(entity.buildup > 0){
|
if(entity.buildup > 0){
|
||||||
@@ -271,7 +258,6 @@ public class ForceProjector extends Block{
|
|||||||
|
|
||||||
public void drawSimple(){
|
public void drawSimple(){
|
||||||
if(realRadius(entity) < 0.5f) return;
|
if(realRadius(entity) < 0.5f) return;
|
||||||
;
|
|
||||||
|
|
||||||
float rad = realRadius(entity);
|
float rad = realRadius(entity);
|
||||||
|
|
||||||
@@ -289,15 +275,4 @@ public class ForceProjector extends Block{
|
|||||||
return shieldGroup;
|
return shieldGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConsumeForceProjectorPower extends ConsumePower{
|
|
||||||
public ConsumeForceProjectorPower(float powerCapacity, float ticksToFill){
|
|
||||||
super(powerCapacity / ticksToFill, powerCapacity, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean valid(TileEntity entity){
|
|
||||||
return entity.power.satisfaction >= basePowerDraw / powerCapacity && super.valid(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,10 @@ package io.anuke.mindustry.world.blocks.defense.turrets;
|
|||||||
|
|
||||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.meta.BlockStat;
|
|
||||||
import io.anuke.mindustry.world.meta.StatUnit;
|
|
||||||
|
|
||||||
public abstract class PowerTurret extends CooledTurret{
|
public abstract class PowerTurret extends CooledTurret{
|
||||||
/** The percentage of power which will be used per shot. */
|
|
||||||
protected float powerUsed = 0.5f;
|
|
||||||
protected BulletType shootType;
|
protected BulletType shootType;
|
||||||
|
protected float powerUse = 1f;
|
||||||
|
|
||||||
public PowerTurret(String name){
|
public PowerTurret(String name){
|
||||||
super(name);
|
super(name);
|
||||||
@@ -16,28 +13,30 @@ public abstract class PowerTurret extends CooledTurret{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStats(){
|
public void init(){
|
||||||
super.setStats();
|
consumes.powerCond(powerUse, entity -> ((TurretEntity)entity).target != null);
|
||||||
|
super.init();
|
||||||
stats.add(BlockStat.powerShot, powerUsed * consumes.getPower().powerCapacity, StatUnit.powerUnits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasAmmo(Tile tile){
|
|
||||||
// Allow shooting as long as the turret is at least at 50% power
|
|
||||||
return tile.entity.power.satisfaction >= powerUsed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BulletType useAmmo(Tile tile){
|
public BulletType useAmmo(Tile tile){
|
||||||
if(tile.isEnemyCheat()) return shootType;
|
//nothing used directly
|
||||||
// Make sure that power can not go negative in case of threading issues or similar
|
|
||||||
tile.entity.power.satisfaction -= Math.min(powerUsed, tile.entity.power.satisfaction);
|
|
||||||
return shootType;
|
return shootType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAmmo(Tile tile){
|
||||||
|
//only shoot if there's power
|
||||||
|
return tile.entity.cons.valid();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BulletType peekAmmo(Tile tile){
|
public BulletType peekAmmo(Tile tile){
|
||||||
return shootType;
|
return shootType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float baseReloadSpeed(Tile tile){
|
||||||
|
return tile.entity.power.satisfaction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,7 @@ public abstract class Turret extends Block{
|
|||||||
|
|
||||||
protected TextureRegion baseRegion, heatRegion;
|
protected TextureRegion baseRegion, heatRegion;
|
||||||
|
|
||||||
protected BiConsumer<Tile, TurretEntity> drawer = (tile, entity) ->
|
protected BiConsumer<Tile, TurretEntity> drawer = (tile, entity) -> Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||||
Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
|
||||||
protected BiConsumer<Tile, TurretEntity> heatDrawer = (tile, entity) -> {
|
protected BiConsumer<Tile, TurretEntity> heatDrawer = (tile, entity) -> {
|
||||||
if(entity.heat <= 0.00001f) return;
|
if(entity.heat <= 0.00001f) return;
|
||||||
Draw.color(heatColor, entity.heat);
|
Draw.color(heatColor, entity.heat);
|
||||||
@@ -195,8 +194,7 @@ public abstract class Turret extends Block{
|
|||||||
protected void findTarget(Tile tile){
|
protected void findTarget(Tile tile){
|
||||||
TurretEntity entity = tile.entity();
|
TurretEntity entity = tile.entity();
|
||||||
|
|
||||||
entity.target = Units.closestTarget(tile.getTeam(),
|
entity.target = Units.closestTarget(tile.getTeam(), tile.drawx(), tile.drawy(), range, e -> !e.isDead() && (!e.isFlying() || targetAir) && (e.isFlying() || targetGround));
|
||||||
tile.drawx(), tile.drawy(), range, e -> !e.isDead() && (!e.isFlying() || targetAir) && (e.isFlying() || targetGround));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void turnToTarget(Tile tile, float targetRot){
|
protected void turnToTarget(Tile tile, float targetRot){
|
||||||
@@ -248,7 +246,7 @@ public abstract class Turret extends Block{
|
|||||||
|
|
||||||
entity.reload = 0f;
|
entity.reload = 0f;
|
||||||
}else{
|
}else{
|
||||||
entity.reload += tile.entity.delta() * peekAmmo(tile).reloadMultiplier;
|
entity.reload += tile.entity.delta() * peekAmmo(tile).reloadMultiplier * baseReloadSpeed(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,6 +294,10 @@ public abstract class Turret extends Block{
|
|||||||
tile.drawy() - Angles.trnsy(entity.rotation, ammoEjectBack), entity.rotation);
|
tile.drawy() - Angles.trnsy(entity.rotation, ammoEjectBack), entity.rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected float baseReloadSpeed(Tile tile){
|
||||||
|
return 1f;
|
||||||
|
}
|
||||||
|
|
||||||
protected boolean isTurret(Tile tile){
|
protected boolean isTurret(Tile tile){
|
||||||
return (tile.entity instanceof TurretEntity);
|
return (tile.entity instanceof TurretEntity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public class Junction extends Block{
|
|||||||
if(entity == null || relative == -1 || entity.buffers[relative].full())
|
if(entity == null || relative == -1 || entity.buffers[relative].full())
|
||||||
return false;
|
return false;
|
||||||
Tile to = tile.getNearby(relative);
|
Tile to = tile.getNearby(relative);
|
||||||
return to != null && to.target().block().hasItems;
|
return to != null && to.target().entity != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public class MassDriver extends Block{
|
|||||||
protected Effect smokeEffect = Fx.shootBigSmoke2;
|
protected Effect smokeEffect = Fx.shootBigSmoke2;
|
||||||
protected Effect recieveEffect = Fx.mineBig;
|
protected Effect recieveEffect = Fx.mineBig;
|
||||||
protected float shake = 3f;
|
protected float shake = 3f;
|
||||||
protected float powerPercentageUsed = 0.95f;
|
|
||||||
protected TextureRegion baseRegion;
|
protected TextureRegion baseRegion;
|
||||||
|
|
||||||
public MassDriver(String name){
|
public MassDriver(String name){
|
||||||
@@ -52,7 +51,6 @@ public class MassDriver extends Block{
|
|||||||
hasItems = true;
|
hasItems = true;
|
||||||
layer = Layer.turret;
|
layer = Layer.turret;
|
||||||
hasPower = true;
|
hasPower = true;
|
||||||
consumes.powerBuffered(30f);
|
|
||||||
outlineIcon = true;
|
outlineIcon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,13 +72,6 @@ public class MassDriver extends Block{
|
|||||||
baseRegion = Core.atlas.find(name + "-base");
|
baseRegion = Core.atlas.find(name + "-base");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setStats(){
|
|
||||||
super.setStats();
|
|
||||||
|
|
||||||
stats.add(BlockStat.powerShot, consumes.getPower().powerCapacity * powerPercentageUsed, StatUnit.powerUnits);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Tile tile){
|
public void update(Tile tile){
|
||||||
MassDriverEntity entity = tile.entity();
|
MassDriverEntity entity = tile.entity();
|
||||||
@@ -112,6 +103,11 @@ public class MassDriver extends Block{
|
|||||||
tryDump(tile);
|
tryDump(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//skip when there's no power
|
||||||
|
if(!entity.cons.valid()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(entity.state == DriverState.accepting){
|
if(entity.state == DriverState.accepting){
|
||||||
//if there's nothing shooting at this, bail
|
//if there's nothing shooting at this, bail
|
||||||
if(entity.currentShooter() == null){
|
if(entity.currentShooter() == null){
|
||||||
@@ -132,7 +128,6 @@ public class MassDriver extends Block{
|
|||||||
|
|
||||||
if(
|
if(
|
||||||
tile.entity.items.total() >= minDistribute && //must shoot minimum amount of items
|
tile.entity.items.total() >= minDistribute && //must shoot minimum amount of items
|
||||||
tile.entity.power.satisfaction >= powerPercentageUsed && //must have power
|
|
||||||
link.block().itemCapacity - link.entity.items.total() >= minDistribute && //must have minimum amount of space
|
link.block().itemCapacity - link.entity.items.total() >= minDistribute && //must have minimum amount of space
|
||||||
entity.reload <= 0.0001f //must have reloaded
|
entity.reload <= 0.0001f //must have reloaded
|
||||||
){
|
){
|
||||||
@@ -235,7 +230,6 @@ public class MassDriver extends Block{
|
|||||||
|
|
||||||
//reset reload, use power.
|
//reset reload, use power.
|
||||||
entity.reload = 1f;
|
entity.reload = 1f;
|
||||||
entity.power.satisfaction -= Math.min(entity.power.satisfaction, powerPercentageUsed);
|
|
||||||
|
|
||||||
DriverBulletData data = Pools.obtain(DriverBulletData.class, DriverBulletData::new);
|
DriverBulletData data = Pools.obtain(DriverBulletData.class, DriverBulletData::new);
|
||||||
data.from = entity;
|
data.from = entity;
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package io.anuke.mindustry.world.blocks.power;
|
||||||
|
|
||||||
|
import io.anuke.arc.function.Predicate;
|
||||||
|
import io.anuke.mindustry.entities.type.TileEntity;
|
||||||
|
import io.anuke.mindustry.world.consumers.ConsumePower;
|
||||||
|
|
||||||
|
/** A power consumer that only activates sometimes. */
|
||||||
|
public class ConditionalConsumePower extends ConsumePower{
|
||||||
|
private final Predicate<TileEntity> consume;
|
||||||
|
|
||||||
|
public ConditionalConsumePower(float usage, Predicate<TileEntity> consume){
|
||||||
|
super(usage, 0, false);
|
||||||
|
this.consume = consume;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float requestedPower(TileEntity entity){
|
||||||
|
return consume.test(entity) ? usage : 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -58,7 +58,7 @@ public class ImpactReactor extends PowerGenerator{
|
|||||||
|
|
||||||
bars.add("poweroutput", entity -> new Bar(() ->
|
bars.add("poweroutput", entity -> new Bar(() ->
|
||||||
Core.bundle.format("bar.poweroutput",
|
Core.bundle.format("bar.poweroutput",
|
||||||
Strings.fixed(Math.max(entity.block.getPowerProduction(entity.tile) - consumes.getPower().powerPerTick, 0) * 60 * entity.timeScale, 1)),
|
Strings.fixed(Math.max(entity.block.getPowerProduction(entity.tile) - consumes.getPower().usage, 0) * 60 * entity.timeScale, 1)),
|
||||||
() -> Pal.powerBar,
|
() -> Pal.powerBar,
|
||||||
() -> ((GeneratorEntity)entity).productionEfficiency));
|
() -> ((GeneratorEntity)entity).productionEfficiency));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class PowerGraph{
|
|||||||
if(consumes.hasPower()){
|
if(consumes.hasPower()){
|
||||||
ConsumePower consumePower = consumes.getPower();
|
ConsumePower consumePower = consumes.getPower();
|
||||||
if(otherConsumersAreValid(consumer, consumePower)){
|
if(otherConsumersAreValid(consumer, consumePower)){
|
||||||
powerNeeded += consumePower.requestedPower(consumer.block(), consumer.entity) * consumer.entity.delta();
|
powerNeeded += consumePower.requestedPower(consumer.entity) * consumer.entity.delta();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,7 +64,7 @@ public class PowerGraph{
|
|||||||
for(Tile battery : batteries){
|
for(Tile battery : batteries){
|
||||||
Consumers consumes = battery.block().consumes;
|
Consumers consumes = battery.block().consumes;
|
||||||
if(consumes.hasPower()){
|
if(consumes.hasPower()){
|
||||||
totalAccumulator += battery.entity.power.satisfaction * consumes.getPower().powerCapacity;
|
totalAccumulator += battery.entity.power.satisfaction * consumes.getPower().capacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return totalAccumulator;
|
return totalAccumulator;
|
||||||
@@ -73,9 +73,9 @@ public class PowerGraph{
|
|||||||
public float getBatteryCapacity(){
|
public float getBatteryCapacity(){
|
||||||
float totalCapacity = 0f;
|
float totalCapacity = 0f;
|
||||||
for(Tile battery : batteries){
|
for(Tile battery : batteries){
|
||||||
Consumers consumes = battery.block().consumes;
|
if(battery.block().consumes.hasPower()){
|
||||||
if(consumes.hasPower()){
|
ConsumePower power = battery.block().consumes.getPower();
|
||||||
totalCapacity += consumes.getPower().requestedPower(battery.block(), battery.entity) * battery.entity.delta();
|
totalCapacity += (1f - battery.entity.power.satisfaction) * power.capacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return totalCapacity;
|
return totalCapacity;
|
||||||
@@ -91,7 +91,7 @@ public class PowerGraph{
|
|||||||
Consumers consumes = battery.block().consumes;
|
Consumers consumes = battery.block().consumes;
|
||||||
if(consumes.hasPower()){
|
if(consumes.hasPower()){
|
||||||
ConsumePower consumePower = consumes.getPower();
|
ConsumePower consumePower = consumes.getPower();
|
||||||
if(consumePower.powerCapacity > 0f){
|
if(consumePower.capacity > 0f){
|
||||||
battery.entity.power.satisfaction = Math.max(0.0f, battery.entity.power.satisfaction - consumedPowerPercentage);
|
battery.entity.power.satisfaction = Math.max(0.0f, battery.entity.power.satisfaction - consumedPowerPercentage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,15 +101,16 @@ public class PowerGraph{
|
|||||||
|
|
||||||
public float chargeBatteries(float excess){
|
public float chargeBatteries(float excess){
|
||||||
float capacity = getBatteryCapacity();
|
float capacity = getBatteryCapacity();
|
||||||
|
//how much of the missing in each battery % is charged
|
||||||
|
float chargedPercent = Math.min(excess/capacity, 1f);
|
||||||
if(Mathf.isEqual(capacity, 0f)) return 0f;
|
if(Mathf.isEqual(capacity, 0f)) return 0f;
|
||||||
|
|
||||||
for(Tile battery : batteries){
|
for(Tile battery : batteries){
|
||||||
Consumers consumes = battery.block().consumes;
|
Consumers consumes = battery.block().consumes;
|
||||||
if(consumes.hasPower()){
|
if(consumes.hasPower()){
|
||||||
ConsumePower consumePower = consumes.getPower();
|
ConsumePower consumePower = consumes.getPower();
|
||||||
if(consumePower.powerCapacity > 0f){
|
if(consumePower.capacity > 0f){
|
||||||
float additionalPowerPercentage = Math.min(1.0f, excess / consumePower.powerCapacity);
|
battery.entity.power.satisfaction += (1f-battery.entity.power.satisfaction) * chargedPercent;
|
||||||
battery.entity.power.satisfaction = Math.min(1.0f, battery.entity.power.satisfaction + additionalPowerPercentage);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,21 +118,29 @@ public class PowerGraph{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void distributePower(float needed, float produced){
|
public void distributePower(float needed, float produced){
|
||||||
//distribute even if not needed. this is because some might be requiring power but not requesting it; it updates consumers
|
//distribute even if not needed. this is because some might be requiring power but not using it; it updates consumers
|
||||||
float coverage = Mathf.isZero(needed) && Mathf.isZero(produced) ? 0f : Mathf.isZero(needed) ? 1f : Math.min(1, produced / needed);
|
float coverage = Mathf.isZero(needed) && Mathf.isZero(produced) ? 0f : Mathf.isZero(needed) ? 1f : Math.min(1, produced / needed);
|
||||||
for(Tile consumer : consumers){
|
for(Tile consumer : consumers){
|
||||||
Consumers consumes = consumer.block().consumes;
|
Consumers consumes = consumer.block().consumes;
|
||||||
if(consumes.hasPower()){
|
if(consumes.hasPower()){
|
||||||
ConsumePower consumePower = consumes.getPower();
|
ConsumePower consumePower = consumes.getPower();
|
||||||
//currently satisfies power even if it's not required yet
|
if(consumePower.buffered){
|
||||||
if(consumePower.isBuffered){
|
if(!Mathf.isZero(consumePower.capacity)){
|
||||||
if(!Mathf.isZero(consumePower.powerCapacity)){
|
|
||||||
// Add an equal percentage of power to all buffers, based on the global power coverage in this graph
|
// Add an equal percentage of power to all buffers, based on the global power coverage in this graph
|
||||||
float maximumRate = consumePower.requestedPower(consumer.block(), consumer.entity()) * coverage * consumer.entity.delta();
|
float maximumRate = consumePower.requestedPower(consumer.entity) * coverage * consumer.entity.delta();
|
||||||
consumer.entity.power.satisfaction = Mathf.clamp(consumer.entity.power.satisfaction + maximumRate / consumePower.powerCapacity);
|
consumer.entity.power.satisfaction = Mathf.clamp(consumer.entity.power.satisfaction + maximumRate / consumePower.capacity);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
consumer.entity.power.satisfaction = coverage;
|
//valid consumers get power as usual
|
||||||
|
if(otherConsumersAreValid(consumer, consumePower)){
|
||||||
|
consumer.entity.power.satisfaction = coverage;
|
||||||
|
}else{ //invalid consumers get an estimate, if they were to activate
|
||||||
|
consumer.entity.power.satisfaction = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta()));
|
||||||
|
//just in case
|
||||||
|
if(Float.isNaN(consumer.entity.power.satisfaction)){
|
||||||
|
consumer.entity.power.satisfaction = 0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,7 +180,7 @@ public class PowerGraph{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void add(Tile tile){
|
public void add(Tile tile){
|
||||||
if(tile.block().consumes.hasPower() && !tile.block().consumes.getPower().isBuffered){
|
if(tile.block().consumes.hasPower() && !tile.block().consumes.getPower().buffered){
|
||||||
//reset satisfaction to zero in case of direct consumer. There is no reason to clear power from buffered consumers.
|
//reset satisfaction to zero in case of direct consumer. There is no reason to clear power from buffered consumers.
|
||||||
tile.entity.power.satisfaction = 0.0f;
|
tile.entity.power.satisfaction = 0.0f;
|
||||||
}
|
}
|
||||||
@@ -179,7 +188,7 @@ public class PowerGraph{
|
|||||||
tile.entity.power.graph = this;
|
tile.entity.power.graph = this;
|
||||||
all.add(tile);
|
all.add(tile);
|
||||||
|
|
||||||
if(tile.block().outputsPower && tile.block().consumesPower && !tile.block().consumes.getPower().isBuffered){
|
if(tile.block().outputsPower && tile.block().consumesPower && !tile.block().consumes.getPower().buffered){
|
||||||
producers.add(tile);
|
producers.add(tile);
|
||||||
consumers.add(tile);
|
consumers.add(tile);
|
||||||
}else if(tile.block().outputsPower && tile.block().consumesPower){
|
}else if(tile.block().outputsPower && tile.block().consumesPower){
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.anuke.arc.math.geom.Geometry;
|
|||||||
import io.anuke.arc.util.Time;
|
import io.anuke.arc.util.Time;
|
||||||
import io.anuke.mindustry.Vars;
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.content.Fx;
|
import io.anuke.mindustry.content.Fx;
|
||||||
|
import io.anuke.mindustry.content.Mechs;
|
||||||
import io.anuke.mindustry.entities.Effects;
|
import io.anuke.mindustry.entities.Effects;
|
||||||
import io.anuke.mindustry.entities.traits.SpawnerTrait;
|
import io.anuke.mindustry.entities.traits.SpawnerTrait;
|
||||||
import io.anuke.mindustry.entities.type.Player;
|
import io.anuke.mindustry.entities.type.Player;
|
||||||
@@ -30,7 +31,6 @@ import static io.anuke.mindustry.Vars.tilesize;
|
|||||||
public class MechPad extends Block{
|
public class MechPad extends Block{
|
||||||
protected Mech mech;
|
protected Mech mech;
|
||||||
protected float buildTime = 60 * 5;
|
protected float buildTime = 60 * 5;
|
||||||
protected float requiredSatisfaction = 0.999f;
|
|
||||||
|
|
||||||
public MechPad(String name){
|
public MechPad(String name){
|
||||||
super(name);
|
super(name);
|
||||||
@@ -56,11 +56,8 @@ public class MechPad extends Block{
|
|||||||
if(player == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return;
|
if(player == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return;
|
||||||
|
|
||||||
MechFactoryEntity entity = tile.entity();
|
MechFactoryEntity entity = tile.entity();
|
||||||
MechPad pad = (MechPad)tile.block();
|
|
||||||
|
|
||||||
if(entity.power.satisfaction < pad.requiredSatisfaction) return;
|
if(!entity.cons.valid()) return;
|
||||||
|
|
||||||
entity.power.satisfaction -= Math.min(entity.power.satisfaction, pad.requiredSatisfaction);
|
|
||||||
player.beginRespawning(entity);
|
player.beginRespawning(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +70,8 @@ public class MechPad extends Block{
|
|||||||
Effects.effect(Fx.spawn, entity);
|
Effects.effect(Fx.spawn, entity);
|
||||||
|
|
||||||
if(entity.player == null) return;
|
if(entity.player == null) return;
|
||||||
entity.player.mech = ((MechPad)tile.block()).mech;
|
Mech mech = ((MechPad)tile.block()).mech;
|
||||||
|
entity.player.mech = entity.player.mech == mech ? Mechs.starter : mech;
|
||||||
|
|
||||||
entity.progress = 0;
|
entity.progress = 0;
|
||||||
entity.player.onRespawn(tile);
|
entity.player.onRespawn(tile);
|
||||||
@@ -102,7 +100,7 @@ public class MechPad extends Block{
|
|||||||
|
|
||||||
if(checkValidTap(tile, player)){
|
if(checkValidTap(tile, player)){
|
||||||
Call.onMechFactoryTap(player, tile);
|
Call.onMechFactoryTap(player, tile);
|
||||||
}else if(player.isLocal && mobile && !player.isDead() && (entity.power.satisfaction >= requiredSatisfaction) && entity.player == null){
|
}else if(player.isLocal && mobile && !player.isDead() && entity.cons.valid() && entity.player == null){
|
||||||
//deselect on double taps
|
//deselect on double taps
|
||||||
player.moveTarget = player.moveTarget == tile.entity ? null : tile.entity;
|
player.moveTarget = player.moveTarget == tile.entity ? null : tile.entity;
|
||||||
}
|
}
|
||||||
@@ -115,7 +113,7 @@ public class MechPad extends Block{
|
|||||||
Draw.rect(Core.atlas.find(name), tile.drawx(), tile.drawy());
|
Draw.rect(Core.atlas.find(name), tile.drawx(), tile.drawy());
|
||||||
|
|
||||||
if(entity.player != null){
|
if(entity.player != null){
|
||||||
TextureRegion region = mech.iconRegion;
|
TextureRegion region = (entity.player.mech == mech ? Mechs.starter.iconRegion : mech.iconRegion);
|
||||||
|
|
||||||
Shaders.build.region = region;
|
Shaders.build.region = region;
|
||||||
Shaders.build.progress = entity.progress;
|
Shaders.build.progress = entity.progress;
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ import io.anuke.mindustry.entities.type.Unit;
|
|||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.consumers.ConsumePower;
|
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||||
import io.anuke.mindustry.world.meta.*;
|
|
||||||
|
|
||||||
public class RepairPoint extends Block{
|
public class RepairPoint extends Block{
|
||||||
private static Rectangle rect = new Rectangle();
|
private static Rectangle rect = new Rectangle();
|
||||||
@@ -24,9 +23,7 @@ public class RepairPoint extends Block{
|
|||||||
|
|
||||||
protected float repairRadius = 50f;
|
protected float repairRadius = 50f;
|
||||||
protected float repairSpeed = 0.3f;
|
protected float repairSpeed = 0.3f;
|
||||||
protected float powerPerEvent = 0.06f;
|
protected float powerUse;
|
||||||
protected ConsumePower consumePower;
|
|
||||||
|
|
||||||
protected TextureRegion baseRegion;
|
protected TextureRegion baseRegion;
|
||||||
|
|
||||||
public RepairPoint(String name){
|
public RepairPoint(String name){
|
||||||
@@ -37,7 +34,6 @@ public class RepairPoint extends Block{
|
|||||||
layer = Layer.turret;
|
layer = Layer.turret;
|
||||||
layer2 = Layer.laser;
|
layer2 = Layer.laser;
|
||||||
hasPower = true;
|
hasPower = true;
|
||||||
consumePower = consumes.powerBuffered(20f);
|
|
||||||
outlineIcon = true;
|
outlineIcon = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,9 +45,9 @@ public class RepairPoint extends Block{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStats(){
|
public void init(){
|
||||||
super.setStats();
|
consumes.powerCond(powerUse, entity -> ((RepairPointEntity)entity).target != null);
|
||||||
stats.add(BlockStat.powerUse, powerPerEvent * 60f, StatUnit.powerSecond);
|
super.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -100,18 +96,13 @@ public class RepairPoint extends Block{
|
|||||||
RepairPointEntity entity = tile.entity();
|
RepairPointEntity entity = tile.entity();
|
||||||
|
|
||||||
boolean targetIsBeingRepaired = false;
|
boolean targetIsBeingRepaired = false;
|
||||||
if(entity.target != null && (entity.target.isDead() || entity.target.dst(tile) > repairRadius ||
|
if(entity.target != null && (entity.target.isDead() || entity.target.dst(tile) > repairRadius || entity.target.health >= entity.target.maxHealth())){
|
||||||
entity.target.health >= entity.target.maxHealth())){
|
|
||||||
entity.target = null;
|
entity.target = null;
|
||||||
}else if(entity.target != null){
|
}else if(entity.target != null && entity.cons.valid()){
|
||||||
float relativeConsumption = powerPerEvent / consumePower.powerCapacity;
|
entity.target.health += repairSpeed * Time.delta() * entity.strength * entity.power.satisfaction;
|
||||||
if(entity.power.satisfaction > 0.0f){
|
entity.target.clampHealth();
|
||||||
entity.target.health += repairSpeed * Time.delta() * entity.strength * Mathf.clamp(entity.power.satisfaction / relativeConsumption);
|
entity.rotation = Mathf.slerpDelta(entity.rotation, entity.angleTo(entity.target), 0.5f);
|
||||||
entity.target.clampHealth();
|
targetIsBeingRepaired = true;
|
||||||
entity.rotation = Mathf.slerpDelta(entity.rotation, entity.angleTo(entity.target), 0.5f);
|
|
||||||
entity.power.satisfaction -= Math.min(entity.power.satisfaction, relativeConsumption);
|
|
||||||
targetIsBeingRepaired = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(entity.target != null && targetIsBeingRepaired){
|
if(entity.target != null && targetIsBeingRepaired){
|
||||||
|
|||||||
@@ -155,11 +155,6 @@ public class UnitFactory extends Block{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tile.isEnemyCheat()){
|
|
||||||
entity.warmup += entity.delta();
|
|
||||||
}
|
|
||||||
|
|
||||||
//player-made spawners have default behavior
|
|
||||||
if(entity.cons.valid() || tile.isEnemyCheat()){
|
if(entity.cons.valid() || tile.isEnemyCheat()){
|
||||||
entity.time += entity.delta() * entity.speedScl * Vars.state.rules.unitBuildSpeedMultiplier * entity.power.satisfaction;
|
entity.time += entity.delta() * entity.speedScl * Vars.state.rules.unitBuildSpeedMultiplier * entity.power.satisfaction;
|
||||||
entity.buildTime += entity.delta() * entity.power.satisfaction * Vars.state.rules.unitBuildSpeedMultiplier;
|
entity.buildTime += entity.delta() * entity.power.satisfaction * Vars.state.rules.unitBuildSpeedMultiplier;
|
||||||
@@ -168,7 +163,6 @@ public class UnitFactory extends Block{
|
|||||||
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 0f, 0.05f);
|
entity.speedScl = Mathf.lerpDelta(entity.speedScl, 0f, 0.05f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(entity.buildTime >= produceTime){
|
if(entity.buildTime >= produceTime){
|
||||||
entity.buildTime = 0f;
|
entity.buildTime = 0f;
|
||||||
|
|
||||||
@@ -199,21 +193,18 @@ public class UnitFactory extends Block{
|
|||||||
float buildTime;
|
float buildTime;
|
||||||
float time;
|
float time;
|
||||||
float speedScl;
|
float speedScl;
|
||||||
//TODO remove next breaking release
|
|
||||||
float warmup; //only for enemy spawners
|
|
||||||
int spawned;
|
int spawned;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(DataOutput stream) throws IOException{
|
public void write(DataOutput stream) throws IOException{
|
||||||
stream.writeFloat(buildTime);
|
stream.writeFloat(buildTime);
|
||||||
stream.writeFloat(warmup);
|
|
||||||
stream.writeInt(spawned);
|
stream.writeInt(spawned);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void read(DataInput stream) throws IOException{
|
public void read(DataInput stream) throws IOException{
|
||||||
buildTime = stream.readFloat();
|
buildTime = stream.readFloat();
|
||||||
warmup = stream.readFloat();
|
stream.readFloat(); //unneeded information, will remove later
|
||||||
spawned = stream.readInt();
|
spawned = stream.readInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
package io.anuke.mindustry.world.consumers;
|
package io.anuke.mindustry.world.consumers;
|
||||||
|
|
||||||
import io.anuke.arc.math.Mathf;
|
|
||||||
import io.anuke.arc.scene.ui.layout.Table;
|
import io.anuke.arc.scene.ui.layout.Table;
|
||||||
import io.anuke.mindustry.entities.type.TileEntity;
|
import io.anuke.mindustry.entities.type.TileEntity;
|
||||||
import io.anuke.mindustry.world.Block;
|
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
import io.anuke.mindustry.world.meta.*;
|
import io.anuke.mindustry.world.meta.*;
|
||||||
|
|
||||||
/** Consumer class for blocks which consume power while being connected to a power graph. */
|
/** Consumer class for blocks which consume power while being connected to a power graph. */
|
||||||
public class ConsumePower extends Consume{
|
public class ConsumePower extends Consume{
|
||||||
/** The maximum amount of power which can be processed per tick. This might influence efficiency or load a buffer. */
|
/** The maximum amount of power which can be processed per tick. This might influence efficiency or load a buffer. */
|
||||||
public final float powerPerTick;
|
public final float usage;
|
||||||
/** The maximum power capacity in power units. */
|
/** The maximum power capacity in power units. */
|
||||||
public final float powerCapacity;
|
public final float capacity;
|
||||||
/** True if the module can store power. */
|
/** True if the module can store power. */
|
||||||
public final boolean isBuffered;
|
public final boolean buffered;
|
||||||
|
|
||||||
public ConsumePower(float powerPerTick, float powerCapacity, boolean isBuffered){
|
public ConsumePower(float usage, float capacity, boolean buffered){
|
||||||
this.powerPerTick = powerPerTick;
|
this.usage = usage;
|
||||||
this.powerCapacity = powerCapacity;
|
this.capacity = capacity;
|
||||||
this.isBuffered = isBuffered;
|
this.buffered = buffered;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -44,7 +42,7 @@ public class ConsumePower extends Consume{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean valid(TileEntity entity){
|
public boolean valid(TileEntity entity){
|
||||||
if(isBuffered){
|
if(buffered){
|
||||||
return true;
|
return true;
|
||||||
}else{
|
}else{
|
||||||
return entity.power.satisfaction > 0f;
|
return entity.power.satisfaction > 0f;
|
||||||
@@ -53,10 +51,10 @@ public class ConsumePower extends Consume{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void display(BlockStats stats){
|
public void display(BlockStats stats){
|
||||||
if(isBuffered){
|
if(buffered){
|
||||||
stats.add(BlockStat.powerCapacity, powerCapacity, StatUnit.none);
|
stats.add(BlockStat.powerCapacity, capacity, StatUnit.none);
|
||||||
}else{
|
}else{
|
||||||
stats.add(BlockStat.powerUse, powerPerTick * 60f, StatUnit.powerSecond);
|
stats.add(BlockStat.powerUse, usage * 60f, StatUnit.powerSecond);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,12 +64,11 @@ public class ConsumePower extends Consume{
|
|||||||
* @param entity The entity which contains the power module.
|
* @param entity The entity which contains the power module.
|
||||||
* @return The amount of power which is requested per tick.
|
* @return The amount of power which is requested per tick.
|
||||||
*/
|
*/
|
||||||
public float requestedPower(Block block, TileEntity entity){
|
public float requestedPower(TileEntity entity){
|
||||||
if(isBuffered){
|
if(buffered){
|
||||||
// Stop requesting power once the buffer is full.
|
return (1f-entity.power.satisfaction)*capacity;
|
||||||
return Mathf.isEqual(entity.power.satisfaction, 1.0f) ? 0.0f : powerPerTick;
|
|
||||||
}else{
|
}else{
|
||||||
return powerPerTick;
|
return usage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package io.anuke.mindustry.world.consumers;
|
package io.anuke.mindustry.world.consumers;
|
||||||
|
|
||||||
|
import io.anuke.arc.function.Predicate;
|
||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.Vars;
|
import io.anuke.mindustry.Vars;
|
||||||
|
import io.anuke.mindustry.entities.type.TileEntity;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
|
import io.anuke.mindustry.world.blocks.power.ConditionalConsumePower;
|
||||||
import io.anuke.mindustry.world.meta.BlockStats;
|
import io.anuke.mindustry.world.meta.BlockStats;
|
||||||
|
|
||||||
public class Consumers{
|
public class Consumers{
|
||||||
@@ -35,7 +38,7 @@ public class Consumers{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a consumer which directly uses power without buffering it. The module will work while the available power is greater than or equal to the minimumSatisfaction percentage (0..1).
|
* Creates a consumer which directly uses power without buffering it.
|
||||||
* @param powerPerTick The amount of power which is required each tick for 100% efficiency.
|
* @param powerPerTick The amount of power which is required each tick for 100% efficiency.
|
||||||
* @return the created consumer object.
|
* @return the created consumer object.
|
||||||
*/
|
*/
|
||||||
@@ -43,22 +46,17 @@ public class Consumers{
|
|||||||
return add(new ConsumePower(powerPerTick, 0.0f, false));
|
return add(new ConsumePower(powerPerTick, 0.0f, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Creates a consumer which only consumes power when the condition is met. */
|
||||||
* Creates a consumer which stores power and uses it only in case of certain events (e.g. a turret firing).
|
public ConsumePower powerCond(float usage, Predicate<TileEntity> cons){
|
||||||
* It will take 180 ticks (three second) to fill the buffer, given enough power supplied.
|
return add(new ConditionalConsumePower(usage, cons));
|
||||||
* @param powerCapacity The maximum capacity in power units.
|
|
||||||
*/
|
|
||||||
public ConsumePower powerBuffered(float powerCapacity){
|
|
||||||
return powerBuffered(powerCapacity, 60f * 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a consumer which stores power and uses it only in case of certain events (e.g. a turret firing).
|
* Creates a consumer which stores power.
|
||||||
* @param powerCapacity The maximum capacity in power units.
|
* @param powerCapacity The maximum capacity in power units.
|
||||||
* @param ticksToFill The number of ticks it shall take to fill the buffer.
|
|
||||||
*/
|
*/
|
||||||
public ConsumePower powerBuffered(float powerCapacity, float ticksToFill){
|
public ConsumePower powerBuffered(float powerCapacity){
|
||||||
return add(new ConsumePower(powerCapacity / ticksToFill, powerCapacity, true));
|
return add(new ConsumePower(0f, powerCapacity, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConsumeItems item(Item item){
|
public ConsumeItems item(Item item){
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ if [[ $# -eq 0 ]] ; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
./gradlew server:dist -Pbuildversion=$1
|
./gradlew server:dist -Pbuildversion=$1
|
||||||
java -jar server/build/libs/server-release.jar
|
java -jar -XX:+HeapDumpOnOutOfMemoryError server/build/libs/server-release.jar
|
||||||
|
|||||||
@@ -23,8 +23,8 @@ import io.anuke.mindustry.net.Packets.KickReason;
|
|||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.type.ItemType;
|
import io.anuke.mindustry.type.ItemType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.*;
|
||||||
import java.net.BindException;
|
import java.net.*;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
@@ -36,6 +36,7 @@ public class ServerControl implements ApplicationListener{
|
|||||||
private static final int roundExtraTime = 12;
|
private static final int roundExtraTime = 12;
|
||||||
//in bytes: 512 kb is max
|
//in bytes: 512 kb is max
|
||||||
private static final int maxLogLength = 1024 * 512;
|
private static final int maxLogLength = 1024 * 512;
|
||||||
|
private static final int commandSocketPort = 6859;
|
||||||
|
|
||||||
private final CommandHandler handler = new CommandHandler("");
|
private final CommandHandler handler = new CommandHandler("");
|
||||||
private final FileHandle logFolder = Core.files.local("logs/");
|
private final FileHandle logFolder = Core.files.local("logs/");
|
||||||
@@ -44,6 +45,9 @@ public class ServerControl implements ApplicationListener{
|
|||||||
private boolean inExtraRound;
|
private boolean inExtraRound;
|
||||||
private Task lastTask;
|
private Task lastTask;
|
||||||
|
|
||||||
|
private Thread socketThread;
|
||||||
|
private PrintWriter socketOutput;
|
||||||
|
|
||||||
public ServerControl(String[] args){
|
public ServerControl(String[] args){
|
||||||
Core.settings.defaults(
|
Core.settings.defaults(
|
||||||
"shufflemode", "normal",
|
"shufflemode", "normal",
|
||||||
@@ -52,7 +56,8 @@ public class ServerControl implements ApplicationListener{
|
|||||||
"shuffle", true,
|
"shuffle", true,
|
||||||
"crashreport", false,
|
"crashreport", false,
|
||||||
"port", port,
|
"port", port,
|
||||||
"logging", true
|
"logging", true,
|
||||||
|
"socket", false
|
||||||
);
|
);
|
||||||
|
|
||||||
Log.setLogger(new LogHandler(){
|
Log.setLogger(new LogHandler(){
|
||||||
@@ -60,7 +65,7 @@ public class ServerControl implements ApplicationListener{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void debug(String text, Object... args){
|
public void debug(String text, Object... args){
|
||||||
print("&lc&fb" + "[DEBUG] " + text, args);
|
print("&lc&fb" + "[DEBG] " + text, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,6 +91,14 @@ public class ServerControl implements ApplicationListener{
|
|||||||
if(Core.settings.getBool("logging")){
|
if(Core.settings.getBool("logging")){
|
||||||
logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", false, args));
|
logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", false, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(socketOutput != null){
|
||||||
|
try{
|
||||||
|
socketOutput.println(format(text + "&fr", false, args).replace("[DEBG] ", "").replace("[WARN] ", "").replace("[INFO] ", "").replace("[ERR!] ", ""));
|
||||||
|
}catch(Throwable e){
|
||||||
|
err("Error occurred logging to socket: {0}", e.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -161,6 +174,10 @@ public class ServerControl implements ApplicationListener{
|
|||||||
|
|
||||||
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
info("&lcServer loaded. Type &ly'help'&lc for help.");
|
||||||
System.out.print("> ");
|
System.out.print("> ");
|
||||||
|
|
||||||
|
if(Core.settings.getBool("socket")){
|
||||||
|
toggleSocket(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerCommands(){
|
private void registerCommands(){
|
||||||
@@ -360,6 +377,19 @@ public class ServerControl implements ApplicationListener{
|
|||||||
info("Strict mode is now {0}.", netServer.admins.getStrict() ? "on" : "off");
|
info("Strict mode is now {0}.", netServer.admins.getStrict() ? "on" : "off");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
handler.register("socketinput", "[on/off]", "Disables or enables a local TCP socket at port "+commandSocketPort+" to recieve commands from other applications", arg -> {
|
||||||
|
if(arg.length == 0){
|
||||||
|
info("Socket input is currently &lc{0}.", Core.settings.getBool("socket") ? "on" : "off");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean value = arg[0].equalsIgnoreCase("on");
|
||||||
|
toggleSocket(value);
|
||||||
|
Core.settings.put("socket", value);
|
||||||
|
Core.settings.save();
|
||||||
|
info("Socket input is now &lc{0}.", value ? "on" : "off");
|
||||||
|
});
|
||||||
|
|
||||||
handler.register("allow-custom-clients", "[on/off]", "Allow or disallow custom clients.", arg -> {
|
handler.register("allow-custom-clients", "[on/off]", "Allow or disallow custom clients.", arg -> {
|
||||||
if(arg.length == 0){
|
if(arg.length == 0){
|
||||||
info("Custom clients are currently &lc{0}.", netServer.admins.allowsCustomClients() ? "allowed" : "disallowed");
|
info("Custom clients are currently &lc{0}.", netServer.admins.allowsCustomClients() ? "allowed" : "disallowed");
|
||||||
@@ -615,39 +645,40 @@ public class ServerControl implements ApplicationListener{
|
|||||||
Scanner scan = new Scanner(System.in);
|
Scanner scan = new Scanner(System.in);
|
||||||
while(scan.hasNext()){
|
while(scan.hasNext()){
|
||||||
String line = scan.nextLine();
|
String line = scan.nextLine();
|
||||||
|
Core.app.post(() -> handleCommandString(line));
|
||||||
Core.app.post(() -> {
|
|
||||||
Response response = handler.handleMessage(line);
|
|
||||||
|
|
||||||
if(response.type == ResponseType.unknownCommand){
|
|
||||||
|
|
||||||
int minDst = 0;
|
|
||||||
Command closest = null;
|
|
||||||
|
|
||||||
for(Command command : handler.getCommandList()){
|
|
||||||
int dst = Strings.levenshtein(command.text, response.runCommand);
|
|
||||||
if(dst < 3 && (closest == null || dst < minDst)){
|
|
||||||
minDst = dst;
|
|
||||||
closest = command;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(closest != null){
|
|
||||||
err("Command not found. Did you mean \"" + closest.text + "\"?");
|
|
||||||
}else{
|
|
||||||
err("Invalid command. Type 'help' for help.");
|
|
||||||
}
|
|
||||||
}else if(response.type == ResponseType.fewArguments){
|
|
||||||
err("Too few command arguments. Usage: " + response.command.text + " " + response.command.paramText);
|
|
||||||
}else if(response.type == ResponseType.manyArguments){
|
|
||||||
err("Too many command arguments. Usage: " + response.command.text + " " + response.command.paramText);
|
|
||||||
}
|
|
||||||
|
|
||||||
System.out.print("> ");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleCommandString(String line){
|
||||||
|
Response response = handler.handleMessage(line);
|
||||||
|
|
||||||
|
if(response.type == ResponseType.unknownCommand){
|
||||||
|
|
||||||
|
int minDst = 0;
|
||||||
|
Command closest = null;
|
||||||
|
|
||||||
|
for(Command command : handler.getCommandList()){
|
||||||
|
int dst = Strings.levenshtein(command.text, response.runCommand);
|
||||||
|
if(dst < 3 && (closest == null || dst < minDst)){
|
||||||
|
minDst = dst;
|
||||||
|
closest = command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(closest != null){
|
||||||
|
err("Command not found. Did you mean \"" + closest.text + "\"?");
|
||||||
|
}else{
|
||||||
|
err("Invalid command. Type 'help' for help.");
|
||||||
|
}
|
||||||
|
}else if(response.type == ResponseType.fewArguments){
|
||||||
|
err("Too few command arguments. Usage: " + response.command.text + " " + response.command.paramText);
|
||||||
|
}else if(response.type == ResponseType.manyArguments){
|
||||||
|
err("Too many command arguments. Usage: " + response.command.text + " " + response.command.paramText);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.print("> ");
|
||||||
|
}
|
||||||
|
|
||||||
private void play(boolean wait, Runnable run){
|
private void play(boolean wait, Runnable run){
|
||||||
inExtraRound = true;
|
inExtraRound = true;
|
||||||
Runnable r = () -> {
|
Runnable r = () -> {
|
||||||
@@ -723,4 +754,38 @@ public class ServerControl implements ApplicationListener{
|
|||||||
|
|
||||||
currentLogFile.writeString(text + "\n", true);
|
currentLogFile.writeString(text + "\n", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void toggleSocket(boolean on){
|
||||||
|
if(on && socketThread == null){
|
||||||
|
socketThread = new Thread(() -> {
|
||||||
|
try{
|
||||||
|
try(ServerSocket socket = new ServerSocket()){
|
||||||
|
socket.bind(new InetSocketAddress("localhost", commandSocketPort));
|
||||||
|
while(true){
|
||||||
|
Socket client = socket.accept();
|
||||||
|
info("&lmRecieved command socket connection: &lb{0}", socket.getLocalSocketAddress());
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
|
||||||
|
socketOutput = new PrintWriter(client.getOutputStream(), true);
|
||||||
|
String line;
|
||||||
|
while(client.isConnected() && (line = in.readLine()) != null){
|
||||||
|
String result = line;
|
||||||
|
Core.app.post(() -> handleCommandString(result));
|
||||||
|
}
|
||||||
|
info("&lmLost command socket connection: &lb{0}", socket.getLocalSocketAddress());
|
||||||
|
socketOutput = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(IOException e){
|
||||||
|
err("Terminating socket server.");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
socketThread.setDaemon(true);
|
||||||
|
socketThread.start();
|
||||||
|
}else if(socketThread != null){
|
||||||
|
socketThread.interrupt();
|
||||||
|
socketThread = null;
|
||||||
|
socketOutput = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ public class PowerTestFixture{
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Battery createFakeBattery(float capacity, float ticksToFill){
|
protected static Battery createFakeBattery(float capacity){
|
||||||
return new Battery("fakebattery"){{
|
return new Battery("fakebattery"){{
|
||||||
consumes.powerBuffered(capacity, ticksToFill);
|
consumes.powerBuffered(capacity);
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,12 +55,6 @@ public class PowerTestFixture{
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Block createFakeBufferedConsumer(float capacity, float ticksToFill){
|
|
||||||
return new PowerBlock("fakebufferedconsumer"){{
|
|
||||||
consumes.powerBuffered(capacity, ticksToFill);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a fake tile on the given location using the given block.
|
* Creates a fake tile on the given location using the given block.
|
||||||
* @param x The X coordinate.
|
* @param x The X coordinate.
|
||||||
|
|||||||
@@ -68,54 +68,6 @@ public class PowerTests extends PowerTestFixture{
|
|||||||
assertEquals(expectedSatisfaction, directConsumerTile.entity.power.satisfaction, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match");
|
assertEquals(expectedSatisfaction, directConsumerTile.entity.power.satisfaction, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Tests the satisfaction of a single buffered consumer after a single update of the power graph which contains a single producer. */
|
|
||||||
@TestFactory
|
|
||||||
DynamicTest[] bufferedConsumerSatisfactionIsAsExpected(){
|
|
||||||
return new DynamicTest[]{
|
|
||||||
// Note: powerPerTick may not be 0 in any of the test cases. This would equal a "ticksToFill" of infinite.
|
|
||||||
// Note: Due to a fixed delta of 0.5, only half of what is defined here will in fact be produced/consumed. Keep this in mind when defining expectedSatisfaction!
|
|
||||||
dynamicTest("01", () -> simulateBufferedConsumption(0.0f, 0.0f, 0.1f, 0.0f, 0.0f, "Empty Buffer, No power anywhere")),
|
|
||||||
dynamicTest("02", () -> simulateBufferedConsumption(0.0f, 1.0f, 0.1f, 0.0f, 0.0f, "Empty Buffer, No power provided")),
|
|
||||||
dynamicTest("03", () -> simulateBufferedConsumption(1.0f, 0.0f, 0.1f, 0.0f, 0.0f, "Empty Buffer, No power requested")),
|
|
||||||
dynamicTest("04", () -> simulateBufferedConsumption(1.0f, 1.0f, 1.0f, 0.0f, 0.5f, "Empty Buffer, Stable Power, One tick to fill")),
|
|
||||||
dynamicTest("05", () -> simulateBufferedConsumption(2.0f, 1.0f, 2.0f, 0.0f, 1.0f, "Empty Buffer, Stable Power, One delta to fill")),
|
|
||||||
dynamicTest("06", () -> simulateBufferedConsumption(1.0f, 1.0f, 0.1f, 0.0f, 0.05f, "Empty Buffer, Stable Power, multiple ticks to fill")),
|
|
||||||
dynamicTest("07", () -> simulateBufferedConsumption(1.2f, 0.5f, 1.0f, 0.0f, 1.0f, "Empty Buffer, Power excess, one delta to fill")),
|
|
||||||
dynamicTest("08", () -> simulateBufferedConsumption(1.0f, 0.5f, 0.1f, 0.0f, 0.1f, "Empty Buffer, Power excess, multiple ticks to fill")),
|
|
||||||
dynamicTest("09", () -> simulateBufferedConsumption(1.0f, 1.0f, 2.0f, 0.0f, 0.5f, "Empty Buffer, Power shortage, one delta to fill")),
|
|
||||||
dynamicTest("10", () -> simulateBufferedConsumption(0.5f, 1.0f, 0.1f, 0.0f, 0.05f, "Empty Buffer, Power shortage, multiple ticks to fill")),
|
|
||||||
dynamicTest("11", () -> simulateBufferedConsumption(0.0f, 1.0f, 0.1f, 0.5f, 0.5f, "Unchanged buffer with no power produced")),
|
|
||||||
dynamicTest("12", () -> simulateBufferedConsumption(1.0f, 1.0f, 0.1f, 1.0f, 1.0f, "Unchanged buffer when already full")),
|
|
||||||
dynamicTest("13", () -> simulateBufferedConsumption(0.2f, 1.0f, 0.5f, 0.5f, 0.6f, "Half buffer, power shortage")),
|
|
||||||
dynamicTest("14", () -> simulateBufferedConsumption(1.0f, 1.0f, 0.5f, 0.9f, 1.0f, "Buffer does not get exceeded")),
|
|
||||||
dynamicTest("15", () -> simulateBufferedConsumption(2.0f, 1.0f, 1.0f, 0.5f, 1.0f, "Half buffer, filled with excess"))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void simulateBufferedConsumption(float producedPower, float maxBuffer, float powerConsumedPerTick, float initialSatisfaction, float expectedSatisfaction, String parameterDescription){
|
|
||||||
Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower));
|
|
||||||
producerTile.<PowerGenerator.GeneratorEntity>entity().productionEfficiency = 1f;
|
|
||||||
Tile bufferedConsumerTile = createFakeTile(0, 1, createFakeBufferedConsumer(maxBuffer, maxBuffer > 0.0f ? maxBuffer / powerConsumedPerTick : 1.0f));
|
|
||||||
bufferedConsumerTile.entity.power.satisfaction = initialSatisfaction;
|
|
||||||
|
|
||||||
PowerGraph powerGraph = new PowerGraph();
|
|
||||||
powerGraph.add(producerTile);
|
|
||||||
powerGraph.add(bufferedConsumerTile);
|
|
||||||
|
|
||||||
assertEquals(producedPower * Time.delta(), powerGraph.getPowerProduced(), Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Produced power did not match");
|
|
||||||
float expectedPowerUsage;
|
|
||||||
if(initialSatisfaction == 1.0f){
|
|
||||||
expectedPowerUsage = 0f;
|
|
||||||
}else{
|
|
||||||
expectedPowerUsage = Math.min(maxBuffer, powerConsumedPerTick * Time.delta());
|
|
||||||
}
|
|
||||||
assertEquals(expectedPowerUsage, powerGraph.getPowerNeeded(), Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Consumed power did not match");
|
|
||||||
|
|
||||||
// Update and check for the expected power satisfaction of the consumer
|
|
||||||
powerGraph.update();
|
|
||||||
assertEquals(expectedSatisfaction, bufferedConsumerTile.entity.power.satisfaction, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of buffered consumer did not match");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the satisfaction of a single direct consumer after a single update of the power graph which contains a single producer and a single battery.
|
* Tests the satisfaction of a single direct consumer after a single update of the power graph which contains a single producer and a single battery.
|
||||||
* The used battery is created with a maximum capacity of 100 and receives ten power per tick.
|
* The used battery is created with a maximum capacity of 100 and receives ten power per tick.
|
||||||
@@ -150,7 +102,7 @@ public class PowerTests extends PowerTestFixture{
|
|||||||
powerGraph.add(directConsumerTile);
|
powerGraph.add(directConsumerTile);
|
||||||
}
|
}
|
||||||
float maxCapacity = 100f;
|
float maxCapacity = 100f;
|
||||||
Tile batteryTile = createFakeTile(0, 2, createFakeBattery(maxCapacity, 10));
|
Tile batteryTile = createFakeTile(0, 2, createFakeBattery(maxCapacity));
|
||||||
batteryTile.entity.power.satisfaction = initialBatteryCapacity / maxCapacity;
|
batteryTile.entity.power.satisfaction = initialBatteryCapacity / maxCapacity;
|
||||||
|
|
||||||
powerGraph.add(batteryTile);
|
powerGraph.add(batteryTile);
|
||||||
|
|||||||
Reference in New Issue
Block a user