Merge remote-tracking branch 'origin/master'

This commit is contained in:
Anuken
2025-09-06 15:53:50 -04:00
44 changed files with 216 additions and 43 deletions

View File

@@ -14,6 +14,8 @@ public class RepairFieldAbility extends Ability{
public Effect healEffect = Fx.heal;
public Effect activeEffect = Fx.healWaveDynamic;
public boolean parentizeEffects = false;
/** Multiplies healing to units of the same type by this amount. */
public float sameTypeHealMult = 1f;
protected float timer;
protected boolean wasHealed = false;
@@ -32,6 +34,10 @@ public class RepairFieldAbility extends Ability{
t.add(Core.bundle.format("bullet.range", Strings.autoFixed(range / tilesize, 2)));
t.row();
t.add(abilityStat("repairspeed", Strings.autoFixed(amount * 60f / reload, 2)));
if(sameTypeHealMult != 1f){
t.row();
t.add(abilityStat("sametypehealmultiplier", (sameTypeHealMult < 1f ? "[negstat]" : "") + Strings.autoFixed(sameTypeHealMult * 100f, 2)));
}
}
@Override
@@ -46,7 +52,8 @@ public class RepairFieldAbility extends Ability{
healEffect.at(other, parentizeEffects);
wasHealed = true;
}
other.heal(amount);
float healMult = unit.type == other.type ? sameTypeHealMult : 1f;
other.heal(amount * healMult);
});
if(wasHealed){

View File

@@ -1,5 +1,6 @@
package mindustry.entities.abilities;
import arc.audio.*;
import arc.func.*;
import arc.graphics.*;
import arc.graphics.g2d.*;
@@ -9,6 +10,7 @@ import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.ui.*;
@@ -19,25 +21,86 @@ public class ShieldArcAbility extends Ability{
private static Vec2 paramPos = new Vec2();
private static final Cons<Bullet> shieldConsumer = b -> {
if(b.team != paramUnit.team && b.type.absorbable && paramField.data > 0 &&
!(b.within(paramPos, paramField.radius - paramField.width/2f) && paramPos.within(b.x - b.deltaX, b.y - b.deltaY, paramField.radius - paramField.width/2f)) &&
(Tmp.v1.set(b).add(b.deltaX, b.deltaY).within(paramPos, paramField.radius + paramField.width/2f) || b.within(paramPos, paramField.radius + paramField.width/2f)) &&
!(b.within(paramPos, paramField.radius - paramField.width) && paramPos.within(b.x - b.deltaX, b.y - b.deltaY, paramField.radius - paramField.width)) &&
(Tmp.v1.set(b).add(b.deltaX, b.deltaY).within(paramPos, paramField.radius + paramField.width) || b.within(paramPos, paramField.radius + paramField.width)) &&
(Angles.within(paramPos.angleTo(b), paramUnit.rotation + paramField.angleOffset, paramField.angle / 2f) || Angles.within(paramPos.angleTo(b.x + b.deltaX, b.y + b.deltaY), paramUnit.rotation + paramField.angleOffset, paramField.angle / 2f))){
b.absorb();
Fx.absorb.at(b);
if(paramField.chanceDeflect > 0f && b.vel.len() >= 0.1f && b.type.reflectable && Mathf.chance(paramField.chanceDeflect)){
//break shield
//make sound
paramField.deflectSound.at(paramPos, Mathf.random(0.9f, 1.1f));
//translate bullet back to where it was upon collision
b.trns(-b.vel.x, -b.vel.y);
float penX = Math.abs(paramPos.x - b.x), penY = Math.abs(paramPos.y - b.y);
if(penX > penY){
b.vel.x *= -1;
}else{
b.vel.y *= -1;
}
b.owner = paramUnit;
b.team = paramUnit.team;
b.time += 1f;
}else{
b.absorb();
Fx.absorb.at(b);
}
// break shield
if(paramField.data <= b.damage()){
paramField.data -= paramField.cooldown * paramField.regen;
Fx.arcShieldBreak.at(paramPos.x, paramPos.y, 0, paramField.color == null ? paramUnit.type.shieldColor(paramUnit) : paramField.color, paramUnit);
}
paramField.data -= b.damage();
// shieldDamage for consistency
paramField.data -= b.type.shieldDamage(b);
paramField.alpha = 1f;
}
};
protected static final Cons<Unit> unitConsumer = unit -> {
// ignore core units
if(paramField.data > 0 && unit.targetable(paramUnit.team) &&
!(unit.within(paramPos, paramField.radius - paramField.width) && paramPos.within(unit.x - unit.deltaX, unit.y - unit.deltaY, paramField.radius - paramField.width)) &&
(Tmp.v1.set(unit).add(unit.deltaX, unit.deltaY).within(paramPos, paramField.radius + paramField.width) || unit.within(paramPos, paramField.radius + paramField.width)) &&
(Angles.within(paramPos.angleTo(unit), paramUnit.rotation + paramField.angleOffset, paramField.angle / 2f) || Angles.within(paramPos.angleTo(unit.x + unit.deltaX, unit.y + unit.deltaY), paramUnit.rotation + paramField.angleOffset, paramField.angle / 2f))){
if(unit.isMissile() && unit.killable() && paramField.missileUnitMultiplier >= 0f){
unit.remove();
unit.type.deathSound.at(unit);
unit.type.deathExplosionEffect.at(unit);
Fx.absorb.at(unit);
Fx.circleColorSpark.at(unit.x, unit.y,paramUnit.team.color);
// consider missile hp and gamerule to damage the shield
paramField.data -= unit.health() * paramField.missileUnitMultiplier * Vars.state.rules.unitDamage(unit.team);
paramField.alpha = 1f;
}else{
float reach = paramField.radius + paramField.width;
float overlapDst = reach - unit.dst(paramPos.x,paramPos.y);
if(overlapDst>0){
//stop
unit.vel.setZero();
// get out
unit.move(Tmp.v1.set(unit).sub(paramUnit).setLength(overlapDst + 0.01f));
if(Mathf.chanceDelta(0.5f*Time.delta)){
Fx.circleColorSpark.at(unit.x,unit.y,paramUnit.team.color);
}
}
}
}
};
/** Shield radius. */
public float radius = 60f;
/** Shield regen speed in damage/tick. */
@@ -54,6 +117,12 @@ public class ShieldArcAbility extends Ability{
public boolean whenShooting = true;
/** Width of shield line. */
public float width = 6f;
/** Bullet deflection chance. -1 to disable */
public float chanceDeflect = -1f;
/** Deflection sound. */
public Sound deflectSound = Sounds.none;
/** Multiplier for shield damage taken from missile units. */
public float missileUnitMultiplier = 2f;
/** Whether to draw the arc line. */
public boolean drawArc = true;
@@ -75,6 +144,8 @@ public class ShieldArcAbility extends Ability{
t.add(abilityStat("repairspeed", Strings.autoFixed(regen * 60f, 2)));
t.row();
t.add(abilityStat("cooldown", Strings.autoFixed(cooldown / 60f, 2)));
t.row();
t.add(abilityStat("deflectchance", Strings.autoFixed(chanceDeflect *100f, 2)));
}
@Override
@@ -93,8 +164,9 @@ public class ShieldArcAbility extends Ability{
paramField = this;
paramPos.set(x, y).rotate(unit.rotation - 90f).add(unit);
float reach = radius + width / 2f;
float reach = radius + width;
Groups.bullet.intersect(paramPos.x - reach, paramPos.y - reach, reach * 2f, reach * 2f, shieldConsumer);
Units.nearbyEnemies(paramUnit.team, paramPos.x - reach, paramPos.y - reach, reach * 2f, reach * 2f, unitConsumer);
}else{
widthScale = Mathf.lerpDelta(widthScale, 0f, 0.11f);
}

View File

@@ -56,7 +56,7 @@ abstract class TankComp implements Posc, Hitboxc, Unitc, ElevationMovec{
boolean anyNonDeep = false;
//calculate overlapping tiles so it slows down when going "over" walls
int r = Math.max((int)(hitSize * 0.6f / tilesize), 0);
int r = Math.max((int)(hitSize * 0.75f / tilesize), 0);
int solids = 0, total = (r*2+1)*(r*2+1);
for(int dx = -r; dx <= r; dx++){
@@ -104,7 +104,7 @@ abstract class TankComp implements Posc, Hitboxc, Unitc, ElevationMovec{
public float floorSpeedMultiplier(){
Floor on = isFlying() || type.hovering ? Blocks.air.asFloor() : floorOn();
//TODO take into account extra blocks
return on.speedMultiplier * speedMultiplier * lastSlowdown;
return (float)Math.pow(on.speedMultiplier, type.floorMultiplier) * speedMultiplier * lastSlowdown;
}
@Replace

View File

@@ -606,7 +606,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
if(floor != null && floor.isLiquid && floor.drownTime > 0 && canDrown()){
lastDrownFloor = floor;
drownTime += Time.delta / floor.drownTime / type.drownTimeMultiplier;
drownTime += Time.delta / (hitSize / 8f * type.drownTimeMultiplier * floor.drownTime);
if(Mathf.chanceDelta(0.05f)){
floor.drownUpdateEffect.at(x, y, hitSize, floor.mapColor);
}