Merge branch 'master' of https://github.com/Anuken/Mindustry into adjacent-campaign-sectors
This commit is contained in:
@@ -147,7 +147,7 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{
|
||||
if(hasAll){
|
||||
Call.beginPlace(self(), current.block, team, current.x, current.y, current.rotation);
|
||||
|
||||
if(current.block.instantBuild){
|
||||
if(!net.client() && current.block.instantBuild){
|
||||
if(plans.size > 0){
|
||||
plans.removeFirst();
|
||||
}
|
||||
@@ -188,7 +188,7 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{
|
||||
//otherwise, update it.
|
||||
if(current.breaking){
|
||||
entity.deconstruct(self(), core, bs);
|
||||
}else if(entity.current != null && entity.current.unlockedNowHost()){ //only allow building unlocked blocks
|
||||
}else if(entity.current != null && (state.isEditor() || (state.rules.waves && team == state.rules.waveTeam && entity.current.isVisible()) || (entity.current.unlockedNowHost() && entity.current.environmentBuildable() && entity.current.isPlaceable()))){ //only allow building unlocked blocks
|
||||
entity.construct(self(), core, bs, current.config);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import static mindustry.logic.GlobalVars.*;
|
||||
@Component(base = true)
|
||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Syncc, Shieldc, Displayable, Ranged, Minerc, Builderc, Senseable, Settable{
|
||||
private static final Vec2 tmp1 = new Vec2(), tmp2 = new Vec2();
|
||||
static final float warpDst = 30f;
|
||||
static final float warpDst = 20f;
|
||||
|
||||
@Import boolean dead, disarmed;
|
||||
@Import float x, y, rotation, maxHealth, drag, armor, hitSize, health, shield, ammo, dragMultiplier, armorOverride, speedMultiplier;
|
||||
@@ -647,6 +647,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
if(y > top) dy -= (y - top)/warpDst;
|
||||
|
||||
velAddNet(dx * Time.delta, dy * Time.delta);
|
||||
float margin = tilesize * 2f;
|
||||
x = Mathf.clamp(x, left - margin, right - tilesize + margin);
|
||||
y = Mathf.clamp(y, bot - margin, top - tilesize + margin);
|
||||
}
|
||||
|
||||
//clamp position if not flying
|
||||
@@ -771,7 +774,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
//move down
|
||||
elevation -= type.fallSpeed * Time.delta;
|
||||
|
||||
if(isGrounded() || health <= -maxHealth){
|
||||
if(isGrounded() || health <= -maxHealth * type.wreckHealthMultiplier){
|
||||
Call.unitDestroy(id);
|
||||
}
|
||||
}
|
||||
@@ -866,7 +869,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
//if this unit crash landed (was flying), damage stuff in a radius
|
||||
if(type.flying && !spawnedByCore && type.createWreck && state.rules.unitCrashDamage(team) > 0){
|
||||
var shields = indexer.getEnemy(team, BlockFlag.shield);
|
||||
float crashDamage = Mathf.pow(hitSize, 0.75f) * type.crashDamageMultiplier * 5f * state.rules.unitCrashDamage(team);
|
||||
float crashDamage = Mathf.pow(hitSize, 0.75f) * type.crashDamageMultiplier * 2.5f * state.rules.unitCrashDamage(team);
|
||||
if(shields.isEmpty() || !shields.contains(b -> b instanceof ExplosionShield s && s.absorbExplosion(x, y, crashDamage))){
|
||||
Damage.damage(team, x, y, Mathf.pow(hitSize, 0.94f) * 1.25f, crashDamage, true, false, true);
|
||||
}
|
||||
|
||||
@@ -1242,6 +1242,7 @@ public class MapObjectives implements Iterable<MapObjective>, Eachable<MapObject
|
||||
@Override
|
||||
public void setTexture(String textureName){
|
||||
this.textureName = textureName;
|
||||
if(headless) return;
|
||||
|
||||
boolean firstUpdate = fetchedRegion == null;
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ public class SectorInfo{
|
||||
}
|
||||
|
||||
/** Prepare data for writing to a save. */
|
||||
public void prepare(){
|
||||
public void prepare(Sector sector){
|
||||
//update core items
|
||||
items.clear();
|
||||
|
||||
@@ -237,12 +237,10 @@ public class SectorInfo{
|
||||
export.clear();
|
||||
}
|
||||
|
||||
if(state.rules.sector != null){
|
||||
state.rules.sector.saveInfo();
|
||||
}
|
||||
sector.saveInfo();
|
||||
|
||||
if(state.rules.sector != null && state.rules.sector.planet.allowWaveSimulation){
|
||||
SectorDamage.writeParameters(this);
|
||||
if(sector.planet.allowWaveSimulation){
|
||||
SectorDamage.writeParameters(sector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ public class Universe{
|
||||
sector.info.wavesPassed = wavesPassed;
|
||||
}
|
||||
|
||||
float damage = attacked ? SectorDamage.getDamage(sector.info) : 0f;
|
||||
float damage = attacked ? SectorDamage.getDamage(sector) : 0f;
|
||||
|
||||
//damage never goes down until the player visits the sector, so use max
|
||||
sector.info.damage = Math.max(sector.info.damage, damage);
|
||||
|
||||
@@ -118,7 +118,7 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
public void writeMeta(DataOutput stream, StringMap tags) throws IOException{
|
||||
//prepare campaign data for writing
|
||||
if(state.isCampaign()){
|
||||
state.rules.sector.info.prepare();
|
||||
state.rules.sector.info.prepare(state.rules.sector);
|
||||
state.rules.sector.saveInfo();
|
||||
}
|
||||
|
||||
|
||||
@@ -1216,8 +1216,7 @@ public class LExecutor{
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public PackColorI(){
|
||||
}
|
||||
public PackColorI(){}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
@@ -1225,6 +1224,29 @@ public class LExecutor{
|
||||
}
|
||||
}
|
||||
|
||||
public static class UnpackColorI implements LInstruction{
|
||||
public LVar r, g, b, a, value;
|
||||
|
||||
public UnpackColorI(LVar r, LVar g, LVar b, LVar a, LVar value){
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public UnpackColorI(){}
|
||||
|
||||
@Override
|
||||
public void run(LExecutor exec){
|
||||
var color = Tmp.c1.fromDouble(value.num());
|
||||
r.setnum(color.r);
|
||||
g.setnum(color.g);
|
||||
b.setnum(color.b);
|
||||
a.setnum(color.a);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CutsceneI implements LInstruction{
|
||||
public CutsceneAction action = CutsceneAction.stop;
|
||||
public LVar p1, p2, p3, p4;
|
||||
|
||||
@@ -244,6 +244,10 @@ public abstract class LStatement{
|
||||
|
||||
}
|
||||
|
||||
public String typeName(){
|
||||
return getClass().getSimpleName().replace("Statement", "");
|
||||
}
|
||||
|
||||
public String name(){
|
||||
return Strings.insertSpaces(getClass().getSimpleName().replace("Statement", ""));
|
||||
}
|
||||
|
||||
@@ -897,6 +897,35 @@ public class LStatements{
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("unpackcolor")
|
||||
public static class UnpackColorStatement extends LStatement{
|
||||
public String r = "r", g = "g", b = "b", a = "a", value = "color";
|
||||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
fields(table, r, str -> r = str);
|
||||
fields(table, g, str -> g = str);
|
||||
fields(table, b, str -> b = str);
|
||||
fields(table, a, str -> a = str);
|
||||
|
||||
row(table);
|
||||
|
||||
table.add(" = unpack ");
|
||||
|
||||
fields(table, value, str -> value = str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LInstruction build(LAssembler builder){
|
||||
return new UnpackColorI(builder.var(r), builder.var(g), builder.var(b), builder.var(a), builder.var(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public LCategory category(){
|
||||
return LCategory.operation;
|
||||
}
|
||||
}
|
||||
|
||||
@RegisterStatement("end")
|
||||
public static class EndStatement extends LStatement{
|
||||
@Override
|
||||
@@ -1605,6 +1634,8 @@ public class LStatements{
|
||||
case mapArea -> {
|
||||
table.add(" = ");
|
||||
|
||||
row(table);
|
||||
|
||||
fields(table, "x", p1, s -> p1 = s);
|
||||
fields(table, "y", p2, s -> p2 = s);
|
||||
row(table);
|
||||
@@ -1624,7 +1655,7 @@ public class LStatements{
|
||||
case ban, unban -> {
|
||||
table.add(" block/unit ");
|
||||
|
||||
field(table, value, s -> value = s);
|
||||
fields(table, value, s -> value = s);
|
||||
}
|
||||
default -> {
|
||||
table.add(" = ");
|
||||
|
||||
@@ -295,7 +295,8 @@ public class LogicDialog extends BaseDialog{
|
||||
|
||||
for(Prov<LStatement> prov : LogicIO.allStatements){
|
||||
LStatement example = prov.get();
|
||||
if(example instanceof InvalidStatement || example.hidden() || (example.privileged() && !privileged) || (example.nonPrivileged() && privileged) || (!text.isEmpty() && !example.name().toLowerCase(Locale.ROOT).contains(text))) continue;
|
||||
if(example instanceof InvalidStatement || example.hidden() || (example.privileged() && !privileged) || (example.nonPrivileged() && privileged) ||
|
||||
(!text.isEmpty() && !example.name().toLowerCase(Locale.ROOT).contains(text) && !example.typeName().toLowerCase(Locale.ROOT).contains(text))) continue;
|
||||
|
||||
if(matched[0] == null){
|
||||
matched[0] = prov;
|
||||
|
||||
@@ -36,10 +36,12 @@ public enum LogicOp{
|
||||
len("len", true, (x, y) -> Mathf.dst((float)x, (float)y)),
|
||||
noise("noise", true, (x, y) -> Simplex.raw2d(0, x, y)),
|
||||
abs("abs", a -> Math.abs(a)), //not a method reference because it fails to compile for some reason
|
||||
sign("sign", Math::signum),
|
||||
log("log", Math::log),
|
||||
log10("log10", Math::log10),
|
||||
floor("floor", Math::floor),
|
||||
ceil("ceil", Math::ceil),
|
||||
round("round", Math::round),
|
||||
sqrt("sqrt", Math::sqrt),
|
||||
rand("rand", d -> GlobalVars.rand.nextDouble() * d),
|
||||
|
||||
|
||||
@@ -239,7 +239,7 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
int modes = Boolean.compare(Gamemode.pvp.valid(this), Gamemode.pvp.valid(map));
|
||||
if(modes != 0) return modes;
|
||||
|
||||
return name().compareTo(map.name());
|
||||
return Strings.stripColors(name()).compareTo(Strings.stripColors(map.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,23 +27,24 @@ public class SectorDamage{
|
||||
private static final boolean rubble = true;
|
||||
|
||||
/** @return calculated capture progress of the enemy */
|
||||
public static float getDamage(SectorInfo info){
|
||||
return getDamage(info, info.wavesPassed);
|
||||
public static float getDamage(Sector sector){
|
||||
return getDamage(sector, sector.info.wavesPassed);
|
||||
}
|
||||
|
||||
/** @return calculated capture progress of the enemy */
|
||||
public static float getDamage(SectorInfo info, int wavesPassed){
|
||||
return getDamage(info, wavesPassed, false);
|
||||
public static float getDamage(Sector sector, int wavesPassed){
|
||||
return getDamage(sector, wavesPassed, false);
|
||||
}
|
||||
|
||||
/** @return maximum waves survived, up to maxRetWave. */
|
||||
public static int getWavesSurvived(SectorInfo info){
|
||||
return (int)getDamage(info, maxRetWave, true);
|
||||
public static int getWavesSurvived(Sector sector){
|
||||
return (int)getDamage(sector, maxRetWave, true);
|
||||
}
|
||||
|
||||
/** @return calculated capture progress of the enemy if retWave is false, otherwise return the maximum waves survived as int.
|
||||
* if it survives all the waves, returns maxRetWave. */
|
||||
public static float getDamage(SectorInfo info, int wavesPassed, boolean retWave){
|
||||
public static float getDamage(Sector sector, int wavesPassed, boolean retWave){
|
||||
var info = sector.info;
|
||||
float health = info.sumHealth;
|
||||
int wave = info.wave;
|
||||
float waveSpace = info.waveSpacing;
|
||||
@@ -64,18 +65,20 @@ public class SectorDamage{
|
||||
for(int i = waveBegin; i <= waveEnd; i++){
|
||||
float enemyDps = 0f, enemyHealth = 0f;
|
||||
|
||||
for(SpawnGroup group : state.rules.spawns){
|
||||
//calculate the amount of spawn points used
|
||||
//if there's a spawn position override, there is only one potential place they spawn
|
||||
//assume that all overridden positions are valid, should always be true in properly designed campaign maps
|
||||
int spawnCount = group.spawn != -1 ? 1 : group.type.flying ? airSpawns : groundSpawns;
|
||||
if(sector.save != null || sector.isBeingPlayed()){
|
||||
for(SpawnGroup group : (sector.isBeingPlayed() ? state.rules.spawns : sector.save.meta.rules.spawns)){
|
||||
//calculate the amount of spawn points used
|
||||
//if there's a spawn position override, there is only one potential place they spawn
|
||||
//assume that all overridden positions are valid, should always be true in properly designed campaign maps
|
||||
int spawnCount = group.spawn != -1 ? 1 : group.type.flying ? airSpawns : groundSpawns;
|
||||
|
||||
float healthMult = 1f + Mathf.clamp(group.type.armor / 20f);
|
||||
StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect);
|
||||
int spawned = group.getSpawned(i) * spawnCount;
|
||||
if(spawned <= 0) continue;
|
||||
enemyHealth += spawned * (group.getShield(i) + group.type.health * effect.healthMultiplier * healthMult);
|
||||
enemyDps += spawned * group.type.dpsEstimate * effect.damageMultiplier;
|
||||
float healthMult = 1f + Mathf.clamp(group.type.armor / 20f);
|
||||
StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect);
|
||||
int spawned = group.getSpawned(i) * spawnCount;
|
||||
if(spawned <= 0) continue;
|
||||
enemyHealth += spawned * (group.getShield(i) + group.type.health * effect.healthMultiplier * healthMult);
|
||||
enemyDps += spawned * group.type.dpsEstimate * effect.damageMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
float efficiency = health / info.sumHealth;
|
||||
@@ -106,7 +109,7 @@ public class SectorDamage{
|
||||
if(timeDestroyEnemy > timeDestroyBase){
|
||||
health = 0f;
|
||||
//return current wave if simulating
|
||||
if(retWave) return i - waveBegin;
|
||||
if(retWave) return Math.max(i - waveBegin - 1, waveBegin);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -132,7 +135,7 @@ public class SectorDamage{
|
||||
/** Applies wave damage based on sector parameters. */
|
||||
public static void applyCalculatedDamage(){
|
||||
//calculate base damage fraction
|
||||
float damage = getDamage(state.rules.sector.info);
|
||||
float damage = getDamage(state.rules.sector);
|
||||
|
||||
//scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier)
|
||||
float scaled = Mathf.pow(damage, 1.2f);
|
||||
@@ -187,7 +190,8 @@ public class SectorDamage{
|
||||
}
|
||||
|
||||
/** Calculates damage simulation parameters before a game is saved. */
|
||||
public static void writeParameters(SectorInfo info){
|
||||
public static void writeParameters(Sector sector){
|
||||
var info = sector.info;
|
||||
Building core = state.rules.defaultTeam.core();
|
||||
Seq<Tile> spawns = new Seq<>();
|
||||
spawner.eachGroundSpawn((x, y) -> spawns.add(world.tile(x, y)));
|
||||
@@ -370,7 +374,7 @@ public class SectorDamage{
|
||||
info.curEnemyDps = curEnemyDps*cmult;
|
||||
info.curEnemyHealth = curEnemyHealth*cmult;
|
||||
|
||||
info.wavesSurvived = getWavesSurvived(info);
|
||||
info.wavesSurvived = getWavesSurvived(sector);
|
||||
}
|
||||
|
||||
public static void apply(float fraction){
|
||||
|
||||
@@ -93,6 +93,8 @@ public class UnitType extends UnlockableContent implements Senseable{
|
||||
buildRange = Vars.buildingRange,
|
||||
/** multiplier for damage this (flying) unit deals when crashing on enemy things */
|
||||
crashDamageMultiplier = 1f,
|
||||
/** multiplier for health that this flying unit has for its wreck, based on its max health. */
|
||||
wreckHealthMultiplier = 0.25f,
|
||||
/** a VERY ROUGH estimate of unit DPS; initialized in init() */
|
||||
dpsEstimate = -1,
|
||||
/** graphics clipping size; <0 to calculate automatically */
|
||||
|
||||
Reference in New Issue
Block a user