mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-12-06 02:40:23 -08:00
Support for unit missiles
This commit is contained in:
parent
f5e9df1265
commit
0b7d8f371e
16 changed files with 276 additions and 77 deletions
|
|
@ -26,6 +26,7 @@ mindustry.type.Weather.WeatherStateComp=14
|
||||||
mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=15
|
mindustry.world.blocks.campaign.LaunchPad.LaunchPayloadComp=15
|
||||||
mindustry.world.blocks.campaign.PayloadLaunchPad.LargeLaunchPayloadComp=34
|
mindustry.world.blocks.campaign.PayloadLaunchPad.LargeLaunchPayloadComp=34
|
||||||
mindustry.world.blocks.defense.ForceProjector.ForceDrawComp=22
|
mindustry.world.blocks.defense.ForceProjector.ForceDrawComp=22
|
||||||
|
missile=39
|
||||||
mono=16
|
mono=16
|
||||||
nova=17
|
nova=17
|
||||||
oct=26
|
oct=26
|
||||||
|
|
@ -36,5 +37,7 @@ quasar=32
|
||||||
risso=20
|
risso=20
|
||||||
scuttler=35
|
scuttler=35
|
||||||
spiroct=21
|
spiroct=21
|
||||||
|
timed=38
|
||||||
|
timedDef=37
|
||||||
toxopid=33
|
toxopid=33
|
||||||
vela=25
|
vela=25
|
||||||
1
annotations/src/main/resources/revisions/missile/0.json
Normal file
1
annotations/src/main/resources/revisions/missile/0.json
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
{fields:[{name:ammo,type:float},{name:controller,type:mindustry.entities.units.UnitController},{name:elevation,type:float},{name:flag,type:double},{name:health,type:float},{name:isShooting,type:boolean},{name:lifetime,type:float},{name:mineTile,type:mindustry.world.Tile},{name:mounts,type:"mindustry.entities.units.WeaponMount[]"},{name:plans,type:arc.struct.Queue<mindustry.entities.units.BuildPlan>},{name:rotation,type:float},{name:shield,type:float},{name:spawnedByCore,type:boolean},{name:stack,type:mindustry.type.ItemStack},{name:statuses,type:arc.struct.Seq<mindustry.entities.units.StatusEntry>},{name:team,type:mindustry.game.Team},{name:time,type:float},{name:type,type:mindustry.type.UnitType},{name:updateBuilding,type:boolean},{name:vel,type:arc.math.geom.Vec2},{name:x,type:float},{name:y,type:float}]}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 947 B After Width: | Height: | Size: 1.1 KiB |
34
core/src/mindustry/ai/types/MissileAI.java
Normal file
34
core/src/mindustry/ai/types/MissileAI.java
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
package mindustry.ai.types;
|
||||||
|
|
||||||
|
import mindustry.entities.units.*;
|
||||||
|
|
||||||
|
public class MissileAI extends AIController{
|
||||||
|
|
||||||
|
//TODO UNPREDICTABLE TARGETING
|
||||||
|
@Override
|
||||||
|
public void updateMovement(){
|
||||||
|
unloadPayloads();
|
||||||
|
|
||||||
|
if(target != null){
|
||||||
|
unit.lookAt(target);
|
||||||
|
|
||||||
|
var build = unit.buildOn();
|
||||||
|
|
||||||
|
//kill instantly on building contact
|
||||||
|
//TODO kill on target unit contact too
|
||||||
|
if(build != null && build == target){
|
||||||
|
unit.kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//move forward forever
|
||||||
|
unit.moveAt(vec.trns(unit.rotation, unit.speed()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean retarget(){
|
||||||
|
//more frequent retarget. TODO lag?
|
||||||
|
return timer.get(timerTarget, 10f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -72,6 +72,9 @@ public class UnitTypes{
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
//missile definition, needed for codegen
|
||||||
|
public static @EntityDef({Unitc.class, TimedKillc.class}) UnitType missile;
|
||||||
|
|
||||||
//region neoplasm
|
//region neoplasm
|
||||||
|
|
||||||
public static @EntityDef({Unitc.class, Crawlc.class}) UnitType scuttler;
|
public static @EntityDef({Unitc.class, Crawlc.class}) UnitType scuttler;
|
||||||
|
|
@ -598,7 +601,11 @@ public class UnitTypes{
|
||||||
shootSound = Sounds.explosion;
|
shootSound = Sounds.explosion;
|
||||||
x = shootY = 0f;
|
x = shootY = 0f;
|
||||||
mirror = false;
|
mirror = false;
|
||||||
bullet = new BombBulletType(0f, 0f, "clear"){{
|
bullet = new BulletType(){{
|
||||||
|
collidesTiles = false;
|
||||||
|
collides = false;
|
||||||
|
hitSound = Sounds.explosion;
|
||||||
|
|
||||||
hitEffect = Fx.pulverize;
|
hitEffect = Fx.pulverize;
|
||||||
lifetime = 10f;
|
lifetime = 10f;
|
||||||
speed = 1f;
|
speed = 1f;
|
||||||
|
|
@ -1461,7 +1468,6 @@ public class UnitTypes{
|
||||||
health = 280;
|
health = 280;
|
||||||
accel = 0.4f;
|
accel = 0.4f;
|
||||||
rotateSpeed = 3.3f;
|
rotateSpeed = 3.3f;
|
||||||
trailLength = 20;
|
|
||||||
rotateShooting = false;
|
rotateShooting = false;
|
||||||
|
|
||||||
armor = 2f;
|
armor = 2f;
|
||||||
|
|
@ -2413,6 +2419,9 @@ public class UnitTypes{
|
||||||
}});
|
}});
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region erekir - core
|
||||||
|
|
||||||
//TODO bad name
|
//TODO bad name
|
||||||
evoke = new UnitType("evoke"){{
|
evoke = new UnitType("evoke"){{
|
||||||
defaultController = BuilderAI::new;
|
defaultController = BuilderAI::new;
|
||||||
|
|
@ -2438,8 +2447,8 @@ public class UnitTypes{
|
||||||
engineSize = 0;
|
engineSize = 0;
|
||||||
|
|
||||||
setEnginesMirror(
|
setEnginesMirror(
|
||||||
new UnitEngine(21 / 4f, 19 / 4f, 2.2f, 45f),
|
new UnitEngine(21 / 4f, 19 / 4f, 2.2f, 45f),
|
||||||
new UnitEngine(23 / 4f, -22 / 4f, 2.2f, 315f)
|
new UnitEngine(23 / 4f, -22 / 4f, 2.2f, 315f)
|
||||||
);
|
);
|
||||||
|
|
||||||
weapons.add(new Weapon(){{
|
weapons.add(new Weapon(){{
|
||||||
|
|
@ -2470,6 +2479,30 @@ public class UnitTypes{
|
||||||
smokeEffect = Fx.shootBigSmoke;
|
smokeEffect = Fx.shootBigSmoke;
|
||||||
buildingDamageMultiplier = 0.4f;
|
buildingDamageMultiplier = 0.4f;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
//TODO REMOVE
|
||||||
|
/*
|
||||||
|
unitSpawned = new MissileUnitType("duo"){{
|
||||||
|
trailScl = 1.1f;
|
||||||
|
speed = 3f;
|
||||||
|
weapons.add(new Weapon(){{
|
||||||
|
shootOnDeath = true;
|
||||||
|
bullet = new BulletType(){{
|
||||||
|
collidesTiles = false;
|
||||||
|
collides = false;
|
||||||
|
hitSound = Sounds.explosion;
|
||||||
|
|
||||||
|
lifetime = 10f;
|
||||||
|
speed = 1f;
|
||||||
|
splashDamageRadius = 55f;
|
||||||
|
instantDisappear = true;
|
||||||
|
splashDamage = 90f;
|
||||||
|
killShooter = true;
|
||||||
|
hittable = false;
|
||||||
|
collidesAir = true;
|
||||||
|
}};
|
||||||
|
}});
|
||||||
|
}};*/
|
||||||
}});
|
}});
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|
@ -2597,8 +2630,6 @@ public class UnitTypes{
|
||||||
}});
|
}});
|
||||||
i ++;
|
i ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ abstract class CommanderComp implements Entityc, Posc{
|
||||||
units.clear();
|
units.clear();
|
||||||
|
|
||||||
Units.nearby(team, x, y, type.commandRadius, u -> {
|
Units.nearby(team, x, y, type.commandRadius, u -> {
|
||||||
if(u.isAI() && include.get(u) && u != self() && u.type.flying == type.flying && u.hitSize <= hitSize * 1.1f){
|
if(u.isAI() && include.get(u) && u != self() && u.type.flying == type.flying && u.hitSize <= hitSize * 1.1f && u.type.playerControllable){
|
||||||
units.add(u);
|
units.add(u);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import arc.util.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.content.*;
|
import mindustry.content.*;
|
||||||
import mindustry.core.*;
|
import mindustry.core.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
import mindustry.world.*;
|
import mindustry.world.*;
|
||||||
import mindustry.world.blocks.environment.*;
|
import mindustry.world.blocks.environment.*;
|
||||||
|
|
||||||
|
|
@ -50,9 +51,9 @@ abstract class PosComp implements Position{
|
||||||
return tile == null ? Blocks.air : tile.block();
|
return tile == null ? Blocks.air : tile.block();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean onSolid(){
|
@Nullable
|
||||||
Tile tile = tileOn();
|
Building buildOn(){
|
||||||
return tile == null || tile.solid();
|
return world.buildWorld(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
@ -60,6 +61,11 @@ abstract class PosComp implements Position{
|
||||||
return world.tileWorld(x, y);
|
return world.tileWorld(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean onSolid(){
|
||||||
|
Tile tile = tileOn();
|
||||||
|
return tile == null || tile.solid();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getX(){
|
public float getX(){
|
||||||
return x;
|
return x;
|
||||||
|
|
|
||||||
28
core/src/mindustry/entities/comp/TimedKillComp.java
Normal file
28
core/src/mindustry/entities/comp/TimedKillComp.java
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
|
import arc.math.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
|
||||||
|
//basically just TimedComp but kills instead of removing.
|
||||||
|
@Component
|
||||||
|
abstract class TimedKillComp implements Entityc, Healthc, Scaled{
|
||||||
|
float time, lifetime;
|
||||||
|
|
||||||
|
//called last so pooling and removal happens then.
|
||||||
|
@MethodPriority(100)
|
||||||
|
@Override
|
||||||
|
public void update(){
|
||||||
|
time = Math.min(time + Time.delta, lifetime);
|
||||||
|
|
||||||
|
if(time >= lifetime){
|
||||||
|
kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float fin(){
|
||||||
|
return time / lifetime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package mindustry.entities.comp;
|
|
||||||
|
|
||||||
import arc.math.*;
|
|
||||||
import mindustry.annotations.Annotations.*;
|
|
||||||
import mindustry.gen.*;
|
|
||||||
import mindustry.graphics.*;
|
|
||||||
import mindustry.type.*;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
abstract class TrailComp implements Unitc{
|
|
||||||
@Import UnitType type;
|
|
||||||
@Import float x, y, rotation;
|
|
||||||
|
|
||||||
transient Trail trail = new Trail(6);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(){
|
|
||||||
trail.length = type.trailLength;
|
|
||||||
|
|
||||||
float scale = elevation();
|
|
||||||
float offset = type.engineOffset/2f + type.engineOffset/2f*scale;
|
|
||||||
|
|
||||||
float cx = x + Angles.trnsx(rotation + 180, offset), cy = y + Angles.trnsy(rotation + 180, offset);
|
|
||||||
trail.update(cx, cy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,6 +20,7 @@ import mindustry.entities.units.*;
|
||||||
import mindustry.game.EventType.*;
|
import mindustry.game.EventType.*;
|
||||||
import mindustry.game.*;
|
import mindustry.game.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
import mindustry.graphics.*;
|
||||||
import mindustry.logic.*;
|
import mindustry.logic.*;
|
||||||
import mindustry.type.*;
|
import mindustry.type.*;
|
||||||
import mindustry.ui.*;
|
import mindustry.ui.*;
|
||||||
|
|
@ -46,6 +47,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||||
boolean spawnedByCore;
|
boolean spawnedByCore;
|
||||||
double flag;
|
double flag;
|
||||||
|
|
||||||
|
transient @Nullable Trail trail;
|
||||||
|
|
||||||
transient float shadowAlpha = -1f;
|
transient float shadowAlpha = -1f;
|
||||||
transient Seq<Ability> abilities = new Seq<>(0);
|
transient Seq<Ability> abilities = new Seq<>(0);
|
||||||
transient float healTime;
|
transient float healTime;
|
||||||
|
|
@ -339,6 +342,11 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||||
public void remove(){
|
public void remove(){
|
||||||
team.data().updateCount(type, -1);
|
team.data().updateCount(type, -1);
|
||||||
controller.removed(self());
|
controller.removed(self());
|
||||||
|
|
||||||
|
//make sure trail doesn't just go poof
|
||||||
|
if(trail != null && trail.size() > 0){
|
||||||
|
Fx.trailFade.at(x, y, trail.width(), team.color, trail.copy());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -390,6 +398,16 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(trail != null){
|
||||||
|
trail.length = type.trailLength;
|
||||||
|
|
||||||
|
float scale = elevation();
|
||||||
|
float offset = type.engineOffset/2f + type.engineOffset/2f*scale;
|
||||||
|
|
||||||
|
float cx = x + Angles.trnsx(rotation + 180, offset), cy = y + Angles.trnsy(rotation + 180, offset);
|
||||||
|
trail.update(cx, cy);
|
||||||
|
}
|
||||||
|
|
||||||
drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f) * dragMultiplier * state.rules.dragMultiplier;
|
drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f) * dragMultiplier * state.rules.dragMultiplier;
|
||||||
|
|
||||||
//apply knockback based on spawns
|
//apply knockback based on spawns
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ public class Trail{
|
||||||
public int length;
|
public int length;
|
||||||
|
|
||||||
private final FloatSeq points;
|
private final FloatSeq points;
|
||||||
private float lastX = -1, lastY = -1, lastAngle = -1, counter = 0f;
|
private float lastX = -1, lastY = -1, lastAngle = -1, counter = 0f, lastW = 0f;
|
||||||
|
|
||||||
public Trail(int length){
|
public Trail(int length){
|
||||||
this.length = length;
|
this.length = length;
|
||||||
|
|
@ -26,6 +26,10 @@ public class Trail{
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float width(){
|
||||||
|
return lastW;
|
||||||
|
}
|
||||||
|
|
||||||
public void clear(){
|
public void clear(){
|
||||||
points.clear();
|
points.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -49,23 +53,43 @@ public class Trail{
|
||||||
public void draw(Color color, float width){
|
public void draw(Color color, float width){
|
||||||
Draw.color(color);
|
Draw.color(color);
|
||||||
float[] items = points.items;
|
float[] items = points.items;
|
||||||
float lx = lastX, ly = lastY, lastAngle = this.lastAngle;
|
float lastAngle = this.lastAngle;
|
||||||
|
float size = width / (points.size / 3);
|
||||||
|
|
||||||
for(int i = 0; i < points.size - 3; i+= 3){
|
for(int i = 0; i < points.size; i += 3){
|
||||||
float x1 = items[i], y1 = items[i + 1], w1 = items[i + 2],
|
float x1 = items[i], y1 = items[i + 1], w1 = items[i + 2];
|
||||||
x2 = items[i + 3], y2 = items[i + 4], w2 = items[i + 5];
|
float x2, y2, w2;
|
||||||
float size = width / (points.size/3);
|
|
||||||
float z1 = lastAngle;
|
//last position is always lastX/Y/W
|
||||||
float z2 = -Angles.angleRad(x2, y2, lx, ly);
|
if(i < points.size - 3){
|
||||||
|
x2 = items[i + 3];
|
||||||
|
y2 = items[i + 4];
|
||||||
|
w2 = items[i + 5];
|
||||||
|
}else{
|
||||||
|
x2 = lastX;
|
||||||
|
y2 = lastY;
|
||||||
|
w2 = lastW;
|
||||||
|
}
|
||||||
|
|
||||||
|
float z2 = -Angles.angleRad(x1, y1, x2, y2);
|
||||||
|
//end of the trail (i = 0) has the same angle as the next.
|
||||||
|
float z1 = i == 0 ? z2 : lastAngle;
|
||||||
if(w1 <= 0.001f || w2 <= 0.001f) continue;
|
if(w1 <= 0.001f || w2 <= 0.001f) continue;
|
||||||
|
|
||||||
float cx = Mathf.sin(z1) * i/3f * size * w1, cy = Mathf.cos(z1) * i/3f * size * w1,
|
float
|
||||||
nx = Mathf.sin(z2) * (i/3f + 1) * size * w2, ny = Mathf.cos(z2) * (i/3f + 1) * size * w2;
|
cx = Mathf.sin(z1) * i/3f * size * w1,
|
||||||
Fill.quad(x1 - cx, y1 - cy, x1 + cx, y1 + cy, x2 + nx, y2 + ny, x2 - nx, y2 - ny);
|
cy = Mathf.cos(z1) * i/3f * size * w1,
|
||||||
|
nx = Mathf.sin(z2) * (i/3f + 1) * size * w2,
|
||||||
|
ny = Mathf.cos(z2) * (i/3f + 1) * size * w2;
|
||||||
|
|
||||||
|
Fill.quad(
|
||||||
|
x1 - cx, y1 - cy,
|
||||||
|
x1 + cx, y1 + cy,
|
||||||
|
x2 + nx, y2 + ny,
|
||||||
|
x2 - nx, y2 - ny
|
||||||
|
);
|
||||||
|
|
||||||
lastAngle = z2;
|
lastAngle = z2;
|
||||||
lx = x2;
|
|
||||||
ly = y2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|
@ -89,19 +113,21 @@ public class Trail{
|
||||||
|
|
||||||
/** Adds a new point to the trail at intervals. */
|
/** Adds a new point to the trail at intervals. */
|
||||||
public void update(float x, float y, float width){
|
public void update(float x, float y, float width){
|
||||||
if((counter += Time.delta) >= 0.99f){
|
//TODO fix longer trails at low FPS
|
||||||
|
if((counter += Time.delta) >= 1f){
|
||||||
if(points.size > length*3){
|
if(points.size > length*3){
|
||||||
points.removeRange(0, 2);
|
points.removeRange(0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastAngle = -Angles.angleRad(x, y, lastX, lastY);
|
|
||||||
|
|
||||||
points.add(x, y, width);
|
points.add(x, y, width);
|
||||||
|
|
||||||
lastX = x;
|
counter %= 1f;
|
||||||
lastY = y;
|
|
||||||
|
|
||||||
counter = 0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update last position regardless, so it joins
|
||||||
|
lastAngle = -Angles.angleRad(x, y, lastX, lastY);
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
lastW = width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
core/src/mindustry/type/MissileUnitType.java
Normal file
30
core/src/mindustry/type/MissileUnitType.java
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
package mindustry.type;
|
||||||
|
|
||||||
|
import mindustry.ai.types.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.world.meta.*;
|
||||||
|
|
||||||
|
/** Field template for unit types. No new functionality. */
|
||||||
|
public class MissileUnitType extends UnitType{
|
||||||
|
|
||||||
|
public MissileUnitType(String name){
|
||||||
|
super(name);
|
||||||
|
|
||||||
|
playerControllable = false;
|
||||||
|
createWreck = false;
|
||||||
|
logicControllable = false;
|
||||||
|
isCounted = false;
|
||||||
|
useUnitCap = false;
|
||||||
|
allowedInPayloads = false;
|
||||||
|
defaultController = MissileAI::new;
|
||||||
|
flying = true;
|
||||||
|
constructor = TimedKillUnit::create;
|
||||||
|
envEnabled = Env.any;
|
||||||
|
envDisabled = Env.none;
|
||||||
|
trailLength = 7;
|
||||||
|
hidden = true;
|
||||||
|
rotateSpeed = 2f;
|
||||||
|
range = 30f;
|
||||||
|
//TODO weapons, etc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,7 +43,7 @@ public class UnitType extends UnlockableContent{
|
||||||
|
|
||||||
/** If true, the unit is always at elevation 1. */
|
/** If true, the unit is always at elevation 1. */
|
||||||
public boolean flying;
|
public boolean flying;
|
||||||
/** If `flying` and this is true, the unit can appear on the title screen */
|
/** If `flying` and this is true, the unit can appear on the title screen. TODO remove with new menu*/
|
||||||
public boolean onTitleScreen = true;
|
public boolean onTitleScreen = true;
|
||||||
/** Creates a new instance of this unit class. */
|
/** Creates a new instance of this unit class. */
|
||||||
public Prov<? extends Unit> constructor;
|
public Prov<? extends Unit> constructor;
|
||||||
|
|
@ -60,6 +60,7 @@ public class UnitType extends UnlockableContent{
|
||||||
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
|
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
|
||||||
public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, riseSpeed = 0.08f, fallSpeed = 0.018f;
|
public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, riseSpeed = 0.08f, fallSpeed = 0.018f;
|
||||||
public float health = 200f, range = -1, miningRange = 70f, armor = 0f, maxRange = -1f, buildRange = Vars.buildingRange;
|
public float health = 200f, range = -1, miningRange = 70f, armor = 0f, maxRange = -1f, buildRange = Vars.buildingRange;
|
||||||
|
public float lifetime = 60f * 5f; //for missiles only
|
||||||
public float crashDamageMultiplier = 1f;
|
public float crashDamageMultiplier = 1f;
|
||||||
public boolean targetAir = true, targetGround = true;
|
public boolean targetAir = true, targetGround = true;
|
||||||
public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false, circleTarget = false;
|
public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false, circleTarget = false;
|
||||||
|
|
@ -135,7 +136,7 @@ public class UnitType extends UnlockableContent{
|
||||||
public float lightRadius = -1f, lightOpacity = 0.6f;
|
public float lightRadius = -1f, lightOpacity = 0.6f;
|
||||||
public Color lightColor = Pal.powerLight;
|
public Color lightColor = Pal.powerLight;
|
||||||
public boolean drawCell = true, drawItems = true, drawShields = true, drawBody = true;
|
public boolean drawCell = true, drawItems = true, drawShields = true, drawBody = true;
|
||||||
public int trailLength = 3;
|
public int trailLength = 0;
|
||||||
public float trailX = 4f, trailY = -3f, trailScl = 1f;
|
public float trailX = 4f, trailY = -3f, trailScl = 1f;
|
||||||
/** Whether the unit can heal blocks. Initialized in init() */
|
/** Whether the unit can heal blocks. Initialized in init() */
|
||||||
public boolean canHeal = false;
|
public boolean canHeal = false;
|
||||||
|
|
@ -182,6 +183,9 @@ public class UnitType extends UnlockableContent{
|
||||||
unit.ammo = ammoCapacity; //fill up on ammo upon creation
|
unit.ammo = ammoCapacity; //fill up on ammo upon creation
|
||||||
unit.elevation = flying ? 1f : 0;
|
unit.elevation = flying ? 1f : 0;
|
||||||
unit.heal();
|
unit.heal();
|
||||||
|
if(unit instanceof TimedKillc u){
|
||||||
|
u.lifetime(lifetime);
|
||||||
|
}
|
||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -811,9 +815,8 @@ public class UnitType extends UnlockableContent{
|
||||||
float scale = unit.elevation;
|
float scale = unit.elevation;
|
||||||
float offset = engineOffset/2f + engineOffset/2f*scale;
|
float offset = engineOffset/2f + engineOffset/2f*scale;
|
||||||
|
|
||||||
if(unit instanceof Trailc){
|
if(trailLength > 0 && !naval){
|
||||||
Trail trail = ((Trailc)unit).trail();
|
drawTrail(unit);
|
||||||
trail.draw(unit.team.color, (engineSize + Mathf.absin(Time.time, 2f, engineSize / 4f) * scale) * trailScl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw.color(engineColor == null ? unit.team.color : engineColor);
|
Draw.color(engineColor == null ? unit.team.color : engineColor);
|
||||||
|
|
@ -831,6 +834,14 @@ public class UnitType extends UnlockableContent{
|
||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void drawTrail(Unit unit){
|
||||||
|
if(unit.trail == null){
|
||||||
|
unit.trail = new Trail(trailLength);
|
||||||
|
}
|
||||||
|
Trail trail = unit.trail;
|
||||||
|
trail.draw(unit.team.color, (engineSize + Mathf.absin(Time.time, 2f, engineSize / 4f) * unit.elevation) * trailScl);
|
||||||
|
}
|
||||||
|
|
||||||
public void drawEngines(Unit unit){
|
public void drawEngines(Unit unit){
|
||||||
if(!unit.isFlying()) return;
|
if(!unit.isFlying()) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ public class Weapon implements Cloneable{
|
||||||
public String name;
|
public String name;
|
||||||
/** bullet shot */
|
/** bullet shot */
|
||||||
public BulletType bullet = Bullets.standardCopper;
|
public BulletType bullet = Bullets.standardCopper;
|
||||||
|
/** unit, to spawn at bullet, e.g. missile. TODO prevent bullet creation */
|
||||||
|
public @Nullable UnitType unitSpawned;
|
||||||
/** shell ejection effect */
|
/** shell ejection effect */
|
||||||
public Effect ejectEffect = Fx.none;
|
public Effect ejectEffect = Fx.none;
|
||||||
/** whether to consume ammo when ammo is enabled in rules */
|
/** whether to consume ammo when ammo is enabled in rules */
|
||||||
|
|
@ -403,13 +405,24 @@ public class Weapon implements Cloneable{
|
||||||
unit.apply(shootStatus, shootStatusDuration);
|
unit.apply(shootStatus, shootStatusDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Bullet bullet(Unit unit, float shootX, float shootY, float angle, float lifescl){
|
protected @Nullable Bullet bullet(Unit unit, float shootX, float shootY, float angle, float lifescl){
|
||||||
float xr = Mathf.range(xRand);
|
float xr = Mathf.range(xRand);
|
||||||
|
float
|
||||||
|
x = shootX + Angles.trnsx(angle, 0, xr),
|
||||||
|
y = shootY + Angles.trnsy(angle, 0, xr);
|
||||||
|
|
||||||
return bullet.create(unit, unit.team,
|
if(unitSpawned == null){
|
||||||
shootX + Angles.trnsx(angle, 0, xr),
|
return bullet.create(unit, unit.team, x, y, angle, (1f - velocityRnd) + Mathf.random(velocityRnd), lifescl);
|
||||||
shootY + Angles.trnsy(angle, 0, xr),
|
}else{
|
||||||
angle, (1f - velocityRnd) + Mathf.random(velocityRnd), lifescl);
|
Unit spawned = unitSpawned.create(unit.team);
|
||||||
|
spawned.set(x, y);
|
||||||
|
spawned.rotation = angle;
|
||||||
|
//immediately spawn at top speed, since it was launched
|
||||||
|
spawned.vel.trns(angle, unitSpawned.speed);
|
||||||
|
spawned.add();
|
||||||
|
//TODO assign AI target here?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Weapon copy(){
|
public Weapon copy(){
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,18 @@
|
||||||
package mindustry.world.blocks.defense;
|
package mindustry.world.blocks.defense;
|
||||||
|
|
||||||
public class DirectionalForceProjector{
|
public class DirectionalForceProjector extends ForceProjector{
|
||||||
|
|
||||||
|
public DirectionalForceProjector(String name){
|
||||||
|
super(name);
|
||||||
|
|
||||||
|
consumeCoolant = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DirectionalForceProjectorBuild extends ForceBuild{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deflectBullets(){
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,15 @@ public class ForceProjector extends Block{
|
||||||
public float cooldownNormal = 1.75f;
|
public float cooldownNormal = 1.75f;
|
||||||
public float cooldownLiquid = 1.5f;
|
public float cooldownLiquid = 1.5f;
|
||||||
public float cooldownBrokenBase = 0.35f;
|
public float cooldownBrokenBase = 0.35f;
|
||||||
|
public float coolantConsumption = 0.1f;
|
||||||
|
public boolean consumeCoolant = true;
|
||||||
public Effect absorbEffect = Fx.absorb;
|
public Effect absorbEffect = Fx.absorb;
|
||||||
public Effect shieldBreakEffect = Fx.shieldBreak;
|
public Effect shieldBreakEffect = Fx.shieldBreak;
|
||||||
public @Load("@-top") TextureRegion topRegion;
|
public @Load("@-top") TextureRegion topRegion;
|
||||||
|
|
||||||
static ForceBuild paramEntity;
|
protected static ForceBuild paramEntity;
|
||||||
static Effect paramEffect;
|
protected static Effect paramEffect;
|
||||||
static final Cons<Bullet> shieldConsumer = trait -> {
|
protected static final Cons<Bullet> shieldConsumer = trait -> {
|
||||||
if(trait.team != paramEntity.team && trait.type.absorbable && Intersector.isInsideHexagon(paramEntity.x, paramEntity.y, paramEntity.realRadius() * 2f, trait.x(), trait.y())){
|
if(trait.team != paramEntity.team && trait.type.absorbable && Intersector.isInsideHexagon(paramEntity.x, paramEntity.y, paramEntity.realRadius() * 2f, trait.x(), trait.y())){
|
||||||
trait.absorb();
|
trait.absorb();
|
||||||
paramEffect.at(trait);
|
paramEffect.at(trait);
|
||||||
|
|
@ -55,10 +57,13 @@ public class ForceProjector extends Block{
|
||||||
hasPower = true;
|
hasPower = true;
|
||||||
hasLiquids = true;
|
hasLiquids = true;
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
|
envEnabled |= Env.space;
|
||||||
ambientSound = Sounds.shield;
|
ambientSound = Sounds.shield;
|
||||||
ambientSoundVolume = 0.08f;
|
ambientSoundVolume = 0.08f;
|
||||||
consumes.add(new ConsumeCoolant(0.1f)).boost().update(false);
|
|
||||||
envEnabled |= Env.space;
|
if(consumeCoolant){
|
||||||
|
consumes.add(new ConsumeCoolant(coolantConsumption)).boost().update(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -80,12 +85,17 @@ public class ForceProjector extends Block{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setStats(){
|
public void setStats(){
|
||||||
stats.timePeriod = phaseUseTime;
|
boolean consItems = consumes.has(ConsumeType.item);
|
||||||
|
|
||||||
|
if(consItems) stats.timePeriod = phaseUseTime;
|
||||||
super.setStats();
|
super.setStats();
|
||||||
stats.add(Stat.shieldHealth, shieldHealth, StatUnit.none);
|
stats.add(Stat.shieldHealth, shieldHealth, StatUnit.none);
|
||||||
stats.add(Stat.cooldownTime, (int) (shieldHealth / cooldownBrokenBase / 60f), StatUnit.seconds);
|
stats.add(Stat.cooldownTime, (int) (shieldHealth / cooldownBrokenBase / 60f), StatUnit.seconds);
|
||||||
stats.add(Stat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks);
|
|
||||||
stats.add(Stat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth);
|
if(consItems){
|
||||||
|
stats.add(Stat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks);
|
||||||
|
stats.add(Stat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -146,9 +156,9 @@ public class ForceProjector extends Block{
|
||||||
|
|
||||||
warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f);
|
warmup = Mathf.lerpDelta(warmup, efficiency(), 0.1f);
|
||||||
|
|
||||||
if(buildup > 0){
|
if(buildup > 0 && consumes.has(ConsumeType.liquid)){
|
||||||
float scale = !broken ? cooldownNormal : cooldownBrokenBase;
|
float scale = !broken ? cooldownNormal : cooldownBrokenBase;
|
||||||
ConsumeLiquidFilter cons = consumes.get(ConsumeType.liquid);
|
Consume cons = consumes.get(ConsumeType.liquid);
|
||||||
if(cons.valid(this)){
|
if(cons.valid(this)){
|
||||||
cons.update(this);
|
cons.update(this);
|
||||||
scale *= (cooldownLiquid * (1f + (liquids.current().heatCapacity - 0.4f) * 0.9f));
|
scale *= (cooldownLiquid * (1f + (liquids.current().heatCapacity - 0.4f) * 0.9f));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue