mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-01-03 13:30:25 +07:00
Added dynamic status for custom speed/health/etc
This commit is contained in:
parent
968fa2f9b1
commit
e5047d752d
@ -11,7 +11,7 @@ import mindustry.type.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class StatusEffects{
|
||||
public static StatusEffect none, burning, freezing, unmoving, slow, fast, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed, disarmed, electrified, invincible;
|
||||
public static StatusEffect none, burning, freezing, unmoving, slow, fast, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed, disarmed, electrified, invincible, dynamic;
|
||||
|
||||
public static void load(){
|
||||
|
||||
@ -203,5 +203,11 @@ public class StatusEffects{
|
||||
invincible = new StatusEffect("invincible"){{
|
||||
healthMultiplier = Float.POSITIVE_INFINITY;
|
||||
}};
|
||||
|
||||
dynamic = new StatusEffect("dynamic"){{
|
||||
show = false;
|
||||
dynamic = true;
|
||||
permanent = true;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import mindustry.type.*;
|
||||
|
||||
@Component
|
||||
abstract class ShieldComp implements Healthc, Posc{
|
||||
@Import float health, hitTime, x, y, healthMultiplier;
|
||||
@Import float health, hitTime, x, y, healthMultiplier, armorOverride;
|
||||
@Import boolean dead;
|
||||
@Import Team team;
|
||||
@Import UnitType type;
|
||||
@ -27,7 +27,7 @@ abstract class ShieldComp implements Healthc, Posc{
|
||||
@Override
|
||||
public void damage(float amount){
|
||||
//apply armor and scaling effects
|
||||
rawDamage(Damage.applyArmor(amount, armor) / healthMultiplier / Vars.state.rules.unitHealth(team));
|
||||
rawDamage(Damage.applyArmor(amount, armorOverride >= 0f ? armorOverride : armor) / healthMultiplier / Vars.state.rules.unitHealth(team));
|
||||
}
|
||||
|
||||
@Replace
|
||||
|
@ -20,10 +20,12 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
private transient Bits applied = new Bits(content.getBy(ContentType.status).size);
|
||||
|
||||
//these are considered read-only
|
||||
transient float speedMultiplier = 1, damageMultiplier = 1, healthMultiplier = 1, reloadMultiplier = 1, buildSpeedMultiplier = 1, dragMultiplier = 1;
|
||||
//note: armor is a special case; it is an override when >= 0, otherwise ignored
|
||||
transient float speedMultiplier = 1, damageMultiplier = 1, healthMultiplier = 1, reloadMultiplier = 1, buildSpeedMultiplier = 1, dragMultiplier = 1, armorOverride = -1f;
|
||||
transient boolean disarmed = false;
|
||||
|
||||
@Import UnitType type;
|
||||
@Import float maxHealth;
|
||||
|
||||
/** Apply a status effect for 1 tick (for permanent effects) **/
|
||||
void apply(StatusEffect effect){
|
||||
@ -108,6 +110,62 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
return Tmp.c1.set(r / count, g / count, b / count, 1f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a dynamic status effect, with stat multipliers that can be customized.
|
||||
* @return the entry to write multipliers to. If the dynamic status was already applied, returns the previous entry.
|
||||
* */
|
||||
public StatusEntry applyDynamicStatus(){
|
||||
if(hasEffect(StatusEffects.dynamic)){
|
||||
StatusEntry entry = statuses.find(s -> s.effect.dynamic);
|
||||
if(entry != null) return entry;
|
||||
}
|
||||
|
||||
StatusEntry entry = Pools.obtain(StatusEntry.class, StatusEntry::new);
|
||||
entry.set(StatusEffects.dynamic, Float.POSITIVE_INFINITY);
|
||||
statuses.add(entry);
|
||||
entry.effect.applied(self(), entry.time, false);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to override speed. */
|
||||
public void statusSpeed(float speed){
|
||||
//type.speed should never be 0
|
||||
applyDynamicStatus().speedMultiplier = speed / type.speed;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to change damage. */
|
||||
public void statusDamageMultiplier(float damageMultiplier){
|
||||
applyDynamicStatus().damageMultiplier = damageMultiplier;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to change reload. */
|
||||
public void statusReloadMultiplier(float reloadMultiplier){
|
||||
applyDynamicStatus().reloadMultiplier = reloadMultiplier;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to override max health. */
|
||||
public void statusMaxHealth(float health){
|
||||
//maxHealth should never be zero
|
||||
applyDynamicStatus().healthMultiplier = health / maxHealth;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to override build speed. */
|
||||
public void statusBuildSpeed(float buildSpeed){
|
||||
//build speed should never be zero
|
||||
applyDynamicStatus().buildSpeedMultiplier = buildSpeed / type.buildSpeed;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to override drag. */
|
||||
public void statusDrag(float drag){
|
||||
//prevent divide by 0 (drag can be zero, if someone makes a broken unit)
|
||||
applyDynamicStatus().dragMultiplier = type.drag == 0f ? 0f : drag / type.drag;
|
||||
}
|
||||
|
||||
/** Uses a dynamic status effect to override armor. */
|
||||
public void statusArmor(float armor){
|
||||
applyDynamicStatus().armorOverride = armor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
Floor floor = floorOn();
|
||||
@ -117,6 +175,7 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
}
|
||||
|
||||
applied.clear();
|
||||
armorOverride = -1f;
|
||||
speedMultiplier = damageMultiplier = healthMultiplier = reloadMultiplier = buildSpeedMultiplier = dragMultiplier = 1f;
|
||||
disarmed = false;
|
||||
|
||||
@ -136,12 +195,24 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
}else{
|
||||
applied.set(entry.effect.id);
|
||||
|
||||
speedMultiplier *= entry.effect.speedMultiplier;
|
||||
healthMultiplier *= entry.effect.healthMultiplier;
|
||||
damageMultiplier *= entry.effect.damageMultiplier;
|
||||
reloadMultiplier *= entry.effect.reloadMultiplier;
|
||||
buildSpeedMultiplier *= entry.effect.buildSpeedMultiplier;
|
||||
dragMultiplier *= entry.effect.dragMultiplier;
|
||||
//TODO this is very ugly...
|
||||
if(entry.effect.dynamic){
|
||||
speedMultiplier *= entry.speedMultiplier;
|
||||
healthMultiplier *= entry.healthMultiplier;
|
||||
damageMultiplier *= entry.damageMultiplier;
|
||||
reloadMultiplier *= entry.reloadMultiplier;
|
||||
buildSpeedMultiplier *= entry.buildSpeedMultiplier;
|
||||
dragMultiplier *= entry.dragMultiplier;
|
||||
//armor is a special case; many units have it set it to 0, so an override at values >= 0 is used
|
||||
if(entry.armorOverride >= 0f) armorOverride = entry.armorOverride;
|
||||
}else{
|
||||
speedMultiplier *= entry.effect.speedMultiplier;
|
||||
healthMultiplier *= entry.effect.healthMultiplier;
|
||||
damageMultiplier *= entry.effect.damageMultiplier;
|
||||
reloadMultiplier *= entry.effect.reloadMultiplier;
|
||||
buildSpeedMultiplier *= entry.effect.buildSpeedMultiplier;
|
||||
dragMultiplier *= entry.effect.dragMultiplier;
|
||||
}
|
||||
|
||||
disarmed |= entry.effect.disarm;
|
||||
|
||||
|
@ -6,6 +6,9 @@ public class StatusEntry{
|
||||
public StatusEffect effect;
|
||||
public float time;
|
||||
|
||||
//all of these are for the dynamic effect only!
|
||||
public float damageMultiplier = 1f, healthMultiplier = 1f, speedMultiplier = 1f, reloadMultiplier = 1f, buildSpeedMultiplier = 1f, dragMultiplier = 1f, armorOverride = -1f;
|
||||
|
||||
public StatusEntry set(StatusEffect effect, float time){
|
||||
this.effect = effect;
|
||||
this.time = time;
|
||||
|
@ -711,12 +711,57 @@ public class TypeIO{
|
||||
}
|
||||
|
||||
public static void writeStatus(Writes write, StatusEntry entry){
|
||||
write.s(entry.effect.id);
|
||||
write.s(entry.effect.id | (entry.effect.dynamic ? 1 << 15 : 0));
|
||||
write.f(entry.time);
|
||||
|
||||
//write dynamic fields
|
||||
if(entry.effect.dynamic){
|
||||
//write a byte with bits set based on which field is actually used
|
||||
write.b(
|
||||
(entry.damageMultiplier != 1f ? (1 << 0) : 0) |
|
||||
(entry.healthMultiplier != 1f ? (1 << 1) : 0) |
|
||||
(entry.speedMultiplier != 1f ? (1 << 2) : 0) |
|
||||
(entry.reloadMultiplier != 1f ? (1 << 3) : 0) |
|
||||
(entry.buildSpeedMultiplier != 1f ? (1 << 4) : 0) |
|
||||
(entry.dragMultiplier != 1f ? (1 << 5) : 0) |
|
||||
(entry.armorOverride >= 0f ? (1 << 6) : 0)
|
||||
);
|
||||
|
||||
if(entry.damageMultiplier != 1f) write.f(entry.damageMultiplier);
|
||||
if(entry.healthMultiplier != 1f) write.f(entry.healthMultiplier);
|
||||
if(entry.speedMultiplier != 1f) write.f(entry.speedMultiplier);
|
||||
if(entry.reloadMultiplier != 1f) write.f(entry.reloadMultiplier);
|
||||
if(entry.buildSpeedMultiplier != 1f) write.f(entry.buildSpeedMultiplier);
|
||||
if(entry.dragMultiplier != 1f) write.f(entry.dragMultiplier);
|
||||
if(entry.armorOverride >= 0f) write.f(entry.armorOverride);
|
||||
}
|
||||
}
|
||||
|
||||
public static StatusEntry readStatus(Reads read){
|
||||
return new StatusEntry().set(content.getByID(ContentType.status, read.s()), read.f());
|
||||
short id = read.s();
|
||||
float time = read.f();
|
||||
|
||||
StatusEntry result = new StatusEntry();
|
||||
|
||||
if((id & (1 << 15)) != 0){
|
||||
//it's a dynamic effect
|
||||
id ^= (1 << 15);
|
||||
|
||||
//read flags that store which fields are set
|
||||
int flags = read.ub();
|
||||
|
||||
if((flags & (1 << 0)) != 0) result.damageMultiplier = read.f();
|
||||
if((flags & (1 << 1)) != 0) result.healthMultiplier = read.f();
|
||||
if((flags & (1 << 2)) != 0) result.speedMultiplier = read.f();
|
||||
if((flags & (1 << 3)) != 0) result.reloadMultiplier = read.f();
|
||||
if((flags & (1 << 4)) != 0) result.buildSpeedMultiplier = read.f();
|
||||
if((flags & (1 << 5)) != 0) result.dragMultiplier = read.f();
|
||||
if((flags & (1 << 6)) != 0) result.armorOverride = read.f();
|
||||
}
|
||||
|
||||
result.set(content.getByID(ContentType.status, id), time);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void writeItems(Writes write, ItemStack stack){
|
||||
|
@ -41,6 +41,8 @@ public class StatusEffect extends UnlockableContent{
|
||||
public boolean permanent;
|
||||
/** If true, this effect will only react with other effects and cannot be applied. */
|
||||
public boolean reactive;
|
||||
/** Special flag for the dynamic effect type with custom stats - do not use. */
|
||||
public boolean dynamic = false;
|
||||
/** Whether to show this effect in the database. */
|
||||
public boolean show = true;
|
||||
/** Tint color of effect. */
|
||||
|
Loading…
Reference in New Issue
Block a user