A significant waste of time and effort

This commit is contained in:
Anuken
2021-11-23 22:41:25 -05:00
parent 4d49b0b2ee
commit ba14151a01
21 changed files with 413 additions and 72 deletions

View File

@@ -99,7 +99,7 @@ public class Blocks implements ContentList{
//storage
coreShard, coreFoundation, coreNucleus, vault, container, unloader,
//storage - erekir
coreBastion, coreCitadel, coreAcropolis,
coreBastion, coreCitadel, coreAcropolis, reinforcedContainer, reinforcedVault,
//turrets
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, foreshadow, spectre, meltdown, segment, parallax, tsunami,
@@ -1143,14 +1143,13 @@ public class Blocks implements ContentList{
size = 3;
liquidCapacity = 40f;
outputLiquid = new LiquidStack(Liquids.cyanogen, 3f);
craftTime = 60f * 1f;
consumes.liquid(Liquids.hydrogen, 3f / 60f);
consumes.item(Items.graphite);
consumes.power(2f);
liquidCapacity = 40f;
}};
//TODO bad name
@@ -1181,7 +1180,7 @@ public class Blocks implements ContentList{
}}, new DrawBlock(), new DrawHeatInput(), new DrawHeatRegion("-vents"){{
heatColor = new Color(1f, 0.4f, 0.3f, 1f);
}});
iconOverride = new String[]{"-bottom", ""};
iconOverride = new String[]{"-bottom", "-weave", ""};
consumes.items(with(Items.thorium, 2, Items.sand, 6));
consumes.liquid(Liquids.ozone, 2f / 60f);
@@ -2126,13 +2125,6 @@ public class Blocks implements ContentList{
researchCostMultiplier = 0.11f;
}};
vault = new StorageBlock("vault"){{
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3;
itemCapacity = 1000;
health = size * size * 55;
}};
container = new StorageBlock("container"){{
requirements(Category.effect, with(Items.titanium, 100));
size = 2;
@@ -2140,12 +2132,27 @@ public class Blocks implements ContentList{
health = size * size * 55;
}};
vault = new StorageBlock("vault"){{
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3;
itemCapacity = 1000;
health = size * size * 55;
}};
//TODO move tabs?
unloader = new Unloader("unloader"){{
requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30));
speed = 60f / 11f;
group = BlockGroup.transportation;
}};
reinforcedContainer = new StorageBlock("reinforced-container"){{
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3;
itemCapacity = 1000;
health = size * size * 120;
}};
//endregion
//region turrets
@@ -2681,10 +2688,31 @@ public class Blocks implements ContentList{
}};
//TODO bad name
if(false)
sublimate = new ContinuousTurret("sublimate"){{
//TODO requirements
requirements(Category.turret, with(Items.tungsten, 35, Items.silicon, 35), true);
draw = new DrawTurret("reinforced-"){{
parts.addAll(new RegionPart("-back"){{
outline = true;
rotMove = 30f;
offsetX = 29 / 4f;
offsetY = -10f / 4f;
originX = -8f / 4f;
originY = 8f / 4f;
}});
}};
outlineColor = Pal.darkOutline;
consumes.liquids(LiquidStack.with(Liquids.cyanogen, 3f / 60f, Liquids.ozone, 2f / 60f));
range = 170f;
shootType = new ContinuousFlameBulletType(){{
length = range;
}};
shootLength = 9f;
size = 3;
}};
//endregion

View File

@@ -0,0 +1,63 @@
package mindustry.entities.bullet;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
/** Basic continuous bullet type that does not draw itself. Essentially abstract. */
public class ContinuousBulletType extends BulletType{
public float length = 220f;
public float shake = 0f;
public float damageInterval = 5f;
public boolean largeHit = false;
{
speed = 0f;
despawnEffect = Fx.none;
lifetime = 16f;
impact = true;
keepVelocity = false;
collides = false;
pierce = true;
hittable = false;
absorbable = false;
}
@Override
public float continuousDamage(){
return damage / damageInterval * 60f;
}
@Override
public float estimateDPS(){
//assume firing duration is about 100 by default, may not be accurate there's no way of knowing in this method
//assume it pierces 3 blocks/units
return damage * 100f / damageInterval * 3f;
}
@Override
public float range(){
return Math.max(length, maxRange);
}
@Override
public void init(){
super.init();
drawSize = Math.max(drawSize, length*2f);
}
@Override
public void update(Bullet b){
//damage every 5 ticks
if(b.timer(1, damageInterval)){
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, largeHit);
}
if(shake > 0){
Effect.shake(shake, shake, b);
}
}
}

View File

@@ -0,0 +1,74 @@
package mindustry.entities.bullet;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
//TODO implement
public class ContinuousFlameBulletType extends ContinuousBulletType{
public float fadeTime = 16f;
public float lightStroke = 40f;
public float width = 3.7f, oscScl = 1.2f, oscMag = 0.02f;
public int divisions = 25;
/** Lengths, widths, ellipse panning, and offsets, all as fractions of the base width and length. Stored as an 'interleaved' array of values: LWPO1 LWPO2 LWPO3... */
public float[] lengthWidthPanOffsets = {
1.12f, 1.3f, 0.32f, 0f,
1f, 1f, 0.3f, 0f,
0.8f, 0.9f, 0.2f, 0.01f,
0.5f, 0.8f, 0.15f, 0.02f,
0.25f, 0.7f, 0.1f, 0.03f
};
public Color[] colors = {Color.valueOf("eb7abe").a(0.55f), Color.valueOf("e189f5").a(0.7f), Color.valueOf("907ef7").a(0.8f), Color.valueOf("91a4ff"), Color.white};
public ContinuousFlameBulletType(float damage){
this.damage = damage;
}
public ContinuousFlameBulletType(){
}
{
length = 120f;
hitEffect = Fx.hitBeam;
hitSize = 4;
drawSize = 420f;
lifetime = 16f;
hitColor = colors[3];
lightColor = colors[3];
}
@Override
public void draw(Bullet b){
float realLength = Damage.findLaserLength(b, length);
float fout = Mathf.clamp(b.time > b.lifetime - fadeTime ? 1f - (b.time - (lifetime - fadeTime)) / fadeTime : 1f);
float baseLen = realLength * fout;
float sin = Mathf.sin(Time.time, oscScl, oscMag);
for(int i = 0; i < colors.length; i++){
Draw.color(colors[i].write(Tmp.c1).mul(0.9f).mul(1f + Mathf.absin(Time.time, 1f, 0.1f)));
Drawf.flame(b.x, b.y, divisions, b.rotation(),
baseLen * lengthWidthPanOffsets[i * 4] * (1f - sin),
width * lengthWidthPanOffsets[i * 4 + 1] * fout * (1f + sin),
lengthWidthPanOffsets[i * 4 + 2],
baseLen * lengthWidthPanOffsets[i * 4 + 3]
);
}
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, lightStroke, lightColor, 0.7f);
Draw.reset();
}
@Override
public void drawLight(Bullet b){
//no light drawn here
}
}

View File

@@ -9,9 +9,7 @@ import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
public class ContinuousLaserBulletType extends BulletType{
public float length = 220f;
public float shake = 1f;
public class ContinuousLaserBulletType extends ContinuousBulletType{
public float fadeTime = 16f;
public float lightStroke = 40f;
public float spaceMag = 35f;
@@ -20,14 +18,18 @@ public class ContinuousLaserBulletType extends BulletType{
public float[] strokes = {2f, 1.5f, 1f, 0.3f};
public float[] lenscales = {1f, 1.12f, 1.15f, 1.17f};
public float width = 9f, oscScl = 0.8f, oscMag = 1.5f;
public boolean largeHit = true;
public ContinuousLaserBulletType(float damage){
this.damage = damage;
this.speed = 0f;
}
public ContinuousLaserBulletType(){
}
{
shake = 1f;
largeHit = true;
hitEffect = Fx.hitBeam;
despawnEffect = Fx.none;
hitSize = 4;
drawSize = 420f;
lifetime = 16f;
@@ -36,53 +38,6 @@ public class ContinuousLaserBulletType extends BulletType{
incendSpread = 5;
incendChance = 0.4f;
lightColor = Color.orange;
impact = true;
keepVelocity = false;
collides = false;
pierce = true;
hittable = false;
absorbable = false;
}
protected ContinuousLaserBulletType(){
this(0);
}
@Override
public float continuousDamage(){
return damage / 5f * 60f;
}
@Override
public float estimateDPS(){
//assume firing duration is about 100 by default, may not be accurate there's no way of knowing in this method
//assume it pierces 3 blocks/units
return damage * 100f / 5f * 3f;
}
@Override
public float range(){
return Math.max(length, maxRange);
}
@Override
public void init(){
super.init();
drawSize = Math.max(drawSize, length*2f);
}
@Override
public void update(Bullet b){
//damage every 5 ticks
if(b.timer(1, 5f)){
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, largeHit);
}
if(shake > 0){
Effect.shake(shake, shake, b);
}
}
@Override

View File

@@ -5,6 +5,7 @@ import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.ctype.*;
@@ -15,6 +16,51 @@ import mindustry.world.*;
import static mindustry.Vars.*;
public class Drawf{
private static FloatSeq points = new FloatSeq();
public static void flame(float x, float y, int divisions, float rotation, float length, float width, float pan){
flame(x, y, divisions, rotation, length, width, pan, 0f);
}
public static void flame(float x, float y, int divisions, float rotation, float length, float width, float pan, float offset){
float len1 = length * pan, len2 = length * (1f - pan);
points.clear();
//left side; half arc beginning at 90 degrees and ending at 270
for(int i = 0; i < divisions; i++){
float rot = 90f + 180f * i / (float)divisions;
Tmp.v1.trnsExact(rot, width);
point(
(Tmp.v1.x + width) / width * len1, //convert to 0..1, then multiply by desired length
Tmp.v1.y, //Y axis remains unchanged
x, y,
rotation
);
}
//right side; half arc beginning at -90 (270) and ending at 90
for(int i = 0; i < divisions; i++){
float rot = -90f + 180f * i / (float)divisions;
Tmp.v1.trnsExact(rot, width);
point(
len1 + (Tmp.v1.x) / width * len2, //convert to 0..1, then multiply by desired length and offset relative to previous segment
Tmp.v1.y, //Y axis remains unchanged
x, y,
rotation
);
}
Fill.poly(points);
}
private static void point(float x, float y, float baseX, float baseY, float rotation){
//TODO test exact and non-exact
Tmp.v1.set(x, y).rotateRadExact(rotation * Mathf.degRad);
points.add(Tmp.v1.x + baseX, Tmp.v1.y + baseY);
}
public static void dashLine(Color color, float x, float y, float x2, float y2){
int segments = (int)(Math.max(Math.abs(x - x2), Math.abs(y - y2)) / tilesize * 2);

View File

@@ -240,7 +240,7 @@ public class Weapon implements Cloneable{
mountY = unit.y + Angles.trnsy(unit.rotation - 90, x, y),
bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX, this.shootY),
bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX, this.shootY),
shootAngle = rotate ? weaponRotation + 90 : Angles.angle(bulletX, bulletY, mount.aimX, mount.aimY) + (unit.rotation - unit.angleTo(mount.aimX, mount.aimY));
shootAngle = rotate ? unit.rotation + mount.rotation : Angles.angle(bulletX, bulletY, mount.aimX, mount.aimY) + (unit.rotation - unit.angleTo(mount.aimX, mount.aimY));
//find a new target
if(!controllable && autoTarget){
@@ -333,8 +333,16 @@ public class Weapon implements Cloneable{
return Units.invalidateTarget(target, unit.team, x, y, range + Math.abs(shootY));
}
protected Vec2 getShootPos(Unit unit, WeaponMount mount, Vec2 out){
float weaponRot = unit.rotation - 90 + (rotate ? mount.rotation : 0);
return out.set(unit.x, unit.y)
.add(Angles.trnsx(unit.rotation - 90, x, y), Angles.trnsy(unit.rotation - 90, x, y))
.add(Angles.trnsx(weaponRot, this.shootX, this.shootY), Angles.trnsx(weaponRot, this.shootX, this.shootY));
}
protected void shoot(Unit unit, WeaponMount mount, float shootX, float shootY, float aimX, float aimY, float mountX, float mountY, float rotation, int side){
float baseX = unit.x, baseY = unit.y;
Vec2 offset = getShootPos(unit, mount, Tmp.v1);
float baseX = offset.x, baseY = offset.y, baseRot = unit.rotation + mount.rotation;
boolean delay = firstShotDelay + shotDelay > 0f;
(delay ? chargeSound : continuous ? Sounds.none : shootSound).at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax));
@@ -347,7 +355,11 @@ public class Weapon implements Cloneable{
Angles.shotgun(shots, spacing, rotation, f -> {
Time.run(sequenceNum * shotDelay + firstShotDelay, () -> {
if(!unit.isAdded()) return;
mount.bullet = bullet(unit, shootX + unit.x - baseX, shootY + unit.y - baseY, f + Mathf.range(inaccuracy), lifeScl);
getShootPos(unit, mount, offset).sub(baseX, baseY);
float rotOffset = unit.rotation + mount.rotation - baseRot;
mount.bullet = bullet(unit, shootX + offset.x, shootY + offset.y, f + Mathf.range(inaccuracy) + rotOffset, lifeScl);
if(!continuous){
shootSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax));
}
@@ -371,7 +383,10 @@ public class Weapon implements Cloneable{
if(!continuous){
shootSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax));
}
ammo.chargeShootEffect.at(shootX + unit.x - baseX, shootY + unit.y - baseY, rotation, parentize ? unit : null);
getShootPos(unit, mount, offset).sub(baseX, baseY);
ammo.chargeShootEffect.at(shootX + offset.x, shootY + offset.y, rotation, parentize ? unit : null);
});
}else{
unit.vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil));

View File

@@ -710,6 +710,10 @@ public class Block extends UnlockableContent{
return teamRegion.found() && minfo.mod == null ? new TextureRegion[]{r, teamRegions[Team.sharded.id]} : new TextureRegion[]{r};
}
public void getRegionsToOutline(Seq<TextureRegion> out){
}
public TextureRegion[] getGeneratedIcons(){
return generatedIcons == null ? (generatedIcons = icons()) : generatedIcons;
}

View File

@@ -42,7 +42,7 @@ public class ContinuousTurret extends Turret{
@Override
public boolean hasAmmo(){
return consValid();
return cons.canConsume();
}
@Override

View File

@@ -48,6 +48,7 @@ public class Turret extends ReloadTurret{
public float ammoEjectBack = 1f;
public float inaccuracy = 0f;
public float velocityInaccuracy = 0f;
public float shootWarmupSpeed = 3f / 60f;
public int shots = 1;
public float spread = 4f;
public float recoilAmount = 1f;
@@ -149,6 +150,11 @@ public class Turret extends ReloadTurret{
return draw.icons(this);
}
@Override
public void getRegionsToOutline(Seq<TextureRegion> out){
draw.getRegionsToOutline(out);
}
public static abstract class AmmoEntry{
public int amount;
@@ -165,6 +171,7 @@ public class Turret extends ReloadTurret{
public Seq<AmmoEntry> ammo = new Seq<>();
public int totalAmmo;
public float recoil, heat, logicControlTime = -1;
public float shootWarmup;
public int shotCounter;
public boolean logicShooting = false;
public @Nullable Posc target;
@@ -172,6 +179,11 @@ public class Turret extends ReloadTurret{
public BlockUnitc unit = (BlockUnitc)UnitTypes.block.create(team);
public boolean wasShooting, charging;
@Override
public float warmup(){
return shootWarmup;
}
@Override
public float drawrot(){
return rotation - 90;
@@ -273,6 +285,9 @@ public class Turret extends ReloadTurret{
public void updateTile(){
if(!validateTarget()) target = null;
//TODO can be lerp instead, that's smoother
shootWarmup = Mathf.approachDelta(shootWarmup, isActive() ? 1f : 0f, shootWarmupSpeed);
wasShooting = false;
recoil = Mathf.lerpDelta(recoil, 0f, restitution);

View File

@@ -138,6 +138,11 @@ public class GenericCrafter extends Block{
return outputItems != null;
}
@Override
public void getRegionsToOutline(Seq<TextureRegion> out){
drawer.getRegionsToOutline(out);
}
public class GenericCrafterBuild extends Building{
public float progress;
public float totalProgress;

View File

@@ -2,6 +2,7 @@ package mindustry.world.draw;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
@@ -22,6 +23,10 @@ public class DrawBlock{
@Deprecated
public void drawLight(GenericCrafterBuild build){}
public void getRegionsToOutline(Seq<TextureRegion> out){
}
/** Draws the block itself. */
public void drawBase(Building build){
Draw.rect(build.block.region, build.x, build.y, build.drawrot());

View File

@@ -24,6 +24,13 @@ public class DrawMulti extends DrawBlock{
this.drawers = drawers.toArray(DrawBlock.class);
}
@Override
public void getRegionsToOutline(Seq<TextureRegion> out){
for(var draw : drawers){
draw.getRegionsToOutline(out);
}
}
@Override
public void drawBase(Building build){
for(var draw : drawers){

View File

@@ -4,6 +4,8 @@ import arc.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.struct.*;
import arc.util.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.world.*;
@@ -14,8 +16,9 @@ import mindustry.world.blocks.defense.turrets.Turret.*;
public class DrawTurret extends DrawBlock{
protected static final Rand rand = new Rand();
public Seq<TurretPart> parts = new Seq<>();
public String basePrefix = "";
public TextureRegion base, liquid, top, heat;
public TextureRegion base, liquid, top, heat, preview;
public DrawTurret(String basePrefix){
this.basePrefix = basePrefix;
@@ -24,6 +27,13 @@ public class DrawTurret extends DrawBlock{
public DrawTurret(){
}
@Override
public void getRegionsToOutline(Seq<TextureRegion> out){
for(var part : parts){
part.getOutlines(out);
}
}
@Override
public void drawBase(Building build){
Turret turret = (Turret)build.block;
@@ -38,6 +48,12 @@ public class DrawTurret extends DrawBlock{
drawTurret(turret, tb);
drawHeat(turret, tb);
if(parts.size > 0){
for(var part : parts){
part.draw(tb);
}
}
}
public void drawTurret(Turret block, TurretBuild build){
@@ -67,11 +83,16 @@ public class DrawTurret extends DrawBlock{
public void load(Block block){
if(!(block instanceof Turret)) throw new ClassCastException("This drawer can only be used on turrets.");
preview = Core.atlas.find(block.name + "-preview", block.region);
liquid = Core.atlas.find(block.name + "-liquid");
top = Core.atlas.find(block.name + "-top");
heat = Core.atlas.find(block.name + "-heat");
base = Core.atlas.find(block.name + "-base");
for(var part : parts){
part.load(block);
}
//TODO test this for mods, e.g. exotic
if(!base.found() && block.minfo.mod != null) base = Core.atlas.find(block.minfo.mod.name + "-block-" + block.size);
if(!base.found()) base = Core.atlas.find(basePrefix + "block-" + block.size);
@@ -80,6 +101,98 @@ public class DrawTurret extends DrawBlock{
/** @return the generated icons to be used for this block. */
@Override
public TextureRegion[] icons(Block block){
return top.found() ? new TextureRegion[]{base, block.region, top} : new TextureRegion[]{base, block.region};
TextureRegion showTop = preview.found() ? preview : block.region;
return top.found() ? new TextureRegion[]{base, showTop, top} : new TextureRegion[]{base, showTop};
}
public static class RegionPart extends TurretPart{
public String suffix = "";
public boolean mirror = true;
public TextureRegion[] regions;
public TextureRegion[] outlines;
public boolean outline = false;
public float layer = -1;
public float outlineLayerOffset = -0.01f;
public float rotation, rotMove;
public float originX, originY;
public float offsetX, offsetY, offsetMoveX, offsetMoveY;
public RegionPart(String region){
this.suffix = region;
}
public RegionPart(){
}
@Override
public void draw(TurretBuild build){
float z = Draw.z();
if(layer > 0){
Draw.z(layer);
}
float prevZ = layer > 0 ? layer : z;
float progress = build.warmup();
for(int i = 0; i < regions.length; i++){
var region = regions[i];
float sign = i == 1 ? -1 : 1;
Tmp.v1.set((offsetX + offsetMoveX * progress) * sign, offsetY + offsetMoveY*progress).rotate(build.rotation - 90);
float
x = build.x + Tmp.v1.x,
y = build.y + Tmp.v1.y,
rot = (i == 0 ? rotation : 180f - rotation) + rotMove * progress * sign + build.rotation,
ox = originX + region.width * Draw.scl/2f, oy = originY + region.height * Draw.scl/2f;
if(outline){
Draw.z(prevZ + outlineLayerOffset);
Draw.rect(outlines[i],
x, y, region.width * Draw.scl, region.height * Draw.scl,
ox, oy, rot);
Draw.z(prevZ);
}
Draw.rect(region,
x, y, region.width * Draw.scl, region.height * Draw.scl,
ox, oy, rot);
}
Draw.z(z);
}
@Override
public void load(Block block){
if(mirror){
regions = new TextureRegion[]{
Core.atlas.find(block.name + suffix + "1"),
Core.atlas.find(block.name + suffix + "2")
};
outlines = new TextureRegion[]{
Core.atlas.find(block.name + suffix + "1-outline"),
Core.atlas.find(block.name + suffix + "2-outline")
};
}else{
regions = new TextureRegion[]{Core.atlas.find(block.name + suffix)};
outlines = new TextureRegion[]{Core.atlas.find(block.name + suffix + "-outline")};
}
}
@Override
public void getOutlines(Seq<TextureRegion> out){
if(outline){
out.addAll(regions);
}
}
}
public static abstract class TurretPart{
public abstract void draw(TurretBuild build);
public abstract void load(Block block);
public void getOutlines(Seq<TextureRegion> out){}
}
}