mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-12-06 02:40:23 -08:00
World play area rule
This commit is contained in:
parent
e2c7c94663
commit
427d43039b
15 changed files with 196 additions and 54 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 277 B |
|
|
@ -1071,6 +1071,7 @@ rules.unithealthmultiplier = Unit Health Multiplier
|
|||
rules.unitdamagemultiplier = Unit Damage Multiplier
|
||||
rules.unitcapvariable = Cores Contribute To Unit Cap
|
||||
rules.unitcap = Base Unit Cap
|
||||
rules.limitarea = Limit Map Area
|
||||
rules.enemycorebuildradius = Enemy Core No-Build Radius:[lightgray] (tiles)
|
||||
rules.wavespacing = Wave Spacing:[lightgray] (sec)
|
||||
rules.initialwavespacing = Initial Wave Spacing:[lightgray] (sec)
|
||||
|
|
|
|||
|
|
@ -1079,7 +1079,9 @@ public class Fx{
|
|||
}),
|
||||
|
||||
ventSteam = new Effect(140f, e -> {
|
||||
color(e.color, e.fslope() * 0.85f);
|
||||
color(e.color, Pal.vent2, e.fin());
|
||||
|
||||
alpha(e.fslope() * 0.78f);
|
||||
|
||||
float length = 3f + e.finpow() * 10f;
|
||||
rand.setSeed(e.id);
|
||||
|
|
@ -1087,7 +1089,7 @@ public class Fx{
|
|||
v.trns(rand.random(360f), rand.random(length));
|
||||
Fill.circle(e.x + v.x, e.y + v.y, rand.random(1.2f, 3.5f) + e.fslope() * 1.1f);
|
||||
}
|
||||
}),
|
||||
}).layer(Layer.darkness - 1),
|
||||
|
||||
drillSteam = new Effect(220f, e -> {
|
||||
|
||||
|
|
|
|||
|
|
@ -223,6 +223,11 @@ public class Renderer implements ApplicationListener{
|
|||
}
|
||||
}
|
||||
|
||||
public void updateAllDarkness(){
|
||||
blocks.updateDarkness();
|
||||
minimap.updateAll();
|
||||
}
|
||||
|
||||
/** @return whether a launch/land cutscene is playing. */
|
||||
public boolean isCutscene(){
|
||||
return landTime > 0;
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ public class World{
|
|||
}
|
||||
|
||||
public Rect getQuadBounds(Rect in){
|
||||
return in.set(-finalWorldBounds, -finalWorldBounds, world.width() * tilesize + finalWorldBounds * 2, world.height() * tilesize + finalWorldBounds * 2);
|
||||
return in.set(-finalWorldBounds, -finalWorldBounds, width() * tilesize + finalWorldBounds * 2, height() * tilesize + finalWorldBounds * 2);
|
||||
}
|
||||
|
||||
public void setGenerating(boolean gen){
|
||||
|
|
@ -295,8 +295,8 @@ public class World{
|
|||
ObjectSet<UnlockableContent> content = new ObjectSet<>();
|
||||
|
||||
//TODO duplicate code?
|
||||
for(Tile tile : world.tiles){
|
||||
if(world.getDarkness(tile.x, tile.y) >= 3){
|
||||
for(Tile tile : tiles){
|
||||
if(getDarkness(tile.x, tile.y) >= 3){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +499,17 @@ public class World{
|
|||
|
||||
if(Vars.state.rules.borderDarkness){
|
||||
int edgeBlend = 2;
|
||||
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (tiles.width - 1)), Math.abs(y - (tiles.height - 1)))));
|
||||
int edgeDst;
|
||||
|
||||
if(!state.rules.limitMapArea){
|
||||
edgeDst = Math.min(x, Math.min(y, Math.min(-(x - (tiles.width - 1)), -(y - (tiles.height - 1)))));
|
||||
}else{
|
||||
edgeDst =
|
||||
Math.min(x - state.rules.limitX,
|
||||
Math.min(y - state.rules.limitY,
|
||||
Math.min(-(x - (state.rules.limitX + state.rules.limitWidth - 1)), -(y - (state.rules.limitY + state.rules.limitHeight - 1)))));
|
||||
}
|
||||
|
||||
if(edgeDst <= edgeBlend){
|
||||
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
|
||||
}
|
||||
|
|
@ -529,7 +539,7 @@ public class World{
|
|||
}
|
||||
}
|
||||
|
||||
Tile tile = world.tile(x, y);
|
||||
Tile tile = tile(x, y);
|
||||
if(tile != null && tile.isDarkened()){
|
||||
dark = Math.max(dark, tile.data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package mindustry.entities.comp;
|
|||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
|
@ -12,30 +13,41 @@ abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{
|
|||
static final float warpDst = 30f;
|
||||
|
||||
@Import float x, y;
|
||||
@Import Team team;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
float bot = 0f, left = 0f, top = world.unitHeight(), right = world.unitWidth();
|
||||
|
||||
//TODO hidden map rules only apply to player teams? should they?
|
||||
if(state.rules.borderDarkness && !team.isAI()){
|
||||
bot = state.rules.limitY * tilesize;
|
||||
left = state.rules.limitX * tilesize;
|
||||
top = state.rules.limitHeight * tilesize + bot;
|
||||
right = state.rules.limitWidth * tilesize + left;
|
||||
}
|
||||
|
||||
if(!net.client() || isLocal()){
|
||||
|
||||
float dx = 0f, dy = 0f;
|
||||
|
||||
//repel unit out of bounds
|
||||
if(x < 0) dx += (-x/warpDst);
|
||||
if(y < 0) dy += (-y/warpDst);
|
||||
if(x > world.unitWidth()) dx -= (x - world.unitWidth())/warpDst;
|
||||
if(y > world.unitHeight()) dy -= (y - world.unitHeight())/warpDst;
|
||||
if(x < left) dx += (-(x - left)/warpDst);
|
||||
if(y < bot) dy += (-(y - bot)/warpDst);
|
||||
if(x > right) dx -= (x - right)/warpDst;
|
||||
if(y > top) dy -= (y - top)/warpDst;
|
||||
|
||||
velAddNet(dx * Time.delta, dy * Time.delta);
|
||||
}
|
||||
|
||||
//clamp position if not flying
|
||||
if(isGrounded()){
|
||||
x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize);
|
||||
y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize);
|
||||
x = Mathf.clamp(x, left, right - tilesize);
|
||||
y = Mathf.clamp(y, bot, top - tilesize);
|
||||
}
|
||||
|
||||
//kill when out of bounds
|
||||
if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){
|
||||
if(x < -finalWorldBounds + left || y < -finalWorldBounds + bot || x >= right + finalWorldBounds || y >= top + finalWorldBounds){
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -134,6 +134,10 @@ public class Rules{
|
|||
public boolean coreIncinerates = false;
|
||||
/** If false, borders fade out into darkness. Only use with custom backgrounds!*/
|
||||
public boolean borderDarkness = true;
|
||||
/** If true, the map play area is cropped based on the rectangle below. */
|
||||
public boolean limitMapArea = false;
|
||||
/** Map area limit rectangle. */
|
||||
public int limitX, limitY, limitWidth = 1, limitHeight = 1;
|
||||
/** special tags for additional info. */
|
||||
public StringMap tags = new StringMap();
|
||||
/** Name of callback to call for background rendering in mods; see Renderer#addCustomBackground. Runs last. */
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ public class BlockRenderer{
|
|||
blockTree = new BlockQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
floorTree = new FloorQuadtree(new Rect(0, 0, world.unitWidth(), world.unitHeight()));
|
||||
shadowEvents.clear();
|
||||
updateFloors.clear();
|
||||
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
|
||||
|
||||
shadows.getTexture().setFilter(TextureFilter.linear, TextureFilter.linear);
|
||||
|
|
@ -74,6 +75,12 @@ public class BlockRenderer{
|
|||
Draw.color(blendShadowColor);
|
||||
|
||||
for(Tile tile : world.tiles){
|
||||
recordIndex(tile);
|
||||
|
||||
if(tile.floor().updateRender(tile)){
|
||||
updateFloors.add(new UpdateRenderState(tile, tile.floor()));
|
||||
}
|
||||
|
||||
if(tile.block().hasShadow){
|
||||
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
||||
}
|
||||
|
|
@ -83,31 +90,7 @@ public class BlockRenderer{
|
|||
Draw.color();
|
||||
shadows.end();
|
||||
|
||||
updateFloors.clear();
|
||||
dark.getTexture().setFilter(TextureFilter.linear);
|
||||
dark.resize(world.width(), world.height());
|
||||
dark.begin();
|
||||
Core.graphics.clear(Color.white);
|
||||
Draw.proj().setOrtho(0, 0, dark.getWidth(), dark.getHeight());
|
||||
|
||||
for(Tile tile : world.tiles){
|
||||
recordIndex(tile);
|
||||
|
||||
if(tile.floor().updateRender(tile)){
|
||||
updateFloors.add(new UpdateRenderState(tile, tile.floor()));
|
||||
}
|
||||
|
||||
float darkness = world.getDarkness(tile.x, tile.y);
|
||||
|
||||
if(darkness > 0){
|
||||
Draw.colorl(1f - Math.min((darkness + 0.5f) / 4f, 1f));
|
||||
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
Draw.color();
|
||||
dark.end();
|
||||
updateDarkness();
|
||||
});
|
||||
|
||||
Events.on(TilePreChangeEvent.class, event -> {
|
||||
|
|
@ -132,6 +115,42 @@ public class BlockRenderer{
|
|||
});
|
||||
}
|
||||
|
||||
public void updateDarkness(){
|
||||
darkEvents.clear();
|
||||
dark.getTexture().setFilter(TextureFilter.linear);
|
||||
dark.resize(world.width(), world.height());
|
||||
dark.begin();
|
||||
|
||||
//fill darkness with black when map area is limited
|
||||
Core.graphics.clear(state.rules.limitMapArea ? Color.black : Color.white);
|
||||
Draw.proj().setOrtho(0, 0, dark.getWidth(), dark.getHeight());
|
||||
|
||||
//clear out initial starting area
|
||||
if(state.rules.limitMapArea){
|
||||
Draw.color(Color.white);
|
||||
Fill.crect(state.rules.limitX, state.rules.limitY, state.rules.limitWidth, state.rules.limitHeight);
|
||||
}
|
||||
|
||||
for(Tile tile : world.tiles){
|
||||
//skip lighting outside rect
|
||||
if(state.rules.limitMapArea && !Rect.contains(state.rules.limitX, state.rules.limitY, state.rules.limitWidth - 1, state.rules.limitHeight - 1, tile.x, tile.y)){
|
||||
continue;
|
||||
}
|
||||
|
||||
float darkness = world.getDarkness(tile.x, tile.y);
|
||||
|
||||
if(darkness > 0){
|
||||
float dark = 1f - Math.min((darkness + 0.5f) / 4f, 1f);
|
||||
Draw.colorl(dark);
|
||||
Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.flush();
|
||||
Draw.color();
|
||||
dark.end();
|
||||
}
|
||||
|
||||
public void invalidateTile(Tile tile){
|
||||
int avgx = (int)(camera.position.x / tilesize);
|
||||
int avgy = (int)(camera.position.y / tilesize);
|
||||
|
|
|
|||
|
|
@ -132,5 +132,6 @@ public class Pal{
|
|||
slagOrange = Color.valueOf("ffa166"),
|
||||
techBlue = Color.valueOf("8ca9e8"),
|
||||
|
||||
vent = Color.valueOf("6b4e4e");
|
||||
vent = Color.valueOf("6b4e4e"),
|
||||
vent2 = Color.valueOf("261d1d");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1269,11 +1269,15 @@ public class LExecutor{
|
|||
|
||||
public static class SetRuleI implements LInstruction{
|
||||
public LogicRule rule = LogicRule.waveSpacing;
|
||||
public int value;
|
||||
public int value, p1, p2, p3, p4;
|
||||
|
||||
public SetRuleI(LogicRule rule, int value){
|
||||
public SetRuleI(LogicRule rule, int value, int p1, int p2, int p3, int p4){
|
||||
this.rule = rule;
|
||||
this.value = value;
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.p3 = p3;
|
||||
this.p4 = p4;
|
||||
}
|
||||
|
||||
public SetRuleI(){
|
||||
|
|
@ -1291,11 +1295,62 @@ public class LExecutor{
|
|||
case dropZoneRadius -> state.rules.dropZoneRadius = exec.numf(value) * 8f;
|
||||
case unitCap -> state.rules.unitCap = exec.numi(value);
|
||||
case lighting -> state.rules.lighting = exec.bool(value);
|
||||
case mapArea -> {
|
||||
int x = exec.numi(p1), y = exec.numi(p2), w = exec.numi(p3), h = exec.numi(p4);
|
||||
if(!checkMapArea(x, y, w, h, false)){
|
||||
Call.setMapArea(x, y, w, h);
|
||||
}
|
||||
}
|
||||
case ambientLight -> state.rules.ambientLight.fromDouble(exec.num(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return whether the map area is already set to this value. */
|
||||
static boolean checkMapArea(int x, int y, int w, int h, boolean set){
|
||||
x = Math.max(x, 0);
|
||||
y = Math.max(y, 0);
|
||||
w = Math.min(world.width(), w);
|
||||
h = Math.min(world.height(), h);
|
||||
boolean full = x == 0 && y == 0 && w == world.width() && h == world.height();
|
||||
|
||||
if(state.rules.limitMapArea){
|
||||
if(state.rules.limitX == x && state.rules.limitY == y && state.rules.limitWidth == w && state.rules.limitHeight == h){
|
||||
return true;
|
||||
}else if(full){
|
||||
//disable the rule, covers the whole map
|
||||
if(set){
|
||||
state.rules.limitMapArea = false;
|
||||
if(!headless){
|
||||
renderer.updateAllDarkness();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}else if(full){ //was already disabled, no need to change anything
|
||||
return true;
|
||||
}
|
||||
|
||||
if(set){
|
||||
state.rules.limitMapArea = true;
|
||||
state.rules.limitX = x;
|
||||
state.rules.limitY = y;
|
||||
state.rules.limitWidth = w;
|
||||
state.rules.limitHeight = h;
|
||||
|
||||
if(!headless){
|
||||
renderer.updateAllDarkness();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void setMapArea(int x, int y, int w, int h){
|
||||
checkMapArea(x, y, w, h, true);
|
||||
}
|
||||
|
||||
public static class FlushMessageI implements LInstruction{
|
||||
public MessageType type = MessageType.announce;
|
||||
public int duration;
|
||||
|
|
|
|||
|
|
@ -1237,19 +1237,39 @@ public class LStatements{
|
|||
@RegisterStatement("setrule")
|
||||
public static class SetRuleStatement extends LStatement{
|
||||
public LogicRule rule = LogicRule.waveSpacing;
|
||||
public String value = "100";
|
||||
public String value = "100", p1 = "0", p2 = "0", p3 = "100", p4 = "100";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
rebuild(table);
|
||||
}
|
||||
|
||||
void rebuild(Table table){
|
||||
table.clearChildren();
|
||||
|
||||
table.button(b -> {
|
||||
b.label(() -> rule.name()).growX().wrap().labelAlign(Align.center);
|
||||
b.clicked(() -> showSelect(b, LogicRule.all, rule, o -> rule = o, 2, c -> c.width(150f)));
|
||||
b.clicked(() -> showSelect(b, LogicRule.all, rule, o -> {
|
||||
rule = o;
|
||||
rebuild(table);
|
||||
}, 2, c -> c.width(150f)));
|
||||
}, Styles.logict, () -> {}).size(160f, 40f).pad(4f).color(table.color);
|
||||
|
||||
table.add(" = ");
|
||||
|
||||
switch(rule){
|
||||
case mapArea -> {
|
||||
fields(table, "x", p1, s -> p1 = s);
|
||||
fields(table, "y", p2, s -> p2 = s);
|
||||
row(table);
|
||||
fields(table, "w", p3, s -> p3 = s);
|
||||
fields(table, "h", p4, s -> p4 = s);
|
||||
}
|
||||
default -> {
|
||||
field(table, value, s -> value = s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean privileged(){
|
||||
|
|
@ -1263,7 +1283,7 @@ public class LStatements{
|
|||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new SetRuleI(rule, builder.var(value));
|
||||
return new SetRuleI(rule, builder.var(value), builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ public enum LogicRule{
|
|||
enemyCoreBuildRadius,
|
||||
dropZoneRadius,
|
||||
unitCap,
|
||||
mapArea,
|
||||
lighting,
|
||||
ambientLight;
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ public class CustomRulesDialog extends BaseDialog{
|
|||
title("@rules.title.unit");
|
||||
check("@rules.unitammo", b -> rules.unitAmmo = b, () -> rules.unitAmmo);
|
||||
check("@rules.unitcapvariable", b -> rules.unitCapVariable = b, () -> rules.unitCapVariable);
|
||||
number("@rules.unitcap", true, f -> rules.unitCap = f, () -> rules.unitCap, -999, 999);
|
||||
numberi("@rules.unitcap", f -> rules.unitCap = f, () -> rules.unitCap, -999, 999);
|
||||
number("@rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
|
||||
number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier, 0.001f, 50f);
|
||||
|
||||
|
|
@ -194,6 +194,14 @@ public class CustomRulesDialog extends BaseDialog{
|
|||
check("@rules.lighting", b -> rules.lighting = b, () -> rules.lighting);
|
||||
check("@rules.enemyLights", b -> rules.enemyLights = b, () -> rules.enemyLights);
|
||||
|
||||
if(experimental){
|
||||
check("@rules.limitarea", b -> rules.limitMapArea = b, () -> rules.limitMapArea);
|
||||
numberi("x", x -> state.rules.limitX = x, () -> state.rules.limitX, () -> state.rules.limitMapArea, 0, 10000);
|
||||
numberi("y", y -> state.rules.limitY = y, () -> state.rules.limitY, () -> state.rules.limitMapArea, 0, 10000);
|
||||
numberi("w", w -> state.rules.limitWidth = w, () -> state.rules.limitWidth, () -> state.rules.limitMapArea, 0, 10000);
|
||||
numberi("h", h -> state.rules.limitHeight = h, () -> state.rules.limitHeight, () -> state.rules.limitMapArea, 0, 10000);
|
||||
}
|
||||
|
||||
main.button(b -> {
|
||||
b.left();
|
||||
b.table(Tex.pane, in -> {
|
||||
|
|
@ -270,12 +278,17 @@ public class CustomRulesDialog extends BaseDialog{
|
|||
number(text, false, cons, prov, condition, 0, Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
//TODO integer param unused
|
||||
void number(String text, boolean integer, Intc cons, Intp prov, int min, int max){
|
||||
void numberi(String text, Intc cons, Intp prov, int min, int max){
|
||||
numberi(text, cons, prov, () -> true, min, max);
|
||||
}
|
||||
|
||||
void numberi(String text, Intc cons, Intp prov, Boolp condition, int min, int max){
|
||||
main.table(t -> {
|
||||
t.left();
|
||||
t.add(text).left().padRight(5);
|
||||
t.add(text).left().padRight(5)
|
||||
.update(a -> a.setColor(condition.get() ? Color.white : Color.gray));
|
||||
t.field((prov.get()) + "", s -> cons.get(Strings.parseInt(s)))
|
||||
.update(a -> a.setDisabled(!condition.get()))
|
||||
.padRight(100f)
|
||||
.valid(f -> Strings.parseInt(f) >= min && Strings.parseInt(f) <= max).width(120f).left();
|
||||
}).padTop(0).row();
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import mindustry.world.meta.*;
|
|||
import static mindustry.Vars.*;
|
||||
|
||||
/** A turret that fires a continuous beam with a delay between shots. Liquid coolant is required. Yes, this class name is awful. NEEDS RENAME */
|
||||
@Deprecated
|
||||
public class LaserTurret extends PowerTurret{
|
||||
public float firingMoveFract = 0.25f;
|
||||
public float shootDuration = 100f;
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ android.useAndroidX=true
|
|||
#used for slow jitpack builds; TODO see if this actually works
|
||||
org.gradle.internal.http.socketTimeout=100000
|
||||
org.gradle.internal.http.connectionTimeout=100000
|
||||
archash=4775df2392
|
||||
archash=ea5e9c0c40
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue