mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-03-16 03:41:55 -07:00
Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features
Conflicts: core/src/mindustry/editor/MapInfoDialog.java core/src/mindustry/maps/filters/ClearFilter.java core/src/mindustry/mod/ClassMap.java gradle.properties
This commit is contained in:
commit
afe963ca5d
21 changed files with 871 additions and 47 deletions
|
|
@ -492,6 +492,7 @@ filter.option.block = Block
|
|||
filter.option.floor = Floor
|
||||
filter.option.flooronto = Target Floor
|
||||
filter.option.target = Target
|
||||
filter.option.replacement = Replacement
|
||||
filter.option.wall = Wall
|
||||
filter.option.ore = Ore
|
||||
filter.option.floor2 = Secondary Floor
|
||||
|
|
@ -994,6 +995,7 @@ rules.waves = Waves
|
|||
rules.attack = Attack Mode
|
||||
rules.buildai = AI Building
|
||||
rules.corecapture = Capture Core On Destruction
|
||||
rules.polygoncoreprotection = Polygonal Core Protection
|
||||
rules.enemyCheat = Infinite AI (Red Team) Resources
|
||||
rules.blockhealthmultiplier = Block Health Multiplier
|
||||
rules.blockdamagemultiplier = Block Damage Multiplier
|
||||
|
|
|
|||
Binary file not shown.
BIN
core/assets/maps/passage.msav
Normal file
BIN
core/assets/maps/passage.msav
Normal file
Binary file not shown.
Binary file not shown.
|
|
@ -1113,6 +1113,47 @@ public class Fx{
|
|||
});
|
||||
}),
|
||||
|
||||
impactReactorExplosion = new Effect(30, 500f, b -> {
|
||||
float intensity = 8f;
|
||||
float baseLifetime = 25f + intensity * 15f;
|
||||
b.lifetime = 50f + intensity * 64f;
|
||||
|
||||
color(Pal.lighterOrange);
|
||||
alpha(0.8f);
|
||||
for(int i = 0; i < 5; i++){
|
||||
rand.setSeed(b.id*2 + i);
|
||||
float lenScl = rand.random(0.25f, 1f);
|
||||
int fi = i;
|
||||
b.scaled(b.lifetime * lenScl, e -> {
|
||||
randLenVectors(e.id + fi - 1, e.fin(Interp.pow10Out), (int)(2.8f * intensity), 25f * intensity, (x, y, in, out) -> {
|
||||
float fout = e.fout(Interp.pow5Out) * rand.random(0.5f, 1f);
|
||||
float rad = fout * ((2f + intensity) * 2.35f);
|
||||
|
||||
Fill.circle(e.x + x, e.y + y, rad);
|
||||
Drawf.light(e.x + x, e.y + y, rad * 2.6f, Pal.lighterOrange, 0.7f);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
b.scaled(baseLifetime, e -> {
|
||||
Draw.color();
|
||||
e.scaled(5 + intensity * 2f, i -> {
|
||||
stroke((3.1f + intensity/5f) * i.fout());
|
||||
Lines.circle(e.x, e.y, (3f + i.fin() * 14f) * intensity);
|
||||
Drawf.light(e.x, e.y, i.fin() * 14f * 2f * intensity, Color.white, 0.9f * e.fout());
|
||||
});
|
||||
|
||||
color(Color.white, Pal.lighterOrange, e.fin());
|
||||
stroke((2f * e.fout()));
|
||||
|
||||
Draw.z(Layer.effect + 0.001f);
|
||||
randLenVectors(e.id + 1, e.finpow() + 0.001f, (int)(8 * intensity), 30f * intensity, (x, y, in, out) -> {
|
||||
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + out * 4 * (4f + intensity));
|
||||
Drawf.light(e.x + x, e.y + y, (out * 4 * (3f + intensity)) * 3.5f, Draw.getColor(), 0.8f);
|
||||
});
|
||||
});
|
||||
}),
|
||||
|
||||
blockExplosion = new Effect(30, e -> {
|
||||
e.scaled(7, i -> {
|
||||
stroke(3.1f * i.fout());
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import arc.util.*;
|
|||
import mindustry.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.io.*;
|
||||
import mindustry.maps.filters.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
|
||||
|
|
@ -74,7 +75,11 @@ public class MapInfoDialog extends BaseDialog{
|
|||
t.row();
|
||||
t.add("@editor.generation").padRight(8).left();
|
||||
t.button("@edit", () -> {
|
||||
generate.show(maps.readFilters(editor.tags.get("genfilters", "")),
|
||||
//randomize so they're not all the same seed
|
||||
var res = maps.readFilters(editor.tags.get("genfilters", ""));
|
||||
res.each(GenerateFilter::randomize);
|
||||
|
||||
generate.show(res,
|
||||
filters -> {
|
||||
//reset seed to 0 so it is not written
|
||||
filters.each(f -> f.seed = 0);
|
||||
|
|
|
|||
|
|
@ -34,13 +34,18 @@ public class Damage{
|
|||
dynamicExplosion(x, y, flammability, explosiveness, power, radius, damage, true, null, Fx.dynamicExplosion);
|
||||
}
|
||||
|
||||
/** Creates a dynamic explosion based on specified parameters. */
|
||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage, Effect explosionFx){
|
||||
dynamicExplosion(x, y, flammability, explosiveness, power, radius, damage, true, null, explosionFx);
|
||||
}
|
||||
|
||||
/** Creates a dynamic explosion based on specified parameters. */
|
||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage, boolean fire, @Nullable Team ignoreTeam){
|
||||
dynamicExplosion(x, y, flammability, explosiveness, power, radius, damage, fire, ignoreTeam, Fx.dynamicExplosion);
|
||||
}
|
||||
|
||||
/** Creates a dynamic explosion based on specified parameters. */
|
||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage, boolean fire, @Nullable Team ignoreTeam, Effect explosion){
|
||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage, boolean fire, @Nullable Team ignoreTeam, Effect explosionFx){
|
||||
if(damage){
|
||||
for(int i = 0; i < Mathf.clamp(power / 700, 0, 8); i++){
|
||||
int length = 5 + Mathf.clamp((int)(power / 500), 1, 20);
|
||||
|
|
@ -74,7 +79,7 @@ public class Damage{
|
|||
|
||||
float shake = Math.min(explosiveness / 4f + 3f, 9f);
|
||||
Effect.shake(shake, shake, x, y);
|
||||
explosion.at(x, y, radius / 8f);
|
||||
explosionFx.at(x, y, radius / 8f);
|
||||
}
|
||||
|
||||
public static void createIncend(float x, float y, float range, int amount){
|
||||
|
|
|
|||
|
|
@ -1059,7 +1059,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
|||
});
|
||||
}
|
||||
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * block.size / 2f, state.rules.damageExplosions);
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * block.size / 2f, state.rules.damageExplosions, block.destroyEffect);
|
||||
|
||||
if(!floor().solid && !floor().isLiquid){
|
||||
Effect.rubble(x, y, block.size);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import mindustry.net.*;
|
|||
import mindustry.net.Packets.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
public class EventType{
|
||||
|
||||
|
|
@ -283,6 +284,15 @@ public class EventType{
|
|||
}
|
||||
}
|
||||
|
||||
/** Called when a core block is placed/removed or its team is changed. */
|
||||
public static class CoreChangeEvent{
|
||||
public CoreBuild core;
|
||||
|
||||
public CoreChangeEvent(CoreBuild core){
|
||||
this.core = core;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StateChangeEvent{
|
||||
public final State from, to;
|
||||
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ public class Rules{
|
|||
public float deconstructRefundMultiplier = 0.5f;
|
||||
/** No-build zone around enemy core radius. */
|
||||
public float enemyCoreBuildRadius = 400f;
|
||||
/** If true, no-build zones are calculated based on the closest core. */
|
||||
public boolean polygonCoreProtection = false;
|
||||
/** Radius around enemy wave drop zones.*/
|
||||
public float dropZoneRadius = 300f;
|
||||
/** Time between waves in ticks. */
|
||||
|
|
|
|||
|
|
@ -5,14 +5,18 @@ import arc.graphics.*;
|
|||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ai.types.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
|
|
@ -23,6 +27,42 @@ public class OverlayRenderer{
|
|||
|
||||
private float buildFade, unitFade;
|
||||
private Sized lastSelect;
|
||||
private Seq<CoreEdge> cedges = new Seq<>();
|
||||
private boolean updatedCores;
|
||||
|
||||
public OverlayRenderer(){
|
||||
Events.on(WorldLoadEvent.class, e -> {
|
||||
updatedCores = true;
|
||||
});
|
||||
|
||||
Events.on(CoreChangeEvent.class, e -> {
|
||||
updatedCores = true;
|
||||
});
|
||||
}
|
||||
|
||||
private void updateCoreEdges(){
|
||||
if(!updatedCores){
|
||||
return;
|
||||
}
|
||||
|
||||
updatedCores = false;
|
||||
cedges.clear();
|
||||
|
||||
Seq<Vec2> pos = new Seq<>();
|
||||
Seq<CoreBuild> teams = new Seq<>();
|
||||
for(TeamData team : state.teams.active){
|
||||
for(CoreBuild b : team.cores){
|
||||
teams.add(b);
|
||||
pos.add(new Vec2(b.x, b.y));
|
||||
}
|
||||
}
|
||||
|
||||
//if this is laggy, it could be shoved in another thread.
|
||||
var result = Voronoi.generate(pos.toArray(Vec2.class), 0, world.unitWidth(), 0, world.unitHeight());
|
||||
for(var edge : result){
|
||||
cedges.add(new CoreEdge(edge.x1, edge.y1, edge.x2, edge.y2, teams.get(edge.site1).team, teams.get(edge.site2).team));
|
||||
}
|
||||
}
|
||||
|
||||
public void drawBottom(){
|
||||
InputHandler input = control.input;
|
||||
|
|
@ -117,15 +157,32 @@ public class OverlayRenderer{
|
|||
Lines.stroke(buildFade * 2f);
|
||||
|
||||
if(buildFade > 0.005f){
|
||||
state.teams.eachEnemyCore(player.team(), core -> {
|
||||
float dst = core.dst(player);
|
||||
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));
|
||||
Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius);
|
||||
if(state.rules.polygonCoreProtection){
|
||||
updateCoreEdges();
|
||||
Draw.color(Pal.accent);
|
||||
|
||||
for(int i = 0; i < 2; i++){
|
||||
float offset = (i == 0 ? -2f : 0f);
|
||||
for(CoreEdge edge : cedges){
|
||||
Team displayed = edge.displayed();
|
||||
if(displayed != null){
|
||||
Draw.color(i == 0 ? Color.darkGray : Tmp.c1.set(displayed.color).lerp(Pal.accent, Mathf.absin(Time.time, 10f, 0.2f)));
|
||||
Lines.line(edge.x1, edge.y1 + offset, edge.x2, edge.y2 + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
}else{
|
||||
state.teams.eachEnemyCore(player.team(), core -> {
|
||||
if(Core.camera.bounds(Tmp.r1).overlaps(Tmp.r2.setCentered(core.x, core.y, state.rules.enemyCoreBuildRadius * 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));
|
||||
Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Lines.stroke(2f);
|
||||
|
|
@ -192,4 +249,28 @@ public class OverlayRenderer{
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class CoreEdge{
|
||||
float x1, y1, x2, y2;
|
||||
Team t1, t2;
|
||||
|
||||
public CoreEdge(float x1, float y1, float x2, float y2, Team t1, Team t2){
|
||||
this.x1 = x1;
|
||||
this.y1 = y1;
|
||||
this.x2 = x2;
|
||||
this.y2 = y2;
|
||||
this.t1 = t1;
|
||||
this.t2 = t2;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Team displayed(){
|
||||
return
|
||||
t1 == t2 ? null :
|
||||
t1 == player.team() ? t2 :
|
||||
t2 == player.team() ? t1 :
|
||||
t2.id == 0 ? t1 :
|
||||
t1.id < t2.id && t1.id != 0 ? t1 : t2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
643
core/src/mindustry/graphics/Voronoi.java
Executable file
643
core/src/mindustry/graphics/Voronoi.java
Executable file
|
|
@ -0,0 +1,643 @@
|
|||
package mindustry.graphics;
|
||||
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
//TODO in dire need of cleanup
|
||||
public class Voronoi{
|
||||
private final static int LE = 0;
|
||||
private final static int RE = 1;
|
||||
|
||||
//TODO make local
|
||||
int siteidx;
|
||||
Site[] sites;
|
||||
int nsites;
|
||||
float borderMinX, borderMaxX, borderMinY, borderMaxY;
|
||||
float ymin;
|
||||
float deltay;
|
||||
int nvertices = 0;
|
||||
int nedges;
|
||||
Site bottomsite;
|
||||
int PQcount;
|
||||
int PQmin;
|
||||
int PQhashsize;
|
||||
Halfedge[] PQhash;
|
||||
int ELhashsize;
|
||||
Halfedge[] ELhash;
|
||||
Seq<GraphEdge> allEdges;
|
||||
float minDistanceBetweenSites = 1f;
|
||||
|
||||
public static Seq<GraphEdge> generate(Vec2[] values, float minX, float maxX, float minY, float maxY){
|
||||
return new Voronoi().generateVoronoi(values, minX, maxX, minY, maxY);
|
||||
}
|
||||
|
||||
Seq<GraphEdge> generateVoronoi(Vec2[] values, float minX, float maxX, float minY, float maxY){
|
||||
allEdges = new Seq<>();
|
||||
|
||||
nsites = values.length;
|
||||
|
||||
float sn = (float)nsites + 4;
|
||||
int rtsites = (int)Math.sqrt(sn);
|
||||
|
||||
sites = new Site[nsites];
|
||||
Vec2 first = values[0];
|
||||
float xmin = first.x;
|
||||
ymin = first.y;
|
||||
float xmax = first.x;
|
||||
float ymax = first.y;
|
||||
for(int i = 0; i < nsites; i++){
|
||||
sites[i] = new Site();
|
||||
sites[i].coord.set(values[i]);
|
||||
sites[i].sitenbr = i;
|
||||
|
||||
if(values[i].x < xmin){
|
||||
xmin = values[i].x;
|
||||
}else if(values[i].x > xmax){
|
||||
xmax = values[i].x;
|
||||
}
|
||||
|
||||
if(values[i].y < ymin){
|
||||
ymin = values[i].y;
|
||||
}else if(values[i].y > ymax){
|
||||
ymax = values[i].y;
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.sort(sites, (p1, p2) -> {
|
||||
Vec2 s1 = p1.coord, s2 = p2.coord;
|
||||
if(s1.y < s2.y){
|
||||
return (-1);
|
||||
}
|
||||
if(s1.y > s2.y){
|
||||
return (1);
|
||||
}
|
||||
return Float.compare(s1.x, s2.x);
|
||||
});
|
||||
|
||||
deltay = ymax - ymin;
|
||||
float deltax = xmax - xmin;
|
||||
|
||||
// Check bounding box inputs - if mins are bigger than maxes, swap them
|
||||
float temp;
|
||||
if(minX > maxX){
|
||||
temp = minX;
|
||||
minX = maxX;
|
||||
maxX = temp;
|
||||
}
|
||||
if(minY > maxY){
|
||||
temp = minY;
|
||||
minY = maxY;
|
||||
maxY = temp;
|
||||
}
|
||||
borderMinX = minX;
|
||||
borderMinY = minY;
|
||||
borderMaxX = maxX;
|
||||
borderMaxY = maxY;
|
||||
|
||||
siteidx = 0;
|
||||
|
||||
PQcount = 0;
|
||||
PQmin = 0;
|
||||
PQhashsize = 4 * rtsites;
|
||||
PQhash = new Halfedge[PQhashsize];
|
||||
|
||||
for(int i2 = 0; i2 < PQhashsize; i2 += 1){
|
||||
PQhash[i2] = new Halfedge();
|
||||
}
|
||||
int i1;
|
||||
ELhashsize = 2 * rtsites;
|
||||
ELhash = new Halfedge[ELhashsize];
|
||||
|
||||
for(i1 = 0; i1 < ELhashsize; i1 += 1){
|
||||
ELhash[i1] = null;
|
||||
}
|
||||
Halfedge ELleftend = newHe(null, 0);
|
||||
Halfedge ELrightend = newHe(null, 0);
|
||||
ELleftend.ELleft = null;
|
||||
ELleftend.ELright = ELrightend;
|
||||
ELrightend.ELleft = ELleftend;
|
||||
ELrightend.ELright = null;
|
||||
ELhash[0] = ELleftend;
|
||||
ELhash[ELhashsize - 1] = ELrightend;
|
||||
|
||||
bottomsite = next();
|
||||
Site newsite = next();
|
||||
Halfedge lbnd;
|
||||
Vec2 newintstar = null;
|
||||
Edge e;
|
||||
while(true){
|
||||
if(PQcount != 0){
|
||||
Vec2 answer = new Vec2();
|
||||
|
||||
while(PQhash[PQmin].PQnext == null){
|
||||
PQmin += 1;
|
||||
}
|
||||
answer.x = PQhash[PQmin].PQnext.vertex.coord.x;
|
||||
answer.y = PQhash[PQmin].PQnext.ystar;
|
||||
newintstar = (answer);
|
||||
}
|
||||
|
||||
Halfedge rbnd;
|
||||
Halfedge bisector;
|
||||
Site p;
|
||||
Site bot;
|
||||
|
||||
if(newsite != null && (PQcount == 0 || newsite.coord.y < newintstar.y || (newsite.coord.y == newintstar.y && newsite.coord.x < newintstar.x))){
|
||||
int bucket = (int)(((newsite.coord).x - xmin) / deltax * ELhashsize);
|
||||
|
||||
if(bucket < 0){
|
||||
bucket = 0;
|
||||
}
|
||||
if(bucket >= ELhashsize){
|
||||
bucket = ELhashsize - 1;
|
||||
}
|
||||
|
||||
Halfedge he = getHash(bucket);
|
||||
if(he == null){
|
||||
for(int i = 1; i < ELhashsize; i += 1){
|
||||
if((he = getHash(bucket - i)) != null){
|
||||
break;
|
||||
}
|
||||
if((he = getHash(bucket + i)) != null){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(he == ELleftend || (he != ELrightend && right(he, (newsite.coord)))){
|
||||
do{
|
||||
he = he.ELright;
|
||||
}while(he != ELrightend && right(he, (newsite.coord)));
|
||||
he = he.ELleft;
|
||||
}else{
|
||||
do{
|
||||
he = he.ELleft;
|
||||
}while(he != ELleftend && !right(he, (newsite.coord)));
|
||||
}
|
||||
|
||||
if(bucket > 0 && bucket < ELhashsize - 1){
|
||||
ELhash[bucket] = he;
|
||||
}
|
||||
lbnd = he;
|
||||
rbnd = lbnd.ELright;
|
||||
|
||||
bot = rightreg(lbnd);
|
||||
e = bisect(bot, newsite);
|
||||
|
||||
bisector = newHe(e, LE);
|
||||
insert(lbnd, bisector);
|
||||
|
||||
if((p = intersect(lbnd, bisector)) != null){
|
||||
pqdelete(lbnd);
|
||||
pqinsert(lbnd, p, p.coord.dst(newsite.coord));
|
||||
}
|
||||
lbnd = bisector;
|
||||
bisector = newHe(e, RE);
|
||||
insert(lbnd, bisector);
|
||||
|
||||
if((p = intersect(bisector, rbnd)) != null){
|
||||
pqinsert(bisector, p, p.coord.dst(newsite.coord));
|
||||
}
|
||||
newsite = next();
|
||||
}else if(!(PQcount == 0)){
|
||||
Halfedge curr;
|
||||
|
||||
curr = PQhash[PQmin].PQnext;
|
||||
PQhash[PQmin].PQnext = curr.PQnext;
|
||||
PQcount -= 1;
|
||||
lbnd = (curr);
|
||||
Halfedge llbnd = lbnd.ELleft;
|
||||
rbnd = lbnd.ELright;
|
||||
Halfedge rrbnd = (rbnd.ELright);
|
||||
bot = leftReg(lbnd);
|
||||
Site top = rightreg(rbnd);
|
||||
|
||||
Site v = lbnd.vertex;
|
||||
v.sitenbr = nvertices;
|
||||
nvertices += 1;
|
||||
endpoint(lbnd.ELedge, lbnd.ELpm, v);
|
||||
endpoint(rbnd.ELedge, rbnd.ELpm, v);
|
||||
delete(lbnd);
|
||||
pqdelete(rbnd);
|
||||
delete(rbnd);
|
||||
int pm = LE;
|
||||
|
||||
if(bot.coord.y > top.coord.y){
|
||||
Site temp1 = bot;
|
||||
bot = top;
|
||||
top = temp1;
|
||||
pm = RE;
|
||||
}
|
||||
|
||||
e = bisect(bot, top);
|
||||
bisector = newHe(e, pm);
|
||||
insert(llbnd, bisector);
|
||||
endpoint(e, RE - pm, v);
|
||||
|
||||
if((p = intersect(llbnd, bisector)) != null){
|
||||
pqdelete(llbnd);
|
||||
pqinsert(llbnd, p, p.coord.dst(bot.coord));
|
||||
}
|
||||
|
||||
if((p = intersect(bisector, rrbnd)) != null){
|
||||
pqinsert(bisector, p, p.coord.dst(bot.coord));
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(lbnd = (ELleftend.ELright); lbnd != ELrightend; lbnd = (lbnd.ELright)){
|
||||
e = lbnd.ELedge;
|
||||
clipLine(e);
|
||||
}
|
||||
|
||||
return allEdges;
|
||||
}
|
||||
|
||||
private Site next(){
|
||||
return siteidx < nsites ? sites[siteidx ++] : null;
|
||||
}
|
||||
|
||||
private Edge bisect(Site s1, Site s2){
|
||||
Edge newedge = new Edge();
|
||||
|
||||
// store the sites that this edge is bisecting
|
||||
newedge.reg[0] = s1;
|
||||
newedge.reg[1] = s2;
|
||||
// to begin with, there are no endpoints on the bisector - it goes to
|
||||
// infinity
|
||||
newedge.ep[0] = null;
|
||||
newedge.ep[1] = null;
|
||||
|
||||
// get the difference in x dist between the sites
|
||||
float dx = s2.coord.x - s1.coord.x;
|
||||
float dy = s2.coord.y - s1.coord.y;
|
||||
// make sure that the difference in positive
|
||||
float adx = dx > 0 ? dx : -dx;
|
||||
float ady = dy > 0 ? dy : -dy;
|
||||
newedge.c = s1.coord.x * dx + s1.coord.y * dy + (dx * dx + dy * dy) * 0.5f;// get the slope of the line
|
||||
|
||||
if(adx > ady){
|
||||
newedge.a = 1.0f;
|
||||
newedge.b = dy / dx;
|
||||
newedge.c /= dx;// set formula of line, with x fixed to 1
|
||||
}else{
|
||||
newedge.b = 1.0f;
|
||||
newedge.a = dx / dy;
|
||||
newedge.c /= dy;// set formula of line, with y fixed to 1
|
||||
}
|
||||
|
||||
newedge.edgenbr = nedges;
|
||||
|
||||
nedges += 1;
|
||||
return newedge;
|
||||
}
|
||||
|
||||
private int pqbucket(Halfedge he){
|
||||
int bucket;
|
||||
|
||||
bucket = (int)((he.ystar - ymin) / deltay * PQhashsize);
|
||||
if(bucket < 0){
|
||||
bucket = 0;
|
||||
}
|
||||
if(bucket >= PQhashsize){
|
||||
bucket = PQhashsize - 1;
|
||||
}
|
||||
if(bucket < PQmin){
|
||||
PQmin = bucket;
|
||||
}
|
||||
return bucket;
|
||||
}
|
||||
|
||||
// push the HalfEdge into the ordered linked list of vertices
|
||||
private void pqinsert(Halfedge he, Site v, float offset){
|
||||
Halfedge last, next;
|
||||
|
||||
he.vertex = v;
|
||||
he.ystar = v.coord.y + offset;
|
||||
last = PQhash[pqbucket(he)];
|
||||
while((next = last.PQnext) != null
|
||||
&& (he.ystar > next.ystar || (he.ystar == next.ystar && v.coord.x > next.vertex.coord.x))){
|
||||
last = next;
|
||||
}
|
||||
he.PQnext = last.PQnext;
|
||||
last.PQnext = he;
|
||||
PQcount += 1;
|
||||
}
|
||||
|
||||
// remove the HalfEdge from the list of vertices
|
||||
private void pqdelete(Halfedge he){
|
||||
Halfedge last;
|
||||
|
||||
if(he.vertex != null){
|
||||
last = PQhash[pqbucket(he)];
|
||||
while(last.PQnext != he){
|
||||
last = last.PQnext;
|
||||
}
|
||||
|
||||
last.PQnext = he.PQnext;
|
||||
PQcount -= 1;
|
||||
he.vertex = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Halfedge newHe(Edge e, int pm){
|
||||
Halfedge answer = new Halfedge();
|
||||
answer.ELedge = e;
|
||||
answer.ELpm = pm;
|
||||
answer.PQnext = null;
|
||||
answer.vertex = null;
|
||||
return answer;
|
||||
}
|
||||
|
||||
private Site leftReg(Halfedge he){
|
||||
if(he.ELedge == null){
|
||||
return bottomsite;
|
||||
}
|
||||
return he.ELpm == LE ? he.ELedge.reg[LE] : he.ELedge.reg[RE];
|
||||
}
|
||||
|
||||
private void insert(Halfedge lb, Halfedge newHe){
|
||||
newHe.ELleft = lb;
|
||||
newHe.ELright = lb.ELright;
|
||||
lb.ELright.ELleft = newHe;
|
||||
lb.ELright = newHe;
|
||||
}
|
||||
|
||||
/*
|
||||
* This delete routine can't reclaim node, since pointers from hash table
|
||||
* may be present.
|
||||
*/
|
||||
private void delete(Halfedge he){
|
||||
he.ELleft.ELright = he.ELright;
|
||||
he.ELright.ELleft = he.ELleft;
|
||||
he.deleted = true;
|
||||
}
|
||||
|
||||
/* Get entry from hash table, pruning any deleted nodes */
|
||||
private Halfedge getHash(int b){
|
||||
Halfedge he;
|
||||
|
||||
if(b < 0 || b >= ELhashsize){
|
||||
return (null);
|
||||
}
|
||||
he = ELhash[b];
|
||||
if(he == null || !he.deleted){
|
||||
return (he);
|
||||
}
|
||||
|
||||
/* Hash table points to deleted half edge. Patch as necessary. */
|
||||
ELhash[b] = null;
|
||||
return (null);
|
||||
}
|
||||
|
||||
private void clipLine(Edge e){
|
||||
float pxmin, pxmax, pymin, pymax;
|
||||
Site s1, s2;
|
||||
float x1 = 0, x2 = 0, y1 = 0, y2 = 0;
|
||||
|
||||
x1 = e.reg[0].coord.x;
|
||||
x2 = e.reg[1].coord.x;
|
||||
y1 = e.reg[0].coord.y;
|
||||
y2 = e.reg[1].coord.y;
|
||||
|
||||
// if the distance between the two points this line was created from is
|
||||
// less than the square root of 2, then ignore it
|
||||
if(Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) < minDistanceBetweenSites){
|
||||
return;
|
||||
}
|
||||
pxmin = borderMinX;
|
||||
pxmax = borderMaxX;
|
||||
pymin = borderMinY;
|
||||
pymax = borderMaxY;
|
||||
|
||||
if(e.a == 1.0 && e.b >= 0.0){
|
||||
s1 = e.ep[1];
|
||||
s2 = e.ep[0];
|
||||
}else{
|
||||
s1 = e.ep[0];
|
||||
s2 = e.ep[1];
|
||||
}
|
||||
|
||||
if(e.a == 1.0){
|
||||
y1 = pymin;
|
||||
if(s1 != null && s1.coord.y > pymin){
|
||||
y1 = s1.coord.y;
|
||||
}
|
||||
if(y1 > pymax){
|
||||
y1 = pymax;
|
||||
}
|
||||
x1 = e.c - e.b * y1;
|
||||
y2 = pymax;
|
||||
if(s2 != null && s2.coord.y < pymax){
|
||||
y2 = s2.coord.y;
|
||||
}
|
||||
|
||||
if(y2 < pymin){
|
||||
y2 = pymin;
|
||||
}
|
||||
x2 = (e.c) - (e.b) * y2;
|
||||
if(((x1 > pxmax) & (x2 > pxmax)) | ((x1 < pxmin) & (x2 < pxmin))){
|
||||
return;
|
||||
}
|
||||
if(x1 > pxmax){
|
||||
x1 = pxmax;
|
||||
y1 = (e.c - x1) / e.b;
|
||||
}
|
||||
if(x1 < pxmin){
|
||||
x1 = pxmin;
|
||||
y1 = (e.c - x1) / e.b;
|
||||
}
|
||||
if(x2 > pxmax){
|
||||
x2 = pxmax;
|
||||
y2 = (e.c - x2) / e.b;
|
||||
}
|
||||
if(x2 < pxmin){
|
||||
x2 = pxmin;
|
||||
y2 = (e.c - x2) / e.b;
|
||||
}
|
||||
}else{
|
||||
x1 = pxmin;
|
||||
if(s1 != null && s1.coord.x > pxmin){
|
||||
x1 = s1.coord.x;
|
||||
}
|
||||
if(x1 > pxmax){
|
||||
x1 = pxmax;
|
||||
}
|
||||
y1 = e.c - e.a * x1;
|
||||
x2 = pxmax;
|
||||
if(s2 != null && s2.coord.x < pxmax){
|
||||
x2 = s2.coord.x;
|
||||
}
|
||||
if(x2 < pxmin){
|
||||
x2 = pxmin;
|
||||
}
|
||||
y2 = e.c - e.a * x2;
|
||||
if(((y1 > pymax) & (y2 > pymax)) | ((y1 < pymin) & (y2 < pymin))){
|
||||
return;
|
||||
}
|
||||
if(y1 > pymax){
|
||||
y1 = pymax;
|
||||
x1 = (e.c - y1) / e.a;
|
||||
}
|
||||
if(y1 < pymin){
|
||||
y1 = pymin;
|
||||
x1 = (e.c - y1) / e.a;
|
||||
}
|
||||
if(y2 > pymax){
|
||||
y2 = pymax;
|
||||
x2 = (e.c - y2) / e.a;
|
||||
}
|
||||
if(y2 < pymin){
|
||||
y2 = pymin;
|
||||
x2 = (e.c - y2) / e.a;
|
||||
}
|
||||
}
|
||||
|
||||
GraphEdge newEdge = new GraphEdge();
|
||||
allEdges.add(newEdge);
|
||||
newEdge.x1 = x1;
|
||||
newEdge.y1 = y1;
|
||||
newEdge.x2 = x2;
|
||||
newEdge.y2 = y2;
|
||||
|
||||
newEdge.site1 = e.reg[0].sitenbr;
|
||||
newEdge.site2 = e.reg[1].sitenbr;
|
||||
}
|
||||
|
||||
private void endpoint(Edge e, int lr, Site s){
|
||||
e.ep[lr] = s;
|
||||
if(e.ep[RE - lr] == null){
|
||||
return;
|
||||
}
|
||||
clipLine(e);
|
||||
}
|
||||
|
||||
private boolean right(Halfedge el, Vec2 p){
|
||||
Edge e = el.ELedge;
|
||||
Site topsite = e.reg[1];
|
||||
boolean rightOf = p.x > topsite.coord.x;
|
||||
if(rightOf && el.ELpm == LE){
|
||||
return true;
|
||||
}
|
||||
if(!rightOf && el.ELpm == RE){
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean above;
|
||||
if(e.a == 1.0){
|
||||
float dyp = p.y - topsite.coord.y;
|
||||
float dxp = p.x - topsite.coord.x;
|
||||
boolean fast = false;
|
||||
if((!rightOf & (e.b < 0.0)) | (rightOf & (e.b >= 0.0))){
|
||||
above = dyp >= e.b * dxp;
|
||||
fast = above;
|
||||
}else{
|
||||
above = p.x + p.y * e.b > e.c;
|
||||
if(e.b < 0.0){
|
||||
above = !above;
|
||||
}
|
||||
if(!above){
|
||||
fast = true;
|
||||
}
|
||||
}
|
||||
if(!fast){
|
||||
float dxs = topsite.coord.x - (e.reg[0]).coord.x;
|
||||
above = e.b * (dxp * dxp - dyp * dyp) < dxs * dyp
|
||||
* (1.0 + 2.0 * dxp / dxs + e.b * e.b);
|
||||
if(e.b < 0.0){
|
||||
above = !above;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
float yl = e.c - e.a * p.x;
|
||||
float t1 = p.y - yl;
|
||||
float t2 = p.x - topsite.coord.x;
|
||||
float t3 = yl - topsite.coord.y;
|
||||
above = t1 * t1 > t2 * t2 + t3 * t3;
|
||||
}
|
||||
return ((el.ELpm == LE) == above);
|
||||
}
|
||||
|
||||
private Site rightreg(Halfedge he){
|
||||
if(he.ELedge == null) return bottomsite;
|
||||
|
||||
return (he.ELpm == LE ? he.ELedge.reg[RE] : he.ELedge.reg[LE]);
|
||||
}
|
||||
|
||||
private Site intersect(Halfedge el1, Halfedge el2){
|
||||
Edge e1, e2, e;
|
||||
Halfedge el;
|
||||
float d, xint, yint;
|
||||
boolean right_of_site;
|
||||
Site v;
|
||||
|
||||
e1 = el1.ELedge;
|
||||
e2 = el2.ELedge;
|
||||
if(e1 == null || e2 == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(e1.reg[1] == e2.reg[1]){
|
||||
return null;
|
||||
}
|
||||
|
||||
d = e1.a * e2.b - e1.b * e2.a;
|
||||
if(-1.0e-10 < d && d < 1.0e-10){
|
||||
return null;
|
||||
}
|
||||
|
||||
xint = (e1.c * e2.b - e2.c * e1.b) / d;
|
||||
yint = (e2.c * e1.a - e1.c * e2.a) / d;
|
||||
|
||||
if((e1.reg[1].coord.y < e2.reg[1].coord.y)
|
||||
|| (e1.reg[1].coord.y == e2.reg[1].coord.y && e1.reg[1].coord.x < e2.reg[1].coord.x)){
|
||||
el = el1;
|
||||
e = e1;
|
||||
}else{
|
||||
el = el2;
|
||||
e = e2;
|
||||
}
|
||||
|
||||
right_of_site = xint >= e.reg[1].coord.x;
|
||||
if((right_of_site && el.ELpm == LE)
|
||||
|| (!right_of_site && el.ELpm == RE)){
|
||||
return null;
|
||||
}
|
||||
|
||||
v = new Site();
|
||||
v.coord.x = xint;
|
||||
v.coord.y = yint;
|
||||
return (v);
|
||||
}
|
||||
|
||||
static class Site{
|
||||
Vec2 coord = new Vec2();
|
||||
int sitenbr;
|
||||
}
|
||||
|
||||
static class Halfedge{
|
||||
Halfedge ELleft, ELright;
|
||||
Edge ELedge;
|
||||
boolean deleted;
|
||||
int ELpm;
|
||||
Site vertex;
|
||||
float ystar;
|
||||
Halfedge PQnext;
|
||||
}
|
||||
|
||||
public static class GraphEdge{
|
||||
public float x1, y1, x2, y2;
|
||||
|
||||
public int site1, site2;
|
||||
}
|
||||
|
||||
static class Edge{
|
||||
float a = 0, b = 0, c = 0;
|
||||
Site[] ep = new Site[2];
|
||||
Site[] reg = new Site[2];
|
||||
int edgenbr;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,9 +29,9 @@ import static mindustry.Vars.*;
|
|||
|
||||
public class Maps{
|
||||
/** List of all built-in maps. Filenames only. */
|
||||
private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "mudFlats", "moltenLake", "archipelago", "debrisField", "veins", "glacier"};
|
||||
private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "mudFlats", "moltenLake", "archipelago", "debrisField", "veins", "glacier", "passage"};
|
||||
/** Maps tagged as PvP */
|
||||
static final String[] pvpMaps = {"veins", "glacier"};
|
||||
static final String[] pvpMaps = {"veins", "glacier", "passage"};
|
||||
/** All maps stored in an ordered array. */
|
||||
private Seq<Map> maps = new Seq<>();
|
||||
/** Serializer for meta. */
|
||||
|
|
|
|||
|
|
@ -7,12 +7,14 @@ import mindustry.world.*;
|
|||
import static mindustry.maps.filters.FilterOption.*;
|
||||
|
||||
public class ClearFilter extends GenerateFilter{
|
||||
protected Block block = Blocks.air;
|
||||
protected Block target = Blocks.stone;
|
||||
protected Block replace = Blocks.air;
|
||||
|
||||
@Override
|
||||
public FilterOption[] options(){
|
||||
return new BlockOption[]{
|
||||
new BlockOption("block", () -> block, b -> block = b, b -> oresOnly.get(b) || wallsOnly.get(b))
|
||||
new BlockOption("target", () -> target, b -> target = b, anyOptional),
|
||||
new BlockOption("replacement", () -> replace, b -> replace = b, anyOptional)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -24,12 +26,21 @@ public class ClearFilter extends GenerateFilter{
|
|||
@Override
|
||||
public void apply(GenerateInput in){
|
||||
|
||||
if(in.block == block){
|
||||
in.block = Blocks.air;
|
||||
}
|
||||
|
||||
if(in.overlay == block){
|
||||
in.overlay = Blocks.air;
|
||||
if(in.block == target || in.floor == target || (target.isOverlay() && in.overlay == target)){
|
||||
//special case: when air is the result, replace only the overlay or wall
|
||||
if(replace == Blocks.air){
|
||||
if(in.overlay == target){
|
||||
in.overlay = Blocks.air;
|
||||
}else{
|
||||
in.block = Blocks.air;
|
||||
}
|
||||
}else if(replace.isOverlay()){ //replace the best match based on type
|
||||
in.overlay = replace;
|
||||
}else if(replace.isFloor()){
|
||||
in.floor = replace;
|
||||
}else{
|
||||
in.block = replace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package mindustry.mod;
|
||||
|
||||
import arc.struct.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
import mindustry.world.blocks.payloads.*;
|
||||
|
||||
/** Generated class. Maps simple class names to concrete classes. For use in JSON mods. */
|
||||
|
|
@ -173,8 +174,11 @@ public class ClassMap{
|
|||
classes.put("OreBlock", mindustry.world.blocks.environment.OreBlock.class);
|
||||
classes.put("OverlayFloor", mindustry.world.blocks.environment.OverlayFloor.class);
|
||||
classes.put("Prop", mindustry.world.blocks.environment.Prop.class);
|
||||
classes.put("Bush", Bush.class);
|
||||
classes.put("WavingProp", WavingProp.class);
|
||||
classes.put("ShallowLiquid", mindustry.world.blocks.environment.ShallowLiquid.class);
|
||||
classes.put("SpawnBlock", mindustry.world.blocks.environment.SpawnBlock.class);
|
||||
classes.put("StaticClusterWall", StaticClusterWall.class);
|
||||
classes.put("StaticTree", mindustry.world.blocks.environment.StaticTree.class);
|
||||
classes.put("StaticWall", mindustry.world.blocks.environment.StaticWall.class);
|
||||
classes.put("TreeBlock", mindustry.world.blocks.environment.TreeBlock.class);
|
||||
|
|
|
|||
|
|
@ -170,7 +170,8 @@ public class CustomRulesDialog extends BaseDialog{
|
|||
check("@rules.attack", b -> rules.attackMode = b, () -> rules.attackMode);
|
||||
check("@rules.buildai", b -> rules.teams.get(rules.waveTeam).ai = rules.teams.get(rules.waveTeam).infiniteResources = b, () -> rules.teams.get(rules.waveTeam).ai);
|
||||
check("@rules.corecapture", b -> rules.coreCapture = b, () -> rules.coreCapture);
|
||||
number("@rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200));
|
||||
check("@rules.polygoncoreprotection", b -> rules.polygonCoreProtection = b, () -> rules.polygonCoreProtection);
|
||||
number("@rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200), () -> !rules.polygonCoreProtection);
|
||||
|
||||
title("@rules.title.environment");
|
||||
check("@rules.explosions", b -> rules.damageExplosions = b, () -> rules.damageExplosions);
|
||||
|
|
|
|||
|
|
@ -229,6 +229,8 @@ public class Block extends UnlockableContent{
|
|||
public boolean instantDeconstruct = false;
|
||||
/** Effect for breaking the block. Passes size as rotation. */
|
||||
public Effect breakEffect = Fx.breakBlock;
|
||||
/** Effect for destroying the block. */
|
||||
public Effect destroyEffect = Fx.dynamicExplosion;
|
||||
/** Multiplier for cost of research in tech tree. */
|
||||
public float researchCostMultiplier = 1;
|
||||
/** Whether this block has instant transfer.*/
|
||||
|
|
|
|||
|
|
@ -10,9 +10,11 @@ import mindustry.content.*;
|
|||
import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.blocks.*;
|
||||
import mindustry.world.blocks.ConstructBlock.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
|
|
@ -132,7 +134,23 @@ public class Build{
|
|||
return false;
|
||||
}
|
||||
|
||||
if(state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset, y * tilesize + type.offset, core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){
|
||||
//find closest core, if it doesn't match the team, placing is not legal
|
||||
if(state.rules.polygonCoreProtection){
|
||||
float mindst = Float.MAX_VALUE;
|
||||
CoreBuild closest = null;
|
||||
for(TeamData data : state.teams.active){
|
||||
for(CoreBuild tile : data.cores){
|
||||
float dst = tile.dst2(x * tilesize + type.offset, y * tilesize + type.offset);
|
||||
if(dst < mindst){
|
||||
closest = tile;
|
||||
mindst = dst;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(closest != null && closest.team != team){
|
||||
return false;
|
||||
}
|
||||
}else if(state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset, y * tilesize + type.offset, core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class ImpactReactor extends PowerGenerator{
|
|||
public float itemDuration = 60f;
|
||||
public int explosionRadius = 23;
|
||||
public int explosionDamage = 1900;
|
||||
public Effect explodeEffect = Fx.impactReactorExplosion;
|
||||
|
||||
public Color plasma1 = Color.valueOf("ffd06b"), plasma2 = Color.valueOf("ff361b");
|
||||
|
||||
|
|
@ -137,32 +138,14 @@ public class ImpactReactor extends PowerGenerator{
|
|||
public void onDestroyed(){
|
||||
super.onDestroyed();
|
||||
|
||||
if(warmup < 0.4f || !state.rules.reactorExplosions) return;
|
||||
if(warmup < 0.3f || !state.rules.reactorExplosions) return;
|
||||
|
||||
Sounds.explosionbig.at(tile);
|
||||
|
||||
Effect.shake(6f, 16f, x, y);
|
||||
Fx.impactShockwave.at(x, y);
|
||||
for(int i = 0; i < 6; i++){
|
||||
Time.run(Mathf.random(80), () -> Fx.impactcloud.at(x, y));
|
||||
}
|
||||
|
||||
Damage.damage(x, y, explosionRadius * tilesize, explosionDamage * 4);
|
||||
|
||||
|
||||
for(int i = 0; i < 20; i++){
|
||||
Time.run(Mathf.random(80), () -> {
|
||||
Tmp.v1.rnd(Mathf.random(40f));
|
||||
Fx.explosion.at(Tmp.v1.x + x, Tmp.v1.y + y);
|
||||
});
|
||||
}
|
||||
|
||||
for(int i = 0; i < 70; i++){
|
||||
Time.run(Mathf.random(90), () -> {
|
||||
Tmp.v1.rnd(Mathf.random(120f));
|
||||
Fx.impactsmoke.at(Tmp.v1.x + x, Tmp.v1.y + y);
|
||||
});
|
||||
}
|
||||
Effect.shake(6f, 16f, x, y);
|
||||
explodeEffect.at(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -194,6 +194,20 @@ public class CoreBlock extends StorageBlock{
|
|||
super.damage(source, damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void created(){
|
||||
super.created();
|
||||
|
||||
Events.fire(new CoreChangeEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeTeam(Team next){
|
||||
super.changeTeam(next);
|
||||
|
||||
Events.fire(new CoreChangeEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double sense(LAccess sensor){
|
||||
if(sensor == LAccess.itemCapacity) return storageCapacity;
|
||||
|
|
@ -260,6 +274,8 @@ public class CoreBlock extends StorageBlock{
|
|||
spawner.getSpawns().add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
Events.fire(new CoreChangeEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@ kapt.include.compile.classpath=false
|
|||
kotlin.stdlib.default.dependency=false
|
||||
#needed for android compilation
|
||||
android.useAndroidX=true
|
||||
archash=07ced971f4c8b8b5a61aa3a84b29c90aa497cb48
|
||||
archash=df2786dd8de1ebc1b70c453d6dcac62c2ecf9e18
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue