Merge branch 'master' of https://github.com/Anuken/Mindustry into refactor-paths
Conflicts: core/src/mindustry/ai/types/GroundAI.java
@@ -13,11 +13,13 @@ assignees: ''
|
||||
|
||||
**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.*
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -79,9 +79,11 @@ com_crashlytics_export_strings.xml
|
||||
/android/bin/
|
||||
/core/bin/
|
||||
/desktop/bin/
|
||||
/html/bin/
|
||||
/ios/bin/
|
||||
/ios-moe/bin/
|
||||
/annotations/bin/
|
||||
/server/bin/
|
||||
/tests/bin/
|
||||
/tools/bin/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
jdk:
|
||||
- openjdk8
|
||||
- openjdk14
|
||||
dist: xenial
|
||||
android:
|
||||
components:
|
||||
|
||||
@@ -15,7 +15,7 @@ See [CONTRIBUTING](CONTRIBUTING.md).
|
||||
|
||||
### 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.
|
||||
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
|
||||
|
||||
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`.
|
||||
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.
|
||||
|
||||
|
||||
@@ -71,22 +71,17 @@ public class LogicStatementProcessor extends BaseProcessor{
|
||||
|
||||
writer.addStatement("out.append(\" \")");
|
||||
writer.addStatement("out.append((($T)obj).$L$L)", c.mirror(), field.name(),
|
||||
field.mirror().toString().equals("java.lang.String") ?
|
||||
".replace(\"\\n\", \"\\\\n\")" :
|
||||
Seq.with(typeu.directSupertypes(field.mirror())).contains(t -> t.toString().contains("java.lang.Enum")) ? ".name()" :
|
||||
"");
|
||||
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
|
||||
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,
|
||||
field.name(),
|
||||
field.mirror().toString().equals("java.lang.String") ?
|
||||
"" : (field.tname().isPrimitive() ? field.tname().box().toString() :
|
||||
field.mirror().toString()) + ".valueOf", //if it's not a string, it must have a valueOf method
|
||||
index + 1,
|
||||
field.mirror().toString().equals("java.lang.String") ?
|
||||
".replace(\"\\\\n\", \"\\n\")" :
|
||||
""
|
||||
index + 1
|
||||
);
|
||||
|
||||
index ++;
|
||||
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -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}]}
|
||||
@@ -187,6 +187,10 @@ configure(subprojects - project(":annotations")){
|
||||
options.compilerArgs.addAll(['--release', '8'])
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(Javadoc){
|
||||
options.addStringOption('Xdoclint:none', '-quiet')
|
||||
}
|
||||
}
|
||||
|
||||
project(":desktop"){
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 517 B After Width: | Height: | Size: 783 B |
|
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 613 B |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 989 B |
|
After Width: | Height: | Size: 617 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 639 B |
|
After Width: | Height: | Size: 938 B |
@@ -136,6 +136,8 @@ mod.scripts.disable = Your device does not support mods with scripts. You must d
|
||||
about.button = About
|
||||
name = Name:
|
||||
noname = Pick a[accent] player name[] first.
|
||||
planetmap = Planet Map
|
||||
launchcore = Launch Core
|
||||
filename = File Name:
|
||||
unlocked = New content unlocked!
|
||||
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.
|
||||
hostserver = Host Multiplayer Game
|
||||
invitefriends = Invite Friends
|
||||
hostserver.mobile = Host\nGame
|
||||
hostserver.mobile = Host Game
|
||||
host = Host
|
||||
hosting = [accent]Opening server...
|
||||
hosts.refresh = Refresh
|
||||
@@ -575,6 +577,8 @@ blocks.shootrange = Range
|
||||
blocks.size = Size
|
||||
blocks.liquidcapacity = Liquid Capacity
|
||||
blocks.powerrange = Power Range
|
||||
blocks.linkrange = Link Range
|
||||
blocks.instructions = Instructions
|
||||
blocks.powerconnections = Max Connections
|
||||
blocks.poweruse = Power Use
|
||||
blocks.powerdamage = Power/Damage
|
||||
@@ -727,6 +731,7 @@ category.blocks.name = Block Select
|
||||
command.attack = Attack
|
||||
command.rally = Rally
|
||||
command.retreat = Retreat
|
||||
command.idle = Idle
|
||||
placement.blockselectkeys = \n[lightgray]Key: [{0},
|
||||
keybind.respawn.name = Respawn
|
||||
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_y.name = Move Y
|
||||
keybind.mouse_move.name = Follow Mouse
|
||||
keybind.pan.name = Pan View
|
||||
keybind.boost.name = Boost
|
||||
keybind.schematic_select.name = Select Region
|
||||
keybind.schematic_menu.name = Schematic Menu
|
||||
@@ -874,6 +880,7 @@ unit.crawler.name = Crawler
|
||||
unit.atrax.name = Atrax
|
||||
unit.spiroct.name = Spiroct
|
||||
unit.arkyid.name = Arkyid
|
||||
unit.toxopid.name = Toxopid
|
||||
unit.flare.name = Flare
|
||||
unit.horizon.name = Horizon
|
||||
unit.zenith.name = Zenith
|
||||
@@ -1073,6 +1080,7 @@ block.container.name = Container
|
||||
block.launch-pad.name = Launch Pad
|
||||
block.launch-pad-large.name = Large Launch Pad
|
||||
block.segment.name = Segment
|
||||
block.command-center.name = Command Center
|
||||
block.ground-factory.name = Ground Factory
|
||||
block.air-factory.name = Air Factory
|
||||
block.naval-factory.name = Naval Factory
|
||||
@@ -1089,6 +1097,7 @@ block.overdrive-dome.name = Overdrive Dome
|
||||
block.switch.name = Switch
|
||||
block.micro-processor.name = Micro Processor
|
||||
block.logic-processor.name = Logic Processor
|
||||
block.hyper-processor.name = Hyper Processor
|
||||
block.logic-display.name = Logic Display
|
||||
block.memory-cell.name = Memory Cell
|
||||
|
||||
|
||||
@@ -286,3 +286,5 @@
|
||||
63458=switch|block-switch-medium
|
||||
63457=memory-cell|block-memory-cell-medium
|
||||
63456=payload-conveyor|block-payload-conveyor-medium
|
||||
63455=hyper-processor|block-hyper-processor-medium
|
||||
63454=toxopid|unit-toxopid-medium
|
||||
|
||||
@@ -5,8 +5,9 @@ const log = function(context, obj){
|
||||
}
|
||||
|
||||
const readString = path => Vars.mods.getScripts().readString(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 modName = "none"
|
||||
|
||||
@@ -7,8 +7,9 @@ const log = function(context, obj){
|
||||
}
|
||||
|
||||
const readString = path => Vars.mods.getScripts().readString(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 modName = "none"
|
||||
@@ -40,6 +41,7 @@ importPackage(Packages.arc)
|
||||
importPackage(Packages.arc.func)
|
||||
importPackage(Packages.arc.graphics)
|
||||
importPackage(Packages.arc.graphics.g2d)
|
||||
importPackage(Packages.arc.graphics.gl)
|
||||
importPackage(Packages.arc.math)
|
||||
importPackage(Packages.arc.math.geom)
|
||||
importPackage(Packages.arc.scene)
|
||||
|
||||
|
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 794 B |
|
Before Width: | Height: | Size: 644 KiB After Width: | Height: | Size: 650 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 994 KiB |
|
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 264 KiB |
|
Before Width: | Height: | Size: 187 KiB After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 406 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 184 KiB |
|
Before Width: | Height: | Size: 402 KiB After Width: | Height: | Size: 416 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
@@ -199,8 +199,7 @@ public class Vars implements Loadable{
|
||||
public static NetServer netServer;
|
||||
public static NetClient netClient;
|
||||
|
||||
public static
|
||||
Player player;
|
||||
public static Player player;
|
||||
|
||||
@Override
|
||||
public void loadAsync(){
|
||||
|
||||
@@ -63,6 +63,7 @@ public class BaseAI{
|
||||
int range = 150;
|
||||
|
||||
Position pos = randomPosition();
|
||||
|
||||
//when there are no random positions, do nothing.
|
||||
if(pos == null) return;
|
||||
|
||||
@@ -159,7 +160,10 @@ public class BaseAI{
|
||||
|
||||
private void tryWalls(){
|
||||
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 wy = lastY; wy <= lastY + lastH; wy++){
|
||||
|
||||
@@ -185,7 +185,7 @@ public class BlockIndexer{
|
||||
|
||||
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);
|
||||
any = true;
|
||||
}
|
||||
@@ -212,11 +212,11 @@ public class BlockIndexer{
|
||||
}
|
||||
|
||||
public void notifyTileDamaged(Building entity){
|
||||
if(damagedTiles[entity.team().id] == null){
|
||||
damagedTiles[entity.team().id] = new BuildingArray();
|
||||
if(damagedTiles[entity.team.id] == null){
|
||||
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){
|
||||
@@ -251,7 +251,7 @@ public class BlockIndexer{
|
||||
|
||||
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;
|
||||
|
||||
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++){
|
||||
Building result = world.build(x, y);
|
||||
//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);
|
||||
break outer;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ public class WaveSpawner{
|
||||
|
||||
private void eachFlyerSpawn(Floatc2 cons){
|
||||
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 spawnX = Mathf.clamp(world.width() * tilesize / 2f + Angles.trnsx(angle, trns), -margin, world.width() * tilesize + margin);
|
||||
|
||||
@@ -6,6 +6,8 @@ import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class FlyingAI extends AIController{
|
||||
|
||||
@Override
|
||||
@@ -18,7 +20,7 @@ public class FlyingAI extends AIController{
|
||||
unit.wobble();
|
||||
}
|
||||
|
||||
if(target != null && unit.hasWeapons()){
|
||||
if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){
|
||||
if(unit.type().weapons.first().rotate){
|
||||
moveTo(target, unit.range() * 0.8f);
|
||||
unit.lookAt(target);
|
||||
@@ -26,6 +28,15 @@ public class FlyingAI extends AIController{
|
||||
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
|
||||
|
||||
@@ -5,6 +5,9 @@ import mindustry.entities.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@@ -17,16 +20,34 @@ public class GroundAI extends AIController{
|
||||
|
||||
Building core = unit.closestEnemyCore();
|
||||
|
||||
if(core != null){
|
||||
if(unit.within(core,unit.range() / 1.1f)){
|
||||
target = core;
|
||||
if(core != null && unit.within(core, unit.range() / 1.1f + core.block.size * tilesize / 2f)){
|
||||
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)){
|
||||
moveTo(Pathfinder.fieldCore);
|
||||
if(move) moveToCore(FlagTarget.enemyCores);
|
||||
}
|
||||
|
||||
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(unit.type().hasWeapons()){
|
||||
unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
|
||||
|
||||
@@ -39,7 +39,7 @@ public class SuicideAI extends GroundAI{
|
||||
boolean blocked = Vars.world.raycast(unit.tileX(), unit.tileY(), target.tileX(), target.tileY(), (x, y) -> {
|
||||
Tile tile = Vars.world.tile(x, y);
|
||||
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;
|
||||
return true;
|
||||
}else{
|
||||
|
||||
@@ -19,6 +19,7 @@ public class MusicControl{
|
||||
public Seq<Music> ambientMusic = Seq.with();
|
||||
/** darker music, used in times of conflict */
|
||||
public Seq<Music> darkMusic = Seq.with();
|
||||
|
||||
protected Music lastRandomPlayed;
|
||||
protected Interval timer = new Interval();
|
||||
protected @Nullable Music current;
|
||||
|
||||
@@ -19,7 +19,6 @@ import mindustry.world.blocks.experimental.*;
|
||||
import mindustry.world.blocks.legacy.*;
|
||||
import mindustry.world.blocks.liquid.*;
|
||||
import mindustry.world.blocks.logic.*;
|
||||
import mindustry.world.blocks.logic.MessageBlock;
|
||||
import mindustry.world.blocks.power.*;
|
||||
import mindustry.world.blocks.production.*;
|
||||
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,
|
||||
|
||||
//units
|
||||
commandCenter,
|
||||
groundFactory, airFactory, navalFactory,
|
||||
additiveReconstructor, multiplicativeReconstructor, exponentialReconstructor, tetrativeReconstructor,
|
||||
repairPoint, resupplyPoint,
|
||||
|
||||
//logic
|
||||
message, switchBlock, microProcessor, logicProcessor, logicDisplay, memoryCell,
|
||||
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, logicDisplay, memoryCell,
|
||||
|
||||
//campaign
|
||||
launchPad, launchPadLarge,
|
||||
@@ -998,10 +998,12 @@ public class Blocks implements ContentList{
|
||||
|
||||
payloadConveyor = new PayloadConveyor("payload-conveyor"){{
|
||||
requirements(Category.distribution, with(Items.graphite, 10, Items.copper, 20));
|
||||
canOverdrive = false;
|
||||
}};
|
||||
|
||||
payloadRouter = new PayloadRouter("payload-router"){{
|
||||
requirements(Category.distribution, with(Items.graphite, 15, Items.copper, 20));
|
||||
canOverdrive = false;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
@@ -1339,7 +1341,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
unloader = new Unloader("unloader"){{
|
||||
requirements(Category.effect, with(Items.titanium, 25, Items.silicon, 30));
|
||||
speed = 7f;
|
||||
speed = 6f;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
@@ -1486,7 +1488,7 @@ public class Blocks implements ContentList{
|
||||
reloadTime = 35f;
|
||||
shootCone = 40f;
|
||||
rotatespeed = 8f;
|
||||
powerUse = 5f;
|
||||
powerUse = 4f;
|
||||
targetAir = false;
|
||||
range = 90f;
|
||||
shootEffect = Fx.lightningShoot;
|
||||
@@ -1502,12 +1504,13 @@ public class Blocks implements ContentList{
|
||||
|
||||
hasPower = true;
|
||||
size = 2;
|
||||
force = 3f;
|
||||
force = 4f;
|
||||
scaledForce = 5.5f;
|
||||
range = 170f;
|
||||
damage = 0.08f;
|
||||
damage = 0.1f;
|
||||
health = 160 * size * size;
|
||||
rotateSpeed = 10;
|
||||
range = 85f;
|
||||
|
||||
consumes.powerCond(3f, (TractorBeamEntity e) -> e.target != null);
|
||||
}};
|
||||
@@ -1556,14 +1559,15 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
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;
|
||||
consumes.power(3f);
|
||||
size = 2;
|
||||
shootLength = 5f;
|
||||
bulletDamage = 12f;
|
||||
reloadTime = 25f;
|
||||
bulletDamage = 16f;
|
||||
reloadTime = 15f;
|
||||
health = 190 * size * size;
|
||||
}};
|
||||
|
||||
@@ -1699,6 +1703,12 @@ public class Blocks implements ContentList{
|
||||
//endregion
|
||||
//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"){{
|
||||
requirements(Category.units, with(Items.copper, 50, Items.lead, 120, Items.silicon, 80));
|
||||
plans = new UnitPlan[]{
|
||||
@@ -1769,11 +1779,11 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
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;
|
||||
consumes.power(12f);
|
||||
consumes.items(with(Items.silicon, 250, Items.titanium, 500, Items.plastanium, 400));
|
||||
consumes.power(13f);
|
||||
consumes.items(with(Items.silicon, 450, Items.titanium, 550, Items.plastanium, 550));
|
||||
consumes.liquid(Liquids.cryofluid, 1f);
|
||||
|
||||
constructTime = 60f * 60f * 1.5f;
|
||||
@@ -1781,15 +1791,16 @@ public class Blocks implements ContentList{
|
||||
|
||||
upgrades = new UnitType[][]{
|
||||
{UnitTypes.zenith, UnitTypes.antumbra},
|
||||
{UnitTypes.spiroct, UnitTypes.arkyid},
|
||||
};
|
||||
}};
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
constructTime = 60f * 60f * 4;
|
||||
@@ -1797,6 +1808,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
upgrades = new UnitType[][]{
|
||||
{UnitTypes.antumbra, UnitTypes.eclipse},
|
||||
{UnitTypes.arkyid, UnitTypes.toxopid},
|
||||
};
|
||||
}};
|
||||
|
||||
@@ -1862,7 +1874,6 @@ public class Blocks implements ContentList{
|
||||
//looked up by name, no ref needed
|
||||
new LegacyMechPad("legacy-mech-pad");
|
||||
new LegacyUnitFactory("legacy-unit-factory");
|
||||
new LegacyCommandCenter("legacy-command-center");
|
||||
|
||||
//endregion
|
||||
//region campaign
|
||||
@@ -1898,7 +1909,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
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;
|
||||
|
||||
@@ -1906,15 +1917,28 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
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;
|
||||
|
||||
range = 16 * 10;
|
||||
range = 8 * 20;
|
||||
|
||||
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"){{
|
||||
requirements(Category.logic, with(Items.copper, 200, Items.lead, 120, Items.silicon, 100, Items.metaglass, 50));
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ public class Bullets implements ContentList{
|
||||
width = 6f;
|
||||
height = 8f;
|
||||
hitEffect = Fx.flakExplosion;
|
||||
splashDamage = 20f;
|
||||
splashDamage = 22f;
|
||||
splashDamageRadius = 20f;
|
||||
fragBullet = flakGlassFrag;
|
||||
fragBullets = 5;
|
||||
@@ -240,7 +240,7 @@ public class Bullets implements ContentList{
|
||||
explodeRange = 20f;
|
||||
}};
|
||||
|
||||
missileExplosive = new MissileBulletType(3f, 10){{
|
||||
missileExplosive = new MissileBulletType(3.7f, 10){{
|
||||
width = 8f;
|
||||
height = 8f;
|
||||
shrinkY = 0f;
|
||||
@@ -255,7 +255,7 @@ public class Bullets implements ContentList{
|
||||
statusDuration = 60f;
|
||||
}};
|
||||
|
||||
missileIncendiary = new MissileBulletType(3f, 12){{
|
||||
missileIncendiary = new MissileBulletType(3.7f, 12){{
|
||||
frontColor = Pal.lightishOrange;
|
||||
backColor = Pal.lightOrange;
|
||||
width = 7f;
|
||||
@@ -269,17 +269,17 @@ public class Bullets implements ContentList{
|
||||
status = StatusEffects.burning;
|
||||
}};
|
||||
|
||||
missileSurge = new MissileBulletType(3f, 20){{
|
||||
missileSurge = new MissileBulletType(3.7f, 20){{
|
||||
width = 8f;
|
||||
height = 8f;
|
||||
shrinkY = 0f;
|
||||
drag = -0.01f;
|
||||
splashDamageRadius = 28f;
|
||||
splashDamage = 40f;
|
||||
splashDamage = 35f;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
lightning = 2;
|
||||
lightningLength = 14;
|
||||
lightningLength = 10;
|
||||
}};
|
||||
|
||||
standardCopper = new BasicBulletType(2.5f, 9){{
|
||||
|
||||
@@ -52,10 +52,11 @@ public class Fx{
|
||||
if(!(e.data instanceof Unit)) return;
|
||||
|
||||
Unit select = e.data();
|
||||
boolean block = select instanceof BlockUnitc;
|
||||
|
||||
mixcol(Pal.accent, 1f);
|
||||
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);
|
||||
Lines.stroke(e.fslope() * 1f);
|
||||
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 -> {
|
||||
|
||||
color(Pal.missileYellow);
|
||||
|
||||
@@ -38,7 +38,6 @@ public class TechTree implements ContentList{
|
||||
node(distributor);
|
||||
node(sorter, () -> {
|
||||
node(invertedSorter);
|
||||
node(message);
|
||||
node(overflowGate, () -> {
|
||||
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(commandCenter, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(dagger, () -> {
|
||||
node(mace, () -> {
|
||||
node(fortress, () -> {
|
||||
@@ -406,8 +429,6 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
});
|
||||
|
||||
//TODO research sectors
|
||||
|
||||
node(groundZero, () -> {
|
||||
node(frozenForest, Seq.with(
|
||||
new SectorComplete(groundZero),
|
||||
@@ -556,25 +577,20 @@ public class TechTree implements ContentList{
|
||||
public ItemStack[] requirements;
|
||||
/** Requirements that have been fulfilled. Always the same length as the requirement array. */
|
||||
public final ItemStack[] finishedRequirements;
|
||||
/** Extra objectives needed to research this. TODO implement */
|
||||
/** Extra objectives needed to research this. */
|
||||
public Seq<Objective> objectives = new Seq<>();
|
||||
/** Time required to research this content, in seconds. */
|
||||
public float time;
|
||||
/** Nodes that depend on this node. */
|
||||
public final Seq<TechNode> children = new Seq<>();
|
||||
/** Research progress, in seconds. */
|
||||
public float progress;
|
||||
|
||||
TechNode(@Nullable TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){
|
||||
if(ccontext != null){
|
||||
ccontext.children.add(this);
|
||||
}
|
||||
if(ccontext != null) ccontext.children.add(this);
|
||||
|
||||
this.parent = ccontext;
|
||||
this.content = content;
|
||||
this.requirements = requirements;
|
||||
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.finishedRequirements = new ItemStack[requirements.length];
|
||||
|
||||
@@ -599,7 +615,6 @@ public class TechTree implements ContentList{
|
||||
|
||||
/** Flushes research progress to settings. */
|
||||
public void save(){
|
||||
Core.settings.put("research-" + content.name, progress);
|
||||
|
||||
//save finished requirements by item type
|
||||
for(ItemStack stack : finishedRequirements){
|
||||
|
||||
@@ -27,7 +27,7 @@ public class UnitTypes implements ContentList{
|
||||
public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax;
|
||||
|
||||
//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)
|
||||
public static @EntityDef({Unitc.class}) UnitType flare, eclipse, horizon, zenith, antumbra;
|
||||
@@ -72,7 +72,6 @@ public class UnitTypes implements ContentList{
|
||||
mace = new UnitType("mace"){{
|
||||
speed = 0.4f;
|
||||
hitsize = 9f;
|
||||
range = 10f;
|
||||
health = 500;
|
||||
armor = 4f;
|
||||
|
||||
@@ -84,12 +83,11 @@ public class UnitTypes implements ContentList{
|
||||
reload = 14f;
|
||||
recoil = 1f;
|
||||
ejectEffect = Fx.none;
|
||||
bullet = new BulletType(3f, 30f){{
|
||||
bullet = new BulletType(3.9f, 30f){{
|
||||
ammoMultiplier = 3f;
|
||||
hitSize = 7f;
|
||||
lifetime = 42f;
|
||||
lifetime = 12f;
|
||||
pierce = true;
|
||||
drag = 0.05f;
|
||||
statusDuration = 60f * 4;
|
||||
shootEffect = Fx.shootSmallFlame;
|
||||
hitEffect = Fx.hitFlameSmall;
|
||||
@@ -376,52 +374,218 @@ public class UnitTypes implements ContentList{
|
||||
}});
|
||||
}};
|
||||
|
||||
//TODO implement
|
||||
arkyid = new UnitType("arkyid"){{
|
||||
drag = 0.1f;
|
||||
speed = 0.5f;
|
||||
hitsize = 9f;
|
||||
health = 140;
|
||||
hitsize = 21f;
|
||||
health = 8000;
|
||||
armor = 6f;
|
||||
|
||||
rotateSpeed = 2.7f;
|
||||
|
||||
legCount = 6;
|
||||
legMoveSpace = 1f;
|
||||
legPairOffset = 3;
|
||||
legLength = 34f;
|
||||
rotateShooting = false;
|
||||
legLength = 30f;
|
||||
legExtension = -15;
|
||||
legBaseOffset = 10f;
|
||||
landShake = 2f;
|
||||
landShake = 1f;
|
||||
legSpeed = 0.1f;
|
||||
legLengthScl = 1f;
|
||||
legLengthScl = 0.96f;
|
||||
rippleScale = 2f;
|
||||
legSpeed = 0.2f;
|
||||
|
||||
legSplashDamage = 32;
|
||||
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(
|
||||
new Weapon("missiles-mount"){{
|
||||
reload = 20f;
|
||||
new Weapon("spiroct-weapon"){{
|
||||
reload = 9f;
|
||||
x = 4f;
|
||||
y = 8f;
|
||||
rotate = true;
|
||||
shake = 1f;
|
||||
bullet = new MissileBulletType(2.7f, 12, "missile"){{
|
||||
width = 8f;
|
||||
height = 8f;
|
||||
shrinkY = 0f;
|
||||
drag = -0.003f;
|
||||
homingRange = 60f;
|
||||
keepVelocity = false;
|
||||
splashDamageRadius = 25f;
|
||||
splashDamage = 10f;
|
||||
lifetime = 120f;
|
||||
trailColor = Color.gray;
|
||||
backColor = Pal.bulletYellowBack;
|
||||
frontColor = Pal.bulletYellow;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
weaveScale = 8f;
|
||||
weaveMag = 2f;
|
||||
bullet = sapper;
|
||||
}},
|
||||
new Weapon("spiroct-weapon"){{
|
||||
reload = 15f;
|
||||
x = 9f;
|
||||
y = 6f;
|
||||
rotate = true;
|
||||
bullet = sapper;
|
||||
}},
|
||||
new Weapon("spiroct-weapon"){{
|
||||
reload = 23f;
|
||||
x = 14f;
|
||||
y = 0f;
|
||||
rotate = true;
|
||||
bullet = sapper;
|
||||
}},
|
||||
new Weapon("large-purple-mount"){{
|
||||
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;
|
||||
engineOffset = 5.5f;
|
||||
range = 140f;
|
||||
crashDamageMultiplier = 4f;
|
||||
|
||||
weapons.add(new Weapon(){{
|
||||
y = 0f;
|
||||
x = 2f;
|
||||
@@ -449,7 +615,7 @@ public class UnitTypes implements ContentList{
|
||||
}};
|
||||
|
||||
horizon = new UnitType("horizon"){{
|
||||
health = 300;
|
||||
health = 350;
|
||||
speed = 2f;
|
||||
accel = 0.08f;
|
||||
drag = 0.016f;
|
||||
@@ -458,19 +624,19 @@ public class UnitTypes implements ContentList{
|
||||
engineOffset = 7.8f;
|
||||
range = 140f;
|
||||
faceTarget = false;
|
||||
armor = 2f;
|
||||
armor = 4f;
|
||||
|
||||
weapons.add(new Weapon(){{
|
||||
minShootVelocity = 0.75f;
|
||||
x = 3f;
|
||||
shootY = 0f;
|
||||
reload = 12f;
|
||||
reload = 11f;
|
||||
shootCone = 180f;
|
||||
ejectEffect = Fx.none;
|
||||
inaccuracy = 15f;
|
||||
ignoreRotation = true;
|
||||
shootSound = Sounds.none;
|
||||
bullet = new BombBulletType(23f, 25f){{
|
||||
bullet = new BombBulletType(28f, 25f){{
|
||||
width = 10f;
|
||||
height = 14f;
|
||||
hitEffect = Fx.flakExplosion;
|
||||
@@ -484,21 +650,21 @@ public class UnitTypes implements ContentList{
|
||||
}};
|
||||
|
||||
zenith = new UnitType("zenith"){{
|
||||
health = 1000;
|
||||
speed = 1.9f;
|
||||
health = 700;
|
||||
speed = 1.7f;
|
||||
accel = 0.04f;
|
||||
drag = 0.016f;
|
||||
flying = true;
|
||||
range = 140f;
|
||||
hitsize = 18f;
|
||||
lowAltitude = true;
|
||||
armor = 6f;
|
||||
armor = 5f;
|
||||
|
||||
engineOffset = 12f;
|
||||
engineSize = 3f;
|
||||
|
||||
weapons.add(new Weapon("zenith-missiles"){{
|
||||
reload = 32f;
|
||||
reload = 40f;
|
||||
x = 7f;
|
||||
rotate = true;
|
||||
shake = 1f;
|
||||
@@ -534,21 +700,21 @@ public class UnitTypes implements ContentList{
|
||||
rotateSpeed = 1.9f;
|
||||
flying = true;
|
||||
lowAltitude = true;
|
||||
health = 9000;
|
||||
health = 7000;
|
||||
armor = 9f;
|
||||
engineOffset = 21;
|
||||
engineSize = 5.3f;
|
||||
hitsize = 58f;
|
||||
hitsize = 56f;
|
||||
|
||||
BulletType missiles = new MissileBulletType(2.7f, 10){{
|
||||
width = 8f;
|
||||
height = 8f;
|
||||
shrinkY = 0f;
|
||||
drag = -0.01f;
|
||||
splashDamageRadius = 40f;
|
||||
splashDamage = 40f;
|
||||
splashDamageRadius = 20f;
|
||||
splashDamage = 30f;
|
||||
ammoMultiplier = 4f;
|
||||
lifetime = 80f;
|
||||
lifetime = 50f;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
|
||||
@@ -582,18 +748,18 @@ public class UnitTypes implements ContentList{
|
||||
new Weapon("large-bullet-mount"){{
|
||||
y = 2f;
|
||||
x = 10f;
|
||||
shootY = 12f;
|
||||
reload = 10;
|
||||
shootY = 10f;
|
||||
reload = 12;
|
||||
shake = 1f;
|
||||
rotateSpeed = 2f;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
shootSound = Sounds.shootBig;
|
||||
rotate = true;
|
||||
occlusion = 8f;
|
||||
bullet = new BasicBulletType(7f, 60){{
|
||||
bullet = new BasicBulletType(7f, 50){{
|
||||
width = 12f;
|
||||
height = 18f;
|
||||
lifetime = 30f;
|
||||
lifetime = 25f;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
}}
|
||||
@@ -607,13 +773,25 @@ public class UnitTypes implements ContentList{
|
||||
rotateSpeed = 1f;
|
||||
flying = true;
|
||||
lowAltitude = true;
|
||||
health = 18000;
|
||||
health = 20000;
|
||||
engineOffset = 38;
|
||||
engineSize = 7.3f;
|
||||
hitsize = 58f;
|
||||
destructibleWreck = false;
|
||||
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(
|
||||
new Weapon("large-laser-mount"){{
|
||||
shake = 4f;
|
||||
@@ -621,14 +799,14 @@ public class UnitTypes implements ContentList{
|
||||
x = 18f;
|
||||
y = 5f;
|
||||
rotateSpeed = 2f;
|
||||
reload = 50f;
|
||||
reload = 45f;
|
||||
recoil = 4f;
|
||||
shootSound = Sounds.laser;
|
||||
occlusion = 20f;
|
||||
rotate = true;
|
||||
|
||||
bullet = new LaserBulletType(){{
|
||||
damage = 75f;
|
||||
damage = 90f;
|
||||
sideAngle = 20f;
|
||||
sideWidth = 1.5f;
|
||||
sideLength = 80f;
|
||||
@@ -638,50 +816,29 @@ public class UnitTypes implements ContentList{
|
||||
colors = new Color[]{Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white};
|
||||
}};
|
||||
}},
|
||||
new Weapon("missiles-mount"){{
|
||||
new Weapon("large-artillery"){{
|
||||
x = 11f;
|
||||
y = 27f;
|
||||
rotateSpeed = 2f;
|
||||
reload = 4f;
|
||||
reload = 9f;
|
||||
shootSound = Sounds.flame;
|
||||
occlusion = 7f;
|
||||
rotate = true;
|
||||
recoil = 0.5f;
|
||||
|
||||
bullet = Bullets.pyraFlame;
|
||||
bullet = fragBullet;
|
||||
}},
|
||||
new Weapon("large-artillery"){{
|
||||
y = -13f;
|
||||
x = 20f;
|
||||
reload = 18f;
|
||||
reload = 12f;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
rotateSpeed = 7f;
|
||||
shake = 1f;
|
||||
shootSound = Sounds.shoot;
|
||||
rotate = true;
|
||||
occlusion = 12f;
|
||||
bullet = new ArtilleryBulletType(3.2f, 12){{
|
||||
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;
|
||||
}};
|
||||
bullet = fragBullet;
|
||||
}});
|
||||
}};
|
||||
|
||||
@@ -700,6 +857,7 @@ public class UnitTypes implements ContentList{
|
||||
engineOffset = 5.7f;
|
||||
itemCapacity = 30;
|
||||
range = 50f;
|
||||
isCounted = false;
|
||||
|
||||
mineTier = 1;
|
||||
mineSpeed = 2.5f;
|
||||
@@ -720,6 +878,7 @@ public class UnitTypes implements ContentList{
|
||||
engineOffset = 6.5f;
|
||||
hitsize = 8f;
|
||||
lowAltitude = true;
|
||||
isCounted = false;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 3.5f;
|
||||
@@ -1094,6 +1253,7 @@ public class UnitTypes implements ContentList{
|
||||
hitsize = 0f;
|
||||
health = 1;
|
||||
rotateSpeed = 360f;
|
||||
itemCapacity = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -325,6 +325,10 @@ public class Logic implements ApplicationListener{
|
||||
Events.fire(Trigger.update);
|
||||
universe.updateGlobal();
|
||||
|
||||
if(Core.settings.modified() && !state.isPlaying()){
|
||||
Core.settings.forceSave();
|
||||
}
|
||||
|
||||
if(state.isGame()){
|
||||
if(!net.client()){
|
||||
state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted);
|
||||
|
||||
@@ -366,6 +366,9 @@ public class NetClient implements ApplicationListener{
|
||||
|
||||
@Remote
|
||||
public static void playerDisconnect(int playerid){
|
||||
if(netClient != null){
|
||||
netClient.addRemovedEntity(playerid);
|
||||
}
|
||||
Groups.player.removeByID(playerid);
|
||||
}
|
||||
|
||||
@@ -559,6 +562,22 @@ public class NetClient implements ApplicationListener{
|
||||
//limit to 10 to prevent buffer overflows
|
||||
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];
|
||||
for(int i = 0; i < usedRequests; i++){
|
||||
requests[i] = player.builder().plans().get(i);
|
||||
|
||||
@@ -371,6 +371,11 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentlyKicking[0] != null){
|
||||
player.sendMessage("[scarlet]A vote is already in progress.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(args.length == 0){
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("[orange]Players to kick: \n");
|
||||
@@ -385,9 +390,7 @@ public class NetServer implements ApplicationListener{
|
||||
int id = Strings.parseInt(args[0].substring(1));
|
||||
found = Groups.player.find(p -> p.id() == id);
|
||||
}else{
|
||||
found = Groups.player.find(p -> {
|
||||
return p.name.equalsIgnoreCase(args[0]);
|
||||
});
|
||||
found = Groups.player.find(p -> p.name.equalsIgnoreCase(args[0]));
|
||||
}
|
||||
|
||||
if(found != null){
|
||||
@@ -527,6 +530,10 @@ public class NetServer implements ApplicationListener{
|
||||
public static void serverPacketUnreliable(Player player, String type, String contents){
|
||||
serverPacketReliable(player, type, contents);
|
||||
}
|
||||
|
||||
private static boolean invalid(float f){
|
||||
return Float.isInfinite(f) || Float.isNaN(f);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client, unreliable = true)
|
||||
public static void clientSnapshot(
|
||||
@@ -545,6 +552,16 @@ public class NetServer implements ApplicationListener{
|
||||
NetConnection con = player.con;
|
||||
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;
|
||||
|
||||
if(con.lastReceivedClientTime == 0) con.lastReceivedClientTime = Time.millis() - 16;
|
||||
@@ -614,7 +631,7 @@ public class NetServer implements ApplicationListener{
|
||||
Unit unit = player.unit();
|
||||
|
||||
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()){
|
||||
maxSpeed *= unit.floorSpeedMultiplier();
|
||||
}
|
||||
@@ -682,8 +699,8 @@ public class NetServer implements ApplicationListener{
|
||||
public static void adminRequest(Player player, Player other, AdminAction action){
|
||||
|
||||
if(!player.admin){
|
||||
Log.warn("ACCESS DENIED: Player @ / @ attempted to perform admin action without proper security access.",
|
||||
player.name, player.con.address);
|
||||
Log.warn("ACCESS DENIED: Player @ / @ attempted to perform admin action '@' on '@' without proper security access.",
|
||||
player.name, player.con.address, action.name(), other == null ? null : other.name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -762,6 +779,10 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
if(state.isGame() && net.server()){
|
||||
if(state.rules.pvp){
|
||||
state.serverPaused = isWaitingForPlayers();
|
||||
}
|
||||
|
||||
sync();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,8 @@ public class Renderer implements ApplicationListener{
|
||||
}
|
||||
|
||||
public void draw(){
|
||||
Events.fire(Trigger.preDraw);
|
||||
|
||||
camera.update();
|
||||
|
||||
if(Float.isNaN(camera.position.x) || Float.isNaN(camera.position.y)){
|
||||
@@ -205,6 +207,8 @@ public class Renderer implements ApplicationListener{
|
||||
|
||||
Draw.sort(true);
|
||||
|
||||
Events.fire(Trigger.draw);
|
||||
|
||||
if(pixelator.enabled()){
|
||||
pixelator.register();
|
||||
}
|
||||
@@ -254,6 +258,8 @@ public class Renderer implements ApplicationListener{
|
||||
Draw.reset();
|
||||
Draw.flush();
|
||||
Draw.sort(false);
|
||||
|
||||
Events.fire(Trigger.postDraw);
|
||||
}
|
||||
|
||||
private void drawBackground(){
|
||||
|
||||
@@ -128,6 +128,8 @@ public class UI implements ApplicationListener, Loadable{
|
||||
public void update(){
|
||||
if(disableUI || Core.scene == null) return;
|
||||
|
||||
Events.fire(Trigger.uiDrawBegin);
|
||||
|
||||
Core.scene.act();
|
||||
Core.scene.draw();
|
||||
|
||||
@@ -143,6 +145,8 @@ public class UI implements ApplicationListener, Loadable{
|
||||
control.tutorial.draw();
|
||||
Draw.flush();
|
||||
}
|
||||
|
||||
Events.fire(Trigger.uiDrawEnd);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,12 +225,15 @@ public class UI implements ApplicationListener, Loadable{
|
||||
}
|
||||
|
||||
public TextureRegionDrawable getIcon(String name){
|
||||
if(Icon.icons.containsKey(name)){
|
||||
return Icon.icons.get(name);
|
||||
}
|
||||
if(Icon.icons.containsKey(name)) return Icon.icons.get(name);
|
||||
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){
|
||||
loadAnd("@loading", call);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public class MapEditor{
|
||||
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);
|
||||
if(!hasOverlap(x, y)){
|
||||
tile(x, y).setBlock(drawBlock, drawTeam, 0);
|
||||
tile(x, y).setBlock(drawBlock, drawTeam, rotation);
|
||||
}
|
||||
}else{
|
||||
boolean isFloor = drawBlock.isFloor() && drawBlock != Blocks.air;
|
||||
|
||||
@@ -110,18 +110,13 @@ public class MapRenderer implements Disposable{
|
||||
if(wall != Blocks.air && wall.synthetic()){
|
||||
region = !Core.atlas.isFound(wall.editorIcon()) || !center ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||
|
||||
if(wall.rotate){
|
||||
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;
|
||||
float width = region.getWidth() * Draw.scl, height = region.getHeight() * Draw.scl;
|
||||
|
||||
mesh.draw(idxWall, region,
|
||||
wx * tilesize + wall.offset + (tilesize - width) / 2f,
|
||||
wy * tilesize + wall.offset + (tilesize - height) / 2f,
|
||||
width, height);
|
||||
}
|
||||
mesh.draw(idxWall, region,
|
||||
wx * tilesize + wall.offset + (tilesize - width) / 2f,
|
||||
wy * tilesize + wall.offset + (tilesize - height) / 2f,
|
||||
width, height,
|
||||
tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg() - 90);
|
||||
}else{
|
||||
region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)];
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import static mindustry.Vars.*;
|
||||
|
||||
/** Utility class for damaging in an area. */
|
||||
public class Damage{
|
||||
private static Tile furthest;
|
||||
private static Rect rect = new Rect();
|
||||
private static Rect hitrect = new Rect();
|
||||
private static Vec2 tr = new Vec2();
|
||||
@@ -30,24 +31,26 @@ public class Damage{
|
||||
private static Unit tmpUnit;
|
||||
|
||||
/** 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){
|
||||
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
|
||||
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)));
|
||||
}
|
||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color, boolean damage){
|
||||
if(damage){
|
||||
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
|
||||
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++){
|
||||
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), Bullets.fireball.damage, 1, 1));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
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++){
|
||||
int f = i;
|
||||
Time.run(i * 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));
|
||||
});
|
||||
for(int i = 0; i < waves; i++){
|
||||
int f = i;
|
||||
Time.run(i * 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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
collideLine(hitter, team, effect, x, y, angle, length, false);
|
||||
}
|
||||
@@ -87,7 +107,7 @@ public class Damage{
|
||||
tr.trns(angle, length);
|
||||
Intc2 collider = (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);
|
||||
collidedBlocks.add(tile.pos());
|
||||
hitter.type.hit(hitter, tile.x, tile.y);
|
||||
|
||||
@@ -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 + "!");
|
||||
T t = map.get(id);
|
||||
if(t != null){ //remove if present in map already
|
||||
remove(t);
|
||||
t.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public class Fires{
|
||||
|
||||
/** Start a fire on the tile. If there already is a file there, refreshes its lifetime. */
|
||||
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());
|
||||
|
||||
|
||||
@@ -19,8 +19,17 @@ public class Units{
|
||||
private static boolean boolResult;
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void unitDeath(Unit unit){
|
||||
unit.killed();
|
||||
public static void unitDeath(int uid){
|
||||
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)
|
||||
|
||||
@@ -23,7 +23,6 @@ public class ForceFieldAbility implements Ability{
|
||||
|
||||
private float realRad;
|
||||
private Unit paramUnit;
|
||||
private boolean hadShield;
|
||||
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){
|
||||
trait.absorb();
|
||||
@@ -32,6 +31,8 @@ public class ForceFieldAbility implements Ability{
|
||||
//break shield
|
||||
if(paramUnit.shield <= trait.damage()){
|
||||
paramUnit.shield -= cooldown * regen;
|
||||
|
||||
Fx.shieldBreak.at(paramUnit.x, paramUnit.y, radius, paramUnit.team.color);
|
||||
}
|
||||
|
||||
paramUnit.shield -= trait.damage();
|
||||
@@ -54,13 +55,6 @@ public class ForceFieldAbility implements Ability{
|
||||
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){
|
||||
unit.timer2 = Mathf.lerpDelta(unit.timer2, 1f, 0.06f);
|
||||
paramUnit = unit;
|
||||
|
||||
@@ -74,7 +74,7 @@ public abstract class BulletType extends Content{
|
||||
|
||||
public float fragCone = 360f;
|
||||
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 Color hitColor = Color.white;
|
||||
|
||||
@@ -92,6 +92,7 @@ public abstract class BulletType extends Content{
|
||||
public float homingPower = 0f;
|
||||
public float homingRange = 50f;
|
||||
|
||||
public Color lightningColor = Pal.surge;
|
||||
public int lightning;
|
||||
public int lightningLength = 5;
|
||||
/** 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++){
|
||||
float len = Mathf.random(1f, 7f);
|
||||
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++){
|
||||
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);
|
||||
}
|
||||
|
||||
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){
|
||||
return create(parent.owner(), parent.team, x, y, angle, velocityScl);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class HealBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public boolean collides(Bullet b, Building tile){
|
||||
return tile.team() != b.team || tile.healthf() < 1f;
|
||||
return tile.team != b.team || tile.healthf() < 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,7 +46,7 @@ public class HealBulletType extends BulletType{
|
||||
public void hitTile(Bullet b, Building tile){
|
||||
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);
|
||||
tile.heal(healPercent / 100f * tile.maxHealth());
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.world;
|
||||
|
||||
public class LaserBulletType extends BulletType{
|
||||
protected static Tile furthest;
|
||||
|
||||
@@ -49,24 +47,13 @@ public class LaserBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
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, hitEffect, b.x, b.y, b.rotation(), resultLength);
|
||||
if(furthest != null) b.data(resultLength);
|
||||
|
||||
float resultLength = Damage.collideLaser(b, length);
|
||||
laserEffect.at(b.x, b.y, b.rotation(), resultLength * 0.75f);
|
||||
}
|
||||
|
||||
@Override
|
||||
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 baseLen = realLength * f;
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ShrapnelBulletType extends BulletType{
|
||||
public Color fromColor = Color.white, toColor = Pal.lancerLaser;
|
||||
|
||||
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(){
|
||||
speed = 0.01f;
|
||||
@@ -24,23 +24,26 @@ public class ShrapnelBulletType extends BulletType{
|
||||
lifetime = 10f;
|
||||
despawnEffect = Fx.none;
|
||||
pierce = true;
|
||||
keepVelocity = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length);
|
||||
Damage.collideLaser(b, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b){
|
||||
float realLength = b.fdata;
|
||||
|
||||
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);
|
||||
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, 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);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class BlockUnitComp implements Unitc{
|
||||
@Override
|
||||
public void update(){
|
||||
if(tile != null){
|
||||
team = tile.team();
|
||||
team = tile.team;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ abstract class BlockUnitComp implements Unitc{
|
||||
public void team(Team team){
|
||||
if(tile != null && this.team != team){
|
||||
this.team = team;
|
||||
if(tile.team() != team){
|
||||
if(tile.team != team){
|
||||
tile.team(team);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,6 @@ abstract class BuilderComp implements Unitc{
|
||||
boolean shouldSkip(BuildPlan request, @Nullable Building core){
|
||||
//requests that you have at least *started* are considered
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,8 +135,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
public final void writeBase(Writes write){
|
||||
write.f(health);
|
||||
write.b(rotation);
|
||||
write.b(rotation | 0b10000000);
|
||||
write.b(team.id);
|
||||
write.b(0); //extra padding for later use
|
||||
if(items != null) items.write(write);
|
||||
if(power != null) power.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){
|
||||
health = read.f();
|
||||
rotation = read.b();
|
||||
byte rot = read.b();
|
||||
team = Team.get(read.b());
|
||||
if(items != null) items.read(read);
|
||||
if(power != null) power.read(read);
|
||||
if(liquids != null) liquids.read(read);
|
||||
if(cons != null) cons.read(read);
|
||||
|
||||
rotation = rot & 0b01111111;
|
||||
boolean legacy = true;
|
||||
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){
|
||||
@@ -410,7 +419,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
int trns = block.size/2 + 1;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
@@ -431,7 +440,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
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);
|
||||
incrementDump(proximity.size);
|
||||
return true;
|
||||
@@ -510,34 +519,31 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
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)){
|
||||
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(flow > 0f && ofract <= fract && next.acceptLiquid(base(), liquid, flow)){
|
||||
next.handleLiquid(base(), liquid, flow);
|
||||
liquids.remove(liquid, flow);
|
||||
return flow;
|
||||
}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)){
|
||||
next.handleLiquid(base(), liquid, flow);
|
||||
liquids.remove(liquid, flow);
|
||||
return flow;
|
||||
}else if(ofract > 0.1f && fract > 0.1f){
|
||||
//TODO these are incorrect effect positions
|
||||
float fx = (x + next.x) / 2f, fy = (y + next.y) / 2f;
|
||||
|
||||
Liquid other = next.liquids().current();
|
||||
if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){
|
||||
damage(1 * Time.delta);
|
||||
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);
|
||||
}
|
||||
Liquid other = next.liquids.current();
|
||||
if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){
|
||||
damage(1 * Time.delta);
|
||||
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++){
|
||||
incrementDump(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);
|
||||
return;
|
||||
}
|
||||
@@ -586,7 +592,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(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);
|
||||
return true;
|
||||
}
|
||||
@@ -619,7 +625,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int ii = 0; ii < content.items().size; 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);
|
||||
items.remove(item, 1);
|
||||
incrementDump(proximity.size);
|
||||
@@ -627,7 +633,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
}
|
||||
}
|
||||
}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);
|
||||
items.remove(todump, 1);
|
||||
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. */
|
||||
public boolean moveForward(Item item){
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
@@ -887,7 +893,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
power += this.power.status * block.consumes.getPower().capacity;
|
||||
}
|
||||
|
||||
if(block.hasLiquids){
|
||||
if(block.hasLiquids && state.rules.damageExplosions){
|
||||
|
||||
liquids.each((liquid, amount) -> {
|
||||
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){
|
||||
Effect.rubble(x, y, block.size);
|
||||
}
|
||||
@@ -960,7 +967,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
table.row();
|
||||
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){
|
||||
String ps = " " + StatUnit.perSecond.localized();
|
||||
@@ -998,9 +1005,21 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
if(liquids != null){
|
||||
table.row();
|
||||
table.table(l -> {
|
||||
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);
|
||||
boolean[] had = {false};
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
Object data;
|
||||
BulletType type;
|
||||
float damage;
|
||||
float fdata;
|
||||
|
||||
@Override
|
||||
public void getCollisions(Cons<QuadTree> consumer){
|
||||
|
||||
@@ -15,14 +15,14 @@ import static mindustry.Vars.*;
|
||||
|
||||
@EntityDef(value = {Firec.class}, pooled = 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;
|
||||
|
||||
@Import float time, lifetime, x, y;
|
||||
|
||||
Tile tile;
|
||||
private Block block;
|
||||
private float baseFlammability = -1, puddleFlammability;
|
||||
private transient Block block;
|
||||
private transient float baseFlammability = -1, puddleFlammability;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
@@ -99,4 +99,9 @@ abstract class FireComp implements Timedc, Posc, Firec{
|
||||
public void afterRead(){
|
||||
Fires.register(base());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSync(){
|
||||
Fires.register(base());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import static mindustry.Vars.net;
|
||||
abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
||||
private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2();
|
||||
|
||||
@Import float x, y;
|
||||
@Import float x, y, speedMultiplier;
|
||||
@Import Vec2 vel;
|
||||
|
||||
@SyncLocal float elevation;
|
||||
@@ -56,7 +56,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
||||
|
||||
float floorSpeedMultiplier(){
|
||||
Floor on = isFlying() || hovering ? Blocks.air.asFloor() : floorOn();
|
||||
return on.speedMultiplier;
|
||||
return on.speedMultiplier * speedMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,7 +33,7 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
|
||||
@Override
|
||||
public void update(){
|
||||
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;
|
||||
|
||||
@@ -95,7 +95,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc{
|
||||
Building tile = payload.entity;
|
||||
int tx = Vars.world.toTile(x - tile.block().offset), ty = Vars.world.toTile(y - tile.block().offset);
|
||||
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;
|
||||
payload.place(on, rot);
|
||||
|
||||
|
||||
@@ -45,11 +45,16 @@ abstract class PosComp implements Position{
|
||||
return tile == null || tile.block() != Blocks.air ? (Floor)Blocks.air : tile.floor();
|
||||
}
|
||||
|
||||
Block blockOn(){
|
||||
Block blockOn(){
|
||||
Tile tile = tileOn();
|
||||
return tile == null ? Blocks.air : tile.block();
|
||||
}
|
||||
|
||||
boolean onSolid(){
|
||||
Tile tile = tileOn();
|
||||
return tile != null && tile.solid();
|
||||
}
|
||||
|
||||
@Nullable Tile tileOn(){
|
||||
return world.tileWorld(x, y);
|
||||
}
|
||||
|
||||
@@ -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 boolean dead;
|
||||
@Import Team team;
|
||||
@Import int id;
|
||||
|
||||
private UnitController controller;
|
||||
private UnitType type;
|
||||
@@ -223,7 +224,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
//apply knockback based on spawns
|
||||
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()){
|
||||
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));
|
||||
@@ -275,10 +276,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
damageContinuous(floor.damageTaken);
|
||||
}
|
||||
|
||||
if(!net.client() && tile.solid()){
|
||||
if(tile.solid()){
|
||||
if(type.canBoost){
|
||||
elevation = 1f;
|
||||
}else{
|
||||
}else if(!net.client()){
|
||||
kill();
|
||||
}
|
||||
}
|
||||
@@ -314,7 +315,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
public void destroy(){
|
||||
float explosiveness = 2f + item().explosiveness * 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;
|
||||
|
||||
@@ -389,6 +390,6 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
if(dead || net.client()) return;
|
||||
|
||||
//deaths are synced; this calls killed()
|
||||
Call.unitDeath(base());
|
||||
Call.unitDeath(id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ package mindustry.entities.units;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
@@ -33,6 +35,10 @@ public class AIController implements UnitController{
|
||||
updateMovement();
|
||||
}
|
||||
|
||||
protected UnitCommand command(){
|
||||
return unit.team.data().command;
|
||||
}
|
||||
|
||||
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){
|
||||
circle(target, circleLength, unit.type().speed);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package mindustry.entities.units;
|
||||
import arc.*;
|
||||
|
||||
public enum UnitCommand{
|
||||
attack, retreat, rally, idle;
|
||||
attack, rally, idle;
|
||||
|
||||
private final String localized;
|
||||
public static final UnitCommand[] all = values();
|
||||
|
||||
@@ -30,7 +30,12 @@ public class EventType{
|
||||
openWiki,
|
||||
teamCoreDamage,
|
||||
socketConfigChanged,
|
||||
update
|
||||
update,
|
||||
draw,
|
||||
preDraw,
|
||||
postDraw,
|
||||
uiDrawBegin,
|
||||
uiDrawEnd
|
||||
}
|
||||
|
||||
public static class WinEvent{}
|
||||
@@ -77,7 +82,6 @@ public class EventType{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class CommandIssueEvent{
|
||||
public final Building tile;
|
||||
public final UnitCommand command;
|
||||
|
||||
@@ -38,6 +38,10 @@ public class Rules{
|
||||
public boolean canGameOver = true;
|
||||
/** Whether reactors can explode and damage other blocks. */
|
||||
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. */
|
||||
public boolean unitAmmo = false;
|
||||
/** How fast unit pads build units. */
|
||||
|
||||
@@ -102,7 +102,7 @@ public class Teams{
|
||||
}
|
||||
|
||||
public void registerCore(CoreBuild core){
|
||||
TeamData data = get(core.team());
|
||||
TeamData data = get(core.team);
|
||||
//add core if not present
|
||||
if(!data.cores.contains(core)){
|
||||
data.cores.add(core);
|
||||
@@ -117,7 +117,7 @@ public class Teams{
|
||||
}
|
||||
|
||||
public void unregisterCore(CoreBuild entity){
|
||||
TeamData data = get(entity.team());
|
||||
TeamData data = get(entity.team);
|
||||
//remove core
|
||||
data.cores.remove(entity);
|
||||
//unregister in active list
|
||||
@@ -181,7 +181,7 @@ public class Teams{
|
||||
|
||||
/** @return whether this team is controlled by the AI and builds bases. */
|
||||
public boolean hasAI(){
|
||||
return state.rules.attackMode && team.rules().ai;
|
||||
return team.rules().ai;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -140,7 +140,7 @@ public class Universe{
|
||||
sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed);
|
||||
|
||||
//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
|
||||
Events.fire(new SectorLoseEvent(sector));
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ public class BlockRenderer implements Disposable{
|
||||
Draw.z(Layer.block);
|
||||
}
|
||||
|
||||
if(entity.team() != player.team()){
|
||||
if(entity.team != player.team()){
|
||||
entity.drawTeam();
|
||||
Draw.z(Layer.block);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ public class Layer{
|
||||
|
||||
public static final float
|
||||
|
||||
//min layer
|
||||
min = -11,
|
||||
|
||||
//background, which may be planets or an image or nothing at all
|
||||
background = -10,
|
||||
|
||||
@@ -81,7 +84,10 @@ public class Layer{
|
||||
end = 200,
|
||||
|
||||
//things after pixelation - used for text
|
||||
endPixeled = 210
|
||||
endPixeled = 210,
|
||||
|
||||
//max layer
|
||||
max = 220
|
||||
|
||||
;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class OverlayRenderer{
|
||||
if(dst < state.rules.enemyCoreBuildRadius * 2.2f){
|
||||
Draw.color(Color.darkGray);
|
||||
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);
|
||||
}
|
||||
});
|
||||
@@ -132,23 +132,25 @@ public class OverlayRenderer{
|
||||
//draw selected block
|
||||
if(input.block == null && !Core.scene.hasMouse()){
|
||||
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()){
|
||||
tile.drawSelect();
|
||||
if(!tile.enabled && tile.block.drawDisabled){
|
||||
tile.drawDisabled();
|
||||
if(build != null && build.team == player.team()){
|
||||
build.drawSelect();
|
||||
if(!build.enabled && build.block.drawDisabled){
|
||||
build.drawDisabled();
|
||||
}
|
||||
|
||||
if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate && tile.interactable(player.team())){
|
||||
control.input.drawArrow(tile.block(), tile.tileX(), tile.tileY(), tile.rotation, true);
|
||||
if(Core.input.keyDown(Binding.rotateplaced) && build.block().rotate && build.interactable(player.team())){
|
||||
control.input.drawArrow(build.block(), build.tileX(), build.tileY(), build.rotation, true);
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input.drawOverSelect();
|
||||
|
||||
//draw selection overlay when dropping item
|
||||
if(input.isDroppingItem()){
|
||||
Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
||||
|
||||
@@ -9,6 +9,8 @@ public class Pal{
|
||||
command = Color.valueOf("eab678"),
|
||||
|
||||
sap = Color.valueOf("665c9f"),
|
||||
sapBullet = Color.valueOf("bf92f9"),
|
||||
sapBulletBack = Color.valueOf("6d56bf"),
|
||||
|
||||
spore = Color.valueOf("7457ce"),
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import arc.input.*;
|
||||
public enum Binding implements KeyBind{
|
||||
move_x(new Axis(KeyCode.a, KeyCode.d), "general"),
|
||||
move_y(new Axis(KeyCode.s, KeyCode.w)),
|
||||
mouse_move(KeyCode.mouseForward),
|
||||
mouse_move(KeyCode.mouseBack),
|
||||
pan(KeyCode.mouseForward),
|
||||
|
||||
boost(KeyCode.shiftLeft),
|
||||
control(KeyCode.controlLeft),
|
||||
|
||||
@@ -27,24 +27,35 @@ import static mindustry.Vars.*;
|
||||
import static mindustry.input.PlaceMode.*;
|
||||
|
||||
public class DesktopInput extends InputHandler{
|
||||
private Vec2 movement = new Vec2();
|
||||
public Vec2 movement = new Vec2();
|
||||
/** Current cursor type. */
|
||||
private Cursor cursorType = SystemCursor.arrow;
|
||||
public Cursor cursorType = SystemCursor.arrow;
|
||||
/** Position where the player started dragging a line. */
|
||||
private int selectX, selectY, schemX, schemY;
|
||||
public int selectX, selectY, schemX, schemY;
|
||||
/** Last known line positions.*/
|
||||
private int lastLineX, lastLineY, schematicX, schematicY;
|
||||
public int lastLineX, lastLineY, schematicX, schematicY;
|
||||
/** Whether selecting mode is active. */
|
||||
private PlaceMode mode;
|
||||
public PlaceMode mode;
|
||||
/** Animation scale for line. */
|
||||
private float selectScale;
|
||||
public float selectScale;
|
||||
/** Selected build request for movement. */
|
||||
private @Nullable BuildPlan sreq;
|
||||
public @Nullable BuildPlan sreq;
|
||||
/** 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
|
||||
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 -> {
|
||||
t.bottom();
|
||||
t.visible(() -> {
|
||||
@@ -77,15 +88,6 @@ public class DesktopInput extends InputHandler{
|
||||
});
|
||||
}).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
|
||||
@@ -132,14 +134,12 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
|
||||
//draw schematic requests
|
||||
for(BuildPlan request : selectRequests){
|
||||
request.animScale = 1f;
|
||||
drawRequest(request);
|
||||
}
|
||||
selectRequests.each(req -> {
|
||||
req.animScale = 1f;
|
||||
drawRequest(req);
|
||||
});
|
||||
|
||||
for(BuildPlan request : selectRequests){
|
||||
drawOverRequest(request);
|
||||
}
|
||||
selectRequests.each(this::drawOverRequest);
|
||||
|
||||
if(player.isBuilder()){
|
||||
//draw things that may be placed soon
|
||||
@@ -180,22 +180,35 @@ public class DesktopInput extends InputHandler{
|
||||
ui.listfrag.toggle();
|
||||
}
|
||||
|
||||
//TODO awful UI state checking code
|
||||
if((player.dead() || state.isPaused()) && !ui.chatfrag.shown()){
|
||||
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));
|
||||
boolean panCam = false;
|
||||
float camSpeed = !Core.input.keyDown(Binding.boost) ? panSpeed : panBoostSpeed;
|
||||
|
||||
if(Core.input.keyDown(Binding.mouse_move)){
|
||||
Core.camera.position.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * camSpeed;
|
||||
Core.camera.position.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * camSpeed;
|
||||
}
|
||||
if(input.keyDown(Binding.pan)){
|
||||
panCam = true;
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if(!scene.hasMouse()){
|
||||
@@ -327,22 +340,24 @@ public class DesktopInput extends InputHandler{
|
||||
table.row();
|
||||
table.left().margin(0f).defaults().size(48f).left();
|
||||
|
||||
//TODO localize these
|
||||
|
||||
table.button(Icon.paste, Styles.clearPartiali, () -> {
|
||||
ui.schematics.show();
|
||||
}).tooltip("Schematics");
|
||||
}).tooltip("@schematics");
|
||||
|
||||
table.button(Icon.tree, Styles.clearPartiali, () -> {
|
||||
ui.research.show();
|
||||
}).visible(() -> state.isCampaign()).tooltip("Research");
|
||||
}).visible(() -> state.isCampaign()).tooltip("@research");
|
||||
|
||||
table.button(Icon.map, Styles.clearPartiali, () -> {
|
||||
ui.planet.show();
|
||||
}).visible(() -> state.isCampaign()).tooltip("Planet Map");
|
||||
}).visible(() -> state.isCampaign()).tooltip("@planetmap");
|
||||
|
||||
table.button(Icon.up, Styles.clearPartiali, () -> {
|
||||
ui.planet.show(state.getSector(), player.team().core());
|
||||
}).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(){
|
||||
@@ -555,6 +570,8 @@ public class DesktopInput extends InputHandler{
|
||||
|
||||
@Override
|
||||
public void updateState(){
|
||||
super.updateState();
|
||||
|
||||
if(state.isMenu()){
|
||||
droppingItem = false;
|
||||
mode = none;
|
||||
@@ -574,7 +591,7 @@ public class DesktopInput extends InputHandler{
|
||||
//limit speed to minimum formation speed to preserve formation
|
||||
if(unit instanceof Commanderc && ((Commanderc)unit).isCommanding()){
|
||||
//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;
|
||||
|
||||
@@ -62,13 +62,13 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
public boolean isBuilding = true, buildWasAutoPaused = false;
|
||||
public @Nullable UnitType controlledType;
|
||||
|
||||
protected @Nullable Schematic lastSchematic;
|
||||
protected GestureDetector detector;
|
||||
protected PlaceLine line = new PlaceLine();
|
||||
protected BuildPlan resultreq;
|
||||
protected BuildPlan brequest = new BuildPlan();
|
||||
protected Seq<BuildPlan> lineRequests = new Seq<>();
|
||||
protected Seq<BuildPlan> selectRequests = new Seq<>();
|
||||
public @Nullable Schematic lastSchematic;
|
||||
public GestureDetector detector;
|
||||
public PlaceLine line = new PlaceLine();
|
||||
public BuildPlan resultreq;
|
||||
public BuildPlan brequest = new BuildPlan();
|
||||
public Seq<BuildPlan> lineRequests = new Seq<>();
|
||||
public Seq<BuildPlan> selectRequests = new Seq<>();
|
||||
|
||||
//methods to override
|
||||
|
||||
@@ -126,7 +126,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
Unit unit = player.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)){
|
||||
//pick up block directly
|
||||
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.deathTimer = 61f;
|
||||
((CoreBuild)((BlockUnitc)unit).tile()).requestSpawn(player);
|
||||
|
||||
}else if(unit == null){ //just clear the unit (is this used?)
|
||||
player.clearUnit();
|
||||
//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(){
|
||||
|
||||
if(state.isMenu()){
|
||||
controlledType = null;
|
||||
}
|
||||
}
|
||||
|
||||
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){
|
||||
Drawf.selected(x, y, block, color);
|
||||
}
|
||||
@@ -538,11 +546,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
if(test.get(req)) return req;
|
||||
}
|
||||
|
||||
for(BuildPlan req : selectRequests){
|
||||
if(test.get(req)) return req;
|
||||
}
|
||||
|
||||
return null;
|
||||
return selectRequests.find(test);
|
||||
}
|
||||
|
||||
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);
|
||||
if(tile instanceof ControlBlock && tile.team() == player.team()){
|
||||
if(tile instanceof ControlBlock && tile.team == player.team()){
|
||||
return ((ControlBlock)tile).unit();
|
||||
}
|
||||
|
||||
|
||||