Merge branch 'master' of https://github.com/Anuken/Mindustry into v106-alpha
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -7,6 +7,8 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Note**: Do not report any new bugs directly relating to the v6 campaign. They will not be fixed or considered at this time.
|
||||
|
||||
**Platform**: *Android/iOS/Mac/Windows/Linux*
|
||||
|
||||
**Build**: *The build number under the title in the main menu. Required.*
|
||||
|
||||
10
README.md
@@ -22,9 +22,9 @@ First, make sure you have [JDK 14](https://adoptopenjdk.net/) installed. Open a
|
||||
|
||||
#### Windows
|
||||
|
||||
_Running:_ `gradlew.bat desktop:run`
|
||||
_Building:_ `gradlew.bat desktop:dist`
|
||||
_Sprite Packing:_ `gradlew.bat tools:pack`
|
||||
_Running:_ `gradlew desktop:run`
|
||||
_Building:_ `gradlew desktop:dist`
|
||||
_Sprite Packing:_ `gradlew tools:pack`
|
||||
|
||||
#### Linux/Mac OS
|
||||
|
||||
@@ -70,3 +70,7 @@ Post feature requests and feedback [here](https://github.com/Anuken/Mindustry-Su
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png"
|
||||
alt="Get it on F-Droid"
|
||||
height="80">](https://f-droid.org/packages/io.anuke.mindustry/)
|
||||
|
||||
[<img src="https://flathub.org/assets/badges/flathub-badge-en.svg"
|
||||
alt="Download On Flathub"
|
||||
height="60">](https://flathub.org/apps/details/com.github.Anuken.Mindustry)
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.content.pm.*;
|
||||
import android.net.*;
|
||||
import android.os.Build.*;
|
||||
import android.os.*;
|
||||
import android.provider.Settings.*;
|
||||
import android.telephony.*;
|
||||
import arc.*;
|
||||
import arc.backend.android.*;
|
||||
@@ -15,7 +14,7 @@ import arc.files.*;
|
||||
import arc.func.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.*;
|
||||
import arc.util.serialization.*;
|
||||
import dalvik.system.*;
|
||||
import mindustry.*;
|
||||
import mindustry.game.Saves.*;
|
||||
import mindustry.io.*;
|
||||
@@ -23,7 +22,6 @@ import mindustry.net.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.System;
|
||||
import java.lang.Thread.*;
|
||||
import java.util.*;
|
||||
|
||||
@@ -73,12 +71,25 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
public void shareFile(Fi file){
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadJar(Fi jar, String mainClass) throws Exception{
|
||||
DexClassLoader loader = new DexClassLoader(jar.file().getPath(), getFilesDir().getPath(), null, getClassLoader());
|
||||
return Class.forName(mainClass, true, loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showFileChooser(boolean open, String extension, Cons<Fi> cons){
|
||||
showFileChooser(open, cons, extension);
|
||||
}
|
||||
|
||||
void showFileChooser(boolean open, Cons<Fi> cons, String... extensions){
|
||||
String extension = extensions[0];
|
||||
|
||||
if(VERSION.SDK_INT >= VERSION_CODES.Q){
|
||||
Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType(extension.equals("zip") && !open ? "application/zip" : "*/*");
|
||||
intent.setType(extension.equals("zip") && !open && extensions.length == 1 ? "application/zip" : "*/*");
|
||||
|
||||
addResultListener(i -> startActivityForResult(intent, i), (code, in) -> {
|
||||
if(code == Activity.RESULT_OK && in != null && in.getData() != null){
|
||||
Uri uri = in.getData();
|
||||
@@ -108,7 +119,7 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
});
|
||||
}else if(VERSION.SDK_INT >= VERSION_CODES.M && !(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
|
||||
checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){
|
||||
chooser = new FileChooser(open ? "@open" : "@save", file -> file.extension().equalsIgnoreCase(extension), open, file -> {
|
||||
chooser = new FileChooser(open ? "@open" : "@save", file -> Structs.contains(extensions, file.extension().toLowerCase()), open, file -> {
|
||||
if(!open){
|
||||
cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension));
|
||||
}else{
|
||||
@@ -125,10 +136,19 @@ public class AndroidLauncher extends AndroidApplication{
|
||||
}
|
||||
requestPermissions(perms.toArray(new String[0]), PERMISSION_REQUEST_CODE);
|
||||
}else{
|
||||
super.showFileChooser(open, extension, cons);
|
||||
if(open){
|
||||
new FileChooser("@open", file -> Structs.contains(extensions, file.extension().toLowerCase()), true, cons).show();
|
||||
}else{
|
||||
super.showFileChooser(open, extension, cons);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMultiFileChooser(Cons<Fi> cons, String... extensions){
|
||||
showFileChooser(true, cons, extensions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginForceLandscape(){
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package mindustry.annotations.entity;
|
||||
|
||||
import arc.*;
|
||||
import arc.files.*;
|
||||
import arc.func.*;
|
||||
import arc.struct.*;
|
||||
@@ -520,7 +519,7 @@ public class EntityProcess extends BaseProcessor{
|
||||
//add free code to remove methods - always at the end
|
||||
//this only gets called next frame.
|
||||
if(first.name().equals("remove") && ann.pooled()){
|
||||
mbuilder.addStatement("$T.app.post(() -> $T.free(this))", Core.class, Pools.class);
|
||||
mbuilder.addStatement("mindustry.gen.Groups.queueFree(($T)this)", Poolable.class);
|
||||
}
|
||||
|
||||
builder.addMethod(mbuilder.build());
|
||||
@@ -587,6 +586,17 @@ public class EntityProcess extends BaseProcessor{
|
||||
//write clear
|
||||
groupsBuilder.addMethod(groupClear.build());
|
||||
|
||||
//add method for pool storage
|
||||
groupsBuilder.addField(FieldSpec.builder(ParameterizedTypeName.get(Seq.class, Poolable.class), "freeQueue", Modifier.PRIVATE, Modifier.STATIC).initializer("new Seq<>()").build());
|
||||
|
||||
//method for freeing things
|
||||
MethodSpec.Builder groupFreeQueue = MethodSpec.methodBuilder("queueFree")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addParameter(Poolable.class, "obj")
|
||||
.addStatement("freeQueue.add(obj)");
|
||||
|
||||
groupsBuilder.addMethod(groupFreeQueue.build());
|
||||
|
||||
//add method for resizing all necessary groups
|
||||
MethodSpec.Builder groupResize = MethodSpec.methodBuilder("resize")
|
||||
.addParameter(TypeName.FLOAT, "x").addParameter(TypeName.FLOAT, "y").addParameter(TypeName.FLOAT, "w").addParameter(TypeName.FLOAT, "h")
|
||||
@@ -595,6 +605,11 @@ public class EntityProcess extends BaseProcessor{
|
||||
MethodSpec.Builder groupUpdate = MethodSpec.methodBuilder("update")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||
|
||||
//free everything pooled at the start of each updaet
|
||||
groupUpdate
|
||||
.addStatement("for($T p : freeQueue) $T.free(p)", Poolable.class, Pools.class)
|
||||
.addStatement("freeQueue.clear()");
|
||||
|
||||
//method resize
|
||||
for(GroupDefinition group : groupDefs){
|
||||
if(group.spatial){
|
||||
|
||||
@@ -3,6 +3,8 @@ package mindustry.annotations.impl;
|
||||
import arc.files.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import arc.util.serialization.*;
|
||||
import com.squareup.javapoet.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
@@ -33,6 +35,17 @@ public class AssetsProcess extends BaseProcessor{
|
||||
String resources = rootDirectory + "/core/assets-raw/sprites/ui";
|
||||
Jval icons = Jval.read(Fi.get(rootDirectory + "/core/assets-raw/fontgen/config.json").readString());
|
||||
|
||||
ObjectMap<String, String> texIcons = new OrderedMap<>();
|
||||
PropertiesUtils.load(texIcons, Fi.get(rootDirectory + "/core/assets/icons/icons.properties").reader());
|
||||
|
||||
texIcons.each((key, val) -> {
|
||||
String[] split = val.split("\\|");
|
||||
String name = Strings.kebabToCamel(split[1]).replace("Medium", "").replace("Icon", "");
|
||||
if(SourceVersion.isKeyword(name) || name.equals("char")) name = name + "i";
|
||||
|
||||
ichtype.addField(FieldSpec.builder(char.class, name, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("(char)" + key).build());
|
||||
});
|
||||
|
||||
ictype.addField(FieldSpec.builder(ParameterizedTypeName.get(ObjectMap.class, String.class, TextureRegionDrawable.class),
|
||||
"icons", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("new ObjectMap<>()").build());
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ public class LogicStatementProcessor extends BaseProcessor{
|
||||
int index = 0;
|
||||
|
||||
for(Svar field : fields){
|
||||
if(field.is(Modifier.TRANSIENT)) continue;
|
||||
if(field.isAny(Modifier.TRANSIENT, Modifier.STATIC)) continue;
|
||||
|
||||
writer.addStatement("out.append(\" \")");
|
||||
writer.addStatement("out.append((($T)obj).$L$L)", c.mirror(), field.name(),
|
||||
|
||||
@@ -200,7 +200,6 @@ project(":desktop"){
|
||||
|
||||
dependencies{
|
||||
implementation project(":core")
|
||||
implementation arcModule("natives:natives-box2d-desktop")
|
||||
implementation arcModule("natives:natives-desktop")
|
||||
implementation arcModule("natives:natives-freetype-desktop")
|
||||
implementation 'com.github.MinnDevelopment:java-discord-rpc:v2.0.1'
|
||||
@@ -239,7 +238,6 @@ project(":ios"){
|
||||
|
||||
implementation arcModule("natives:natives-ios")
|
||||
implementation arcModule("natives:natives-freetype-ios")
|
||||
implementation arcModule("natives:natives-box2d-ios")
|
||||
implementation arcModule("backends:backend-robovm")
|
||||
|
||||
compileOnly project(":annotations")
|
||||
@@ -282,7 +280,6 @@ project(":core"){
|
||||
api "org.lz4:lz4-java:1.4.1"
|
||||
api arcModule("arc-core")
|
||||
api arcModule("extensions:freetype")
|
||||
api arcModule("extensions:box2d")
|
||||
api arcModule("extensions:g3d")
|
||||
api arcModule("extensions:fx")
|
||||
api arcModule("extensions:arcnet")
|
||||
@@ -299,7 +296,6 @@ project(":server"){
|
||||
|
||||
dependencies{
|
||||
implementation project(":core")
|
||||
implementation arcModule("natives:natives-box2d-desktop")
|
||||
implementation arcModule("backends:backend-headless")
|
||||
}
|
||||
}
|
||||
@@ -312,7 +308,6 @@ project(":tests"){
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-params:5.3.1"
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:5.3.1"
|
||||
testImplementation arcModule("backends:backend-headless")
|
||||
testImplementation arcModule("natives:natives-box2d-desktop")
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:5.3.1"
|
||||
}
|
||||
|
||||
@@ -334,7 +329,6 @@ project(":tools"){
|
||||
|
||||
implementation arcModule("natives:natives-desktop")
|
||||
implementation arcModule("natives:natives-freetype-desktop")
|
||||
implementation arcModule("natives:natives-box2d-desktop")
|
||||
implementation arcModule("backends:backend-headless")
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 330 B After Width: | Height: | Size: 376 B |
|
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 490 B |
|
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 304 B |
|
Before Width: | Height: | Size: 812 B After Width: | Height: | Size: 1.1 KiB |
BIN
core/assets-raw/sprites/blocks/turrets/wave-top.png
Normal file
|
After Width: | Height: | Size: 285 B |
BIN
core/assets-raw/sprites/blocks/units/command-center-team.png
Normal file
|
After Width: | Height: | Size: 511 B |
|
Before Width: | Height: | Size: 783 B After Width: | Height: | Size: 347 B |
|
Before Width: | Height: | Size: 427 B After Width: | Height: | Size: 660 B |
|
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 843 B |
|
Before Width: | Height: | Size: 244 B After Width: | Height: | Size: 323 B |
|
Before Width: | Height: | Size: 602 B After Width: | Height: | Size: 796 B |
|
Before Width: | Height: | Size: 226 B After Width: | Height: | Size: 323 B |
|
Before Width: | Height: | Size: 428 B After Width: | Height: | Size: 655 B |
|
Before Width: | Height: | Size: 890 B After Width: | Height: | Size: 908 B |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 586 B |
@@ -473,16 +473,9 @@ requirement.wave = Reach Wave {0} in {1}
|
||||
requirement.core = Destroy Enemy Core in {0}
|
||||
requirement.research = Research {0}
|
||||
requirement.capture = Capture {0}
|
||||
resume = Resume Zone:\n[lightgray]{0}
|
||||
bestwave = [lightgray]Best Wave: {0}
|
||||
#TODO fix/remove this
|
||||
launch = < LAUNCH >
|
||||
launch.text = Launch
|
||||
launch.title = Launch Successful
|
||||
launch.next = [lightgray]next opportunity at wave {0}
|
||||
launch.unable2 = [scarlet]Unable to LAUNCH.[]
|
||||
launch.confirm = This will launch all resources in your core.\nYou will not be able to return to this base.
|
||||
launch.skip.confirm = If you skip now, you will not be able to launch until later waves.
|
||||
campaign.multiplayer = While playing multiplayer in campaign, you can only research using items from [accent]your[] sectors, [scarlet]not[] the host's sector that you are on right now.\n\nTo get items to [accent]your[] sectors in multiplayer, use a [accent]launch pad[].
|
||||
uncover = Uncover
|
||||
configure = Configure Loadout
|
||||
#TODO
|
||||
@@ -1173,7 +1166,7 @@ tutorial.drillturret = Duo turrets require[accent] copper ammo[] to shoot.\nPlac
|
||||
tutorial.pause = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press space to pause.
|
||||
tutorial.pause.mobile = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press this button in the top left to pause.
|
||||
tutorial.unpause = Now press space again to unpause.
|
||||
tutorial.unpause.mobile = Now press it again to unpause.d
|
||||
tutorial.unpause.mobile = Now press it again to unpause.
|
||||
tutorial.breaking = Blocks frequently need to be destroyed.\n[accent]Hold down right-click[] to destroy all blocks in a selection.[]\n\n[accent]Destroy all the scrap blocks to the left of your core using area selection.
|
||||
tutorial.breaking.mobile = Blocks frequently need to be destroyed.\n[accent]Select deconstruction mode[], then tap a block to begin breaking it.\nDestroy an area by holding down your finger for a few seconds[] and dragging in a direction.\nPress the checkmark button to confirm breaking.\n\n[accent]Destroy all the scrap blocks to the left of your core using area selection.
|
||||
tutorial.withdraw = In some situations, taking items directly from blocks is necessary.\nTo do this, [accent]tap a block[] with items in it, then [accent]tap the item[] in the inventory.\nMultiple items can be withdrawn by [accent]tapping and holding[].\n\n[accent]Withdraw some copper from the core.[]
|
||||
|
||||
@@ -21,15 +21,8 @@
|
||||
63723=ice|block-ice-medium
|
||||
63722=ice-snow|block-ice-snow-medium
|
||||
63721=cliffs|block-cliffs-medium
|
||||
63720=rocks|block-rocks-medium
|
||||
63719=sporerocks|block-sporerocks-medium
|
||||
63718=rock|block-rock-medium
|
||||
63717=snowrock|block-snowrock-medium
|
||||
63716=icerocks|block-icerocks-medium
|
||||
63715=snowrocks|block-snowrocks-medium
|
||||
63714=dunerocks|block-dunerocks-medium
|
||||
63713=sandrocks|block-sandrocks-medium
|
||||
63712=saltrocks|block-saltrocks-medium
|
||||
63711=spore-pine|block-spore-pine-medium
|
||||
63710=snow-pine|block-snow-pine-medium
|
||||
63709=pine|block-pine-medium
|
||||
@@ -38,7 +31,6 @@
|
||||
63706=white-tree|block-white-tree-medium
|
||||
63705=spore-cluster|block-spore-cluster-medium
|
||||
63704=shale|block-shale-medium
|
||||
63703=shalerocks|block-shalerocks-medium
|
||||
63702=shale-boulder|block-shale-boulder-medium
|
||||
63701=sand-boulder|block-sand-boulder-medium
|
||||
63700=moss|block-moss-medium
|
||||
|
||||
@@ -154,7 +154,6 @@ const SaveLoadEvent = Packages.mindustry.game.EventType.SaveLoadEvent
|
||||
const MapPublishEvent = Packages.mindustry.game.EventType.MapPublishEvent
|
||||
const MapMakeEvent = Packages.mindustry.game.EventType.MapMakeEvent
|
||||
const ResizeEvent = Packages.mindustry.game.EventType.ResizeEvent
|
||||
const LaunchEvent = Packages.mindustry.game.EventType.LaunchEvent
|
||||
const LoseEvent = Packages.mindustry.game.EventType.LoseEvent
|
||||
const WinEvent = Packages.mindustry.game.EventType.WinEvent
|
||||
const Trigger = Packages.mindustry.game.EventType.Trigger
|
||||
|
||||
|
Before Width: | Height: | Size: 813 B After Width: | Height: | Size: 812 B |
|
Before Width: | Height: | Size: 553 KiB After Width: | Height: | Size: 563 KiB |
|
Before Width: | Height: | Size: 662 KiB After Width: | Height: | Size: 668 KiB |
|
Before Width: | Height: | Size: 951 KiB After Width: | Height: | Size: 969 KiB |
|
Before Width: | Height: | Size: 508 KiB After Width: | Height: | Size: 506 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 419 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 2.8 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 189 KiB |
|
Before Width: | Height: | Size: 420 KiB After Width: | Height: | Size: 419 KiB |
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
@@ -63,7 +63,7 @@ public class Vars implements Loadable{
|
||||
/** URL to the JSON file containing all the BE servers. Only queried in the V6 alpha (will be removed once it's out). */
|
||||
public static final String serverJsonV6URL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_v6.json";
|
||||
/** URL of the github issue report template.*/
|
||||
public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?template=bug_report.md";
|
||||
public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?labels=bug&template=bug_report.md";
|
||||
/** list of built-in servers.*/
|
||||
public static final Seq<String> defaultServers = Seq.with();
|
||||
/** maximum distance between mine and core that supports automatic transferring */
|
||||
@@ -72,8 +72,6 @@ public class Vars implements Loadable{
|
||||
public static final int maxTextLength = 150;
|
||||
/** max player name length in bytes */
|
||||
public static final int maxNameLength = 40;
|
||||
/** shadow color for turrets */
|
||||
public static final float turretShadowColor = Color.toFloatBits(0, 0, 0, 0.22f);
|
||||
/** displayed item size when ingame. */
|
||||
public static final float itemSize = 5f;
|
||||
/** units outside of this bound will die instantly */
|
||||
|
||||
@@ -6,6 +6,7 @@ import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.EnumSet;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
@@ -165,6 +166,11 @@ public class BlockIndexer{
|
||||
return flagMap[team.id][type.ordinal()];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Tile findClosestFlag(float x, float y, Team team, BlockFlag flag){
|
||||
return Geometry.findClosest(x, y, getAllied(team, flag));
|
||||
}
|
||||
|
||||
public boolean eachBlock(Teamc team, float range, Boolf<Building> pred, Cons<Building> cons){
|
||||
return eachBlock(team.team(), team.getX(), team.getY(), range, pred, cons);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class Pathfinder implements Runnable{
|
||||
PathTile.health(tile) * 5 +
|
||||
(PathTile.nearSolid(tile) ? 2 : 0) +
|
||||
(PathTile.nearLiquid(tile) ? 6 : 0) +
|
||||
(PathTile.deep(tile) ? 70 : 0) +
|
||||
(PathTile.deep(tile) ? 6000 : 0) +
|
||||
(PathTile.damages(tile) ? 30 : 0),
|
||||
|
||||
//legs
|
||||
@@ -116,7 +116,7 @@ public class Pathfinder implements Runnable{
|
||||
}
|
||||
|
||||
return PathTile.get(
|
||||
tile.build == null ? 0 : Math.min((int)(tile.build.health / 40), 127),
|
||||
tile.build == null ? 0 : Math.min((int)(tile.build.health / 40), 80),
|
||||
tile.getTeamID(),
|
||||
tile.solid(),
|
||||
tile.floor().isLiquid,
|
||||
|
||||
@@ -16,7 +16,7 @@ public class FlyingAI extends AIController{
|
||||
moveTo(target, unit.range() * 0.8f);
|
||||
unit.lookAt(target);
|
||||
}else{
|
||||
attack(80f);
|
||||
attack(100f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,6 @@ public class GroundAI extends AIController{
|
||||
|
||||
if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type().rotateShooting){
|
||||
if(unit.type().hasWeapons()){
|
||||
//TODO certain units should not look at the target, e.g. ships
|
||||
unit.lookAt(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
|
||||
}
|
||||
}else if(unit.moving()){
|
||||
|
||||
@@ -1,31 +1,25 @@
|
||||
package mindustry.async;
|
||||
|
||||
import arc.box2d.*;
|
||||
import arc.box2d.BodyDef.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.math.geom.QuadTree.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.async.PhysicsProcess.PhysicsWorld.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public class PhysicsProcess implements AsyncProcess{
|
||||
private Physics physics;
|
||||
private static final int
|
||||
layers = 3,
|
||||
layerGround = 0,
|
||||
layerLegs = 1,
|
||||
layerFlying = 2;
|
||||
|
||||
private PhysicsWorld physics;
|
||||
private Seq<PhysicRef> refs = new Seq<>(false);
|
||||
private BodyDef def;
|
||||
|
||||
private EntityGroup<? extends Physicsc> group;
|
||||
private Filter flying = new Filter(){{
|
||||
maskBits = categoryBits = 2;
|
||||
}}, ground = new Filter(){{
|
||||
maskBits = categoryBits = 1;
|
||||
}};
|
||||
|
||||
public PhysicsProcess(){
|
||||
def = new BodyDef();
|
||||
def.type = BodyType.dynamicBody;
|
||||
|
||||
//currently only enabled for units
|
||||
group = Groups.unit;
|
||||
}
|
||||
//currently only enabled for units
|
||||
private EntityGroup<Unit> group = Groups.unit;
|
||||
|
||||
@Override
|
||||
public void begin(){
|
||||
@@ -34,47 +28,39 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
//remove stale entities
|
||||
refs.removeAll(ref -> {
|
||||
if(!ref.entity.isAdded()){
|
||||
physics.destroyBody(ref.body);
|
||||
physics.remove(ref.body);
|
||||
ref.entity.physref(null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
//find entities without bodies and assign them
|
||||
for(Physicsc entity : group){
|
||||
boolean grounded = entity.isGrounded();
|
||||
int bits = grounded ? ground.maskBits : flying.maskBits;
|
||||
//find Unit without bodies and assign them
|
||||
for(Unit entity : group){
|
||||
|
||||
if(entity.physref() == null){
|
||||
//add bodies to entities that have none
|
||||
FixtureDef fd = new FixtureDef();
|
||||
fd.shape = new CircleShape(entity.hitSize() / 2f);
|
||||
fd.density = 5f;
|
||||
fd.restitution = 0.0f;
|
||||
fd.filter.maskBits = fd.filter.categoryBits = (grounded ? ground : flying).maskBits;
|
||||
|
||||
def.position.set(entity);
|
||||
|
||||
Body body = physics.createBody(def);
|
||||
body.createFixture(fd);
|
||||
PhysicsBody body = new PhysicsBody();
|
||||
body.x = entity.x();
|
||||
body.y = entity.y();
|
||||
body.mass = entity.mass();
|
||||
body.radius = entity.hitSize() / 2f;
|
||||
|
||||
PhysicRef ref = new PhysicRef(entity, body);
|
||||
refs.add(ref);
|
||||
|
||||
entity.physref(ref);
|
||||
|
||||
physics.add(body);
|
||||
}
|
||||
|
||||
//save last position
|
||||
PhysicRef ref = entity.physref();
|
||||
|
||||
if(ref.body.getFixtureList().any() && ref.body.getFixtureList().first().getFilterData().categoryBits != bits){
|
||||
//set correct filter
|
||||
ref.body.getFixtureList().first().setFilterData(grounded ? ground : flying);
|
||||
}
|
||||
|
||||
ref.velocity.set(entity.deltaX(), entity.deltaY());
|
||||
ref.position.set(entity);
|
||||
ref.body.layer =
|
||||
entity.type().allowLegStep ? layerLegs :
|
||||
entity.isGrounded() ? layerGround : layerFlying;
|
||||
ref.x = entity.x();
|
||||
ref.y = entity.y();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,26 +71,11 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
//get last position vectors before step
|
||||
for(PhysicRef ref : refs){
|
||||
//force set target position
|
||||
ref.body.setPosition(ref.position.x, ref.position.y);
|
||||
|
||||
//save last position for delta
|
||||
ref.lastPosition.set(ref.body.getPosition());
|
||||
|
||||
//write velocity
|
||||
ref.body.setLinearVelocity(ref.velocity);
|
||||
|
||||
ref.lastVelocity.set(ref.velocity);
|
||||
ref.body.x = ref.x;
|
||||
ref.body.y = ref.y;
|
||||
}
|
||||
|
||||
physics.step(1f/45f, 5, 8);
|
||||
|
||||
//get delta vectors
|
||||
for(PhysicRef ref : refs){
|
||||
//get delta vector
|
||||
ref.delta.set(ref.body.getPosition()).sub(ref.lastPosition);
|
||||
|
||||
ref.velocity.set(ref.body.getLinearVelocity());
|
||||
}
|
||||
physics.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,13 +86,8 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
for(PhysicRef ref : refs){
|
||||
Physicsc entity = ref.entity;
|
||||
|
||||
entity.move(ref.delta.x, ref.delta.y);
|
||||
|
||||
//save last position
|
||||
ref.position.set(entity);
|
||||
|
||||
//add delta velocity - this doesn't work very well yet
|
||||
//entity.vel().add(ref.velocity).sub(ref.lastVelocity);
|
||||
//move by delta
|
||||
entity.move(ref.body.x - ref.x, ref.body.y - ref.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +95,6 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
public void reset(){
|
||||
if(physics != null){
|
||||
refs.clear();
|
||||
physics.dispose();
|
||||
physics = null;
|
||||
}
|
||||
}
|
||||
@@ -138,17 +103,95 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
public void init(){
|
||||
reset();
|
||||
|
||||
physics = new Physics(new Vec2(), true);
|
||||
physics = new PhysicsWorld(Vars.world.getQuadBounds(new Rect()));
|
||||
}
|
||||
|
||||
public static class PhysicRef{
|
||||
public Physicsc entity;
|
||||
public Body body;
|
||||
public Vec2 lastPosition = new Vec2(), delta = new Vec2(), velocity = new Vec2(), lastVelocity = new Vec2(), position = new Vec2();
|
||||
public PhysicsBody body;
|
||||
public float x, y;
|
||||
|
||||
public PhysicRef(Physicsc entity, Body body){
|
||||
public PhysicRef(Physicsc entity, PhysicsBody body){
|
||||
this.entity = entity;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
|
||||
//world for simulating physics in a different thread
|
||||
public static class PhysicsWorld{
|
||||
//how much to soften movement by
|
||||
private static final float scl = 1.25f;
|
||||
|
||||
private final QuadTree<PhysicsBody>[] trees = new QuadTree[layers];
|
||||
private final Seq<PhysicsBody> bodies = new Seq<>(false, 16, PhysicsBody.class);
|
||||
private final Seq<PhysicsBody> seq = new Seq<>(PhysicsBody.class);
|
||||
private final Rect rect = new Rect();
|
||||
private final Vec2 vec = new Vec2();
|
||||
|
||||
public PhysicsWorld(Rect bounds){
|
||||
for(int i = 0; i < layers; i++){
|
||||
trees[i] = new QuadTree<>(new Rect(bounds));
|
||||
}
|
||||
}
|
||||
|
||||
public void add(PhysicsBody body){
|
||||
bodies.add(body);
|
||||
}
|
||||
|
||||
public void remove(PhysicsBody body){
|
||||
bodies.remove(body);
|
||||
}
|
||||
|
||||
public void update(){
|
||||
for(int i = 0; i < layers; i++){
|
||||
trees[i].clear();
|
||||
}
|
||||
|
||||
for(int i = 0; i < bodies.size; i++){
|
||||
PhysicsBody body = bodies.items[i];
|
||||
body.collided = false;
|
||||
trees[body.layer].insert(body);
|
||||
}
|
||||
|
||||
for(int i = 0; i < bodies.size; i++){
|
||||
PhysicsBody body = bodies.items[i];
|
||||
body.hitbox(rect);
|
||||
|
||||
seq.size = 0;
|
||||
trees[body.layer].intersect(rect, seq);
|
||||
|
||||
for(int j = 0; j < seq.size; j++){
|
||||
PhysicsBody other = seq.items[j];
|
||||
|
||||
if(other == body || other.collided) continue;
|
||||
|
||||
float rs = body.radius + other.radius;
|
||||
float dst = Mathf.dst(body.x, body.y, other.x, other.y);
|
||||
|
||||
if(dst < rs){
|
||||
vec.set(body.x - other.x, body.y - other.y).setLength(rs - dst);
|
||||
float ms = body.mass + other.mass;
|
||||
float m1 = other.mass / ms, m2 = body.mass / ms;
|
||||
|
||||
body.x += vec.x * m1 / scl;
|
||||
body.y += vec.y * m1 / scl;
|
||||
other.x -= vec.x * m2 / scl;
|
||||
other.y -= vec.y * m2 / scl;
|
||||
}
|
||||
}
|
||||
body.collided = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PhysicsBody implements QuadTreeObject{
|
||||
public float x, y, radius, mass;
|
||||
public int layer = 0;
|
||||
public boolean collided = false;
|
||||
|
||||
@Override
|
||||
public void hitbox(Rect out){
|
||||
out.setCentered(x, y, radius * 2, radius * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,6 +208,7 @@ public class Blocks implements ContentList{
|
||||
liquidDrop = Liquids.slag;
|
||||
isLiquid = true;
|
||||
cacheLayer = CacheLayer.slag;
|
||||
attributes.set(Attribute.heat, 0.85f);
|
||||
}};
|
||||
|
||||
stone = new Floor("stone");
|
||||
@@ -265,7 +266,7 @@ public class Blocks implements ContentList{
|
||||
variants = 3;
|
||||
status = StatusEffects.muddy;
|
||||
statusDuration = 30f;
|
||||
attributes.set(Attribute.water, 2f);
|
||||
attributes.set(Attribute.water, 1f);
|
||||
cacheLayer = CacheLayer.mud;
|
||||
albedo = 0.35f;
|
||||
}};
|
||||
@@ -865,7 +866,8 @@ public class Blocks implements ContentList{
|
||||
size = 2;
|
||||
reload = 250f;
|
||||
range = 85f;
|
||||
healPercent = 14f;
|
||||
healPercent = 11f;
|
||||
phaseBoost = 15f;
|
||||
health = 80 * size * size;
|
||||
consumes.item(Items.phasefabric).boost();
|
||||
}};
|
||||
@@ -1142,13 +1144,14 @@ public class Blocks implements ContentList{
|
||||
powerProduction = 1.8f;
|
||||
generateEffect = Fx.redgeneratespark;
|
||||
size = 2;
|
||||
floating = true;
|
||||
}};
|
||||
|
||||
steamGenerator = new BurnerGenerator("steam-generator"){{
|
||||
requirements(Category.power, with(Items.copper, 35, Items.graphite, 25, Items.lead, 40, Items.silicon, 30));
|
||||
powerProduction = 5.5f;
|
||||
itemDuration = 90f;
|
||||
consumes.liquid(Liquids.water, 0.09f);
|
||||
consumes.liquid(Liquids.water, 0.1f);
|
||||
hasLiquids = true;
|
||||
size = 2;
|
||||
}};
|
||||
@@ -1268,7 +1271,7 @@ public class Blocks implements ContentList{
|
||||
rotateSpeed = 1.4f;
|
||||
attribute = Attribute.water;
|
||||
|
||||
consumes.power(1.25f);
|
||||
consumes.power(1.5f);
|
||||
}};
|
||||
|
||||
cultivator = new Cultivator("cultivator"){{
|
||||
@@ -1751,6 +1754,7 @@ public class Blocks implements ContentList{
|
||||
};
|
||||
size = 3;
|
||||
consumes.power(1.2f);
|
||||
floating = true;
|
||||
}};
|
||||
|
||||
additiveReconstructor = new Reconstructor("additive-reconstructor"){{
|
||||
|
||||
@@ -378,7 +378,11 @@ public class TechTree implements ContentList{
|
||||
node(nova, () -> {
|
||||
node(pulsar, () -> {
|
||||
node(quasar, () -> {
|
||||
node(vela, () -> {
|
||||
node(corvus, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -69,7 +69,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
dagger = new UnitType("dagger"){{
|
||||
speed = 0.5f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
health = 140;
|
||||
weapons.add(new Weapon("large-weapon"){{
|
||||
reload = 14f;
|
||||
@@ -83,7 +83,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
mace = new UnitType("mace"){{
|
||||
speed = 0.4f;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
health = 500;
|
||||
armor = 4f;
|
||||
|
||||
@@ -114,7 +114,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
fortress = new UnitType("fortress"){{
|
||||
speed = 0.38f;
|
||||
hitsize = 13f;
|
||||
hitSize = 13f;
|
||||
rotateSpeed = 3f;
|
||||
targetAir = false;
|
||||
health = 790;
|
||||
@@ -147,7 +147,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
scepter = new UnitType("scepter"){{
|
||||
speed = 0.35f;
|
||||
hitsize = 20f;
|
||||
hitSize = 20f;
|
||||
rotateSpeed = 2.1f;
|
||||
health = 9000;
|
||||
armor = 11f;
|
||||
@@ -156,6 +156,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
mechStepParticles = true;
|
||||
mechStepShake = 0.15f;
|
||||
singleTarget = true;
|
||||
|
||||
weapons.add(
|
||||
new Weapon("scepter-weapon"){{
|
||||
@@ -207,7 +208,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
reign = new UnitType("reign"){{
|
||||
speed = 0.35f;
|
||||
hitsize = 26f;
|
||||
hitSize = 26f;
|
||||
rotateSpeed = 1.65f;
|
||||
health = 24000;
|
||||
armor = 14f;
|
||||
@@ -269,13 +270,14 @@ public class UnitTypes implements ContentList{
|
||||
canBoost = true;
|
||||
boostMultiplier = 1.5f;
|
||||
speed = 0.55f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
health = 110f;
|
||||
buildSpeed = 0.8f;
|
||||
armor = 1f;
|
||||
commandLimit = 8;
|
||||
|
||||
abilities.add(new HealFieldAbility(10f, 60f * 4, 60f));
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
weapons.add(new Weapon("heal-weapon"){{
|
||||
top = false;
|
||||
@@ -295,16 +297,17 @@ public class UnitTypes implements ContentList{
|
||||
canBoost = true;
|
||||
boostMultiplier = 1.5f;
|
||||
speed = 0.65f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
health = 320f;
|
||||
buildSpeed = 0.9f;
|
||||
armor = 4f;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 5f;
|
||||
commandLimit = 15;
|
||||
commandLimit = 8;
|
||||
|
||||
abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f));
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
weapons.add(new Weapon("heal-shotgun-weapon"){{
|
||||
top = false;
|
||||
@@ -335,7 +338,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
quasar = new UnitType("quasar"){{
|
||||
mineTier = 1;
|
||||
hitsize = 12f;
|
||||
hitSize = 12f;
|
||||
boostMultiplier = 2f;
|
||||
itemCapacity = 80;
|
||||
health = 650f;
|
||||
@@ -344,11 +347,12 @@ public class UnitTypes implements ContentList{
|
||||
armor = 9f;
|
||||
landShake = 2f;
|
||||
|
||||
commandLimit = 18;
|
||||
commandLimit = 10;
|
||||
mechFrontSway = 0.55f;
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
speed = 0.4f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 7f;
|
||||
@@ -377,7 +381,7 @@ public class UnitTypes implements ContentList{
|
||||
}};
|
||||
|
||||
vela = new UnitType("vela"){{
|
||||
hitsize = 23f;
|
||||
hitSize = 23f;
|
||||
|
||||
rotateSpeed = 1.6f;
|
||||
canDrown = false;
|
||||
@@ -385,6 +389,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
mechStepParticles = true;
|
||||
mechStepShake = 0.15f;
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
speed = 0.35f;
|
||||
boostMultiplier = 2.1f;
|
||||
@@ -392,12 +397,12 @@ public class UnitTypes implements ContentList{
|
||||
engineSize = 6f;
|
||||
lowAltitude = true;
|
||||
|
||||
health = 6000f;
|
||||
health = 6500f;
|
||||
armor = 7f;
|
||||
canBoost = true;
|
||||
landShake = 4f;
|
||||
|
||||
commandLimit = 20;
|
||||
commandLimit = 8;
|
||||
|
||||
weapons.add(new Weapon("vela-weapon"){{
|
||||
mirror = false;
|
||||
@@ -414,7 +419,7 @@ public class UnitTypes implements ContentList{
|
||||
continuous = true;
|
||||
cooldownTime = 200f;
|
||||
|
||||
bullet = new ContinuousLaserBulletType(16){{
|
||||
bullet = new ContinuousLaserBulletType(17){{
|
||||
length = 150f;
|
||||
hitEffect = Fx.hitMeltHeal;
|
||||
drawSize = 420f;
|
||||
@@ -439,7 +444,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
corvus = new UnitType("corvus"){{
|
||||
mineTier = 1;
|
||||
hitsize = 29f;
|
||||
hitSize = 29f;
|
||||
itemCapacity = 80;
|
||||
health = 19000f;
|
||||
buildSpeed = 1.7f;
|
||||
@@ -447,7 +452,7 @@ public class UnitTypes implements ContentList{
|
||||
landShake = 1.5f;
|
||||
rotateSpeed = 1.5f;
|
||||
|
||||
commandLimit = 20;
|
||||
commandLimit = 8;
|
||||
|
||||
legCount = 4;
|
||||
legLength = 14f;
|
||||
@@ -457,6 +462,8 @@ public class UnitTypes implements ContentList{
|
||||
hovering = true;
|
||||
visualElevation = 0.2f;
|
||||
allowLegStep = true;
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
groundLayer = Layer.legUnit;
|
||||
|
||||
speed = 0.3f;
|
||||
|
||||
@@ -513,7 +520,7 @@ public class UnitTypes implements ContentList{
|
||||
defaultController = SuicideAI::new;
|
||||
|
||||
speed = 0.85f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
health = 180;
|
||||
mechSideSway = 0.25f;
|
||||
range = 40f;
|
||||
@@ -541,7 +548,7 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 80;
|
||||
speed = 0.5f;
|
||||
drag = 0.4f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
rotateSpeed = 3f;
|
||||
targetAir = false;
|
||||
health = 600;
|
||||
@@ -581,7 +588,7 @@ public class UnitTypes implements ContentList{
|
||||
spiroct = new UnitType("spiroct"){{
|
||||
speed = 0.4f;
|
||||
drag = 0.4f;
|
||||
hitsize = 12f;
|
||||
hitSize = 12f;
|
||||
rotateSpeed = 3f;
|
||||
health = 760;
|
||||
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
|
||||
@@ -592,6 +599,7 @@ public class UnitTypes implements ContentList{
|
||||
legBaseOffset = 2f;
|
||||
hovering = true;
|
||||
armor = 5f;
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
buildSpeed = 0.75f;
|
||||
|
||||
@@ -646,7 +654,7 @@ public class UnitTypes implements ContentList{
|
||||
arkyid = new UnitType("arkyid"){{
|
||||
drag = 0.1f;
|
||||
speed = 0.5f;
|
||||
hitsize = 21f;
|
||||
hitSize = 21f;
|
||||
health = 8000;
|
||||
armor = 6f;
|
||||
|
||||
@@ -663,6 +671,7 @@ public class UnitTypes implements ContentList{
|
||||
legLengthScl = 0.96f;
|
||||
rippleScale = 2f;
|
||||
legSpeed = 0.2f;
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
legSplashDamage = 32;
|
||||
legSplashRange = 30;
|
||||
@@ -744,7 +753,7 @@ public class UnitTypes implements ContentList{
|
||||
toxopid = new UnitType("toxopid"){{
|
||||
drag = 0.1f;
|
||||
speed = 0.5f;
|
||||
hitsize = 21f;
|
||||
hitSize = 21f;
|
||||
health = 22000;
|
||||
armor = 13f;
|
||||
|
||||
@@ -761,6 +770,7 @@ public class UnitTypes implements ContentList{
|
||||
legLengthScl = 0.93f;
|
||||
rippleScale = 3f;
|
||||
legSpeed = 0.19f;
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
legSplashDamage = 80;
|
||||
legSplashRange = 60;
|
||||
@@ -875,7 +885,7 @@ public class UnitTypes implements ContentList{
|
||||
weapons.add(new Weapon(){{
|
||||
y = 0f;
|
||||
x = 2f;
|
||||
reload = 15f;
|
||||
reload = 13f;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardCopper;
|
||||
shootSound = Sounds.shoot;
|
||||
@@ -888,7 +898,7 @@ public class UnitTypes implements ContentList{
|
||||
accel = 0.08f;
|
||||
drag = 0.016f;
|
||||
flying = true;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
targetAir = false;
|
||||
engineOffset = 7.8f;
|
||||
range = 140f;
|
||||
@@ -925,7 +935,7 @@ public class UnitTypes implements ContentList{
|
||||
drag = 0.016f;
|
||||
flying = true;
|
||||
range = 140f;
|
||||
hitsize = 18f;
|
||||
hitSize = 20f;
|
||||
lowAltitude = true;
|
||||
armor = 5f;
|
||||
|
||||
@@ -963,9 +973,9 @@ public class UnitTypes implements ContentList{
|
||||
}};
|
||||
|
||||
antumbra = new UnitType("antumbra"){{
|
||||
speed = 1.13f;
|
||||
accel = 0.035f;
|
||||
drag = 0.05f;
|
||||
speed = 0.8f;
|
||||
accel = 0.04f;
|
||||
drag = 0.04f;
|
||||
rotateSpeed = 1.9f;
|
||||
flying = true;
|
||||
lowAltitude = true;
|
||||
@@ -973,7 +983,7 @@ public class UnitTypes implements ContentList{
|
||||
armor = 9f;
|
||||
engineOffset = 21;
|
||||
engineSize = 5.3f;
|
||||
hitsize = 56f;
|
||||
hitSize = 56f;
|
||||
|
||||
BulletType missiles = new MissileBulletType(2.7f, 10){{
|
||||
width = 8f;
|
||||
@@ -1036,16 +1046,16 @@ public class UnitTypes implements ContentList{
|
||||
}};
|
||||
|
||||
eclipse = new UnitType("eclipse"){{
|
||||
speed = 1.09f;
|
||||
accel = 0.02f;
|
||||
drag = 0.05f;
|
||||
speed = 0.52f;
|
||||
accel = 0.04f;
|
||||
drag = 0.04f;
|
||||
rotateSpeed = 1f;
|
||||
flying = true;
|
||||
lowAltitude = true;
|
||||
health = 20000;
|
||||
engineOffset = 38;
|
||||
engineSize = 7.3f;
|
||||
hitsize = 58f;
|
||||
hitSize = 58f;
|
||||
destructibleWreck = false;
|
||||
armor = 13f;
|
||||
|
||||
@@ -1128,6 +1138,8 @@ public class UnitTypes implements ContentList{
|
||||
range = 50f;
|
||||
isCounted = false;
|
||||
|
||||
ammoType = AmmoTypes.powerLow;
|
||||
|
||||
mineTier = 1;
|
||||
mineSpeed = 2.5f;
|
||||
}};
|
||||
@@ -1145,10 +1157,12 @@ public class UnitTypes implements ContentList{
|
||||
health = 400;
|
||||
buildSpeed = 0.5f;
|
||||
engineOffset = 6.5f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
lowAltitude = true;
|
||||
isCounted = false;
|
||||
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 3.5f;
|
||||
|
||||
@@ -1197,11 +1211,13 @@ public class UnitTypes implements ContentList{
|
||||
flying = true;
|
||||
engineOffset = 10.5f;
|
||||
rotateShooting = false;
|
||||
hitsize = 15f;
|
||||
hitSize = 15f;
|
||||
engineSize = 3f;
|
||||
payloadCapacity = (2 * 2) * tilePayload;
|
||||
buildSpeed = 2.5f;
|
||||
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
weapons.add(
|
||||
new Weapon("heal-weapon-mount"){{
|
||||
reload = 25f;
|
||||
@@ -1231,12 +1247,14 @@ public class UnitTypes implements ContentList{
|
||||
engineOffset = 12f;
|
||||
engineSize = 6f;
|
||||
rotateShooting = false;
|
||||
hitsize = 32f;
|
||||
hitSize = 32f;
|
||||
payloadCapacity = (3 * 3) * tilePayload;
|
||||
buildSpeed = 2.5f;
|
||||
range = 140f;
|
||||
targetAir = false;
|
||||
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
weapons.add(
|
||||
new Weapon(){{
|
||||
x = y = 0f;
|
||||
@@ -1291,11 +1309,11 @@ public class UnitTypes implements ContentList{
|
||||
engineOffset = 46f;
|
||||
engineSize = 7.8f;
|
||||
rotateShooting = false;
|
||||
hitsize = 60f;
|
||||
hitSize = 60f;
|
||||
payloadCapacity = (5.3f * 5.3f) * tilePayload;
|
||||
buildSpeed = 4f;
|
||||
drawShields = false;
|
||||
commandLimit = 25;
|
||||
commandLimit = 6;
|
||||
|
||||
abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f));
|
||||
}};
|
||||
@@ -1306,7 +1324,7 @@ public class UnitTypes implements ContentList{
|
||||
risso = new UnitType("risso"){{
|
||||
speed = 1.1f;
|
||||
drag = 0.13f;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
health = 280;
|
||||
accel = 0.4f;
|
||||
rotateSpeed = 3.3f;
|
||||
@@ -1357,7 +1375,7 @@ public class UnitTypes implements ContentList{
|
||||
health = 600;
|
||||
speed = 0.9f;
|
||||
drag = 0.15f;
|
||||
hitsize = 11f;
|
||||
hitSize = 11f;
|
||||
armor = 4f;
|
||||
accel = 0.3f;
|
||||
rotateSpeed = 2.6f;
|
||||
@@ -1400,7 +1418,7 @@ public class UnitTypes implements ContentList{
|
||||
accel = 0.2f;
|
||||
rotateSpeed = 1.8f;
|
||||
drag = 0.17f;
|
||||
hitsize = 16f;
|
||||
hitSize = 16f;
|
||||
armor = 7f;
|
||||
rotateShooting = false;
|
||||
|
||||
@@ -1493,7 +1511,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
speed = 0.73f;
|
||||
drag = 0.17f;
|
||||
hitsize = 39f;
|
||||
hitSize = 39f;
|
||||
accel = 0.2f;
|
||||
rotateSpeed = 1.3f;
|
||||
rotateShooting = false;
|
||||
@@ -1576,7 +1594,7 @@ public class UnitTypes implements ContentList{
|
||||
health = 22000;
|
||||
speed = 0.62f;
|
||||
drag = 0.18f;
|
||||
hitsize = 50f;
|
||||
hitSize = 50f;
|
||||
armor = 16f;
|
||||
accel = 0.19f;
|
||||
rotateSpeed = 0.9f;
|
||||
@@ -1639,7 +1657,7 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 30;
|
||||
health = 120f;
|
||||
engineOffset = 6f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
|
||||
weapons.add(new Weapon("small-basic-weapon"){{
|
||||
reload = 17f;
|
||||
@@ -1673,7 +1691,7 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 50;
|
||||
health = 150f;
|
||||
engineOffset = 6f;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
rotateShooting = false;
|
||||
lowAltitude = true;
|
||||
|
||||
@@ -1713,7 +1731,7 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 70;
|
||||
health = 190f;
|
||||
engineOffset = 6f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
|
||||
weapons.add(new Weapon("small-mount-weapon"){{
|
||||
top = false;
|
||||
@@ -1743,7 +1761,7 @@ public class UnitTypes implements ContentList{
|
||||
block = new UnitType("block"){
|
||||
{
|
||||
speed = 0f;
|
||||
hitsize = 0f;
|
||||
hitSize = 0f;
|
||||
health = 1;
|
||||
rotateSpeed = 360f;
|
||||
itemCapacity = 0;
|
||||
|
||||
@@ -170,12 +170,13 @@ public class Weathers implements ContentList{
|
||||
sandstorm = new Weather("sandstorm"){
|
||||
TextureRegion region;
|
||||
float size = 140f, padding = size, invDensity = 1500f, baseSpeed = 6.1f;
|
||||
float force = 0.45f;
|
||||
float force = 0.4f * 0;
|
||||
Color color = Color.valueOf("f7cba4");
|
||||
Texture noise;
|
||||
|
||||
{
|
||||
attrs.set(Attribute.light, -0.1f);
|
||||
opacityMultiplier = 0.8f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -250,7 +251,7 @@ public class Weathers implements ContentList{
|
||||
|
||||
sporestorm = new Weather("sporestorm"){
|
||||
TextureRegion region;
|
||||
float size = 5f, padding = size, invDensity = 2000f, baseSpeed = 4.3f, force = 0.28f;
|
||||
float size = 5f, padding = size, invDensity = 2000f, baseSpeed = 4.3f, force = 0.28f * 0;
|
||||
Color color = Color.valueOf("7457ce");
|
||||
Texture noise;
|
||||
|
||||
@@ -259,6 +260,7 @@ public class Weathers implements ContentList{
|
||||
attrs.set(Attribute.light, -0.15f);
|
||||
status = StatusEffects.sporeSlowed;
|
||||
statusGround = false;
|
||||
opacityMultiplier = 0.85f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,7 @@ public class ContentLoader{
|
||||
new StatusEffects(),
|
||||
new Liquids(),
|
||||
new Bullets(),
|
||||
new AmmoTypes(),
|
||||
new UnitTypes(),
|
||||
new Blocks(),
|
||||
new Loadouts(),
|
||||
|
||||
@@ -17,7 +17,7 @@ public class GameState{
|
||||
/** Wave countdown in ticks. */
|
||||
public float wavetime;
|
||||
/** Whether the game is in game over state. */
|
||||
public boolean gameOver = false, launched = false, serverPaused = false, wasTimeout;
|
||||
public boolean gameOver = false, serverPaused = false, wasTimeout;
|
||||
/** Map that is currently being played on. */
|
||||
public @NonNull Map map = emptyMap;
|
||||
/** The current game rules. */
|
||||
@@ -52,7 +52,7 @@ public class GameState{
|
||||
|
||||
/** @return whether the player is in a campaign and they are out of sector time */
|
||||
public boolean isOutOfTime(){
|
||||
return isCampaign() && isGame() && getSector().getTimeSpent() >= turnDuration;
|
||||
return isCampaign() && isGame() && getSector().getTimeSpent() >= turnDuration && !net.active();
|
||||
}
|
||||
|
||||
public boolean hasSector(){
|
||||
|
||||
@@ -4,7 +4,6 @@ import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
@@ -178,7 +177,7 @@ public class Logic implements ApplicationListener{
|
||||
public void runWave(){
|
||||
spawner.spawnEnemies();
|
||||
state.wave++;
|
||||
state.wavetime = state.hasSector() && state.getSector().isLaunchWave(state.wave) ? state.rules.waveSpacing * state.rules.launchWaveMultiplier : state.rules.waveSpacing;
|
||||
state.wavetime = state.rules.waveSpacing;
|
||||
|
||||
Events.fire(new WaveEvent());
|
||||
}
|
||||
@@ -251,58 +250,6 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both)
|
||||
public static void launchZone(){
|
||||
if(!state.isCampaign()) return;
|
||||
|
||||
if(!headless){
|
||||
ui.hudfrag.showLaunch();
|
||||
}
|
||||
|
||||
//TODO better core launch effect
|
||||
for(Building tile : state.teams.playerCores()){
|
||||
Fx.launch.at(tile);
|
||||
}
|
||||
|
||||
Sector sector = state.rules.sector;
|
||||
|
||||
//TODO containers must be launched too
|
||||
Time.runTask(30f, () -> {
|
||||
Sector origin = sector.save.meta.secinfo.origin;
|
||||
if(origin != null){
|
||||
ItemSeq stacks = origin.getExtraItems();
|
||||
|
||||
//add up all items into list
|
||||
for(Building entity : state.teams.playerCores()){
|
||||
entity.items.each(stacks::add);
|
||||
}
|
||||
|
||||
//save received items
|
||||
origin.setExtraItems(stacks);
|
||||
}
|
||||
|
||||
//remove all the cores
|
||||
state.teams.playerCores().each(b -> b.tile.remove());
|
||||
|
||||
state.launched = true;
|
||||
state.gameOver = true;
|
||||
|
||||
//save over the data w/o the cores
|
||||
sector.save.save();
|
||||
|
||||
//run a turn, since launching takes up a turn
|
||||
universe.runTurn();
|
||||
|
||||
//TODO apply extra damage to sector
|
||||
//sector.setTurnsPassed(sector.getTurnsPassed() + 3);
|
||||
|
||||
//TODO load the sector that was launched from
|
||||
Events.fire(new LaunchEvent());
|
||||
//manually fire game over event now
|
||||
Events.fire(new GameOverEvent(state.rules.defaultTeam));
|
||||
});
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both)
|
||||
public static void updateGameOver(Team winner){
|
||||
state.gameOver = true;
|
||||
|
||||
@@ -131,7 +131,7 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
if(Time.millis() < info.lastKicked){
|
||||
if(Time.millis() < admins.getKickTime(uuid, con.address)){
|
||||
con.kick(KickReason.recentKick);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,18 @@ import mindustry.type.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
import rhino.*;
|
||||
|
||||
import java.net.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public interface Platform{
|
||||
|
||||
/** Dynamically loads a jar file. */
|
||||
default Class<?> loadJar(Fi jar, String mainClass) throws Exception{
|
||||
URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
||||
return classLoader.loadClass(mainClass);
|
||||
}
|
||||
|
||||
/** Steam: Update lobby visibility.*/
|
||||
default void updateLobby(){}
|
||||
|
||||
@@ -121,7 +129,7 @@ public interface Platform{
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a file chooser for multiple file types. Only supported on desktop.
|
||||
* Show a file chooser for multiple file types.
|
||||
* @param cons Selection listener
|
||||
* @param extensions File extensions to filter
|
||||
*/
|
||||
|
||||
@@ -15,7 +15,8 @@ public enum ContentType{
|
||||
loadout_UNUSED,
|
||||
typeid_UNUSED,
|
||||
error,
|
||||
planet;
|
||||
planet,
|
||||
ammo;
|
||||
|
||||
public static final ContentType[] all = values();
|
||||
}
|
||||
|
||||
@@ -257,6 +257,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
player.set(world.width() * tilesize/2f, world.height() * tilesize/2f);
|
||||
player.clearUnit();
|
||||
Groups.unit.clear();
|
||||
Groups.build.clear();
|
||||
logic.play();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,17 +24,17 @@ public class Lightning{
|
||||
|
||||
/** Create a lighting branch at a location. Use Team.derelict to damage everyone. */
|
||||
public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){
|
||||
createLightingInternal(null, lastSeed++, team, color, damage, x, y, targetAngle, length);
|
||||
createLightningInternal(null, lastSeed++, team, color, damage, x, y, targetAngle, length);
|
||||
}
|
||||
|
||||
/** Create a lighting branch at a location. Uses bullet parameters. */
|
||||
public static void create(Bullet bullet, Color color, float damage, float x, float y, float targetAngle, int length){
|
||||
createLightingInternal(bullet, lastSeed++, bullet.team, color, damage, x, y, targetAngle, length);
|
||||
createLightningInternal(bullet, lastSeed++, bullet.team, color, damage, x, y, targetAngle, length);
|
||||
}
|
||||
|
||||
//TODO remote method
|
||||
//@Remote(called = Loc.server, unreliable = true)
|
||||
private static void createLightingInternal(Bullet hitter, int seed, Team team, Color color, float damage, float x, float y, float rotation, int length){
|
||||
private static void createLightningInternal(Bullet hitter, int seed, Team team, Color color, float damage, float x, float y, float rotation, int length){
|
||||
random.setSeed(seed);
|
||||
hit.clear();
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ public abstract class BulletType extends Content{
|
||||
//additional effects
|
||||
|
||||
public float fragCone = 360f;
|
||||
public float fragAngle = 0f;
|
||||
public int fragBullets = 9;
|
||||
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f, fragLifeMin = 1f, fragLifeMax = 1f;
|
||||
public BulletType fragBullet = null;
|
||||
@@ -101,6 +102,8 @@ public abstract class BulletType extends Content{
|
||||
public int lightningLength = 5, lightningLengthRand = 0;
|
||||
/** Use a negative value to use default bullet damage. */
|
||||
public float lightningDamage = -1;
|
||||
public float lightningCone = 360f;
|
||||
public float lightningAngle = 0f;
|
||||
|
||||
public float weaveScale = 1f;
|
||||
public float weaveMag = -1f;
|
||||
@@ -156,7 +159,7 @@ public abstract class BulletType extends Content{
|
||||
if(fragBullet != null){
|
||||
for(int i = 0; i < fragBullets; i++){
|
||||
float len = Mathf.random(1f, 7f);
|
||||
float a = b.rotation() + Mathf.range(fragCone/2);
|
||||
float a = b.rotation() + Mathf.range(fragCone/2) + fragAngle;
|
||||
fragBullet.create(b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax), Mathf.random(fragLifeMin, fragLifeMax));
|
||||
}
|
||||
}
|
||||
@@ -181,7 +184,7 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
for(int i = 0; i < lightning; i++){
|
||||
Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength + Mathf.random(lightningLengthRand));
|
||||
Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, b.rotation() + Mathf.range(lightningCone/2) + lightningAngle, lightningLength + Mathf.random(lightningLengthRand));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ public class HealBulletType extends BulletType{
|
||||
despawnEffect = Fx.hitLaser;
|
||||
collidesTeam = true;
|
||||
hittable = false;
|
||||
reflectable = false;
|
||||
}
|
||||
|
||||
public HealBulletType(){
|
||||
|
||||
@@ -71,7 +71,7 @@ abstract class BuilderComp implements Unitc{
|
||||
Tile tile = world.tile(current.x, current.y);
|
||||
|
||||
if(within(tile, finalPlaceDst)){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(tile), 0.4f);
|
||||
lookAt(angleTo(tile));
|
||||
}
|
||||
|
||||
if(!(tile.block() instanceof ConstructBlock)){
|
||||
|
||||
@@ -73,7 +73,7 @@ abstract class CommanderComp implements Unitc{
|
||||
void command(Formation formation, Seq<Unit> units){
|
||||
clearCommand();
|
||||
|
||||
float spacing = hitSize() * 1f;
|
||||
float spacing = hitSize() * 0.65f;
|
||||
minFormationSpeed = type().speed;
|
||||
|
||||
controlling.addAll(units);
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
@@ -90,7 +92,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
||||
//TODO is the netClient check necessary?
|
||||
if(drownTime >= 0.999f && !net.client()){
|
||||
kill();
|
||||
//TODO drown event!
|
||||
Events.fire(new UnitDrownEvent(self()));
|
||||
}
|
||||
}else{
|
||||
drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f);
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, ElevationMovec{
|
||||
@Import float x, y, hitSize;
|
||||
@Import UnitType type;
|
||||
|
||||
@SyncField(false) @SyncLocal float baseRotation;
|
||||
transient float walkTime, walkExtension;
|
||||
transient private boolean walked;
|
||||
@@ -21,6 +31,49 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati
|
||||
walkTime += len;
|
||||
walked = false;
|
||||
}
|
||||
|
||||
//update mech effects
|
||||
float extend = walkExtend(false);
|
||||
float base = walkExtend(true);
|
||||
float extendScl = base % 1f;
|
||||
|
||||
float lastExtend = walkExtension;
|
||||
|
||||
if(extendScl < lastExtend && base % 2f > 1f){
|
||||
int side = -Mathf.sign(extend);
|
||||
float width = hitSize / 2f * side, length = type.mechStride * 1.35f;
|
||||
|
||||
float cx = x + Angles.trnsx(baseRotation, length, width),
|
||||
cy = y + Angles.trnsy(baseRotation, length, width);
|
||||
|
||||
if(type.mechStepShake > 0){
|
||||
Effect.shake(type.mechStepShake, type.mechStepShake, cx, cy);
|
||||
}
|
||||
|
||||
if(type.mechStepParticles){
|
||||
Tile tile = world.tileWorld(cx, cy);
|
||||
if(tile != null){
|
||||
Color color = tile.floor().mapColor;
|
||||
Fx.unitLand.at(cx, cy, hitSize/8f, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walkExtension = extendScl;
|
||||
}
|
||||
|
||||
public float walkExtend(boolean scaled){
|
||||
|
||||
//now ranges from -maxExtension to maxExtension*3
|
||||
float raw = walkTime % (type.mechStride * 4);
|
||||
|
||||
if(scaled) return raw / type.mechStride;
|
||||
|
||||
if(raw > type.mechStride*3) raw = raw - type.mechStride * 4;
|
||||
else if(raw > type.mechStride*2) raw = type.mechStride * 2 - raw;
|
||||
else if(raw > type.mechStride) raw = type.mechStride * 2 - raw;
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -56,7 +56,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
||||
mineTimer = 0f;
|
||||
}else if(mining()){
|
||||
Item item = mineTile.drop();
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(mineTile.worldx(), mineTile.worldy()), 0.4f);
|
||||
lookAt(angleTo(mineTile.worldx(), mineTile.worldy()));
|
||||
mineTimer += Time.delta *type.mineSpeed;
|
||||
|
||||
if(Mathf.chance(0.06 * Time.delta)){
|
||||
|
||||
@@ -92,7 +92,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
|
||||
@Replace
|
||||
public float clipSize(){
|
||||
return unit.isNull() ? 20 : unit.type().hitsize * 2f;
|
||||
return unit.isNull() ? 20 : unit.type().hitSize * 2f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -30,9 +30,8 @@ import static mindustry.Vars.*;
|
||||
@Component(base = true)
|
||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable{
|
||||
|
||||
@Import boolean hovering;
|
||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health;
|
||||
@Import boolean dead;
|
||||
@Import boolean hovering, dead;
|
||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo;
|
||||
@Import Team team;
|
||||
@Import int id;
|
||||
|
||||
@@ -41,6 +40,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
boolean spawnedByCore;
|
||||
|
||||
transient Seq<Ability> abilities = new Seq<>(0);
|
||||
private transient float resupplyTime = Mathf.random(10f);
|
||||
|
||||
public void moveAt(Vec2 vector){
|
||||
moveAt(vector, type.accel);
|
||||
@@ -191,7 +191,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
this.maxHealth = type.health;
|
||||
this.drag = type.drag;
|
||||
this.armor = type.armor;
|
||||
this.hitSize = type.hitsize;
|
||||
this.hitSize = type.hitSize;
|
||||
this.hovering = type.hovering;
|
||||
|
||||
if(controller == null) controller(type.createController());
|
||||
@@ -245,6 +245,16 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
type.update(self());
|
||||
|
||||
if(state.rules.unitAmmo && ammo < type.ammoCapacity - 0.0001f){
|
||||
resupplyTime += Time.delta;
|
||||
|
||||
//resupply only at a fixed interval to prevent lag
|
||||
if(resupplyTime > 10f){
|
||||
type.ammoType.resupply(self());
|
||||
resupplyTime = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if(abilities.size > 0){
|
||||
for(Ability a : abilities){
|
||||
a.update(self());
|
||||
@@ -366,7 +376,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
if(!headless){
|
||||
for(int i = 0; i < type.wreckRegions.length; i++){
|
||||
if(type.wreckRegions[i].found()){
|
||||
float range = type.hitsize/4f;
|
||||
float range = type.hitSize /4f;
|
||||
Tmp.v1.rnd(range);
|
||||
Effect.decal(type.wreckRegions[i], x + Tmp.v1.x, y + Tmp.v1.y, rotation - 90);
|
||||
}
|
||||
|
||||
@@ -18,8 +18,6 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
|
||||
@Import Vec2 vel;
|
||||
@Import UnitType type;
|
||||
|
||||
/** minimum cursor distance from unit, fixes 'cross-eyed' shooting */
|
||||
static final float minAimDst = 18f;
|
||||
/** temporary weapon sequence number */
|
||||
static int sequenceNum = 0;
|
||||
|
||||
@@ -67,7 +65,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
|
||||
/** Aim at something. This will make all mounts point at it. */
|
||||
void aim(float x, float y){
|
||||
Tmp.v1.set(x, y).sub(this.x, this.y);
|
||||
if(Tmp.v1.len() < minAimDst) Tmp.v1.setLength(minAimDst);
|
||||
if(Tmp.v1.len() < type.aimDst) Tmp.v1.setLength(type.aimDst);
|
||||
|
||||
x = Tmp.v1.x + this.x;
|
||||
y = Tmp.v1.y + this.y;
|
||||
|
||||
@@ -1,47 +1,51 @@
|
||||
package mindustry.game;
|
||||
|
||||
import arc.struct.Seq;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.type.ItemStack;
|
||||
import mindustry.type.*;
|
||||
|
||||
import static mindustry.content.UnitTypes.*;
|
||||
|
||||
public class DefaultWaves{
|
||||
private Seq<SpawnGroup> spawns;
|
||||
|
||||
public Seq<SpawnGroup> get(){
|
||||
if(spawns == null && UnitTypes.dagger != null){
|
||||
if(spawns == null && dagger != null){
|
||||
spawns = Seq.with(
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
end = 10;
|
||||
unitScaling = 2f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
new SpawnGroup(crawler){{
|
||||
begin = 4;
|
||||
end = 13;
|
||||
unitAmount = 2;
|
||||
unitScaling = 1.5f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.flare){{
|
||||
new SpawnGroup(flare){{
|
||||
begin = 12;
|
||||
end = 16;
|
||||
unitScaling = 1f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
begin = 11;
|
||||
unitScaling = 1.7f;
|
||||
spacing = 2;
|
||||
max = 4;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.pulsar){{
|
||||
new SpawnGroup(pulsar){{
|
||||
begin = 13;
|
||||
spacing = 3;
|
||||
unitScaling = 0.5f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.mace){{
|
||||
new SpawnGroup(mace){{
|
||||
begin = 7;
|
||||
spacing = 3;
|
||||
unitScaling = 2;
|
||||
@@ -49,28 +53,28 @@ public class DefaultWaves{
|
||||
end = 30;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
begin = 8;
|
||||
unitScaling = 1;
|
||||
unitAmount = 4;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.mace){{
|
||||
new SpawnGroup(mace){{
|
||||
begin = 28;
|
||||
spacing = 3;
|
||||
unitScaling = 1;
|
||||
end = 40;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.mace){{
|
||||
new SpawnGroup(mace){{
|
||||
begin = 45;
|
||||
spacing = 3;
|
||||
unitScaling = 2;
|
||||
effect = StatusEffects.overdrive;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.mace){{
|
||||
new SpawnGroup(mace){{
|
||||
begin = 120;
|
||||
spacing = 2;
|
||||
unitScaling = 3;
|
||||
@@ -78,13 +82,13 @@ public class DefaultWaves{
|
||||
effect = StatusEffects.overdrive;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.flare){{
|
||||
new SpawnGroup(flare){{
|
||||
begin = 16;
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
begin = 82;
|
||||
spacing = 3;
|
||||
unitAmount = 4;
|
||||
@@ -92,7 +96,7 @@ public class DefaultWaves{
|
||||
effect = StatusEffects.overdrive;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
begin = 41;
|
||||
spacing = 5;
|
||||
unitAmount = 1;
|
||||
@@ -100,7 +104,7 @@ public class DefaultWaves{
|
||||
effect = StatusEffects.shielded;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.fortress){{
|
||||
new SpawnGroup(fortress){{
|
||||
begin = 40;
|
||||
spacing = 5;
|
||||
unitAmount = 2;
|
||||
@@ -108,7 +112,7 @@ public class DefaultWaves{
|
||||
max = 20;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
begin = 35;
|
||||
spacing = 3;
|
||||
unitAmount = 4;
|
||||
@@ -117,7 +121,7 @@ public class DefaultWaves{
|
||||
end = 60;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
new SpawnGroup(dagger){{
|
||||
begin = 42;
|
||||
spacing = 3;
|
||||
unitAmount = 4;
|
||||
@@ -126,14 +130,14 @@ public class DefaultWaves{
|
||||
end = 130;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.horizon){{
|
||||
new SpawnGroup(horizon){{
|
||||
begin = 40;
|
||||
unitAmount = 2;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.flare){{
|
||||
new SpawnGroup(flare){{
|
||||
begin = 50;
|
||||
unitAmount = 4;
|
||||
unitScaling = 3;
|
||||
@@ -141,7 +145,7 @@ public class DefaultWaves{
|
||||
effect = StatusEffects.overdrive;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.zenith){{
|
||||
new SpawnGroup(zenith){{
|
||||
begin = 50;
|
||||
unitAmount = 2;
|
||||
unitScaling = 3;
|
||||
@@ -149,42 +153,42 @@ public class DefaultWaves{
|
||||
max = 16;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.horizon){{
|
||||
new SpawnGroup(horizon){{
|
||||
begin = 53;
|
||||
unitAmount = 2;
|
||||
unitScaling = 3;
|
||||
spacing = 4;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.atrax){{
|
||||
new SpawnGroup(atrax){{
|
||||
begin = 31;
|
||||
unitAmount = 4;
|
||||
unitScaling = 1;
|
||||
spacing = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.scepter){{
|
||||
new SpawnGroup(scepter){{
|
||||
begin = 41;
|
||||
unitAmount = 1;
|
||||
unitScaling = 1;
|
||||
spacing = 30;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.reign){{
|
||||
new SpawnGroup(reign){{
|
||||
begin = 81;
|
||||
unitAmount = 1;
|
||||
unitScaling = 1;
|
||||
spacing = 40;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.antumbra){{
|
||||
new SpawnGroup(antumbra){{
|
||||
begin = 131;
|
||||
unitAmount = 1;
|
||||
unitScaling = 1;
|
||||
spacing = 40;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.horizon){{
|
||||
new SpawnGroup(horizon){{
|
||||
begin = 90;
|
||||
unitAmount = 2;
|
||||
unitScaling = 3;
|
||||
@@ -194,4 +198,76 @@ public class DefaultWaves{
|
||||
}
|
||||
return spawns == null ? new Seq<>() : spawns;
|
||||
}
|
||||
|
||||
//TODO move elsewhere
|
||||
public static Seq<SpawnGroup> generate(){
|
||||
UnitType[][] species = {
|
||||
{dagger, mace, fortress, scepter, reign},
|
||||
{nova, pulsar, quasar, vela, corvus},
|
||||
{crawler, atrax, spiroct, arkyid, toxopid},
|
||||
//{risso, minke, bryde, sei, omura}, //questionable choices
|
||||
//{mono, poly, mega, quad, oct}, //do not attack
|
||||
{flare, horizon, zenith, antumbra, eclipse}
|
||||
};
|
||||
|
||||
//required progression:
|
||||
//- extra periodic patterns
|
||||
|
||||
Seq<SpawnGroup> out = new Seq<>();
|
||||
|
||||
//max reasonable wave, after which everything gets boring
|
||||
int cap = 400;
|
||||
|
||||
//main sequence
|
||||
float shieldStart = 30, shieldsPerWave = 12;
|
||||
UnitType[] curSpecies = Structs.random(species);
|
||||
int curTier = 0;
|
||||
|
||||
for(int i = 0; i < cap;){
|
||||
int f = i;
|
||||
int next = Mathf.random(15, 25);
|
||||
|
||||
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
|
||||
|
||||
//main progression
|
||||
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
||||
unitAmount = f == 0 ? 1 : 10;
|
||||
begin = f;
|
||||
end = f + next >= cap ? never : f + next;
|
||||
max = 16;
|
||||
unitScaling = Mathf.random(1f, 2f);
|
||||
shields = shieldAmount;
|
||||
shieldScaling = shieldsPerWave;
|
||||
}});
|
||||
|
||||
//extra progression that tails out, blends in
|
||||
out.add(new SpawnGroup(curSpecies[Math.min(curTier, curSpecies.length - 1)]){{
|
||||
unitAmount = 6;
|
||||
begin = f + next;
|
||||
end = f + next + Mathf.random(8, 12);
|
||||
max = 10;
|
||||
unitScaling = Mathf.random(2f);
|
||||
spacing = Mathf.random(2, 3);
|
||||
shields = shieldAmount;
|
||||
shieldScaling = shieldsPerWave;
|
||||
}});
|
||||
|
||||
i += next;
|
||||
if(curTier < 3 || Mathf.chance(0.2)){
|
||||
curTier ++;
|
||||
}
|
||||
|
||||
//do not spawn bosses
|
||||
curTier = Math.min(curTier, 3);
|
||||
|
||||
//small chance to switch species
|
||||
if(Mathf.chance(0.2)){
|
||||
curSpecies = Structs.random(species);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ public class EventType{
|
||||
|
||||
public static class WinEvent{}
|
||||
public static class LoseEvent{}
|
||||
public static class LaunchEvent{}
|
||||
public static class ResizeEvent{}
|
||||
public static class MapMakeEvent{}
|
||||
public static class MapPublishEvent{}
|
||||
@@ -271,6 +270,14 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnitDrownEvent{
|
||||
public final Unit unit;
|
||||
|
||||
public UnitDrownEvent(Unit unit){
|
||||
this.unit = unit;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnitCreateEvent{
|
||||
public final Unit unit;
|
||||
|
||||
|
||||
@@ -68,8 +68,6 @@ public class Rules{
|
||||
public float dropZoneRadius = 300f;
|
||||
/** Time between waves in ticks. */
|
||||
public float waveSpacing = 60 * 60 * 2;
|
||||
/** How many times longer a launch wave takes. */
|
||||
public float launchWaveMultiplier = 2f;
|
||||
/** Wave after which the player 'wins'. Used in sectors. Use a value <= 0 to disable. */
|
||||
public int winWave = 0;
|
||||
/** Base unit cap. Can still be increased by blocks. */
|
||||
|
||||
@@ -22,6 +22,7 @@ public class Stats{
|
||||
/** Friendly buildings destroyed. */
|
||||
public int buildingsDestroyed;
|
||||
|
||||
//TODO fix
|
||||
public RankResult calculateRank(Sector zone, boolean launched){
|
||||
float score = 0;
|
||||
|
||||
|
||||
@@ -84,6 +84,18 @@ public class Drawf{
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public static void shadow(TextureRegion region, float x, float y, float rotation){
|
||||
Draw.color(Pal.shadow);
|
||||
Draw.rect(region, x, y, rotation);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public static void shadow(TextureRegion region, float x, float y){
|
||||
Draw.color(Pal.shadow);
|
||||
Draw.rect(region, x, y);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public static void dashCircle(float x, float y, float rad, Color color){
|
||||
Lines.stroke(3f, Pal.gray);
|
||||
Lines.dashCircle(x, y, rad);
|
||||
|
||||
@@ -228,7 +228,7 @@ public class FloorRenderer implements Disposable{
|
||||
int chunksx = Mathf.ceil((float)(world.width()) / chunksize),
|
||||
chunksy = Mathf.ceil((float)(world.height()) / chunksize);
|
||||
cache = new Chunk[chunksx][chunksy];
|
||||
cbatch = new MultiCacheBatch(chunksize * chunksize * 7);
|
||||
cbatch = new MultiCacheBatch(chunksize * chunksize * 8);
|
||||
|
||||
Time.mark();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import arc.util.*;
|
||||
public class IndexedRenderer implements Disposable{
|
||||
private static final int vsize = 5;
|
||||
|
||||
private Shader program = new Shader(
|
||||
private final Shader program = new Shader(
|
||||
"attribute vec4 a_position;\n" +
|
||||
"attribute vec4 a_color;\n" +
|
||||
"attribute vec2 a_texCoord0;\n" +
|
||||
|
||||
@@ -122,7 +122,7 @@ public class MinimapRenderer implements Disposable{
|
||||
float dy = (Core.camera.position.y / tilesize);
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
float invTexWidth = 1f / texture.getWidth();
|
||||
float invTexWidth = 1f / texture.width;
|
||||
float invTexHeight = 1f / texture.height;
|
||||
float x = dx - sz, y = world.height() - dy - sz, width = sz * 2, height = sz * 2;
|
||||
region.set(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight);
|
||||
|
||||
@@ -47,6 +47,7 @@ public class Pal{
|
||||
darkishGray = new Color(0.3f, 0.3f, 0.3f, 1f),
|
||||
darkerGray = new Color(0.2f, 0.2f, 0.2f, 1f),
|
||||
darkestGray = new Color(0.1f, 0.1f, 0.1f, 1f),
|
||||
shadow = new Color(0, 0, 0, 0.22f),
|
||||
ammo = Color.valueOf("ff8947"),
|
||||
rubble = Color.valueOf("1c1817"),
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public class Shaders{
|
||||
setUniformf("u_progress", progress);
|
||||
setUniformf("u_uv", region.u, region.v);
|
||||
setUniformf("u_uv2", region.u2, region.v2);
|
||||
setUniformf("u_texsize", region.texture.getWidth(), region.texture.height);
|
||||
setUniformf("u_texsize", region.texture.width, region.texture.height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ public class Shaders{
|
||||
setUniformf("u_uv", region.u, region.v);
|
||||
setUniformf("u_uv2", region.u2, region.v2);
|
||||
setUniformf("u_time", Time.time());
|
||||
setUniformf("u_texsize", region.texture.getWidth(), region.texture.height);
|
||||
setUniformf("u_texsize", region.texture.width, region.texture.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@ import arc.graphics.*;
|
||||
import arc.graphics.VertexAttributes.*;
|
||||
import arc.graphics.gl.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.graphics.g3d.PlanetGrid.*;
|
||||
|
||||
public class MeshBuilder{
|
||||
private static final Vec3 v1 = new Vec3(), v2 = new Vec3(), v3 = new Vec3();
|
||||
private static final Vec3 v1 = new Vec3(), v2 = new Vec3(), v3 = new Vec3(), v4 = new Vec3();
|
||||
private static final float[] floats = new float[3 + 3 + 1];
|
||||
private static Mesh mesh;
|
||||
|
||||
@@ -111,7 +110,7 @@ public class MeshBuilder{
|
||||
}
|
||||
|
||||
private static Vec3 normal(Vec3 v1, Vec3 v2, Vec3 v3){
|
||||
return Tmp.v32.set(v2).sub(v1).crs(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z).nor();
|
||||
return v4.set(v2).sub(v1).crs(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z).nor();
|
||||
}
|
||||
|
||||
private static void verts(Vec3 a, Vec3 b, Vec3 c, Vec3 normal, Color color){
|
||||
|
||||
@@ -113,7 +113,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
Payloadc pay = (Payloadc)unit;
|
||||
|
||||
if(target.isAI() && target.isGrounded() && pay.canPickup(target)
|
||||
&& target.within(unit, unit.type().hitsize * 2f + target.type().hitsize * 2f)){
|
||||
&& target.within(unit, unit.type().hitSize * 2f + target.type().hitSize * 2f)){
|
||||
Call.pickedUnitPayload(player, target);
|
||||
}
|
||||
}
|
||||
@@ -395,7 +395,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
if(!(unit instanceof Payloadc)) return;
|
||||
Payloadc pay = (Payloadc)unit;
|
||||
|
||||
Unit target = Units.closest(player.team(), pay.x(), pay.y(), unit.type().hitsize * 2.5f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
|
||||
Unit target = Units.closest(player.team(), pay.x(), pay.y(), unit.type().hitSize * 2.5f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
|
||||
if(target != null){
|
||||
Call.requestUnitPayload(player, target);
|
||||
}else{
|
||||
|
||||
@@ -6,7 +6,8 @@ public enum ConditionOp{
|
||||
lessThan("<", (a, b) -> a < b),
|
||||
lessThanEq("<=", (a, b) -> a <= b),
|
||||
greaterThan(">", (a, b) -> a > b),
|
||||
greaterThanEq(">=", (a, b) -> a >= b);
|
||||
greaterThanEq(">=", (a, b) -> a >= b),
|
||||
always("always", (a, b) -> true);
|
||||
|
||||
public static final ConditionOp[] all = values();
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mindustry.logic;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
@@ -633,6 +634,8 @@ public class LStatements{
|
||||
|
||||
@RegisterStatement("jump")
|
||||
public static class JumpStatement extends LStatement{
|
||||
private static Color last = new Color();
|
||||
|
||||
public transient StatementElem dest;
|
||||
|
||||
public int destIndex;
|
||||
@@ -644,19 +647,30 @@ public class LStatements{
|
||||
public void build(Table table){
|
||||
table.add("if ").padLeft(4);
|
||||
|
||||
field(table, value, str -> value = str);
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> op.symbol);
|
||||
b.clicked(() -> showSelect(b, ConditionOp.all, op, o -> op = o));
|
||||
}, Styles.logict, () -> {}).size(48f, 40f).pad(4f).color(table.color);
|
||||
|
||||
field(table, compare, str -> compare = str);
|
||||
last = table.color;
|
||||
table.table(this::rebuild);
|
||||
|
||||
table.add().growX();
|
||||
table.add(new JumpButton(() -> dest, s -> dest = s)).size(30).right().padLeft(-8);
|
||||
}
|
||||
|
||||
void rebuild(Table table){
|
||||
table.clearChildren();
|
||||
table.setColor(last);
|
||||
|
||||
if(op != ConditionOp.always) field(table, value, str -> value = str);
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> op.symbol);
|
||||
b.clicked(() -> showSelect(b, ConditionOp.all, op, o -> {
|
||||
op = o;
|
||||
rebuild(table);
|
||||
}));
|
||||
}, Styles.logict, () -> {}).size(op == ConditionOp.always ? 80f : 48f, 40f).pad(4f).color(table.color);
|
||||
|
||||
if(op != ConditionOp.always) field(table, compare, str -> compare = str);
|
||||
}
|
||||
|
||||
//elements need separate conversion logic
|
||||
@Override
|
||||
public void setupUI(){
|
||||
|
||||
@@ -6,6 +6,8 @@ import mindustry.gen.*;
|
||||
public enum RadarSort{
|
||||
distance((pos, other) -> -pos.dst2(other)),
|
||||
health((pos, other) -> other.health()),
|
||||
shield((pos, other) -> other.shield()),
|
||||
armor((pos, other) -> other.armor()),
|
||||
maxHealth((pos, other) -> other.maxHealth());
|
||||
|
||||
public final RadarSortFunc func;
|
||||
@@ -17,6 +19,6 @@ public enum RadarSort{
|
||||
}
|
||||
|
||||
public interface RadarSortFunc{
|
||||
float get(Position pos, Healthc other);
|
||||
float get(Position pos, Unit other);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ public enum RadarTarget{
|
||||
enemy((team, other) -> team != other.team),
|
||||
ally((team, other) -> team == other.team),
|
||||
player((team, other) -> other.isPlayer()),
|
||||
attacker((pos, other) -> other.canShoot()),
|
||||
flying((team, other) -> other.isFlying()),
|
||||
boss((team, other) -> other.isBoss()),
|
||||
ground((team, other) -> other.isGrounded());
|
||||
|
||||
public final RadarTargetFunc func;
|
||||
|
||||
@@ -25,7 +25,6 @@ import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -634,12 +633,11 @@ public class Mods implements Loadable{
|
||||
//make sure the main class exists before loading it; if it doesn't just don't put it there
|
||||
if(mainFile.exists()){
|
||||
//mobile versions don't support class mods
|
||||
if(mobile){
|
||||
throw new IllegalArgumentException("Java class mods are not supported on mobile.");
|
||||
if(ios){
|
||||
throw new IllegalArgumentException("Java class mods are not supported on iOS.");
|
||||
}
|
||||
|
||||
URLClassLoader classLoader = new URLClassLoader(new URL[]{sourceFile.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
||||
Class<?> main = classLoader.loadClass(mainClass);
|
||||
Class<?> main = platform.loadJar(sourceFile, mainClass);
|
||||
metas.put(main, meta);
|
||||
mainMod = (Mod)main.getDeclaredConstructor().newInstance();
|
||||
}else{
|
||||
|
||||
@@ -24,6 +24,7 @@ public class Administration{
|
||||
public Seq<ChatFilter> chatFilters = new Seq<>();
|
||||
public Seq<ActionFilter> actionFilters = new Seq<>();
|
||||
public Seq<String> subnetBans = new Seq<>();
|
||||
public ObjectMap<String, Long> kickedIPs = new ObjectMap<>();
|
||||
|
||||
/** All player info. Maps UUIDs to info. This persists throughout restarts. Do not access directly. */
|
||||
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
||||
@@ -86,6 +87,20 @@ public class Administration{
|
||||
});
|
||||
}
|
||||
|
||||
/** @return time at which a player would be pardoned for a kick (0 means they were never kicked) */
|
||||
public long getKickTime(String uuid, String ip){
|
||||
return Math.max(getInfo(uuid).lastKicked, kickedIPs.get(ip, 0L));
|
||||
}
|
||||
|
||||
/** Sets up kick duration for a player. */
|
||||
public void handleKicked(String uuid, String ip, long duration){
|
||||
kickedIPs.put(ip, Math.max(kickedIPs.get(ip, 0L), Time.millis() + duration));
|
||||
|
||||
PlayerInfo info = getInfo(uuid);
|
||||
info.timesKicked++;
|
||||
info.lastKicked = Math.max(Time.millis() + duration, info.lastKicked);
|
||||
}
|
||||
|
||||
public Seq<String> getSubnetBans(){
|
||||
return subnetBans;
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ public class CrashSender{
|
||||
public static String createReport(String error){
|
||||
String report = "Oh no, Mindustry crashed!\n";
|
||||
if(mods.list().size == 0){
|
||||
report += "Please report this at https://github.com/Anuken/Mindustry/issues/new?labels=bug&template=bug_report.md\n\n";
|
||||
report += "Please report this at " + Vars.reportIssueURL + "\n\n";
|
||||
}
|
||||
return report + "Version: " + Version.combined() + (Vars.headless ? " (Server)" : "") + "\n"
|
||||
+ "OS: " + System.getProperty("os.name") + " x" + (OS.is64Bit ? "64" : "32") + "\n"
|
||||
+ "Java Version: " + System.getProperty("java.version") + "\n"
|
||||
+ "Java Architecture: " + System.getProperty("sun.arch.data.model") + "\n"
|
||||
+ mods.list().size + " Mods: " + mods.list().toString(", ", mod -> mod.name + ":" + mod.meta.version)
|
||||
+ mods.list().size + " Mods: " + (mods.list().isEmpty() ? "none" : mods.list().toString(", ", mod -> mod.name + ":" + mod.meta.version))
|
||||
+ "\n\n" + error;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,9 +65,7 @@ public abstract class NetConnection{
|
||||
|
||||
Log.info("Kicking connection @; Reason: @", address, reason.replace("\n", " "));
|
||||
|
||||
PlayerInfo info = netServer.admins.getInfo(uuid);
|
||||
info.timesKicked++;
|
||||
info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked);
|
||||
netServer.admins.handleKicked(uuid, address, kickDuration);
|
||||
|
||||
Call.kick(this, reason);
|
||||
|
||||
|
||||
28
core/src/mindustry/type/AmmoType.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package mindustry.type;
|
||||
|
||||
import arc.graphics.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
/** Type of ammo that a unit uses. */
|
||||
public class AmmoType extends Content{
|
||||
public String icon = Iconc.itemCopper + "";
|
||||
public Color color = Pal.ammo;
|
||||
public Color barColor = Pal.ammo;
|
||||
|
||||
public AmmoType(char icon, Color color){
|
||||
this.icon = icon + "";
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public AmmoType(){
|
||||
}
|
||||
|
||||
public void resupply(Unit unit){}
|
||||
|
||||
@Override
|
||||
public ContentType getContentType(){
|
||||
return ContentType.ammo;
|
||||
}
|
||||
}
|
||||
86
core/src/mindustry/type/AmmoTypes.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package mindustry.type;
|
||||
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
public class AmmoTypes implements ContentList{
|
||||
public static AmmoType
|
||||
powerLow,
|
||||
power,
|
||||
powerHigh,
|
||||
copper,
|
||||
thorium;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
powerLow = new PowerAmmoType(500);
|
||||
power = new PowerAmmoType(1000);
|
||||
powerHigh = new PowerAmmoType(2000);
|
||||
copper = new ItemAmmoType(Items.copper);
|
||||
thorium = new ItemAmmoType(Items.thorium);
|
||||
}
|
||||
|
||||
public static class PowerAmmoType extends AmmoType{
|
||||
public float totalPower = 1000;
|
||||
|
||||
public PowerAmmoType(){
|
||||
super(Iconc.power, Pal.powerLight);
|
||||
barColor = color;
|
||||
}
|
||||
|
||||
public PowerAmmoType(float totalPower){
|
||||
this();
|
||||
this.totalPower = totalPower;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resupply(Unit unit){
|
||||
float range = unit.hitSize + 60f;
|
||||
Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.powerResupply);
|
||||
|
||||
if(closest != null && closest.build != null && unit.within(closest.build, range) && closest.build.power != null){
|
||||
Building build = closest.build;
|
||||
|
||||
if(build.block.consumes.hasPower() && build.block.consumes.getPower().buffered){
|
||||
float amount = closest.build.power.status * build.block.consumes.getPower().capacity;
|
||||
float powerPerAmmo = totalPower / unit.type().ammoCapacity;
|
||||
float ammoRequired = unit.type().ammoCapacity - unit.ammo;
|
||||
float powerRequired = ammoRequired * powerPerAmmo;
|
||||
float powerTaken = Math.min(amount, powerRequired);
|
||||
|
||||
if(powerTaken > 1){
|
||||
closest.build.power.status -= powerTaken / build.block.consumes.getPower().capacity;
|
||||
unit.ammo += powerTaken / powerPerAmmo;
|
||||
|
||||
Fx.itemTransfer.at(build.x, build.y, Math.max(powerTaken / 100f, 1f), Pal.power, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemAmmoType extends AmmoType{
|
||||
public @NonNull Item item;
|
||||
|
||||
public ItemAmmoType(Item item){
|
||||
this.item = item;
|
||||
this.color = item.color;
|
||||
}
|
||||
|
||||
public ItemAmmoType(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
if(item != null){
|
||||
icon = item.emoji();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,9 +31,6 @@ public class Sector{
|
||||
public float baseCoverage;
|
||||
public boolean generateEnemyBase;
|
||||
|
||||
//TODO implement a dynamic launch period
|
||||
public int launchPeriod = 10;
|
||||
|
||||
public Sector(Planet planet, Ptile tile){
|
||||
this.planet = planet;
|
||||
this.tile = tile;
|
||||
@@ -100,7 +97,7 @@ public class Sector{
|
||||
|
||||
public boolean isBeingPlayed(){
|
||||
//after the launch dialog, a sector is no longer considered being played
|
||||
return Vars.state.isGame() && Vars.state.rules.sector == this && !Vars.state.launched && !Vars.state.gameOver;
|
||||
return Vars.state.isGame() && Vars.state.rules.sector == this && !Vars.state.gameOver;
|
||||
}
|
||||
|
||||
public boolean isCaptured(){
|
||||
@@ -134,16 +131,6 @@ public class Sector{
|
||||
return res % 2 == 0 ? res : res + 1;
|
||||
}
|
||||
|
||||
//TODO implement
|
||||
public boolean isLaunchWave(int wave){
|
||||
return metCondition() && wave % launchPeriod == 0;
|
||||
}
|
||||
|
||||
public boolean metCondition(){
|
||||
//TODO implement
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO this should be stored in a more efficient structure, and be updated each turn
|
||||
public ItemSeq getExtraItems(){
|
||||
return Core.settings.getJson(key("extra-items"), ItemSeq.class, ItemSeq::new);
|
||||
|
||||
@@ -56,7 +56,7 @@ public class StatusEffect extends MappableContent{
|
||||
}
|
||||
|
||||
if(effect != Fx.none && Mathf.chanceDelta(effectChance)){
|
||||
Tmp.v1.rnd(unit.type().hitsize/2f);
|
||||
Tmp.v1.rnd(unit.type().hitSize /2f);
|
||||
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ import mindustry.world.consumers.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class UnitType extends UnlockableContent{
|
||||
public static final float shadowTX = -12, shadowTY = -13, shadowColor = Color.toFloatBits(0, 0, 0, 0.22f), outlineSpace = 0.01f;
|
||||
public static final float shadowTX = -12, shadowTY = -13, outlineSpace = 0.01f;
|
||||
private static final Vec2 legOffset = new Vec2();
|
||||
|
||||
/** If true, the unit is always at elevation 1. */
|
||||
@@ -51,6 +51,7 @@ public class UnitType extends UnlockableContent{
|
||||
public boolean destructibleWreck = true;
|
||||
public float groundLayer = Layer.groundUnit;
|
||||
public float payloadCapacity = 8;
|
||||
public float aimDst = -1f;
|
||||
public int commandLimit = 24;
|
||||
public float visualElevation = -1f;
|
||||
public boolean allowLegStep = false;
|
||||
@@ -72,7 +73,8 @@ public class UnitType extends UnlockableContent{
|
||||
public Color mechLegColor = Pal.darkMetal;
|
||||
|
||||
public int itemCapacity = -1;
|
||||
public int ammoCapacity = 220;
|
||||
public int ammoCapacity = -1;
|
||||
public AmmoType ammoType = AmmoTypes.copper;
|
||||
public int mineTier = -1;
|
||||
public float buildSpeed = 1f, mineSpeed = 1f;
|
||||
|
||||
@@ -80,7 +82,7 @@ public class UnitType extends UnlockableContent{
|
||||
public boolean canDrown = true;
|
||||
public float engineOffset = 5f, engineSize = 2.5f;
|
||||
public float strafePenalty = 0.5f;
|
||||
public float hitsize = 6f;
|
||||
public float hitSize = 6f;
|
||||
public float itemOffsetY = 3f;
|
||||
public float lightRadius = 60f, lightOpacity = 0.6f;
|
||||
public Color lightColor = Pal.powerLight;
|
||||
@@ -136,41 +138,6 @@ public class UnitType extends UnlockableContent{
|
||||
|
||||
public void update(Unit unit){
|
||||
|
||||
if(unit instanceof Mechc && !unit.isFlying()){
|
||||
updateMechEffects(unit);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateMechEffects(Unit unit){
|
||||
Mechc mech = (Mechc)unit;
|
||||
|
||||
float extend = walkExtend((Mechc)unit, false);
|
||||
float base = walkExtend((Mechc)unit, true);
|
||||
float extendScl = base % 1f;
|
||||
|
||||
float lastExtend = mech.walkExtension();
|
||||
|
||||
if(extendScl < lastExtend && base % 2f > 1f){
|
||||
int side = -Mathf.sign(extend);
|
||||
float width = hitsize / 2f * side, length = mechStride * 1.35f;
|
||||
|
||||
float cx = unit.x + Angles.trnsx(mech.baseRotation(), length, width),
|
||||
cy = unit.y + Angles.trnsy(mech.baseRotation(), length, width);
|
||||
|
||||
if(mechStepShake > 0){
|
||||
Effect.shake(mechStepShake, mechStepShake, cx, cy);
|
||||
}
|
||||
|
||||
if(mechStepParticles){
|
||||
Tile tile = world.tileWorld(cx, cy);
|
||||
if(tile != null){
|
||||
Color color = tile.floor().mapColor;
|
||||
Fx.unitLand.at(cx, cy, hitsize/8f, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mech.walkExtension(extendScl);
|
||||
}
|
||||
|
||||
public void landed(Unit unit){}
|
||||
@@ -184,13 +151,13 @@ public class UnitType extends UnlockableContent{
|
||||
table.row();
|
||||
|
||||
table.table(bars -> {
|
||||
bars.defaults().growX().height(18f).pad(4);
|
||||
bars.defaults().growX().height(20f).pad(4);
|
||||
|
||||
bars.add(new Bar("blocks.health", Pal.health, unit::healthf).blink(Color.white));
|
||||
bars.row();
|
||||
|
||||
if(state.rules.unitAmmo){
|
||||
bars.add(new Bar("blocks.ammo", Pal.ammo, () -> unit.ammo / ammoCapacity));
|
||||
bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("blocks.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity));
|
||||
bars.row();
|
||||
}
|
||||
}).growX();
|
||||
@@ -237,24 +204,28 @@ public class UnitType extends UnlockableContent{
|
||||
singleTarget = weapons.size <= 1;
|
||||
|
||||
if(itemCapacity < 0){
|
||||
itemCapacity = Math.max(Mathf.round(hitsize * 7, 20), 20);
|
||||
itemCapacity = Math.max(Mathf.round(hitSize * 7, 20), 20);
|
||||
}
|
||||
|
||||
//set up default range
|
||||
if(range < 0){
|
||||
range = Float.MAX_VALUE;
|
||||
for(Weapon weapon : weapons){
|
||||
range = Math.min(range, weapon.bullet.range() + hitsize/2f);
|
||||
range = Math.min(range, weapon.bullet.range() + hitSize /2f);
|
||||
}
|
||||
}
|
||||
|
||||
if(mechStride < 0){
|
||||
mechStride = 4f + (hitsize-8f)/2.1f;
|
||||
mechStride = 4f + (hitSize -8f)/2.1f;
|
||||
}
|
||||
|
||||
if(aimDst < 0){
|
||||
aimDst = weapons.contains(w -> !w.rotate) ? hitSize * 2f : hitSize / 2f;
|
||||
}
|
||||
|
||||
if(mechStepShake < 0){
|
||||
mechStepShake = Mathf.round((hitsize - 11f) / 9f);
|
||||
mechStepParticles = hitsize > 15f;
|
||||
mechStepShake = Mathf.round((hitSize - 11f) / 9f);
|
||||
mechStepParticles = hitSize > 15f;
|
||||
}
|
||||
|
||||
canHeal = weapons.contains(w -> w.bullet instanceof HealBulletType);
|
||||
@@ -281,6 +252,15 @@ public class UnitType extends UnlockableContent{
|
||||
}
|
||||
}
|
||||
this.weapons = mapped;
|
||||
|
||||
//dynamically create ammo capacity based on firing rate
|
||||
if(ammoCapacity < 0){
|
||||
float shotsPerSecond = weapons.sumf(w -> 60f / w.reload);
|
||||
//duration of continuous fire without reload
|
||||
float targetSeconds = 30;
|
||||
|
||||
ammoCapacity = Math.max(1, (int)(shotsPerSecond * targetSeconds));
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
@@ -342,7 +322,7 @@ public class UnitType extends UnlockableContent{
|
||||
|
||||
public void draw(Unit unit){
|
||||
Mechc mech = unit instanceof Mechc ? (Mechc)unit : null;
|
||||
float z = unit.elevation > 0.5f ? (lowAltitude ? Layer.flyingUnitLow : Layer.flyingUnit) : groundLayer + Mathf.clamp(hitsize/4000f, 0, 0.01f);
|
||||
float z = unit.elevation > 0.5f ? (lowAltitude ? Layer.flyingUnitLow : Layer.flyingUnit) : groundLayer + Mathf.clamp(hitSize / 4000f, 0, 0.01f);
|
||||
|
||||
if(unit.controller().isBeingControlled(player.unit())){
|
||||
drawControl(unit);
|
||||
@@ -359,10 +339,10 @@ public class UnitType extends UnlockableContent{
|
||||
drawMech(mech);
|
||||
|
||||
//side
|
||||
legOffset.trns(mech.baseRotation(), 0f, Mathf.lerp(Mathf.sin(walkExtend(mech, true), 2f/Mathf.PI, 1) * mechSideSway, 0f, unit.elevation));
|
||||
legOffset.trns(mech.baseRotation(), 0f, Mathf.lerp(Mathf.sin(mech.walkExtend(true), 2f/Mathf.PI, 1) * mechSideSway, 0f, unit.elevation));
|
||||
|
||||
//front
|
||||
legOffset.add(Tmp.v1.trns(mech.baseRotation() + 90, 0f, Mathf.lerp(Mathf.sin(walkExtend(mech, true), 1f/Mathf.PI, 1) * mechFrontSway, 0f, unit.elevation)));
|
||||
legOffset.add(Tmp.v1.trns(mech.baseRotation() + 90, 0f, Mathf.lerp(Mathf.sin(mech.walkExtend(true), 1f/Mathf.PI, 1) * mechFrontSway, 0f, unit.elevation)));
|
||||
|
||||
unit.trns(legOffset.x, legOffset.y);
|
||||
}
|
||||
@@ -434,7 +414,7 @@ public class UnitType extends UnlockableContent{
|
||||
}
|
||||
|
||||
public void drawShadow(Unit unit){
|
||||
Draw.color(shadowColor);
|
||||
Draw.color(Pal.shadow);
|
||||
float e = Math.max(unit.elevation, visualElevation);
|
||||
Draw.rect(shadowRegion, unit.x + shadowTX * e, unit.y + shadowTY * e, unit.rotation - 90);
|
||||
Draw.color();
|
||||
@@ -619,7 +599,7 @@ public class UnitType extends UnlockableContent{
|
||||
if(leg.moving && visualElevation > 0){
|
||||
float scl = visualElevation;
|
||||
float elev = Mathf.slope(1f - leg.stage) * scl;
|
||||
Draw.color(shadowColor);
|
||||
Draw.color(Pal.shadow);
|
||||
Draw.rect(footRegion, leg.base.x + shadowTX * elev, leg.base.y + shadowTY * elev, position.angleTo(leg.base));
|
||||
Draw.color();
|
||||
}
|
||||
@@ -656,8 +636,8 @@ public class UnitType extends UnlockableContent{
|
||||
|
||||
float e = unit.elevation;
|
||||
|
||||
float sin = Mathf.lerp(Mathf.sin(walkExtend(mech, true), 2f / Mathf.PI, 1f), 0f, e);
|
||||
float extension = Mathf.lerp(walkExtend(mech, false), 0, e);
|
||||
float sin = Mathf.lerp(Mathf.sin(mech.walkExtend(true), 2f / Mathf.PI, 1f), 0f, e);
|
||||
float extension = Mathf.lerp(mech.walkExtend(false), 0, e);
|
||||
float boostTrns = e * 2f;
|
||||
|
||||
Floor floor = unit.isFlying() ? Blocks.air.asFloor() : unit.floorOn();
|
||||
@@ -690,20 +670,6 @@ public class UnitType extends UnlockableContent{
|
||||
Draw.mixcol();
|
||||
}
|
||||
|
||||
public float walkExtend(Mechc mech, boolean scaled){
|
||||
|
||||
//now ranges from -maxExtension to maxExtension*3
|
||||
float raw = mech.walkTime() % (mechStride * 4);
|
||||
|
||||
if(scaled) return raw / mechStride;
|
||||
|
||||
if(raw > mechStride*3) raw = raw - mechStride * 4;
|
||||
else if(raw > mechStride*2) raw = mechStride * 2 - raw;
|
||||
else if(raw > mechStride) raw = mechStride * 2 - raw;
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
public void applyColor(Unit unit){
|
||||
Draw.color();
|
||||
Draw.mixcol(Color.white, unit.hitTime);
|
||||
|
||||
@@ -17,7 +17,8 @@ import static mindustry.Vars.*;
|
||||
|
||||
public abstract class Weather extends UnlockableContent{
|
||||
/** Default duration of this weather event in ticks. */
|
||||
public float duration = 9f * Time.toMinutes;
|
||||
public float duration = 8f * Time.toMinutes;
|
||||
public float opacityMultiplier = 1f;
|
||||
public Attributes attrs = new Attributes();
|
||||
|
||||
//internals
|
||||
@@ -122,7 +123,7 @@ public abstract class Weather extends UnlockableContent{
|
||||
|
||||
/** Creates a weather entry with some approximate weather values. */
|
||||
public WeatherEntry(Weather weather){
|
||||
this(weather, weather.duration * 1f, weather.duration * 3f, weather.duration / 2f, weather.duration * 1.5f);
|
||||
this(weather, weather.duration * 3f, weather.duration * 6f, weather.duration / 2f, weather.duration * 1.5f);
|
||||
}
|
||||
|
||||
public WeatherEntry(Weather weather, float minFrequency, float maxFrequency, float minDuration, float maxDuration){
|
||||
@@ -177,14 +178,14 @@ public abstract class Weather extends UnlockableContent{
|
||||
if(renderer.weatherAlpha() > 0.0001f){
|
||||
Draw.draw(Layer.weather, () -> {
|
||||
weather.rand.setSeed(0);
|
||||
Draw.alpha(renderer.weatherAlpha() * opacity);
|
||||
Draw.alpha(renderer.weatherAlpha() * opacity * weather.opacityMultiplier);
|
||||
weather.drawOver(self());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
Draw.draw(Layer.debris, () -> {
|
||||
weather.rand.setSeed(0);
|
||||
Draw.alpha(renderer.weatherAlpha() * opacity);
|
||||
Draw.alpha(renderer.weatherAlpha() * opacity * weather.opacityMultiplier);
|
||||
weather.drawUnder(self());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ public class Bar extends Element{
|
||||
|
||||
public Bar(String name, Color color, Floatp fraction){
|
||||
this.fraction = fraction;
|
||||
this.name = Core.bundle.get(name);
|
||||
this.name = Core.bundle.get(name, name);
|
||||
this.blinkColor.set(color);
|
||||
lastValue = value = fraction.get();
|
||||
setColor(color);
|
||||
|
||||
@@ -130,7 +130,7 @@ public class ContentDisplay{
|
||||
|
||||
public static void displayUnit(Table table, UnitType unit){
|
||||
table.table(title -> {
|
||||
title.image(unit.icon(Cicon.xlarge));
|
||||
title.image(unit.icon(Cicon.xlarge)).size(8 * 6).scaling(Scaling.fit);
|
||||
title.add("[accent]" + unit.localizedName).padLeft(5);
|
||||
});
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ public class GameOverDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
void rebuild(){
|
||||
title.setText(state.launched ? "@launch.title" : "@gameover");
|
||||
title.setText("@gameover");
|
||||
buttons.clear();
|
||||
cont.clear();
|
||||
|
||||
@@ -79,7 +79,7 @@ public class GameOverDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
if(state.hasSector()){
|
||||
RankResult result = state.stats.calculateRank(state.getSector(), state.launched);
|
||||
RankResult result = state.stats.calculateRank(state.getSector(), true);
|
||||
t.add(Core.bundle.format("stat.rank", result.rank + result.modifier));
|
||||
t.row();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ public class JoinDialog extends BaseDialog{
|
||||
Table global = new Table();
|
||||
Table hosts = new Table();
|
||||
int totalHosts;
|
||||
int refreshes;
|
||||
|
||||
public JoinDialog(){
|
||||
super("@joingame");
|
||||
@@ -95,6 +96,8 @@ public class JoinDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
void refreshAll(){
|
||||
refreshes ++;
|
||||
|
||||
refreshLocal();
|
||||
refreshRemote();
|
||||
refreshGlobal();
|
||||
@@ -327,12 +330,15 @@ public class JoinDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
void refreshGlobal(){
|
||||
int cur = refreshes;
|
||||
|
||||
global.clear();
|
||||
global.background(null);
|
||||
for(String host : defaultServers){
|
||||
String resaddress = host.contains(":") ? host.split(":")[0] : host;
|
||||
int resport = host.contains(":") ? Strings.parseInt(host.split(":")[1]) : port;
|
||||
net.pingHost(resaddress, resport, res -> {
|
||||
if(refreshes != cur) return;
|
||||
res.port = resport;
|
||||
addGlobalHost(res);
|
||||
}, e -> {});
|
||||
|
||||
@@ -163,6 +163,19 @@ public class ResearchDialog extends BaseDialog{
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog show(){
|
||||
Core.app.post(() -> {
|
||||
if(net.client()){
|
||||
//TODO make this not display every time
|
||||
//TODO rework this in the future
|
||||
ui.showInfo("@campaign.multiplayer");
|
||||
}
|
||||
});
|
||||
|
||||
return super.show();
|
||||
}
|
||||
|
||||
void treeLayout(){
|
||||
float spacing = 20f;
|
||||
LayoutNode node = new LayoutNode(root, null);
|
||||
|
||||