Compare commits

..

41 Commits
v128 ... v128.1

Author SHA1 Message Date
Anuken
33d4ab9edb Fixed block plans not being deleted locally 2021-07-17 19:17:47 -04:00
Anuken
f7f2b3438c Use short filter names in JSON 2021-07-17 16:46:35 -04:00
Anuken
0ed7934df0 arc 2021-07-17 15:33:19 -04:00
Anuken
55920e6242 Cleanup 2021-07-17 15:18:51 -04:00
Anuken
820920e5f9 Redundant cast cleanup 2021-07-17 09:30:31 -04:00
Anuken
8e21c627a7 Improved Serpulo sector path generation 2021-07-17 09:22:02 -04:00
Anuken
6973ed7d55 PvP defeated team cleanup 2021-07-17 08:52:24 -04:00
Anuken
0980495a28 (commented) support for Call server-to-client sounds 2021-07-16 15:39:03 -04:00
Anuken
5c6b659ce3 Possible rare crash fix 2021-07-16 12:59:50 -04:00
Anuken
35e263223d Merge remote-tracking branch 'origin/master' 2021-07-16 12:37:36 -04:00
Anuken
07ba378095 Hide construct/legacy blocks 2021-07-16 12:37:31 -04:00
buthed010203
6e10f86546 Display item rates on reconstructors (#5581)
Display the rates here because why not
![]https://mee6.is-terrible.com/54feDAY76.png
2021-07-16 12:21:58 -04:00
RebornTrack970
fc6ee11ffe Some more servers are back (#5594)
* Servers Back

* Update servers_v7.json
2021-07-16 12:19:56 -04:00
Anuken
84cd87370f Merge remote-tracking branch 'origin/master' 2021-07-16 10:06:07 -04:00
Anuken
822fe9ab7a Fixed inaccessible gaps in Serpulo generator 2021-07-16 10:05:59 -04:00
Sharlotte
57b22a9cab Update bundle_ko.properties (#5590) 2021-07-16 08:56:23 -04:00
Anuken
278c4f17e5 Why was this class even created 2021-07-15 20:19:51 -04:00
Anuken
b0d4607798 Fixed #5588 2021-07-15 20:08:05 -04:00
Anuken
3f7dc66ac0 Fixed #5587 2021-07-15 14:55:32 -04:00
Anuken
1c2b1fb757 System property cleanup 2021-07-15 11:27:21 -04:00
Anuken
eb31483a15 Fixed #5585 2021-07-15 10:18:08 -04:00
Anuken
8fb7cdaba6 Fixed #5584 2021-07-15 10:10:36 -04:00
Anuken
61d81046ae Fixed #5583 2021-07-15 08:46:56 -04:00
Anuken
0c3d7e09e0 Don't crash when font glyphs are missing 2021-07-14 21:40:47 -04:00
Anuken
a9f9ddcacf AnnotationProxyMaker workaround cleanup 2021-07-14 19:52:43 -04:00
Anuken
a559c3581e Fixed continuous weapon sounds / Improved naval support audio 2021-07-14 18:46:51 -04:00
Anuken
dd5389c738 New sound for rock/plant breaking 2021-07-14 17:22:21 -04:00
Anuken
ac25e17286 Unused property cleanup 2021-07-14 16:06:03 -04:00
Anuken
9de4c89e76 Fixed #5582 2021-07-14 15:55:40 -04:00
Anuken
2f6846d8c3 Conveyor tweaks 2021-07-14 15:12:00 -04:00
Anuken
c3e60531c4 Merge remote-tracking branch 'origin/master' 2021-07-14 09:28:05 -04:00
Anuken
44aff82a6c "Fixed" #5580 2021-07-14 09:27:59 -04:00
alex
7619e7643d Update v6 servers for alex servers (#5576) 2021-07-14 09:23:53 -04:00
RebornTrack970
353ef05b93 OmegaHub is back (kinda) (#5578) 2021-07-14 09:23:41 -04:00
Anuken
2801e4ed80 Fixed #5579 2021-07-14 09:14:19 -04:00
Anuken
173dd0a90e Fixed #5577 2021-07-14 09:07:17 -04:00
Anuken
e5412aeb1b Inventory constant cleanup 2021-07-13 17:38:42 -04:00
Anuken
0eec955a3d #5563 2021-07-13 10:42:00 -04:00
Anuken
47038ac06d Longer mod test timeout 2021-07-13 10:33:44 -04:00
Anuken
8041c305ad Misc bugfixes 2021-07-13 10:28:35 -04:00
Anuken
e0d249898e Fixed mod dialog width... again. 2021-07-12 16:18:29 -04:00
65 changed files with 339 additions and 220 deletions

View File

@@ -1,5 +1,7 @@
package mindustry.annotations.impl; package mindustry.annotations.impl;
import arc.*;
import arc.audio.*;
import arc.files.*; import arc.files.*;
import arc.scene.style.*; import arc.scene.style.*;
import arc.struct.*; import arc.struct.*;
@@ -118,9 +120,31 @@ public class AssetsProcess extends BaseProcessor{
void processSounds(String classname, String path, String rtype) throws Exception{ void processSounds(String classname, String path, String rtype) throws Exception{
TypeSpec.Builder type = TypeSpec.classBuilder(classname).addModifiers(Modifier.PUBLIC); TypeSpec.Builder type = TypeSpec.classBuilder(classname).addModifiers(Modifier.PUBLIC);
MethodSpec.Builder loadBegin = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC); MethodSpec.Builder loadBegin = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
CodeBlock.Builder staticb = CodeBlock.builder();
type.addField(FieldSpec.builder(IntMap.class, "idToSound", Modifier.STATIC, Modifier.PRIVATE).initializer("new IntMap()").build());
type.addField(FieldSpec.builder(ObjectIntMap.class, "soundToId", Modifier.STATIC, Modifier.PRIVATE).initializer("new ObjectIntMap()").build());
type.addMethod(MethodSpec.methodBuilder("getSoundId")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(Sound.class, "sound")
.returns(int.class)
.addStatement("return soundToId.get(sound, -1)").build());
type.addMethod(MethodSpec.methodBuilder("getSound")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(int.class, "id")
.returns(Sound.class)
.addStatement("return (Sound)idToSound.get(id, () -> Sounds.none)").build());
HashSet<String> names = new HashSet<>(); HashSet<String> names = new HashSet<>();
Fi.get(path).walk(p -> { Seq<Fi> files = new Seq<>();
Fi.get(path).walk(files::add);
files.sortComparing(Fi::name);
int id = 0;
for(Fi p : files){
String name = p.nameWithoutExtension(); String name = p.nameWithoutExtension();
if(names.contains(name)){ if(names.contains(name)){
@@ -133,14 +157,20 @@ public class AssetsProcess extends BaseProcessor{
String filepath = path.substring(path.lastIndexOf("/") + 1) + p.path().substring(p.path().lastIndexOf(path) + path.length()); String filepath = path.substring(path.lastIndexOf("/") + 1) + p.path().substring(p.path().lastIndexOf(path) + path.length());
String filename = "\"" + filepath + "\""; staticb.addStatement("soundToId.put($L, $L)", name, id);
loadBegin.addStatement("arc.Core.assets.load(" + filename + ", " + rtype + ".class).loaded = a -> " + name + " = (" + rtype + ")a", filepath, filepath.replace(".ogg", ".mp3"));
type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), name, Modifier.STATIC, Modifier.PUBLIC).initializer("new arc.audio." + rtype.substring(rtype.lastIndexOf(".") + 1) + "()").build()); loadBegin.addStatement("$T.assets.load($S, $L.class).loaded = a -> { $L = ($L)a; soundToId.put(a, $L); idToSound.put($L, a); }",
}); Core.class, filepath, rtype, name, rtype, id, id);
type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), name, Modifier.STATIC, Modifier.PUBLIC).initializer("new " + rtype + "()").build());
id ++;
}
type.addStaticBlock(staticb.build());
if(classname.equals("Sounds")){ if(classname.equals("Sounds")){
type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), "none", Modifier.STATIC, Modifier.PUBLIC).initializer("new arc.audio." + rtype.substring(rtype.lastIndexOf(".") + 1) + "()").build()); type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), "none", Modifier.STATIC, Modifier.PUBLIC).initializer("new " + rtype + "()").build());
} }
type.addMethod(loadBegin.build()); type.addMethod(loadBegin.build());

View File

@@ -7,6 +7,7 @@ import com.sun.tools.javac.code.Attribute.Enum;
import com.sun.tools.javac.code.Attribute.Error; import com.sun.tools.javac.code.Attribute.Error;
import com.sun.tools.javac.code.Attribute.Visitor; import com.sun.tools.javac.code.Attribute.Visitor;
import com.sun.tools.javac.code.Attribute.*; import com.sun.tools.javac.code.Attribute.*;
import com.sun.tools.javac.code.Scope.*;
import com.sun.tools.javac.code.Type; import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.ArrayType; import com.sun.tools.javac.code.Type.ArrayType;
@@ -64,36 +65,13 @@ public class AnnotationProxyMaker{
LinkedHashMap map = new LinkedHashMap(); LinkedHashMap map = new LinkedHashMap();
ClassSymbol cl = (ClassSymbol)this.anno.type.tsym; ClassSymbol cl = (ClassSymbol)this.anno.type.tsym;
//try to use Java 8 API for this if possible for(Symbol s : cl.members().getSymbols(LookupKind.NON_RECURSIVE)){
try{ if(s.getKind() == ElementKind.METHOD){
Class entryClass = Class.forName("com.sun.tools.javac.code.Scope$Entry"); MethodSymbol var4 = (MethodSymbol)s;
Object members = cl.members(); Attribute var5 = var4.getDefaultValue();
Field field = members.getClass().getField("elems"); if(var5 != null){
Object elems = field.get(members); map.put(var4, var5);
Field siblingField = entryClass.getField("sibling");
Field symField = entryClass.getField("sym");
for(Object currEntry = elems; currEntry != null; currEntry = siblingField.get(currEntry)){
handleSymbol((Symbol)symField.get(currEntry), map);
}
}catch(Throwable e){
//otherwise try other API
try{
Class lookupClass = Class.forName("com.sun.tools.javac.code.Scope$LookupKind");
Field nonRecField = lookupClass.getField("NON_RECURSIVE");
Object nonRec = nonRecField.get(null);
Scope scope = cl.members();
Method getSyms = scope.getClass().getMethod("getSymbols", lookupClass);
Iterable<Symbol> it = (Iterable<Symbol>)getSyms.invoke(scope, nonRec);
Iterator<Symbol> i = it.iterator();
while(i.hasNext()){
handleSymbol(i.next(), map);
} }
}catch(Throwable death){
//I tried
throw new RuntimeException(death);
} }
} }
@@ -104,17 +82,6 @@ public class AnnotationProxyMaker{
return map; return map;
} }
private void handleSymbol(Symbol sym, LinkedHashMap map){
if(sym.getKind() == ElementKind.METHOD){
MethodSymbol var4 = (MethodSymbol)sym;
Attribute var5 = var4.getDefaultValue();
if(var5 != null){
map.put(var4, var5);
}
}
}
private Object generateValue(MethodSymbol var1, Attribute var2){ private Object generateValue(MethodSymbol var1, Attribute var2){
AnnotationProxyMaker.ValueVisitor var3 = new AnnotationProxyMaker.ValueVisitor(var1); AnnotationProxyMaker.ValueVisitor var3 = new AnnotationProxyMaker.ValueVisitor(var1);
return var3.getValue(var2); return var3.getValue(var2);

View File

@@ -12,6 +12,10 @@ import java.lang.Class;
import java.lang.annotation.*; import java.lang.annotation.*;
import java.lang.reflect.*; import java.lang.reflect.*;
/**
* Wrapper over Element with added utility functions.
* I would have preferred to use extension methods for this, but Java doesn't have any.
* */
public class Selement<T extends Element>{ public class Selement<T extends Element>{
public final T e; public final T e;

View File

@@ -57,7 +57,7 @@ allprojects{
if(!project.hasProperty("versionType")) versionType = 'official' if(!project.hasProperty("versionType")) versionType = 'official'
appName = 'Mindustry' appName = 'Mindustry'
steamworksVersion = '0b86023401880bb5e586bc404bedbaae9b1f1c94' steamworksVersion = '0b86023401880bb5e586bc404bedbaae9b1f1c94'
rhinoVersion = '55bf0dac1cfa7770672fd26112512c733ca9d5dc' rhinoVersion = '9f792d202471fb3789eab7bb261fec13d67287e2'
loadVersionProps = { loadVersionProps = {
return new Properties().with{p -> p.load(file('../core/assets/version.properties').newReader()); return p } return new Properties().with{p -> p.load(file('../core/assets/version.properties').newReader()); return p }

View File

@@ -101,6 +101,7 @@ customgame = Custom Game
newgame = New Game newgame = New Game
none = <none> none = <none>
none.found = [lightgray]<none found> none.found = [lightgray]<none found>
none.inmap = [lightgray]<none in map>
minimap = Minimap minimap = Minimap
position = Position position = Position
close = Close close = Close
@@ -995,6 +996,7 @@ rules.wavetimer = Wave Timer
rules.waves = Waves rules.waves = Waves
rules.attack = Attack Mode rules.attack = Attack Mode
rules.buildai = AI Building rules.buildai = AI Building
rules.cleanupdeadteams = Clean Up Defeated Team Buildings (PvP)
rules.corecapture = Capture Core On Destruction rules.corecapture = Capture Core On Destruction
rules.polygoncoreprotection = Polygonal Core Protection rules.polygoncoreprotection = Polygonal Core Protection
rules.enemyCheat = Infinite AI (Red Team) Resources rules.enemyCheat = Infinite AI (Red Team) Resources

View File

@@ -100,7 +100,8 @@ joingame = 게임 참여
customgame = 사용자 지정 게임 customgame = 사용자 지정 게임
newgame = 새 게임 newgame = 새 게임
none = < 없음 > none = < 없음 >
none.found = [lightgray]< 없거나 찾을 수 없음 > none.found = [lightgray]< 찾을 수 없음 >
none.inmap = [lightgray]< 맵에 없음 >
minimap = 미니맵 minimap = 미니맵
position = 위치 position = 위치
close = 닫기 close = 닫기

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -55,7 +55,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
Log.info("[GL] Max texture size: @", maxTextureSize); Log.info("[GL] Max texture size: @", maxTextureSize);
Log.info("[GL] Using @ context.", gl30 != null ? "OpenGL 3" : "OpenGL 2"); Log.info("[GL] Using @ context.", gl30 != null ? "OpenGL 3" : "OpenGL 2");
if(maxTextureSize < 4096) Log.warn("[GL] Your maximum texture size is below the recommended minimum of 4096. This will cause severe performance issues."); if(maxTextureSize < 4096) Log.warn("[GL] Your maximum texture size is below the recommended minimum of 4096. This will cause severe performance issues.");
Log.info("[JAVA] Version: @", System.getProperty("java.version")); Log.info("[JAVA] Version: @", OS.javaVersion);
Time.setDeltaProvider(() -> { Time.setDeltaProvider(() -> {
float result = Core.graphics.getDeltaTime() * 60f; float result = Core.graphics.getDeltaTime() * 60f;

View File

@@ -24,10 +24,8 @@ import mindustry.logic.*;
import mindustry.maps.Map; import mindustry.maps.Map;
import mindustry.maps.*; import mindustry.maps.*;
import mindustry.mod.*; import mindustry.mod.*;
import mindustry.net.Net;
import mindustry.net.*; import mindustry.net.*;
import mindustry.service.*; import mindustry.service.*;
import mindustry.world.*;
import java.io.*; import java.io.*;
import java.nio.charset.*; import java.nio.charset.*;
@@ -113,8 +111,6 @@ public class Vars implements Loadable{
public static final float tilePayload = tilesize * tilesize; public static final float tilePayload = tilesize * tilesize;
/** icon sizes for UI */ /** icon sizes for UI */
public static final float iconXLarge = 8*6f, iconLarge = 8*5f, iconMed = 8*4f, iconSmall = 8*3f; public static final float iconXLarge = 8*6f, iconLarge = 8*5f, iconMed = 8*4f, iconSmall = 8*3f;
/** tile used in certain situations, instead of null */
public static Tile emptyTile;
/** for map generator dialog */ /** for map generator dialog */
public static boolean updateEditorOnChange = false; public static boolean updateEditorOnChange = false;
/** all choosable player colors in join/host dialog */ /** all choosable player colors in join/host dialog */
@@ -278,7 +274,6 @@ public class Vars implements Loadable{
schematicDirectory = dataDirectory.child("schematics/"); schematicDirectory = dataDirectory.child("schematics/");
bebuildDirectory = dataDirectory.child("be_builds/"); bebuildDirectory = dataDirectory.child("be_builds/");
emptyMap = new Map(new StringMap()); emptyMap = new Map(new StringMap());
emptyTile = null;
if(tree == null) tree = new FileTree(); if(tree == null) tree = new FileTree();
if(mods == null) mods = new Mods(); if(mods == null) mods = new Mods();

View File

@@ -48,6 +48,7 @@ public class BlockIndexer{
private Seq<Building> breturnArray = new Seq<>(Building.class); private Seq<Building> breturnArray = new Seq<>(Building.class);
public BlockIndexer(){ public BlockIndexer(){
clearFlags();
Events.on(TilePreChangeEvent.class, event -> { Events.on(TilePreChangeEvent.class, event -> {
removeIndex(event.tile); removeIndex(event.tile);
@@ -62,11 +63,7 @@ public class BlockIndexer{
flagMap = new TileArray[Team.all.length][BlockFlag.all.length]; flagMap = new TileArray[Team.all.length][BlockFlag.all.length];
activeTeams = new Seq<>(Team.class); activeTeams = new Seq<>(Team.class);
for(int i = 0; i < flagMap.length; i++){ clearFlags();
for(int j = 0; j < BlockFlag.all.length; j++){
flagMap[i][j] = new TileArray();
}
}
allOres.clear(); allOres.clear();
ores = new IntSeq[content.items().size][][]; ores = new IntSeq[content.items().size][][];
@@ -106,7 +103,7 @@ public class BlockIndexer{
public void removeIndex(Tile tile){ public void removeIndex(Tile tile){
var team = tile.team(); var team = tile.team();
if(team != Team.derelict && tile.isCenter()){ if(tile.build != null && tile.isCenter()){
var flags = tile.block().flags; var flags = tile.block().flags;
var data = team.data(); var data = team.data();
@@ -160,6 +157,14 @@ public class BlockIndexer{
return blocksPresent != null && blocksPresent[block.id]; return blocksPresent != null && blocksPresent[block.id];
} }
private void clearFlags(){
for(int i = 0; i < flagMap.length; i++){
for(int j = 0; j < BlockFlag.all.length; j++){
flagMap[i][j] = new TileArray();
}
}
}
private TileArray[] getFlagged(Team team){ private TileArray[] getFlagged(Team team){
return flagMap[team.id]; return flagMap[team.id];
} }

View File

@@ -19,6 +19,7 @@ public class BuilderAI extends AIController{
@Nullable Unit following; @Nullable Unit following;
@Nullable Teamc enemy; @Nullable Teamc enemy;
float retreatTimer; float retreatTimer;
@Nullable BlockPlan lastPlan;
@Override @Override
public void updateMovement(){ public void updateMovement(){
@@ -43,6 +44,7 @@ public class BuilderAI extends AIController{
//set to follower's first build plan, whatever that is //set to follower's first build plan, whatever that is
unit.plans.clear(); unit.plans.clear();
unit.plans.addFirst(following.buildPlan()); unit.plans.addFirst(following.buildPlan());
lastPlan = null;
}else if(unit.buildPlan() == null){ }else if(unit.buildPlan() == null){
//not following anyone or building //not following anyone or building
if(timer.get(timerTarget4, 40)){ if(timer.get(timerTarget4, 40)){
@@ -78,10 +80,11 @@ public class BuilderAI extends AIController{
} }
boolean valid = boolean valid =
(req.tile() != null && req.tile().build instanceof ConstructBuild cons && cons.current == req.block) || !(lastPlan != null && lastPlan.removed) &&
(req.breaking ? ((req.tile() != null && req.tile().build instanceof ConstructBuild cons && cons.current == req.block) ||
Build.validBreak(unit.team(), req.x, req.y) : (req.breaking ?
Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation)); Build.validBreak(unit.team(), req.x, req.y) :
Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation)));
if(valid){ if(valid){
//move toward the request //move toward the request
@@ -89,6 +92,7 @@ public class BuilderAI extends AIController{
}else{ }else{
//discard invalid request //discard invalid request
unit.plans.removeFirst(); unit.plans.removeFirst();
lastPlan = null;
} }
}else{ }else{
@@ -127,6 +131,7 @@ public class BuilderAI extends AIController{
if(world.tile(block.x, block.y) != null && world.tile(block.x, block.y).block().id == block.block){ if(world.tile(block.x, block.y) != null && world.tile(block.x, block.y).block().id == block.block){
blocks.removeFirst(); blocks.removeFirst();
}else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid. }else if(Build.validPlace(content.block(block.block), unit.team(), block.x, block.y, block.rotation)){ //it's valid.
lastPlan = block;
//add build request. //add build request.
unit.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config)); unit.addBuild(new BuildPlan(block.x, block.y, block.rotation, content.block(block.block), block.config));
//shift build plan to tail so next unit builds something else. //shift build plan to tail so next unit builds something else.

View File

@@ -235,7 +235,6 @@ public class Blocks implements ContentList{
magmarock = new Floor("magmarock"){{ magmarock = new Floor("magmarock"){{
attributes.set(Attribute.heat, 0.75f); attributes.set(Attribute.heat, 0.75f);
attributes.set(Attribute.water, -0.75f); attributes.set(Attribute.water, -0.75f);
updateEffect = Fx.magmasmoke;
blendGroup = basalt; blendGroup = basalt;
emitLight = true; emitLight = true;
@@ -369,6 +368,7 @@ public class Blocks implements ContentList{
sporeCluster = new Prop("spore-cluster"){{ sporeCluster = new Prop("spore-cluster"){{
variants = 3; variants = 3;
breakSound = Sounds.plantBreak;
}}; }};
boulder = new Prop("boulder"){{ boulder = new Prop("boulder"){{
@@ -426,6 +426,9 @@ public class Blocks implements ContentList{
darkMetal = new StaticWall("dark-metal"); darkMetal = new StaticWall("dark-metal");
Seq.with(metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor4, metalFloor5, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6)
.each(b -> b.asFloor().wall = darkMetal);
pebbles = new DoubleOverlayFloor("pebbles"); pebbles = new DoubleOverlayFloor("pebbles");
tendrils = new OverlayFloor("tendrils"); tendrils = new OverlayFloor("tendrils");

View File

@@ -47,7 +47,6 @@ public class StatusEffects implements ContentList{
affinity(blasted, ((unit, result, time) -> { affinity(blasted, ((unit, result, time) -> {
unit.damagePierce(transitionDamage); unit.damagePierce(transitionDamage);
result.set(freezing, time);
})); }));
}); });
}}; }};
@@ -75,7 +74,6 @@ public class StatusEffects implements ContentList{
if(unit.team == state.rules.waveTeam){ if(unit.team == state.rules.waveTeam){
Events.fire(Trigger.shock); Events.fire(Trigger.shock);
} }
result.set(wet, time);
})); }));
opposite(burning, melting); opposite(burning, melting);
}); });

View File

@@ -1780,6 +1780,7 @@ public class UnitTypes implements ContentList{
shots = 3; shots = 3;
shotDelay = 7f; shotDelay = 7f;
x = y = shootX = shootY = 0f; x = y = shootX = shootY = 0f;
shootSound = Sounds.mineDeploy;
bullet = new BasicBulletType(){{ bullet = new BasicBulletType(){{
sprite = "mine-bullet"; sprite = "mine-bullet";
@@ -2150,6 +2151,8 @@ public class UnitTypes implements ContentList{
shootY = 7f; shootY = 7f;
recoil = 4f; recoil = 4f;
cooldownTime = reload - 10f; cooldownTime = reload - 10f;
//TODO better sound
shootSound = Sounds.laser;
bullet = new EmpBulletType(){{ bullet = new EmpBulletType(){{
float rad = 100f; float rad = 100f;
@@ -2182,6 +2185,7 @@ public class UnitTypes implements ContentList{
hitShake = 4f; hitShake = 4f;
trailRotation = true; trailRotation = true;
status = StatusEffects.electrified; status = StatusEffects.electrified;
hitSound = Sounds.plasmaboom;
trailEffect = new Effect(16f, e -> { trailEffect = new Effect(16f, e -> {
color(Pal.heal); color(Pal.heal);

View File

@@ -49,6 +49,7 @@ public class Logic implements ApplicationListener{
BlockPlan b = it.next(); BlockPlan b = it.next();
Block block = content.block(b.block); Block block = content.block(b.block);
if(event.tile.block().bounds(event.tile.x, event.tile.y, Tmp.r1).overlaps(block.bounds(b.x, b.y, Tmp.r2))){ if(event.tile.block().bounds(event.tile.x, event.tile.y, Tmp.r1).overlaps(block.bounds(b.x, b.y, Tmp.r2))){
b.removed = true;
it.remove(); it.remove();
} }
} }
@@ -128,25 +129,7 @@ public class Logic implements ApplicationListener{
Events.on(SectorCaptureEvent.class, e -> { Events.on(SectorCaptureEvent.class, e -> {
if(!net.client() && e.sector == state.getSector() && e.sector.isBeingPlayed()){ if(!net.client() && e.sector == state.getSector() && e.sector.isBeingPlayed()){
for(Tile tile : world.tiles){ state.rules.waveTeam.data().destroyToDerelict();
//convert all blocks to neutral, randomly killing them
if(tile.isCenter() && tile.build != null && tile.build.team == state.rules.waveTeam){
Building b = tile.build;
Call.setTeam(b, Team.derelict);
Time.run(Mathf.random(0f, 60f * 6f), () -> {
if(Mathf.chance(0.25)){
b.kill();
}
});
}
}
//kill all units
Groups.unit.each(u -> {
if(u.team == state.rules.waveTeam){
Time.run(Mathf.random(0f, 60f * 5f), u::kill);
}
});
} }
}); });
@@ -162,6 +145,12 @@ public class Logic implements ApplicationListener{
} }
}); });
//listen to core changes; if all cores have been destroyed, set to derelict.
Events.on(CoreChangeEvent.class, e -> Core.app.post(() -> {
if(state.rules.cleanupDeadTeams && state.rules.pvp && !e.core.isAdded() && e.core.team != Team.derelict && e.core.team.cores().isEmpty()){
e.core.team.data().destroyToDerelict();
}
}));
} }
/** Adds starting items, resets wave time, and sets state to playing. */ /** Adds starting items, resets wave time, and sets state to playing. */

View File

@@ -159,6 +159,22 @@ public class NetClient implements ApplicationListener{
clientPacketReliable(type, contents); clientPacketReliable(type, contents);
} }
//TODO enable in build 129
/*
@Remote(variants = Variant.both, unreliable = true)
public static void sound(Sound sound, float volume, float pitch, float pan){
if(sound == null) return;
sound.play(volume * Core.settings.getInt("sfxvol") / 100f, pitch, pan);
}
@Remote(variants = Variant.both, unreliable = true)
public static void soundAt(Sound sound, float x, float y, float volume, float pitch){
if(sound == null) return;
sound.at(x, y, pitch, volume);
}*/
@Remote(variants = Variant.both, unreliable = true) @Remote(variants = Variant.both, unreliable = true)
public static void effect(Effect effect, float x, float y, float rotation, Color color){ public static void effect(Effect effect, float x, float y, float rotation, Color color){
if(effect == null) return; if(effect == null) return;

View File

@@ -33,7 +33,7 @@ import static arc.scene.actions.Actions.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class UI implements ApplicationListener, Loadable{ public class UI implements ApplicationListener, Loadable{
private static String billions, millions, thousands; public static String billions, millions, thousands;
public static PixmapPacker packer; public static PixmapPacker packer;

View File

@@ -525,8 +525,7 @@ public class World{
private class Context implements WorldContext{ private class Context implements WorldContext{
Context(){ Context(){}
}
@Override @Override
public Tile tile(int index){ public Tile tile(int index){
@@ -579,7 +578,7 @@ public class World{
for(GenerateFilter filter : filters){ for(GenerateFilter filter : filters){
filter.randomize(); filter.randomize();
input.begin(filter, width(), height(), (x, y) -> tiles.getn(x, y)); input.begin(width(), height(), (x, y) -> tiles.getn(x, y));
filter.apply(tiles, input); filter.apply(tiles, input);
} }
} }

View File

@@ -15,6 +15,7 @@ import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.maps.*;
import mindustry.maps.filters.*; import mindustry.maps.filters.*;
import mindustry.maps.filters.GenerateFilter.*; import mindustry.maps.filters.GenerateFilter.*;
import mindustry.ui.*; import mindustry.ui.*;
@@ -26,12 +27,6 @@ import static mindustry.Vars.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class MapGenerateDialog extends BaseDialog{ public class MapGenerateDialog extends BaseDialog{
final Prov<GenerateFilter>[] filterTypes = new Prov[]{
NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new,
RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new,
BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new,
EnemySpawnFilter::new, SpawnPathFilter::new
};
final boolean applied; final boolean applied;
Pixmap pixmap; Pixmap pixmap;
@@ -158,7 +153,7 @@ public class MapGenerateDialog extends BaseDialog{
long[] writeTiles = new long[editor.width() * editor.height()]; long[] writeTiles = new long[editor.width() * editor.height()];
for(GenerateFilter filter : filters){ for(GenerateFilter filter : filters){
input.begin(filter, editor.width(), editor.height(), editor::tile); input.begin(editor.width(), editor.height(), editor::tile);
//write to buffer //write to buffer
for(int x = 0; x < editor.width(); x++){ for(int x = 0; x < editor.width(); x++){
@@ -333,7 +328,7 @@ public class MapGenerateDialog extends BaseDialog{
p.marginRight(14); p.marginRight(14);
p.defaults().size(195f, 56f); p.defaults().size(195f, 56f);
int i = 0; int i = 0;
for(var gen : filterTypes){ for(var gen : Maps.allFilterTypes){
var filter = gen.get(); var filter = gen.get();
var icon = filter.icon(); var icon = filter.icon();
@@ -414,7 +409,7 @@ public class MapGenerateDialog extends BaseDialog{
} }
for(var filter : copy){ for(var filter : copy){
input.begin(filter, editor.width(), editor.height(), (x, y) -> unpack(buffer1[Mathf.clamp(x / scaling, 0, pixmap.width -1) + w* Mathf.clamp(y / scaling, 0, pixmap.height -1)])); input.begin(editor.width(), editor.height(), (x, y) -> unpack(buffer1[Mathf.clamp(x / scaling, 0, pixmap.width -1) + w* Mathf.clamp(y / scaling, 0, pixmap.height -1)]));
//read from buffer1 and write to buffer2 //read from buffer1 and write to buffer2
pixmap.each((px, py) -> { pixmap.each((px, py) -> {

View File

@@ -1,6 +1,7 @@
package mindustry.entities.abilities; package mindustry.entities.abilities;
import arc.*; import arc.*;
import arc.audio.*;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
@@ -19,6 +20,7 @@ public class EnergyFieldAbility extends Ability{
public float damage = 1, reload = 100, range = 60; public float damage = 1, reload = 100, range = 60;
public Effect healEffect = Fx.heal, hitEffect = Fx.hitLaserBlast, damageEffect = Fx.chainLightning; public Effect healEffect = Fx.heal, hitEffect = Fx.hitLaserBlast, damageEffect = Fx.chainLightning;
public StatusEffect status = StatusEffects.electrified; public StatusEffect status = StatusEffects.electrified;
public Sound shootSound = Sounds.spark;
public float statusDuration = 60f * 6f; public float statusDuration = 60f * 6f;
public float x, y; public float x, y;
public boolean hitBuildings = true; public boolean hitBuildings = true;
@@ -139,6 +141,10 @@ public class EnergyFieldAbility extends Ability{
} }
} }
if(anyNearby){
shootSound.at(unit);
}
timer = 0f; timer = 0f;
} }
} }

View File

@@ -232,8 +232,8 @@ public class BulletType extends Content implements Cloneable{
} }
if(entity instanceof Unit unit){ if(entity instanceof Unit unit){
Tmp.v3.set(unit).sub(b.x, b.y).nor().scl(knockback * 80f); Tmp.v3.set(unit).sub(b).nor().scl(knockback * 80f);
if(impact) Tmp.v3.setAngle(b.rotation()); if(impact) Tmp.v3.setAngle(b.rotation() + (knockback < 0 ? 180f : 0f));
unit.impulse(Tmp.v3); unit.impulse(Tmp.v3);
unit.apply(status, statusDuration); unit.apply(status, statusDuration);
} }

View File

@@ -9,7 +9,7 @@ import static mindustry.Vars.*;
@Component @Component
abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{ abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{
static final float warpDst = 40f; static final float warpDst = 30f;
@Import float x, y; @Import float x, y;

View File

@@ -106,7 +106,6 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Sets up all the necessary variables, but does not add this entity anywhere. */ /** Sets up all the necessary variables, but does not add this entity anywhere. */
public Building create(Block block, Team team){ public Building create(Block block, Team team){
this.tile = emptyTile;
this.block = block; this.block = block;
this.team = team; this.team = team;
@@ -1443,7 +1442,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
@Override @Override
public void killed(){ public void killed(){
Events.fire(new BlockDestroyEvent(tile)); Events.fire(new BlockDestroyEvent(tile));
block.breakSound.at(tile); block.destroySound.at(tile);
onDestroyed(); onDestroyed();
tile.remove(); tile.remove();
remove(); remove();

View File

@@ -2,6 +2,7 @@ package mindustry.entities.comp;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.util.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.async.PhysicsProcess.*; import mindustry.async.PhysicsProcess.*;
import mindustry.gen.*; import mindustry.gen.*;

View File

@@ -70,6 +70,8 @@ public class Rules{
public float enemyCoreBuildRadius = 400f; public float enemyCoreBuildRadius = 400f;
/** If true, no-build zones are calculated based on the closest core. */ /** If true, no-build zones are calculated based on the closest core. */
public boolean polygonCoreProtection = false; public boolean polygonCoreProtection = false;
/** If true, dead teams in PvP automatically have their blocks & units converted to derelict upon death. */
public boolean cleanupDeadTeams = true;
/** Radius around enemy wave drop zones.*/ /** Radius around enemy wave drop zones.*/
public float dropZoneRadius = 300f; public float dropZoneRadius = 300f;
/** Time between waves in ticks. */ /** Time between waves in ticks. */

View File

@@ -1,6 +1,7 @@
package mindustry.game; package mindustry.game;
import arc.func.*; import arc.func.*;
import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.Queue; import arc.struct.Queue;
import arc.struct.*; import arc.struct.*;
@@ -260,6 +261,34 @@ public class Teams{
this.ai = new BaseAI(this); this.ai = new BaseAI(this);
} }
/** Destroys this team's presence on the map, killing part of its buildings and converting everything to 'derelict'. */
public void destroyToDerelict(){
//grab all buildings from quadtree.
var builds = new Seq<Building>();
if(buildings != null){
buildings.getObjects(builds);
}
//convert all team tiles to neutral, randomly killing them
for(var b : builds){
//TODO this may cause a lot of packet spam, optimize?
Call.setTeam(b, Team.derelict);
if(Mathf.chance(0.25)){
Time.run(Mathf.random(0f, 60f * 6f), b::kill);
}
}
//kill all units randomly
units.each(u -> Time.run(Mathf.random(0f, 60f * 5f), () -> {
//ensure unit hasn't switched teams for whatever reason
if(u.team == team){
u.kill();
}
}));
}
@Nullable @Nullable
public Seq<Unit> unitCache(UnitType type){ public Seq<Unit> unitCache(UnitType type){
if(unitsByType == null || unitsByType.length <= type.id || unitsByType[type.id] == null) return null; if(unitsByType == null || unitsByType.length <= type.id || unitsByType[type.id] == null) return null;
@@ -320,6 +349,7 @@ public class Teams{
public static class BlockPlan{ public static class BlockPlan{
public final short x, y, rotation, block; public final short x, y, rotation, block;
public final Object config; public final Object config;
public boolean removed;
public BlockPlan(int x, int y, short rotation, short block, Object config){ public BlockPlan(int x, int y, short rotation, short block, Object config){
this.x = (short)x; this.x = (short)x;

View File

@@ -145,6 +145,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
for(int pos : positions){ for(int pos : positions){
if(req.x == Point2.x(pos) && req.y == Point2.y(pos)){ if(req.x == Point2.x(pos) && req.y == Point2.y(pos)){
req.removed = true;
it.remove(); it.remove();
continue outer; continue outer;
} }
@@ -893,6 +894,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Block block = content.block(req.block); Block block = content.block(req.block);
if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){
removed.add(Point2.pack(req.x, req.y)); removed.add(Point2.pack(req.x, req.y));
req.removed = true;
broken.remove(); broken.remove();
} }
} }

View File

@@ -1,11 +1,13 @@
package mindustry.io; package mindustry.io;
import arc.util.*;
import arc.util.serialization.*; import arc.util.serialization.*;
import arc.util.serialization.Json.*; import arc.util.serialization.Json.*;
import mindustry.*; import mindustry.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.maps.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
@@ -215,6 +217,12 @@ public class JsonIO{
return item != null ? item : liquid; return item != null ? item : liquid;
} }
}); });
//use short names for all filter types
for(var filter : Maps.allFilterTypes){
var i = filter.get();
json.addClassTag(Strings.camelize(i.getClass().getSimpleName().replace("Filter", "")), i.getClass());
}
} }
static class CustomJson extends Json{ static class CustomJson extends Json{

View File

@@ -1,5 +1,6 @@
package mindustry.io; package mindustry.io;
import arc.audio.*;
import arc.graphics.*; import arc.graphics.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
@@ -501,6 +502,15 @@ public class TypeIO{
return id == -1 ? null : content.item(id); return id == -1 ? null : content.item(id);
} }
//note that only the standard sound constants in Sounds are supported; modded sounds are not.
public static void writeSound(Writes write, Sound sound){
write.s(Sounds.getSoundId(sound));
}
public static Sound readSound(Reads read){
return Sounds.getSound(read.s());
}
public static void writeWeather(Writes write, Weather item){ public static void writeWeather(Writes write, Weather item){
write.s(item == null ? -1 : item.id); write.s(item == null ? -1 : item.id);
} }
@@ -633,7 +643,7 @@ public class TypeIO{
} }
} }
/** Representes a building that has not been resolved yet. */ /** Represents a building that has not been resolved yet. */
public static class BuildingBox{ public static class BuildingBox{
public int pos; public int pos;

View File

@@ -363,6 +363,9 @@ public class LExecutor{
float x1 = World.unconv(exec.numf(p1)), y1 = World.unconv(exec.numf(p2)), d1 = World.unconv(exec.numf(p3)); float x1 = World.unconv(exec.numf(p1)), y1 = World.unconv(exec.numf(p2)), d1 = World.unconv(exec.numf(p3));
switch(type){ switch(type){
case idle -> {
ai.control = type;
}
case move, stop, approach -> { case move, stop, approach -> {
ai.control = type; ai.control = type;
ai.moveX = x1; ai.moveX = x1;

View File

@@ -24,23 +24,30 @@ import mindustry.world.*;
import mindustry.world.blocks.storage.*; import mindustry.world.blocks.storage.*;
import java.io.*; import java.io.*;
import java.util.concurrent.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class Maps{ public class Maps{
/** All generation filter types. */
public static Prov<GenerateFilter>[] allFilterTypes = new Prov[]{
NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new,
RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new,
BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new,
EnemySpawnFilter::new, SpawnPathFilter::new
};
/** List of all built-in maps. Filenames only. */ /** List of all built-in maps. Filenames only. */
private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "mudFlats", "moltenLake", "archipelago", "debrisField", "veins", "glacier", "passage"}; private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "mudFlats", "moltenLake", "archipelago", "debrisField", "veins", "glacier", "passage"};
/** Maps tagged as PvP */ /** Maps tagged as PvP */
static final String[] pvpMaps = {"veins", "glacier", "passage"}; private static String[] pvpMaps = {"veins", "glacier", "passage"};
/** All maps stored in an ordered array. */ /** All maps stored in an ordered array. */
private Seq<Map> maps = new Seq<>(); private Seq<Map> maps = new Seq<>();
/** Serializer for meta. */
private Json json = new Json();
private ShuffleMode shuffleMode = ShuffleMode.all; private ShuffleMode shuffleMode = ShuffleMode.all;
private @Nullable MapProvider shuffler; private @Nullable MapProvider shuffler;
private AsyncExecutor executor = new AsyncExecutor(2); private ExecutorService executor = Threads.executor(3);
private ObjectSet<Map> previewList = new ObjectSet<>(); private ObjectSet<Map> previewList = new ObjectSet<>();
public ShuffleMode getShuffleMode(){ public ShuffleMode getShuffleMode(){
@@ -352,20 +359,20 @@ public class Maps{
if(groups == null) return "[]"; if(groups == null) return "[]";
StringWriter buffer = new StringWriter(); StringWriter buffer = new StringWriter();
json.setWriter(new JsonWriter(buffer)); JsonIO.json.setWriter(new JsonWriter(buffer));
json.writeArrayStart(); JsonIO.json.writeArrayStart();
for(int i = 0; i < groups.size; i++){ for(int i = 0; i < groups.size; i++){
json.writeObjectStart(SpawnGroup.class, SpawnGroup.class); JsonIO.json.writeObjectStart(SpawnGroup.class, SpawnGroup.class);
groups.get(i).write(json); groups.get(i).write(JsonIO.json);
json.writeObjectEnd(); JsonIO.json.writeObjectEnd();
} }
json.writeArrayEnd(); JsonIO.json.writeArrayEnd();
return buffer.toString(); return buffer.toString();
} }
public Seq<SpawnGroup> readWaves(String str){ public Seq<SpawnGroup> readWaves(String str){
return str == null ? null : str.equals("[]") ? new Seq<>() : Seq.with(json.fromJson(SpawnGroup[].class, str)); return str == null ? null : str.equals("[]") ? new Seq<>() : Seq.with(JsonIO.json.fromJson(SpawnGroup[].class, str));
} }
public void loadPreviews(){ public void loadPreviews(){

View File

@@ -75,8 +75,7 @@ public abstract class GenerateFilter{
/** localized display name */ /** localized display name */
public String name(){ public String name(){
var s = simpleName(); return Core.bundle.get("filter." + simpleName());
return Core.bundle.get("filter." + s);
} }
public char icon(){ public char icon(){
@@ -100,14 +99,12 @@ public abstract class GenerateFilter{
//utility generation functions //utility generation functions
//TODO would be nice if these functions used the seed and ditched "in" completely; simplex should be stateless
protected float noise(GenerateInput in, float scl, float mag){ protected float noise(GenerateInput in, float scl, float mag){
return (float)Simplex.noise2d(seed, 1f, 0f, 1f / scl, in.x, in.y) * mag; return Simplex.noise2d(seed, 1f, 0f, 1f / scl, in.x, in.y) * mag;
} }
protected float noise(GenerateInput in, float scl, float mag, float octaves, float persistence){ protected float noise(GenerateInput in, float scl, float mag, float octaves, float persistence){
return (float)Simplex.noise2d(seed, octaves, persistence, 1f / scl, in.x, in.y) * mag; return Simplex.noise2d(seed, octaves, persistence, 1f / scl, in.x, in.y) * mag;
} }
protected float rnoise(float x, float y, float scl, float mag){ protected float rnoise(float x, float y, float scl, float mag){
@@ -141,7 +138,7 @@ public abstract class GenerateFilter{
this.y = y; this.y = y;
} }
public void begin(GenerateFilter filter, int width, int height, TileProvider buffer){ public void begin(int width, int height, TileProvider buffer){
this.buffer = buffer; this.buffer = buffer;
this.width = width; this.width = width;
this.height = height; this.height = height;

View File

@@ -115,7 +115,7 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe
@Override @Override
protected float noise(float x, float y, double octaves, double falloff, double scl, double mag){ protected float noise(float x, float y, double octaves, double falloff, double scl, double mag){
Vec3 v = sector.rect.project(x, y); Vec3 v = sector.rect.project(x, y);
return (float)Simplex.noise3d(0, octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag; return Simplex.noise3d(0, octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag;
} }
/** @return the scaling factor for sector rects. */ /** @return the scaling factor for sector rects. */

View File

@@ -57,7 +57,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
float rawHeight(Vec3 position){ float rawHeight(Vec3 position){
position = Tmp.v33.set(position).scl(scl); position = Tmp.v33.set(position).scl(scl);
return (Mathf.pow((float)Simplex.noise3d(seed, 7, 0.5f, 1f/3f, position.x, position.y, position.z), 2.3f) + waterOffset) / (1f + waterOffset); return (Mathf.pow(Simplex.noise3d(seed, 7, 0.5f, 1f/3f, position.x, position.y, position.z), 2.3f) + waterOffset) / (1f + waterOffset);
} }
@Override @Override
@@ -127,12 +127,12 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
position = Tmp.v33.set(position).scl(scl); position = Tmp.v33.set(position).scl(scl);
float rad = scl; float rad = scl;
float temp = Mathf.clamp(Math.abs(position.y * 2f) / (rad)); float temp = Mathf.clamp(Math.abs(position.y * 2f) / (rad));
float tnoise = (float)Simplex.noise3d(seed, 7, 0.56, 1f/3f, position.x, position.y + 999f, position.z); float tnoise = Simplex.noise3d(seed, 7, 0.56, 1f/3f, position.x, position.y + 999f, position.z);
temp = Mathf.lerp(temp, tnoise, 0.5f); temp = Mathf.lerp(temp, tnoise, 0.5f);
height *= 1.2f; height *= 1.2f;
height = Mathf.clamp(height); height = Mathf.clamp(height);
float tar = (float)Simplex.noise3d(seed, 4, 0.55f, 1f/2f, position.x, position.y + 999f, position.z) * 0.3f + Tmp.v31.dst(0, 0, 1f) * 0.2f; float tar = Simplex.noise3d(seed, 4, 0.55f, 1f/2f, position.x, position.y + 999f, position.z) * 0.3f + Tmp.v31.dst(0, 0, 1f) * 0.2f;
Block res = arr[Mathf.clamp((int)(temp * arr.length), 0, arr[0].length - 1)][Mathf.clamp((int)(height * arr[0].length), 0, arr[0].length - 1)]; Block res = arr[Mathf.clamp((int)(temp * arr.length), 0, arr[0].length - 1)][Mathf.clamp((int)(height * arr[0].length), 0, arr[0].length - 1)];
if(tar > 0.5f){ if(tar > 0.5f){
@@ -145,7 +145,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
@Override @Override
protected float noise(float x, float y, double octaves, double falloff, double scl, double mag){ protected float noise(float x, float y, double octaves, double falloff, double scl, double mag){
Vec3 v = sector.rect.project(x, y).scl(5f); Vec3 v = sector.rect.project(x, y).scl(5f);
return (float)Simplex.noise3d(seed, octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag; return Simplex.noise3d(seed, octaves, falloff, 1f / scl, v.x, v.y, v.z) * (float)mag;
} }
@Override @Override
@@ -162,12 +162,27 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
connected.add(this); connected.add(this);
} }
void con(int x1, int y1, int x2, int y2){
float nscl = rand.random(100f, 140f) * 6f;
int stroke = rand.random(3, 9);
brush(pathfind(x1, y1, x2, y2, tile -> (tile.solid() ? 50f : 0f) + noise(tile.x, tile.y, 2, 0.4f, 1f / nscl) * 500, Astar.manhattan), stroke);
}
void connect(Room to){ void connect(Room to){
if(!connected.add(to)) return; if(!connected.add(to)) return;
float nscl = rand.random(100f, 140f); Vec2 midpoint = Tmp.v1.set(to.x, to.y).add(x, y).scl(0.5f);
int stroke = rand.random(3, 9); rand.nextFloat();
brush(pathfind(x, y, to.x, to.y, tile -> (tile.solid() ? 5f : 0f) + noise(tile.x, tile.y, 2, 0.4, 1f / nscl) * 500, Astar.manhattan), stroke);
//add randomized offset to avoid straight lines
midpoint.add(Tmp.v2.setToRandomDirection(rand).scl(Tmp.v1.dst(x, y)));
midpoint.sub(width/2f, height/2f).limit(width / 2f / Mathf.sqrt3).add(width/2f, height/2f);
int mx = (int)midpoint.x, my = (int)midpoint.y;
con(x, y, mx, my);
con(mx, my, to.x, to.y);
} }
} }
@@ -244,8 +259,6 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
cells(1); cells(1);
distort(10f, 6f); distort(10f, 6f);
inverseFloodFill(tiles.getn(spawn.x, spawn.y));
Seq<Block> ores = Seq.with(Blocks.oreCopper, Blocks.oreLead); Seq<Block> ores = Seq.with(Blocks.oreCopper, Blocks.oreLead);
float poles = Math.abs(sector.tile.v.y); float poles = Math.abs(sector.tile.v.y);
float nmag = 0.5f; float nmag = 0.5f;
@@ -296,6 +309,8 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
median(2); median(2);
inverseFloodFill(tiles.getn(spawn.x, spawn.y));
tech(); tech();
pass((x, y) -> { pass((x, y) -> {

View File

@@ -29,18 +29,17 @@ public class CrashSender{
report += "Report this at " + Vars.reportIssueURL + "\n\n"; report += "Report this at " + Vars.reportIssueURL + "\n\n";
} }
return report return report
+ "Version: " + Version.combined() + (Vars.headless ? " (Server)" : "") + "\n" + "Version: " + Version.combined() + (Vars.headless ? " (Server)" : "") + "\n"
+ "OS: " + System.getProperty("os.name") + " x" + (OS.is64Bit ? "64" : "32") + "\n" + "OS: " + OS.osName + " x" + (OS.osArchBits) + " (" + OS.osArch + ")\n"
+ "Java Version: " + System.getProperty("java.version") + "\n" + "Java Version: " + OS.javaVersion + "\n"
+ "Java Architecture: " + System.getProperty("sun.arch.data.model") + "\n" + (mods == null ? "<no mod init>" : mods.list().size + " Mods" + (mods.list().isEmpty() ? "" : ": " + mods.list().toString(", ", mod -> mod.name + ":" + mod.meta.version)))
+ (mods == null ? "<no mod init>" : mods.list().size + " Mods" + (mods.list().isEmpty() ? "" : ": " + mods.list().toString(", ", mod -> mod.name + ":" + mod.meta.version))) + "\n\n" + error;
+ "\n\n" + error;
} }
public static void log(Throwable exception){ public static void log(Throwable exception){
try{ try{
Core.settings.getDataDirectory().child("crashes").child("crash_" + System.currentTimeMillis() + ".txt") Core.settings.getDataDirectory().child("crashes").child("crash_" + System.currentTimeMillis() + ".txt")
.writeString(createReport(Strings.neatError(exception))); .writeString(createReport(Strings.neatError(exception)));
}catch(Throwable ignored){ }catch(Throwable ignored){
} }
} }
@@ -60,7 +59,7 @@ public class CrashSender{
}catch(Throwable ignored){} }catch(Throwable ignored){}
//don't create crash logs for custom builds, as it's expected //don't create crash logs for custom builds, as it's expected
if(Version.build == -1 || (System.getProperty("user.name").equals("anuke") && "release".equals(Version.modifier))){ if(Version.build == -1 || (OS.username.equals("anuke") && !"steam".equals(Version.modifier))){
ret(); ret();
} }
@@ -141,10 +140,10 @@ public class CrashSender{
ex(() -> value.addChild("server", new JsonValue(fs))); ex(() -> value.addChild("server", new JsonValue(fs)));
ex(() -> value.addChild("players", new JsonValue(Groups.player.size()))); ex(() -> value.addChild("players", new JsonValue(Groups.player.size())));
ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name()))); ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name())));
ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name") + "x" + (OS.is64Bit ? "64" : "32")))); ex(() -> value.addChild("os", new JsonValue(OS.osName + " x" + OS.osArchBits + " " + OS.osVersion)));
ex(() -> value.addChild("trace", new JsonValue(parseException(exception)))); ex(() -> value.addChild("trace", new JsonValue(parseException(exception))));
ex(() -> value.addChild("javaVersion", new JsonValue(System.getProperty("java.version")))); ex(() -> value.addChild("javaVersion", new JsonValue(OS.javaVersion)));
ex(() -> value.addChild("javaArch", new JsonValue(System.getProperty("sun.arch.data.model")))); ex(() -> value.addChild("javaArch", new JsonValue(OS.osArchBits)));
Log.info("Sending crash report."); Log.info("Sending crash report.");

View File

@@ -76,7 +76,7 @@ public class StatusEffect extends UnlockableContent{
if(reloadMultiplier != 1) stats.addPercent(Stat.reloadMultiplier, reloadMultiplier); if(reloadMultiplier != 1) stats.addPercent(Stat.reloadMultiplier, reloadMultiplier);
if(buildSpeedMultiplier != 1) stats.addPercent(Stat.buildSpeedMultiplier, buildSpeedMultiplier); if(buildSpeedMultiplier != 1) stats.addPercent(Stat.buildSpeedMultiplier, buildSpeedMultiplier);
if(damage > 0) stats.add(Stat.damage, damage * 60f, StatUnit.perSecond); if(damage > 0) stats.add(Stat.damage, damage * 60f, StatUnit.perSecond);
if(damage < 0) stats.add(Stat.healing, -(damage * 60f), StatUnit.perSecond); if(damage < 0) stats.add(Stat.healing, -damage * 60f, StatUnit.perSecond);
boolean reacts = false; boolean reacts = false;

View File

@@ -249,7 +249,7 @@ public class Weapon implements Cloneable{
unit.vel.add(Tmp.v1.trns(unit.rotation + 180f, mount.bullet.type.recoil)); unit.vel.add(Tmp.v1.trns(unit.rotation + 180f, mount.bullet.type.recoil));
if(shootSound != Sounds.none && !headless){ if(shootSound != Sounds.none && !headless){
if(mount.sound == null) mount.sound = new SoundLoop(shootSound, 1f); if(mount.sound == null) mount.sound = new SoundLoop(shootSound, 1f);
mount.sound.update(x, y, true); mount.sound.update(bulletX, bulletY, true);
} }
} }
}else{ }else{
@@ -285,8 +285,7 @@ public class Weapon implements Cloneable{
can && //must be able to shoot can && //must be able to shoot
(!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo || unit.team.rules().infiniteAmmo) && //check ammo (!useAmmo || unit.ammo > 0 || !state.rules.unitAmmo || unit.team.rules().infiniteAmmo) && //check ammo
(!alternate || mount.side == flipSprite) && (!alternate || mount.side == flipSprite) &&
//TODO checking for velocity this way isn't entirely correct unit.vel.len() >= mount.weapon.minShootVelocity && //check velocity requirements
(unit.vel.len() >= mount.weapon.minShootVelocity || (net.active() && !unit.isLocal())) && //check velocity requirements
mount.reload <= 0.0001f && //reload has to be 0 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, mount.weapon.shootCone) //has to be within the cone
){ ){
@@ -324,6 +323,9 @@ public class Weapon implements Cloneable{
Time.run(sequenceNum * shotDelay + firstShotDelay, () -> { Time.run(sequenceNum * shotDelay + firstShotDelay, () -> {
if(!unit.isAdded()) return; if(!unit.isAdded()) return;
mount.bullet = bullet(unit, shootX + unit.x - baseX, shootY + unit.y - baseY, f + Mathf.range(inaccuracy), lifeScl); mount.bullet = bullet(unit, shootX + unit.x - baseX, shootY + unit.y - baseY, f + Mathf.range(inaccuracy), lifeScl);
if(!continuous){
shootSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax));
}
}); });
sequenceNum++; sequenceNum++;
}); });

View File

@@ -236,8 +236,12 @@ public class Fonts{
} }
public static TextureRegionDrawable getGlyph(Font font, char glyph){ public static TextureRegionDrawable getGlyph(Font font, char glyph){
Glyph g = font.getData().getGlyph(glyph); Glyph found = font.getData().getGlyph(glyph);
if(g == null) throw new IllegalArgumentException("No glyph: " + glyph + " (" + (int)glyph + ")"); if(found == null){
Log.warn("No icon found for glyph: @ (@)", glyph, (int)glyph);
found = font.getData().getGlyph('F');
}
Glyph g = found;
float size = Math.max(g.width, g.height); float size = Math.max(g.width, g.height);
TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(font.getRegion().texture, g.u, g.v2, g.u2, g.v)){ TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(font.getRegion().texture, g.u, g.v2, g.u2, g.v)){

View File

@@ -55,20 +55,30 @@ public class Links{
private static String report(){ private static String report(){
return "https://github.com/Anuken/Mindustry/issues/new?assignees=&labels=bug&body=" + return "https://github.com/Anuken/Mindustry/issues/new?assignees=&labels=bug&body=" +
Strings.encode(Strings.format( Strings.encode(Strings.format(
"**Platform**: `@`\n" + """
"\n**Build**: `@`\n" + **Platform**: `@`
"\n**Issue**: *Explain your issue in detail.*\n" +
"\n**Steps to reproduce**: *How you happened across the issue, and what exactly you did to make the bug happen.*\n" + **Build**: `@`
"\n**Link(s) to mod(s) used**: `@`\n" +
"\n**Save file**: *The (zipped) save file you were playing on when the bug happened. THIS IS REQUIRED FOR ANY ISSUE HAPPENING IN-GAME, REGARDLESS OF WHETHER YOU THINK IT HAPPENS EVERYWHERE. DO NOT DELETE OR OMIT THIS LINE UNLESS YOU ARE SURE THAT THE ISSUE DOES NOT HAPPEN IN-GAME.*\n" + **Issue**: *Explain your issue in detail.*
"\n**Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.*\n" +
"\n---\n" + **Steps to reproduce**: *How you happened across the issue, and what exactly you did to make the bug happen.*
"\n*Place an X (no spaces) between the brackets to confirm that you have read the line below.*" +
"\n- [ ] **I have updated to the latest release (https://github.com/Anuken/Mindustry/releases) to make sure my issue has not been fixed.**" + **Link(s) to mod(s) used**: `@`
"\n- [ ] **I have searched the closed and open issues to make sure that this problem has not already been reported.**",
OS.isAndroid ? "Android " + Core.app.getVersion() : (System.getProperty("os.name") + (OS.is64Bit ? " x64" : " x32")), **Save file**: *The (zipped) save file you were playing on when the bug happened. THIS IS REQUIRED FOR ANY ISSUE HAPPENING IN-GAME, REGARDLESS OF WHETHER YOU THINK IT HAPPENS EVERYWHERE. DO NOT DELETE OR OMIT THIS LINE UNLESS YOU ARE SURE THAT THE ISSUE DOES NOT HAPPEN IN-GAME.*
Version.combined(),
Vars.mods.list().any() ? Vars.mods.list().select(LoadedMod::enabled).map(l -> l.meta.author + "/" + l.name + ":" + l.meta.version) : "none")); **Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.*
---
*Place an X (no spaces) between the brackets to confirm that you have read the line below.*
- [ ] **I have updated to the latest release (https://github.com/Anuken/Mindustry/releases) to make sure my issue has not been fixed.**
- [ ] **I have searched the closed and open issues to make sure that this problem has not already been reported.**
""",
OS.isAndroid ? "Android " + Core.app.getVersion() : (OS.osName + " x" + OS.osArchBits),
Version.combined(),
Vars.mods.list().any() ? Vars.mods.list().select(LoadedMod::enabled).map(l -> l.meta.author + "/" + l.name + ":" + l.meta.version) : "none"));
} }
} }

View File

@@ -142,6 +142,7 @@ public class CustomRulesDialog extends BaseDialog{
check("@rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions); check("@rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions);
check("@rules.schematic", b -> rules.schematicsAllowed = b, () -> rules.schematicsAllowed); check("@rules.schematic", b -> rules.schematicsAllowed = b, () -> rules.schematicsAllowed);
check("@rules.coreincinerates", b -> rules.coreIncinerates = b, () -> rules.coreIncinerates); check("@rules.coreincinerates", b -> rules.coreIncinerates = b, () -> rules.coreIncinerates);
check("@rules.cleanupdeadteams", b -> rules.cleanupDeadTeams = b, () -> rules.cleanupDeadTeams, () -> rules.pvp);
number("@rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources); number("@rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier, 0.001f, 50f); number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier, 0.001f, 50f);
number("@rules.deconstructrefundmultiplier", false, f -> rules.deconstructRefundMultiplier = f, () -> rules.deconstructRefundMultiplier, () -> !rules.infiniteResources); number("@rules.deconstructrefundmultiplier", false, f -> rules.deconstructRefundMultiplier = f, () -> rules.deconstructRefundMultiplier, () -> !rules.infiniteResources);

View File

@@ -80,9 +80,7 @@ public class ModsDialog extends BaseDialog{
} }
shown(this::setup); shown(this::setup);
if(mobile){ onResize(this::setup);
onResize(this::setup);
}
Events.on(ResizeEvent.class, event -> { Events.on(ResizeEvent.class, event -> {
if(currentContent != null){ if(currentContent != null){
@@ -144,10 +142,10 @@ public class ModsDialog extends BaseDialog{
void setup(){ void setup(){
float h = 110f; float h = 110f;
float w = Math.min(Core.graphics.getWidth() / 1.1f, 520f); float w = Math.min(Core.graphics.getWidth() / Scl.scl(1.05f), 520f);
cont.clear(); cont.clear();
cont.defaults().width(Math.min(Core.graphics.getWidth() / 1.2f, 556f)).pad(4); cont.defaults().width(Math.min(Core.graphics.getWidth() / Scl.scl(1.05f), 556f)).pad(4);
cont.add("@mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center); cont.add("@mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center);
cont.row(); cont.row();

View File

@@ -14,6 +14,7 @@ import arc.scene.ui.layout.Stack;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.core.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
@@ -200,9 +201,9 @@ public class BlockInventoryFragment extends Fragment{
private String round(float f){ private String round(float f){
f = (int)f; f = (int)f;
if(f >= 1000000){ if(f >= 1000000){
return (int)(f / 1000000f) + "[gray]" + Core.bundle.getOrNull("unit.millions") + "[]"; return (int)(f / 1000000f) + "[gray]" + UI.millions;
}else if(f >= 1000){ }else if(f >= 1000){
return (int)(f / 1000) + Core.bundle.getOrNull("unit.thousands"); return (int)(f / 1000) + UI.thousands;
}else{ }else{
return (int)f + ""; return (int)f + "";
} }

View File

@@ -190,8 +190,10 @@ public class Block extends UnlockableContent{
public int outlinedIcon = -1; public int outlinedIcon = -1;
/** Whether this block has a shadow under it. */ /** Whether this block has a shadow under it. */
public boolean hasShadow = true; public boolean hasShadow = true;
/** Sounds made when this block breaks.*/ /** Sounds made when this block is destroyed.*/
public Sound breakSound = Sounds.boom; public Sound destroySound = Sounds.boom;
/** Sound made when this block is deconstructed. */
public Sound breakSound = Sounds.breaks;
/** How reflective this block is. */ /** How reflective this block is. */
public float albedo = 0f; public float albedo = 0f;
/** Environmental passive light color. */ /** Environmental passive light color. */

View File

@@ -1,4 +0,0 @@
package mindustry.world;
public class TileData{
}

View File

@@ -4,7 +4,7 @@ import mindustry.content.*;
public class TileGen{ public class TileGen{
public Block floor; public Block floor;
public Block block ; public Block block;
public Block overlay; public Block overlay;
{ {

View File

@@ -41,13 +41,14 @@ public class ConstructBlock extends Block{
health = 20; health = 20;
consumesTap = true; consumesTap = true;
solidifes = true; solidifes = true;
inEditor = false;
consBlocks[size - 1] = this; consBlocks[size - 1] = this;
sync = true; sync = true;
} }
/** Returns a ConstructBlock by size. */ /** Returns a ConstructBlock by size. */
public static ConstructBlock get(int size){ public static ConstructBlock get(int size){
if(size > maxBlockSize) throw new IllegalArgumentException("No. Don't place ConstructBlock of size greater than " + maxBlockSize); if(size > maxBlockSize) throw new IllegalArgumentException("No. Don't place ConstructBlocks of size greater than " + maxBlockSize);
return consBlocks[size - 1]; return consBlocks[size - 1];
} }
@@ -57,7 +58,7 @@ public class ConstructBlock extends Block{
block.breakEffect.at(tile.drawx(), tile.drawy(), block.size, block.mapColor); block.breakEffect.at(tile.drawx(), tile.drawy(), block.size, block.mapColor);
Events.fire(new BlockBuildEndEvent(tile, builder, team, true, null)); Events.fire(new BlockBuildEndEvent(tile, builder, team, true, null));
tile.remove(); tile.remove();
if(shouldPlay()) Sounds.breaks.at(tile, calcPitch(false)); if(shouldPlay()) block.breakSound.at(tile, calcPitch(false));
} }
@Remote(called = Loc.server) @Remote(called = Loc.server)

View File

@@ -14,7 +14,6 @@ import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
@@ -247,7 +246,7 @@ public class Conveyor extends Block implements Autotiler{
if(ys[i] > nextMax) ys[i] = nextMax; if(ys[i] > nextMax) ys[i] = nextMax;
if(ys[i] > 0.5 && i > 0) mid = i - 1; if(ys[i] > 0.5 && i > 0) mid = i - 1;
xs[i] = Mathf.approachDelta(xs[i], 0, speed*2); xs[i] = Mathf.approach(xs[i], 0, moved*2);
if(ys[i] >= 1f && pass(ids[i])){ if(ys[i] >= 1f && pass(ids[i])){
//align X position if passing forwards //align X position if passing forwards
@@ -263,7 +262,7 @@ public class Conveyor extends Block implements Autotiler{
} }
if(minitem < itemSpace + (blendbits == 1 ? 0.3f : 0f)){ if(minitem < itemSpace + (blendbits == 1 ? 0.3f : 0f)){
clogHeat = Mathf.lerpDelta(clogHeat, 1f, 0.02f); clogHeat = Mathf.approachDelta(clogHeat, 1f, 1f / 60f);
}else{ }else{
clogHeat = 0f; clogHeat = 0f;
} }

View File

@@ -52,8 +52,6 @@ public class Floor extends Block{
public boolean playerUnmineable = false; public boolean playerUnmineable = false;
/** Group of blocks that this block does not draw edges on. */ /** Group of blocks that this block does not draw edges on. */
public Block blendGroup = this; public Block blendGroup = this;
/** Effect displayed when randomly updated. */
public Effect updateEffect = Fx.none;
/** Array of affinities to certain things. */ /** Array of affinities to certain things. */
public Attributes attributes = new Attributes(); public Attributes attributes = new Attributes();
/** Whether this ore generates in maps by default. */ /** Whether this ore generates in maps by default. */

View File

@@ -30,6 +30,7 @@ public class OreBlock extends OverlayFloor{
/** For mod use only!*/ /** For mod use only!*/
public OreBlock(String name){ public OreBlock(String name){
super(name); super(name);
this.useColor = true;
variants = 3; variants = 3;
} }

View File

@@ -4,15 +4,18 @@ import arc.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.gen.*;
import mindustry.world.*; import mindustry.world.*;
public class Prop extends Block{ public class Prop extends Block{
public Prop(String name){ public Prop(String name){
super(name); super(name);
breakable = true; breakable = true;
alwaysReplace = true; alwaysReplace = true;
instantDeconstruct = true; instantDeconstruct = true;
breakEffect = Fx.breakProp; breakEffect = Fx.breakProp;
breakSound = Sounds.rockBreak;
} }
@Override @Override

View File

@@ -7,6 +7,7 @@ public class LegacyBlock extends Block{
public LegacyBlock(String name){ public LegacyBlock(String name){
super(name); super(name);
inEditor = false;
} }
/** Removes this block from the world, or replaces it with something else. */ /** Removes this block from the world, or replaces it with something else. */

View File

@@ -249,18 +249,6 @@ public class LogicBlock extends Block{
} }
} }
@Override
public void onProximityAdded(){
super.onProximityAdded();
//unbox buildings after reading
for(var v : executor.vars){
if(v.objval instanceof BuildingBox b){
v.objval = world.build(b.pos);
}
}
}
public String findLinkName(Block block){ public String findLinkName(Block block){
String bname = getLinkName(block); String bname = getLinkName(block);
Bits taken = new Bits(links.size); Bits taken = new Bits(links.size);
@@ -595,7 +583,7 @@ public class LogicBlock extends Block{
for(int i = 0; i < varcount; i++){ for(int i = 0; i < varcount; i++){
BVar dest = asm.getVar(names[i]); BVar dest = asm.getVar(names[i]);
if(dest != null && !dest.constant){ if(dest != null && !dest.constant){
dest.value = values[i]; dest.value = values[i] instanceof BuildingBox box ? world.build(box.pos) : values[i];
} }
} }
}); });

View File

@@ -6,6 +6,7 @@ import arc.util.*;
import arc.util.io.*; import arc.util.io.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -47,6 +48,12 @@ public interface Payload extends Position{
/** @return icon describing the contents. */ /** @return icon describing the contents. */
TextureRegion icon(); TextureRegion icon();
/** @deprecated use icon() instead. */
@Deprecated
default TextureRegion icon(Cicon icon){
return icon();
}
@Override @Override
default float getX(){ default float getX(){
return x(); return x();

View File

@@ -15,7 +15,10 @@ import mindustry.world.draw.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
public class GenericCrafter extends Block{ public class GenericCrafter extends Block{
/** Written to outputItems as a single-element array if outputItems is null. */
public @Nullable ItemStack outputItem; public @Nullable ItemStack outputItem;
/** Overwrites outputItem if not null. */
public @Nullable ItemStack[] outputItems;
public @Nullable LiquidStack outputLiquid; public @Nullable LiquidStack outputLiquid;
public float craftTime = 80; public float craftTime = 80;
@@ -45,8 +48,8 @@ public class GenericCrafter extends Block{
super.setStats(); super.setStats();
stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds); stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds);
if(outputItem != null){ if(outputItems != null){
stats.add(Stat.output, StatValues.items(craftTime, outputItem)); stats.add(Stat.output, StatValues.items(craftTime, outputItems));
} }
if(outputLiquid != null){ if(outputLiquid != null){
@@ -64,6 +67,9 @@ public class GenericCrafter extends Block{
@Override @Override
public void init(){ public void init(){
outputsLiquid = outputLiquid != null; outputsLiquid = outputLiquid != null;
if(outputItems == null && outputItem != null){
outputItems = new ItemStack[]{outputItem};
}
super.init(); super.init();
} }
@@ -74,7 +80,7 @@ public class GenericCrafter extends Block{
@Override @Override
public boolean outputsItems(){ public boolean outputsItems(){
return outputItem != null; return outputItems != null;
} }
public class GenericCrafterBuild extends Building{ public class GenericCrafterBuild extends Building{
@@ -95,8 +101,12 @@ public class GenericCrafter extends Block{
@Override @Override
public boolean shouldConsume(){ public boolean shouldConsume(){
if(outputItem != null && items.get(outputItem.item) + outputItem.amount > itemCapacity){ if(outputItems != null){
return false; for(ItemStack output : outputItems){
if(items.get(output.item) + output.amount > itemCapacity){
return false;
}
}
} }
return (outputLiquid == null || !(liquids.get(outputLiquid.liquid) >= liquidCapacity - 0.001f)) && enabled; return (outputLiquid == null || !(liquids.get(outputLiquid.liquid) >= liquidCapacity - 0.001f)) && enabled;
} }
@@ -119,9 +129,11 @@ public class GenericCrafter extends Block{
if(progress >= 1f){ if(progress >= 1f){
consume(); consume();
if(outputItem != null){ if(outputItems != null){
for(int i = 0; i < outputItem.amount; i++){ for(ItemStack output : outputItems){
offload(outputItem.item); for(int i = 0; i < output.amount; i++){
offload(output.item);
}
} }
} }
@@ -133,8 +145,10 @@ public class GenericCrafter extends Block{
progress %= 1f; progress %= 1f;
} }
if(outputItem != null && timer(timerDump, dumpTime / timeScale)){ if(outputItems != null && timer(timerDump, dumpTime / timeScale)){
dump(outputItem.item); for(ItemStack output : outputItems){
dump(output.item);
}
} }
if(outputLiquid != null){ if(outputLiquid != null){

View File

@@ -281,7 +281,7 @@ public class CoreBlock extends StorageBlock{
@Override @Override
public void afterDestroyed(){ public void afterDestroyed(){
if(state.rules.coreCapture){ if(state.rules.coreCapture){
tile.setBlock(block, lastDamage); tile.setNet(block, lastDamage, 0);
//core is invincible for several seconds to prevent recapture //core is invincible for several seconds to prevent recapture
((CoreBuild)tile.build).iframes = captureInvicibility; ((CoreBuild)tile.build).iframes = captureInvicibility;
} }

View File

@@ -64,6 +64,7 @@ public class Reconstructor extends UnitBlock{
@Override @Override
public void setStats(){ public void setStats(){
stats.timePeriod = constructTime;
super.setStats(); super.setStats();
stats.add(Stat.productionTime, constructTime / 60f, StatUnit.seconds); stats.add(Stat.productionTime, constructTime / 60f, StatUnit.seconds);

View File

@@ -143,7 +143,7 @@ public class StatValues{
} }
} }
}else{ }else{
c.add("@none.found"); c.add("@none.inmap");
} }
}else{ }else{
c.add("@stat.showinmap"); c.add("@stat.showinmap");

View File

@@ -10,4 +10,4 @@ kapt.include.compile.classpath=false
kotlin.stdlib.default.dependency=false kotlin.stdlib.default.dependency=false
#needed for android compilation #needed for android compilation
android.useAndroidX=true android.useAndroidX=true
archash=b8db131172548e1f10ba86392e09819c34296711 archash=626d16628b5c1f69a4a8cbd720eb99bb278e8a1f

View File

@@ -278,7 +278,7 @@ public class ServerControl implements ApplicationListener{
handler.register("version", "Displays server version info.", arg -> { handler.register("version", "Displays server version info.", arg -> {
info("Version: Mindustry @-@ @ / build @", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision)); info("Version: Mindustry @-@ @ / build @", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision));
info("Java Version: @", System.getProperty("java.version")); info("Java Version: @", OS.javaVersion);
}); });
handler.register("exit", "Exit the server application.", arg -> { handler.register("exit", "Exit the server application.", arg -> {

View File

@@ -45,7 +45,7 @@
}, },
{ {
"name": "ALEX", "name": "ALEX",
"address": ["alexmindustryhub.ddns.net:6568", "alexmindustry.ddns.net:6568", "alexmindustry.ddns.net:6569", "alexmindustryattac.ddns.net:25800","alexmindustryturbo.ddns.net:25854","alexmindustryhex.ddns.net:25587"] "address": ["alexmindustryhub.ddns.net:6568", "alexmindustry.ddns.net:25586", "alexmindustry.ddns.net:25587", "alexmindustryattac.ddns.net:25800","alexmindustryturbo.ddns.net:25581","alexmindustryhex.ddns.net:25583"]
}, },
{ {
"name": "Minty [subzero]", "name": "Minty [subzero]",
@@ -57,7 +57,7 @@
}, },
{ {
"name": "Omega", "name": "Omega",
"address": ["178.170.47.34:20204", "157.90.213.2:30308", "157.90.180.53:25738"] "address": ["178.170.47.34:20204", "157.90.213.2:30308", "157.90.180.53:25738", "185.86.230.61:25578"]
}, },
{ {
"name": "md.obvilionnetwork.ru", "name": "md.obvilionnetwork.ru",

View File

@@ -20,7 +20,7 @@
}, },
{ {
"name": "Omega", "name": "Omega",
"address": ["157.90.180.53:25777", "redstonneur1256.ml"] "address": ["185.86.230.61:25571", "185.86.230.61:25570", "185.86.230.62:25572"]
}, },
{ {
"name": "MeowLand", "name": "MeowLand",

View File

@@ -13,7 +13,7 @@ public class GenericModTest{
static void grabMod(String url){ static void grabMod(String url){
//clear older mods //clear older mods
ApplicationTests.testDataFolder.deleteDirectory(); ApplicationTests.testDataFolder.deleteDirectory();
Http.get(url).error(Assertions::fail).block(httpResponse -> { Http.get(url).error(Assertions::fail).timeout(20000).block(httpResponse -> {
try{ try{
ApplicationTests.testDataFolder.child("mods").child("test_mod." + (url.endsWith("jar") ? "jar" : "zip")).writeBytes(Streams.copyBytes(httpResponse.getResultAsStream())); ApplicationTests.testDataFolder.child("mods").child("test_mod." + (url.endsWith("jar") ? "jar" : "zip")).writeBytes(Streams.copyBytes(httpResponse.getResultAsStream()));
}catch(IOException e){ }catch(IOException e){

View File

@@ -598,7 +598,7 @@ public class Generators{
}); });
} }
/** Generates a scorch pixmap based on parameters. Thread safe, unless multiple scorch generators are running in parallel. */ /** Generates a scorch pixmap based on parameters. Thread safe. */
public static class ScorchGenerator{ public static class ScorchGenerator{
public int size = 80, seed = 0, color = Color.whiteRgba; public int size = 80, seed = 0, color = Color.whiteRgba;
public double scale = 18, pow = 2, octaves = 4, pers = 0.4, add = 2, nscl = 4.5f; public double scale = 18, pow = 2, octaves = 4, pers = 0.4, add = 2, nscl = 4.5f;