Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features
Conflicts: core/assets/logicids.dat core/src/mindustry/content/Blocks.java gradle.properties
This commit is contained in:
BIN
core/assets-raw/sprites/blocks/environment/pooled-cryofluid.png
Normal file
BIN
core/assets-raw/sprites/blocks/environment/pooled-cryofluid.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.3 KiB |
@@ -379,6 +379,9 @@ editor.ingame = Edit In-Game
|
||||
editor.publish.workshop = Publish On Workshop
|
||||
editor.newmap = New Map
|
||||
editor.center = Center
|
||||
editor.search = Search Maps...
|
||||
editor.filters = Filter Maps
|
||||
editor.showAll = Show Default Maps
|
||||
workshop = Workshop
|
||||
waves.title = Waves
|
||||
waves.remove = Remove
|
||||
@@ -1133,6 +1136,7 @@ block.sand-boulder.name = Sand Boulder
|
||||
block.basalt-boulder.name = Basalt Boulder
|
||||
block.grass.name = Grass
|
||||
block.molten-slag.name = Slag
|
||||
block.pooled-cryofluid.name = Cryofluid
|
||||
block.space.name = Space
|
||||
block.salt.name = Salt
|
||||
block.salt-wall.name = Salt Wall
|
||||
@@ -1613,7 +1617,7 @@ unit.omura.description = Fires a long-range piercing railgun bolt at enemies. Co
|
||||
unit.alpha.description = Defends the Shard core from enemies. Builds structures.
|
||||
unit.beta.description = Defends the Foundation core from enemies. Builds structures.
|
||||
unit.gamma.description = Defends the Nucleus core from enemies. Builds structures.
|
||||
unit.retusa.description = Places proximity mines. Repairs allied units.
|
||||
unit.retusa.description = Fires homing torpedos at nearby enemies. Repairs allied units.
|
||||
unit.oxynoe.description = Fires structure-repairing streams of flame at nearby enemies. Targets nearby enemy projectiles with a point defense turret.
|
||||
unit.cyerce.description = Fires seeking cluster-missiles at enemies. Repairs allied units.
|
||||
unit.aegires.description = Shocks all enemy units and structures that enter its energy field. Repairs all allies.
|
||||
|
||||
@@ -360,3 +360,4 @@
|
||||
63348=molten-slag|block-molten-slag-ui
|
||||
63347=crater-stone|block-crater-stone-ui
|
||||
63346=deep-tainted-water|block-deep-tainted-water-ui
|
||||
63345=pooled-cryofluid|block-pooled-cryofluid-ui
|
||||
|
||||
Binary file not shown.
Binary file not shown.
33
core/assets/shaders/cryofluid.frag
Normal file
33
core/assets/shaders/cryofluid.frag
Normal file
@@ -0,0 +1,33 @@
|
||||
#define HIGHP
|
||||
|
||||
//shades of cryofluid
|
||||
#define S1 vec3(53.0, 83.0, 93.0) / 100.0
|
||||
#define S2 vec3(68.0, 90.0, 97.0) / 100.0
|
||||
#define NSCALE 100.0 / 2.0
|
||||
|
||||
uniform sampler2D u_texture;
|
||||
uniform sampler2D u_noise;
|
||||
|
||||
uniform vec2 u_campos;
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_time;
|
||||
|
||||
varying vec2 v_texCoords;
|
||||
|
||||
void main(){
|
||||
vec2 c = v_texCoords.xy;
|
||||
vec2 coords = vec2(c.x * u_resolution.x + u_campos.x, c.y * u_resolution.y + u_campos.y);
|
||||
|
||||
float btime = u_time / 5000.0;
|
||||
float wave = abs(sin(coords.x * 1.1 + coords.y) + 0.1 * sin(2.5 * coords.x) + 0.15 * sin(3.0 * coords.y)) / 30.0;
|
||||
float noise = wave + (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.2, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0;
|
||||
vec4 color = texture2D(u_texture, c);
|
||||
|
||||
if(noise > 0.54 && noise < 0.57){
|
||||
color.rgb = S2;
|
||||
}else if (noise > 0.49 && noise < 0.62){
|
||||
color.rgb = S1;
|
||||
}
|
||||
|
||||
gl_FragColor = color;
|
||||
}
|
||||
@@ -18,7 +18,7 @@ void main(){
|
||||
vec2 c = v_texCoords.xy;
|
||||
vec2 coords = vec2(c.x * u_resolution.x + u_campos.x, c.y * u_resolution.y + u_campos.y);
|
||||
|
||||
float btime = u_time / 4000.0;
|
||||
float btime = u_time / 5000.0;
|
||||
float noise = (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.9, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0;
|
||||
vec4 color = texture2D(u_texture, c);
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@ import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Astar{
|
||||
@@ -13,7 +15,7 @@ public class Astar{
|
||||
|
||||
private static final Seq<Tile> out = new Seq<>();
|
||||
private static final PQueue<Tile> queue = new PQueue<>(200 * 200 / 4, (a, b) -> 0);
|
||||
private static final IntFloatMap costs = new IntFloatMap();
|
||||
private static float[] costs;
|
||||
private static byte[][] rotations;
|
||||
|
||||
public static Seq<Tile> pathfind(Tile from, Tile to, TileHueristic th, Boolf<Tile> passable){
|
||||
@@ -32,9 +34,14 @@ public class Astar{
|
||||
|
||||
GridBits closed = new GridBits(tiles.width, tiles.height);
|
||||
|
||||
costs.clear();
|
||||
if(costs == null || costs.length != tiles.width * tiles.height){
|
||||
costs = new float[tiles.width * tiles.height];
|
||||
}
|
||||
|
||||
Arrays.fill(costs, 0);
|
||||
|
||||
queue.clear();
|
||||
queue.comparator = Structs.comparingFloat(a -> costs.get(a.pos(), 0f) + dh.cost(a.x, a.y, end.x, end.y));
|
||||
queue.comparator = Structs.comparingFloat(a -> costs[a.array()] + dh.cost(a.x, a.y, end.x, end.y));
|
||||
queue.add(start);
|
||||
if(rotations == null || rotations.length != world.width() || rotations[0].length != world.height()){
|
||||
rotations = new byte[world.width()][world.height()];
|
||||
@@ -43,7 +50,7 @@ public class Astar{
|
||||
boolean found = false;
|
||||
while(!queue.empty()){
|
||||
Tile next = queue.poll();
|
||||
float baseCost = costs.get(next.pos(), 0f);
|
||||
float baseCost = costs[next.array()];
|
||||
if(next == end){
|
||||
found = true;
|
||||
break;
|
||||
@@ -58,7 +65,7 @@ public class Astar{
|
||||
if(!closed.get(child.x, child.y)){
|
||||
closed.set(child.x, child.y);
|
||||
rotations[child.x][child.y] = child.relativeTo(next.x, next.y);
|
||||
costs.put(child.pos(), newCost);
|
||||
costs[child.array()] = newCost;
|
||||
queue.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ public class SoundControl{
|
||||
sound.setBus(uiBus);
|
||||
}
|
||||
}
|
||||
|
||||
Events.fire(new MusicRegisterEvent());
|
||||
}
|
||||
|
||||
public void loop(Sound sound, float volume){
|
||||
|
||||
@@ -35,7 +35,7 @@ public class Blocks implements ContentList{
|
||||
public static Block
|
||||
|
||||
//environment
|
||||
air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty,
|
||||
air, spawn, cliff, deepwater, water, taintedWater, deepTaintedWater, tar, slag, cryofluid, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, empty,
|
||||
dacite, rhyolite, rhyoliteCrater, regolith, yellowStone, redIce,
|
||||
redmat, bluemat,
|
||||
stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
||||
@@ -210,6 +210,22 @@ public class Blocks implements ContentList{
|
||||
cacheLayer = CacheLayer.tar;
|
||||
}};
|
||||
|
||||
cryofluid = new Floor("pooled-cryofluid"){{
|
||||
drownTime = 150f;
|
||||
status = StatusEffects.freezing;
|
||||
statusDuration = 240f;
|
||||
speedMultiplier = 0.5f;
|
||||
variants = 0;
|
||||
liquidDrop = Liquids.cryofluid;
|
||||
liquidMultiplier = 0.5f;
|
||||
isLiquid = true;
|
||||
cacheLayer = CacheLayer.cryofluid;
|
||||
|
||||
emitLight = true;
|
||||
lightRadius = 25f;
|
||||
lightColor = Color.cyan.cpy().a(0.19f);
|
||||
}};
|
||||
|
||||
slag = new Floor("molten-slag"){{
|
||||
drownTime = 230f;
|
||||
status = StatusEffects.melting;
|
||||
@@ -1060,6 +1076,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
thruster = new Thruster("thruster"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, with(Items.scrap, 96));
|
||||
health = 55 * 16 * wallHealthMultiplier;
|
||||
size = 4;
|
||||
}};
|
||||
|
||||
@@ -369,13 +369,13 @@ public class Fx{
|
||||
|
||||
Fill.circle(e.x, e.y, e.fin() * 10);
|
||||
Drawf.light(e.x, e.y, e.fin() * 20f, Pal.heal, 0.7f);
|
||||
}).followParent(true),
|
||||
}).followParent(true).rotWithParent(true),
|
||||
|
||||
greenLaserChargeSmall = new Effect(40f, 100f, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fin() * 2f);
|
||||
Lines.circle(e.x, e.y, e.fout() * 50f);
|
||||
}).followParent(true),
|
||||
}).followParent(true).rotWithParent(true),
|
||||
|
||||
greenCloud = new Effect(80f, e -> {
|
||||
color(Pal.heal);
|
||||
@@ -1975,7 +1975,7 @@ public class Fx{
|
||||
}
|
||||
|
||||
Lines.endLine();
|
||||
}).followParent(false),
|
||||
}).followParent(false).rotWithParent(false),
|
||||
|
||||
chainEmp = new Effect(30f, 300f, e -> {
|
||||
if(!(e.data instanceof Position p)) return;
|
||||
@@ -2012,5 +2012,5 @@ public class Fx{
|
||||
}
|
||||
|
||||
Lines.endLine();
|
||||
}).followParent(false);
|
||||
}).followParent(false).rotWithParent(false);
|
||||
}
|
||||
|
||||
@@ -1787,7 +1787,6 @@ public class UnitTypes implements ContentList{
|
||||
//endregion
|
||||
//region naval support
|
||||
retusa = new UnitType("retusa"){{
|
||||
defaultController = HugAI::new;
|
||||
speed = 0.9f;
|
||||
targetAir = false;
|
||||
drag = 0.14f;
|
||||
@@ -1821,15 +1820,17 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
weapons.add(new Weapon(){{
|
||||
mirror = false;
|
||||
reload = 80f;
|
||||
rotate = true;
|
||||
reload = 90f;
|
||||
shots = 3;
|
||||
shotDelay = 7f;
|
||||
x = y = shootX = shootY = 0f;
|
||||
shootSound = Sounds.mineDeploy;
|
||||
rotateSpeed = 180f;
|
||||
|
||||
bullet = new BasicBulletType(){{
|
||||
sprite = "mine-bullet";
|
||||
width = height = 11f;
|
||||
width = height = 8f;
|
||||
layer = Layer.scorch;
|
||||
shootEffect = smokeEffect = Fx.none;
|
||||
|
||||
@@ -1843,23 +1844,31 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
hitSound = Sounds.plasmaboom;
|
||||
|
||||
shootCone = 360f;
|
||||
ejectEffect = Fx.none;
|
||||
hitSize = 22f;
|
||||
|
||||
collidesAir = false;
|
||||
|
||||
lifetime = 500f;
|
||||
lifetime = 87f;
|
||||
|
||||
hitEffect = new MultiEffect(Fx.blastExplosion, Fx.greenCloud);
|
||||
keepVelocity = false;
|
||||
|
||||
shrinkX = shrinkY = 0f;
|
||||
|
||||
speed = 0f;
|
||||
inaccuracy = 2f;
|
||||
weaveMag = 5f;
|
||||
weaveScale = 4f;
|
||||
speed = 0.7f;
|
||||
drag = -0.017f;
|
||||
homingPower = 0.05f;
|
||||
collideFloor = true;
|
||||
trailColor = Pal.heal;
|
||||
trailWidth = 3f;
|
||||
trailLength = 8;
|
||||
|
||||
splashDamage = 55f;
|
||||
splashDamageRadius = 45f;
|
||||
splashDamage = 33f;
|
||||
splashDamageRadius = 32f;
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
@@ -1934,7 +1943,7 @@ public class UnitTypes implements ContentList{
|
||||
shootEffect = Fx.sparkShoot;
|
||||
hitEffect = Fx.pointHit;
|
||||
maxRange = 100f;
|
||||
damage = 15f;
|
||||
damage = 17f;
|
||||
}};
|
||||
}});
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ public class GameState{
|
||||
public int wave = 1;
|
||||
/** Wave countdown in ticks. */
|
||||
public float wavetime;
|
||||
/** Logic tick. */
|
||||
public double tick;
|
||||
/** Whether the game is in game over state. */
|
||||
public boolean gameOver = false, serverPaused = false;
|
||||
/** Server ticks/second. Only valid in multiplayer. */
|
||||
|
||||
@@ -370,6 +370,9 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
|
||||
if(!state.isPaused()){
|
||||
float delta = Core.graphics.getDeltaTime();
|
||||
state.tick += Float.isNaN(delta) || Float.isInfinite(delta) ? 0f : delta * 60f;
|
||||
|
||||
state.teams.updateTeamStats();
|
||||
|
||||
if(state.isCampaign()){
|
||||
|
||||
@@ -19,6 +19,7 @@ import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.net.Administration.*;
|
||||
import mindustry.net.*;
|
||||
import mindustry.net.Packets.*;
|
||||
@@ -452,7 +453,7 @@ public class NetClient implements ApplicationListener{
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||
public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, int timeData, byte tps, byte[] coreData){
|
||||
public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, int timeData, byte tps, long rand0, long rand1, byte[] coreData){
|
||||
try{
|
||||
if(wave > state.wave){
|
||||
state.wave = wave;
|
||||
@@ -466,6 +467,11 @@ public class NetClient implements ApplicationListener{
|
||||
state.serverPaused = paused;
|
||||
state.serverTps = tps & 0xff;
|
||||
|
||||
//note that this is far from a guarantee that random state is synced - tiny changes in delta and ping can throw everything off again.
|
||||
//syncing will only make much of a difference when rand() is called infrequently
|
||||
GlobalConstants.rand.seed0 = rand0;
|
||||
GlobalConstants.rand.seed1 = rand1;
|
||||
|
||||
universe.updateNetSeconds(timeData);
|
||||
|
||||
netClient.byteStream.setBytes(coreData);
|
||||
|
||||
@@ -19,6 +19,7 @@ import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.net.*;
|
||||
import mindustry.net.Administration.*;
|
||||
import mindustry.net.Packets.*;
|
||||
@@ -867,7 +868,8 @@ public class NetServer implements ApplicationListener{
|
||||
dataStream.close();
|
||||
|
||||
//write basic state data.
|
||||
Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver, universe.seconds(), tps, syncStream.toByteArray());
|
||||
Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver,
|
||||
universe.seconds(), tps, GlobalConstants.rand.seed0, GlobalConstants.rand.seed1, syncStream.toByteArray());
|
||||
|
||||
syncStream.reset();
|
||||
|
||||
|
||||
@@ -30,8 +30,12 @@ public class Effect{
|
||||
public float lifetime = 50f;
|
||||
/** Clip size. */
|
||||
public float clip;
|
||||
/** Amount added to rotation */
|
||||
public float baseRotation;
|
||||
/** If true, parent unit is data are followed. */
|
||||
public boolean followParent;
|
||||
/** If this and followParent are true, the effect will offset and rotate with the parent's rotation. */
|
||||
public boolean rotWithParent;
|
||||
|
||||
public float layer = Layer.effect;
|
||||
public float layerDuration;
|
||||
@@ -61,11 +65,21 @@ public class Effect{
|
||||
return this;
|
||||
}
|
||||
|
||||
public Effect rotWithParent(boolean follow){
|
||||
rotWithParent = follow;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Effect layer(float l){
|
||||
layer = l;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Effect baseRotation(float d){
|
||||
baseRotation = d;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Effect layer(float l, float duration){
|
||||
layer = l;
|
||||
this.layerDuration = duration;
|
||||
@@ -156,12 +170,15 @@ public class Effect{
|
||||
|
||||
EffectState entity = EffectState.create();
|
||||
entity.effect = effect;
|
||||
entity.rotation = rotation;
|
||||
entity.rotation = effect.baseRotation + rotation;
|
||||
entity.data = data;
|
||||
entity.lifetime = effect.lifetime;
|
||||
entity.set(x, y);
|
||||
entity.color.set(color);
|
||||
if(effect.followParent && data instanceof Posc p) entity.parent = p;
|
||||
if(effect.followParent && data instanceof Posc p){
|
||||
entity.parent = p;
|
||||
entity.rotWithParent = effect.rotWithParent;
|
||||
}
|
||||
entity.add();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mindustry.entities.abilities;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
@@ -12,6 +13,7 @@ public class StatusFieldAbility extends Ability{
|
||||
public float duration = 60, reload = 100, range = 20;
|
||||
public Effect applyEffect = Fx.none;
|
||||
public Effect activeEffect = Fx.overdriveWave;
|
||||
public float effectX, effectY;
|
||||
public boolean parentizeEffects;
|
||||
|
||||
protected float timer;
|
||||
@@ -40,7 +42,8 @@ public class StatusFieldAbility extends Ability{
|
||||
applyEffect.at(other, parentizeEffects);
|
||||
});
|
||||
|
||||
activeEffect.at(unit, parentizeEffects);
|
||||
float x = unit.x + Angles.trnsx(unit.rotation, effectY, effectX), y = unit.y + Angles.trnsy(unit.rotation, effectY, effectX);
|
||||
activeEffect.at(x, y, unit.rotation, parentizeEffects ? unit : null);
|
||||
|
||||
timer = 0f;
|
||||
}
|
||||
|
||||
@@ -91,6 +91,10 @@ public class BulletType extends Content implements Cloneable{
|
||||
public boolean collidesAir = true, collidesGround = true;
|
||||
/** Whether this bullet types collides with anything at all. */
|
||||
public boolean collides = true;
|
||||
/** If true, this projectile collides with non-surface floors. */
|
||||
public boolean collideFloor = false;
|
||||
/** If true, this projectile collides with static walls */
|
||||
public boolean collideTerrain = false;
|
||||
/** Whether velocity is inherited from the shooter. */
|
||||
public boolean keepVelocity = true;
|
||||
/** Whether to scale lifetime (not actually velocity!) to disappear at the target position. Used for artillery. */
|
||||
|
||||
@@ -1037,7 +1037,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
int amount = Math.min(items.get(item), explosionItemCap());
|
||||
explosiveness += item.explosiveness * amount;
|
||||
flammability += item.flammability * amount;
|
||||
power += item.charge * amount * 100f;
|
||||
power += item.charge * Mathf.pow(amount, 1.1f) * 150f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,15 @@ import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -137,6 +140,20 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
|
||||
while(x >= 0 && y >= 0 && x < ww && y < wh){
|
||||
Building build = world.build(x, y);
|
||||
|
||||
if(type.collideFloor || type.collideTerrain){
|
||||
Tile tile = world.tile(x, y);
|
||||
if(
|
||||
type.collideFloor && (tile == null || tile.floor().hasSurface() || tile.block() != Blocks.air) ||
|
||||
type.collideTerrain && tile != null && tile.block() instanceof StaticWall
|
||||
){
|
||||
type.despawned(self());
|
||||
remove();
|
||||
hit = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(build != null && isAdded() && build.collide(self()) && type.testCollision(self(), build)
|
||||
&& !build.dead() && (type.collidesTeam || build.team != team) && !(type.pierceBuilding && hasCollided(build.id))){
|
||||
|
||||
|
||||
@@ -1,29 +1,41 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
@Component
|
||||
abstract class ChildComp implements Posc{
|
||||
@Import float x, y;
|
||||
abstract class ChildComp implements Posc, Rotc{
|
||||
@Import float x, y, rotation;
|
||||
|
||||
@Nullable Posc parent;
|
||||
float offsetX, offsetY;
|
||||
boolean rotWithParent;
|
||||
float offsetX, offsetY, offsetPos, offsetRot;
|
||||
|
||||
@Override
|
||||
public void add(){
|
||||
if(parent != null){
|
||||
offsetX = x - parent.getX();
|
||||
offsetY = y - parent.getY();
|
||||
if(rotWithParent && parent instanceof Rotc r){
|
||||
offsetPos = -r.rotation();
|
||||
offsetRot = rotation - r.rotation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
if(parent != null){
|
||||
x = parent.getX() + offsetX;
|
||||
y = parent.getY() + offsetY;
|
||||
if(rotWithParent && parent instanceof Rotc r){
|
||||
x = parent.getX() + Angles.trnsx(r.rotation() + offsetPos, offsetX, offsetY);
|
||||
y = parent.getY() + Angles.trnsy(r.rotation() + offsetPos, offsetX, offsetY);
|
||||
rotation = r.rotation() + offsetRot;
|
||||
}else{
|
||||
x = parent.getX() + offsetX;
|
||||
y = parent.getY() + offsetY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,7 +482,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
float explosiveness = 2f + item().explosiveness * stack().amount * 1.53f;
|
||||
float flammability = item().flammability * stack().amount / 1.9f;
|
||||
float power = item().charge * stack().amount * 150f;
|
||||
float power = item().charge * Mathf.pow(stack().amount, 1.11f) * 160f;
|
||||
|
||||
if(!spawnedByCore){
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness, power, bounds() / 2f, state.rules.damageExplosions, item().flammability > 1, team, type.deathExplosionEffect);
|
||||
|
||||
@@ -70,6 +70,8 @@ public class EventType{
|
||||
public static class ContentInitEvent{}
|
||||
/** Called when the client game is first loaded. */
|
||||
public static class ClientLoadEvent{}
|
||||
/** Called after SoundControl registers its music. */
|
||||
public static class MusicRegisterEvent{}
|
||||
/** Called *after* all the modded files have been added into Vars.tree */
|
||||
public static class FileTreeInitEvent{}
|
||||
/** Called when a game begins and the world is loaded. */
|
||||
|
||||
@@ -117,10 +117,30 @@ public class BlockRenderer{
|
||||
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
|
||||
}
|
||||
|
||||
invalidateTile(event.tile);
|
||||
recordIndex(event.tile);
|
||||
});
|
||||
}
|
||||
|
||||
public void invalidateTile(Tile tile){
|
||||
int avgx = (int)(camera.position.x / tilesize);
|
||||
int avgy = (int)(camera.position.y / tilesize);
|
||||
int rangex = (int)(camera.width / tilesize / 2) + 3;
|
||||
int rangey = (int)(camera.height / tilesize / 2) + 3;
|
||||
|
||||
if(Math.abs(avgx - tile.x) <= rangex && Math.abs(avgy - tile.y) <= rangey){
|
||||
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFloorIndex(Tile tile){
|
||||
if(indexFloor(tile)) floorTree.remove(tile);
|
||||
}
|
||||
|
||||
public void addFloorIndex(Tile tile){
|
||||
if(indexFloor(tile)) floorTree.insert(tile);
|
||||
}
|
||||
|
||||
boolean indexBlock(Tile tile){
|
||||
var block = tile.block();
|
||||
return tile.isCenter() && block != Blocks.air && block.cacheLayer == CacheLayer.normal;
|
||||
|
||||
@@ -10,7 +10,7 @@ import static mindustry.Vars.*;
|
||||
public class CacheLayer{
|
||||
public static CacheLayer
|
||||
|
||||
water, mud, tar, slag, space, normal, walls;
|
||||
water, mud, cryofluid, tar, slag, space, normal, walls;
|
||||
|
||||
public static CacheLayer[] all = {};
|
||||
|
||||
@@ -37,6 +37,7 @@ public class CacheLayer{
|
||||
mud = new ShaderLayer(Shaders.mud),
|
||||
tar = new ShaderLayer(Shaders.tar),
|
||||
slag = new ShaderLayer(Shaders.slag),
|
||||
cryofluid = new ShaderLayer(Shaders.cryofluid),
|
||||
space = new ShaderLayer(Shaders.space),
|
||||
normal = new CacheLayer(),
|
||||
walls = new CacheLayer()
|
||||
|
||||
@@ -21,7 +21,7 @@ public class Shaders{
|
||||
public static UnitBuildShader build;
|
||||
public static DarknessShader darkness;
|
||||
public static LightShader light;
|
||||
public static SurfaceShader water, mud, tar, slag, space, caustics;
|
||||
public static SurfaceShader water, mud, tar, slag, cryofluid, space, caustics;
|
||||
public static PlanetShader planet;
|
||||
public static CloudShader clouds;
|
||||
public static PlanetGridShader planetGrid;
|
||||
@@ -48,6 +48,7 @@ public class Shaders{
|
||||
mud = new SurfaceShader("mud");
|
||||
tar = new SurfaceShader("tar");
|
||||
slag = new SurfaceShader("slag");
|
||||
cryofluid = new SurfaceShader("cryofluid");
|
||||
space = new SpaceShader("space");
|
||||
caustics = new SurfaceShader("caustics"){
|
||||
@Override
|
||||
|
||||
@@ -92,6 +92,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
"build", Version.build,
|
||||
"mapname", state.map.name(),
|
||||
"wave", state.wave,
|
||||
"tick", state.tick,
|
||||
"wavetime", state.wavetime,
|
||||
"stats", JsonIO.write(state.stats),
|
||||
"rules", JsonIO.write(state.rules),
|
||||
@@ -110,6 +111,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
|
||||
state.wave = map.getInt("wave");
|
||||
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
|
||||
state.tick = map.getFloat("tick");
|
||||
state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}"));
|
||||
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
|
||||
if(state.rules.spawns.isEmpty()) state.rules.spawns = waves.get();
|
||||
|
||||
@@ -2,6 +2,7 @@ package mindustry.logic;
|
||||
|
||||
import arc.*;
|
||||
import arc.files.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
@@ -18,6 +19,8 @@ import java.io.*;
|
||||
public class GlobalConstants{
|
||||
public static final int ctrlProcessor = 1, ctrlPlayer = 2, ctrlFormation = 3;
|
||||
public static final ContentType[] lookableContent = {ContentType.block, ContentType.unit, ContentType.item, ContentType.liquid};
|
||||
/** Global random state. */
|
||||
public static final Rand rand = new Rand();
|
||||
|
||||
private ObjectIntMap<String> namesToIds = new ObjectIntMap<>();
|
||||
private Seq<Var> vars = new Seq<>(Var.class);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
@@ -56,9 +57,10 @@ public class LExecutor{
|
||||
|
||||
/** Runs a single instruction. */
|
||||
public void runOnce(){
|
||||
//set time
|
||||
vars[varTime].numval = Time.millis();
|
||||
vars[varTick].numval = Time.time;
|
||||
//set up time; note that @time is now only updated once every invocation and directly based off of @tick.
|
||||
//having time be based off of user system time was a very bad idea.
|
||||
vars[varTime].numval = state.tick / 60.0 * 1000.0;
|
||||
vars[varTick].numval = state.tick;
|
||||
|
||||
//reset to start
|
||||
if(vars[varCounter].numval >= instructions.length || vars[varCounter].numval < 0){
|
||||
@@ -449,7 +451,7 @@ public class LExecutor{
|
||||
case build -> {
|
||||
if(state.rules.logicUnitBuild && unit.canBuild() && exec.obj(p3) instanceof Block block && block.canBeBuilt()){
|
||||
int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize);
|
||||
int rot = exec.numi(p4);
|
||||
int rot = Mathf.mod(exec.numi(p4), 4);
|
||||
|
||||
//reset state of last request when necessary
|
||||
if(ai.plan.x != x || ai.plan.y != y || ai.plan.block != block || unit.plans.isEmpty()){
|
||||
|
||||
@@ -34,13 +34,13 @@ public enum LogicOp{
|
||||
angle("angle", true, (x, y) -> Angles.angle((float)x, (float)y)),
|
||||
len("len", true, (x, y) -> Mathf.dst((float)x, (float)y)),
|
||||
noise("noise", true, (x, y) -> Simplex.raw2d(0, x, y)),
|
||||
abs("abs", a -> Math.abs(a)),
|
||||
abs("abs", a -> Math.abs(a)), //not a method reference because it fails to compile for some reason
|
||||
log("log", Math::log),
|
||||
log10("log10", Math::log10),
|
||||
floor("floor", Math::floor),
|
||||
ceil("ceil", Math::ceil),
|
||||
sqrt("sqrt", Math::sqrt),
|
||||
rand("rand", d -> Mathf.rand.nextDouble() * d),
|
||||
rand("rand", d -> GlobalConstants.rand.nextDouble() * d),
|
||||
|
||||
sin("sin", d -> Math.sin(d * Mathf.doubleDegRad)),
|
||||
cos("cos", d -> Math.cos(d * Mathf.doubleDegRad)),
|
||||
|
||||
@@ -262,9 +262,36 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
|
||||
for(Room room : roomseq){
|
||||
spawn.connect(room);
|
||||
}
|
||||
|
||||
Room fspawn = spawn;
|
||||
|
||||
cells(1);
|
||||
|
||||
//shoreline setup
|
||||
int deepRadius = 4;
|
||||
|
||||
pass((x, y) -> {
|
||||
if(floor.asFloor().isLiquid && !floor.asFloor().isDeep()){
|
||||
|
||||
for(int cx = -deepRadius; cx <= deepRadius; cx++){
|
||||
for(int cy = -deepRadius; cy <= deepRadius; cy++){
|
||||
|
||||
if((cx) * (cx) + (cy) * (cy) <= deepRadius * deepRadius){
|
||||
int wx = cx + x, wy = cy + y;
|
||||
|
||||
Tile tile = tiles.get(wx, wy);
|
||||
if(tile != null && (!tile.floor().isLiquid || tile.block() != Blocks.air)){
|
||||
//found something solid, skip replacing anything
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
floor = floor == Blocks.darksandTaintedWater ? Blocks.taintedWater : Blocks.water;
|
||||
}
|
||||
});
|
||||
|
||||
distort(10f, 6f);
|
||||
|
||||
//rivers
|
||||
@@ -286,7 +313,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
|
||||
floor = spore ?
|
||||
(deep ? Blocks.taintedWater : Blocks.darksandTaintedWater) :
|
||||
(deep ? Blocks.water :
|
||||
(floor == Blocks.sand ? Blocks.sandWater : Blocks.darksandWater));
|
||||
(floor == Blocks.sand || floor == Blocks.salt ? Blocks.sandWater : Blocks.darksandWater));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.io.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.maps.Map;
|
||||
import mindustry.net.Administration.*;
|
||||
|
||||
@@ -40,6 +41,9 @@ public class NetworkIO{
|
||||
|
||||
stream.writeInt(state.wave);
|
||||
stream.writeFloat(state.wavetime);
|
||||
stream.writeDouble(state.tick);
|
||||
stream.writeLong(GlobalConstants.rand.seed0);
|
||||
stream.writeLong(GlobalConstants.rand.seed1);
|
||||
|
||||
stream.writeInt(player.id);
|
||||
player.write(Writes.get(stream));
|
||||
@@ -61,6 +65,9 @@ public class NetworkIO{
|
||||
|
||||
state.wave = stream.readInt();
|
||||
state.wavetime = stream.readFloat();
|
||||
state.tick = stream.readDouble();
|
||||
GlobalConstants.rand.seed0 = stream.readLong();
|
||||
GlobalConstants.rand.seed1 = stream.readLong();
|
||||
|
||||
Groups.clear();
|
||||
int id = stream.readInt();
|
||||
|
||||
@@ -166,6 +166,7 @@ public class GameService{
|
||||
if(campaign()){
|
||||
if(unitsBuilt.add(e.unit.type.name)){
|
||||
SStat.unitTypesBuilt.set(content.units().count(u -> unitsBuilt.contains(u.name) && !u.isHidden()));
|
||||
save();
|
||||
}
|
||||
|
||||
if(t5s.contains(e.unit.type)){
|
||||
|
||||
@@ -33,6 +33,8 @@ public class StatusEffect extends UnlockableContent{
|
||||
public float damage;
|
||||
/** Chance of effect appearing. */
|
||||
public float effectChance = 0.15f;
|
||||
/** Should the effect be given a parent */
|
||||
public boolean parentizeEffect;
|
||||
/** If true, the effect never disappears. */
|
||||
public boolean permanent;
|
||||
/** If true, this effect will only react with other effects and cannot be applied. */
|
||||
@@ -120,7 +122,7 @@ public class StatusEffect extends UnlockableContent{
|
||||
|
||||
if(effect != Fx.none && Mathf.chanceDelta(effectChance)){
|
||||
Tmp.v1.rnd(Mathf.range(unit.type.hitSize/2f));
|
||||
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, color);
|
||||
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y, 0, color, parentizeEffect ? unit : null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,18 @@ public class Weapon implements Cloneable{
|
||||
boolean can = unit.canShoot();
|
||||
mount.reload = Math.max(mount.reload - Time.delta * unit.reloadMultiplier, 0);
|
||||
|
||||
//rotate if applicable
|
||||
if(rotate && (mount.rotate || mount.shoot) && can){
|
||||
float axisX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
|
||||
axisY = unit.y + Angles.trnsy(unit.rotation - 90, x, y);
|
||||
|
||||
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - unit.rotation;
|
||||
mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, rotateSpeed * Time.delta);
|
||||
}else if(!rotate){
|
||||
mount.rotation = 0;
|
||||
mount.targetRotation = unit.angleTo(mount.aimX, mount.aimY);
|
||||
}
|
||||
|
||||
float
|
||||
weaponRotation = unit.rotation - 90 + (rotate ? mount.rotation : 0),
|
||||
mountX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
|
||||
@@ -256,7 +268,7 @@ public class Weapon implements Cloneable{
|
||||
}
|
||||
}else{
|
||||
//heat decreases when not firing
|
||||
mount.heat = Math.max(mount.heat - Time.delta * unit.reloadMultiplier / mount.weapon.cooldownTime, 0);
|
||||
mount.heat = Math.max(mount.heat - Time.delta * unit.reloadMultiplier / cooldownTime, 0);
|
||||
|
||||
if(mount.sound != null){
|
||||
mount.sound.update(bulletX, bulletY, false);
|
||||
@@ -270,26 +282,14 @@ public class Weapon implements Cloneable{
|
||||
mount.side = !mount.side;
|
||||
}
|
||||
|
||||
//rotate if applicable
|
||||
if(rotate && (mount.rotate || mount.shoot) && can){
|
||||
float axisX = unit.x + Angles.trnsx(unit.rotation - 90, x, y),
|
||||
axisY = unit.y + Angles.trnsy(unit.rotation - 90, x, y);
|
||||
|
||||
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - unit.rotation;
|
||||
mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, rotateSpeed * Time.delta);
|
||||
}else if(!rotate){
|
||||
mount.rotation = 0;
|
||||
mount.targetRotation = unit.angleTo(mount.aimX, mount.aimY);
|
||||
}
|
||||
|
||||
//shoot if applicable
|
||||
if(mount.shoot && //must be shooting
|
||||
can && //must be able to shoot
|
||||
(!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo || unit.team.rules().infiniteAmmo) && //check ammo
|
||||
(!alternate || mount.side == flipSprite) &&
|
||||
unit.vel.len() >= mount.weapon.minShootVelocity && //check velocity requirements
|
||||
unit.vel.len() >= minShootVelocity && //check velocity requirements
|
||||
mount.reload <= 0.0001f && //reload has to be 0
|
||||
Angles.within(rotate ? mount.rotation : unit.rotation, mount.targetRotation, mount.weapon.shootCone) //has to be within the cone
|
||||
Angles.within(rotate ? mount.rotation : unit.rotation, mount.targetRotation, shootCone) //has to be within the cone
|
||||
){
|
||||
shoot(unit, mount, bulletX, bulletY, mount.aimX, mount.aimY, mountX, mountY, shootAngle, Mathf.sign(x));
|
||||
|
||||
|
||||
@@ -2,11 +2,14 @@ package mindustry.ui.dialogs;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.io.*;
|
||||
@@ -17,6 +20,12 @@ import static mindustry.Vars.*;
|
||||
|
||||
public class MapsDialog extends BaseDialog{
|
||||
private BaseDialog dialog;
|
||||
private String searchString;
|
||||
private Seq<Gamemode> modes = new Seq<>();
|
||||
private Table mapTable = new Table();
|
||||
private TextField searchField;
|
||||
|
||||
private boolean showAll = Core.settings.getBool("editorShowAllMaps", true);
|
||||
|
||||
public MapsDialog(){
|
||||
super("@maps");
|
||||
@@ -37,8 +46,10 @@ public class MapsDialog extends BaseDialog{
|
||||
void setup(){
|
||||
buttons.clearChildren();
|
||||
|
||||
searchString = null;
|
||||
|
||||
if(Core.graphics.isPortrait()){
|
||||
buttons.button("@back", Icon.left, this::hide).size(210f*2f, 64f).colspan(2);
|
||||
buttons.button("@back", Icon.left, this::hide).size(210f * 2f, 64f).colspan(2);
|
||||
buttons.row();
|
||||
}else{
|
||||
buttons.button("@back", Icon.left, this::hide).size(210f, 64f);
|
||||
@@ -108,26 +119,58 @@ public class MapsDialog extends BaseDialog{
|
||||
});
|
||||
}).size(210f, 64f);
|
||||
|
||||
|
||||
cont.clear();
|
||||
|
||||
Table maps = new Table();
|
||||
maps.marginRight(24);
|
||||
rebuildMaps();
|
||||
|
||||
ScrollPane pane = new ScrollPane(maps);
|
||||
ScrollPane pane = new ScrollPane(mapTable);
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
Table search = new Table();
|
||||
search.image(Icon.zoom);
|
||||
searchField = search.field("", t -> {
|
||||
searchString = t.length() > 0 ? t.toLowerCase() : null;
|
||||
rebuildMaps();
|
||||
}).maxTextLength(50).growX().get();
|
||||
searchField.setMessageText("@editor.search");
|
||||
search.button(Icon.filter, Styles.emptyi, this::showMapFilters);
|
||||
|
||||
cont.add(search).growX();
|
||||
cont.row();
|
||||
cont.add(pane).uniformX().growY();
|
||||
cont.row();
|
||||
cont.add(buttons).growX();
|
||||
}
|
||||
|
||||
void rebuildMaps(){
|
||||
mapTable.clear();
|
||||
|
||||
mapTable.marginRight(24);
|
||||
|
||||
int maxwidth = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1);
|
||||
float mapsize = 200f;
|
||||
boolean noMapsShown = true;
|
||||
|
||||
int i = 0;
|
||||
for(Map map : Vars.maps.all()){
|
||||
|
||||
if(i % maxwidth == 0){
|
||||
maps.row();
|
||||
Seq<Map> mapList = showAll ? Vars.maps.all() : Vars.maps.customMaps();
|
||||
for(Map map : mapList){
|
||||
|
||||
boolean invalid = false;
|
||||
for(Gamemode mode : modes){
|
||||
invalid |= !mode.valid(map);
|
||||
}
|
||||
if(invalid || (searchString != null && !Strings.stripColors(map.name()).toLowerCase().contains(searchString))){
|
||||
continue;
|
||||
}
|
||||
|
||||
TextButton button = maps.button("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get();
|
||||
noMapsShown = false;
|
||||
|
||||
if(i % maxwidth == 0){
|
||||
mapTable.row();
|
||||
}
|
||||
|
||||
TextButton button = mapTable.button("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get();
|
||||
button.clearChildren();
|
||||
button.margin(9);
|
||||
button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true);
|
||||
@@ -141,13 +184,41 @@ public class MapsDialog extends BaseDialog{
|
||||
i++;
|
||||
}
|
||||
|
||||
if(Vars.maps.all().size == 0){
|
||||
maps.add("@maps.none");
|
||||
if(noMapsShown){
|
||||
mapTable.add("@maps.none");
|
||||
}
|
||||
}
|
||||
|
||||
cont.add(buttons).growX();
|
||||
cont.row();
|
||||
cont.add(pane).uniformX();
|
||||
void showMapFilters(){
|
||||
dialog = new BaseDialog("@editor.filters");
|
||||
dialog.addCloseButton();
|
||||
dialog.setFillParent(false);
|
||||
dialog.cont.table(Tex.button, t -> {
|
||||
int i = 0;
|
||||
for(Gamemode mode : Gamemode.all){
|
||||
TextureRegionDrawable icon = Vars.ui.getIcon("mode" + Strings.capitalize(mode.name()));
|
||||
if(Core.atlas.isFound(icon.getRegion())){
|
||||
t.button(mode.name(), icon, Styles.clearTogglet, () -> {
|
||||
if(modes.contains(mode)){
|
||||
modes.remove(mode);
|
||||
}else{
|
||||
modes.add(mode);
|
||||
}
|
||||
rebuildMaps();
|
||||
}).size(150f, 60f).marginLeft(6f).checked(modes.contains(mode));
|
||||
if(++i % 3 == 0) t.row();
|
||||
}
|
||||
}
|
||||
t.row();
|
||||
t.button("@editor.showAll", Styles.clearTogglet, () -> {
|
||||
showAll = !showAll;
|
||||
Core.settings.put("editorShowAllMaps", showAll);
|
||||
Core.settings.forceSave();
|
||||
rebuildMaps();
|
||||
}).checked(b -> showAll).colspan(3).growX().height(40f);
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
void showMapInfo(Map map){
|
||||
@@ -213,4 +284,15 @@ public class MapsDialog extends BaseDialog{
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog show(){
|
||||
super.show();
|
||||
|
||||
if(Core.app.isDesktop() && searchField != null){
|
||||
Core.scene.setKeyboardFocus(searchField);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ public class ModsDialog extends BaseDialog{
|
||||
|
||||
}).tooltip(c.localizedName);
|
||||
|
||||
if(++i % Math.min(Core.graphics.getWidth() / Scl.scl(110), 14) == 0) cs.row();
|
||||
if(++i % (int)Math.min(Core.graphics.getWidth() / Scl.scl(110), 14) == 0) cs.row();
|
||||
}
|
||||
}).grow();
|
||||
d.addCloseButton();
|
||||
|
||||
@@ -35,7 +35,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
private String search = "";
|
||||
private TextField searchField;
|
||||
private Runnable rebuildPane = () -> {}, rebuildTags = () -> {};
|
||||
private Pattern ignoreSymbols = Pattern.compile("[`~!@#$%^&*()-_=+{}|;:'\",<.>/?]");
|
||||
private Pattern ignoreSymbols = Pattern.compile("[`~!@#$%^&*()\\-_=+{}|;:'\",<.>/?]");
|
||||
private Seq<String> tags, selectedTags = new Seq<>();
|
||||
private boolean checkedTags;
|
||||
|
||||
@@ -334,12 +334,6 @@ public class SchematicsDialog extends BaseDialog{
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public void focusSearchField(){
|
||||
if(searchField == null) return;
|
||||
|
||||
Core.scene.setKeyboardFocus(searchField);
|
||||
}
|
||||
|
||||
|
||||
//adds all new tags to the global list of tags
|
||||
//alternatively, unknown tags could be discarded on import?
|
||||
@@ -635,8 +629,8 @@ public class SchematicsDialog extends BaseDialog{
|
||||
public Dialog show(){
|
||||
super.show();
|
||||
|
||||
if(Core.app.isDesktop()){
|
||||
focusSearchField();
|
||||
if(Core.app.isDesktop() && searchField != null){
|
||||
Core.scene.setKeyboardFocus(searchField);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
@@ -17,7 +17,6 @@ import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.content.TechTree.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -32,7 +31,7 @@ import java.util.zip.*;
|
||||
import static arc.Core.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class SettingsMenuDialog extends Dialog{
|
||||
public class SettingsMenuDialog extends BaseDialog{
|
||||
public SettingsTable graphics;
|
||||
public SettingsTable game;
|
||||
public SettingsTable sound;
|
||||
@@ -48,39 +47,20 @@ public class SettingsMenuDialog extends Dialog{
|
||||
addCloseButton();
|
||||
|
||||
cont.add(main = new SettingsTable());
|
||||
|
||||
hidden(() -> {
|
||||
Sounds.back.play();
|
||||
if(state.isGame()){
|
||||
if(!wasPaused || net.active())
|
||||
state.set(State.playing);
|
||||
}
|
||||
});
|
||||
shouldPause = true;
|
||||
|
||||
shown(() -> {
|
||||
back();
|
||||
if(state.isGame()){
|
||||
wasPaused = state.is(State.paused);
|
||||
state.set(State.paused);
|
||||
}
|
||||
|
||||
rebuildMenu();
|
||||
});
|
||||
|
||||
Events.on(ResizeEvent.class, event -> {
|
||||
if(isShown() && Core.scene.getDialog() == this){
|
||||
graphics.rebuild();
|
||||
sound.rebuild();
|
||||
game.rebuild();
|
||||
updateScrollFocus();
|
||||
}
|
||||
onResize(() -> {
|
||||
graphics.rebuild();
|
||||
sound.rebuild();
|
||||
game.rebuild();
|
||||
updateScrollFocus();
|
||||
});
|
||||
|
||||
setFillParent(true);
|
||||
title.setAlignment(Align.center);
|
||||
titleTable.row();
|
||||
titleTable.add(new Image()).growX().height(3f).pad(4f).get().setColor(Pal.accent);
|
||||
|
||||
cont.clearChildren();
|
||||
cont.remove();
|
||||
buttons.remove();
|
||||
|
||||
@@ -177,9 +177,7 @@ public class HintsFragment extends Fragment{
|
||||
&& state.rules.defaultTeam.core().items.has(Blocks.coreFoundation.requirements),
|
||||
() -> ui.hints.placedBlocks.contains(Blocks.coreFoundation)),
|
||||
presetLaunch(() -> state.isCampaign()
|
||||
&& state.getSector().preset == null
|
||||
&& SectorPresets.frozenForest.unlocked()
|
||||
&& SectorPresets.frozenForest.sector.save == null,
|
||||
&& state.getSector().preset == null,
|
||||
() -> state.isCampaign() && state.getSector().preset == SectorPresets.frozenForest),
|
||||
presetDifficulty(() -> state.isCampaign()
|
||||
&& state.getSector().preset == null
|
||||
|
||||
@@ -205,10 +205,16 @@ public class Block extends UnlockableContent{
|
||||
public int outlinedIcon = -1;
|
||||
/** Whether this block has a shadow under it. */
|
||||
public boolean hasShadow = true;
|
||||
/** Sounds made when this block is destroyed.*/
|
||||
public Sound destroySound = Sounds.boom;
|
||||
/** Should the sound made when this block is built change in pitch. */
|
||||
public boolean placePitchChange = true;
|
||||
/** Should the sound made when this block is deconstructed change in pitch. */
|
||||
public boolean breakPitchChange = true;
|
||||
/** Sound made when this block is built. */
|
||||
public Sound placeSound = Sounds.place;
|
||||
/** Sound made when this block is deconstructed. */
|
||||
public Sound breakSound = Sounds.breaks;
|
||||
/** Sounds made when this block is destroyed.*/
|
||||
public Sound destroySound = Sounds.boom;
|
||||
/** How reflective this block is. */
|
||||
public float albedo = 0f;
|
||||
/** Environmental passive light color. */
|
||||
|
||||
@@ -62,6 +62,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
return Point2.pack(x, y);
|
||||
}
|
||||
|
||||
/** @return this tile's position, packed to the world width - for use in width*height arrays. */
|
||||
public int array(){
|
||||
return x + y * world.tiles.width;
|
||||
}
|
||||
|
||||
public byte relativeTo(Tile tile){
|
||||
return relativeTo(tile.x, tile.y);
|
||||
}
|
||||
@@ -269,6 +274,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
this.floor = type;
|
||||
this.overlay = (Floor)Blocks.air;
|
||||
|
||||
if(!headless && !world.isGenerating()){
|
||||
renderer.blocks.removeFloorIndex(this);
|
||||
}
|
||||
|
||||
recache();
|
||||
if(build != null){
|
||||
build.onProximityUpdate();
|
||||
@@ -305,6 +314,8 @@ public class Tile implements Position, QuadTreeObject, Displayable{
|
||||
if(!headless && !world.isGenerating()){
|
||||
renderer.blocks.floor.recacheTile(this);
|
||||
renderer.minimap.update(this);
|
||||
renderer.blocks.invalidateTile(this);
|
||||
renderer.blocks.addFloorIndex(this);
|
||||
//update neighbor tiles as well
|
||||
for(int i = 0; i < 8; i++){
|
||||
Tile other = world.tile(x + Geometry.d8[i].x, y + Geometry.d8[i].y);
|
||||
|
||||
@@ -58,7 +58,7 @@ public class ConstructBlock extends Block{
|
||||
block.breakEffect.at(tile.drawx(), tile.drawy(), block.size, block.mapColor);
|
||||
Events.fire(new BlockBuildEndEvent(tile, builder, team, true, null));
|
||||
tile.remove();
|
||||
if(shouldPlay()) block.breakSound.at(tile, calcPitch(false));
|
||||
if(shouldPlay()) block.breakSound.at(tile, block.breakPitchChange ? calcPitch(false) : 1f);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
@@ -97,7 +97,7 @@ public class ConstructBlock extends Block{
|
||||
}
|
||||
|
||||
Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size);
|
||||
if(shouldPlay()) Sounds.place.at(tile, calcPitch(true));
|
||||
if(shouldPlay()) block.placeSound.at(tile, block.placePitchChange ? calcPitch(true) : 1f);
|
||||
|
||||
Events.fire(new BlockBuildEndEvent(tile, builder, team, false, config));
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class LaserTurret extends PowerTurret{
|
||||
Liquid liquid = liquids.current();
|
||||
float maxUsed = consumes.<ConsumeLiquidBase>get(ConsumeType.liquid).amount;
|
||||
|
||||
float used = (cheating() ? maxUsed * Time.delta : Math.min(liquids.get(liquid), maxUsed * Time.delta));
|
||||
float used = (cheating() ? maxUsed : Math.min(liquids.get(liquid), maxUsed)) * Time.delta;
|
||||
reload -= used * liquid.heatCapacity * coolantMultiplier;
|
||||
liquids.remove(liquid, used);
|
||||
|
||||
|
||||
@@ -127,24 +127,32 @@ public class GenericCrafter extends Block{
|
||||
}
|
||||
|
||||
if(progress >= 1f){
|
||||
consume();
|
||||
|
||||
if(outputItems != null){
|
||||
for(ItemStack output : outputItems){
|
||||
for(int i = 0; i < output.amount; i++){
|
||||
offload(output.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(outputLiquid != null){
|
||||
handleLiquid(this, outputLiquid.liquid, outputLiquid.amount);
|
||||
}
|
||||
|
||||
craftEffect.at(x, y);
|
||||
progress %= 1f;
|
||||
craft();
|
||||
}
|
||||
|
||||
dumpOutputs();
|
||||
}
|
||||
|
||||
public void craft(){
|
||||
consume();
|
||||
|
||||
if(outputItems != null){
|
||||
for(ItemStack output : outputItems){
|
||||
for(int i = 0; i < output.amount; i++){
|
||||
offload(output.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(outputLiquid != null){
|
||||
handleLiquid(this, outputLiquid.liquid, outputLiquid.amount);
|
||||
}
|
||||
|
||||
craftEffect.at(x, y);
|
||||
progress %= 1f;
|
||||
}
|
||||
|
||||
public void dumpOutputs(){
|
||||
if(outputItems != null && timer(timerDump, dumpTime / timeScale)){
|
||||
for(ItemStack output : outputItems){
|
||||
dump(output.item);
|
||||
|
||||
Reference in New Issue
Block a user