Bugfixes / Mender block / Extra stats / Balancing

This commit is contained in:
Anuken 2019-03-26 11:05:47 -04:00
parent 0b1e2bf19b
commit 10c999a4a2
29 changed files with 1957 additions and 1822 deletions

View File

@ -7,13 +7,13 @@ import java.lang.annotation.Target;
public class Annotations{
@Target(ElementType.METHOD)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Nullable{
}
@Target(ElementType.METHOD)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface NonNull{

View File

@ -129,7 +129,7 @@ public class StructAnnotationProcessor extends AbstractProcessor{
//floats: need conversion
setter.addStatement("return ($T)(($L & $L) | (($T)Float.floatToIntBits(value) << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset);
}else{
cons.append(" | (").append("(").append(structType).append(")").append(varName).append(" << ").append(offset).append("L)");
cons.append(" | (((").append(structType).append(")").append(varName).append(" << ").append(offset).append("L)").append(" & ").append(bitString(offset, size, structTotalSize)).append(")");
//bytes, shorts, chars, ints
setter.addStatement("return ($T)(($L & $L) | (($T)value << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset);

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -366,6 +366,8 @@ blocks.itemcapacity = Item Capacity
blocks.basepowergeneration = Base Power Generation
blocks.powertransferspeed = Power Transfer
blocks.craftspeed = Production Speed
blocks.repairtime = Block Full Repair Time
blocks.range = Range
blocks.inputliquid = Input Liquid
blocks.inputliquidaux = Aux Liquid
blocks.inputitem = Input Item
@ -399,7 +401,7 @@ blocks.inputcapacity = Input capacity
blocks.outputcapacity = Output capacity
blocks.ammo = Ammo
bullet.damage = [stat]{0}[lightgray] dmg
bullet.damage = [stat]{0}[lightgray] damage
bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles
bullet.incendiary = [stat]incendiary
bullet.homing = [stat]homing
@ -510,7 +512,7 @@ mode.custom = Custom Rules
rules.infiniteresources = Infinite Resources
rules.wavetimer = Wave Timer
rules.waves = Waves
rules.enemyCheat = Infinite AI Resources
rules.enemyCheat = Infinite AI (Red Team) Resources
rules.pvp = PvP
rules.unitdrops = Unit Drops
rules.enemycorebuildradius = Enemy Core No-Build Radius:[LIGHT_GRAY] (tiles)
@ -759,6 +761,7 @@ block.blast-drill.name = Airblast Drill
block.thermal-pump.name = Thermal Pump
block.thermal-generator.name = Thermal Generator
block.alloy-smelter.name = Alloy Smelter
block.mender.name = Mender
block.mend-projector.name = Mend Projector
block.surge-wall.name = Surge Wall
block.surge-wall-large.name = Large Surge Wall

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 505 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

After

Width:  |  Height:  |  Size: 244 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 KiB

After

Width:  |  Height:  |  Size: 516 KiB

View File

@ -14,6 +14,7 @@ import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.entities.type.BaseUnit;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.SpawnGroup;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.Pos;
import java.io.DataInput;
@ -105,7 +106,7 @@ public class WaveSpawner{
}
public boolean isSpawning(){
return spawning;
return spawning && !Net.client();
}
private void reset(){

View File

@ -53,7 +53,7 @@ public class Blocks implements ContentList{
//defense
scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet
copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge,
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mendProjector, overdriveProjector, forceProjector, shockMine,
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine,
//transport
conveyor, titaniumConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, router, overflowGate, massDriver,
@ -529,7 +529,7 @@ public class Blocks implements ContentList{
cultivator = new Cultivator("cultivator"){{
requirements(Category.crafting, ItemStack.with(Items.copper, 20, Items.lead, 50, Items.silicon, 20));
output = Items.sporePod;
craftTime = 200;
craftTime = 160;
size = 2;
hasLiquids = true;
hasPower = true;
@ -544,7 +544,7 @@ public class Blocks implements ContentList{
liquidCapacity = 60f;
craftTime = 20f;
outputLiquid = Liquids.oil;
outputLiquidAmount = 2.5f;
outputLiquidAmount = 4f;
size = 2;
health = 320;
hasLiquids = true;
@ -695,10 +695,23 @@ public class Blocks implements ContentList{
size = 2;
}};
mender = new MendProjector("mender"){{
requirements(Category.effect, ItemStack.with(Items.lead, 60, Items.copper, 50));
consumes.power(0.7f);
size = 1;
reload = 200f;
range = 40f;
healPercent = 5f;
consumes.item(Items.phasefabric).optional(true);
}};
mendProjector = new MendProjector("mend-projector"){{
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 50, Items.silicon, 180));
consumes.power(2f);
requirements(Category.effect, ItemStack.with(Items.lead, 200, Items.titanium, 40, Items.silicon, 80));
consumes.power(1.8f);
size = 2;
reload = 250f;
range = 70f;
healPercent = 13f;
consumes.item(Items.phasefabric).optional(true);
}};
@ -1118,7 +1131,7 @@ public class Blocks implements ContentList{
Items.scrap, Bullets.flakScrap,
Items.lead, Bullets.flakLead
);
reload = 33f;
reload = 25f;
range = 180f;
size = 2;
burstSpacing = 5f;
@ -1126,7 +1139,7 @@ public class Blocks implements ContentList{
targetGround = false;
recoil = 2f;
rotatespeed = 10f;
rotatespeed = 15f;
inaccuracy = 17f;
shootCone = 35f;

View File

@ -141,25 +141,25 @@ public class Bullets implements ContentList{
}};
flakLead = new FlakBulletType(4.2f, 3){{
lifetime = 50f;
lifetime = 60f;
ammoMultiplier = 3f;
shootEffect = Fx.shootSmall;
bulletWidth = 6f;
bulletHeight = 8f;
hitEffect = Fx.flakExplosion;
splashDamage = 30f;
splashDamage = 35f;
splashDamageRadius = 15f;
}};
flakScrap = new FlakBulletType(4f, 3){{
lifetime = 50f;
lifetime = 60f;
ammoMultiplier = 3f;
shootEffect = Fx.shootSmall;
reloadMultiplier = 0.5f;
bulletWidth = 6f;
bulletHeight = 8f;
hitEffect = Fx.flakExplosion;
splashDamage = 24f;
splashDamage = 26f;
splashDamageRadius = 24f;
}};

View File

@ -201,7 +201,9 @@ public class TechTree implements ContentList{
});
});
});
});
node(mender, () -> {
node(mendProjector, () -> {
node(forceProjector, () -> {
node(overdriveProjector, () -> {
@ -263,7 +265,7 @@ public class TechTree implements ContentList{
private TechNode node(Block block, Runnable children){
ItemStack[] requirements = new ItemStack[block.buildRequirements.length];
for(int i = 0; i < requirements.length; i++){
requirements[i] = new ItemStack(block.buildRequirements[i].item, block.buildRequirements[i].amount * 6);
requirements[i] = new ItemStack(block.buildRequirements[i].item, block.buildRequirements[i].amount * 5);
}
return new TechNode(block, requirements, children);

View File

@ -458,7 +458,7 @@ public class NetServer implements ApplicationListener{
byte[] stateBytes = syncStream.toByteArray();
//write basic state data.
Call.onStateSnapshot(player.con.id, state.wavetime, state.wave, state.enemies, (short)stateBytes.length, Net.compressSnapshot(stateBytes));
Call.onStateSnapshot(player.con.id, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, Net.compressSnapshot(stateBytes));
viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY);

View File

@ -53,7 +53,7 @@ public class Renderer implements ApplicationListener{
public Renderer(){
batch = new SpriteBatch(4096);
camera = new Camera();
Lines.setCircleVertices(14);
Lines.setCircleVertices(20);
Shaders.init();
Effects.setScreenShakeProvider((intensity, duration) -> {

View File

@ -4,6 +4,7 @@ import io.anuke.annotations.Annotations.Struct;
import io.anuke.arc.collection.LongArray;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.gen.TileOp;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor;
@ -39,7 +40,11 @@ public class DrawOperation{
if(type == OpType.floor.ordinal()){
tile.setFloor((Floor)content.block(to));
}else if(type == OpType.block.ordinal()){
tile.setBlock(content.block(to));
Block block = content.block(to);
tile.setBlock(block);
if(block.isMultiblock()){
editor.updateLinks(block, tile.x, tile.y);
}
}else if(type == OpType.rotation.ordinal()){
tile.setRotation(to);
}else if(type == OpType.team.ordinal()){

View File

@ -49,8 +49,7 @@ public class EditorTile extends Tile{
@Override
public void setBlock(Block type){
if(type == null) return;
Block previous = wall == null ? Blocks.air : wall;
Block previous =wall;
if(previous == type) return;
super.setBlock(type);
op(TileOp.get(x, y, (byte)OpType.block.ordinal(), previous.id, type.id));

View File

@ -146,6 +146,27 @@ public class MapEditor{
return tiles[0].length;
}
public void updateLinks(Block block, int x, int y){
int offsetx = -(block.size - 1) / 2;
int offsety = -(block.size - 1) / 2;
for(int dx = 0; dx < block.size; dx++){
for(int dy = 0; dy < block.size; dy++){
int worldx = dx + offsetx + x;
int worldy = dy + offsety + y;
if(Structs.inBounds(worldx, worldy, width(), height())){
Tile tile = tiles[worldx][worldy];
if(!(worldx == x && worldy == y)){
tile.setBlock(Blocks.part);
tile.setLinkByte(Pack.byteByte((byte)(dx + offsetx + 8), (byte)(dy + offsety + 8)));
}
}
}
}
}
public void draw(int x, int y, boolean paint){
draw(x, y, paint, drawBlock);
}

View File

@ -35,9 +35,9 @@ public class CustomRulesDialog extends FloatingDialog{
main.row();
main.addCheck("$rules.wavetimer", b -> rules.waveTimer = b).checked(b -> rules.waveTimer);
main.row();
main.addCheck("$rules.waves", b -> rules.waves = b).checked(b -> rules.waves).disabled(b -> rules.pvp);
main.addCheck("$rules.waves", b -> rules.waves = b).checked(b -> rules.waves);
main.row();
main.addCheck("$rules.pvp", b -> rules.pvp = b).checked(b -> rules.pvp).disabled(b -> rules.waves);
main.addCheck("$rules.pvp", b -> rules.pvp = b).checked(b -> rules.pvp);
main.row();
main.addCheck("$rules.unitdrops", b -> rules.unitDrops = b).checked(b -> rules.unitDrops);
main.row();

View File

@ -449,15 +449,17 @@ public class HudFragment extends Fragment{
builder.append(wavef.get(state.wave));
builder.append("\n");
if(state.enemies() > 0 && !state.rules.waveTimer){
if(state.enemies() > 0){
if(state.enemies() == 1){
builder.append(enemyf.get(state.enemies()));
}else{
builder.append(enemiesf.get(state.enemies()));
}
}else if(state.rules.waveTimer){
}
if(state.rules.waveTimer){
builder.append(waitingf.get((int)(state.wavetime/60)));
}else{
}else if(state.enemies() == 0){
builder.append(Core.bundle.get("waiting"));
}

View File

@ -136,14 +136,14 @@ public class Block extends BlockStorage{
TileEntity entity = tile.entity();
for(Tile other : getPowerConnections(tile, tempTiles)){
if(other.entity.power != null && other.entity.power.graph != null){
if(other.entity.power != null){
other.entity.power.graph.add(entity.power.graph);
}
}
}
protected void powerGraphRemoved(Tile tile){
if(tile.entity == null || tile.entity.power == null || tile.entity.power.graph == null){
if(tile.entity == null || tile.entity.power == null){
return;
}

View File

@ -15,6 +15,8 @@ import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import java.io.DataInput;
import java.io.DataOutput;
@ -32,8 +34,8 @@ public class MendProjector extends Block{
protected TextureRegion topRegion;
protected float reload = 250f;
protected float range = 50f;
protected float healPercent = 6f;
protected float range = 60f;
protected float healPercent = 12f;
protected float phaseBoost = 12f;
protected float phaseRangeBoost = 50f;
protected float useTime = 400f;
@ -52,6 +54,14 @@ public class MendProjector extends Block{
topRegion = Core.atlas.find(name + "-top");
}
@Override
public void setStats(){
super.setStats();
stats.add(BlockStat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds);
stats.add(BlockStat.range, range / tilesize, StatUnit.blocks);
}
@Override
public void update(Tile tile){
MendEntity entity = tile.entity();

View File

@ -13,8 +13,6 @@ public class PowerDistributor extends PowerBlock{
@Override
public void update(Tile tile){
if(tile.entity.power.graph != null){
tile.entity.power.graph.update();
}
tile.entity.power.graph.update();
}
}

View File

@ -176,6 +176,11 @@ public class PowerGraph{
}
public void add(Tile tile){
if(tile.block().consumes.has(ConsumePower.class) && !tile.block().consumes.get(ConsumePower.class).isBuffered){
//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.graph = this;
all.add(tile);
@ -191,32 +196,15 @@ public class PowerGraph{
}
}
public void clear(){
for(Tile other : all){
if(other.entity != null && other.entity.power != null){
if(other.block().consumes.has(ConsumePower.class) && !other.block().consumes.get(ConsumePower.class).isBuffered){
// Reset satisfaction to zero in case of direct consumer. There is no reason to clear power from buffered consumers.
other.entity.power.satisfaction = 0.0f;
}
other.entity.power.graph = null;
}
}
all.clear();
producers.clear();
consumers.clear();
batteries.clear();
}
public void reflow(Tile tile){
queue.clear();
queue.addLast(tile);
closedSet.clear();
while(queue.size > 0){
Tile child = queue.removeFirst();
child.entity.power.graph = this;
add(child);
for(Tile next : child.block().getPowerConnections(child, outArray2)){
if(next.entity.power != null && next.entity.power.graph == null && !closedSet.contains(next.pos())){
if(!closedSet.contains(next.pos())){
queue.addLast(next);
closedSet.add(next.pos());
}
@ -224,27 +212,47 @@ public class PowerGraph{
}
}
private void removeSingle(Tile tile){
all.remove(tile);
producers.remove(tile);
consumers.remove(tile);
batteries.remove(tile);
}
public void remove(Tile tile){
clear();
removeSingle(tile);
//begin by clearing the closed set
closedSet.clear();
//go through all the connections of this tile
for(Tile other : tile.block().getPowerConnections(tile, outArray1)){
if(other.entity.power == null || other.entity.power.graph != null) continue;
//a graph has already been assigned to this tile from a previous call, skip it
if(other.entity.power.graph != this) continue;
//create graph for this branch
PowerGraph graph = new PowerGraph();
graph.add(other);
//add to queue for BFS
queue.clear();
queue.addLast(other);
while(queue.size > 0){
//get child from queue
Tile child = queue.removeFirst();
child.entity.power.graph = graph;
//remove it from this graph
removeSingle(child);
//add it to the new branch graph
graph.add(child);
//go through connections
for(Tile next : child.block().getPowerConnections(child, outArray2)){
if(next != tile && next.entity.power != null && next.entity.power.graph == null && !closedSet.contains(next.pos())){
//make sure it hasn't looped back, and that the new graph being assigned hasn't already been assigned
//also skip closed tiles
if(next != tile && next.entity.power.graph != graph && !closedSet.contains(next.pos())){
queue.addLast(next);
closedSet.add(next.pos());
}
}
}
// Update the graph once so direct consumers without any connected producer lose their power
//update the graph once so direct consumers without any connected producer lose their power
graph.update();
}
}

View File

@ -72,17 +72,15 @@ public class PowerNode extends PowerBlock{
TileEntity entity = tile.entity();
//clear all graph data first
PowerGraph tg = entity.power.graph;
tg.clear();
entity.power.links.removeValue(other.pos());
other.entity.power.links.removeValue(tile.pos());
//reflow from this point, covering all tiles on this side
tg.reflow(tile);
PowerGraph newgraph = new PowerGraph();
if(other.entity.power.graph != tg){
//reflow from this point, covering all tiles on this side
newgraph.reflow(tile);
if(other.entity.power.graph != newgraph){
//create new graph for other end
PowerGraph og = new PowerGraph();
//reflow from other end
@ -95,9 +93,9 @@ public class PowerNode extends PowerBlock{
super.setBars();
bars.add("power", entity -> new Bar(() ->
Core.bundle.format("blocks.powerbalance",
entity.power.graph == null ? "+0" : ((entity.power.graph.getPowerBalance() >= 0 ? "+" : "") + Strings.toFixed(entity.power.graph.getPowerBalance()*60, 1))),
((entity.power.graph.getPowerBalance() >= 0 ? "+" : "") + Strings.toFixed(entity.power.graph.getPowerBalance()*60, 1))),
() -> Pal.powerBar,
() -> entity.power.graph == null ? 0 : Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded())));
() -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded())));
}
@Override
@ -125,7 +123,7 @@ public class PowerNode extends PowerBlock{
@Override
public void update(Tile tile){
if(tile.entity.power.graph != null) tile.entity.power.graph.update();
tile.entity.power.graph.update();
}
@Override
@ -169,8 +167,8 @@ public class PowerNode extends PowerBlock{
Lines.poly(tile.drawx(), tile.drawy(), 50, laserRange*tilesize);
for(int x = (int) (tile.x - laserRange); x <= tile.x + laserRange; x++){
for(int y = (int) (tile.y - laserRange); y <= tile.y + laserRange; y++){
for(int x = (int) (tile.x - laserRange - 1); x <= tile.x + laserRange + 1; x++){
for(int y = (int) (tile.y - laserRange - 1); y <= tile.y + laserRange + 1; y++){
Tile link = world.tile(x, y);
if(link != null) link = link.target();

View File

@ -41,6 +41,8 @@ public enum BlockStat{
drillSpeed(StatCategory.crafting),
maxUnits(StatCategory.crafting),
repairTime(StatCategory.shooting),
range(StatCategory.shooting),
shootRange(StatCategory.shooting),
inaccuracy(StatCategory.shooting),
shots(StatCategory.shooting),
@ -51,7 +53,9 @@ public enum BlockStat{
ammo(StatCategory.shooting),
boostItem(StatCategory.optional),
boostLiquid(StatCategory.optional),;
boostLiquid(StatCategory.optional),
;
public final StatCategory category;

View File

@ -1,5 +1,6 @@
package io.anuke.mindustry.world.modules;
import io.anuke.annotations.Annotations.NonNull;
import io.anuke.arc.collection.IntArray;
import io.anuke.mindustry.world.blocks.power.PowerGraph;
@ -15,7 +16,7 @@ public class PowerModule extends BlockModule{
public float satisfaction = 0.0f;
/** Specifies power which is required additionally, e.g. while a force projector is being shot at. */
public float extraUse = 0f;
public PowerGraph graph = new PowerGraph();
public @NonNull PowerGraph graph = new PowerGraph();
public IntArray links = new IntArray();
@Override