Merge branch 'master' of https://github.com/Anuken/Mindustry into refactor-paths

 Conflicts:
	core/src/mindustry/ai/types/GroundAI.java
This commit is contained in:
Anuken
2020-09-03 09:18:06 -04:00
186 changed files with 10171 additions and 8983 deletions

View File

@@ -13,11 +13,13 @@ assignees: ''
**Issue**: *Explain your issue in detail.* **Issue**: *Explain your issue in detail.*
**Steps to reproduce**: *How you happened across the issue, and what you were doing at the time.* **Steps to reproduce**: *How you happened across the issue, and what exactly you did to make the bug happen.*
**Link to mod(s) used, if applicable**: *The mod repositories or zip files that are related to the issue.* **Link(s) to mod(s) used**: *The mod repositories or zip files that are related to the issue, if applicable.*
**Crash report, if applicable**: *The contents of relevant crash report files.* **Save file**: *The save file you were playing on when the bug happened, if applicable.*
**Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.*
--- ---

6
.gitignore vendored
View File

@@ -79,9 +79,11 @@ com_crashlytics_export_strings.xml
/android/bin/ /android/bin/
/core/bin/ /core/bin/
/desktop/bin/ /desktop/bin/
/html/bin/
/ios/bin/ /ios/bin/
/ios-moe/bin/ /annotations/bin/
/server/bin/
/tests/bin/
/tools/bin/
*.tmp *.tmp
*.bak *.bak
*.swp *.swp

View File

@@ -1,5 +1,5 @@
jdk: jdk:
- openjdk8 - openjdk14
dist: xenial dist: xenial
android: android:
components: components:

View File

@@ -15,7 +15,7 @@ See [CONTRIBUTING](CONTRIBUTING.md).
### Building ### Building
Bleeding-edge live builds are generated automatically for every commit. You can see them [here](https://github.com/Anuken/MindustryBuilds/releases). Old builds might still be on [jenkins](https://jenkins.hellomouse.net/job/mindustry/). Bleeding-edge builds are generated automatically for every commit. You can see them [here](https://github.com/Anuken/MindustryBuilds/releases). Old builds might still be on [jenkins](https://jenkins.hellomouse.net/job/mindustry/).
If you'd rather compile on your own, follow these instructions. If you'd rather compile on your own, follow these instructions.
First, make sure you have [JDK 14](https://adoptopenjdk.net/) installed. Open a terminal in the root directory, `cd` to the Mindustry folder and run the following commands: First, make sure you have [JDK 14](https://adoptopenjdk.net/) installed. Open a terminal in the root directory, `cd` to the Mindustry folder and run the following commands:
@@ -39,7 +39,7 @@ Server builds are bundled with each released build (in Releases). If you'd rathe
#### Android #### Android
1. Install the Android SDK [here.](https://developer.android.com/studio#downloads) Make sure you're downloading the "Command line tools only", as Android Studio is not required. 1. Install the Android SDK [here.](https://developer.android.com/studio#downloads) Make sure you're downloading the "Command line tools only", as Android Studio is not required.
2. Create a file named `local.properties` inside the Mindustry directory, with its contents looking like this: `sdk.dir=<Path to Android SDK you just downloaded, without these bracket>`. For example, if you're on Windows and installed the tools to C:\\tools, your local.properties would contain `sdk.dir=C:\\tools` (*note the double backslashes are required instead of single ones!*). 2. Set the `ANDROID_HOME` environment variable to point to your unzipped Android SDK directory.
3. Run `gradlew android:assembleDebug` (or `./gradlew` if on linux/mac). This will create an unsigned APK in `android/build/outputs/apk`. 3. Run `gradlew android:assembleDebug` (or `./gradlew` if on linux/mac). This will create an unsigned APK in `android/build/outputs/apk`.
4. (Optional) To debug the application on a connected phone, do `gradlew android:installDebug android:run`. It is **highly recommended** to use IntelliJ for this instead. 4. (Optional) To debug the application on a connected phone, do `gradlew android:installDebug android:run`. It is **highly recommended** to use IntelliJ for this instead.

View File

@@ -71,22 +71,17 @@ public class LogicStatementProcessor extends BaseProcessor{
writer.addStatement("out.append(\" \")"); writer.addStatement("out.append(\" \")");
writer.addStatement("out.append((($T)obj).$L$L)", c.mirror(), field.name(), writer.addStatement("out.append((($T)obj).$L$L)", c.mirror(), field.name(),
field.mirror().toString().equals("java.lang.String") ? Seq.with(typeu.directSupertypes(field.mirror())).contains(t -> t.toString().contains("java.lang.Enum")) ? ".name()" :
".replace(\"\\n\", \"\\\\n\")" : "");
Seq.with(typeu.directSupertypes(field.mirror())).contains(t -> t.toString().contains("java.lang.Enum")) ? ".name()" :
"");
//reading primitives, strings and enums is supported; nothing else is //reading primitives, strings and enums is supported; nothing else is
reader.addStatement("if(tokens.length > $L) result.$L = $L(tokens[$L])$L", reader.addStatement("if(tokens.length > $L) result.$L = $L(tokens[$L])",
index + 1, index + 1,
field.name(), field.name(),
field.mirror().toString().equals("java.lang.String") ? field.mirror().toString().equals("java.lang.String") ?
"" : (field.tname().isPrimitive() ? field.tname().box().toString() : "" : (field.tname().isPrimitive() ? field.tname().box().toString() :
field.mirror().toString()) + ".valueOf", //if it's not a string, it must have a valueOf method field.mirror().toString()) + ".valueOf", //if it's not a string, it must have a valueOf method
index + 1, index + 1
field.mirror().toString().equals("java.lang.String") ?
".replace(\"\\\\n\", \"\\n\")" :
""
); );
index ++; index ++;

View File

@@ -1 +1 @@
{fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]} {fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:fdata,type:float,size:4},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -1 +0,0 @@
{version:1,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -1 +0,0 @@
{version:2,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:mindustry.gen.Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -1 +0,0 @@
{version:3,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -1 +0,0 @@
{version:4,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -1 +0,0 @@
{version:5,fields:[{name:collided,type:arc.struct.IntSeq,size:-1},{name:damage,type:float,size:4},{name:data,type:java.lang.Object,size:-1},{name:lifetime,type:float,size:4},{name:owner,type:Entityc,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:time,type:float,size:4},{name:type,type:mindustry.entities.bullet.BulletType,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -0,0 +1 @@
{version:1,fields:[{name:lifetime,type:float,size:4},{name:tile,type:mindustry.world.Tile,size:-1},{name:time,type:float,size:4},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -0,0 +1 @@
{version:2,fields:[{name:effectTimer,type:float,size:4},{name:intensity,type:float,size:4},{name:life,type:float,size:4},{name:opacity,type:float,size:4},{name:weather,type:mindustry.type.Weather,size:-1},{name:windVector,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}

View File

@@ -187,6 +187,10 @@ configure(subprojects - project(":annotations")){
options.compilerArgs.addAll(['--release', '8']) options.compilerArgs.addAll(['--release', '8'])
} }
} }
tasks.withType(Javadoc){
options.addStringOption('Xdoclint:none', '-quiet')
}
} }
project(":desktop"){ project(":desktop"){

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 783 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 989 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 617 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

View File

@@ -136,6 +136,8 @@ mod.scripts.disable = Your device does not support mods with scripts. You must d
about.button = About about.button = About
name = Name: name = Name:
noname = Pick a[accent] player name[] first. noname = Pick a[accent] player name[] first.
planetmap = Planet Map
launchcore = Launch Core
filename = File Name: filename = File Name:
unlocked = New content unlocked! unlocked = New content unlocked!
completed = [accent]Completed completed = [accent]Completed
@@ -170,7 +172,7 @@ host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \n
join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] or [accent]global[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]If you want to connect to someone by IP, you would need to ask the host for their IP, which can be found by googling "my ip" from their device. join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] or [accent]global[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]If you want to connect to someone by IP, you would need to ask the host for their IP, which can be found by googling "my ip" from their device.
hostserver = Host Multiplayer Game hostserver = Host Multiplayer Game
invitefriends = Invite Friends invitefriends = Invite Friends
hostserver.mobile = Host\nGame hostserver.mobile = Host Game
host = Host host = Host
hosting = [accent]Opening server... hosting = [accent]Opening server...
hosts.refresh = Refresh hosts.refresh = Refresh
@@ -575,6 +577,8 @@ blocks.shootrange = Range
blocks.size = Size blocks.size = Size
blocks.liquidcapacity = Liquid Capacity blocks.liquidcapacity = Liquid Capacity
blocks.powerrange = Power Range blocks.powerrange = Power Range
blocks.linkrange = Link Range
blocks.instructions = Instructions
blocks.powerconnections = Max Connections blocks.powerconnections = Max Connections
blocks.poweruse = Power Use blocks.poweruse = Power Use
blocks.powerdamage = Power/Damage blocks.powerdamage = Power/Damage
@@ -727,6 +731,7 @@ category.blocks.name = Block Select
command.attack = Attack command.attack = Attack
command.rally = Rally command.rally = Rally
command.retreat = Retreat command.retreat = Retreat
command.idle = Idle
placement.blockselectkeys = \n[lightgray]Key: [{0}, placement.blockselectkeys = \n[lightgray]Key: [{0},
keybind.respawn.name = Respawn keybind.respawn.name = Respawn
keybind.control.name = Control Unit keybind.control.name = Control Unit
@@ -739,6 +744,7 @@ keybind.toggle_block_status.name = Toggle Block Statuses
keybind.move_x.name = Move X keybind.move_x.name = Move X
keybind.move_y.name = Move Y keybind.move_y.name = Move Y
keybind.mouse_move.name = Follow Mouse keybind.mouse_move.name = Follow Mouse
keybind.pan.name = Pan View
keybind.boost.name = Boost keybind.boost.name = Boost
keybind.schematic_select.name = Select Region keybind.schematic_select.name = Select Region
keybind.schematic_menu.name = Schematic Menu keybind.schematic_menu.name = Schematic Menu
@@ -874,6 +880,7 @@ unit.crawler.name = Crawler
unit.atrax.name = Atrax unit.atrax.name = Atrax
unit.spiroct.name = Spiroct unit.spiroct.name = Spiroct
unit.arkyid.name = Arkyid unit.arkyid.name = Arkyid
unit.toxopid.name = Toxopid
unit.flare.name = Flare unit.flare.name = Flare
unit.horizon.name = Horizon unit.horizon.name = Horizon
unit.zenith.name = Zenith unit.zenith.name = Zenith
@@ -1073,6 +1080,7 @@ block.container.name = Container
block.launch-pad.name = Launch Pad block.launch-pad.name = Launch Pad
block.launch-pad-large.name = Large Launch Pad block.launch-pad-large.name = Large Launch Pad
block.segment.name = Segment block.segment.name = Segment
block.command-center.name = Command Center
block.ground-factory.name = Ground Factory block.ground-factory.name = Ground Factory
block.air-factory.name = Air Factory block.air-factory.name = Air Factory
block.naval-factory.name = Naval Factory block.naval-factory.name = Naval Factory
@@ -1089,6 +1097,7 @@ block.overdrive-dome.name = Overdrive Dome
block.switch.name = Switch block.switch.name = Switch
block.micro-processor.name = Micro Processor block.micro-processor.name = Micro Processor
block.logic-processor.name = Logic Processor block.logic-processor.name = Logic Processor
block.hyper-processor.name = Hyper Processor
block.logic-display.name = Logic Display block.logic-display.name = Logic Display
block.memory-cell.name = Memory Cell block.memory-cell.name = Memory Cell

View File

@@ -286,3 +286,5 @@
63458=switch|block-switch-medium 63458=switch|block-switch-medium
63457=memory-cell|block-memory-cell-medium 63457=memory-cell|block-memory-cell-medium
63456=payload-conveyor|block-payload-conveyor-medium 63456=payload-conveyor|block-payload-conveyor-medium
63455=hyper-processor|block-hyper-processor-medium
63454=toxopid|unit-toxopid-medium

View File

@@ -5,8 +5,9 @@ const log = function(context, obj){
} }
const readString = path => Vars.mods.getScripts().readString(path) const readString = path => Vars.mods.getScripts().readString(path)
const readBytes = path => Vars.mods.getScripts().readBytes(path) const readBytes = path => Vars.mods.getScripts().readBytes(path)
const loadMusic = path => Vars.mods.getScripts().loadMusic(path)
const loadSound = path => Vars.mods.getScripts().loadSound(path)
var scriptName = "base.js" var scriptName = "base.js"
var modName = "none" var modName = "none"

View File

@@ -7,8 +7,9 @@ const log = function(context, obj){
} }
const readString = path => Vars.mods.getScripts().readString(path) const readString = path => Vars.mods.getScripts().readString(path)
const readBytes = path => Vars.mods.getScripts().readBytes(path) const readBytes = path => Vars.mods.getScripts().readBytes(path)
const loadMusic = path => Vars.mods.getScripts().loadMusic(path)
const loadSound = path => Vars.mods.getScripts().loadSound(path)
var scriptName = "base.js" var scriptName = "base.js"
var modName = "none" var modName = "none"
@@ -40,6 +41,7 @@ importPackage(Packages.arc)
importPackage(Packages.arc.func) importPackage(Packages.arc.func)
importPackage(Packages.arc.graphics) importPackage(Packages.arc.graphics)
importPackage(Packages.arc.graphics.g2d) importPackage(Packages.arc.graphics.g2d)
importPackage(Packages.arc.graphics.gl)
importPackage(Packages.arc.math) importPackage(Packages.arc.math)
importPackage(Packages.arc.math.geom) importPackage(Packages.arc.math.geom)
importPackage(Packages.arc.scene) importPackage(Packages.arc.scene)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

After

Width:  |  Height:  |  Size: 794 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 644 KiB

After

Width:  |  Height:  |  Size: 650 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 994 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

After

Width:  |  Height:  |  Size: 406 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

@@ -199,8 +199,7 @@ public class Vars implements Loadable{
public static NetServer netServer; public static NetServer netServer;
public static NetClient netClient; public static NetClient netClient;
public static public static Player player;
Player player;
@Override @Override
public void loadAsync(){ public void loadAsync(){

View File

@@ -63,6 +63,7 @@ public class BaseAI{
int range = 150; int range = 150;
Position pos = randomPosition(); Position pos = randomPosition();
//when there are no random positions, do nothing. //when there are no random positions, do nothing.
if(pos == null) return; if(pos == null) return;
@@ -159,7 +160,10 @@ public class BaseAI{
private void tryWalls(){ private void tryWalls(){
Block wall = Blocks.copperWall; Block wall = Blocks.copperWall;
Tile spawn = state.rules.defaultTeam.core() != null ? state.rules.defaultTeam.core().tile : data.team.core().tile; Building spawnt = state.rules.defaultTeam.core() != null ? state.rules.defaultTeam.core() : data.team.core();
Tile spawn = spawnt == null ? null : spawnt.tile;
if(spawn == null) return;
for(int wx = lastX; wx <= lastX + lastW; wx++){ for(int wx = lastX; wx <= lastX + lastW; wx++){
for(int wy = lastY; wy <= lastY + lastH; wy++){ for(int wy = lastY; wy <= lastY + lastH; wy++){

View File

@@ -185,7 +185,7 @@ public class BlockIndexer{
if(other == null) continue; if(other == null) continue;
if(other.team() == team && pred.get(other) && intSet.add(other.pos())){ if(other.team == team && pred.get(other) && intSet.add(other.pos())){
cons.get(other); cons.get(other);
any = true; any = true;
} }
@@ -212,11 +212,11 @@ public class BlockIndexer{
} }
public void notifyTileDamaged(Building entity){ public void notifyTileDamaged(Building entity){
if(damagedTiles[entity.team().id] == null){ if(damagedTiles[entity.team.id] == null){
damagedTiles[entity.team().id] = new BuildingArray(); damagedTiles[entity.team.id] = new BuildingArray();
} }
damagedTiles[entity.team().id].add(entity); damagedTiles[entity.team.id].add(entity);
} }
public Building findEnemyTile(Team team, float x, float y, float range, Boolf<Building> pred){ public Building findEnemyTile(Team team, float x, float y, float range, Boolf<Building> pred){
@@ -251,7 +251,7 @@ public class BlockIndexer{
if(e == null) continue; if(e == null) continue;
if(e.team() != team || !pred.get(e) || !e.block().targetable) if(e.team != team || !pred.get(e) || !e.block().targetable)
continue; continue;
float ndst = e.dst2(x, y); float ndst = e.dst2(x, y);
@@ -390,7 +390,7 @@ public class BlockIndexer{
for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){ for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
Building result = world.build(x, y); Building result = world.build(x, y);
//when a targetable block is found, mark this quadrant as occupied and stop searching //when a targetable block is found, mark this quadrant as occupied and stop searching
if(result != null && result.team() == team){ if(result != null && result.team == team){
bits.set(quadrantX, quadrantY); bits.set(quadrantX, quadrantY);
break outer; break outer;
} }

View File

@@ -99,7 +99,7 @@ public class WaveSpawner{
private void eachFlyerSpawn(Floatc2 cons){ private void eachFlyerSpawn(Floatc2 cons){
for(Tile tile : spawns){ for(Tile tile : spawns){
float angle = Angles.angle(tile.x, tile.y, world.width() / 2, world.height() / 2); float angle = Angles.angle(world.width() / 2, world.height() / 2, tile.x, tile.y);
float trns = Math.max(world.width(), world.height()) * Mathf.sqrt2 * tilesize; float trns = Math.max(world.width(), world.height()) * Mathf.sqrt2 * tilesize;
float spawnX = Mathf.clamp(world.width() * tilesize / 2f + Angles.trnsx(angle, trns), -margin, world.width() * tilesize + margin); float spawnX = Mathf.clamp(world.width() * tilesize / 2f + Angles.trnsx(angle, trns), -margin, world.width() * tilesize + margin);

View File

@@ -6,6 +6,8 @@ import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
import static mindustry.Vars.*;
public class FlyingAI extends AIController{ public class FlyingAI extends AIController{
@Override @Override
@@ -18,7 +20,7 @@ public class FlyingAI extends AIController{
unit.wobble(); unit.wobble();
} }
if(target != null && unit.hasWeapons()){ if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){
if(unit.type().weapons.first().rotate){ if(unit.type().weapons.first().rotate){
moveTo(target, unit.range() * 0.8f); moveTo(target, unit.range() * 0.8f);
unit.lookAt(target); unit.lookAt(target);
@@ -26,6 +28,15 @@ public class FlyingAI extends AIController{
attack(80f); attack(80f);
} }
} }
if(target == null && command() == UnitCommand.attack && state.rules.waves && unit.team == state.rules.defaultTeam){
moveTo(getClosestSpawner(), state.rules.dropZoneRadius + 120f);
}
if(command() == UnitCommand.rally){
target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
moveTo(target, 60f);
}
} }
@Override @Override

View File

@@ -5,6 +5,9 @@ import mindustry.entities.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.meta.*;
import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -17,16 +20,34 @@ public class GroundAI extends AIController{
Building core = unit.closestEnemyCore(); Building core = unit.closestEnemyCore();
if(core != null){ if(core != null && unit.within(core, unit.range() / 1.1f + core.block.size * tilesize / 2f)){
if(unit.within(core,unit.range() / 1.1f)){ target = core;
target = core; Arrays.fill(targets, core);
}
if((core == null || !unit.within(core, unit.range() * 0.5f)) && command() == UnitCommand.attack){
boolean move = true;
if(state.rules.waves && unit.team == state.rules.defaultTeam){
Tile spawner = getClosestSpawner();
if(spawner != null && unit.within(spawner, state.rules.dropZoneRadius + 120f)) move = false;
} }
if(!unit.within(core, unit.range() * 0.5f)){ if(move) moveToCore(FlagTarget.enemyCores);
moveTo(Pathfinder.fieldCore); }
if(command() == UnitCommand.rally){
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
if(target != null && !unit.within(target, 70f)){
moveToCore(FlagTarget.rallyPoints);
} }
} }
if(unit.type().canBoost && !unit.onSolid()){
unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
}
if(!Units.invalidateTarget(target, unit, unit.range())){ if(!Units.invalidateTarget(target, unit, unit.range())){
if(unit.type().hasWeapons()){ if(unit.type().hasWeapons()){
unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed)); unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));

View File

@@ -39,7 +39,7 @@ public class SuicideAI extends GroundAI{
boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> { boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> {
Tile tile = Vars.world.tile(x, y); Tile tile = Vars.world.tile(x, y);
if(tile != null && tile.build == target) return false; if(tile != null && tile.build == target) return false;
if(tile != null && tile.build != null && tile.build.team() != unit.team()){ if(tile != null && tile.build != null && tile.build.team != unit.team()){
blockedByBlock = true; blockedByBlock = true;
return true; return true;
}else{ }else{

View File

@@ -19,6 +19,7 @@ public class MusicControl{
public Seq<Music> ambientMusic = Seq.with(); public Seq<Music> ambientMusic = Seq.with();
/** darker music, used in times of conflict */ /** darker music, used in times of conflict */
public Seq<Music> darkMusic = Seq.with(); public Seq<Music> darkMusic = Seq.with();
protected Music lastRandomPlayed; protected Music lastRandomPlayed;
protected Interval timer = new Interval(); protected Interval timer = new Interval();
protected @Nullable Music current; protected @Nullable Music current;

View File

@@ -19,7 +19,6 @@ import mindustry.world.blocks.experimental.*;
import mindustry.world.blocks.legacy.*; import mindustry.world.blocks.legacy.*;
import mindustry.world.blocks.liquid.*; import mindustry.world.blocks.liquid.*;
import mindustry.world.blocks.logic.*; import mindustry.world.blocks.logic.*;
import mindustry.world.blocks.logic.MessageBlock;
import mindustry.world.blocks.power.*; import mindustry.world.blocks.power.*;
import mindustry.world.blocks.production.*; import mindustry.world.blocks.production.*;
import mindustry.world.blocks.sandbox.*; import mindustry.world.blocks.sandbox.*;
@@ -78,12 +77,13 @@ public class Blocks implements ContentList{
duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, segment, parallax, duo, scatter, scorch, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown, segment, parallax,
//units //units
commandCenter,
groundFactory, airFactory, navalFactory, groundFactory, airFactory, navalFactory,
additiveReconstructor, multiplicativeReconstructor, exponentialReconstructor, tetrativeReconstructor, additiveReconstructor, multiplicativeReconstructor, exponentialReconstructor, tetrativeReconstructor,
repairPoint, resupplyPoint, repairPoint, resupplyPoint,
//logic //logic
message, switchBlock, microProcessor, logicProcessor, logicDisplay, memoryCell, message, switchBlock, microProcessor, logicProcessor, hyperProcessor, logicDisplay, memoryCell,
//campaign //campaign
launchPad, launchPadLarge, launchPad, launchPadLarge,
@@ -998,10 +998,12 @@ public class Blocks implements ContentList{
payloadConveyor = new PayloadConveyor("payload-conveyor"){{ payloadConveyor = new PayloadConveyor("payload-conveyor"){{
requirements(Category.distribution, with(Items.graphite, 10, Items.copper, 20)); requirements(Category.distribution, with(Items.graphite, 10, Items.copper, 20));
canOverdrive = false;
}}; }};
payloadRouter = new PayloadRouter("payload-router"){{ payloadRouter = new PayloadRouter("payload-router"){{
requirements(Category.distribution, with(Items.graphite, 15, Items.copper, 20)); requirements(Category.distribution, with(Items.graphite, 15, Items.copper, 20));
canOverdrive = false;
}}; }};
//endregion //endregion
@@ -1339,7 +1341,7 @@ public class Blocks implements ContentList{
unloader = new Unloader("unloader"){{ unloader = new Unloader("unloader"){{
requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30)); requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30));
speed = 7f; speed = 6f;
}}; }};
//endregion //endregion
@@ -1486,7 +1488,7 @@ public class Blocks implements ContentList{
reloadTime = 35f; reloadTime = 35f;
shootCone = 40f; shootCone = 40f;
rotatespeed = 8f; rotatespeed = 8f;
powerUse = 5f; powerUse = 4f;
targetAir = false; targetAir = false;
range = 90f; range = 90f;
shootEffect = Fx.lightningShoot; shootEffect = Fx.lightningShoot;
@@ -1502,12 +1504,13 @@ public class Blocks implements ContentList{
hasPower = true; hasPower = true;
size = 2; size = 2;
force = 3f; force = 4f;
scaledForce = 5.5f; scaledForce = 5.5f;
range = 170f; range = 170f;
damage = 0.08f; damage = 0.1f;
health = 160 * size * size; health = 160 * size * size;
rotateSpeed = 10; rotateSpeed = 10;
range = 85f;
consumes.powerCond(3f, (TractorBeamEntity e) -> e.target != null); consumes.powerCond(3f, (TractorBeamEntity e) -> e.target != null);
}}; }};
@@ -1556,14 +1559,15 @@ public class Blocks implements ContentList{
}}; }};
segment = new PointDefenseTurret("segment"){{ segment = new PointDefenseTurret("segment"){{
requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phasefabric, 50)); requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phasefabric, 25));
range = 100f;
hasPower = true; hasPower = true;
consumes.power(3f); consumes.power(3f);
size = 2; size = 2;
shootLength = 5f; shootLength = 5f;
bulletDamage = 12f; bulletDamage = 16f;
reloadTime = 25f; reloadTime = 15f;
health = 190 * size * size; health = 190 * size * size;
}}; }};
@@ -1699,6 +1703,12 @@ public class Blocks implements ContentList{
//endregion //endregion
//region units //region units
commandCenter = new CommandCenter("command-center"){{
requirements(Category.units, ItemStack.with(Items.copper, 200, Items.lead, 250, Items.silicon, 250, Items.graphite, 100));
size = 2;
health = size * size * 55;
}};
groundFactory = new UnitFactory("ground-factory"){{ groundFactory = new UnitFactory("ground-factory"){{
requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80)); requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80));
plans = new UnitPlan[]{ plans = new UnitPlan[]{
@@ -1769,11 +1779,11 @@ public class Blocks implements ContentList{
}}; }};
exponentialReconstructor = new Reconstructor("exponential-reconstructor"){{ exponentialReconstructor = new Reconstructor("exponential-reconstructor"){{
requirements(Category.units, with(Items.lead, 2000, Items.silicon, 750, Items.titanium, 950, Items.thorium, 450, Items.plastanium, 350, Items.phasefabric, 250)); requirements(Category.units, with(Items.lead, 2000, Items.silicon, 750, Items.titanium, 950, Items.thorium, 450, Items.plastanium, 350, Items.phasefabric, 450));
size = 7; size = 7;
consumes.power(12f); consumes.power(13f);
consumes.items(with(Items.silicon, 250, Items.titanium, 500, Items.plastanium, 400)); consumes.items(with(Items.silicon, 450, Items.titanium, 550, Items.plastanium, 550));
consumes.liquid(Liquids.cryofluid, 1f); consumes.liquid(Liquids.cryofluid, 1f);
constructTime = 60f * 60f * 1.5f; constructTime = 60f * 60f * 1.5f;
@@ -1781,15 +1791,16 @@ public class Blocks implements ContentList{
upgrades = new UnitType[][]{ upgrades = new UnitType[][]{
{UnitTypes.zenith, UnitTypes.antumbra}, {UnitTypes.zenith, UnitTypes.antumbra},
{UnitTypes.spiroct, UnitTypes.arkyid},
}; };
}}; }};
tetrativeReconstructor = new Reconstructor("tetrative-reconstructor"){{ tetrativeReconstructor = new Reconstructor("tetrative-reconstructor"){{
requirements(Category.units, with(Items.lead, 4000, Items.silicon, 1500, Items.thorium, 500, Items.plastanium, 50, Items.phasefabric, 600, Items.surgealloy, 500)); requirements(Category.units, with(Items.lead, 4000, Items.silicon, 1500, Items.thorium, 500, Items.plastanium, 450, Items.phasefabric, 600, Items.surgealloy, 500));
size = 9; size = 9;
consumes.power(25f); consumes.power(25f);
consumes.items(with(Items.silicon, 350, Items.plastanium, 450, Items.surgealloy, 400, Items.phasefabric, 150)); consumes.items(with(Items.silicon, 350, Items.plastanium, 550, Items.surgealloy, 350, Items.phasefabric, 150));
consumes.liquid(Liquids.cryofluid, 3f); consumes.liquid(Liquids.cryofluid, 3f);
constructTime = 60f * 60f * 4; constructTime = 60f * 60f * 4;
@@ -1797,6 +1808,7 @@ public class Blocks implements ContentList{
upgrades = new UnitType[][]{ upgrades = new UnitType[][]{
{UnitTypes.antumbra, UnitTypes.eclipse}, {UnitTypes.antumbra, UnitTypes.eclipse},
{UnitTypes.arkyid, UnitTypes.toxopid},
}; };
}}; }};
@@ -1862,7 +1874,6 @@ public class Blocks implements ContentList{
//looked up by name, no ref needed //looked up by name, no ref needed
new LegacyMechPad("legacy-mech-pad"); new LegacyMechPad("legacy-mech-pad");
new LegacyUnitFactory("legacy-unit-factory"); new LegacyUnitFactory("legacy-unit-factory");
new LegacyCommandCenter("legacy-command-center");
//endregion //endregion
//region campaign //region campaign
@@ -1898,7 +1909,7 @@ public class Blocks implements ContentList{
}}; }};
microProcessor = new LogicBlock("micro-processor"){{ microProcessor = new LogicBlock("micro-processor"){{
requirements(Category.logic, with(Items.copper, 80, Items.lead, 50, Items.silicon, 60)); requirements(Category.logic, with(Items.copper, 80, Items.lead, 50, Items.silicon, 50));
instructionsPerTick = 2; instructionsPerTick = 2;
@@ -1906,15 +1917,28 @@ public class Blocks implements ContentList{
}}; }};
logicProcessor = new LogicBlock("logic-processor"){{ logicProcessor = new LogicBlock("logic-processor"){{
requirements(Category.logic, with(Items.lead, 320, Items.silicon, 140, Items.graphite, 80, Items.thorium, 70)); requirements(Category.logic, with(Items.lead, 320, Items.silicon, 100, Items.graphite, 60, Items.thorium, 50));
instructionsPerTick = 5; instructionsPerTick = 5;
range = 16 * 10; range = 8 * 20;
size = 2; size = 2;
}}; }};
hyperProcessor = new LogicBlock("hyper-processor"){{
requirements(Category.logic, with(Items.lead, 450, Items.silicon, 150, Items.thorium, 75, Items.surgealloy, 50));
consumes.liquid(Liquids.cryofluid, 0.08f);
hasLiquids = true;
instructionsPerTick = 25;
range = 8 * 40;
size = 3;
}};
logicDisplay = new LogicDisplay("logic-display"){{ logicDisplay = new LogicDisplay("logic-display"){{
requirements(Category.logic, with(Items.copper, 200, Items.lead, 120, Items.silicon, 100, Items.metaglass, 50)); requirements(Category.logic, with(Items.copper, 200, Items.lead, 120, Items.silicon, 100, Items.metaglass, 50));

View File

@@ -163,7 +163,7 @@ public class Bullets implements ContentList{
width = 6f; width = 6f;
height = 8f; height = 8f;
hitEffect = Fx.flakExplosion; hitEffect = Fx.flakExplosion;
splashDamage = 20f; splashDamage = 22f;
splashDamageRadius = 20f; splashDamageRadius = 20f;
fragBullet = flakGlassFrag; fragBullet = flakGlassFrag;
fragBullets = 5; fragBullets = 5;
@@ -240,7 +240,7 @@ public class Bullets implements ContentList{
explodeRange = 20f; explodeRange = 20f;
}}; }};
missileExplosive = new MissileBulletType(3f, 10){{ missileExplosive = new MissileBulletType(3.7f, 10){{
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
@@ -255,7 +255,7 @@ public class Bullets implements ContentList{
statusDuration = 60f; statusDuration = 60f;
}}; }};
missileIncendiary = new MissileBulletType(3f, 12){{ missileIncendiary = new MissileBulletType(3.7f, 12){{
frontColor = Pal.lightishOrange; frontColor = Pal.lightishOrange;
backColor = Pal.lightOrange; backColor = Pal.lightOrange;
width = 7f; width = 7f;
@@ -269,17 +269,17 @@ public class Bullets implements ContentList{
status = StatusEffects.burning; status = StatusEffects.burning;
}}; }};
missileSurge = new MissileBulletType(3f, 20){{ missileSurge = new MissileBulletType(3.7f, 20){{
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
drag = -0.01f; drag = -0.01f;
splashDamageRadius = 28f; splashDamageRadius = 28f;
splashDamage = 40f; splashDamage = 35f;
hitEffect = Fx.blastExplosion; hitEffect = Fx.blastExplosion;
despawnEffect = Fx.blastExplosion; despawnEffect = Fx.blastExplosion;
lightning = 2; lightning = 2;
lightningLength = 14; lightningLength = 10;
}}; }};
standardCopper = new BasicBulletType(2.5f, 9){{ standardCopper = new BasicBulletType(2.5f, 9){{

View File

@@ -52,10 +52,11 @@ public class Fx{
if(!(e.data instanceof Unit)) return; if(!(e.data instanceof Unit)) return;
Unit select = e.data(); Unit select = e.data();
boolean block = select instanceof BlockUnitc;
mixcol(Pal.accent, 1f); mixcol(Pal.accent, 1f);
alpha(e.fout()); alpha(e.fout());
rect(select.type().icon(Cicon.full), select.x, select.y, select.rotation - 90f); rect(block ? ((BlockUnitc)select).tile().block.icon(Cicon.full) : select.type().icon(Cicon.full), select.x, select.y, block ? 0f : select.rotation - 90f);
alpha(1f); alpha(1f);
Lines.stroke(e.fslope() * 1f); Lines.stroke(e.fslope() * 1f);
Lines.square(select.x, select.y, e.fout() * select.hitSize * 2f, 45); Lines.square(select.x, select.y, e.fout() * select.hitSize * 2f, 45);
@@ -514,6 +515,29 @@ public class Fx{
}), }),
sapExplosion = new Effect(25, e -> {
color(Pal.sapBullet);
e.scaled(6, i -> {
stroke(3f * i.fout());
Lines.circle(e.x, e.y, 3f + i.fin() * 80f);
});
color(Color.gray);
randLenVectors(e.id, 9, 2f + 70 * e.finpow(), (x, y) -> {
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f);
});
color(Pal.sapBulletBack);
stroke(1f * e.fout());
randLenVectors(e.id + 1, 8, 1f + 60f * e.finpow(), (x, y) -> {
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f);
});
}),
massiveExplosion = new Effect(30, e -> { massiveExplosion = new Effect(30, e -> {
color(Pal.missileYellow); color(Pal.missileYellow);

View File

@@ -38,7 +38,6 @@ public class TechTree implements ContentList{
node(distributor); node(distributor);
node(sorter, () -> { node(sorter, () -> {
node(invertedSorter); node(invertedSorter);
node(message);
node(overflowGate, () -> { node(overflowGate, () -> {
node(underflowGate); node(underflowGate);
}); });
@@ -204,6 +203,26 @@ public class TechTree implements ContentList{
}); });
}); });
}); });
node(microProcessor, () -> {
node(switchBlock, () -> {
node(message, () -> {
node(logicDisplay, () -> {
});
node(memoryCell, () -> {
});
});
node(logicProcessor, () -> {
node(hyperProcessor, () -> {
});
});
});
});
}); });
}); });
}); });
@@ -340,6 +359,10 @@ public class TechTree implements ContentList{
}); });
node(groundFactory, () -> { node(groundFactory, () -> {
node(commandCenter, () -> {
});
node(dagger, () -> { node(dagger, () -> {
node(mace, () -> { node(mace, () -> {
node(fortress, () -> { node(fortress, () -> {
@@ -406,8 +429,6 @@ public class TechTree implements ContentList{
}); });
}); });
//TODO research sectors
node(groundZero, () -> { node(groundZero, () -> {
node(frozenForest, Seq.with( node(frozenForest, Seq.with(
new SectorComplete(groundZero), new SectorComplete(groundZero),
@@ -556,25 +577,20 @@ public class TechTree implements ContentList{
public ItemStack[] requirements; public ItemStack[] requirements;
/** Requirements that have been fulfilled. Always the same length as the requirement array. */ /** Requirements that have been fulfilled. Always the same length as the requirement array. */
public final ItemStack[] finishedRequirements; public final ItemStack[] finishedRequirements;
/** Extra objectives needed to research this. TODO implement */ /** Extra objectives needed to research this. */
public Seq<Objective> objectives = new Seq<>(); public Seq<Objective> objectives = new Seq<>();
/** Time required to research this content, in seconds. */ /** Time required to research this content, in seconds. */
public float time; public float time;
/** Nodes that depend on this node. */ /** Nodes that depend on this node. */
public final Seq<TechNode> children = new Seq<>(); public final Seq<TechNode> children = new Seq<>();
/** Research progress, in seconds. */
public float progress;
TechNode(@Nullable TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){ TechNode(@Nullable TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){
if(ccontext != null){ if(ccontext != null) ccontext.children.add(this);
ccontext.children.add(this);
}
this.parent = ccontext; this.parent = ccontext;
this.content = content; this.content = content;
this.requirements = requirements; this.requirements = requirements;
this.depth = parent == null ? 0 : parent.depth + 1; this.depth = parent == null ? 0 : parent.depth + 1;
this.progress = Core.settings == null ? 0 : Core.settings.getFloat("research-" + content.name, 0f);
this.time = Seq.with(requirements).mapFloat(i -> i.item.cost * i.amount).sum() * 10; this.time = Seq.with(requirements).mapFloat(i -> i.item.cost * i.amount).sum() * 10;
this.finishedRequirements = new ItemStack[requirements.length]; this.finishedRequirements = new ItemStack[requirements.length];
@@ -599,7 +615,6 @@ public class TechTree implements ContentList{
/** Flushes research progress to settings. */ /** Flushes research progress to settings. */
public void save(){ public void save(){
Core.settings.put("research-" + content.name, progress);
//save finished requirements by item type //save finished requirements by item type
for(ItemStack stack : finishedRequirements){ for(ItemStack stack : finishedRequirements){

View File

@@ -27,7 +27,7 @@ public class UnitTypes implements ContentList{
public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax; public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax;
//legs + building //legs + building
public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid; public static @EntityDef({Unitc.class, Legsc.class, Builderc.class}) UnitType spiroct, arkyid, toxopid;
//air (no special traits) //air (no special traits)
public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra; public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra;
@@ -72,7 +72,6 @@ public class UnitTypes implements ContentList{
mace = new UnitType("mace"){{ mace = new UnitType("mace"){{
speed = 0.4f; speed = 0.4f;
hitsize = 9f; hitsize = 9f;
range = 10f;
health = 500; health = 500;
armor = 4f; armor = 4f;
@@ -84,12 +83,11 @@ public class UnitTypes implements ContentList{
reload = 14f; reload = 14f;
recoil = 1f; recoil = 1f;
ejectEffect = Fx.none; ejectEffect = Fx.none;
bullet = new BulletType(3f, 30f){{ bullet = new BulletType(3.9f, 30f){{
ammoMultiplier = 3f; ammoMultiplier = 3f;
hitSize = 7f; hitSize = 7f;
lifetime = 42f; lifetime = 12f;
pierce = true; pierce = true;
drag = 0.05f;
statusDuration = 60f * 4; statusDuration = 60f * 4;
shootEffect = Fx.shootSmallFlame; shootEffect = Fx.shootSmallFlame;
hitEffect = Fx.hitFlameSmall; hitEffect = Fx.hitFlameSmall;
@@ -376,52 +374,218 @@ public class UnitTypes implements ContentList{
}}); }});
}}; }};
//TODO implement
arkyid = new UnitType("arkyid"){{ arkyid = new UnitType("arkyid"){{
drag = 0.1f; drag = 0.1f;
speed = 0.5f; speed = 0.5f;
hitsize = 9f; hitsize = 21f;
health = 140; health = 8000;
armor = 6f;
rotateSpeed = 2.7f;
legCount = 6; legCount = 6;
legMoveSpace = 1f; legMoveSpace = 1f;
legPairOffset = 3; legPairOffset = 3;
legLength = 34f; legLength = 30f;
rotateShooting = false;
legExtension = -15; legExtension = -15;
legBaseOffset = 10f; legBaseOffset = 10f;
landShake = 2f; landShake = 1f;
legSpeed = 0.1f; legSpeed = 0.1f;
legLengthScl = 1f; legLengthScl = 0.96f;
rippleScale = 2f; rippleScale = 2f;
legSpeed = 0.2f; legSpeed = 0.2f;
legSplashDamage = 32; legSplashDamage = 32;
legSplashRange = 30; legSplashRange = 30;
hovering = true;
allowLegStep = true;
visualElevation = 0.65f;
groundLayer = Layer.legUnit;
BulletType sapper = new SapBulletType(){{
sapStrength = 0.83f;
length = 55f;
damage = 34;
shootEffect = Fx.shootSmall;
hitColor = color = Color.valueOf("bf92f9");
despawnEffect = Fx.none;
width = 0.55f;
lifetime = 30f;
knockback = -1f;
}};
weapons.add( weapons.add(
new Weapon("missiles-mount"){{ new Weapon("spiroct-weapon"){{
reload = 20f; reload = 9f;
x = 4f; x = 4f;
y = 8f;
rotate = true; rotate = true;
shake = 1f; bullet = sapper;
bullet = new MissileBulletType(2.7f, 12, "missile"){{ }},
width = 8f; new Weapon("spiroct-weapon"){{
height = 8f; reload = 15f;
shrinkY = 0f; x = 9f;
drag = -0.003f; y = 6f;
homingRange = 60f; rotate = true;
keepVelocity = false; bullet = sapper;
splashDamageRadius = 25f; }},
splashDamage = 10f; new Weapon("spiroct-weapon"){{
lifetime = 120f; reload = 23f;
trailColor = Color.gray; x = 14f;
backColor = Pal.bulletYellowBack; y = 0f;
frontColor = Pal.bulletYellow; rotate = true;
hitEffect = Fx.blastExplosion; bullet = sapper;
despawnEffect = Fx.blastExplosion; }},
weaveScale = 8f; new Weapon("large-purple-mount"){{
weaveMag = 2f; y = -7f;
x = 9f;
shootY = 7f;
reload = 45;
shake = 3f;
rotateSpeed = 2f;
ejectEffect = Fx.shellEjectSmall;
shootSound = Sounds.shootBig;
rotate = true;
occlusion = 8f;
recoil = 3f;
bullet = new ArtilleryBulletType(2f, 12){{
hitEffect = Fx.sapExplosion;
knockback = 0.8f;
lifetime = 70f;
width = height = 19f;
collidesTiles = true;
ammoMultiplier = 4f;
splashDamageRadius = 95f;
splashDamage = 65f;
backColor = Pal.sapBulletBack;
frontColor = lightningColor = Pal.sapBullet;
lightning = 3;
lightningLength = 10;
smokeEffect = Fx.shootBigSmoke2;
shake = 5f;
status = StatusEffects.sapped;
statusDuration = 60f * 10;
}};
}});
}};
toxopid = new UnitType("toxopid"){{
drag = 0.1f;
speed = 0.5f;
hitsize = 21f;
health = 23000;
armor = 14f;
rotateSpeed = 1.9f;
legCount = 8;
legMoveSpace = 0.8f;
legPairOffset = 3;
legLength = 75f;
legExtension = -20;
legBaseOffset = 8f;
landShake = 1f;
legSpeed = 0.1f;
legLengthScl = 0.93f;
rippleScale = 3f;
legSpeed = 0.19f;
legSplashDamage = 80;
legSplashRange = 60;
hovering = true;
allowLegStep = true;
visualElevation = 0.95f;
groundLayer = Layer.legUnit;
weapons.add(
new Weapon("large-purple-mount"){{
y = -5f;
x = 11f;
shootY = 7f;
reload = 30;
shake = 4f;
rotateSpeed = 2f;
ejectEffect = Fx.shellEjectSmall;
shootSound = Sounds.shootBig;
rotate = true;
occlusion = 12f;
recoil = 3f;
shots = 2;
spacing = 17f;
bullet = new ShrapnelBulletType(){{
length = 90f;
damage = 110f;
width = 25f;
serrationLenScl = 7f;
serrationSpaceOffset = 60f;
serrationFadeOffset = 0f;
serrations = 10;
serrationWidth = 6f;
fromColor = Pal.sapBullet;
toColor = Pal.sapBulletBack;
shootEffect = smokeEffect = Fx.sparkShoot;
}};
}});
weapons.add(new Weapon("toxopid-cannon"){{
y = -14f;
x = 0f;
shootY = 22f;
mirror = false;
reload = 180;
shake = 10f;
recoil = 10f;
rotateSpeed = 1f;
ejectEffect = Fx.shellEjectBig;
shootSound = Sounds.shootBig;
rotate = true;
occlusion = 30f;
bullet = new ArtilleryBulletType(3f, 70){{
hitEffect = Fx.sapExplosion;
knockback = 0.8f;
lifetime = 80f;
width = height = 25f;
collidesTiles = collides = true;
ammoMultiplier = 4f;
splashDamageRadius = 95f;
splashDamage = 90f;
backColor = Pal.sapBulletBack;
frontColor = lightningColor = Pal.sapBullet;
lightning = 5;
lightningLength = 20;
smokeEffect = Fx.shootBigSmoke2;
hitShake = 10f;
status = StatusEffects.sapped;
statusDuration = 60f * 10;
fragLifeMin = 0.3f;
fragBullets = 12;
fragBullet = new ArtilleryBulletType(2.3f, 30){{
hitEffect = Fx.sapExplosion;
knockback = 0.8f;
lifetime = 90f;
width = height = 20f;
collidesTiles = false;
splashDamageRadius = 90f;
splashDamage = 55f;
backColor = Pal.sapBulletBack;
frontColor = lightningColor = Pal.sapBullet;
lightning = 2;
lightningLength = 5;
smokeEffect = Fx.shootBigSmoke2;
hitShake = 5f;
status = StatusEffects.sapped;
statusDuration = 60f * 10;
}};
}}; }};
}}); }});
}}; }};
@@ -438,6 +602,8 @@ public class UnitTypes implements ContentList{
faceTarget = false; faceTarget = false;
engineOffset = 5.5f; engineOffset = 5.5f;
range = 140f; range = 140f;
crashDamageMultiplier = 4f;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
y = 0f; y = 0f;
x = 2f; x = 2f;
@@ -449,7 +615,7 @@ public class UnitTypes implements ContentList{
}}; }};
horizon = new UnitType("horizon"){{ horizon = new UnitType("horizon"){{
health = 300; health = 350;
speed = 2f; speed = 2f;
accel = 0.08f; accel = 0.08f;
drag = 0.016f; drag = 0.016f;
@@ -458,19 +624,19 @@ public class UnitTypes implements ContentList{
engineOffset = 7.8f; engineOffset = 7.8f;
range = 140f; range = 140f;
faceTarget = false; faceTarget = false;
armor = 2f; armor = 4f;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
minShootVelocity = 0.75f; minShootVelocity = 0.75f;
x = 3f; x = 3f;
shootY = 0f; shootY = 0f;
reload = 12f; reload = 11f;
shootCone = 180f; shootCone = 180f;
ejectEffect = Fx.none; ejectEffect = Fx.none;
inaccuracy = 15f; inaccuracy = 15f;
ignoreRotation = true; ignoreRotation = true;
shootSound = Sounds.none; shootSound = Sounds.none;
bullet = new BombBulletType(23f, 25f){{ bullet = new BombBulletType(28f, 25f){{
width = 10f; width = 10f;
height = 14f; height = 14f;
hitEffect = Fx.flakExplosion; hitEffect = Fx.flakExplosion;
@@ -484,21 +650,21 @@ public class UnitTypes implements ContentList{
}}; }};
zenith = new UnitType("zenith"){{ zenith = new UnitType("zenith"){{
health = 1000; health = 700;
speed = 1.9f; speed = 1.7f;
accel = 0.04f; accel = 0.04f;
drag = 0.016f; drag = 0.016f;
flying = true; flying = true;
range = 140f; range = 140f;
hitsize = 18f; hitsize = 18f;
lowAltitude = true; lowAltitude = true;
armor = 6f; armor = 5f;
engineOffset = 12f; engineOffset = 12f;
engineSize = 3f; engineSize = 3f;
weapons.add(new Weapon("zenith-missiles"){{ weapons.add(new Weapon("zenith-missiles"){{
reload = 32f; reload = 40f;
x = 7f; x = 7f;
rotate = true; rotate = true;
shake = 1f; shake = 1f;
@@ -534,21 +700,21 @@ public class UnitTypes implements ContentList{
rotateSpeed = 1.9f; rotateSpeed = 1.9f;
flying = true; flying = true;
lowAltitude = true; lowAltitude = true;
health = 9000; health = 7000;
armor = 9f; armor = 9f;
engineOffset = 21; engineOffset = 21;
engineSize = 5.3f; engineSize = 5.3f;
hitsize = 58f; hitsize = 56f;
BulletType missiles = new MissileBulletType(2.7f, 10){{ BulletType missiles = new MissileBulletType(2.7f, 10){{
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
drag = -0.01f; drag = -0.01f;
splashDamageRadius = 40f; splashDamageRadius = 20f;
splashDamage = 40f; splashDamage = 30f;
ammoMultiplier = 4f; ammoMultiplier = 4f;
lifetime = 80f; lifetime = 50f;
hitEffect = Fx.blastExplosion; hitEffect = Fx.blastExplosion;
despawnEffect = Fx.blastExplosion; despawnEffect = Fx.blastExplosion;
@@ -582,18 +748,18 @@ public class UnitTypes implements ContentList{
new Weapon("large-bullet-mount"){{ new Weapon("large-bullet-mount"){{
y = 2f; y = 2f;
x = 10f; x = 10f;
shootY = 12f; shootY = 10f;
reload = 10; reload = 12;
shake = 1f; shake = 1f;
rotateSpeed = 2f; rotateSpeed = 2f;
ejectEffect = Fx.shellEjectSmall; ejectEffect = Fx.shellEjectSmall;
shootSound = Sounds.shootBig; shootSound = Sounds.shootBig;
rotate = true; rotate = true;
occlusion = 8f; occlusion = 8f;
bullet = new BasicBulletType(7f, 60){{ bullet = new BasicBulletType(7f, 50){{
width = 12f; width = 12f;
height = 18f; height = 18f;
lifetime = 30f; lifetime = 25f;
shootEffect = Fx.shootBig; shootEffect = Fx.shootBig;
}}; }};
}} }}
@@ -607,13 +773,25 @@ public class UnitTypes implements ContentList{
rotateSpeed = 1f; rotateSpeed = 1f;
flying = true; flying = true;
lowAltitude = true; lowAltitude = true;
health = 18000; health = 20000;
engineOffset = 38; engineOffset = 38;
engineSize = 7.3f; engineSize = 7.3f;
hitsize = 58f; hitsize = 58f;
destructibleWreck = false; destructibleWreck = false;
armor = 13f; armor = 13f;
BulletType fragBullet = new FlakBulletType(4f, 5){{
shootEffect = Fx.shootBig;
ammoMultiplier = 4f;
splashDamage = 42f;
splashDamageRadius = 25f;
collidesGround = true;
lifetime = 38f;
status = StatusEffects.blasted;
statusDuration = 60f;
}};
weapons.add( weapons.add(
new Weapon("large-laser-mount"){{ new Weapon("large-laser-mount"){{
shake = 4f; shake = 4f;
@@ -621,14 +799,14 @@ public class UnitTypes implements ContentList{
x = 18f; x = 18f;
y = 5f; y = 5f;
rotateSpeed = 2f; rotateSpeed = 2f;
reload = 50f; reload = 45f;
recoil = 4f; recoil = 4f;
shootSound = Sounds.laser; shootSound = Sounds.laser;
occlusion = 20f; occlusion = 20f;
rotate = true; rotate = true;
bullet = new LaserBulletType(){{ bullet = new LaserBulletType(){{
damage = 75f; damage = 90f;
sideAngle = 20f; sideAngle = 20f;
sideWidth = 1.5f; sideWidth = 1.5f;
sideLength = 80f; sideLength = 80f;
@@ -638,50 +816,29 @@ public class UnitTypes implements ContentList{
colors = new Color[]{Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white}; colors = new Color[]{Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white};
}}; }};
}}, }},
new Weapon("missiles-mount"){{ new Weapon("large-artillery"){{
x = 11f; x = 11f;
y = 27f; y = 27f;
rotateSpeed = 2f; rotateSpeed = 2f;
reload = 4f; reload = 9f;
shootSound = Sounds.flame; shootSound = Sounds.flame;
occlusion = 7f; occlusion = 7f;
rotate = true; rotate = true;
recoil = 0.5f; recoil = 0.5f;
bullet = Bullets.pyraFlame; bullet = fragBullet;
}}, }},
new Weapon("large-artillery"){{ new Weapon("large-artillery"){{
y = -13f; y = -13f;
x = 20f; x = 20f;
reload = 18f; reload = 12f;
ejectEffect = Fx.shellEjectSmall; ejectEffect = Fx.shellEjectSmall;
rotateSpeed = 7f; rotateSpeed = 7f;
shake = 1f; shake = 1f;
shootSound = Sounds.shoot; shootSound = Sounds.shoot;
rotate = true; rotate = true;
occlusion = 12f; occlusion = 12f;
bullet = new ArtilleryBulletType(3.2f, 12){{ bullet = fragBullet;
trailMult = 0.8f;
hitEffect = Fx.massiveExplosion;
knockback = 1.5f;
lifetime = 140f;
height = 12f;
width = 12f;
collidesTiles = false;
ammoMultiplier = 4f;
splashDamageRadius = 60f;
splashDamage = 60f;
backColor = Pal.missileYellowBack;
frontColor = Pal.missileYellow;
trailEffect = Fx.artilleryTrail;
trailSize = 6f;
hitShake = 4f;
shootEffect = Fx.shootBig2;
status = StatusEffects.blasted;
statusDuration = 60f;
}};
}}); }});
}}; }};
@@ -700,6 +857,7 @@ public class UnitTypes implements ContentList{
engineOffset = 5.7f; engineOffset = 5.7f;
itemCapacity = 30; itemCapacity = 30;
range = 50f; range = 50f;
isCounted = false;
mineTier = 1; mineTier = 1;
mineSpeed = 2.5f; mineSpeed = 2.5f;
@@ -720,6 +878,7 @@ public class UnitTypes implements ContentList{
engineOffset = 6.5f; engineOffset = 6.5f;
hitsize = 8f; hitsize = 8f;
lowAltitude = true; lowAltitude = true;
isCounted = false;
mineTier = 2; mineTier = 2;
mineSpeed = 3.5f; mineSpeed = 3.5f;
@@ -1094,6 +1253,7 @@ public class UnitTypes implements ContentList{
hitsize = 0f; hitsize = 0f;
health = 1; health = 1;
rotateSpeed = 360f; rotateSpeed = 360f;
itemCapacity = 0;
} }
@Override @Override

View File

@@ -325,6 +325,10 @@ public class Logic implements ApplicationListener{
Events.fire(Trigger.update); Events.fire(Trigger.update);
universe.updateGlobal(); universe.updateGlobal();
if(Core.settings.modified() && !state.isPlaying()){
Core.settings.forceSave();
}
if(state.isGame()){ if(state.isGame()){
if(!net.client()){ if(!net.client()){
state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted); state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted);

View File

@@ -366,6 +366,9 @@ public class NetClient implements ApplicationListener{
@Remote @Remote
public static void playerDisconnect(int playerid){ public static void playerDisconnect(int playerid){
if(netClient != null){
netClient.addRemovedEntity(playerid);
}
Groups.player.removeByID(playerid); Groups.player.removeByID(playerid);
} }
@@ -559,6 +562,22 @@ public class NetClient implements ApplicationListener{
//limit to 10 to prevent buffer overflows //limit to 10 to prevent buffer overflows
int usedRequests = Math.min(player.builder().plans().size, 10); int usedRequests = Math.min(player.builder().plans().size, 10);
int totalLength = 0;
//prevent buffer overflow by checking config length
for(int i = 0; i < usedRequests; i++){
BuildPlan plan = player.builder().plans().get(i);
if(plan.config instanceof byte[]){
int length = ((byte[])plan.config).length;
totalLength += length;
}
if(totalLength > 2048){
usedRequests = i + 1;
break;
}
}
requests = new BuildPlan[usedRequests]; requests = new BuildPlan[usedRequests];
for(int i = 0; i < usedRequests; i++){ for(int i = 0; i < usedRequests; i++){
requests[i] = player.builder().plans().get(i); requests[i] = player.builder().plans().get(i);

View File

@@ -371,6 +371,11 @@ public class NetServer implements ApplicationListener{
return; return;
} }
if(currentlyKicking[0] != null){
player.sendMessage("[scarlet]A vote is already in progress.");
return;
}
if(args.length == 0){ if(args.length == 0){
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("[orange]Players to kick: \n"); builder.append("[orange]Players to kick: \n");
@@ -385,9 +390,7 @@ public class NetServer implements ApplicationListener{
int id = Strings.parseInt(args[0].substring(1)); int id = Strings.parseInt(args[0].substring(1));
found = Groups.player.find(p -> p.id() == id); found = Groups.player.find(p -> p.id() == id);
}else{ }else{
found = Groups.player.find(p -> { found = Groups.player.find(p -> p.name.equalsIgnoreCase(args[0]));
return p.name.equalsIgnoreCase(args[0]);
});
} }
if(found != null){ if(found != null){
@@ -528,6 +531,10 @@ public class NetServer implements ApplicationListener{
serverPacketReliable(player, type, contents); serverPacketReliable(player, type, contents);
} }
private static boolean invalid(float f){
return Float.isInfinite(f) || Float.isNaN(f);
}
@Remote(targets = Loc.client, unreliable = true) @Remote(targets = Loc.client, unreliable = true)
public static void clientSnapshot( public static void clientSnapshot(
Player player, Player player,
@@ -545,6 +552,16 @@ public class NetServer implements ApplicationListener{
NetConnection con = player.con; NetConnection con = player.con;
if(con == null || snapshotID < con.lastReceivedClientSnapshot) return; if(con == null || snapshotID < con.lastReceivedClientSnapshot) return;
//validate coordinates just in case
if(invalid(x)) x = 0f;
if(invalid(y)) y = 0f;
if(invalid(xVelocity)) xVelocity = 0f;
if(invalid(yVelocity)) yVelocity = 0f;
if(invalid(pointerX)) pointerX = 0f;
if(invalid(pointerY)) pointerY = 0f;
if(invalid(rotation)) rotation = 0f;
if(invalid(baseRotation)) baseRotation = 0f;
boolean verifyPosition = !player.dead() && netServer.admins.getStrict() && headless; boolean verifyPosition = !player.dead() && netServer.admins.getStrict() && headless;
if(con.lastReceivedClientTime == 0) con.lastReceivedClientTime = Time.millis() - 16; if(con.lastReceivedClientTime == 0) con.lastReceivedClientTime = Time.millis() - 16;
@@ -614,7 +631,7 @@ public class NetServer implements ApplicationListener{
Unit unit = player.unit(); Unit unit = player.unit();
long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime); long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime);
float maxSpeed = (boosting ? player.unit().type().boostMultiplier : 1f) * player.unit().type().speed; float maxSpeed = ((player.unit().type().canBoost && player.unit().isFlying()) ? player.unit().type().boostMultiplier : 1f) * player.unit().type().speed;
if(unit.isGrounded()){ if(unit.isGrounded()){
maxSpeed *= unit.floorSpeedMultiplier(); maxSpeed *= unit.floorSpeedMultiplier();
} }
@@ -682,8 +699,8 @@ public class NetServer implements ApplicationListener{
public static void adminRequest(Player player, Player other, AdminAction action){ public static void adminRequest(Player player, Player other, AdminAction action){
if(!player.admin){ if(!player.admin){
Log.warn("ACCESS DENIED: Player @ / @ attempted to perform admin action without proper security access.", Log.warn("ACCESS DENIED: Player @ / @ attempted to perform admin action '@' on '@' without proper security access.",
player.name, player.con.address); player.name, player.con.address, action.name(), other == null ? null : other.name);
return; return;
} }
@@ -762,6 +779,10 @@ public class NetServer implements ApplicationListener{
} }
if(state.isGame() && net.server()){ if(state.isGame() && net.server()){
if(state.rules.pvp){
state.serverPaused = isWaitingForPlayers();
}
sync(); sync();
} }
} }

View File

@@ -185,6 +185,8 @@ public class Renderer implements ApplicationListener{
} }
public void draw(){ public void draw(){
Events.fire(Trigger.preDraw);
camera.update(); camera.update();
if(Float.isNaN(camera.position.x) || Float.isNaN(camera.position.y)){ if(Float.isNaN(camera.position.x) || Float.isNaN(camera.position.y)){
@@ -205,6 +207,8 @@ public class Renderer implements ApplicationListener{
Draw.sort(true); Draw.sort(true);
Events.fire(Trigger.draw);
if(pixelator.enabled()){ if(pixelator.enabled()){
pixelator.register(); pixelator.register();
} }
@@ -254,6 +258,8 @@ public class Renderer implements ApplicationListener{
Draw.reset(); Draw.reset();
Draw.flush(); Draw.flush();
Draw.sort(false); Draw.sort(false);
Events.fire(Trigger.postDraw);
} }
private void drawBackground(){ private void drawBackground(){

View File

@@ -128,6 +128,8 @@ public class UI implements ApplicationListener, Loadable{
public void update(){ public void update(){
if(disableUI || Core.scene == null) return; if(disableUI || Core.scene == null) return;
Events.fire(Trigger.uiDrawBegin);
Core.scene.act(); Core.scene.act();
Core.scene.draw(); Core.scene.draw();
@@ -143,6 +145,8 @@ public class UI implements ApplicationListener, Loadable{
control.tutorial.draw(); control.tutorial.draw();
Draw.flush(); Draw.flush();
} }
Events.fire(Trigger.uiDrawEnd);
} }
@Override @Override
@@ -221,12 +225,15 @@ public class UI implements ApplicationListener, Loadable{
} }
public TextureRegionDrawable getIcon(String name){ public TextureRegionDrawable getIcon(String name){
if(Icon.icons.containsKey(name)){ if(Icon.icons.containsKey(name)) return Icon.icons.get(name);
return Icon.icons.get(name);
}
return Core.atlas.getDrawable("error"); return Core.atlas.getDrawable("error");
} }
public TextureRegionDrawable getIcon(String name, String def){
if(Icon.icons.containsKey(name)) return Icon.icons.get(name);
return getIcon(def);
}
public void loadAnd(Runnable call){ public void loadAnd(Runnable call){
loadAnd("@loading", call); loadAnd("@loading", call);
} }

View File

@@ -126,7 +126,7 @@ public class MapEditor{
x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1); x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1);
y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1); y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1);
if(!hasOverlap(x, y)){ if(!hasOverlap(x, y)){
tile(x, y).setBlock(drawBlock, drawTeam, 0); tile(x, y).setBlock(drawBlock, drawTeam, rotation);
} }
}else{ }else{
boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air; boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air;

View File

@@ -110,18 +110,13 @@ public class MapRenderer implements Disposable{
if(wall != Blocks.air && wall.synthetic()){ if(wall != Blocks.air && wall.synthetic()){
region = !Core.atlas.isFound(wall.editorIcon()) || !center ? Core.atlas.find("clear-editor") : wall.editorIcon(); region = !Core.atlas.isFound(wall.editorIcon()) || !center ? Core.atlas.find("clear-editor") : wall.editorIcon();
if(wall.rotate){ float width = region.getWidth() * Draw.scl, height = region.getHeight() * Draw.scl;
mesh.draw(idxWall, region,
wx * tilesize + wall.offset, wy * tilesize + wall.offset,
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.build == null ? 0 : tile.build.rotdeg() - 90);
}else{
float width = region.getWidth() * Draw.scl, height = region.getHeight() * Draw.scl;
mesh.draw(idxWall, region, mesh.draw(idxWall, region,
wx * tilesize + wall.offset + (tilesize - width) / 2f, wx * tilesize + wall.offset + (tilesize - width) / 2f,
wy * tilesize + wall.offset + (tilesize - height) / 2f, wy * tilesize + wall.offset + (tilesize - height) / 2f,
width, height); width, height,
} tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg() - 90);
}else{ }else{
region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)]; region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)];

View File

@@ -20,6 +20,7 @@ import static mindustry.Vars.*;
/** Utility class for damaging in an area. */ /** Utility class for damaging in an area. */
public class Damage{ public class Damage{
private static Tile furthest;
private static Rect rect = new Rect(); private static Rect rect = new Rect();
private static Rect hitrect = new Rect(); private static Rect hitrect = new Rect();
private static Vec2 tr = new Vec2(); private static Vec2 tr = new Vec2();
@@ -30,24 +31,26 @@ public class Damage{
private static Unit tmpUnit; private static Unit tmpUnit;
/** Creates a dynamic explosion based on specified parameters. */ /** Creates a dynamic explosion based on specified parameters. */
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){ public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color, boolean damage){
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){ if(damage){
int branches = 5 + Mathf.clamp((int)(power / 30), 1, 20); for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.derelict, Pal.power, 3, x, y, Mathf.random(360f), branches + Mathf.range(2))); int branches = 5 + Mathf.clamp((int)(power / 30), 1, 20);
} Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.derelict, Pal.power, 3, x, y, Mathf.random(360f), branches + Mathf.range(2)));
}
for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){ for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), Bullets.fireball.damage, 1, 1)); Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), Bullets.fireball.damage, 1, 1));
} }
int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30); int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30);
for(int i = 0; i < waves; i++){ for(int i = 0; i < waves; i++){
int f = i; int f = i;
Time.run(i * 2f, () -> { Time.run(i * 2f, () -> {
Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f); Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f);
Fx.blockExplosionSmoke.at(x + Mathf.range(radius), y + Mathf.range(radius)); Fx.blockExplosionSmoke.at(x + Mathf.range(radius), y + Mathf.range(radius));
}); });
}
} }
if(explosiveness > 15f){ if(explosiveness > 15f){
@@ -74,6 +77,23 @@ public class Damage{
} }
} }
/** Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */
public static float collideLaser(Bullet b, float length){
Tmp.v1.trns(b.rotation(), length);
furthest = null;
world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y),
(x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers);
float resultLength = furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length;
Damage.collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), resultLength);
b.fdata = furthest != null ? resultLength : length;
return resultLength;
}
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){ public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){
collideLine(hitter, team, effect, x, y, angle, length, false); collideLine(hitter, team, effect, x, y, angle, length, false);
} }
@@ -87,7 +107,7 @@ public class Damage{
tr.trns(angle, length); tr.trns(angle, length);
Intc2 collider = (cx, cy) -> { Intc2 collider = (cx, cy) -> {
Building tile = world.build(cx, cy); Building tile = world.build(cx, cy);
if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.team() != team && tile.collide(hitter)){ if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.team != team && tile.collide(hitter)){
tile.collision(hitter); tile.collision(hitter);
collidedBlocks.add(tile.pos()); collidedBlocks.add(tile.pos());
hitter.type.hit(hitter, tile.x, tile.y); hitter.type.hit(hitter, tile.x, tile.y);

View File

@@ -101,7 +101,7 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
if(map == null) throw new RuntimeException("Mapping is not enabled for group " + id + "!"); if(map == null) throw new RuntimeException("Mapping is not enabled for group " + id + "!");
T t = map.get(id); T t = map.get(id);
if(t != null){ //remove if present in map already if(t != null){ //remove if present in map already
remove(t); t.remove();
} }
} }

View File

@@ -17,7 +17,7 @@ public class Fires{
/** Start a fire on the tile. If there already is a file there, refreshes its lifetime. */ /** Start a fire on the tile. If there already is a file there, refreshes its lifetime. */
public static void create(Tile tile){ public static void create(Tile tile){
if(net.client() || tile == null) return; //not clientside. if(net.client() || tile == null || !state.rules.fire) return; //not clientside.
Fire fire = map.get(tile.pos()); Fire fire = map.get(tile.pos());

View File

@@ -19,8 +19,17 @@ public class Units{
private static boolean boolResult; private static boolean boolResult;
@Remote(called = Loc.server) @Remote(called = Loc.server)
public static void unitDeath(Unit unit){ public static void unitDeath(int uid){
unit.killed(); Unit unit = Groups.unit.getByID(uid);
//if there's no unit don't add it later and get it stuck as a ghost
if(netClient != null){
netClient.addRemovedEntity(uid);
}
if(unit != null){
unit.killed();
}
} }
@Remote(called = Loc.server) @Remote(called = Loc.server)

View File

@@ -23,7 +23,6 @@ public class ForceFieldAbility implements Ability{
private float realRad; private float realRad;
private Unit paramUnit; private Unit paramUnit;
private boolean hadShield;
private final Cons<Shielderc> shieldConsumer = trait -> { private final Cons<Shielderc> shieldConsumer = trait -> {
if(trait.team() != paramUnit.team && Intersector.isInsideHexagon(paramUnit.x, paramUnit.y, realRad * 2f, trait.x(), trait.y()) && paramUnit.shield > 0){ if(trait.team() != paramUnit.team && Intersector.isInsideHexagon(paramUnit.x, paramUnit.y, realRad * 2f, trait.x(), trait.y()) && paramUnit.shield > 0){
trait.absorb(); trait.absorb();
@@ -32,6 +31,8 @@ public class ForceFieldAbility implements Ability{
//break shield //break shield
if(paramUnit.shield <= trait.damage()){ if(paramUnit.shield <= trait.damage()){
paramUnit.shield -= cooldown * regen; paramUnit.shield -= cooldown * regen;
Fx.shieldBreak.at(paramUnit.x, paramUnit.y, radius, paramUnit.team.color);
} }
paramUnit.shield -= trait.damage(); paramUnit.shield -= trait.damage();
@@ -54,13 +55,6 @@ public class ForceFieldAbility implements Ability{
unit.shield += Time.delta * regen; unit.shield += Time.delta * regen;
} }
//break effect
if(hadShield && unit.shield <= 0){
Fx.shieldBreak.at(paramUnit.x, paramUnit.y, radius, paramUnit.team.color);
}
hadShield = unit.shield > 0;
if(unit.shield > 0){ if(unit.shield > 0){
unit.timer2 = Mathf.lerpDelta(unit.timer2, 1f, 0.06f); unit.timer2 = Mathf.lerpDelta(unit.timer2, 1f, 0.06f);
paramUnit = unit; paramUnit = unit;

View File

@@ -74,7 +74,7 @@ public abstract class BulletType extends Content{
public float fragCone = 360f; public float fragCone = 360f;
public int fragBullets = 9; public int fragBullets = 9;
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f; public float fragVelocityMin = 0.2f, fragVelocityMax = 1f, fragLifeMin = 1f, fragLifeMax = 1f;
public BulletType fragBullet = null; public BulletType fragBullet = null;
public Color hitColor = Color.white; public Color hitColor = Color.white;
@@ -92,6 +92,7 @@ public abstract class BulletType extends Content{
public float homingPower = 0f; public float homingPower = 0f;
public float homingRange = 50f; public float homingRange = 50f;
public Color lightningColor = Pal.surge;
public int lightning; public int lightning;
public int lightningLength = 5; public int lightningLength = 5;
/** Use a negative value to use default bullet damage. */ /** Use a negative value to use default bullet damage. */
@@ -148,7 +149,7 @@ public abstract class BulletType extends Content{
for(int i = 0; i < fragBullets; i++){ for(int i = 0; i < fragBullets; i++){
float len = Mathf.random(1f, 7f); float len = Mathf.random(1f, 7f);
float a = b.rotation() + Mathf.range(fragCone/2); float a = b.rotation() + Mathf.range(fragCone/2);
fragBullet.create(b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax)); fragBullet.create(b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax), Mathf.random(fragLifeMin, fragLifeMax));
} }
} }
@@ -172,7 +173,7 @@ public abstract class BulletType extends Content{
} }
for(int i = 0; i < lightning; i++){ for(int i = 0; i < lightning; i++){
Lightning.create(b, Pal.surge, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength); Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength);
} }
} }
@@ -246,6 +247,10 @@ public abstract class BulletType extends Content{
return create(parent.owner(), parent.team, x, y, angle); return create(parent.owner(), parent.team, x, y, angle);
} }
public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl, float lifeScale){
return create(parent.owner(), parent.team, x, y, angle, velocityScl, lifeScale);
}
public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl){ public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl){
return create(parent.owner(), parent.team, x, y, angle, velocityScl); return create(parent.owner(), parent.team, x, y, angle, velocityScl);
} }

View File

@@ -29,7 +29,7 @@ public class HealBulletType extends BulletType{
@Override @Override
public boolean collides(Bullet b, Building tile){ public boolean collides(Bullet b, Building tile){
return tile.team() != b.team || tile.healthf() < 1f; return tile.team != b.team || tile.healthf() < 1f;
} }
@Override @Override
@@ -46,7 +46,7 @@ public class HealBulletType extends BulletType{
public void hitTile(Bullet b, Building tile){ public void hitTile(Bullet b, Building tile){
super.hit(b); super.hit(b);
if(tile.team() == b.team && !(tile.block() instanceof BuildBlock)){ if(tile.team == b.team && !(tile.block() instanceof BuildBlock)){
Fx.healBlockFull.at(tile.x, tile.y, tile.block().size, Pal.heal); Fx.healBlockFull.at(tile.x, tile.y, tile.block().size, Pal.heal);
tile.heal(healPercent / 100f * tile.maxHealth()); tile.heal(healPercent / 100f * tile.maxHealth());
} }

View File

@@ -10,8 +10,6 @@ import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.world.*; import mindustry.world.*;
import static mindustry.Vars.world;
public class LaserBulletType extends BulletType{ public class LaserBulletType extends BulletType{
protected static Tile furthest; protected static Tile furthest;
@@ -49,24 +47,13 @@ public class LaserBulletType extends BulletType{
@Override @Override
public void init(Bullet b){ public void init(Bullet b){
Tmp.v1.trns(b.rotation(), length); float resultLength = Damage.collideLaser(b, length);
furthest = null;
world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y),
(x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers);
float resultLength = furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length;
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), resultLength);
if(furthest != null) b.data(resultLength);
laserEffect.at(b.x, b.y, b.rotation(), resultLength * 0.75f); laserEffect.at(b.x, b.y, b.rotation(), resultLength * 0.75f);
} }
@Override @Override
public void draw(Bullet b){ public void draw(Bullet b){
float realLength = b.data() == null ? length : (Float)b.data(); float realLength = b.fdata;
float f = Mathf.curve(b.fin(), 0f, 0.2f); float f = Mathf.curve(b.fin(), 0f, 0.2f);
float baseLen = realLength * f; float baseLen = realLength * f;

View File

@@ -15,7 +15,7 @@ public class ShrapnelBulletType extends BulletType{
public Color fromColor = Color.white, toColor = Pal.lancerLaser; public Color fromColor = Color.white, toColor = Pal.lancerLaser;
public int serrations = 7; public int serrations = 7;
public float serrationLenScl = 10f, serrationWidth = 4f, serrationSpacing = 8f, serrationSpaceOffset = 80f; public float serrationLenScl = 10f, serrationWidth = 4f, serrationSpacing = 8f, serrationSpaceOffset = 80f, serrationFadeOffset = 0.5f;
public ShrapnelBulletType(){ public ShrapnelBulletType(){
speed = 0.01f; speed = 0.01f;
@@ -24,23 +24,26 @@ public class ShrapnelBulletType extends BulletType{
lifetime = 10f; lifetime = 10f;
despawnEffect = Fx.none; despawnEffect = Fx.none;
pierce = true; pierce = true;
keepVelocity = false;
} }
@Override @Override
public void init(Bullet b){ public void init(Bullet b){
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length); Damage.collideLaser(b, length);
} }
@Override @Override
public void draw(Bullet b){ public void draw(Bullet b){
float realLength = b.fdata;
Draw.color(fromColor, toColor, b.fin()); Draw.color(fromColor, toColor, b.fin());
for(int i = 0; i < serrations; i++){ for(int i = 0; i < (int)(serrations * realLength / length); i++){
Tmp.v1.trns(b.rotation(), i * serrationSpacing); Tmp.v1.trns(b.rotation(), i * serrationSpacing);
float sl = Mathf.clamp(b.fout() - 0.5f) * (serrationSpaceOffset - i * serrationLenScl); float sl = Mathf.clamp(b.fout() - serrationFadeOffset) * (serrationSpaceOffset - i * serrationLenScl);
Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, serrationWidth, sl, b.rotation() + 90); Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, serrationWidth, sl, b.rotation() + 90);
Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, serrationWidth, sl, b.rotation() - 90); Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, serrationWidth, sl, b.rotation() - 90);
} }
Drawf.tri(b.x, b.y, width * b.fout(), (length + 50), b.rotation()); Drawf.tri(b.x, b.y, width * b.fout(), (realLength + 50), b.rotation());
Drawf.tri(b.x, b.y, width * b.fout(), 10f, b.rotation() + 180f); Drawf.tri(b.x, b.y, width * b.fout(), 10f, b.rotation() + 180f);
Draw.reset(); Draw.reset();
} }

View File

@@ -27,7 +27,7 @@ abstract class BlockUnitComp implements Unitc{
@Override @Override
public void update(){ public void update(){
if(tile != null){ if(tile != null){
team = tile.team(); team = tile.team;
} }
} }
@@ -61,7 +61,7 @@ abstract class BlockUnitComp implements Unitc{
public void team(Team team){ public void team(Team team){
if(tile != null && this.team != team){ if(tile != null && this.team != team){
this.team = team; this.team = team;
if(tile.team() != team){ if(tile.team != team){
tile.team(team); tile.team(team);
} }
} }

View File

@@ -144,7 +144,6 @@ abstract class BuilderComp implements Unitc{
boolean shouldSkip(BuildPlan request, @Nullable Building core){ boolean shouldSkip(BuildPlan request, @Nullable Building core){
//requests that you have at least *started* are considered //requests that you have at least *started* are considered
if(state.rules.infiniteResources || team().rules().infiniteResources || request.breaking || core == null) return false; if(state.rules.infiniteResources || team().rules().infiniteResources || request.breaking || core == null) return false;
//TODO these are bad criteria
return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item)) && !request.initialized); return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item)) && !request.initialized);
} }

View File

@@ -135,8 +135,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public final void writeBase(Writes write){ public final void writeBase(Writes write){
write.f(health); write.f(health);
write.b(rotation); write.b(rotation | 0b10000000);
write.b(team.id); write.b(team.id);
write.b(0); //extra padding for later use
if(items != null) items.write(write); if(items != null) items.write(write);
if(power != null) power.write(write); if(power != null) power.write(write);
if(liquids != null) liquids.write(write); if(liquids != null) liquids.write(write);
@@ -145,12 +146,20 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public final void readBase(Reads read){ public final void readBase(Reads read){
health = read.f(); health = read.f();
rotation = read.b(); byte rot = read.b();
team = Team.get(read.b()); team = Team.get(read.b());
if(items != null) items.read(read);
if(power != null) power.read(read); rotation = rot & 0b01111111;
if(liquids != null) liquids.read(read); boolean legacy = true;
if(cons != null) cons.read(read); if((rot & 0b10000000) != 0){
read.b(); //padding
legacy = false;
}
if(items != null) items.read(read, legacy);
if(power != null) power.read(read, legacy);
if(liquids != null) liquids.read(read, legacy);
if(cons != null) cons.read(read, legacy);
} }
public void writeAll(Writes write){ public void writeAll(Writes write){
@@ -410,7 +419,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
int trns = block.size/2 + 1; int trns = block.size/2 + 1;
Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns); Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
if(next != null && next.build != null && next.build.team() == team && next.build.acceptPayload(base(), todump)){ if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(base(), todump)){
next.build.handlePayload(base(), todump); next.build.handlePayload(base(), todump);
return true; return true;
} }
@@ -431,7 +440,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
if(other.team() == team && other.acceptPayload(base(), todump)){ if(other.team == team && other.acceptPayload(base(), todump)){
other.handlePayload(base(), todump); other.handlePayload(base(), todump);
incrementDump(proximity.size); incrementDump(proximity.size);
return true; return true;
@@ -510,34 +519,31 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
next = next.getLiquidDestination(base(), liquid); next = next.getLiquidDestination(base(), liquid);
if(next.team() == team && next.block.hasLiquids && liquids.get(liquid) > 0f){ if(next.team == team && next.block.hasLiquids && liquids.get(liquid) > 0f){
float ofract = next.liquids.get(liquid) / next.block.liquidCapacity;
float fract = liquids.get(liquid) / block.liquidCapacity * block.liquidPressure;
float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (block.liquidCapacity), liquids.get(liquid));
flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f);
if(next.acceptLiquid(base(), liquid, 0f)){ if(flow > 0f && ofract <= fract && next.acceptLiquid(base(), liquid, flow)){
float ofract = next.liquids().get(liquid) / next.block.liquidCapacity; next.handleLiquid(base(), liquid, flow);
float fract = liquids.get(liquid) / block.liquidCapacity * block.liquidPressure; liquids.remove(liquid, flow);
float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (block.liquidCapacity), liquids.get(liquid)); return flow;
flow = Math.min(flow, next.block.liquidCapacity - next.liquids().get(liquid) - 0.001f); }else if(next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){
//TODO these are incorrect effect positions
float fx = (x + next.x) / 2f, fy = (y + next.y) / 2f;
if(flow > 0f && ofract <= fract && next.acceptLiquid(base(), liquid, flow)){ Liquid other = next.liquids.current();
next.handleLiquid(base(), liquid, flow); if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){
liquids.remove(liquid, flow); damage(1 * Time.delta);
return flow; next.damage(1 * Time.delta);
}else if(ofract > 0.1f && fract > 0.1f){ if(Mathf.chance(0.1 * Time.delta)){
//TODO these are incorrect effect positions Fx.fire.at(fx, fy);
float fx = (x + next.x) / 2f, fy = (y + next.y) / 2f; }
}else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){
Liquid other = next.liquids().current(); liquids.remove(liquid, Math.min(liquids.get(liquid), 0.7f * Time.delta));
if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){ if(Mathf.chance(0.2f * Time.delta)){
damage(1 * Time.delta); Fx.steam.at(fx, fy);
next.damage(1 * Time.delta);
if(Mathf.chance(0.1 * Time.delta)){
Fx.fire.at(fx, fy);
}
}else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){
liquids.remove(liquid, Math.min(liquids.get(liquid), 0.7f * Time.delta));
if(Mathf.chance(0.2f * Time.delta)){
Fx.steam.at(fx, fy);
}
} }
} }
} }
@@ -568,7 +574,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
incrementDump(proximity.size); incrementDump(proximity.size);
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
if(other.team() == team && other.acceptItem(base(), item) && canDump(other, item)){ if(other.team == team && other.acceptItem(base(), item) && canDump(other, item)){
other.handleItem(base(), item); other.handleItem(base(), item);
return; return;
} }
@@ -586,7 +592,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
incrementDump(proximity.size); incrementDump(proximity.size);
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
if(other.team() == team && other.acceptItem(base(), item) && canDump(other, item)){ if(other.team == team && other.acceptItem(base(), item) && canDump(other, item)){
other.handleItem(base(), item); other.handleItem(base(), item);
return true; return true;
} }
@@ -619,7 +625,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int ii = 0; ii < content.items().size; ii++){ for(int ii = 0; ii < content.items().size; ii++){
Item item = content.item(ii); Item item = content.item(ii);
if(other.team() == team && items.has(item) && other.acceptItem(base(), item) && canDump(other, item)){ if(other.team == team && items.has(item) && other.acceptItem(base(), item) && canDump(other, item)){
other.handleItem(base(), item); other.handleItem(base(), item);
items.remove(item, 1); items.remove(item, 1);
incrementDump(proximity.size); incrementDump(proximity.size);
@@ -627,7 +633,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
} }
} }
}else{ }else{
if(other.team() == team && other.acceptItem(base(), todump) && canDump(other, todump)){ if(other.team == team && other.acceptItem(base(), todump) && canDump(other, todump)){
other.handleItem(base(), todump); other.handleItem(base(), todump);
items.remove(todump, 1); items.remove(todump, 1);
incrementDump(proximity.size); incrementDump(proximity.size);
@@ -653,7 +659,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Try offloading an item to a nearby container in its facing direction. Returns true if success. */ /** Try offloading an item to a nearby container in its facing direction. Returns true if success. */
public boolean moveForward(Item item){ public boolean moveForward(Item item){
Building other = front(); Building other = front();
if(other != null && other.team() == team && other.acceptItem(base(), item)){ if(other != null && other.team == team && other.acceptItem(base(), item)){
other.handleItem(base(), item); other.handleItem(base(), item);
return true; return true;
} }
@@ -887,7 +893,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
power += this.power.status * block.consumes.getPower().capacity; power += this.power.status * block.consumes.getPower().capacity;
} }
if(block.hasLiquids){ if(block.hasLiquids && state.rules.damageExplosions){
liquids.each((liquid, amount) -> { liquids.each((liquid, amount) -> {
float splash = Mathf.clamp(amount / 4f, 0f, 10f); float splash = Mathf.clamp(amount / 4f, 0f, 10f);
@@ -903,7 +909,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}); });
} }
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * block.size / 2f, Pal.darkFlame); Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * block.size / 2f, Pal.darkFlame, state.rules.damageExplosions);
if(!floor().solid && !floor().isLiquid){ if(!floor().solid && !floor().isLiquid){
Effect.rubble(x, y, block.size); Effect.rubble(x, y, block.size);
} }
@@ -960,7 +967,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
table.row(); table.row();
table.table(this::displayConsumption).growX(); table.table(this::displayConsumption).growX();
boolean displayFlow = (block.category == Category.distribution || block.category == Category.liquid) && Core.settings.getBool("flow"); boolean displayFlow = (block.category == Category.distribution || block.category == Category.liquid) && Core.settings.getBool("flow") && block.displayFlow;
if(displayFlow){ if(displayFlow){
String ps = " " + StatUnit.perSecond.localized(); String ps = " " + StatUnit.perSecond.localized();
@@ -998,9 +1005,21 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if(liquids != null){ if(liquids != null){
table.row(); table.row();
table.table(l -> { table.table(l -> {
l.left(); boolean[] had = {false};
l.image(() -> liquids.current().icon(Cicon.small)).padRight(3f);
l.label(() -> liquids.getFlowRate() < 0 ? "..." : Strings.fixed(liquids.getFlowRate(), 2) + ps).color(Color.lightGray); Runnable rebuild = () -> {
l.clearChildren();
l.left();
l.image(() -> liquids.current().icon(Cicon.small)).padRight(3f);
l.label(() -> liquids.getFlowRate() < 0 ? "..." : Strings.fixed(liquids.getFlowRate(), 2) + ps).color(Color.lightGray);
};
l.update(() -> {
if(!had[0] && liquids.hadFlow()){
had[0] = true;
rebuild.run();
}
});
}).left(); }).left();
} }
} }

View File

@@ -25,6 +25,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
Object data; Object data;
BulletType type; BulletType type;
float damage; float damage;
float fdata;
@Override @Override
public void getCollisions(Cons<QuadTree> consumer){ public void getCollisions(Cons<QuadTree> consumer){

View File

@@ -15,14 +15,14 @@ import static mindustry.Vars.*;
@EntityDef(value = {Firec.class}, pooled = true) @EntityDef(value = {Firec.class}, pooled = true)
@Component(base = true) @Component(base = true)
abstract class FireComp implements Timedc, Posc, Firec{ abstract class FireComp implements Timedc, Posc, Firec, Syncc{
private static final float spreadChance = 0.05f, fireballChance = 0.07f; private static final float spreadChance = 0.05f, fireballChance = 0.07f;
@Import float time, lifetime, x, y; @Import float time, lifetime, x, y;
Tile tile; Tile tile;
private Block block; private transient Block block;
private float baseFlammability = -1, puddleFlammability; private transient float baseFlammability = -1, puddleFlammability;
@Override @Override
public void update(){ public void update(){
@@ -99,4 +99,9 @@ abstract class FireComp implements Timedc, Posc, Firec{
public void afterRead(){ public void afterRead(){
Fires.register(base()); Fires.register(base());
} }
@Override
public void afterSync(){
Fires.register(base());
}
} }

View File

@@ -14,7 +14,7 @@ import static mindustry.Vars.net;
abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2(); private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2();
@Import float x, y; @Import float x, y, speedMultiplier;
@Import Vec2 vel; @Import Vec2 vel;
@SyncLocal float elevation; @SyncLocal float elevation;
@@ -56,7 +56,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
float floorSpeedMultiplier(){ float floorSpeedMultiplier(){
Floor on = isFlying() || hovering ? Blocks.air.asFloor() : floorOn(); Floor on = isFlying() || hovering ? Blocks.air.asFloor() : floorOn();
return on.speedMultiplier; return on.speedMultiplier * speedMultiplier;
} }
@Override @Override

View File

@@ -33,7 +33,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
@Override @Override
public void update(){ public void update(){
if(Mathf.dst(deltaX(), deltaY()) > 0.001f){ if(Mathf.dst(deltaX(), deltaY()) > 0.001f){
baseRotation = Mathf.slerpDelta(baseRotation, Mathf.angle(deltaX(), deltaY()), 0.1f); baseRotation = Angles.moveToward(baseRotation, Mathf.angle(deltaX(), deltaY()), type.rotateSpeed);
} }
float rot = baseRotation; float rot = baseRotation;

View File

@@ -95,7 +95,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc{
Building tile = payload.entity; Building tile = payload.entity;
int tx = Vars.world.toTile(x - tile.block().offset), ty = Vars.world.toTile(y - tile.block().offset); int tx = Vars.world.toTile(x - tile.block().offset), ty = Vars.world.toTile(y - tile.block().offset);
Tile on = Vars.world.tile(tx, ty); Tile on = Vars.world.tile(tx, ty);
if(on != null && Build.validPlace(tile.block(), tile.team(), tx, ty, tile.rotation)){ if(on != null && Build.validPlace(tile.block(), tile.team, tx, ty, tile.rotation)){
int rot = (int)((rotation + 45f) / 90f) % 4; int rot = (int)((rotation + 45f) / 90f) % 4;
payload.place(on, rot); payload.place(on, rot);

View File

@@ -45,11 +45,16 @@ abstract class PosComp implements Position{
return tile == null || tile.block() != Blocks.air ? (Floor)Blocks.air : tile.floor(); return tile == null || tile.block() != Blocks.air ? (Floor)Blocks.air : tile.floor();
} }
Block blockOn(){ Block blockOn(){
Tile tile = tileOn(); Tile tile = tileOn();
return tile == null ? Blocks.air : tile.block(); return tile == null ? Blocks.air : tile.block();
} }
boolean onSolid(){
Tile tile = tileOn();
return tile != null && tile.solid();
}
@Nullable Tile tileOn(){ @Nullable Tile tileOn(){
return world.tileWorld(x, y); return world.tileWorld(x, y);
} }

View File

@@ -31,6 +31,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health;
@Import boolean dead; @Import boolean dead;
@Import Team team; @Import Team team;
@Import int id;
private UnitController controller; private UnitController controller;
private UnitType type; private UnitType type;
@@ -223,7 +224,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
//apply knockback based on spawns //apply knockback based on spawns
if(team != state.rules.waveTeam){ if(team != state.rules.waveTeam){
float relativeSize = state.rules.dropZoneRadius + bounds()/2f + 1f; float relativeSize = state.rules.dropZoneRadius + hitSize/2f + 1f;
for(Tile spawn : spawner.getSpawns()){ for(Tile spawn : spawner.getSpawns()){
if(within(spawn.worldx(), spawn.worldy(), relativeSize)){ if(within(spawn.worldx(), spawn.worldy(), relativeSize)){
vel().add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta)); vel().add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta));
@@ -275,10 +276,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
damageContinuous(floor.damageTaken); damageContinuous(floor.damageTaken);
} }
if(!net.client() && tile.solid()){ if(tile.solid()){
if(type.canBoost){ if(type.canBoost){
elevation = 1f; elevation = 1f;
}else{ }else if(!net.client()){
kill(); kill();
} }
} }
@@ -314,7 +315,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
public void destroy(){ public void destroy(){
float explosiveness = 2f + item().explosiveness * stack().amount; float explosiveness = 2f + item().explosiveness * stack().amount;
float flammability = item().flammability * stack().amount; float flammability = item().flammability * stack().amount;
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame); Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame, state.rules.damageExplosions);
float shake = hitSize / 3f; float shake = hitSize / 3f;
@@ -389,6 +390,6 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
if(dead || net.client()) return; if(dead || net.client()) return;
//deaths are synced; this calls killed() //deaths are synced; this calls killed()
Call.unitDeath(base()); Call.unitDeath(id);
} }
} }

View File

@@ -2,7 +2,9 @@ package mindustry.entities.units;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.util.ArcAnnotate.*;
import arc.util.*; import arc.util.*;
import mindustry.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
@@ -33,6 +35,10 @@ public class AIController implements UnitController{
updateMovement(); updateMovement();
} }
protected UnitCommand command(){
return unit.team.data().command;
}
protected void updateMovement(){ protected void updateMovement(){
} }
@@ -115,6 +121,10 @@ public class AIController implements UnitController{
} }
protected @Nullable Tile getClosestSpawner(){
return Geometry.findClosest(unit.x, unit.y, Vars.spawner.getSpawns());
}
protected void circle(Position target, float circleLength){ protected void circle(Position target, float circleLength){
circle(target, circleLength, unit.type().speed); circle(target, circleLength, unit.type().speed);
} }

View File

@@ -3,7 +3,7 @@ package mindustry.entities.units;
import arc.*; import arc.*;
public enum UnitCommand{ public enum UnitCommand{
attack, retreat, rally, idle; attack, rally, idle;
private final String localized; private final String localized;
public static final UnitCommand[] all = values(); public static final UnitCommand[] all = values();

View File

@@ -30,7 +30,12 @@ public class EventType{
openWiki, openWiki,
teamCoreDamage, teamCoreDamage,
socketConfigChanged, socketConfigChanged,
update update,
draw,
preDraw,
postDraw,
uiDrawBegin,
uiDrawEnd
} }
public static class WinEvent{} public static class WinEvent{}
@@ -77,7 +82,6 @@ public class EventType{
} }
} }
public static class CommandIssueEvent{ public static class CommandIssueEvent{
public final Building tile; public final Building tile;
public final UnitCommand command; public final UnitCommand command;

View File

@@ -38,6 +38,10 @@ public class Rules{
public boolean canGameOver = true; public boolean canGameOver = true;
/** Whether reactors can explode and damage other blocks. */ /** Whether reactors can explode and damage other blocks. */
public boolean reactorExplosions = true; public boolean reactorExplosions = true;
/** Whether friendly explosions can occur and set fire/damage other blocks. */
public boolean damageExplosions = true;
/** Whether fire is enabled. */
public boolean fire = true;
/** Whether units use and require ammo. */ /** Whether units use and require ammo. */
public boolean unitAmmo = false; public boolean unitAmmo = false;
/** How fast unit pads build units. */ /** How fast unit pads build units. */

View File

@@ -102,7 +102,7 @@ public class Teams{
} }
public void registerCore(CoreBuild core){ public void registerCore(CoreBuild core){
TeamData data = get(core.team()); TeamData data = get(core.team);
//add core if not present //add core if not present
if(!data.cores.contains(core)){ if(!data.cores.contains(core)){
data.cores.add(core); data.cores.add(core);
@@ -117,7 +117,7 @@ public class Teams{
} }
public void unregisterCore(CoreBuild entity){ public void unregisterCore(CoreBuild entity){
TeamData data = get(entity.team()); TeamData data = get(entity.team);
//remove core //remove core
data.cores.remove(entity); data.cores.remove(entity);
//unregister in active list //unregister in active list
@@ -181,7 +181,7 @@ public class Teams{
/** @return whether this team is controlled by the AI and builds bases. */ /** @return whether this team is controlled by the AI and builds bases. */
public boolean hasAI(){ public boolean hasAI(){
return state.rules.attackMode && team.rules().ai; return team.rules().ai;
} }
@Override @Override

View File

@@ -140,7 +140,7 @@ public class Universe{
sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed); sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed);
//check if the sector has been attacked too many times... //check if the sector has been attacked too many times...
if(sector.hasBase() && sector.getSecondsPassed() * 60f > turnDuration * sectorDestructionTurns){ if(sector.hasBase() && sector.hasWaves() && sector.getSecondsPassed() * 60f > turnDuration * sectorDestructionTurns){
//fire event for losing the sector //fire event for losing the sector
Events.fire(new SectorLoseEvent(sector)); Events.fire(new SectorLoseEvent(sector));

View File

@@ -249,7 +249,7 @@ public class BlockRenderer implements Disposable{
Draw.z(Layer.block); Draw.z(Layer.block);
} }
if(entity.team() != player.team()){ if(entity.team != player.team()){
entity.drawTeam(); entity.drawTeam();
Draw.z(Layer.block); Draw.z(Layer.block);
} }

View File

@@ -5,6 +5,9 @@ public class Layer{
public static final float public static final float
//min layer
min = -11,
//background, which may be planets or an image or nothing at all //background, which may be planets or an image or nothing at all
background = -10, background = -10,
@@ -81,7 +84,10 @@ public class Layer{
end = 200, end = 200,
//things after pixelation - used for text //things after pixelation - used for text
endPixeled = 210 endPixeled = 210,
//max layer
max = 220
; ;
} }

View File

@@ -111,7 +111,7 @@ public class OverlayRenderer{
if(dst < state.rules.enemyCoreBuildRadius * 2.2f){ if(dst < state.rules.enemyCoreBuildRadius * 2.2f){
Draw.color(Color.darkGray); Draw.color(Color.darkGray);
Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius); Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius);
Draw.color(Pal.accent, core.team().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); Draw.color(Pal.accent, core.team.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f));
Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius); Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius);
} }
}); });
@@ -132,23 +132,25 @@ public class OverlayRenderer{
//draw selected block //draw selected block
if(input.block == null && !Core.scene.hasMouse()){ if(input.block == null && !Core.scene.hasMouse()){
Vec2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY()); Vec2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
Building tile = world.buildWorld(vec.x, vec.y); Building build = world.buildWorld(vec.x, vec.y);
if(tile != null && tile.team() == player.team()){ if(build != null && build.team == player.team()){
tile.drawSelect(); build.drawSelect();
if(!tile.enabled && tile.block.drawDisabled){ if(!build.enabled && build.block.drawDisabled){
tile.drawDisabled(); build.drawDisabled();
} }
if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate && tile.interactable(player.team())){ if(Core.input.keyDown(Binding.rotateplaced) && build.block().rotate && build.interactable(player.team())){
control.input.drawArrow(tile.block(), tile.tileX(), tile.tileY(), tile.rotation, true); control.input.drawArrow(build.block(), build.tileX(), build.tileY(), build.rotation, true);
Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f)); Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f));
Fill.square(tile.x, tile.y, tile.block().size * tilesize/2f); Fill.square(build.x, build.y, build.block().size * tilesize/2f);
Draw.color(); Draw.color();
} }
} }
} }
input.drawOverSelect();
//draw selection overlay when dropping item //draw selection overlay when dropping item
if(input.isDroppingItem()){ if(input.isDroppingItem()){
Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY()); Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());

View File

@@ -9,6 +9,8 @@ public class Pal{
command = Color.valueOf("eab678"), command = Color.valueOf("eab678"),
sap = Color.valueOf("665c9f"), sap = Color.valueOf("665c9f"),
sapBullet = Color.valueOf("bf92f9"),
sapBulletBack = Color.valueOf("6d56bf"),
spore = Color.valueOf("7457ce"), spore = Color.valueOf("7457ce"),

View File

@@ -8,7 +8,8 @@ import arc.input.*;
public enum Binding implements KeyBind{ public enum Binding implements KeyBind{
move_x(new Axis(KeyCode.a, KeyCode.d), "general"), move_x(new Axis(KeyCode.a, KeyCode.d), "general"),
move_y(new Axis(KeyCode.s, KeyCode.w)), move_y(new Axis(KeyCode.s, KeyCode.w)),
mouse_move(KeyCode.mouseForward), mouse_move(KeyCode.mouseBack),
pan(KeyCode.mouseForward),
boost(KeyCode.shiftLeft), boost(KeyCode.shiftLeft),
control(KeyCode.controlLeft), control(KeyCode.controlLeft),

View File

@@ -27,24 +27,35 @@ import static mindustry.Vars.*;
import static mindustry.input.PlaceMode.*; import static mindustry.input.PlaceMode.*;
public class DesktopInput extends InputHandler{ public class DesktopInput extends InputHandler{
private Vec2 movement = new Vec2(); public Vec2 movement = new Vec2();
/** Current cursor type. */ /** Current cursor type. */
private Cursor cursorType = SystemCursor.arrow; public Cursor cursorType = SystemCursor.arrow;
/** Position where the player started dragging a line. */ /** Position where the player started dragging a line. */
private int selectX, selectY, schemX, schemY; public int selectX, selectY, schemX, schemY;
/** Last known line positions.*/ /** Last known line positions.*/
private int lastLineX, lastLineY, schematicX, schematicY; public int lastLineX, lastLineY, schematicX, schematicY;
/** Whether selecting mode is active. */ /** Whether selecting mode is active. */
private PlaceMode mode; public PlaceMode mode;
/** Animation scale for line. */ /** Animation scale for line. */
private float selectScale; public float selectScale;
/** Selected build request for movement. */ /** Selected build request for movement. */
private @Nullable BuildPlan sreq; public @Nullable BuildPlan sreq;
/** Whether player is currently deleting removal requests. */ /** Whether player is currently deleting removal requests. */
private boolean deleting = false, shouldShoot = false; public boolean deleting = false, shouldShoot = false, panning = false;
/** Mouse pan speed. */
public float panScale = 0.005f, panSpeed = 4.5f, panBoostSpeed = 9f;
@Override @Override
public void buildUI(Group group){ public void buildUI(Group group){
group.fill(t -> {
t.visible(() -> Core.settings.getBool("hints") && !player.dead() && !player.unit().spawnedByCore() && !(Core.settings.getBool("hints") && lastSchematic != null && !selectRequests.isEmpty()));
t.bottom();
t.table(Styles.black6, b -> {
b.defaults().left();
b.label(() -> Core.bundle.format("respawn", Core.keybinds.get(Binding.respawn).key.toString())).style(Styles.outlineLabel);
}).margin(6f);
});
group.fill(t -> { group.fill(t -> {
t.bottom(); t.bottom();
t.visible(() -> { t.visible(() -> {
@@ -77,15 +88,6 @@ public class DesktopInput extends InputHandler{
}); });
}).margin(6f); }).margin(6f);
}); });
group.fill(t -> {
t.visible(() -> Core.settings.getBool("hints") && !player.dead() && !player.unit().spawnedByCore());
t.bottom();
t.table(Styles.black6, b -> {
b.defaults().left();
b.label(() -> Core.bundle.format("respawn", Core.keybinds.get(Binding.respawn).key.toString())).style(Styles.outlineLabel);
}).margin(6f);
});
} }
@Override @Override
@@ -132,14 +134,12 @@ public class DesktopInput extends InputHandler{
} }
//draw schematic requests //draw schematic requests
for(BuildPlan request : selectRequests){ selectRequests.each(req -> {
request.animScale = 1f; req.animScale = 1f;
drawRequest(request); drawRequest(req);
} });
for(BuildPlan request : selectRequests){ selectRequests.each(this::drawOverRequest);
drawOverRequest(request);
}
if(player.isBuilder()){ if(player.isBuilder()){
//draw things that may be placed soon //draw things that may be placed soon
@@ -180,22 +180,35 @@ public class DesktopInput extends InputHandler{
ui.listfrag.toggle(); ui.listfrag.toggle();
} }
//TODO awful UI state checking code boolean panCam = false;
if((player.dead() || state.isPaused()) && !ui.chatfrag.shown()){ float camSpeed = !Core.input.keyDown(Binding.boost) ? panSpeed : panBoostSpeed;
if(!(scene.getKeyboardFocus() instanceof TextField) && !scene.hasDialog()){
//move camera around
float camSpeed = !Core.input.keyDown(Binding.boost) ? 3f : 8f;
Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta * camSpeed));
if(Core.input.keyDown(Binding.mouse_move)){ if(input.keyDown(Binding.pan)){
Core.camera.position.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * camSpeed; panCam = true;
Core.camera.position.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * camSpeed; panning = true;
} }
if((Math.abs(Core.input.axis(Binding.move_x)) > 0 || Math.abs(Core.input.axis(Binding.move_y)) > 0 || input.keyDown(Binding.mouse_move)) && (!scene.hasField())){
panning = false;
}
//TODO awful UI state checking code
if(((player.dead() || state.isPaused()) && !ui.chatfrag.shown()) && (!scene.hasField() && !scene.hasDialog())){
if(input.keyDown(Binding.mouse_move)){
panCam = true;
} }
}else if(!player.dead()){ panning = false;
Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta * camSpeed));
}else if(!player.dead() && !panning){
Core.camera.position.lerpDelta(player, Core.settings.getBool("smoothcamera") ? 0.08f : 1f); Core.camera.position.lerpDelta(player, Core.settings.getBool("smoothcamera") ? 0.08f : 1f);
} }
if(panCam){
Core.camera.position.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * panScale, -1, 1) * camSpeed;
Core.camera.position.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * panScale, -1, 1) * camSpeed;
}
shouldShoot = !scene.hasMouse(); shouldShoot = !scene.hasMouse();
if(!scene.hasMouse()){ if(!scene.hasMouse()){
@@ -327,22 +340,24 @@ public class DesktopInput extends InputHandler{
table.row(); table.row();
table.left().margin(0f).defaults().size(48f).left(); table.left().margin(0f).defaults().size(48f).left();
//TODO localize these
table.button(Icon.paste, Styles.clearPartiali, () -> { table.button(Icon.paste, Styles.clearPartiali, () -> {
ui.schematics.show(); ui.schematics.show();
}).tooltip("Schematics"); }).tooltip("@schematics");
table.button(Icon.tree, Styles.clearPartiali, () -> { table.button(Icon.tree, Styles.clearPartiali, () -> {
ui.research.show(); ui.research.show();
}).visible(() -> state.isCampaign()).tooltip("Research"); }).visible(() -> state.isCampaign()).tooltip("@research");
table.button(Icon.map, Styles.clearPartiali, () -> { table.button(Icon.map, Styles.clearPartiali, () -> {
ui.planet.show(); ui.planet.show();
}).visible(() -> state.isCampaign()).tooltip("Planet Map"); }).visible(() -> state.isCampaign()).tooltip("@planetmap");
table.button(Icon.up, Styles.clearPartiali, () -> { table.button(Icon.up, Styles.clearPartiali, () -> {
ui.planet.show(state.getSector(), player.team().core()); ui.planet.show(state.getSector(), player.team().core());
}).visible(() -> state.isCampaign()) }).visible(() -> state.isCampaign())
.disabled(b -> player.team().core() == null || !player.team().core().items.has(player.team().core().block.requirements)).tooltip("Launch Core"); .disabled(b -> player.team().core() == null || !player.team().core().items.has(player.team().core().block.requirements)).tooltip("@launchcore");
} }
void pollInput(){ void pollInput(){
@@ -555,6 +570,8 @@ public class DesktopInput extends InputHandler{
@Override @Override
public void updateState(){ public void updateState(){
super.updateState();
if(state.isMenu()){ if(state.isMenu()){
droppingItem = false; droppingItem = false;
mode = none; mode = none;
@@ -574,7 +591,7 @@ public class DesktopInput extends InputHandler{
//limit speed to minimum formation speed to preserve formation //limit speed to minimum formation speed to preserve formation
if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){ if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){
//add a tiny multiplier to let units catch up just in case //add a tiny multiplier to let units catch up just in case
baseSpeed = ((Commanderc)unit).minFormationSpeed() * 0.98f; baseSpeed = ((Commanderc)unit).minFormationSpeed() * 0.95f;
} }
float speed = baseSpeed * Mathf.lerp(1f, unit.type().canBoost ? unit.type().boostMultiplier : 1f, unit.elevation) * strafePenalty; float speed = baseSpeed * Mathf.lerp(1f, unit.type().canBoost ? unit.type().boostMultiplier : 1f, unit.elevation) * strafePenalty;

View File

@@ -62,13 +62,13 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
public boolean isBuilding = true, buildWasAutoPaused = false; public boolean isBuilding = true, buildWasAutoPaused = false;
public @Nullable UnitType controlledType; public @Nullable UnitType controlledType;
protected @Nullable Schematic lastSchematic; public @Nullable Schematic lastSchematic;
protected GestureDetector detector; public GestureDetector detector;
protected PlaceLine line = new PlaceLine(); public PlaceLine line = new PlaceLine();
protected BuildPlan resultreq; public BuildPlan resultreq;
protected BuildPlan brequest = new BuildPlan(); public BuildPlan brequest = new BuildPlan();
protected Seq<BuildPlan> lineRequests = new Seq<>(); public Seq<BuildPlan> lineRequests = new Seq<>();
protected Seq<BuildPlan> selectRequests = new Seq<>(); public Seq<BuildPlan> selectRequests = new Seq<>();
//methods to override //methods to override
@@ -126,7 +126,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Unit unit = player.unit(); Unit unit = player.unit();
Payloadc pay = (Payloadc)unit; Payloadc pay = (Payloadc)unit;
if(tile != null && tile.team() == unit.team && pay.payloads().size < unit.type().payloadCapacity if(tile != null && tile.team == unit.team && pay.payloads().size < unit.type().payloadCapacity
&& unit.within(tile, tilesize * tile.block.size * 1.2f)){ && unit.within(tile, tilesize * tile.block.size * 1.2f)){
//pick up block directly //pick up block directly
if(tile.block().buildVisibility != BuildVisibility.hidden && tile.block().size <= 2 && tile.canPickup()){ if(tile.block().buildVisibility != BuildVisibility.hidden && tile.block().size <= 2 && tile.canPickup()){
@@ -236,6 +236,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
player.clearUnit(); player.clearUnit();
player.deathTimer = 61f; player.deathTimer = 61f;
((CoreBuild)((BlockUnitc)unit).tile()).requestSpawn(player);
}else if(unit == null){ //just clear the unit (is this used?) }else if(unit == null){ //just clear the unit (is this used?)
player.clearUnit(); player.clearUnit();
//make sure it's AI controlled, so players can't overwrite each other //make sure it's AI controlled, so players can't overwrite each other
@@ -372,7 +374,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
public void updateState(){ public void updateState(){
if(state.isMenu()){
controlledType = null;
}
} }
public void drawBottom(){ public void drawBottom(){
@@ -383,6 +387,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
public void drawOverSelect(){
}
public void drawSelected(int x, int y, Block block, Color color){ public void drawSelected(int x, int y, Block block, Color color){
Drawf.selected(x, y, block, color); Drawf.selected(x, y, block, color);
} }
@@ -538,11 +546,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
if(test.get(req)) return req; if(test.get(req)) return req;
} }
for(BuildPlan req : selectRequests){ return selectRequests.find(test);
if(test.get(req)) return req;
}
return null;
} }
protected void drawBreakSelection(int x1, int y1, int x2, int y2){ protected void drawBreakSelection(int x1, int y1, int x2, int y2){
@@ -873,7 +877,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
if(tile instanceof ControlBlock && tile.team() == player.team()){ if(tile instanceof ControlBlock && tile.team == player.team()){
return ((ControlBlock)tile).unit(); return ((ControlBlock)tile).unit();
} }

Some files were not shown because too many files have changed in this diff Show More