king and queen progress. vortex lens fixes. time dilation fields for queen
This commit is contained in:
1 parent
357f41d9d6
commit
c573c574b9
181 files changed
+8555
-198
No files matched your search
@@ -231,6 +231,19 @@ public final class AntarchySettings {
|
|||||||
private static int royalGuardianShieldDurability = 1008;
|
private static int royalGuardianShieldDurability = 1008;
|
||||||
private static double royalBoltDamage = 6.0D;
|
private static double royalBoltDamage = 6.0D;
|
||||||
private static int royalEggHatchChance = 3;
|
private static int royalEggHatchChance = 3;
|
||||||
|
private static double kingHealth = 6000.0D;
|
||||||
|
private static double queenHealth = 6000.0D;
|
||||||
|
private static double kingAttackDamage = 50.0D;
|
||||||
|
private static double queenAttackDamage = 45.0D;
|
||||||
|
private static double royalBossArmor = 20.0D;
|
||||||
|
private static double royalBossFollowRange = 128.0D;
|
||||||
|
private static double royalBossMovementSpeed = 0.22D;
|
||||||
|
private static double royalBossKnockbackResistance = 1.0D;
|
||||||
|
private static double royalBossStepHeight = 3.0D;
|
||||||
|
private static double royalBossMaxSingleHitDamage = 250.0D;
|
||||||
|
private static double royalBossBiteReach = 10.0D;
|
||||||
|
private static double royalBossBiteDamageMultiplier = 1.6D;
|
||||||
|
private static int royalBossBiteCooldownTicks = 45;
|
||||||
private static boolean basiliskPetrifyingGazeEnabled = true;
|
private static boolean basiliskPetrifyingGazeEnabled = true;
|
||||||
private static int basiliskSpawnMaxLightLevel = 5;
|
private static int basiliskSpawnMaxLightLevel = 5;
|
||||||
private static double basiliskHealth = 320.0D;
|
private static double basiliskHealth = 320.0D;
|
||||||
@@ -261,7 +274,7 @@ public final class AntarchySettings {
|
|||||||
private static double diamondMinecartCoastDeceleration = 0.02D;
|
private static double diamondMinecartCoastDeceleration = 0.02D;
|
||||||
private static boolean diamondMinecartMobDamageEnabled = false;
|
private static boolean diamondMinecartMobDamageEnabled = false;
|
||||||
private static double diamondMinecartMaxMobDamage = 4.0D;
|
private static double diamondMinecartMaxMobDamage = 4.0D;
|
||||||
private static double hoverboardMaxSpeed = 3.0D;
|
private static double hoverboardMaxSpeed = 6.0D;
|
||||||
private static double hoverboardAcceleration = 0.05D;
|
private static double hoverboardAcceleration = 0.05D;
|
||||||
private static boolean dreadHallucinationSoundsEnabled = true;
|
private static boolean dreadHallucinationSoundsEnabled = true;
|
||||||
private static double dreadHallucinationSoundMinInterval = 3.0D;
|
private static double dreadHallucinationSoundMinInterval = 3.0D;
|
||||||
@@ -386,18 +399,18 @@ public final class AntarchySettings {
|
|||||||
private static int eyeOfTheStormSurgeCooldownTicks = 70;
|
private static int eyeOfTheStormSurgeCooldownTicks = 70;
|
||||||
private static double eyeOfTheStormSurgeRange = 16.0D;
|
private static double eyeOfTheStormSurgeRange = 16.0D;
|
||||||
private static int eyeOfTheStormSurgeDurationTicks = 300;
|
private static int eyeOfTheStormSurgeDurationTicks = 300;
|
||||||
private static double eyeOfTheStormSurgeRadius = 3.5D;
|
private static double eyeOfTheStormSurgeRadius = 4.0D;
|
||||||
private static double eyeOfTheStormSurgeHeight = 5.0D;
|
private static double eyeOfTheStormSurgeHeight = 6.0D;
|
||||||
private static double eyeOfTheStormSurgePullStrength = 0.45D;
|
private static double eyeOfTheStormSurgePullStrength = 0.85D;
|
||||||
private static double eyeOfTheStormSurgeReturnStrength = 1.4D;
|
private static double eyeOfTheStormSurgeReturnStrength = 1.4D;
|
||||||
private static float eyeOfTheStormSurgeDamage = 5.0F;
|
private static float eyeOfTheStormSurgeDamage = 5.0F;
|
||||||
private static double vortexLensMinRadius = 1.5D;
|
private static double vortexLensMinRadius = 1.5D;
|
||||||
private static double vortexLensMaxRadius = 10.0D;
|
private static double vortexLensMaxRadius = 10.0D;
|
||||||
private static double vortexLensMinHeight = 3.0D;
|
private static double vortexLensMinHeight = 3.0D;
|
||||||
private static double vortexLensMaxHeight = 20.0D;
|
private static double vortexLensMaxHeight = 20.0D;
|
||||||
private static double vortexLensPullStrength = 0.42D;
|
private static double vortexLensPullStrength = 0.65D;
|
||||||
private static double vortexLensPushStrength = 0.38D;
|
private static double vortexLensPushStrength = 0.65D;
|
||||||
private static double vortexLensLaunchStrength = 1.15D;
|
private static double vortexLensLaunchStrength = 1.4D;
|
||||||
private static double missileSquidHealth = 60.0D;
|
private static double missileSquidHealth = 60.0D;
|
||||||
private static double missileSquidAttackDamage = 9.0D;
|
private static double missileSquidAttackDamage = 9.0D;
|
||||||
private static double missileSquidMovementSpeed = 0.84D;
|
private static double missileSquidMovementSpeed = 0.84D;
|
||||||
@@ -496,6 +509,10 @@ public final class AntarchySettings {
|
|||||||
private static double creepingHorrorAttackDamage = 6.0D;
|
private static double creepingHorrorAttackDamage = 6.0D;
|
||||||
private static double lurkingTerrorHealth = 15.0D;
|
private static double lurkingTerrorHealth = 15.0D;
|
||||||
private static double lurkingTerrorAttackDamage = 6.0D;
|
private static double lurkingTerrorAttackDamage = 6.0D;
|
||||||
|
private static double manticoreHealth = 40.0D;
|
||||||
|
private static double manticoreAttackDamage = 7.0D;
|
||||||
|
private static int manticoreStingPoisonTicks = 100;
|
||||||
|
private static int queenManticoreCap = 15;
|
||||||
private static double jerryInfantHealth = 20.0D;
|
private static double jerryInfantHealth = 20.0D;
|
||||||
private static double jerryInfantAttackDamage = 2.0D;
|
private static double jerryInfantAttackDamage = 2.0D;
|
||||||
private static double jerryMatureHealth = 40.0D;
|
private static double jerryMatureHealth = 40.0D;
|
||||||
@@ -1914,6 +1931,45 @@ public final class AntarchySettings {
|
|||||||
public static int royalEggHatchChance() { return royalEggHatchChance; }
|
public static int royalEggHatchChance() { return royalEggHatchChance; }
|
||||||
public static void setRoyalEggHatchChance(int v) { royalEggHatchChance = v; }
|
public static void setRoyalEggHatchChance(int v) { royalEggHatchChance = v; }
|
||||||
|
|
||||||
|
public static double kingHealth() { return kingHealth; }
|
||||||
|
public static void setKingHealth(double v) { kingHealth = v; }
|
||||||
|
|
||||||
|
public static double queenHealth() { return queenHealth; }
|
||||||
|
public static void setQueenHealth(double v) { queenHealth = v; }
|
||||||
|
|
||||||
|
public static double kingAttackDamage() { return kingAttackDamage; }
|
||||||
|
public static void setKingAttackDamage(double v) { kingAttackDamage = v; }
|
||||||
|
|
||||||
|
public static double queenAttackDamage() { return queenAttackDamage; }
|
||||||
|
public static void setQueenAttackDamage(double v) { queenAttackDamage = v; }
|
||||||
|
|
||||||
|
public static double royalBossArmor() { return royalBossArmor; }
|
||||||
|
public static void setRoyalBossArmor(double v) { royalBossArmor = v; }
|
||||||
|
|
||||||
|
public static double royalBossFollowRange() { return royalBossFollowRange; }
|
||||||
|
public static void setRoyalBossFollowRange(double v) { royalBossFollowRange = v; }
|
||||||
|
|
||||||
|
public static double royalBossMovementSpeed() { return royalBossMovementSpeed; }
|
||||||
|
public static void setRoyalBossMovementSpeed(double v) { royalBossMovementSpeed = v; }
|
||||||
|
|
||||||
|
public static double royalBossKnockbackResistance() { return royalBossKnockbackResistance; }
|
||||||
|
public static void setRoyalBossKnockbackResistance(double v) { royalBossKnockbackResistance = v; }
|
||||||
|
|
||||||
|
public static double royalBossStepHeight() { return royalBossStepHeight; }
|
||||||
|
public static void setRoyalBossStepHeight(double v) { royalBossStepHeight = v; }
|
||||||
|
|
||||||
|
public static double royalBossMaxSingleHitDamage() { return royalBossMaxSingleHitDamage; }
|
||||||
|
public static void setRoyalBossMaxSingleHitDamage(double v) { royalBossMaxSingleHitDamage = v; }
|
||||||
|
|
||||||
|
public static double royalBossBiteReach() { return royalBossBiteReach; }
|
||||||
|
public static void setRoyalBossBiteReach(double v) { royalBossBiteReach = v; }
|
||||||
|
|
||||||
|
public static double royalBossBiteDamageMultiplier() { return royalBossBiteDamageMultiplier; }
|
||||||
|
public static void setRoyalBossBiteDamageMultiplier(double v) { royalBossBiteDamageMultiplier = v; }
|
||||||
|
|
||||||
|
public static int royalBossBiteCooldownTicks() { return royalBossBiteCooldownTicks; }
|
||||||
|
public static void setRoyalBossBiteCooldownTicks(int v) { royalBossBiteCooldownTicks = v; }
|
||||||
|
|
||||||
public static double nightmareSwordBaseDamage() { return nightmareSwordBaseDamage; }
|
public static double nightmareSwordBaseDamage() { return nightmareSwordBaseDamage; }
|
||||||
public static void setNightmareSwordBaseDamage(double v) { nightmareSwordBaseDamage = v; }
|
public static void setNightmareSwordBaseDamage(double v) { nightmareSwordBaseDamage = v; }
|
||||||
|
|
||||||
@@ -2685,6 +2741,14 @@ public final class AntarchySettings {
|
|||||||
public static void setLurkingTerrorHealth(double v) { lurkingTerrorHealth = v; }
|
public static void setLurkingTerrorHealth(double v) { lurkingTerrorHealth = v; }
|
||||||
public static double lurkingTerrorAttackDamage() { return lurkingTerrorAttackDamage; }
|
public static double lurkingTerrorAttackDamage() { return lurkingTerrorAttackDamage; }
|
||||||
public static void setLurkingTerrorAttackDamage(double v) { lurkingTerrorAttackDamage = v; }
|
public static void setLurkingTerrorAttackDamage(double v) { lurkingTerrorAttackDamage = v; }
|
||||||
|
public static double manticoreHealth() { return manticoreHealth; }
|
||||||
|
public static void setManticoreHealth(double v) { manticoreHealth = v; }
|
||||||
|
public static double manticoreAttackDamage() { return manticoreAttackDamage; }
|
||||||
|
public static void setManticoreAttackDamage(double v) { manticoreAttackDamage = v; }
|
||||||
|
public static int manticoreStingPoisonTicks() { return manticoreStingPoisonTicks; }
|
||||||
|
public static void setManticoreStingPoisonTicks(int v) { manticoreStingPoisonTicks = v; }
|
||||||
|
public static int queenManticoreCap() { return queenManticoreCap; }
|
||||||
|
public static void setQueenManticoreCap(int v) { queenManticoreCap = v; }
|
||||||
public static double jerryInfantHealth() { return jerryInfantHealth; }
|
public static double jerryInfantHealth() { return jerryInfantHealth; }
|
||||||
public static void setJerryInfantHealth(double v) { jerryInfantHealth = v; }
|
public static void setJerryInfantHealth(double v) { jerryInfantHealth = v; }
|
||||||
public static double jerryInfantAttackDamage() { return jerryInfantAttackDamage; }
|
public static double jerryInfantAttackDamage() { return jerryInfantAttackDamage; }
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.craisinlord.antarchy.content.entity.lucid.LucidEntity;
|
|||||||
import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity;
|
import com.craisinlord.antarchy.content.entity.vortex.VortexChargeProjectileEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.vortex.VortexEntity;
|
import com.craisinlord.antarchy.content.entity.vortex.VortexEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
|
import com.craisinlord.antarchy.content.entity.vortex.WindVortexEntity;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationFieldEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
|
import com.craisinlord.antarchy.content.entity.nightmare.NightmareEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
|
import com.craisinlord.antarchy.content.entity.nightmare.NightmareBiteEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
|
import com.craisinlord.antarchy.content.entity.nightmare.NightmarePortalEntity;
|
||||||
@@ -81,6 +82,11 @@ public final class AntarchyObjects {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<DimensionalTearEntity>> DIMENSIONAL_TEAR = (Supplier<EntityType<DimensionalTearEntity>>) UNBOUND;
|
public static Supplier<EntityType<DimensionalTearEntity>> DIMENSIONAL_TEAR = (Supplier<EntityType<DimensionalTearEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<Block> DIMENSIONAL_TEAR_MARKER = (Supplier<Block>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.DimensionalTearMarkerBlockEntity>> DIMENSIONAL_TEAR_MARKER_BLOCK_ENTITY =
|
||||||
|
(Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.DimensionalTearMarkerBlockEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<NightmareBiteEntity>> NIGHTMARE_BITE = (Supplier<EntityType<NightmareBiteEntity>>) UNBOUND;
|
public static Supplier<EntityType<NightmareBiteEntity>> NIGHTMARE_BITE = (Supplier<EntityType<NightmareBiteEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<LucidEntity>> LUCID = (Supplier<EntityType<LucidEntity>>) UNBOUND;
|
public static Supplier<EntityType<LucidEntity>> LUCID = (Supplier<EntityType<LucidEntity>>) UNBOUND;
|
||||||
@@ -91,6 +97,8 @@ public final class AntarchyObjects {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<VortexChargeProjectileEntity>> VORTEX_CHARGE_PROJECTILE = (Supplier<EntityType<VortexChargeProjectileEntity>>) UNBOUND;
|
public static Supplier<EntityType<VortexChargeProjectileEntity>> VORTEX_CHARGE_PROJECTILE = (Supplier<EntityType<VortexChargeProjectileEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<TimeDilationFieldEntity>> TIME_DILATION_FIELD = (Supplier<EntityType<TimeDilationFieldEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<Block> VORTEX_LENS = (Supplier<Block>) UNBOUND;
|
public static Supplier<Block> VORTEX_LENS = (Supplier<Block>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<BlockEntityType<VortexLensBlockEntity>> VORTEX_LENS_BLOCK_ENTITY = (Supplier<BlockEntityType<VortexLensBlockEntity>>) UNBOUND;
|
public static Supplier<BlockEntityType<VortexLensBlockEntity>> VORTEX_LENS_BLOCK_ENTITY = (Supplier<BlockEntityType<VortexLensBlockEntity>>) UNBOUND;
|
||||||
@@ -129,6 +137,8 @@ public final class AntarchyObjects {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<LurkingTerrorEntity>> LURKING_TERROR = (Supplier<EntityType<LurkingTerrorEntity>>) UNBOUND;
|
public static Supplier<EntityType<LurkingTerrorEntity>> LURKING_TERROR = (Supplier<EntityType<LurkingTerrorEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>> MANTICORE = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<StinkBugEntity>> STINK_BUG = (Supplier<EntityType<StinkBugEntity>>) UNBOUND;
|
public static Supplier<EntityType<StinkBugEntity>> STINK_BUG = (Supplier<EntityType<StinkBugEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>> ROLLY_POLLY = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>>) UNBOUND;
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>> ROLLY_POLLY = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.RollyPollyEntity>>) UNBOUND;
|
||||||
@@ -145,6 +155,10 @@ public final class AntarchyObjects {
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>> ROYAL_BOLT = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>>) UNBOUND;
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>> ROYAL_BOLT = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.RoyalBoltEntity>>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>> KING = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>> QUEEN = (Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>>) UNBOUND;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<Block> PRINCE_EGG = (Supplier<Block>) UNBOUND;
|
public static Supplier<Block> PRINCE_EGG = (Supplier<Block>) UNBOUND;
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static Supplier<Block> PRINCESS_EGG = (Supplier<Block>) UNBOUND;
|
public static Supplier<Block> PRINCESS_EGG = (Supplier<Block>) UNBOUND;
|
||||||
@@ -625,6 +639,16 @@ public final class AntarchyObjects {
|
|||||||
DIMENSIONAL_TEAR = supplier;
|
DIMENSIONAL_TEAR = supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setDimensionalTearMarker(Supplier<Block> supplier) {
|
||||||
|
DIMENSIONAL_TEAR_MARKER = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDimensionalTearMarkerBlockEntity(
|
||||||
|
Supplier<BlockEntityType<com.craisinlord.antarchy.content.block.entity.DimensionalTearMarkerBlockEntity>> supplier
|
||||||
|
) {
|
||||||
|
DIMENSIONAL_TEAR_MARKER_BLOCK_ENTITY = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setNightmare(Supplier<EntityType<NightmareEntity>> supplier) {
|
public static void setNightmare(Supplier<EntityType<NightmareEntity>> supplier) {
|
||||||
NIGHTMARE = supplier;
|
NIGHTMARE = supplier;
|
||||||
}
|
}
|
||||||
@@ -649,6 +673,10 @@ public final class AntarchyObjects {
|
|||||||
VORTEX_CHARGE_PROJECTILE = supplier;
|
VORTEX_CHARGE_PROJECTILE = supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setTimeDilationField(Supplier<EntityType<TimeDilationFieldEntity>> supplier) {
|
||||||
|
TIME_DILATION_FIELD = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setVortexLens(Supplier<Block> supplier) {
|
public static void setVortexLens(Supplier<Block> supplier) {
|
||||||
VORTEX_LENS = supplier;
|
VORTEX_LENS = supplier;
|
||||||
}
|
}
|
||||||
@@ -689,6 +717,18 @@ public final class AntarchyObjects {
|
|||||||
ROYAL_BOLT = supplier;
|
ROYAL_BOLT = supplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setKing(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.KingEntity>> supplier) {
|
||||||
|
KING = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setManticore(Supplier<EntityType<com.craisinlord.antarchy.content.entity.ManticoreEntity>> supplier) {
|
||||||
|
MANTICORE = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setQueen(Supplier<EntityType<com.craisinlord.antarchy.content.entity.royal.QueenEntity>> supplier) {
|
||||||
|
QUEEN = supplier;
|
||||||
|
}
|
||||||
|
|
||||||
public static void setPrinceEgg(Supplier<Block> supplier) {
|
public static void setPrinceEgg(Supplier<Block> supplier) {
|
||||||
PRINCE_EGG = supplier;
|
PRINCE_EGG = supplier;
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-1
@@ -178,6 +178,14 @@ public final class AntarchySoundEvents {
|
|||||||
public static Supplier<SoundEvent> BLOOD_CRYSTAL_ARMOR_EQUIP = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> BLOOD_CRYSTAL_ARMOR_EQUIP = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> BLOODGLASS_WARD_HEART_BREAK = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> BLOODGLASS_WARD_HEART_BREAK = (Supplier<SoundEvent>) UNBOUND;
|
||||||
public static Supplier<SoundEvent> BLOODGLASS_WARD_HEART_REGEN = (Supplier<SoundEvent>) UNBOUND;
|
public static Supplier<SoundEvent> BLOODGLASS_WARD_HEART_REGEN = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_IDLE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_HURT = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_DEATH = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> KING_BITE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> QUEEN_IDLE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> QUEEN_HURT = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> QUEEN_DEATH = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
public static Supplier<SoundEvent> QUEEN_BITE = (Supplier<SoundEvent>) UNBOUND;
|
||||||
|
|
||||||
private AntarchySoundEvents() {
|
private AntarchySoundEvents() {
|
||||||
}
|
}
|
||||||
@@ -351,7 +359,15 @@ public final class AntarchySoundEvents {
|
|||||||
Supplier<SoundEvent> bloodCrystalKatanaDash,
|
Supplier<SoundEvent> bloodCrystalKatanaDash,
|
||||||
Supplier<SoundEvent> bloodCrystalArmorEquip,
|
Supplier<SoundEvent> bloodCrystalArmorEquip,
|
||||||
Supplier<SoundEvent> bloodglassWardHeartBreak,
|
Supplier<SoundEvent> bloodglassWardHeartBreak,
|
||||||
Supplier<SoundEvent> bloodglassWardHeartRegen
|
Supplier<SoundEvent> bloodglassWardHeartRegen,
|
||||||
|
Supplier<SoundEvent> kingIdle,
|
||||||
|
Supplier<SoundEvent> kingHurt,
|
||||||
|
Supplier<SoundEvent> kingDeath,
|
||||||
|
Supplier<SoundEvent> kingBite,
|
||||||
|
Supplier<SoundEvent> queenIdle,
|
||||||
|
Supplier<SoundEvent> queenHurt,
|
||||||
|
Supplier<SoundEvent> queenDeath,
|
||||||
|
Supplier<SoundEvent> queenBite
|
||||||
) {
|
) {
|
||||||
SQUIDZOOKA_FIRE = squidzookaFire;
|
SQUIDZOOKA_FIRE = squidzookaFire;
|
||||||
SHRINK_RAY_CHARGE = shrinkRayCharge;
|
SHRINK_RAY_CHARGE = shrinkRayCharge;
|
||||||
@@ -522,5 +538,13 @@ public final class AntarchySoundEvents {
|
|||||||
BLOOD_CRYSTAL_ARMOR_EQUIP = bloodCrystalArmorEquip;
|
BLOOD_CRYSTAL_ARMOR_EQUIP = bloodCrystalArmorEquip;
|
||||||
BLOODGLASS_WARD_HEART_BREAK = bloodglassWardHeartBreak;
|
BLOODGLASS_WARD_HEART_BREAK = bloodglassWardHeartBreak;
|
||||||
BLOODGLASS_WARD_HEART_REGEN = bloodglassWardHeartRegen;
|
BLOODGLASS_WARD_HEART_REGEN = bloodglassWardHeartRegen;
|
||||||
|
KING_IDLE = kingIdle;
|
||||||
|
KING_HURT = kingHurt;
|
||||||
|
KING_DEATH = kingDeath;
|
||||||
|
KING_BITE = kingBite;
|
||||||
|
QUEEN_IDLE = queenIdle;
|
||||||
|
QUEEN_HURT = queenHurt;
|
||||||
|
QUEEN_DEATH = queenDeath;
|
||||||
|
QUEEN_BITE = queenBite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.block.entity.DimensionalTearMarkerBlockEntity;
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public class DimensionalTearMarkerBlock extends BaseEntityBlock {
|
||||||
|
private static final VoxelShape EMPTY = Shapes.empty();
|
||||||
|
private final Supplier<? extends BlockEntityType<DimensionalTearMarkerBlockEntity>> blockEntityTypeSupplier;
|
||||||
|
private final MapCodec<DimensionalTearMarkerBlock> codec;
|
||||||
|
|
||||||
|
public DimensionalTearMarkerBlock(Supplier<? extends BlockEntityType<DimensionalTearMarkerBlockEntity>> blockEntityTypeSupplier, BlockBehaviour.Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
|
||||||
|
this.codec = Block.simpleCodec(ignored -> this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<DimensionalTearMarkerBlock> codec() {
|
||||||
|
return this.codec;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.INVISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return new DimensionalTearMarkerBlockEntity(pos, state, this.blockEntityTypeSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
|
||||||
|
if (level.isClientSide) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return createTickerHelper(blockEntityType, this.blockEntityTypeSupplier.get(), (tickLevel, tickPos, tickState, blockEntity) -> {
|
||||||
|
if (tickLevel instanceof ServerLevel serverLevel) {
|
||||||
|
DimensionalTearMarkerBlockEntity.serverTick(serverLevel, tickPos, tickState, blockEntity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block;
|
||||||
|
|
||||||
|
import com.mojang.serialization.MapCodec;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.particles.DustParticleOptions;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
public class NadirVeilBlock extends Block {
|
||||||
|
public static final MapCodec<NadirVeilBlock> CODEC = simpleCodec(NadirVeilBlock::new);
|
||||||
|
|
||||||
|
private static final int GLOW_LIGHT_LEVEL = 6;
|
||||||
|
private static final DustParticleOptions DRIP_PARTICLE =
|
||||||
|
new DustParticleOptions(new Vector3f(0.63F, 0.26F, 0.92F), 1.0F);
|
||||||
|
|
||||||
|
public NadirVeilBlock(BlockBehaviour.Properties properties) {
|
||||||
|
super(properties.lightLevel(state -> GLOW_LIGHT_LEVEL));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected MapCodec<? extends Block> codec() {
|
||||||
|
return CODEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
|
||||||
|
if (random.nextInt(6) != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double x = pos.getX() + 0.5D + (random.nextDouble() - 0.5D) * 0.7D;
|
||||||
|
double y = pos.getY() + 0.15D + random.nextDouble() * 0.4D;
|
||||||
|
double z = pos.getZ() + 0.5D + (random.nextDouble() - 0.5D) * 0.7D;
|
||||||
|
level.addParticle(DRIP_PARTICLE, x, y, z, 0.0D, 0.02D + random.nextDouble() * 0.02D, 0.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@ import com.craisinlord.antarchy.content.block.entity.RoyalEggBlockEntity;
|
|||||||
import com.craisinlord.antarchy.content.entity.royal.RoyalMountEntity;
|
import com.craisinlord.antarchy.content.entity.royal.RoyalMountEntity;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@@ -17,20 +19,35 @@ import net.minecraft.world.entity.MobSpawnType;
|
|||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.block.BaseEntityBlock;
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.FallingBlock;
|
||||||
import net.minecraft.world.level.block.RenderShape;
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
import net.minecraft.world.level.block.state.properties.IntegerProperty;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public abstract class RoyalEggBlock extends BaseEntityBlock {
|
public abstract class RoyalEggBlock extends BaseEntityBlock {
|
||||||
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
|
public static final IntegerProperty HATCH = BlockStateProperties.HATCH;
|
||||||
private static final int MAX_HATCH = 2;
|
private static final int MAX_HATCH = 2;
|
||||||
|
private static final int FALL_DELAY = 2;
|
||||||
|
|
||||||
|
private static final VoxelShape SHAPE = Shapes.or(
|
||||||
|
Block.box(3.0D, 0.0D, 3.0D, 13.0D, 13.0D, 13.0D),
|
||||||
|
Block.box(2.0D, 1.0D, 2.0D, 14.0D, 11.0D, 14.0D),
|
||||||
|
Block.box(4.0D, 13.0D, 4.0D, 12.0D, 14.0D, 12.0D),
|
||||||
|
Block.box(5.0D, 14.0D, 5.0D, 11.0D, 15.0D, 11.0D),
|
||||||
|
Block.box(6.0D, 15.0D, 6.0D, 10.0D, 16.0D, 10.0D));
|
||||||
|
|
||||||
protected RoyalEggBlock(Properties properties) {
|
protected RoyalEggBlock(Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
@@ -49,6 +66,11 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
|
|||||||
return RenderShape.MODEL;
|
return RenderShape.MODEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
|
||||||
|
return SHAPE;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
@@ -94,6 +116,31 @@ public abstract class RoyalEggBlock extends BaseEntityBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
|
||||||
|
level.scheduleTick(pos, this, FALL_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
|
||||||
|
level.scheduleTick(pos, this, FALL_DELAY);
|
||||||
|
return super.updateShape(state, direction, neighborState, level, pos, neighborPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||||
|
if (!FallingBlock.isFree(level.getBlockState(pos.below())) || pos.getY() < level.getMinBuildHeight()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CompoundTag blockData = level.getBlockEntity(pos) instanceof RoyalEggBlockEntity egg
|
||||||
|
? egg.saveWithoutMetadata(level.registryAccess())
|
||||||
|
: null;
|
||||||
|
FallingBlockEntity falling = FallingBlockEntity.fall(level, pos, state);
|
||||||
|
if (blockData != null && !blockData.isEmpty()) {
|
||||||
|
falling.blockData = blockData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isRandomlyTicking(BlockState state) {
|
protected boolean isRandomlyTicking(BlockState state) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+9
-3
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
public class VortexLensBlock extends BaseEntityBlock {
|
public class VortexLensBlock extends BaseEntityBlock {
|
||||||
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
||||||
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
|
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
|
||||||
|
public static final BooleanProperty PUSHING = BooleanProperty.create("pushing");
|
||||||
|
|
||||||
private final Supplier<? extends BlockEntityType<VortexLensBlockEntity>> blockEntityTypeSupplier;
|
private final Supplier<? extends BlockEntityType<VortexLensBlockEntity>> blockEntityTypeSupplier;
|
||||||
private final MapCodec<VortexLensBlock> codec;
|
private final MapCodec<VortexLensBlock> codec;
|
||||||
@@ -35,7 +36,8 @@ public class VortexLensBlock extends BaseEntityBlock {
|
|||||||
super(properties);
|
super(properties);
|
||||||
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
|
this.blockEntityTypeSupplier = blockEntityTypeSupplier;
|
||||||
this.codec = Block.simpleCodec(ignored -> this);
|
this.codec = Block.simpleCodec(ignored -> this);
|
||||||
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.UP).setValue(POWERED, false));
|
this.registerDefaultState(this.stateDefinition.any()
|
||||||
|
.setValue(FACING, Direction.UP).setValue(POWERED, false).setValue(PUSHING, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -45,14 +47,18 @@ public class VortexLensBlock extends BaseEntityBlock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
builder.add(FACING, POWERED);
|
builder.add(FACING, POWERED, PUSHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||||
|
Level level = context.getLevel();
|
||||||
|
BlockPos pos = context.getClickedPos();
|
||||||
|
boolean bluestone = BluestoneSignalHelper.getBestNeighborSignal(level, pos) > 0;
|
||||||
return this.defaultBlockState()
|
return this.defaultBlockState()
|
||||||
.setValue(FACING, context.getClickedFace())
|
.setValue(FACING, context.getClickedFace())
|
||||||
.setValue(POWERED, hasAnySignal(context.getLevel(), context.getClickedPos()));
|
.setValue(POWERED, hasAnySignal(level, pos))
|
||||||
|
.setValue(PUSHING, bluestone);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+130
@@ -0,0 +1,130 @@
|
|||||||
|
package com.craisinlord.antarchy.content.block.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class DimensionalTearMarkerBlockEntity extends BlockEntity {
|
||||||
|
private static final int MAX_ATTEMPT_TICKS = 100;
|
||||||
|
private static final int MIN_LINK_RANGE = 50;
|
||||||
|
private static final int MAX_LINK_RANGE = 500;
|
||||||
|
private static final int PARTNER_ORIGIN_ATTEMPTS = 12;
|
||||||
|
private static final int PARTNER_SEARCH_ATTEMPTS = 48;
|
||||||
|
private static final int LOCAL_SEARCH_ATTEMPTS = 18;
|
||||||
|
|
||||||
|
private int attemptTicks;
|
||||||
|
|
||||||
|
public DimensionalTearMarkerBlockEntity(
|
||||||
|
BlockPos pos,
|
||||||
|
BlockState blockState,
|
||||||
|
Supplier<? extends BlockEntityType<DimensionalTearMarkerBlockEntity>> blockEntityTypeSupplier
|
||||||
|
) {
|
||||||
|
super(blockEntityTypeSupplier.get(), pos, blockState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void serverTick(ServerLevel level, BlockPos pos, BlockState state, DimensionalTearMarkerBlockEntity blockEntity) {
|
||||||
|
blockEntity.attemptTicks++;
|
||||||
|
boolean spawned = blockEntity.trySpawnLinkedPair(level, pos);
|
||||||
|
if (spawned || blockEntity.attemptTicks >= MAX_ATTEMPT_TICKS) {
|
||||||
|
level.removeBlock(pos, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean trySpawnLinkedPair(ServerLevel level, BlockPos origin) {
|
||||||
|
RandomSource random = level.getRandom();
|
||||||
|
BlockPos first = findOpenPocket(level, origin, random, LOCAL_SEARCH_ATTEMPTS);
|
||||||
|
if (first == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos second = null;
|
||||||
|
for (int i = 0; i < PARTNER_ORIGIN_ATTEMPTS && second == null; i++) {
|
||||||
|
second = findOpenPocket(level, linkedOrigin(first, random), random, PARTNER_SEARCH_ATTEMPTS);
|
||||||
|
}
|
||||||
|
if (second == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lifetime = Math.max(1200, AntarchySettings.dimensionalTearLifetimeTicks());
|
||||||
|
float yawA = random.nextFloat() * 360.0F;
|
||||||
|
float yawB = Mth.wrapDegrees(yawA + 140.0F + random.nextFloat() * 80.0F);
|
||||||
|
DimensionalTearEntity tearA = DimensionalTearEntity.create(level, center(first), yawA, lifetime);
|
||||||
|
DimensionalTearEntity tearB = DimensionalTearEntity.create(level, center(second), yawB, lifetime);
|
||||||
|
tearA.linkTo(tearB);
|
||||||
|
tearB.linkTo(tearA);
|
||||||
|
level.addFreshEntity(tearA);
|
||||||
|
level.addFreshEntity(tearB);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockPos linkedOrigin(BlockPos first, RandomSource random) {
|
||||||
|
double angle = random.nextDouble() * Math.PI * 2.0D;
|
||||||
|
int distance = Mth.nextInt(random, MIN_LINK_RANGE, MAX_LINK_RANGE);
|
||||||
|
int dx = Mth.floor(Math.cos(angle) * distance);
|
||||||
|
int dz = Mth.floor(Math.sin(angle) * distance);
|
||||||
|
int dy = Mth.nextInt(random, -36, 36);
|
||||||
|
return first.offset(dx, dy, dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static BlockPos findOpenPocket(ServerLevel level, BlockPos origin, RandomSource random, int attempts) {
|
||||||
|
int minY = level.getMinBuildHeight() + 8;
|
||||||
|
int maxY = level.getMaxBuildHeight() - 8;
|
||||||
|
for (int i = 0; i < attempts; i++) {
|
||||||
|
BlockPos candidate = origin.offset(
|
||||||
|
Mth.nextInt(random, -16, 16),
|
||||||
|
Mth.nextInt(random, -24, 24),
|
||||||
|
Mth.nextInt(random, -16, 16)
|
||||||
|
);
|
||||||
|
candidate = new BlockPos(candidate.getX(), Mth.clamp(candidate.getY(), minY, maxY), candidate.getZ());
|
||||||
|
if (isUsablePocket(level, candidate)) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isUsablePocket(ServerLevel level, BlockPos pos) {
|
||||||
|
for (int dx = -2; dx <= 2; dx++) {
|
||||||
|
for (int dy = -2; dy <= 3; dy++) {
|
||||||
|
for (int dz = -4; dz <= 4; dz++) {
|
||||||
|
BlockPos checkPos = pos.offset(dx, dy, dz);
|
||||||
|
if (!level.isLoaded(checkPos)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!level.getBlockState(checkPos).getCollisionShape(level, checkPos).isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3 center(BlockPos pos) {
|
||||||
|
return new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
super.saveAdditional(tag, registries);
|
||||||
|
tag.putInt("attempt_ticks", this.attemptTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
super.loadAdditional(tag, registries);
|
||||||
|
this.attemptTicks = tag.getInt("attempt_ticks");
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-5
@@ -66,7 +66,7 @@ public class VortexLensBlockEntity extends BlockEntity {
|
|||||||
|
|
||||||
if (signal <= 0) {
|
if (signal <= 0) {
|
||||||
this.removeActiveVortex();
|
this.removeActiveVortex();
|
||||||
this.updatePoweredState(level, pos, state, false);
|
this.updateBlockState(level, pos, state, false, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ public class VortexLensBlockEntity extends BlockEntity {
|
|||||||
vortex.resetVortexAge();
|
vortex.resetVortexAge();
|
||||||
vortex.setVortexStrengths(strength, AntarchySettings.vortexLensLaunchStrength());
|
vortex.setVortexStrengths(strength, AntarchySettings.vortexLensLaunchStrength());
|
||||||
vortex.setDamaging(false);
|
vortex.setDamaging(false);
|
||||||
this.updatePoweredState(level, pos, state, true);
|
this.updateBlockState(level, pos, state, true, pushMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -131,9 +131,14 @@ public class VortexLensBlockEntity extends BlockEntity {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePoweredState(ServerLevel level, BlockPos pos, BlockState state, boolean powered) {
|
private void updateBlockState(ServerLevel level, BlockPos pos, BlockState state, boolean powered, boolean pushing) {
|
||||||
if (state.getBlock() instanceof VortexLensBlock && state.getValue(VortexLensBlock.POWERED) != powered) {
|
if (!(state.getBlock() instanceof VortexLensBlock)) {
|
||||||
level.setBlock(pos, state.setValue(VortexLensBlock.POWERED, powered), Block.UPDATE_CLIENTS);
|
return;
|
||||||
|
}
|
||||||
|
if (state.getValue(VortexLensBlock.POWERED) != powered || state.getValue(VortexLensBlock.PUSHING) != pushing) {
|
||||||
|
level.setBlock(pos,
|
||||||
|
state.setValue(VortexLensBlock.POWERED, powered).setValue(VortexLensBlock.PUSHING, pushing),
|
||||||
|
Block.UPDATE_CLIENTS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationEntityAccess;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationFieldEntity;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationFieldSampler;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
public final class ClientTimeDilationTicker {
|
||||||
|
private static boolean hadFields;
|
||||||
|
private static volatile List<TimeDilationFieldEntity> activeFields = List.of();
|
||||||
|
private static final Map<Entity, Double> ANIM_OFFSETS = new WeakHashMap<>();
|
||||||
|
|
||||||
|
private ClientTimeDilationTicker() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tick(ClientLevel level) {
|
||||||
|
List<TimeDilationFieldEntity> fields = new ArrayList<>();
|
||||||
|
for (Entity entity : level.entitiesForRendering()) {
|
||||||
|
if (entity instanceof TimeDilationFieldEntity field && field.isAlive()) {
|
||||||
|
fields.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activeFields = fields;
|
||||||
|
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
if (hadFields) {
|
||||||
|
resetRates(level);
|
||||||
|
hadFields = false;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
hadFields = true;
|
||||||
|
|
||||||
|
for (Entity entity : level.entitiesForRendering()) {
|
||||||
|
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double rate = TimeDilationFieldSampler.sample(fields, entity.position());
|
||||||
|
access.antarchy$setTimeDilationRate(rate);
|
||||||
|
if (rate < TimeDilationMath.NORMAL_RATE) {
|
||||||
|
ANIM_OFFSETS.merge(entity, rate - TimeDilationMath.NORMAL_RATE, Double::sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float dilateAnimationTime(Entity entity, float vanillaTime) {
|
||||||
|
Double offset = ANIM_OFFSETS.get(entity);
|
||||||
|
return offset == null ? vanillaTime : (float) (vanillaTime + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double rateAt(double x, double y, double z) {
|
||||||
|
List<TimeDilationFieldEntity> fields = activeFields;
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
return TimeDilationMath.NORMAL_RATE;
|
||||||
|
}
|
||||||
|
return TimeDilationFieldSampler.sample(fields, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resetRates(ClientLevel level) {
|
||||||
|
for (Entity entity : level.entitiesForRendering()) {
|
||||||
|
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (access.antarchy$getTimeDilationRate() < TimeDilationMath.NORMAL_RATE) {
|
||||||
|
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+18
-1
@@ -256,7 +256,24 @@ public final class HoverboardTrailSystem {
|
|||||||
if (color == null) {
|
if (color == null) {
|
||||||
return DEFAULT_COLOR;
|
return DEFAULT_COLOR;
|
||||||
}
|
}
|
||||||
return rgb(color.getTextureDiffuseColor());
|
return switch (color) {
|
||||||
|
case PURPLE -> rgb(0x00FF3C);
|
||||||
|
case WHITE -> rgb(0xFF1919);
|
||||||
|
case ORANGE -> rgb(0x33CCFF);
|
||||||
|
case LIGHT_BLUE -> rgb(0xFF8A00);
|
||||||
|
case YELLOW -> rgb(0xB026FF);
|
||||||
|
case PINK -> rgb(0x66E0FF);
|
||||||
|
case LIME -> rgb(0xFF00E6);
|
||||||
|
case GRAY -> rgb(0xFF9F4D);
|
||||||
|
case LIGHT_GRAY -> rgb(0x9BFF1A);
|
||||||
|
case BLUE -> rgb(0x2ED9A0);
|
||||||
|
case BROWN -> rgb(0x66C6FF);
|
||||||
|
case GREEN -> rgb(0xFF3B1F);
|
||||||
|
case RED -> rgb(0xFF7A00);
|
||||||
|
case BLACK -> rgb(0xFFFFFF);
|
||||||
|
case MAGENTA -> rgb(0x00E5FF);
|
||||||
|
case CYAN -> rgb(0xFF3DDB);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float[] rgb(int color) {
|
private static float[] rgb(int color) {
|
||||||
|
|||||||
+8
-2
@@ -7,6 +7,8 @@ import com.craisinlord.antarchy.content.entity.HerculesBeetleEntity;
|
|||||||
import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
|
import com.craisinlord.antarchy.content.entity.ToreterrorEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
|
import com.craisinlord.antarchy.content.entity.brutalfly.BrutalflyEntity;
|
||||||
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
|
import com.craisinlord.antarchy.content.entity.kraken.KrakenEntity;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.KingEntity;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -29,7 +31,9 @@ public final class CustomBossBarRenderer {
|
|||||||
AlphaMantisEntity.class, textures("green", "alpha_mantis", 205, 49, 6),
|
AlphaMantisEntity.class, textures("green", "alpha_mantis", 205, 49, 6),
|
||||||
BrutalflyEntity.class, textures("brutalfly", "brutalfly", 198, 38, 3),
|
BrutalflyEntity.class, textures("brutalfly", "brutalfly", 198, 38, 3),
|
||||||
HerculesBeetleEntity.class, textures("beetle", "hercules_beetle", 194, 33, 1),
|
HerculesBeetleEntity.class, textures("beetle", "hercules_beetle", 194, 33, 1),
|
||||||
EmperorScorpionEntity.class, textures("purple", "scorpion", 218, 34, -2)
|
EmperorScorpionEntity.class, textures("purple", "scorpion", 218, 34, -2),
|
||||||
|
KingEntity.class, textures("king", "king", 256, 67, 4),
|
||||||
|
QueenEntity.class, textures("queen", "queen", 253, 50, 6)
|
||||||
);
|
);
|
||||||
private static final Map<String, Textures> BY_LOCALIZED_NAME_AND_COLOR = Map.of(
|
private static final Map<String, Textures> BY_LOCALIZED_NAME_AND_COLOR = Map.of(
|
||||||
key(Component.translatable("entity.antarchy.kraken").getString(), BossEvent.BossBarColor.BLUE), BY_ENTITY_CLASS.get(KrakenEntity.class),
|
key(Component.translatable("entity.antarchy.kraken").getString(), BossEvent.BossBarColor.BLUE), BY_ENTITY_CLASS.get(KrakenEntity.class),
|
||||||
@@ -37,7 +41,9 @@ public final class CustomBossBarRenderer {
|
|||||||
key(Component.translatable("entity.antarchy.alpha_mantis").getString(), BossEvent.BossBarColor.GREEN), BY_ENTITY_CLASS.get(AlphaMantisEntity.class),
|
key(Component.translatable("entity.antarchy.alpha_mantis").getString(), BossEvent.BossBarColor.GREEN), BY_ENTITY_CLASS.get(AlphaMantisEntity.class),
|
||||||
key(Component.translatable("entity.antarchy.brutalfly").getString(), BossEvent.BossBarColor.YELLOW), BY_ENTITY_CLASS.get(BrutalflyEntity.class),
|
key(Component.translatable("entity.antarchy.brutalfly").getString(), BossEvent.BossBarColor.YELLOW), BY_ENTITY_CLASS.get(BrutalflyEntity.class),
|
||||||
key(Component.translatable("entity.antarchy.hercules_beetle").getString(), BossEvent.BossBarColor.RED), BY_ENTITY_CLASS.get(HerculesBeetleEntity.class),
|
key(Component.translatable("entity.antarchy.hercules_beetle").getString(), BossEvent.BossBarColor.RED), BY_ENTITY_CLASS.get(HerculesBeetleEntity.class),
|
||||||
key(Component.translatable("entity.antarchy.emperor_scorpion").getString(), BossEvent.BossBarColor.PURPLE), BY_ENTITY_CLASS.get(EmperorScorpionEntity.class)
|
key(Component.translatable("entity.antarchy.emperor_scorpion").getString(), BossEvent.BossBarColor.PURPLE), BY_ENTITY_CLASS.get(EmperorScorpionEntity.class),
|
||||||
|
key(Component.translatable("entity.antarchy.king").getString(), BossEvent.BossBarColor.YELLOW), BY_ENTITY_CLASS.get(KingEntity.class),
|
||||||
|
key(Component.translatable("entity.antarchy.queen").getString(), BossEvent.BossBarColor.PURPLE), BY_ENTITY_CLASS.get(QueenEntity.class)
|
||||||
);
|
);
|
||||||
|
|
||||||
private CustomBossBarRenderer() {
|
private CustomBossBarRenderer() {
|
||||||
|
|||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.model;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.entity.ManticoreEntity;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
|
public class ManticoreModel extends GeoModel<ManticoreEntity> {
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getModelResource(ManticoreEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/manticore.geo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureResource(ManticoreEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/manticore.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getAnimationResource(ManticoreEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/manticore.animation.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.model;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import software.bernie.geckolib.model.GeoModel;
|
||||||
|
|
||||||
|
public class RoyalBossModel extends GeoModel<RoyalBossEntity> {
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getModelResource(RoyalBossEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "geo/" + animatable.geoNameForRender() + ".geo.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureResource(RoyalBossEntity animatable) {
|
||||||
|
String name = animatable.geoNameForRender();
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "textures/entity/" + name + "/" + name + ".png");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getAnimationResource(RoyalBossEntity animatable) {
|
||||||
|
return ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "animations/" + animatable.geoNameForRender() + ".animation.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.model.ManticoreModel;
|
||||||
|
import com.craisinlord.antarchy.content.entity.ManticoreEntity;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
|
public class ManticoreRenderer extends GeoEntityRenderer<ManticoreEntity> {
|
||||||
|
public ManticoreRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new ManticoreModel());
|
||||||
|
this.shadowRadius = 0.9F;
|
||||||
|
}
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.model.RoyalBossModel;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.RoyalBossEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import software.bernie.geckolib.cache.object.BakedGeoModel;
|
||||||
|
import software.bernie.geckolib.renderer.GeoEntityRenderer;
|
||||||
|
|
||||||
|
public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
||||||
|
public RoyalBossRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context, new RoyalBossModel());
|
||||||
|
this.shadowRadius = 8.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RenderType getRenderType(RoyalBossEntity animatable, ResourceLocation texture, @Nullable MultiBufferSource bufferSource, float partialTick) {
|
||||||
|
return RenderType.entityCutoutNoCull(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preRender(PoseStack poseStack, RoyalBossEntity animatable, BakedGeoModel model, @Nullable MultiBufferSource bufferSource,
|
||||||
|
@Nullable VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int colour) {
|
||||||
|
super.preRender(poseStack, animatable, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, colour);
|
||||||
|
poseStack.scale(RoyalBossEntity.MODEL_RENDER_SCALE, RoyalBossEntity.MODEL_RENDER_SCALE, RoyalBossEntity.MODEL_RENDER_SCALE);
|
||||||
|
this.shadowRadius = 8.0F * RoyalBossEntity.MODEL_RENDER_SCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.craisinlord.antarchy.content.client.renderer;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationFieldEntity;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public class TimeDilationFieldRenderer extends EntityRenderer<TimeDilationFieldEntity> {
|
||||||
|
public TimeDilationFieldRenderer(EntityRendererProvider.Context context) {
|
||||||
|
super(context);
|
||||||
|
this.shadowRadius = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(TimeDilationFieldEntity entity, float entityYaw, float partialTick, PoseStack poseStack,
|
||||||
|
MultiBufferSource bufferSource, int packedLight) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTextureLocation(TimeDilationFieldEntity entity) {
|
||||||
|
return ResourceLocation.withDefaultNamespace("textures/misc/unknown_pack.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
-3
@@ -406,7 +406,7 @@ public final class CreativeTabContents {
|
|||||||
entry("shrink_ray", "combat"),
|
entry("shrink_ray", "combat"),
|
||||||
entry("growth_ray", "combat"),
|
entry("growth_ray", "combat"),
|
||||||
entry("gravity_gun", "combat"),
|
entry("gravity_gun", "combat"),
|
||||||
entry("portal_gun", "combat"),
|
// entry("portal_gun", "combat"), // deferred — out of scope for 2.0
|
||||||
entry("eye_of_the_storm", "combat"),
|
entry("eye_of_the_storm", "combat"),
|
||||||
entry("water_cannon", "combat"),
|
entry("water_cannon", "combat"),
|
||||||
entry("attitude_adjuster", "combat"),
|
entry("attitude_adjuster", "combat"),
|
||||||
@@ -436,8 +436,13 @@ public final class CreativeTabContents {
|
|||||||
entry("royal_assailant_chestplate", "combat"),
|
entry("royal_assailant_chestplate", "combat"),
|
||||||
entry("royal_assailant_leggings", "combat"),
|
entry("royal_assailant_leggings", "combat"),
|
||||||
entry("royal_assailant_boots", "combat"),
|
entry("royal_assailant_boots", "combat"),
|
||||||
entry("prince_egg", "spawn_eggs"),
|
entry("prince_egg", "functional_blocks"),
|
||||||
entry("princess_egg", "spawn_eggs"),
|
entry("princess_egg", "functional_blocks"),
|
||||||
|
entry("king_spawn_egg", "spawn_eggs"),
|
||||||
|
entry("queen_spawn_egg", "spawn_eggs"),
|
||||||
|
entry("manticore_spawn_egg", "spawn_eggs"),
|
||||||
|
entry("prince_spawn_egg", "spawn_eggs"),
|
||||||
|
entry("princess_spawn_egg", "spawn_eggs"),
|
||||||
entry("tigers_eye_helmet", "combat"),
|
entry("tigers_eye_helmet", "combat"),
|
||||||
entry("tigers_eye_chestplate", "combat"),
|
entry("tigers_eye_chestplate", "combat"),
|
||||||
entry("tigers_eye_leggings", "combat"),
|
entry("tigers_eye_leggings", "combat"),
|
||||||
|
|||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package com.craisinlord.antarchy.content.dispenser;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.item.EyeOfTheStormItem;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.dispenser.BlockSource;
|
||||||
|
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.level.block.DispenserBlock;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class EyeOfTheStormDispenseBehavior extends DefaultDispenseItemBehavior {
|
||||||
|
@Override
|
||||||
|
protected ItemStack execute(BlockSource source, ItemStack stack) {
|
||||||
|
ServerLevel level = source.level();
|
||||||
|
Direction direction = source.state().getValue(DispenserBlock.FACING);
|
||||||
|
BlockPos pos = source.pos().relative(direction);
|
||||||
|
Vec3 origin = new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D);
|
||||||
|
Vec3 aim = new Vec3(direction.getStepX(), direction.getStepY(), direction.getStepZ());
|
||||||
|
|
||||||
|
EyeOfTheStormItem.launchStormVortex(level, origin, aim, null);
|
||||||
|
|
||||||
|
if (stack.isDamageableItem()) {
|
||||||
|
stack.setDamageValue(stack.getDamageValue() + 1);
|
||||||
|
if (stack.getDamageValue() >= stack.getMaxDamage()) {
|
||||||
|
stack.shrink(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void playSound(BlockSource source) {
|
||||||
|
source.level().levelEvent(1002, source.pos(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -51,7 +51,7 @@ public class HoverboardEntity extends PathfinderMob implements GeoEntity {
|
|||||||
private static final RawAnimation MOVE_ANIM = RawAnimation.begin().thenLoop("move");
|
private static final RawAnimation MOVE_ANIM = RawAnimation.begin().thenLoop("move");
|
||||||
|
|
||||||
private static final double MAX_HOVER_HEIGHT = 5.0D;
|
private static final double MAX_HOVER_HEIGHT = 5.0D;
|
||||||
private static final double ASCEND_SPEED = 0.15D;
|
private static final double ASCEND_SPEED = 0.2D;
|
||||||
private static final double SETTLE_DESCEND_SPEED = 0.08D;
|
private static final double SETTLE_DESCEND_SPEED = 0.08D;
|
||||||
private static final double FAST_DESCEND_SPEED = 0.9D;
|
private static final double FAST_DESCEND_SPEED = 0.9D;
|
||||||
private static final double FAST_DESCEND_RAMP = 0.2D;
|
private static final double FAST_DESCEND_RAMP = 0.2D;
|
||||||
|
|||||||
+367
@@ -0,0 +1,367 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.QueenEntity;
|
||||||
|
import com.craisinlord.antarchy.content.gravity.AntarchyGravityApi;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.Difficulty;
|
||||||
|
import net.minecraft.world.DifficultyInstance;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.effect.MobEffectInstance;
|
||||||
|
import net.minecraft.world.effect.MobEffects;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.MobSpawnType;
|
||||||
|
import net.minecraft.world.entity.SpawnGroupData;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
|
||||||
|
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
||||||
|
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
|
||||||
|
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
||||||
|
import net.minecraft.world.entity.monster.Monster;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.ServerLevelAccessor;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
|
import software.bernie.geckolib.animation.AnimationController;
|
||||||
|
import software.bernie.geckolib.animation.AnimationState;
|
||||||
|
import software.bernie.geckolib.animation.PlayState;
|
||||||
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
|
public class ManticoreEntity extends Monster implements GeoEntity {
|
||||||
|
private static final String SUMMONER_KEY = "QueenSummoner";
|
||||||
|
private static final int LOST_SUMMONER_GRACE_TICKS = 200;
|
||||||
|
private static final int TAKEOFF_COOLDOWN_TICKS = 40;
|
||||||
|
private static final int STING_COOLDOWN_TICKS = 60;
|
||||||
|
private static final float STING_CHANCE = 0.35F;
|
||||||
|
private static final int SWARM_RETARGET_INTERVAL = 40;
|
||||||
|
|
||||||
|
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||||
|
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||||
|
private static final RawAnimation FLY_ANIM = RawAnimation.begin().thenLoop("fly");
|
||||||
|
private static final RawAnimation BITE_ANIM = RawAnimation.begin().thenPlay("bite");
|
||||||
|
private static final RawAnimation FLY_BITE_ANIM = RawAnimation.begin().thenPlay("fly_bite");
|
||||||
|
private static final RawAnimation STING_ANIM = RawAnimation.begin().thenPlay("sting");
|
||||||
|
private static final RawAnimation FLY_START_ANIM = RawAnimation.begin().thenPlay("fly_start");
|
||||||
|
private static final RawAnimation FLY_LAND_ANIM = RawAnimation.begin().thenPlay("fly_land");
|
||||||
|
|
||||||
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private UUID summonerId;
|
||||||
|
private int lostSummonerTicks;
|
||||||
|
private int takeoffCooldown;
|
||||||
|
private int stingCooldown;
|
||||||
|
private boolean wasFlyingLastTick;
|
||||||
|
|
||||||
|
public ManticoreEntity(EntityType<? extends ManticoreEntity> type, Level level) {
|
||||||
|
super(type, level);
|
||||||
|
this.moveControl = new FlyingMoveControl(this, 10, true);
|
||||||
|
this.xpReward = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
|
return Mob.createMobAttributes()
|
||||||
|
.add(Attributes.MAX_HEALTH, AntarchySettings.manticoreHealth())
|
||||||
|
.add(Attributes.MOVEMENT_SPEED, 0.3D)
|
||||||
|
.add(Attributes.FLYING_SPEED, 0.6D)
|
||||||
|
.add(Attributes.ATTACK_DAMAGE, AntarchySettings.manticoreAttackDamage())
|
||||||
|
.add(Attributes.FOLLOW_RANGE, 28.0D)
|
||||||
|
.add(Attributes.KNOCKBACK_RESISTANCE, 0.2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canSpawn(EntityType<ManticoreEntity> type, ServerLevelAccessor level, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
|
||||||
|
if (spawnReason == MobSpawnType.SPAWN_EGG || spawnReason == MobSpawnType.SPAWNER || spawnReason == MobSpawnType.COMMAND) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
BlockState below = level.getBlockState(pos.below());
|
||||||
|
BlockState above = level.getBlockState(pos.above());
|
||||||
|
boolean floorSupport = !below.is(Blocks.BEDROCK) && below.isFaceSturdy(level, pos.below(), Direction.UP);
|
||||||
|
boolean ceilingSupport = !above.is(Blocks.BEDROCK) && above.isFaceSturdy(level, pos.above(), Direction.DOWN);
|
||||||
|
return level.getDifficulty() != Difficulty.PEACEFUL
|
||||||
|
&& (floorSupport || ceilingSupport)
|
||||||
|
&& level.isEmptyBlock(pos)
|
||||||
|
&& Monster.checkMonsterSpawnRules(type, level, spawnReason, pos, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PathNavigation createNavigation(Level level) {
|
||||||
|
FlyingPathNavigation navigation = new FlyingPathNavigation(this, level);
|
||||||
|
navigation.setCanOpenDoors(false);
|
||||||
|
navigation.setCanFloat(true);
|
||||||
|
navigation.setCanPassDoors(true);
|
||||||
|
return navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerGoals() {
|
||||||
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||||
|
this.goalSelector.addGoal(1, new ManticoreAttackGoal(this));
|
||||||
|
this.goalSelector.addGoal(3, new WaterAvoidingRandomStrollGoal(this, 0.9D));
|
||||||
|
this.goalSelector.addGoal(4, new LookAtPlayerGoal(this, Player.class, 10.0F));
|
||||||
|
this.goalSelector.addGoal(5, new RandomLookAroundGoal(this));
|
||||||
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
|
||||||
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData spawnData) {
|
||||||
|
ConfiguredMobSpawnUtil.applyConfiguredHealth(this, AntarchySettings.manticoreHealth());
|
||||||
|
return super.finalizeSpawn(level, difficulty, spawnReason, spawnData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markQueenSummoned(UUID queenId) {
|
||||||
|
this.summonerId = queenId;
|
||||||
|
this.lostSummonerTicks = 0;
|
||||||
|
this.setPersistenceRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSummonedBy(UUID queenId) {
|
||||||
|
return queenId.equals(this.summonerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isQueenSummoned() {
|
||||||
|
return this.summonerId != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int countSummonedBy(ServerLevel level, UUID queenId) {
|
||||||
|
int count = 0;
|
||||||
|
for (Entity entity : level.getAllEntities()) {
|
||||||
|
if (entity instanceof ManticoreEntity manticore && manticore.isAlive() && manticore.isSummonedBy(queenId)) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeWhenFarAway(double distanceToClosestPlayer) {
|
||||||
|
return this.summonerId == null && super.removeWhenFarAway(distanceToClosestPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresCustomPersistence() {
|
||||||
|
return this.summonerId != null || super.requiresCustomPersistence();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean flying = !this.onGround();
|
||||||
|
if (flying != this.wasFlyingLastTick) {
|
||||||
|
this.triggerAnim("controller", flying ? "fly_start" : "fly_land");
|
||||||
|
this.wasFlyingLastTick = flying;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.takeoffCooldown > 0) {
|
||||||
|
this.takeoffCooldown--;
|
||||||
|
}
|
||||||
|
if (this.stingCooldown > 0) {
|
||||||
|
this.stingCooldown--;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tickQueenSummonCleanup();
|
||||||
|
|
||||||
|
LivingEntity target = this.getTarget();
|
||||||
|
if (target != null && target.isAlive()) {
|
||||||
|
if (this.onGround() && this.takeoffCooldown <= 0 && this.distanceToSqr(target) > 6.0D) {
|
||||||
|
this.takeoff();
|
||||||
|
}
|
||||||
|
if (this.tickCount % SWARM_RETARGET_INTERVAL == 0) {
|
||||||
|
this.spreadSwarmTarget(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickQueenSummonCleanup() {
|
||||||
|
if (this.summonerId == null || !(this.level() instanceof ServerLevel serverLevel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Entity summoner = serverLevel.getEntity(this.summonerId);
|
||||||
|
if (summoner instanceof QueenEntity queen && queen.isAlive()) {
|
||||||
|
this.lostSummonerTicks = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (++this.lostSummonerTicks > LOST_SUMMONER_GRACE_TICKS) {
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void takeoff() {
|
||||||
|
this.takeoffCooldown = TAKEOFF_COOLDOWN_TICKS;
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.55D, 0.0D));
|
||||||
|
this.hasImpulse = true;
|
||||||
|
LivingEntity target = this.getTarget();
|
||||||
|
if (target != null) {
|
||||||
|
Vec3 above = target.position().add(oppositeGravity(this).scale(3.0D));
|
||||||
|
this.getMoveControl().setWantedPosition(above.x, above.y, above.z, 1.2D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spreadSwarmTarget(LivingEntity currentTarget) {
|
||||||
|
List<Player> nearbyPlayers = this.level().getEntitiesOfClass(
|
||||||
|
Player.class,
|
||||||
|
this.getBoundingBox().inflate(this.getAttributeValue(Attributes.FOLLOW_RANGE)),
|
||||||
|
player -> player.isAlive() && this.canAttack(player));
|
||||||
|
if (nearbyPlayers.size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ManticoreEntity> swarm = this.level().getEntitiesOfClass(
|
||||||
|
ManticoreEntity.class,
|
||||||
|
this.getBoundingBox().inflate(32.0D),
|
||||||
|
manticore -> manticore != this && manticore.isAlive());
|
||||||
|
|
||||||
|
Player bestPlayer = null;
|
||||||
|
int bestLoad = Integer.MAX_VALUE;
|
||||||
|
for (Player player : nearbyPlayers) {
|
||||||
|
int load = 0;
|
||||||
|
for (ManticoreEntity manticore : swarm) {
|
||||||
|
if (manticore.getTarget() == player) {
|
||||||
|
load++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (load < bestLoad) {
|
||||||
|
bestLoad = load;
|
||||||
|
bestPlayer = player;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentLoad = 0;
|
||||||
|
for (ManticoreEntity manticore : swarm) {
|
||||||
|
if (manticore.getTarget() == currentTarget) {
|
||||||
|
currentLoad++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bestPlayer != null && bestPlayer != currentTarget && currentLoad - bestLoad >= 2) {
|
||||||
|
this.setTarget(bestPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Vec3 oppositeGravity(Entity entity) {
|
||||||
|
return AntarchyGravityApi.isGravityInverted(entity) ? new Vec3(0.0D, -1.0D, 0.0D) : new Vec3(0.0D, 1.0D, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
void performSting(LivingEntity enemy) {
|
||||||
|
this.swing(InteractionHand.MAIN_HAND);
|
||||||
|
if (enemy.hurt(this.damageSources().mobAttack(this), (float) this.getAttributeValue(Attributes.ATTACK_DAMAGE))) {
|
||||||
|
enemy.addEffect(new MobEffectInstance(MobEffects.POISON, AntarchySettings.manticoreStingPoisonTicks(), 0), this);
|
||||||
|
}
|
||||||
|
this.stingCooldown = STING_COOLDOWN_TICKS;
|
||||||
|
this.triggerAnim("controller", "sting");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean stingReady() {
|
||||||
|
return this.stingCooldown <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean doHurtTarget(Entity target) {
|
||||||
|
boolean hurt = super.doHurtTarget(target);
|
||||||
|
if (hurt) {
|
||||||
|
this.triggerAnim("controller", this.onGround() ? "bite" : "fly_bite");
|
||||||
|
}
|
||||||
|
return hurt;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInWall() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.addAdditionalSaveData(tag);
|
||||||
|
if (this.summonerId != null) {
|
||||||
|
tag.putUUID(SUMMONER_KEY, this.summonerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
super.readAdditionalSaveData(tag);
|
||||||
|
this.summonerId = tag.hasUUID(SUMMONER_KEY) ? tag.getUUID(SUMMONER_KEY) : null;
|
||||||
|
this.lostSummonerTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
|
controllers.add(new AnimationController<>(this, "controller", 3, this::locomotionPredicate)
|
||||||
|
.triggerableAnim("bite", BITE_ANIM)
|
||||||
|
.triggerableAnim("fly_bite", FLY_BITE_ANIM)
|
||||||
|
.triggerableAnim("sting", STING_ANIM)
|
||||||
|
.triggerableAnim("fly_start", FLY_START_ANIM)
|
||||||
|
.triggerableAnim("fly_land", FLY_LAND_ANIM));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayState locomotionPredicate(AnimationState<ManticoreEntity> state) {
|
||||||
|
if (!this.onGround()) {
|
||||||
|
return state.setAndContinue(FLY_ANIM);
|
||||||
|
}
|
||||||
|
if (state.isMoving()) {
|
||||||
|
return state.setAndContinue(WALK_ANIM);
|
||||||
|
}
|
||||||
|
return state.setAndContinue(IDLE_ANIM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
|
return this.geoCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ManticoreAttackGoal extends MeleeAttackGoal {
|
||||||
|
private final ManticoreEntity manticore;
|
||||||
|
|
||||||
|
ManticoreAttackGoal(ManticoreEntity manticore) {
|
||||||
|
super(manticore, 1.1D, true);
|
||||||
|
this.manticore = manticore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void checkAndPerformAttack(LivingEntity enemy) {
|
||||||
|
if (this.canPerformAttack(enemy) && this.isTimeToAttack()) {
|
||||||
|
this.resetAttackCooldown();
|
||||||
|
if (this.manticore.onGround() && this.manticore.stingReady() && this.manticore.getRandom().nextFloat() < STING_CHANCE) {
|
||||||
|
this.manticore.performSting(enemy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.manticore.swing(InteractionHand.MAIN_HAND);
|
||||||
|
this.manticore.doHurtTarget(enemy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.checkAndPerformAttack(enemy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.world.BossEvent;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class KingEntity extends RoyalBossEntity {
|
||||||
|
public KingEntity(EntityType<? extends KingEntity> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
|
return createBaseAttributes(AntarchySettings.kingHealth(), AntarchySettings.kingAttackDamage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String geoName() {
|
||||||
|
return "king";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isFlyingBoss() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossEvent.BossBarColor bossBarColor() {
|
||||||
|
return BossEvent.BossBarColor.YELLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalIdleSound() {
|
||||||
|
return AntarchySoundEvents.KING_IDLE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalHurtSound() {
|
||||||
|
return AntarchySoundEvents.KING_HURT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalDeathSound() {
|
||||||
|
return AntarchySoundEvents.KING_DEATH.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalBiteSound() {
|
||||||
|
return AntarchySoundEvents.KING_BITE.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.AntarchySoundEvents;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.world.BossEvent;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public class QueenEntity extends RoyalBossEntity {
|
||||||
|
public QueenEntity(EntityType<? extends QueenEntity> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AttributeSupplier.Builder createAttributes() {
|
||||||
|
return createBaseAttributes(AntarchySettings.queenHealth(), AntarchySettings.queenAttackDamage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String geoName() {
|
||||||
|
return "queen";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isFlyingBoss() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BossEvent.BossBarColor bossBarColor() {
|
||||||
|
return BossEvent.BossBarColor.PURPLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalIdleSound() {
|
||||||
|
return AntarchySoundEvents.QUEEN_IDLE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalHurtSound() {
|
||||||
|
return AntarchySoundEvents.QUEEN_HURT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalDeathSound() {
|
||||||
|
return AntarchySoundEvents.QUEEN_DEATH.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent royalBiteSound() {
|
||||||
|
return AntarchySoundEvents.QUEEN_BITE.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.GameRules;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public final class RoyalBlockDestruction {
|
||||||
|
private RoyalBlockDestruction() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int destroySphere(
|
||||||
|
ServerLevel level,
|
||||||
|
Entity source,
|
||||||
|
Vec3 center,
|
||||||
|
double radius,
|
||||||
|
int maxBlocks,
|
||||||
|
double maxResistance,
|
||||||
|
float dropChance
|
||||||
|
) {
|
||||||
|
if (maxBlocks <= 0 || radius <= 0.0D || !level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minX = net.minecraft.util.Mth.floor(center.x - radius);
|
||||||
|
int minY = net.minecraft.util.Mth.floor(center.y - radius);
|
||||||
|
int minZ = net.minecraft.util.Mth.floor(center.z - radius);
|
||||||
|
int maxX = net.minecraft.util.Mth.floor(center.x + radius);
|
||||||
|
int maxY = net.minecraft.util.Mth.floor(center.y + radius);
|
||||||
|
int maxZ = net.minecraft.util.Mth.floor(center.z + radius);
|
||||||
|
double radiusSqr = radius * radius;
|
||||||
|
|
||||||
|
int destroyed = 0;
|
||||||
|
for (BlockPos cursor : BlockPos.betweenClosed(minX, minY, minZ, maxX, maxY, maxZ)) {
|
||||||
|
if (destroyed >= maxBlocks) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (cursor.distToCenterSqr(center.x, center.y, center.z) > radiusSqr
|
||||||
|
|| cursor.getY() < level.getMinBuildHeight()
|
||||||
|
|| cursor.getY() >= level.getMaxBuildHeight()
|
||||||
|
|| !level.getWorldBorder().isWithinBounds(cursor)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos pos = cursor.immutable();
|
||||||
|
BlockState existing = level.getBlockState(pos);
|
||||||
|
if (existing.isAir()
|
||||||
|
|| level.getBlockEntity(pos) != null
|
||||||
|
|| existing.getDestroySpeed(level, pos) < 0.0F
|
||||||
|
|| existing.getBlock().getExplosionResistance() > maxResistance
|
||||||
|
|| existing.getCollisionShape(level, pos).isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source.getRandom().nextFloat() <= dropChance) {
|
||||||
|
level.destroyBlock(pos, true, source);
|
||||||
|
} else {
|
||||||
|
level.levelEvent(2001, pos, Block.getId(existing));
|
||||||
|
level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
|
||||||
|
}
|
||||||
|
destroyed++;
|
||||||
|
}
|
||||||
|
return destroyed;
|
||||||
|
}
|
||||||
|
}
|
||||||
+568
@@ -0,0 +1,568 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
|
import com.craisinlord.antarchy.content.entity.multipart.MultipartEntityOwner;
|
||||||
|
import com.craisinlord.antarchy.content.entity.multipart.MultipartLayout;
|
||||||
|
import com.craisinlord.antarchy.content.entity.multipart.MultipartPartDefinition;
|
||||||
|
import com.craisinlord.antarchy.content.entity.royal.beam.RoyalBeamController;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.server.level.ServerBossEvent;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.BossEvent;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.MoverType;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
|
||||||
|
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
|
||||||
|
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
|
||||||
|
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
|
||||||
|
import net.minecraft.world.entity.ai.navigation.PathNavigation;
|
||||||
|
import net.minecraft.world.entity.monster.Monster;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import software.bernie.geckolib.animatable.GeoEntity;
|
||||||
|
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||||
|
import software.bernie.geckolib.animation.AnimatableManager;
|
||||||
|
import software.bernie.geckolib.animation.AnimationController;
|
||||||
|
import software.bernie.geckolib.animation.AnimationState;
|
||||||
|
import software.bernie.geckolib.animation.PlayState;
|
||||||
|
import software.bernie.geckolib.animation.RawAnimation;
|
||||||
|
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||||
|
|
||||||
|
public abstract class RoyalBossEntity extends Monster implements GeoEntity, MultipartEntityOwner {
|
||||||
|
public static final float MODEL_RENDER_SCALE = 2.0F;
|
||||||
|
public static final float GAMEPLAY_WIDTH = 30.0F;
|
||||||
|
public static final float GAMEPLAY_HEIGHT = 30.0F;
|
||||||
|
|
||||||
|
public enum Phase {
|
||||||
|
ONE(1, 1.00F),
|
||||||
|
TWO(2, 0.72F),
|
||||||
|
THREE(3, 0.48F);
|
||||||
|
|
||||||
|
private final int maxConcurrentHeadAttacks;
|
||||||
|
private final float cooldownScale;
|
||||||
|
|
||||||
|
Phase(int maxConcurrentHeadAttacks, float cooldownScale) {
|
||||||
|
this.maxConcurrentHeadAttacks = maxConcurrentHeadAttacks;
|
||||||
|
this.cooldownScale = cooldownScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int maxConcurrentHeadAttacks() {
|
||||||
|
return this.maxConcurrentHeadAttacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float cooldownScale() {
|
||||||
|
return this.cooldownScale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final float PHASE_TWO_THRESHOLD = 0.70F;
|
||||||
|
private static final float PHASE_THREE_THRESHOLD = 0.35F;
|
||||||
|
|
||||||
|
private static final int BITE_DURATION_TICKS = 16;
|
||||||
|
private static final int BITE_HIT_TICK = 6;
|
||||||
|
private static final int DEATH_TICKS = 60;
|
||||||
|
private static final double CRUSH_RADIUS = 3.5D;
|
||||||
|
private static final int CRUSH_MAX_BLOCKS = 24;
|
||||||
|
private static final double CRUSH_MAX_RESISTANCE = 60.0D;
|
||||||
|
private static final float CRUSH_DROP_CHANCE = 0.1F;
|
||||||
|
|
||||||
|
private static final EntityDataAccessor<Boolean> FIRING =
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Boolean> HAS_BEAM_END =
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.BOOLEAN);
|
||||||
|
private static final EntityDataAccessor<Float> BEAM_END_X =
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> BEAM_END_Y =
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> BEAM_END_Z =
|
||||||
|
SynchedEntityData.defineId(RoyalBossEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
|
||||||
|
private static final RawAnimation IDLE_ANIM = RawAnimation.begin().thenLoop("idle");
|
||||||
|
private static final RawAnimation WALK_ANIM = RawAnimation.begin().thenLoop("walk");
|
||||||
|
private static final RawAnimation FLY_ANIM = RawAnimation.begin().thenLoop("fly");
|
||||||
|
private static final RawAnimation DEATH_ANIM = RawAnimation.begin().thenPlayAndHold("death");
|
||||||
|
|
||||||
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
protected final RoyalBeamController beamController = new RoyalBeamController(this);
|
||||||
|
private final ServerBossEvent bossEvent;
|
||||||
|
private final RoyalHead[] heads = {
|
||||||
|
new RoyalHead(RoyalHead.Slot.LEFT),
|
||||||
|
new RoyalHead(RoyalHead.Slot.CENTER),
|
||||||
|
new RoyalHead(RoyalHead.Slot.RIGHT)
|
||||||
|
};
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Entity[] multipartParts;
|
||||||
|
|
||||||
|
protected RoyalBossEntity(EntityType<? extends RoyalBossEntity> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.xpReward = 500;
|
||||||
|
if (this.isFlyingBoss()) {
|
||||||
|
this.moveControl = new FlyingMoveControl(this, 20, true);
|
||||||
|
}
|
||||||
|
this.bossEvent = new com.craisinlord.antarchy.content.boss.EntityLinkedServerBossEvent(
|
||||||
|
this.getUUID(),
|
||||||
|
Component.translatable(entityType.getDescriptionId()),
|
||||||
|
this.bossBarColor(),
|
||||||
|
BossEvent.BossBarOverlay.PROGRESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract BossEvent.BossBarColor bossBarColor();
|
||||||
|
|
||||||
|
protected abstract SoundEvent royalIdleSound();
|
||||||
|
|
||||||
|
protected abstract SoundEvent royalHurtSound();
|
||||||
|
|
||||||
|
protected abstract SoundEvent royalDeathSound();
|
||||||
|
|
||||||
|
protected abstract SoundEvent royalBiteSound();
|
||||||
|
|
||||||
|
public static AttributeSupplier.Builder createBaseAttributes(double health, double attackDamage) {
|
||||||
|
return Mob.createMobAttributes()
|
||||||
|
.add(Attributes.MAX_HEALTH, health)
|
||||||
|
.add(Attributes.ATTACK_DAMAGE, attackDamage)
|
||||||
|
.add(Attributes.ARMOR, AntarchySettings.royalBossArmor())
|
||||||
|
.add(Attributes.FOLLOW_RANGE, AntarchySettings.royalBossFollowRange())
|
||||||
|
.add(Attributes.MOVEMENT_SPEED, AntarchySettings.royalBossMovementSpeed())
|
||||||
|
.add(Attributes.FLYING_SPEED, AntarchySettings.royalBossMovementSpeed())
|
||||||
|
.add(Attributes.KNOCKBACK_RESISTANCE, AntarchySettings.royalBossKnockbackResistance())
|
||||||
|
.add(Attributes.STEP_HEIGHT, AntarchySettings.royalBossStepHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String geoName();
|
||||||
|
|
||||||
|
protected abstract boolean isFlyingBoss();
|
||||||
|
|
||||||
|
public String geoNameForRender() {
|
||||||
|
return this.geoName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartLayout antarchy$getMultipartLayout() {
|
||||||
|
return RoyalBossMultipartLayout.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Entity[] antarchy$getMultipartParts() {
|
||||||
|
return this.multipartParts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void antarchy$setMultipartParts(@Nullable Entity[] parts) {
|
||||||
|
this.multipartParts = parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PathNavigation createNavigation(Level level) {
|
||||||
|
if (this.isFlyingBoss()) {
|
||||||
|
FlyingPathNavigation navigation = new FlyingPathNavigation(this, level);
|
||||||
|
navigation.setCanOpenDoors(false);
|
||||||
|
navigation.setCanFloat(true);
|
||||||
|
return navigation;
|
||||||
|
}
|
||||||
|
return super.createNavigation(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void registerGoals() {
|
||||||
|
this.goalSelector.addGoal(0, new FloatGoal(this));
|
||||||
|
this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 48.0F));
|
||||||
|
this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
|
||||||
|
this.targetSelector.addGoal(1, new HurtByTargetGoal(this));
|
||||||
|
this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
|
super.defineSynchedData(builder);
|
||||||
|
builder.define(FIRING, false);
|
||||||
|
builder.define(HAS_BEAM_END, false);
|
||||||
|
builder.define(BEAM_END_X, 0.0F);
|
||||||
|
builder.define(BEAM_END_Y, 0.0F);
|
||||||
|
builder.define(BEAM_END_Z, 0.0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeWhenFarAway(double distanceToClosestPlayer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkDespawn() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent getAmbientSound() {
|
||||||
|
return this.royalIdleSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent getHurtSound(DamageSource damageSource) {
|
||||||
|
return this.royalHurtSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SoundEvent getDeathSound() {
|
||||||
|
return this.royalDeathSound();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected float getSoundVolume() {
|
||||||
|
return 2.5F;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void travel(Vec3 travelVector) {
|
||||||
|
if (this.isFlyingBoss() && this.isEffectiveAi()) {
|
||||||
|
this.moveRelative(this.getSpeed(), travelVector);
|
||||||
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
||||||
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.91D));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.travel(travelVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (this.isFlyingBoss()) {
|
||||||
|
this.setNoGravity(true);
|
||||||
|
}
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bossEvent.setProgress(this.getHealth() / this.getMaxHealth());
|
||||||
|
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
head.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.isDeadOrDying()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LivingEntity primaryTarget = this.getTarget();
|
||||||
|
if (primaryTarget == null || !primaryTarget.isAlive() || !this.canAttack(primaryTarget)) {
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
head.setTarget(null);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getLookControl().setLookAt(primaryTarget, 30.0F, 30.0F);
|
||||||
|
this.assignHeadTargets(primaryTarget);
|
||||||
|
this.steerTowardTarget(primaryTarget);
|
||||||
|
this.tickBodyCrush();
|
||||||
|
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
if (head.tickBiteHit()) {
|
||||||
|
this.applyBiteHit(head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Phase phase = this.phase();
|
||||||
|
int activeHeadAttacks = 0;
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
if (head.busy()) {
|
||||||
|
activeHeadAttacks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
if (activeHeadAttacks >= phase.maxConcurrentHeadAttacks()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!head.readyToAttack()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LivingEntity headTarget = head.target(this.level());
|
||||||
|
if (headTarget != null && this.headWithinBiteReach(head, headTarget)) {
|
||||||
|
this.startBite(head, phase);
|
||||||
|
activeHeadAttacks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Phase phase() {
|
||||||
|
float fraction = this.getMaxHealth() <= 0.0F ? 1.0F : this.getHealth() / this.getMaxHealth();
|
||||||
|
if (fraction > PHASE_TWO_THRESHOLD) {
|
||||||
|
return Phase.ONE;
|
||||||
|
}
|
||||||
|
if (fraction > PHASE_THREE_THRESHOLD) {
|
||||||
|
return Phase.TWO;
|
||||||
|
}
|
||||||
|
return Phase.THREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assignHeadTargets(LivingEntity fallback) {
|
||||||
|
List<Player> candidates = this.level().getEntitiesOfClass(
|
||||||
|
Player.class,
|
||||||
|
this.getBoundingBox().inflate(AntarchySettings.royalBossFollowRange()),
|
||||||
|
player -> player.isAlive() && this.canAttack(player));
|
||||||
|
if (candidates.isEmpty()) {
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
head.setTarget(fallback);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] assignedCounts = new int[candidates.size()];
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
Vec3 anchor = this.headAnchor(head);
|
||||||
|
int bestIndex = 0;
|
||||||
|
int bestCount = Integer.MAX_VALUE;
|
||||||
|
double bestDistance = Double.MAX_VALUE;
|
||||||
|
for (int i = 0; i < candidates.size(); i++) {
|
||||||
|
double distance = candidates.get(i).position().distanceToSqr(anchor);
|
||||||
|
if (assignedCounts[i] < bestCount || (assignedCounts[i] == bestCount && distance < bestDistance)) {
|
||||||
|
bestIndex = i;
|
||||||
|
bestCount = assignedCounts[i];
|
||||||
|
bestDistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assignedCounts[bestIndex]++;
|
||||||
|
head.setTarget(candidates.get(bestIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void steerTowardTarget(LivingEntity target) {
|
||||||
|
double reach = this.getBbWidth() * 0.5D + this.biteReach() * 0.5D;
|
||||||
|
double dx = target.getX() - this.getX();
|
||||||
|
double dz = target.getZ() - this.getZ();
|
||||||
|
if ((dx * dx + dz * dz) > reach * reach) {
|
||||||
|
double wantedY = this.isFlyingBoss() ? target.getY() + 3.0D : target.getY();
|
||||||
|
this.getMoveControl().setWantedPosition(target.getX(), wantedY, target.getZ(), this.isFlyingBoss() ? 1.1D : 1.0D);
|
||||||
|
} else {
|
||||||
|
this.getNavigation().stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tickBodyCrush() {
|
||||||
|
if (!(this.level() instanceof ServerLevel serverLevel) || this.tickCount % 10 != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.getDeltaMovement().horizontalDistanceSqr() < 0.0016D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double yaw = this.yBodyRot * Mth.DEG_TO_RAD;
|
||||||
|
Vec3 forward = new Vec3(-Math.sin(yaw), 0.0D, Math.cos(yaw));
|
||||||
|
Vec3 center = new Vec3(
|
||||||
|
this.getX() + forward.x * (this.getBbWidth() * 0.45D),
|
||||||
|
this.getY() + (this.isFlyingBoss() ? 0.0D : 1.0D),
|
||||||
|
this.getZ() + forward.z * (this.getBbWidth() * 0.45D));
|
||||||
|
RoyalBlockDestruction.destroySphere(serverLevel, this, center, CRUSH_RADIUS, CRUSH_MAX_BLOCKS, CRUSH_MAX_RESISTANCE, CRUSH_DROP_CHANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startBite(RoyalHead head, Phase phase) {
|
||||||
|
int cooldown = Math.max(10, Mth.floor(AntarchySettings.royalBossBiteCooldownTicks() * phase.cooldownScale()));
|
||||||
|
head.startBite(BITE_DURATION_TICKS, BITE_HIT_TICK, cooldown);
|
||||||
|
this.triggerAnim(head.slot().controllerName(), "bite");
|
||||||
|
this.playSound(this.royalBiteSound(), 3.0F, 0.9F + this.random.nextFloat() * 0.2F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyBiteHit(RoyalHead head) {
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 anchor = this.headAnchor(head);
|
||||||
|
double reach = this.biteReach();
|
||||||
|
float damage = (float) (this.getAttributeValue(Attributes.ATTACK_DAMAGE) * AntarchySettings.royalBossBiteDamageMultiplier());
|
||||||
|
DamageSource damageSource = this.damageSources().mobAttack(this);
|
||||||
|
AABB box = new AABB(anchor, anchor).inflate(reach);
|
||||||
|
for (LivingEntity living : this.level().getEntitiesOfClass(LivingEntity.class, box, entity -> entity.isAlive() && entity != this)) {
|
||||||
|
if (living instanceof RoyalBossEntity || living.getType() == this.getType()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (living.position().distanceToSqr(anchor) > reach * reach) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (living.hurt(damageSource, damage)) {
|
||||||
|
Vec3 push = living.position().subtract(anchor).multiply(1.0D, 0.0D, 1.0D);
|
||||||
|
if (push.lengthSqr() < 1.0E-4D) {
|
||||||
|
push = this.getViewVector(1.0F).multiply(1.0D, 0.0D, 1.0D);
|
||||||
|
}
|
||||||
|
push = push.normalize().scale(1.4D);
|
||||||
|
living.push(push.x, 0.42D, push.z);
|
||||||
|
living.hurtMarked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean headWithinBiteReach(RoyalHead head, LivingEntity target) {
|
||||||
|
Vec3 anchor = this.headAnchor(head);
|
||||||
|
double reach = this.biteReach() + target.getBbWidth();
|
||||||
|
return target.position().distanceToSqr(anchor) <= reach * reach;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double biteReach() {
|
||||||
|
return AntarchySettings.royalBossBiteReach();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vec3 headAnchor(RoyalHead head) {
|
||||||
|
int partIndex = head.slot().partIndex();
|
||||||
|
Entity[] parts = this.multipartParts;
|
||||||
|
if (parts != null && partIndex < parts.length && parts[partIndex] != null) {
|
||||||
|
Entity part = parts[partIndex];
|
||||||
|
return part.position().add(0.0D, part.getBbHeight() * 0.5D, 0.0D);
|
||||||
|
}
|
||||||
|
|
||||||
|
MultipartPartDefinition spec = RoyalBossMultipartLayout.INSTANCE.parts()[partIndex];
|
||||||
|
double yaw = this.yBodyRot * Mth.DEG_TO_RAD;
|
||||||
|
Vec3 forward = new Vec3(-Math.sin(yaw), 0.0D, Math.cos(yaw));
|
||||||
|
Vec3 right = new Vec3(forward.z, 0.0D, -forward.x);
|
||||||
|
return new Vec3(
|
||||||
|
this.getX() + forward.x * spec.forwardOffset() + right.x * spec.lateralOffset(),
|
||||||
|
this.getY() + spec.yOffset(),
|
||||||
|
this.getZ() + forward.z * spec.forwardOffset() + right.z * spec.lateralOffset());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void die(DamageSource damageSource) {
|
||||||
|
if (!this.level().isClientSide) {
|
||||||
|
for (RoyalHead head : this.heads) {
|
||||||
|
head.reset();
|
||||||
|
}
|
||||||
|
this.beamController.stop();
|
||||||
|
this.setFiringRoyalBeam(false);
|
||||||
|
this.setRoyalBeamEndPosition(null);
|
||||||
|
this.getNavigation().stop();
|
||||||
|
this.setDeltaMovement(Vec3.ZERO);
|
||||||
|
}
|
||||||
|
super.die(damageSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tickDeath() {
|
||||||
|
this.deathTime++;
|
||||||
|
if (this.deathTime == 20 && !this.level().isClientSide()) {
|
||||||
|
this.level().broadcastEntityEvent(this, (byte) 60);
|
||||||
|
}
|
||||||
|
if (this.deathTime >= DEATH_TICKS) {
|
||||||
|
this.remove(RemovalReason.KILLED);
|
||||||
|
this.dropExperience(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startSeenByPlayer(ServerPlayer player) {
|
||||||
|
super.startSeenByPlayer(player);
|
||||||
|
this.bossEvent.addPlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stopSeenByPlayer(ServerPlayer player) {
|
||||||
|
super.stopSeenByPlayer(player);
|
||||||
|
this.bossEvent.removePlayer(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hurt(DamageSource source, float amount) {
|
||||||
|
float cappedAmount = (float) Math.min(amount, AntarchySettings.royalBossMaxSingleHitDamage());
|
||||||
|
return super.hurt(source, cappedAmount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFiringRoyalBeam() {
|
||||||
|
return this.entityData.get(FIRING);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFiringRoyalBeam(boolean firing) {
|
||||||
|
this.entityData.set(FIRING, firing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoyalBeamController beamController() {
|
||||||
|
return this.beamController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoyalBeamEndPosition(@Nullable Vec3 position) {
|
||||||
|
this.entityData.set(HAS_BEAM_END, position != null);
|
||||||
|
if (position != null) {
|
||||||
|
this.entityData.set(BEAM_END_X, (float) position.x);
|
||||||
|
this.entityData.set(BEAM_END_Y, (float) position.y);
|
||||||
|
this.entityData.set(BEAM_END_Z, (float) position.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Vec3 getRoyalBeamEndPosition() {
|
||||||
|
if (!this.entityData.get(HAS_BEAM_END)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new Vec3(this.entityData.get(BEAM_END_X), this.entityData.get(BEAM_END_Y), this.entityData.get(BEAM_END_Z));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getRoyalBeamShootFrom(float partialTicks) {
|
||||||
|
double x = Mth.lerp(partialTicks, this.xo, this.getX());
|
||||||
|
double y = Mth.lerp(partialTicks, this.yo, this.getY()) + this.getBbHeight() * 0.72D;
|
||||||
|
double z = Mth.lerp(partialTicks, this.zo, this.getZ());
|
||||||
|
return new Vec3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerControllers(AnimatableManager.ControllerRegistrar controllers) {
|
||||||
|
controllers.add(new AnimationController<>(this, "locomotion", 4, this::locomotionPredicate));
|
||||||
|
controllers.add(new AnimationController<>(this, "head_left", 0, RoyalBossEntity::headIdle)
|
||||||
|
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_1"))
|
||||||
|
.triggerableAnim("shoot", RawAnimation.begin().thenLoop("shoot_1")));
|
||||||
|
controllers.add(new AnimationController<>(this, "head_center", 0, RoyalBossEntity::headIdle)
|
||||||
|
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_2"))
|
||||||
|
.triggerableAnim("shoot", RawAnimation.begin().thenLoop("shoot_2")));
|
||||||
|
controllers.add(new AnimationController<>(this, "head_right", 0, RoyalBossEntity::headIdle)
|
||||||
|
.triggerableAnim("bite", RawAnimation.begin().thenPlay("bite_3"))
|
||||||
|
.triggerableAnim("shoot", RawAnimation.begin().thenLoop("shoot_3")));
|
||||||
|
controllers.add(new AnimationController<>(this, "body_action", 0, this::bodyActionPredicate)
|
||||||
|
.triggerableAnim("stomp", RawAnimation.begin().thenPlay("stomp"))
|
||||||
|
.triggerableAnim("wing_gust", RawAnimation.begin().thenPlay("wing_gust"))
|
||||||
|
.triggerableAnim("minion_spawn", RawAnimation.begin().thenPlay("minion_spawn")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayState locomotionPredicate(AnimationState<RoyalBossEntity> state) {
|
||||||
|
if (this.isDeadOrDying()) {
|
||||||
|
return PlayState.STOP;
|
||||||
|
}
|
||||||
|
if (this.isFlyingBoss()) {
|
||||||
|
state.setAndContinue(FLY_ANIM);
|
||||||
|
} else if (state.isMoving()) {
|
||||||
|
state.setAndContinue(WALK_ANIM);
|
||||||
|
} else {
|
||||||
|
state.setAndContinue(IDLE_ANIM);
|
||||||
|
}
|
||||||
|
return PlayState.CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PlayState bodyActionPredicate(AnimationState<RoyalBossEntity> state) {
|
||||||
|
if (this.isDeadOrDying()) {
|
||||||
|
return state.setAndContinue(DEATH_ANIM);
|
||||||
|
}
|
||||||
|
return PlayState.STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlayState headIdle(AnimationState<RoyalBossEntity> state) {
|
||||||
|
return PlayState.STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatableInstanceCache getAnimatableInstanceCache() {
|
||||||
|
return this.geoCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.entity.multipart.MultipartLayout;
|
||||||
|
import com.craisinlord.antarchy.content.entity.multipart.MultipartPartDefinition;
|
||||||
|
|
||||||
|
public final class RoyalBossMultipartLayout implements MultipartLayout {
|
||||||
|
public static final RoyalBossMultipartLayout INSTANCE = new RoyalBossMultipartLayout();
|
||||||
|
|
||||||
|
public static final MultipartPartDefinition BODY = new MultipartPartDefinition(
|
||||||
|
"body", 20.0F, 24.0F, 1.00F, 0.0D, 3.0D, 0.0D, true);
|
||||||
|
public static final MultipartPartDefinition LEFT_HEAD = new MultipartPartDefinition(
|
||||||
|
"left_head", 8.0F, 8.0F, 1.30F, 12.0D, 20.0D, -7.0D, true);
|
||||||
|
public static final MultipartPartDefinition CENTER_HEAD = new MultipartPartDefinition(
|
||||||
|
"center_head", 9.0F, 9.0F, 1.20F, 13.0D, 22.0D, 0.0D, true);
|
||||||
|
public static final MultipartPartDefinition RIGHT_HEAD = new MultipartPartDefinition(
|
||||||
|
"right_head", 8.0F, 8.0F, 1.30F, 12.0D, 20.0D, 7.0D, true);
|
||||||
|
public static final MultipartPartDefinition LEFT_WING = new MultipartPartDefinition(
|
||||||
|
"left_wing", 14.0F, 16.0F, 0.85F, -2.0D, 14.0D, -13.0D, true);
|
||||||
|
public static final MultipartPartDefinition RIGHT_WING = new MultipartPartDefinition(
|
||||||
|
"right_wing", 14.0F, 16.0F, 0.85F, -2.0D, 14.0D, 13.0D, true);
|
||||||
|
|
||||||
|
private static final MultipartPartDefinition[] PARTS = {
|
||||||
|
BODY,
|
||||||
|
LEFT_HEAD,
|
||||||
|
CENTER_HEAD,
|
||||||
|
RIGHT_HEAD,
|
||||||
|
LEFT_WING,
|
||||||
|
RIGHT_WING
|
||||||
|
};
|
||||||
|
|
||||||
|
private RoyalBossMultipartLayout() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultipartPartDefinition[] parts() {
|
||||||
|
return PARTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
+126
@@ -0,0 +1,126 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public final class RoyalHead {
|
||||||
|
public enum Slot {
|
||||||
|
LEFT(1, "head_left", "bite_1", "shoot_1"),
|
||||||
|
CENTER(2, "head_center", "bite_2", "shoot_2"),
|
||||||
|
RIGHT(3, "head_right", "bite_3", "shoot_3");
|
||||||
|
|
||||||
|
private final int partIndex;
|
||||||
|
private final String controllerName;
|
||||||
|
private final String biteAnimation;
|
||||||
|
private final String shootAnimation;
|
||||||
|
|
||||||
|
Slot(int partIndex, String controllerName, String biteAnimation, String shootAnimation) {
|
||||||
|
this.partIndex = partIndex;
|
||||||
|
this.controllerName = controllerName;
|
||||||
|
this.biteAnimation = biteAnimation;
|
||||||
|
this.shootAnimation = shootAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int partIndex() {
|
||||||
|
return this.partIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String controllerName() {
|
||||||
|
return this.controllerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String biteAnimation() {
|
||||||
|
return this.biteAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String shootAnimation() {
|
||||||
|
return this.shootAnimation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Slot slot;
|
||||||
|
private int targetId = -1;
|
||||||
|
private int attackCooldown;
|
||||||
|
private int biteTicks;
|
||||||
|
private int biteHitTick = -1;
|
||||||
|
private int shootTicks;
|
||||||
|
private boolean beamActive;
|
||||||
|
|
||||||
|
public RoyalHead(Slot slot) {
|
||||||
|
this.slot = slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot slot() {
|
||||||
|
return this.slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public LivingEntity target(Level level) {
|
||||||
|
if (this.targetId < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return level.getEntity(this.targetId) instanceof LivingEntity living && living.isAlive() ? living : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(@Nullable LivingEntity target) {
|
||||||
|
this.targetId = target == null ? -1 : target.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean busy() {
|
||||||
|
return this.biteTicks > 0 || this.shootTicks > 0 || this.beamActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readyToAttack() {
|
||||||
|
return !this.busy() && this.attackCooldown <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startBite(int durationTicks, int hitTick, int cooldownTicks) {
|
||||||
|
this.biteTicks = durationTicks;
|
||||||
|
this.biteHitTick = hitTick;
|
||||||
|
this.attackCooldown = cooldownTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startShoot(int durationTicks, int cooldownTicks) {
|
||||||
|
this.shootTicks = durationTicks;
|
||||||
|
this.attackCooldown = cooldownTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeamActive(boolean beamActive) {
|
||||||
|
this.beamActive = beamActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean beamActive() {
|
||||||
|
return this.beamActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tickBiteHit() {
|
||||||
|
if (this.biteTicks <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.biteTicks--;
|
||||||
|
boolean hit = this.biteTicks == this.biteHitTick;
|
||||||
|
if (hit) {
|
||||||
|
this.biteHitTick = -1;
|
||||||
|
}
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
if (this.attackCooldown > 0) {
|
||||||
|
this.attackCooldown--;
|
||||||
|
}
|
||||||
|
if (this.shootTicks > 0) {
|
||||||
|
this.shootTicks--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
this.targetId = -1;
|
||||||
|
this.attackCooldown = 0;
|
||||||
|
this.biteTicks = 0;
|
||||||
|
this.biteHitTick = -1;
|
||||||
|
this.shootTicks = 0;
|
||||||
|
this.beamActive = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
+295
@@ -0,0 +1,295 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal.beam;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.damagesource.DamageSource;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntitySelector;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
|
import net.minecraft.world.level.ClipContext;
|
||||||
|
import net.minecraft.world.level.GameRules;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public final class RoyalBeamController {
|
||||||
|
private final Mob owner;
|
||||||
|
private Vec3 serverTarget;
|
||||||
|
private Vec3 beamEndPosition;
|
||||||
|
private int beamTicks;
|
||||||
|
private int terrainMutationsThisTick;
|
||||||
|
|
||||||
|
public RoyalBeamController(Mob owner) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFiring() {
|
||||||
|
return this.beamTicks > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int beamTicks() {
|
||||||
|
return this.beamTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Vec3 beamEndPosition() {
|
||||||
|
return this.beamEndPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(Vec3 shootFrom, Vec3 target, int durationTicks) {
|
||||||
|
this.serverTarget = target;
|
||||||
|
this.beamEndPosition = target;
|
||||||
|
this.beamTicks = Math.max(1, durationTicks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
this.serverTarget = null;
|
||||||
|
this.beamEndPosition = null;
|
||||||
|
this.beamTicks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick(
|
||||||
|
Vec3 shootFrom,
|
||||||
|
@Nullable LivingEntity target,
|
||||||
|
RoyalBeamSettings settings,
|
||||||
|
RoyalBeamTerrainMode terrainMode,
|
||||||
|
Consumer<@Nullable Vec3> syncedEndPosition
|
||||||
|
) {
|
||||||
|
if (this.beamTicks <= 0) {
|
||||||
|
syncedEndPosition.accept(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.beamTicks--;
|
||||||
|
this.terrainMutationsThisTick = 0;
|
||||||
|
if (target != null && target.isAlive()) {
|
||||||
|
Vec3 targetEye = target.getEyePosition();
|
||||||
|
this.serverTarget = this.serverTarget == null
|
||||||
|
? targetEye
|
||||||
|
: this.serverTarget.add(targetEye.subtract(this.serverTarget).scale(settings.targetTracking()));
|
||||||
|
}
|
||||||
|
if (this.serverTarget == null) {
|
||||||
|
this.stop();
|
||||||
|
syncedEndPosition.accept(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 direction = this.serverTarget.subtract(shootFrom).normalize();
|
||||||
|
if (direction.lengthSqr() < 1.0E-7D) {
|
||||||
|
direction = this.owner.getLookAngle();
|
||||||
|
}
|
||||||
|
Vec3 clipEnd = shootFrom.add(direction.scale(settings.range()));
|
||||||
|
HitResult hit = this.owner.level().clip(new ClipContext(
|
||||||
|
shootFrom,
|
||||||
|
clipEnd,
|
||||||
|
ClipContext.Block.COLLIDER,
|
||||||
|
ClipContext.Fluid.NONE,
|
||||||
|
this.owner
|
||||||
|
));
|
||||||
|
this.beamEndPosition = hit.getLocation();
|
||||||
|
syncedEndPosition.accept(this.beamEndPosition);
|
||||||
|
|
||||||
|
if (!this.owner.level().isClientSide && this.beamEndPosition != null) {
|
||||||
|
marchDamageAndTerrain(shootFrom, this.beamEndPosition, settings, terrainMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.beamTicks <= 0) {
|
||||||
|
this.stop();
|
||||||
|
syncedEndPosition.accept(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void marchDamageAndTerrain(
|
||||||
|
Vec3 shootFrom,
|
||||||
|
Vec3 beamEnd,
|
||||||
|
RoyalBeamSettings settings,
|
||||||
|
RoyalBeamTerrainMode terrainMode
|
||||||
|
) {
|
||||||
|
Vec3 direction = beamEnd.subtract(shootFrom).normalize();
|
||||||
|
double distance = shootFrom.distanceTo(beamEnd);
|
||||||
|
DamageSource damageSource = this.owner.damageSources().mobAttack(this.owner);
|
||||||
|
for (double walked = settings.pathStep(); walked < Math.min(distance, settings.range()); walked += settings.pathStep()) {
|
||||||
|
Vec3 sample = shootFrom.add(direction.scale(walked));
|
||||||
|
hurtEntitiesAround(sample, settings.pathDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage());
|
||||||
|
if (shouldMutateTerrain(settings, walked)) {
|
||||||
|
mutateTerrainAround(sample, settings.pathTerrainRadius(), settings, terrainMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hurtEntitiesAround(beamEnd, settings.impactDamageRadius(), settings.damage(), settings.knockback(), damageSource, settings.requireLineOfSightForDamage());
|
||||||
|
if (shouldMutateTerrain(settings, shootFrom.distanceTo(beamEnd))) {
|
||||||
|
mutateTerrainAround(beamEnd, settings.impactTerrainRadius(), settings, terrainMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean shouldMutateTerrain(RoyalBeamSettings settings, double distanceFromOwner) {
|
||||||
|
return settings.terrainEnabled()
|
||||||
|
&& settings.maxTerrainMutationsPerTick() > 0
|
||||||
|
&& this.beamTicks % settings.terrainIntervalTicks() == 0
|
||||||
|
&& distanceFromOwner <= settings.maxTerrainDistance()
|
||||||
|
&& this.owner.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hurtEntitiesAround(
|
||||||
|
Vec3 center,
|
||||||
|
float radius,
|
||||||
|
float damageAmount,
|
||||||
|
float knockbackAmount,
|
||||||
|
DamageSource damageSource,
|
||||||
|
boolean requireLineOfSight
|
||||||
|
) {
|
||||||
|
if (radius <= 0.0F || damageAmount <= 0.0F) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AABB aabb = new AABB(center.subtract(radius, radius, radius), center.add(radius, radius, radius));
|
||||||
|
List<LivingEntity> entities = this.owner.level().getEntitiesOfClass(
|
||||||
|
LivingEntity.class,
|
||||||
|
aabb,
|
||||||
|
EntitySelector.NO_CREATIVE_OR_SPECTATOR
|
||||||
|
);
|
||||||
|
boolean hurtAny = false;
|
||||||
|
for (LivingEntity living : entities) {
|
||||||
|
if (living.is(this.owner)
|
||||||
|
|| this.owner.isAlliedTo(living)
|
||||||
|
|| living.getType() == this.owner.getType()
|
||||||
|
|| living.distanceToSqr(center) > radius * radius
|
||||||
|
|| requireLineOfSight && !canEntityBeHurtFrom(center, living)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (living.hurt(damageSource, damageAmount)) {
|
||||||
|
hurtAny = true;
|
||||||
|
knockbackTarget(living, knockbackAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hurtAny;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canEntityBeHurtFrom(Vec3 center, LivingEntity living) {
|
||||||
|
Vec3 targetCenter = living.position().add(0.0D, living.getBbHeight() * 0.5D, 0.0D);
|
||||||
|
return this.owner.level().clip(new ClipContext(
|
||||||
|
center,
|
||||||
|
targetCenter,
|
||||||
|
ClipContext.Block.COLLIDER,
|
||||||
|
ClipContext.Fluid.NONE,
|
||||||
|
this.owner
|
||||||
|
)).getType() == HitResult.Type.MISS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void knockbackTarget(Entity target, double strength) {
|
||||||
|
if (strength <= 0.0D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double resistance = target instanceof LivingEntity living
|
||||||
|
? living.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE)
|
||||||
|
: 0.0D;
|
||||||
|
double appliedStrength = strength * Math.max(0.0D, 1.0D - resistance);
|
||||||
|
if (appliedStrength <= 0.0D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 push = target.position().subtract(this.owner.position()).multiply(1.0D, 0.0D, 1.0D).normalize().scale(appliedStrength);
|
||||||
|
Vec3 movement = target.getDeltaMovement();
|
||||||
|
target.setDeltaMovement(
|
||||||
|
movement.x * 0.5D + push.x,
|
||||||
|
Math.min(0.4D, movement.y * 0.5D + appliedStrength),
|
||||||
|
movement.z * 0.5D + push.z
|
||||||
|
);
|
||||||
|
target.hasImpulse = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mutateTerrainAround(
|
||||||
|
Vec3 center,
|
||||||
|
float radius,
|
||||||
|
RoyalBeamSettings settings,
|
||||||
|
RoyalBeamTerrainMode terrainMode
|
||||||
|
) {
|
||||||
|
if (terrainMode == RoyalBeamTerrainMode.NONE || radius <= 0.0F) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Level level = this.owner.level();
|
||||||
|
int minX = Mth.floor(center.x - radius);
|
||||||
|
int minY = Mth.floor(center.y - radius);
|
||||||
|
int minZ = Mth.floor(center.z - radius);
|
||||||
|
int maxX = Mth.floor(center.x + radius);
|
||||||
|
int maxY = Mth.floor(center.y + radius);
|
||||||
|
int maxZ = Mth.floor(center.z + radius);
|
||||||
|
float radiusSqr = radius * radius;
|
||||||
|
|
||||||
|
for (BlockPos cursor : BlockPos.betweenClosed(minX, minY, minZ, maxX, maxY, maxZ)) {
|
||||||
|
if (this.terrainMutationsThisTick >= settings.maxTerrainMutationsPerTick()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BlockPos pos = cursor.immutable();
|
||||||
|
if (pos.distToCenterSqr(center.x, center.y, center.z) > radiusSqr
|
||||||
|
|| this.owner.getRandom().nextFloat() > settings.terrainMutationChance()
|
||||||
|
|| pos.getY() < level.getMinBuildHeight()
|
||||||
|
|| pos.getY() >= level.getMaxBuildHeight()
|
||||||
|
|| !level.getWorldBorder().isWithinBounds(pos)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState existing = level.getBlockState(pos);
|
||||||
|
if (terrainMode == RoyalBeamTerrainMode.DESTROY) {
|
||||||
|
destroyBeamBlock(level, pos, existing, settings);
|
||||||
|
} else if (terrainMode == RoyalBeamTerrainMode.BUILD_ICE) {
|
||||||
|
buildIceBlock(level, pos, existing, settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyBeamBlock(Level level, BlockPos pos, BlockState existing, RoyalBeamSettings settings) {
|
||||||
|
if (existing.isAir()
|
||||||
|
|| level.getBlockEntity(pos) != null
|
||||||
|
|| existing.getDestroySpeed(level, pos) < 0.0F
|
||||||
|
|| existing.getBlock().getExplosionResistance() > settings.maxTerrainResistance()
|
||||||
|
|| existing.getCollisionShape(level, pos).isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.owner.getRandom().nextFloat() <= settings.terrainDropChance()) {
|
||||||
|
level.destroyBlock(pos, true, this.owner);
|
||||||
|
} else {
|
||||||
|
level.levelEvent(2001, pos, Block.getId(existing));
|
||||||
|
level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
|
||||||
|
}
|
||||||
|
this.terrainMutationsThisTick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildIceBlock(Level level, BlockPos pos, BlockState existing, RoyalBeamSettings settings) {
|
||||||
|
boolean softTarget = existing.isAir()
|
||||||
|
|| existing.canBeReplaced()
|
||||||
|
|| !existing.getFluidState().isEmpty()
|
||||||
|
|| existing.getBlock().getExplosionResistance() <= settings.maxTerrainResistance()
|
||||||
|
&& existing.getDestroySpeed(level, pos) >= 0.0F
|
||||||
|
&& level.getBlockEntity(pos) == null;
|
||||||
|
if (!softTarget) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
level.levelEvent(2001, pos, Block.getId(existing));
|
||||||
|
level.setBlock(pos, randomIceBlock().defaultBlockState(), Block.UPDATE_ALL);
|
||||||
|
this.terrainMutationsThisTick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Block randomIceBlock() {
|
||||||
|
return switch (this.owner.getRandom().nextInt(5)) {
|
||||||
|
case 0 -> Blocks.BLUE_ICE;
|
||||||
|
case 1 -> Blocks.PACKED_ICE;
|
||||||
|
case 2 -> Blocks.FROSTED_ICE;
|
||||||
|
case 3 -> Blocks.SNOW_BLOCK;
|
||||||
|
default -> Blocks.ICE;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal.beam;
|
||||||
|
|
||||||
|
public record RoyalBeamSettings(
|
||||||
|
double range,
|
||||||
|
double targetTracking,
|
||||||
|
double pathStep,
|
||||||
|
float pathDamageRadius,
|
||||||
|
float impactDamageRadius,
|
||||||
|
float damage,
|
||||||
|
float knockback,
|
||||||
|
int terrainIntervalTicks,
|
||||||
|
double maxTerrainDistance,
|
||||||
|
float pathTerrainRadius,
|
||||||
|
float impactTerrainRadius,
|
||||||
|
int maxTerrainMutationsPerTick,
|
||||||
|
float terrainMutationChance,
|
||||||
|
float terrainDropChance,
|
||||||
|
float maxTerrainResistance,
|
||||||
|
boolean terrainEnabled,
|
||||||
|
boolean requireLineOfSightForDamage
|
||||||
|
) {
|
||||||
|
public static RoyalBeamSettings tremorzillaLike(float damage, boolean terrainEnabled) {
|
||||||
|
return new RoyalBeamSettings(
|
||||||
|
100.0D,
|
||||||
|
0.1D,
|
||||||
|
7.5D,
|
||||||
|
6.0F,
|
||||||
|
6.0F,
|
||||||
|
damage,
|
||||||
|
1.0F,
|
||||||
|
3,
|
||||||
|
100.0D,
|
||||||
|
5.0F,
|
||||||
|
4.0F,
|
||||||
|
192,
|
||||||
|
1.0F,
|
||||||
|
0.08F,
|
||||||
|
15.0F,
|
||||||
|
terrainEnabled,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RoyalBeamSettings {
|
||||||
|
range = Math.max(1.0D, range);
|
||||||
|
targetTracking = Math.clamp(targetTracking, 0.0D, 1.0D);
|
||||||
|
pathStep = Math.max(1.0D, pathStep);
|
||||||
|
pathDamageRadius = Math.max(0.0F, pathDamageRadius);
|
||||||
|
impactDamageRadius = Math.max(0.0F, impactDamageRadius);
|
||||||
|
damage = Math.max(0.0F, damage);
|
||||||
|
knockback = Math.max(0.0F, knockback);
|
||||||
|
terrainIntervalTicks = Math.max(1, terrainIntervalTicks);
|
||||||
|
maxTerrainDistance = Math.max(0.0D, maxTerrainDistance);
|
||||||
|
pathTerrainRadius = Math.max(0.0F, pathTerrainRadius);
|
||||||
|
impactTerrainRadius = Math.max(0.0F, impactTerrainRadius);
|
||||||
|
maxTerrainMutationsPerTick = Math.max(0, maxTerrainMutationsPerTick);
|
||||||
|
terrainMutationChance = Math.clamp(terrainMutationChance, 0.0F, 1.0F);
|
||||||
|
terrainDropChance = Math.clamp(terrainDropChance, 0.0F, 1.0F);
|
||||||
|
maxTerrainResistance = Math.max(0.0F, maxTerrainResistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package com.craisinlord.antarchy.content.entity.royal.beam;
|
||||||
|
|
||||||
|
public enum RoyalBeamTerrainMode {
|
||||||
|
NONE,
|
||||||
|
DESTROY,
|
||||||
|
BUILD_ICE
|
||||||
|
}
|
||||||
+69
-12
@@ -62,6 +62,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
private static final String TRAVEL_Y_KEY = "TravelY";
|
private static final String TRAVEL_Y_KEY = "TravelY";
|
||||||
private static final String TRAVEL_Z_KEY = "TravelZ";
|
private static final String TRAVEL_Z_KEY = "TravelZ";
|
||||||
private static final String TRAVELLING_KEY = "Travelling";
|
private static final String TRAVELLING_KEY = "Travelling";
|
||||||
|
private static final String HOMING_KEY = "Homing";
|
||||||
|
|
||||||
private static final double BASE_RADIUS = 0.35D;
|
private static final double BASE_RADIUS = 0.35D;
|
||||||
private static final double DRIFT_FRICTION = 0.96D;
|
private static final double DRIFT_FRICTION = 0.96D;
|
||||||
@@ -80,6 +81,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
private float damageOverride = -1.0F;
|
private float damageOverride = -1.0F;
|
||||||
private Vec3 travelVelocity = Vec3.ZERO;
|
private Vec3 travelVelocity = Vec3.ZERO;
|
||||||
private boolean travelling = false;
|
private boolean travelling = false;
|
||||||
|
private boolean homing = false;
|
||||||
private final Map<UUID, Double> carriedProgress = new HashMap<>();
|
private final Map<UUID, Double> carriedProgress = new HashMap<>();
|
||||||
@Nullable
|
@Nullable
|
||||||
private UUID ownerUuid;
|
private UUID ownerUuid;
|
||||||
@@ -139,6 +141,9 @@ public class WindVortexEntity extends Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.travelling) {
|
if (this.travelling) {
|
||||||
|
if (this.homing) {
|
||||||
|
this.steerTowardPrey();
|
||||||
|
}
|
||||||
Vec3 from = this.position();
|
Vec3 from = this.position();
|
||||||
Vec3 to = from.add(this.travelVelocity);
|
Vec3 to = from.add(this.travelVelocity);
|
||||||
HitResult blockHit = this.level().clip(
|
HitResult blockHit = this.level().clip(
|
||||||
@@ -160,6 +165,40 @@ public class WindVortexEntity extends Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void steerTowardPrey() {
|
||||||
|
double speed = this.travelVelocity.length();
|
||||||
|
if (speed < 1.0E-4D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AABB seekArea = this.getBoundingBox().inflate(12.0D);
|
||||||
|
Entity best = null;
|
||||||
|
double bestDistSqr = Double.MAX_VALUE;
|
||||||
|
for (Entity candidate : this.level().getEntities(this, seekArea, this::isSeekTarget)) {
|
||||||
|
double distSqr = candidate.distanceToSqr(this);
|
||||||
|
if (distSqr < bestDistSqr) {
|
||||||
|
bestDistSqr = distSqr;
|
||||||
|
best = candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (best == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 desired = best.getBoundingBox().getCenter().subtract(this.position());
|
||||||
|
if (desired.lengthSqr() < 1.0E-6D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 steered = this.travelVelocity.normalize().lerp(desired.normalize(), 0.18D);
|
||||||
|
if (steered.lengthSqr() < 1.0E-6D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.travelVelocity = steered.normalize().scale(speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSeekTarget(Entity entity) {
|
||||||
|
return entity instanceof LivingEntity && !(entity instanceof Player) && !this.isOwnedBy(entity)
|
||||||
|
&& this.canAffectEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isInsideSolidBlock() {
|
private boolean isInsideSolidBlock() {
|
||||||
BlockPos pos = this.blockPosition();
|
BlockPos pos = this.blockPosition();
|
||||||
BlockState state = this.level().getBlockState(pos);
|
BlockState state = this.level().getBlockState(pos);
|
||||||
@@ -191,7 +230,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
for (Entity entity : this.level().getEntities(this, area, this::canAffectEntity)) {
|
for (Entity entity : this.level().getEntities(this, area, this::canAffectEntity)) {
|
||||||
Vec3 relative = entity.position().subtract(this.position());
|
Vec3 relative = entity.position().subtract(this.position());
|
||||||
double axisDistance = relative.dot(basis.axis);
|
double axisDistance = relative.dot(basis.axis);
|
||||||
if (axisDistance < -0.25D || axisDistance > height + 0.75D) {
|
if (axisDistance < -1.0D || axisDistance > height + 2.0D) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
double along = Mth.clamp(axisDistance, 0.0D, height);
|
double along = Mth.clamp(axisDistance, 0.0D, height);
|
||||||
@@ -201,9 +240,11 @@ public class WindVortexEntity extends Entity {
|
|||||||
double radius = this.radiusAt(shapeProgress);
|
double radius = this.radiusAt(shapeProgress);
|
||||||
Vec3 axisPoint = basis.axis.scale(axisDistance);
|
Vec3 axisPoint = basis.axis.scale(axisDistance);
|
||||||
Vec3 radialVector = relative.subtract(axisPoint);
|
Vec3 radialVector = relative.subtract(axisPoint);
|
||||||
double captureRadius = radius + (entity instanceof Player ? 1.0D : 0.35D);
|
double captureRadius = radius * 1.35D + (entity instanceof Player ? 1.5D : 1.75D);
|
||||||
|
boolean requireLos = !this.travelling && mode == VortexMode.GATHER_RETURN;
|
||||||
|
|
||||||
if (radialVector.lengthSqr() > captureRadius * captureRadius || !this.hasClearPathTo(entity)) {
|
if (radialVector.lengthSqr() > captureRadius * captureRadius
|
||||||
|
|| (requireLos && !this.hasClearPathTo(entity))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,6 +267,9 @@ public class WindVortexEntity extends Entity {
|
|||||||
double progress = entry.getValue();
|
double progress = entry.getValue();
|
||||||
double direction = mode == VortexMode.LENS_PULL ? -1.0D : 1.0D;
|
double direction = mode == VortexMode.LENS_PULL ? -1.0D : 1.0D;
|
||||||
progress += direction * 0.055D;
|
progress += direction * 0.055D;
|
||||||
|
if (this.travelling) {
|
||||||
|
progress = Math.min(progress, 0.85D);
|
||||||
|
}
|
||||||
if (mode == VortexMode.LENS_PULL && progress <= 0.0D) {
|
if (mode == VortexMode.LENS_PULL && progress <= 0.0D) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
continue;
|
continue;
|
||||||
@@ -237,7 +281,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == VortexMode.UPWARD && progress >= 0.92D) {
|
if (mode == VortexMode.UPWARD && progress >= 0.92D && !this.travelling) {
|
||||||
this.launch(entity, this.radialVectorAt(entity, progress, basis), progress, basis);
|
this.launch(entity, this.radialVectorAt(entity, progress, basis), progress, basis);
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
continue;
|
continue;
|
||||||
@@ -274,9 +318,6 @@ public class WindVortexEntity extends Entity {
|
|||||||
if (!entity.isAlive() || entity.isSpectator() || entity.noPhysics || entity.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) {
|
if (!entity.isAlive() || entity.isSpectator() || entity.noPhysics || entity.getType().is(AntarchyTags.Entities.WIND_VORTEX_IMMUNE)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (entity instanceof Player player && player.isCreative()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +336,9 @@ public class WindVortexEntity extends Entity {
|
|||||||
? Math.max(0.05D, radius * 0.18D)
|
? Math.max(0.05D, radius * 0.18D)
|
||||||
: Mth.lerp(shapeProgress, BASE_RADIUS, radius * 0.82D);
|
: Mth.lerp(shapeProgress, BASE_RADIUS, radius * 0.82D);
|
||||||
double radialError = targetRadius - horizontal;
|
double radialError = targetRadius - horizontal;
|
||||||
double playerScale = entity instanceof Player ? 1.8D : 1.0D;
|
boolean lensMode = mode == VortexMode.LENS_PULL || mode == VortexMode.LENS_PUSH;
|
||||||
|
double lensLivingBoost = lensMode && entity instanceof LivingEntity ? 1.6D : 1.0D;
|
||||||
|
double playerScale = (entity instanceof Player ? 1.8D : 1.35D) * lensLivingBoost;
|
||||||
double pull = this.pullStrength * playerScale * (entity.isShiftKeyDown() ? 0.5D : 1.0D);
|
double pull = this.pullStrength * playerScale * (entity.isShiftKeyDown() ? 0.5D : 1.0D);
|
||||||
double massScale = Mth.clamp(1.35D / Math.max(0.35D, entity.getBbWidth() * entity.getBbHeight()), 0.28D, 1.0D);
|
double massScale = Mth.clamp(1.35D / Math.max(0.35D, entity.getBbWidth() * entity.getBbHeight()), 0.28D, 1.0D);
|
||||||
double spin = (0.24D + progress * 0.34D) * massScale * playerScale;
|
double spin = (0.24D + progress * 0.34D) * massScale * playerScale;
|
||||||
@@ -305,8 +348,8 @@ public class WindVortexEntity extends Entity {
|
|||||||
case UPWARD -> (0.13D + progress * 0.16D) * massScale;
|
case UPWARD -> (0.13D + progress * 0.16D) * massScale;
|
||||||
case GATHER_RETURN -> (0.05D + progress * 0.08D) * massScale;
|
case GATHER_RETURN -> (0.05D + progress * 0.08D) * massScale;
|
||||||
} * playerScale;
|
} * playerScale;
|
||||||
if (mode == VortexMode.UPWARD && entity instanceof Player && entity.onGround()) {
|
if (mode == VortexMode.UPWARD && entity.onGround()) {
|
||||||
axialSpeed = Math.max(axialSpeed, 0.38D);
|
axialSpeed = Math.max(axialSpeed, entity instanceof Player ? 0.38D : 0.3D);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 wanted = radial.scale(radialError * pull)
|
Vec3 wanted = radial.scale(radialError * pull)
|
||||||
@@ -318,8 +361,16 @@ public class WindVortexEntity extends Entity {
|
|||||||
Mth.lerp(0.58D, current.y, wanted.y),
|
Mth.lerp(0.58D, current.y, wanted.y),
|
||||||
Mth.lerp(0.72D, current.z, wanted.z)
|
Mth.lerp(0.72D, current.z, wanted.z)
|
||||||
);
|
);
|
||||||
if (mode == VortexMode.UPWARD && entity instanceof Player && entity.onGround()) {
|
if (this.travelling) {
|
||||||
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, 0.38D), updatedMovement.z);
|
updatedMovement = updatedMovement.add(this.travelVelocity.x * 0.8D, 0.0D, this.travelVelocity.z * 0.8D);
|
||||||
|
}
|
||||||
|
if (mode == VortexMode.UPWARD && entity.onGround()) {
|
||||||
|
double minRise = entity instanceof Player ? 0.38D : 0.3D;
|
||||||
|
updatedMovement = new Vec3(updatedMovement.x, Math.max(updatedMovement.y, minRise), updatedMovement.z);
|
||||||
|
entity.setOnGround(false);
|
||||||
|
}
|
||||||
|
if (entity instanceof Player) {
|
||||||
|
entity.move(net.minecraft.world.entity.MoverType.SELF, wanted.scale(0.65D));
|
||||||
entity.setOnGround(false);
|
entity.setOnGround(false);
|
||||||
}
|
}
|
||||||
entity.setDeltaMovement(updatedMovement);
|
entity.setDeltaMovement(updatedMovement);
|
||||||
@@ -455,6 +506,10 @@ public class WindVortexEntity extends Entity {
|
|||||||
this.noPhysics = true;
|
this.noPhysics = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setHoming(boolean homing) {
|
||||||
|
this.homing = homing;
|
||||||
|
}
|
||||||
|
|
||||||
public void setVortexStrengths(double pullStrength, double launchStrength) {
|
public void setVortexStrengths(double pullStrength, double launchStrength) {
|
||||||
this.pullStrength = Math.max(0.0D, pullStrength);
|
this.pullStrength = Math.max(0.0D, pullStrength);
|
||||||
this.launchStrength = Math.max(0.0D, launchStrength);
|
this.launchStrength = Math.max(0.0D, launchStrength);
|
||||||
@@ -491,6 +546,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
this.setMode(VortexMode.values()[Mth.clamp(tag.getInt(MODE_KEY), 0, VortexMode.values().length - 1)]);
|
this.setMode(VortexMode.values()[Mth.clamp(tag.getInt(MODE_KEY), 0, VortexMode.values().length - 1)]);
|
||||||
this.setAxis(new Vec3(tag.getFloat(AXIS_X_KEY), tag.getFloat(AXIS_Y_KEY), tag.getFloat(AXIS_Z_KEY)));
|
this.setAxis(new Vec3(tag.getFloat(AXIS_X_KEY), tag.getFloat(AXIS_Y_KEY), tag.getFloat(AXIS_Z_KEY)));
|
||||||
this.travelling = tag.getBoolean(TRAVELLING_KEY);
|
this.travelling = tag.getBoolean(TRAVELLING_KEY);
|
||||||
|
this.homing = tag.getBoolean(HOMING_KEY);
|
||||||
this.travelVelocity = new Vec3(tag.getDouble(TRAVEL_X_KEY), tag.getDouble(TRAVEL_Y_KEY), tag.getDouble(TRAVEL_Z_KEY));
|
this.travelVelocity = new Vec3(tag.getDouble(TRAVEL_X_KEY), tag.getDouble(TRAVEL_Y_KEY), tag.getDouble(TRAVEL_Z_KEY));
|
||||||
if (this.travelling) {
|
if (this.travelling) {
|
||||||
this.noPhysics = true;
|
this.noPhysics = true;
|
||||||
@@ -514,6 +570,7 @@ public class WindVortexEntity extends Entity {
|
|||||||
tag.putFloat(AXIS_Y_KEY, (float) this.getAxis().y);
|
tag.putFloat(AXIS_Y_KEY, (float) this.getAxis().y);
|
||||||
tag.putFloat(AXIS_Z_KEY, (float) this.getAxis().z);
|
tag.putFloat(AXIS_Z_KEY, (float) this.getAxis().z);
|
||||||
tag.putBoolean(TRAVELLING_KEY, this.travelling);
|
tag.putBoolean(TRAVELLING_KEY, this.travelling);
|
||||||
|
tag.putBoolean(HOMING_KEY, this.homing);
|
||||||
tag.putDouble(TRAVEL_X_KEY, this.travelVelocity.x);
|
tag.putDouble(TRAVEL_X_KEY, this.travelVelocity.x);
|
||||||
tag.putDouble(TRAVEL_Y_KEY, this.travelVelocity.y);
|
tag.putDouble(TRAVEL_Y_KEY, this.travelVelocity.y);
|
||||||
tag.putDouble(TRAVEL_Z_KEY, this.travelVelocity.z);
|
tag.putDouble(TRAVEL_Z_KEY, this.travelVelocity.z);
|
||||||
|
|||||||
+20
-18
@@ -23,7 +23,9 @@ import net.minecraft.stats.Stats;
|
|||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.InteractionResultHolder;
|
import net.minecraft.world.InteractionResultHolder;
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
import net.minecraft.world.entity.EquipmentSlot;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
@@ -45,8 +47,7 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
private static final String IDLE_CONTROLLER = "idle_controller";
|
private static final String IDLE_CONTROLLER = "idle_controller";
|
||||||
private static final String IDLE_ANIMATION = "spinning_idle";
|
private static final String IDLE_ANIMATION = "spinning_idle";
|
||||||
private static final Map<UUID, Long> LAST_UPDRAFT_TICK = new ConcurrentHashMap<>();
|
private static final Map<UUID, Long> LAST_UPDRAFT_TICK = new ConcurrentHashMap<>();
|
||||||
private static final Map<UUID, Long> LAST_SURGE_TICK = new ConcurrentHashMap<>();
|
private static final float SURGE_PROJECTILE_SPEED = 0.65F;
|
||||||
private static final float SURGE_PROJECTILE_SPEED = 0.9F;
|
|
||||||
|
|
||||||
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
private final AnimatableInstanceCache geoCache = GeckoLibUtil.createInstanceCache(this);
|
||||||
|
|
||||||
@@ -107,22 +108,25 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long now = level.getGameTime();
|
Vec3 look = player.getViewVector(1.0F);
|
||||||
Long last = LAST_SURGE_TICK.get(player.getUUID());
|
launchStormVortex(level, player.getEyePosition().add(look), look, player);
|
||||||
if (last != null && now - last < AntarchySettings.eyeOfTheStormSurgeCooldownTicks()) {
|
|
||||||
|
player.awardStat(Stats.ITEM_USED.get(this));
|
||||||
|
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void launchStormVortex(ServerLevel level, Vec3 origin, Vec3 direction, @Nullable LivingEntity owner) {
|
||||||
|
if (!AntarchySettings.eyeOfTheStormEnabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
LAST_SURGE_TICK.put(player.getUUID(), now);
|
Vec3 dir = direction.lengthSqr() < 1.0E-6D ? new Vec3(0.0D, 0.0D, 1.0D) : direction.normalize();
|
||||||
|
|
||||||
Vec3 look = player.getViewVector(1.0F);
|
|
||||||
Vec3 spawn = player.getEyePosition().add(look);
|
|
||||||
|
|
||||||
WindVortexEntity vortex = WindVortexEntity.create(
|
WindVortexEntity vortex = WindVortexEntity.create(
|
||||||
level,
|
level,
|
||||||
AntarchyObjects.WIND_VORTEX.get(),
|
AntarchyObjects.WIND_VORTEX.get(),
|
||||||
spawn,
|
origin,
|
||||||
Vec3.ZERO,
|
Vec3.ZERO,
|
||||||
player,
|
owner,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
vortex.setMode(WindVortexEntity.VortexMode.UPWARD);
|
vortex.setMode(WindVortexEntity.VortexMode.UPWARD);
|
||||||
@@ -131,14 +135,12 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
vortex.setVortexDurationTicks(AntarchySettings.eyeOfTheStormSurgeDurationTicks());
|
vortex.setVortexDurationTicks(AntarchySettings.eyeOfTheStormSurgeDurationTicks());
|
||||||
vortex.setVortexStrengths(AntarchySettings.eyeOfTheStormSurgePullStrength(), AntarchySettings.eyeOfTheStormSurgeReturnStrength());
|
vortex.setVortexStrengths(AntarchySettings.eyeOfTheStormSurgePullStrength(), AntarchySettings.eyeOfTheStormSurgeReturnStrength());
|
||||||
vortex.setDamageOverride(AntarchySettings.eyeOfTheStormSurgeDamage());
|
vortex.setDamageOverride(AntarchySettings.eyeOfTheStormSurgeDamage());
|
||||||
vortex.setTravel(look.scale(SURGE_PROJECTILE_SPEED));
|
vortex.setTravel(dir.scale(SURGE_PROJECTILE_SPEED));
|
||||||
|
vortex.setHoming(true);
|
||||||
level.addFreshEntity(vortex);
|
level.addFreshEntity(vortex);
|
||||||
|
|
||||||
level.playSound(null, spawn.x, spawn.y, spawn.z,
|
level.playSound(null, origin.x, origin.y, origin.z,
|
||||||
SoundEvents.BREEZE_WIND_CHARGE_BURST, SoundSource.PLAYERS, 1.0F, 0.8F);
|
SoundEvents.BREEZE_WIND_CHARGE_BURST, SoundSource.PLAYERS, 1.0F, 0.8F);
|
||||||
|
|
||||||
player.awardStat(Stats.ITEM_USED.get(this));
|
|
||||||
stack.hurtAndBreak(1, player, EquipmentSlot.MAINHAND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -148,8 +150,8 @@ public class EyeOfTheStormItem extends Item implements GeoItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
||||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.eye_of_the_storm.updraft").withStyle(ChatFormatting.AQUA));
|
tooltipComponents.add(Component.translatable("tooltip.antarchy.eye_of_the_storm.updraft").withStyle(ChatFormatting.DARK_AQUA));
|
||||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.eye_of_the_storm.surge").withStyle(ChatFormatting.AQUA));
|
tooltipComponents.add(Component.translatable("tooltip.antarchy.eye_of_the_storm.surge").withStyle(ChatFormatting.DARK_AQUA));
|
||||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-10
@@ -1,14 +1,10 @@
|
|||||||
package com.craisinlord.antarchy.content.item;
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.ShieldItem;
|
import net.minecraft.world.item.ShieldItem;
|
||||||
import net.minecraft.world.item.TooltipFlag;
|
|
||||||
import net.minecraft.world.item.crafting.Ingredient;
|
import net.minecraft.world.item.crafting.Ingredient;
|
||||||
|
|
||||||
public class RoyalGuardianShieldItem extends ShieldItem {
|
public class RoyalGuardianShieldItem extends ShieldItem {
|
||||||
@@ -28,10 +24,4 @@ public class RoyalGuardianShieldItem extends ShieldItem {
|
|||||||
public int getEnchantmentValue() {
|
public int getEnchantmentValue() {
|
||||||
return AntarchySettings.royalWeaponEnchantability();
|
return AntarchySettings.royalWeaponEnchantability();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
|
||||||
tooltipComponents.add(Component.translatable("tooltip.antarchy.royal_guardian_shield").withStyle(ChatFormatting.GOLD));
|
|
||||||
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
package com.craisinlord.antarchy.content.item;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.item.BlockItem;
|
||||||
|
import net.minecraft.world.item.Item;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.TooltipFlag;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
public class VortexLensBlockItem extends BlockItem {
|
||||||
|
public VortexLensBlockItem(Block block, Properties properties) {
|
||||||
|
super(block, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendHoverText(ItemStack stack, Item.TooltipContext context, List<Component> tooltipComponents, TooltipFlag tooltipFlag) {
|
||||||
|
tooltipComponents.add(Component.translatable("tooltip.antarchy.vortex_lens").withStyle(ChatFormatting.DARK_AQUA));
|
||||||
|
super.appendHoverText(stack, context, tooltipComponents, tooltipFlag);
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.craisinlord.antarchy.content.network;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.Antarchy;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
|
import net.minecraft.network.codec.StreamCodec;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public record TimeDilationRatePayload(int entityId, double rate) implements CustomPacketPayload {
|
||||||
|
public static final Type<TimeDilationRatePayload> TYPE =
|
||||||
|
new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "time_dilation_rate"));
|
||||||
|
public static final StreamCodec<ByteBuf, TimeDilationRatePayload> STREAM_CODEC = StreamCodec.composite(
|
||||||
|
ByteBufCodecs.VAR_INT,
|
||||||
|
TimeDilationRatePayload::entityId,
|
||||||
|
ByteBufCodecs.DOUBLE,
|
||||||
|
TimeDilationRatePayload::rate,
|
||||||
|
TimeDilationRatePayload::new
|
||||||
|
);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Type<TimeDilationRatePayload> type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public final class TimeDilationApi {
|
||||||
|
private static BiConsumer<ServerPlayer, Double> syncDispatcher = (player, rate) -> {
|
||||||
|
};
|
||||||
|
|
||||||
|
private TimeDilationApi() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSyncDispatcher(BiConsumer<ServerPlayer, Double> dispatcher) {
|
||||||
|
syncDispatcher = dispatcher != null ? dispatcher : (player, rate) -> {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TimeDilationFieldEntity createField(ServerLevel level, Vec3 center, double radius, double rate, int durationTicks) {
|
||||||
|
TimeDilationFieldEntity field = TimeDilationFieldEntity.create(level, center, radius, rate, durationTicks);
|
||||||
|
level.addFreshEntity(field);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getRate(Entity entity) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
return access.antarchy$getTimeDilationRate();
|
||||||
|
}
|
||||||
|
return TimeDilationMath.NORMAL_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDilated(Entity entity) {
|
||||||
|
return getRate(entity) < TimeDilationMath.NORMAL_RATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void applySyncedRate(Entity entity, double rate) {
|
||||||
|
if (entity instanceof TimeDilationEntityAccess access) {
|
||||||
|
access.antarchy$setTimeDilationRate(rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void syncPlayerRate(ServerPlayer player, double rate) {
|
||||||
|
syncDispatcher.accept(player, TimeDilationMath.clampRate(rate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean consumeTick(Entity entity, String timerKey) {
|
||||||
|
if (entity instanceof Player) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
double rate = getRate(entity);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE || !(entity instanceof TimeDilationEntityAccess access)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return access.antarchy$consumeTimeDilationTick(timerKey, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int scaleCooldownTicks(Entity entity, int ticks) {
|
||||||
|
double rate = getRate(entity);
|
||||||
|
if (ticks <= 0 || rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return ticks;
|
||||||
|
}
|
||||||
|
return (int) Math.ceil(ticks / Math.max(TimeDilationMath.MIN_RATE, rate));
|
||||||
|
}
|
||||||
|
}
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
|
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||||
|
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.Commands;
|
||||||
|
import net.minecraft.commands.arguments.coordinates.Vec3Argument;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public final class TimeDilationCommand {
|
||||||
|
private TimeDilationCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||||
|
dispatcher.register(
|
||||||
|
Commands.literal("timedilation")
|
||||||
|
.requires(source -> source.hasPermission(2))
|
||||||
|
.then(Commands.literal("create")
|
||||||
|
.then(Commands.argument("center", Vec3Argument.vec3())
|
||||||
|
.then(Commands.argument("radius", DoubleArgumentType.doubleArg(0.5D, 128.0D))
|
||||||
|
.then(Commands.argument("rate", DoubleArgumentType.doubleArg(TimeDilationMath.MIN_RATE, 1.0D))
|
||||||
|
.then(Commands.argument("durationTicks", IntegerArgumentType.integer(-1))
|
||||||
|
.executes(TimeDilationCommand::create))))))
|
||||||
|
.then(Commands.literal("create_here")
|
||||||
|
.then(Commands.argument("radius", DoubleArgumentType.doubleArg(0.5D, 128.0D))
|
||||||
|
.then(Commands.argument("rate", DoubleArgumentType.doubleArg(TimeDilationMath.MIN_RATE, 1.0D))
|
||||||
|
.then(Commands.argument("durationTicks", IntegerArgumentType.integer(-1))
|
||||||
|
.executes(TimeDilationCommand::createHere)))))
|
||||||
|
.then(Commands.literal("list").executes(TimeDilationCommand::list))
|
||||||
|
.then(Commands.literal("clear").executes(TimeDilationCommand::clear))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int create(CommandContext<CommandSourceStack> context) {
|
||||||
|
return createField(context, Vec3Argument.getVec3(context, "center"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int createHere(CommandContext<CommandSourceStack> context) {
|
||||||
|
return createField(context, context.getSource().getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int createField(CommandContext<CommandSourceStack> context, Vec3 center) {
|
||||||
|
ServerLevel level = context.getSource().getLevel();
|
||||||
|
double radius = DoubleArgumentType.getDouble(context, "radius");
|
||||||
|
double rate = DoubleArgumentType.getDouble(context, "rate");
|
||||||
|
int durationTicks = IntegerArgumentType.getInteger(context, "durationTicks");
|
||||||
|
TimeDilationFieldEntity field = TimeDilationApi.createField(level, center, radius, rate, durationTicks);
|
||||||
|
context.getSource().sendSuccess(
|
||||||
|
() -> Component.literal("Created time dilation field " + field.getUUID() + " radius=" + radius
|
||||||
|
+ " rate=" + rate + " durationTicks=" + durationTicks),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int list(CommandContext<CommandSourceStack> context) {
|
||||||
|
int count = 0;
|
||||||
|
for (ServerLevel level : context.getSource().getServer().getAllLevels()) {
|
||||||
|
for (Entity entity : level.getAllEntities()) {
|
||||||
|
if (!(entity instanceof TimeDilationFieldEntity field)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
context.getSource().sendSuccess(
|
||||||
|
() -> Component.literal(field.getUUID() + " " + level.dimension().location() + " @ "
|
||||||
|
+ format(field.position()) + " radius=" + field.fieldRadius() + " rate=" + field.fieldRate()
|
||||||
|
+ " age=" + field.fieldAge()
|
||||||
|
+ (field.isInfinite() ? " duration=infinite" : " duration=" + field.fieldDurationTicks())),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int clear(CommandContext<CommandSourceStack> context) {
|
||||||
|
List<TimeDilationFieldEntity> fields = new ArrayList<>();
|
||||||
|
for (ServerLevel level : context.getSource().getServer().getAllLevels()) {
|
||||||
|
for (Entity entity : level.getAllEntities()) {
|
||||||
|
if (entity instanceof TimeDilationFieldEntity field) {
|
||||||
|
fields.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fields.forEach(Entity::discard);
|
||||||
|
int count = fields.size();
|
||||||
|
context.getSource().sendSuccess(() -> Component.literal("Cleared " + count + " time dilation field(s)"), true);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String format(Vec3 vec) {
|
||||||
|
return String.format(java.util.Locale.ROOT, "%.2f %.2f %.2f", vec.x, vec.y, vec.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
public interface TimeDilationEntityAccess {
|
||||||
|
double antarchy$getTimeDilationRate();
|
||||||
|
|
||||||
|
void antarchy$setTimeDilationRate(double rate);
|
||||||
|
|
||||||
|
boolean antarchy$consumeTimeDilationTick(String timerKey, double rate);
|
||||||
|
|
||||||
|
boolean antarchy$isInTimeDilationMove();
|
||||||
|
|
||||||
|
void antarchy$setInTimeDilationMove(boolean inMove);
|
||||||
|
}
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||||
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||||
|
import net.minecraft.network.syncher.SynchedEntityData;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public class TimeDilationFieldEntity extends Entity {
|
||||||
|
private static final EntityDataAccessor<Float> RADIUS =
|
||||||
|
SynchedEntityData.defineId(TimeDilationFieldEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
private static final EntityDataAccessor<Float> RATE =
|
||||||
|
SynchedEntityData.defineId(TimeDilationFieldEntity.class, EntityDataSerializers.FLOAT);
|
||||||
|
|
||||||
|
private static final String RADIUS_KEY = "Radius";
|
||||||
|
private static final String RATE_KEY = "Rate";
|
||||||
|
private static final String DURATION_KEY = "DurationTicks";
|
||||||
|
private static final String AGE_KEY = "Age";
|
||||||
|
|
||||||
|
private int durationTicks = -1;
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
public TimeDilationFieldEntity(EntityType<? extends TimeDilationFieldEntity> entityType, Level level) {
|
||||||
|
super(entityType, level);
|
||||||
|
this.noPhysics = true;
|
||||||
|
this.noCulling = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TimeDilationFieldEntity create(Level level, Vec3 center, double radius, double rate, int durationTicks) {
|
||||||
|
TimeDilationFieldEntity field = new TimeDilationFieldEntity(AntarchyObjects.TIME_DILATION_FIELD.get(), level);
|
||||||
|
field.setPos(center.x, center.y, center.z);
|
||||||
|
field.setFieldRadius(radius);
|
||||||
|
field.setFieldRate(rate);
|
||||||
|
field.durationTicks = durationTicks;
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData(SynchedEntityData.Builder builder) {
|
||||||
|
builder.define(RADIUS, 8.0F);
|
||||||
|
builder.define(RATE, (float) TimeDilationMath.NORMAL_RATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if (this.level().isClientSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.age++;
|
||||||
|
if (this.durationTicks >= 0 && this.age >= this.durationTicks) {
|
||||||
|
this.discard();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldRadius(double radius) {
|
||||||
|
this.entityData.set(RADIUS, (float) Math.max(0.5D, radius));
|
||||||
|
}
|
||||||
|
|
||||||
|
public double fieldRadius() {
|
||||||
|
return this.entityData.get(RADIUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double fieldRadiusSqr() {
|
||||||
|
double radius = this.fieldRadius();
|
||||||
|
return radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFieldRate(double rate) {
|
||||||
|
this.entityData.set(RATE, (float) TimeDilationMath.clampRate(rate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public double fieldRate() {
|
||||||
|
return TimeDilationMath.clampRate(this.entityData.get(RATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fieldDurationTicks() {
|
||||||
|
return this.durationTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int fieldAge() {
|
||||||
|
return this.age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInfinite() {
|
||||||
|
return this.durationTicks < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isIgnoringBlockTriggers() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
||||||
|
this.setFieldRadius(tag.getDouble(RADIUS_KEY));
|
||||||
|
this.setFieldRate(tag.getDouble(RATE_KEY));
|
||||||
|
this.durationTicks = tag.contains(DURATION_KEY) ? tag.getInt(DURATION_KEY) : -1;
|
||||||
|
this.age = tag.getInt(AGE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addAdditionalSaveData(CompoundTag tag) {
|
||||||
|
tag.putDouble(RADIUS_KEY, this.fieldRadius());
|
||||||
|
tag.putDouble(RATE_KEY, this.fieldRate());
|
||||||
|
tag.putInt(DURATION_KEY, this.durationTicks);
|
||||||
|
tag.putInt(AGE_KEY, this.age);
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public final class TimeDilationFieldSampler {
|
||||||
|
private TimeDilationFieldSampler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sample(List<TimeDilationFieldEntity> fields, Vec3 position) {
|
||||||
|
return sample(fields, position.x, position.y, position.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double sample(List<TimeDilationFieldEntity> fields, double x, double y, double z) {
|
||||||
|
double combinedRate = TimeDilationMath.NORMAL_RATE;
|
||||||
|
for (TimeDilationFieldEntity field : fields) {
|
||||||
|
Vec3 center = field.position();
|
||||||
|
double dx = center.x - x;
|
||||||
|
double dy = center.y - y;
|
||||||
|
double dz = center.z - z;
|
||||||
|
double distanceSqr = dx * dx + dy * dy + dz * dz;
|
||||||
|
if (distanceSqr >= field.fieldRadiusSqr()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double falloff = TimeDilationMath.gaussianFalloff(Math.sqrt(distanceSqr), field.fieldRadius());
|
||||||
|
combinedRate *= TimeDilationMath.localFieldRate(field.fieldRate(), falloff);
|
||||||
|
}
|
||||||
|
return TimeDilationMath.clampRate(combinedRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
|
public final class TimeDilationManager {
|
||||||
|
private static final Set<ResourceKey<Level>> DILATED_LEVELS = new HashSet<>();
|
||||||
|
|
||||||
|
private TimeDilationManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void tickServer(MinecraftServer server) {
|
||||||
|
for (ServerLevel level : server.getAllLevels()) {
|
||||||
|
List<TimeDilationFieldEntity> fields = collectFields(level);
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
if (DILATED_LEVELS.remove(level.dimension())) {
|
||||||
|
resetRates(level);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DILATED_LEVELS.add(level.dimension());
|
||||||
|
updateEntities(level, fields);
|
||||||
|
TimeDilationParticles.spawnFieldBorders(level, fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<TimeDilationFieldEntity> collectFields(ServerLevel level) {
|
||||||
|
List<TimeDilationFieldEntity> fields = new ArrayList<>();
|
||||||
|
for (Entity entity : level.getAllEntities()) {
|
||||||
|
if (entity instanceof TimeDilationFieldEntity field && field.isAlive()) {
|
||||||
|
fields.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateEntities(ServerLevel level, List<TimeDilationFieldEntity> fields) {
|
||||||
|
for (Entity entity : level.getAllEntities()) {
|
||||||
|
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
double previousRate = access.antarchy$getTimeDilationRate();
|
||||||
|
double rate = TimeDilationFieldSampler.sample(fields, entity.position());
|
||||||
|
access.antarchy$setTimeDilationRate(rate);
|
||||||
|
if (entity instanceof ServerPlayer player && Math.abs(previousRate - rate) > 0.001D) {
|
||||||
|
TimeDilationApi.syncPlayerRate(player, rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resetRates(ServerLevel level) {
|
||||||
|
for (Entity entity : level.getAllEntities()) {
|
||||||
|
if (!(entity instanceof TimeDilationEntityAccess access) || entity instanceof TimeDilationFieldEntity) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (access.antarchy$getTimeDilationRate() >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
access.antarchy$setTimeDilationRate(TimeDilationMath.NORMAL_RATE);
|
||||||
|
if (entity instanceof ServerPlayer player) {
|
||||||
|
TimeDilationApi.syncPlayerRate(player, TimeDilationMath.NORMAL_RATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
public final class TimeDilationMath {
|
||||||
|
public static final double MIN_RATE = 0.05D;
|
||||||
|
public static final double NORMAL_RATE = 1.0D;
|
||||||
|
private static final double GAUSSIAN_EDGE_EXPONENT = -4.5D;
|
||||||
|
|
||||||
|
private TimeDilationMath() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double clampRate(double rate) {
|
||||||
|
if (Double.isNaN(rate) || Double.isInfinite(rate)) {
|
||||||
|
return NORMAL_RATE;
|
||||||
|
}
|
||||||
|
return Math.max(MIN_RATE, Math.min(NORMAL_RATE, rate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double gaussianFalloff(double distance, double radius) {
|
||||||
|
if (distance < 0.0D || distance >= radius || radius <= 0.0D) {
|
||||||
|
return 0.0D;
|
||||||
|
}
|
||||||
|
double normalized = distance / radius;
|
||||||
|
return Math.exp(GAUSSIAN_EDGE_EXPONENT * normalized * normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double localFieldRate(double fieldRate, double falloff) {
|
||||||
|
double clampedRate = clampRate(fieldRate);
|
||||||
|
double clampedFalloff = Math.max(0.0D, Math.min(1.0D, falloff));
|
||||||
|
if (clampedRate <= 0.0D) {
|
||||||
|
return 0.0D;
|
||||||
|
}
|
||||||
|
return Math.pow(clampedRate, clampedFalloff);
|
||||||
|
}
|
||||||
|
}
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
package com.craisinlord.antarchy.content.time;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public final class TimeDilationParticles {
|
||||||
|
private static final int PARTICLE_INTERVAL_TICKS = 4;
|
||||||
|
private static final int MAX_RING_POINTS = 96;
|
||||||
|
|
||||||
|
private TimeDilationParticles() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void spawnFieldBorders(ServerLevel level, List<TimeDilationFieldEntity> fields) {
|
||||||
|
if (level.getGameTime() % PARTICLE_INTERVAL_TICKS != 0L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (TimeDilationFieldEntity field : fields) {
|
||||||
|
spawnBorder(level, field.position(), field.fieldRadius());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void spawnBorder(ServerLevel level, Vec3 center, double radius) {
|
||||||
|
int points = Mth.clamp((int) Math.ceil(radius * 10.0D), 24, MAX_RING_POINTS);
|
||||||
|
double phase = (level.getGameTime() % 80L) * 0.07853981633974483D;
|
||||||
|
|
||||||
|
for (int i = 0; i < points; i++) {
|
||||||
|
double angle = phase + (Math.PI * 2.0D * i / points);
|
||||||
|
double x = center.x + Math.cos(angle) * radius;
|
||||||
|
double z = center.z + Math.sin(angle) * radius;
|
||||||
|
spawnParticle(level, x, center.y, z);
|
||||||
|
|
||||||
|
if (i % 4 == 0) {
|
||||||
|
spawnParticle(level, x, center.y + radius * 0.5D, z);
|
||||||
|
spawnParticle(level, x, center.y - radius * 0.5D, z);
|
||||||
|
}
|
||||||
|
if (i % 8 == 0) {
|
||||||
|
spawnParticle(level, center.x + Math.cos(angle) * radius * 0.7D, center.y + Math.sin(angle) * radius, center.z);
|
||||||
|
spawnParticle(level, center.x, center.y + Math.sin(angle) * radius, center.z + Math.cos(angle) * radius * 0.7D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void spawnParticle(ServerLevel level, double x, double y, double z) {
|
||||||
|
level.sendParticles(ParticleTypes.REVERSE_PORTAL, x, y, z, 1, 0.02D, 0.02D, 0.02D, 0.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
-42
@@ -1,10 +1,8 @@
|
|||||||
package com.craisinlord.antarchy.content.worldgen.thoraxis;
|
package com.craisinlord.antarchy.content.worldgen.thoraxis;
|
||||||
|
|
||||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||||
import com.craisinlord.antarchy.content.entity.portal.DimensionalTearEntity;
|
|
||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
import net.minecraft.server.level.WorldGenRegion;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
@@ -13,15 +11,10 @@ import net.minecraft.world.level.WorldGenLevel;
|
|||||||
import net.minecraft.world.level.levelgen.feature.Feature;
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
||||||
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
|
||||||
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
import net.minecraft.world.level.levelgen.feature.configurations.NoneFeatureConfiguration;
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public final class DimensionalTearFeature extends Feature<NoneFeatureConfiguration> {
|
public final class DimensionalTearFeature extends Feature<NoneFeatureConfiguration> {
|
||||||
private static final int MIN_LINK_RANGE = 50;
|
|
||||||
private static final int MAX_LINK_RANGE = 500;
|
|
||||||
private static final int LOCAL_SEARCH_ATTEMPTS = 18;
|
private static final int LOCAL_SEARCH_ATTEMPTS = 18;
|
||||||
private static final int PARTNER_ORIGIN_ATTEMPTS = 12;
|
|
||||||
private static final int PARTNER_SEARCH_ATTEMPTS = 48;
|
|
||||||
|
|
||||||
public DimensionalTearFeature(Codec<NoneFeatureConfiguration> codec) {
|
public DimensionalTearFeature(Codec<NoneFeatureConfiguration> codec) {
|
||||||
super(codec);
|
super(codec);
|
||||||
@@ -30,46 +23,20 @@ public final class DimensionalTearFeature extends Feature<NoneFeatureConfigurati
|
|||||||
@Override
|
@Override
|
||||||
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
public boolean place(FeaturePlaceContext<NoneFeatureConfiguration> context) {
|
||||||
WorldGenLevel level = context.level();
|
WorldGenLevel level = context.level();
|
||||||
if (!(level instanceof ServerLevelAccessor serverLevelAccessor)) {
|
if (!(level instanceof ServerLevelAccessor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RandomSource random = context.random();
|
RandomSource random = context.random();
|
||||||
BlockPos first = findOpenPocket(level, context.origin(), random, LOCAL_SEARCH_ATTEMPTS);
|
BlockPos anchor = findOpenPocket(level, context.origin(), random, LOCAL_SEARCH_ATTEMPTS);
|
||||||
if (first == null) {
|
if (anchor == null || !canAccess(level, anchor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockPos second = null;
|
level.setBlock(anchor, AntarchyObjects.DIMENSIONAL_TEAR_MARKER.get().defaultBlockState(), 2);
|
||||||
for (int i = 0; i < PARTNER_ORIGIN_ATTEMPTS && second == null; i++) {
|
|
||||||
second = findOpenPocket(level, linkedOrigin(first, random), random, PARTNER_SEARCH_ATTEMPTS);
|
|
||||||
}
|
|
||||||
if (second == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ServerLevel serverLevel = serverLevelAccessor.getLevel();
|
|
||||||
int lifetime = Math.max(1200, AntarchySettings.dimensionalTearLifetimeTicks());
|
|
||||||
float yawA = random.nextFloat() * 360.0F;
|
|
||||||
float yawB = Mth.wrapDegrees(yawA + 140.0F + random.nextFloat() * 80.0F);
|
|
||||||
DimensionalTearEntity tearA = DimensionalTearEntity.create(serverLevel, center(first), yawA, lifetime);
|
|
||||||
DimensionalTearEntity tearB = DimensionalTearEntity.create(serverLevel, center(second), yawB, lifetime);
|
|
||||||
tearA.linkTo(tearB);
|
|
||||||
tearB.linkTo(tearA);
|
|
||||||
serverLevel.addFreshEntity(tearA);
|
|
||||||
serverLevel.addFreshEntity(tearB);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockPos linkedOrigin(BlockPos first, RandomSource random) {
|
|
||||||
double angle = random.nextDouble() * Math.PI * 2.0D;
|
|
||||||
int distance = Mth.nextInt(random, MIN_LINK_RANGE, MAX_LINK_RANGE);
|
|
||||||
int dx = Mth.floor(Math.cos(angle) * distance);
|
|
||||||
int dz = Mth.floor(Math.sin(angle) * distance);
|
|
||||||
int dy = Mth.nextInt(random, -36, 36);
|
|
||||||
return first.offset(dx, dy, dz);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static BlockPos findOpenPocket(WorldGenLevel level, BlockPos origin, RandomSource random, int attempts) {
|
private static BlockPos findOpenPocket(WorldGenLevel level, BlockPos origin, RandomSource random, int attempts) {
|
||||||
int minY = level.getMinBuildHeight() + 8;
|
int minY = level.getMinBuildHeight() + 8;
|
||||||
@@ -105,8 +72,4 @@ public final class DimensionalTearFeature extends Feature<NoneFeatureConfigurati
|
|||||||
private static boolean canAccess(WorldGenLevel level, BlockPos pos) {
|
private static boolean canAccess(WorldGenLevel level, BlockPos pos) {
|
||||||
return !(level instanceof WorldGenRegion region) || region.ensureCanWrite(pos);
|
return !(level instanceof WorldGenRegion region) || region.ensureCanWrite(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Vec3 center(BlockPos pos) {
|
|
||||||
return new Vec3(pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+97
-44
@@ -48,9 +48,13 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
|
|||||||
Map<BlockPos, Direction.Axis> logs = new LinkedHashMap<>();
|
Map<BlockPos, Direction.Axis> logs = new LinkedHashMap<>();
|
||||||
Set<BlockPos> foliage = new LinkedHashSet<>();
|
Set<BlockPos> foliage = new LinkedHashSet<>();
|
||||||
|
|
||||||
placeTrunk(spine, bottomRadius, logs, random);
|
int tierCount = Mth.clamp(2 + branchCount / 2, 3, 5);
|
||||||
|
int outerRadius = 4 + bottomRadius + random.nextInt(3);
|
||||||
|
|
||||||
|
placeTrunk(spine, logs, random);
|
||||||
placeRootWaves(spine, bottomRadius, logs, foliage, random, veilRadius);
|
placeRootWaves(spine, bottomRadius, logs, foliage, random, veilRadius);
|
||||||
placeBranches(spine, branchCount, branchLength, logs, foliage, random, veilRadius);
|
placeChandelierTiers(spine, tierCount, outerRadius, logs, foliage, random, veilRadius);
|
||||||
|
placeBranches(spine, Math.max(1, branchCount / 2), branchLength, logs, foliage, random, veilRadius);
|
||||||
placeVeilCurtains(spine, foliage, random, veilRadius);
|
placeVeilCurtains(spine, foliage, random, veilRadius);
|
||||||
|
|
||||||
if (logs.isEmpty()) {
|
if (logs.isEmpty()) {
|
||||||
@@ -114,38 +118,27 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
|
|||||||
return spine;
|
return spine;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void placeTrunk(List<BlockPos> spine, int bottomRadius, Map<BlockPos, Direction.Axis> logs, RandomSource random) {
|
private void placeTrunk(List<BlockPos> spine, Map<BlockPos, Direction.Axis> logs, RandomSource random) {
|
||||||
for (int index = 0; index < spine.size(); index++) {
|
for (int index = 0; index < spine.size(); index++) {
|
||||||
BlockPos center = spine.get(index);
|
fillTrunkLayer(spine.get(index), index < 2, logs, random);
|
||||||
float progress = spine.size() == 1 ? 1.0F : index / (float) (spine.size() - 1);
|
|
||||||
float wave = Mth.sin(progress * Mth.PI * 2.75F) * 0.55F + Mth.sin(progress * Mth.PI * 5.5F) * 0.25F;
|
|
||||||
int radius = Mth.clamp(Math.round((0.45F + progress * 0.3F + wave * 0.22F) * bottomRadius), 0, Math.max(1, bottomRadius - 1));
|
|
||||||
if (index < 2) {
|
|
||||||
radius = Math.max(radius, 1);
|
|
||||||
}
|
|
||||||
fillTrunkLayer(center, radius, logs, random);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillTrunkLayer(BlockPos center, int radius, Map<BlockPos, Direction.Axis> logs, RandomSource random) {
|
private void fillTrunkLayer(BlockPos center, boolean flare, Map<BlockPos, Direction.Axis> logs, RandomSource random) {
|
||||||
if (radius <= 0) {
|
for (int dx = 0; dx <= 1; dx++) {
|
||||||
putLog(logs, center, Direction.Axis.Y);
|
for (int dz = 0; dz <= 1; dz++) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int radiusSq = radius * radius;
|
|
||||||
for (int dx = -radius; dx <= radius; dx++) {
|
|
||||||
for (int dz = -radius; dz <= radius; dz++) {
|
|
||||||
int dist = dx * dx + dz * dz;
|
|
||||||
if (dist > radiusSq + 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (dist > radiusSq - radius && random.nextFloat() < 0.48F) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
putLog(logs, center.offset(dx, 0, dz), Direction.Axis.Y);
|
putLog(logs, center.offset(dx, 0, dz), Direction.Axis.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (flare) {
|
||||||
|
for (int dx = -1; dx <= 2; dx++) {
|
||||||
|
for (int dz = -1; dz <= 2; dz++) {
|
||||||
|
if ((dx == -1 || dx == 2 || dz == -1 || dz == 2) && random.nextFloat() < 0.5F) {
|
||||||
|
putLog(logs, center.offset(dx, 0, dz), Direction.Axis.Y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void placeRootWaves(
|
private void placeRootWaves(
|
||||||
@@ -231,6 +224,67 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void placeChandelierTiers(
|
||||||
|
List<BlockPos> spine,
|
||||||
|
int tierCount,
|
||||||
|
int outerRadius,
|
||||||
|
Map<BlockPos, Direction.Axis> logs,
|
||||||
|
Set<BlockPos> foliage,
|
||||||
|
RandomSource random,
|
||||||
|
int veilRadius
|
||||||
|
) {
|
||||||
|
int top = Math.max(2, spine.size() / 5);
|
||||||
|
int bottom = Math.max(top + 1, spine.size() - 2);
|
||||||
|
for (int tier = 0; tier < tierCount; tier++) {
|
||||||
|
float progress = tierCount == 1 ? 0.0F : tier / (float) (tierCount - 1);
|
||||||
|
int index = Mth.clamp(Math.round(Mth.lerp(progress, top, bottom)), 0, spine.size() - 1);
|
||||||
|
BlockPos hub = spine.get(index);
|
||||||
|
int radius = Math.max(2, Math.round(Mth.lerp(progress, outerRadius, 2.0F)) + random.nextInt(2));
|
||||||
|
int droop = 1 + random.nextInt(2);
|
||||||
|
BlockPos ringCenter = hub.below(droop);
|
||||||
|
|
||||||
|
placeTierRing(ringCenter, radius, logs, random);
|
||||||
|
placeTierSpokes(hub, ringCenter, radius, logs);
|
||||||
|
|
||||||
|
for (Direction spoke : Direction.Plane.HORIZONTAL) {
|
||||||
|
BlockPos rim = ringCenter.relative(spoke, radius);
|
||||||
|
Direction tangent = spoke.getClockWise();
|
||||||
|
placeVeilRibbon(foliage, rim, tangent, Math.max(2, veilRadius + random.nextInt(2)), random);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void placeTierRing(BlockPos center, int radius, Map<BlockPos, Direction.Axis> logs, RandomSource random) {
|
||||||
|
int outerSq = (radius + 1) * (radius + 1);
|
||||||
|
int innerSq = (radius - 1) * (radius - 1);
|
||||||
|
for (int dx = -radius - 1; dx <= radius + 1; dx++) {
|
||||||
|
for (int dz = -radius - 1; dz <= radius + 1; dz++) {
|
||||||
|
int distSq = dx * dx + dz * dz;
|
||||||
|
if (distSq > outerSq || distSq < innerSq) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (random.nextFloat() < 0.12F) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Direction.Axis axis = Math.abs(dx) >= Math.abs(dz) ? Direction.Axis.X : Direction.Axis.Z;
|
||||||
|
putLog(logs, center.offset(dx, 0, dz), axis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void placeTierSpokes(BlockPos hub, BlockPos ringCenter, int radius, Map<BlockPos, Direction.Axis> logs) {
|
||||||
|
for (Direction spoke : Direction.Plane.HORIZONTAL) {
|
||||||
|
BlockPos previous = hub;
|
||||||
|
for (int step = 1; step <= radius; step++) {
|
||||||
|
float t = step / (float) radius;
|
||||||
|
int y = Math.round(Mth.lerp(t, hub.getY(), ringCenter.getY()));
|
||||||
|
BlockPos next = new BlockPos(hub.getX() + spoke.getStepX() * step, y, hub.getZ() + spoke.getStepZ() * step);
|
||||||
|
putLog(logs, next, axisForSegment(previous, next));
|
||||||
|
previous = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void placeVeilCurtains(List<BlockPos> spine, Set<BlockPos> foliage, RandomSource random, int veilRadius) {
|
private void placeVeilCurtains(List<BlockPos> spine, Set<BlockPos> foliage, RandomSource random, int veilRadius) {
|
||||||
for (int index = 1; index < spine.size(); index++) {
|
for (int index = 1; index < spine.size(); index++) {
|
||||||
if (random.nextFloat() > 0.24F) {
|
if (random.nextFloat() > 0.24F) {
|
||||||
@@ -244,23 +298,22 @@ public class NadirTreeFeature extends Feature<NadirTreeConfiguration> {
|
|||||||
|
|
||||||
private void placeVeilRibbon(Set<BlockPos> foliage, BlockPos start, Direction flow, int length, RandomSource random) {
|
private void placeVeilRibbon(Set<BlockPos> foliage, BlockPos start, Direction flow, int length, RandomSource random) {
|
||||||
Direction side = random.nextBoolean() ? flow.getClockWise() : flow.getCounterClockWise();
|
Direction side = random.nextBoolean() ? flow.getClockWise() : flow.getCounterClockWise();
|
||||||
BlockPos cursor = start;
|
int span = Math.max(4, length + 2);
|
||||||
for (int step = 0; step < length; step++) {
|
int bands = 1 + random.nextInt(2);
|
||||||
foliage.add(cursor);
|
float phase = random.nextFloat() * Mth.PI * 2.0F;
|
||||||
if (random.nextFloat() < 0.34F) {
|
float frequency = 0.55F + random.nextFloat() * 0.45F;
|
||||||
foliage.add(cursor.relative(side));
|
for (int band = 0; band < bands; band++) {
|
||||||
}
|
BlockPos rowAnchor = start.relative(side, band);
|
||||||
if (random.nextFloat() < 0.18F) {
|
float bandPhase = phase + band * 1.7F;
|
||||||
foliage.add(cursor.relative(side.getOpposite()));
|
for (int step = 0; step < span; step++) {
|
||||||
}
|
float wave = Mth.sin(step * frequency + bandPhase);
|
||||||
cursor = cursor.below();
|
int lift = Math.round(wave * 1.5F);
|
||||||
if (step > 0 && random.nextFloat() < 0.4F) {
|
BlockPos top = rowAnchor.relative(flow, step).offset(0, lift, 0);
|
||||||
cursor = cursor.relative(random.nextBoolean() ? side : side.getOpposite());
|
int strand = Math.max(2, 3 + Math.round((wave + 1.0F) * 2.0F) + random.nextInt(2) - (1 + random.nextInt(3)));
|
||||||
}
|
BlockPos cursor = top;
|
||||||
if (random.nextFloat() < 0.18F) {
|
for (int drop = 0; drop < strand; drop++) {
|
||||||
BlockPos drift = cursor.relative(flow);
|
foliage.add(cursor);
|
||||||
if (random.nextBoolean()) {
|
cursor = cursor.below();
|
||||||
foliage.add(drift);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-4
@@ -26,18 +26,22 @@ public final class ThoraxisUndersideManager {
|
|||||||
private static final ResourceLocation THORAXIS_DIMENSION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis");
|
private static final ResourceLocation THORAXIS_DIMENSION = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "thoraxis");
|
||||||
private static final AntarchyGravityTransition TRANSITION = new AntarchyGravityTransition(12);
|
private static final AntarchyGravityTransition TRANSITION = new AntarchyGravityTransition(12);
|
||||||
private static final int EFFECT_DURATION_TICKS = 40;
|
private static final int EFFECT_DURATION_TICKS = 40;
|
||||||
|
private static final int MAX_FLIPS_PER_TICK = 8;
|
||||||
private static final Set<UUID> UNDERSIDE_APPLIED_EFFECT = new HashSet<>();
|
private static final Set<UUID> UNDERSIDE_APPLIED_EFFECT = new HashSet<>();
|
||||||
private static final Set<UUID> UNDERSIDE_FORCED_GRAVITY = new HashSet<>();
|
private static final Set<UUID> UNDERSIDE_FORCED_GRAVITY = new HashSet<>();
|
||||||
|
private static final Set<UUID> ACTIVE_ITEMS_SCRATCH = new HashSet<>();
|
||||||
|
|
||||||
private ThoraxisUndersideManager() {
|
private ThoraxisUndersideManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void tick(ServerLevel level) {
|
public static void tick(ServerLevel level) {
|
||||||
if (!isThoraxis(level)) {
|
if (!isThoraxis(level) || level.players().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<UUID> activeThisTick = new HashSet<>();
|
Set<UUID> activeThisTick = ACTIVE_ITEMS_SCRATCH;
|
||||||
|
activeThisTick.clear();
|
||||||
|
int flipsRemaining = MAX_FLIPS_PER_TICK;
|
||||||
for (Entity entity : level.getAllEntities()) {
|
for (Entity entity : level.getAllEntities()) {
|
||||||
if (!entity.isAlive() || entity.isSpectator()) {
|
if (!entity.isAlive() || entity.isSpectator()) {
|
||||||
continue;
|
continue;
|
||||||
@@ -48,6 +52,14 @@ public final class ThoraxisUndersideManager {
|
|||||||
if (entity instanceof LivingEntity living) {
|
if (entity instanceof LivingEntity living) {
|
||||||
UUID uuid = entity.getUUID();
|
UUID uuid = entity.getUUID();
|
||||||
if (inUnderside) {
|
if (inUnderside) {
|
||||||
|
boolean needsFlip = AntarchyGravityApi.getGravityDirection(living) != AntarchyGravityDirection.UP
|
||||||
|
|| !AntarchyGravityApi.isGravityForced(living);
|
||||||
|
if (needsFlip && flipsRemaining <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (needsFlip) {
|
||||||
|
flipsRemaining--;
|
||||||
|
}
|
||||||
applyUndersideInversion(living);
|
applyUndersideInversion(living);
|
||||||
} else if (UNDERSIDE_APPLIED_EFFECT.remove(uuid)) {
|
} else if (UNDERSIDE_APPLIED_EFFECT.remove(uuid)) {
|
||||||
if (living.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
|
if (living.hasEffect(AntarchyObjects.INVERTED_EFFECT.get())) {
|
||||||
@@ -67,10 +79,15 @@ public final class ThoraxisUndersideManager {
|
|||||||
|
|
||||||
UUID uuid = entity.getUUID();
|
UUID uuid = entity.getUUID();
|
||||||
if (inUnderside) {
|
if (inUnderside) {
|
||||||
|
boolean needsFlip = AntarchyGravityApi.getGravityDirection(entity) != AntarchyGravityDirection.UP
|
||||||
|
|| !AntarchyGravityApi.isGravityForced(entity);
|
||||||
|
if (needsFlip && flipsRemaining <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
activeThisTick.add(uuid);
|
activeThisTick.add(uuid);
|
||||||
UNDERSIDE_FORCED_GRAVITY.add(uuid);
|
UNDERSIDE_FORCED_GRAVITY.add(uuid);
|
||||||
if (AntarchyGravityApi.getGravityDirection(entity) != AntarchyGravityDirection.UP
|
if (needsFlip) {
|
||||||
|| !AntarchyGravityApi.isGravityForced(entity)) {
|
flipsRemaining--;
|
||||||
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, TRANSITION);
|
AntarchyGravityApi.setForcedGravityDirection(entity, AntarchyGravityDirection.UP, TRANSITION);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
+1
-1
@@ -38,6 +38,6 @@ public abstract class CustomBossBarMixin {
|
|||||||
|
|
||||||
@ModifyConstant(method = "render", constant = @Constant(intValue = 9, ordinal = 1))
|
@ModifyConstant(method = "render", constant = @Constant(intValue = 9, ordinal = 1))
|
||||||
private int antarchy$doubleGapForCustomBossBar(int original, @Local LerpingBossEvent bossEvent) {
|
private int antarchy$doubleGapForCustomBossBar(int original, @Local LerpingBossEvent bossEvent) {
|
||||||
return CustomBossBarRenderer.isCustomBoss(bossEvent) ? original + 19 : original;
|
return CustomBossBarRenderer.isCustomBoss(bossEvent) ? original + 30 : original;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationEntityAccess;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class EntityDeltaMovementTimeDilationMixin {
|
||||||
|
@ModifyVariable(method = "setDeltaMovement(Lnet/minecraft/world/phys/Vec3;)V", at = @At("HEAD"), argsOnly = true, ordinal = 0)
|
||||||
|
private Vec3 antarchy$scaleTimeDilatedVelocityChange(Vec3 nextMovement) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (!(entity instanceof TimeDilationEntityAccess access)
|
||||||
|
|| access.antarchy$isInTimeDilationMove()) {
|
||||||
|
return nextMovement;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rate = TimeDilationApi.getRate(entity);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return nextMovement;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 currentMovement = entity.getDeltaMovement();
|
||||||
|
double y = currentMovement.y + (nextMovement.y - currentMovement.y) * rate;
|
||||||
|
if (nextMovement.y > currentMovement.y && nextMovement.y > 0.0D && (entity.onGround() || currentMovement.y <= 0.0D)) {
|
||||||
|
y = nextMovement.y;
|
||||||
|
}
|
||||||
|
return new Vec3(
|
||||||
|
currentMovement.x + (nextMovement.x - currentMovement.x) * rate,
|
||||||
|
y,
|
||||||
|
currentMovement.z + (nextMovement.z - currentMovement.z) * rate
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationEntityAccess;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.MoverType;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class EntityMoveTimeDilationMixin {
|
||||||
|
@Inject(method = "move", at = @At("HEAD"))
|
||||||
|
private void antarchy$beginTimeDilationMove(MoverType moverType, Vec3 movement, CallbackInfo ci) {
|
||||||
|
if (this instanceof TimeDilationEntityAccess access) {
|
||||||
|
access.antarchy$setInTimeDilationMove(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "move", at = @At("RETURN"))
|
||||||
|
private void antarchy$endTimeDilationMove(MoverType moverType, Vec3 movement, CallbackInfo ci) {
|
||||||
|
if (this instanceof TimeDilationEntityAccess access) {
|
||||||
|
access.antarchy$setInTimeDilationMove(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModifyVariable(method = "move", at = @At("HEAD"), argsOnly = true, ordinal = 0)
|
||||||
|
private Vec3 antarchy$scaleTimeDilatedMovement(Vec3 movement) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
double rate = TimeDilationApi.getRate(entity);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return movement;
|
||||||
|
}
|
||||||
|
return movement.scale(rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationEntityAccess;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class EntityTimeDilationStateMixin implements TimeDilationEntityAccess {
|
||||||
|
@Unique
|
||||||
|
private double antarchy$timeDilationRate = TimeDilationMath.NORMAL_RATE;
|
||||||
|
@Unique
|
||||||
|
private final Map<String, Double> antarchy$timeDilationTimerProgress = new HashMap<>();
|
||||||
|
@Unique
|
||||||
|
private boolean antarchy$inTimeDilationMove;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double antarchy$getTimeDilationRate() {
|
||||||
|
return this.antarchy$timeDilationRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void antarchy$setTimeDilationRate(double rate) {
|
||||||
|
this.antarchy$timeDilationRate = TimeDilationMath.clampRate(rate);
|
||||||
|
if (this.antarchy$timeDilationRate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
this.antarchy$timeDilationTimerProgress.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean antarchy$consumeTimeDilationTick(String timerKey, double rate) {
|
||||||
|
double clampedRate = TimeDilationMath.clampRate(rate);
|
||||||
|
if (clampedRate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
double progress = this.antarchy$timeDilationTimerProgress.getOrDefault(timerKey, 0.0D) + clampedRate;
|
||||||
|
int wholeTicks = (int) Math.floor(progress + 1.0E-9D);
|
||||||
|
if (wholeTicks <= 0) {
|
||||||
|
this.antarchy$timeDilationTimerProgress.put(timerKey, progress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.antarchy$timeDilationTimerProgress.put(timerKey, progress - wholeTicks);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean antarchy$isInTimeDilationMove() {
|
||||||
|
return this.antarchy$inTimeDilationMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void antarchy$setInTimeDilationMove(boolean inMove) {
|
||||||
|
this.antarchy$inTimeDilationMove = inMove;
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker;
|
||||||
|
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||||
|
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
@Mixin(LivingEntityRenderer.class)
|
||||||
|
public abstract class LivingEntityRendererAnimationTimeDilationMixin {
|
||||||
|
@ModifyReturnValue(method = "getBob", at = @At("RETURN"))
|
||||||
|
private float antarchy$slowIdleAnimation(float bob, LivingEntity entity, float partialTick) {
|
||||||
|
return ClientTimeDilationTicker.dilateAnimationTime(entity, bob);
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(LivingEntity.class)
|
||||||
|
public abstract class LivingEntityTimeDilationMixin {
|
||||||
|
@Inject(method = "updateSwingTime", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowSwingTime(CallbackInfo ci) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (!TimeDilationApi.consumeTick(entity, "living_swing")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tickEffects", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowEffectTicks(CallbackInfo ci) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (!TimeDilationApi.consumeTick(entity, "living_effects")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "updatingUsingItem", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowUsingItem(CallbackInfo ci) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (!TimeDilationApi.consumeTick(entity, "living_using_item")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "swing(Lnet/minecraft/world/InteractionHand;Z)V", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowSwingStart(InteractionHand hand, boolean updateSelf, CallbackInfo ci) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (!TimeDilationApi.consumeTick(entity, "living_swing_start")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "updateUsingItem", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowItemUseProgress(ItemStack stack, CallbackInfo ci) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (!TimeDilationApi.consumeTick(entity, "living_item_use_progress")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.ai.control.LookControl;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
@Mixin(LookControl.class)
|
||||||
|
public abstract class LookControlTimeDilationMixin {
|
||||||
|
@Shadow
|
||||||
|
protected Mob mob;
|
||||||
|
|
||||||
|
@ModifyReturnValue(method = "rotateTowards", at = @At("RETURN"))
|
||||||
|
private float antarchy$slowLookTurn(float result, float from, float to, float maxAngle) {
|
||||||
|
double rate = TimeDilationApi.getRate(this.mob);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return from + (float) (Mth.wrapDegrees(result - from) * rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
+26
@@ -0,0 +1,26 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import net.minecraft.world.entity.PathfinderMob;
|
||||||
|
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(MeleeAttackGoal.class)
|
||||||
|
public abstract class MeleeAttackGoalTimeDilationMixin {
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
protected PathfinderMob mob;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private int ticksUntilNextAttack;
|
||||||
|
|
||||||
|
@Inject(method = "resetAttackCooldown", at = @At("RETURN"))
|
||||||
|
private void antarchy$scaleMeleeCooldown(CallbackInfo ci) {
|
||||||
|
this.ticksUntilNextAttack = TimeDilationApi.scaleCooldownTicks(this.mob, this.ticksUntilNextAttack);
|
||||||
|
}
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(Mob.class)
|
||||||
|
public abstract class MobAttackTimeDilationMixin {
|
||||||
|
@Unique
|
||||||
|
private long antarchy$nextAttackTick = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
@Inject(method = "doHurtTarget", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$rateLimitAttack(Entity target, CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
Mob mob = (Mob) (Object) this;
|
||||||
|
if (mob.level().isClientSide) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double rate = TimeDilationApi.getRate(mob);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long now = mob.level().getGameTime();
|
||||||
|
if (now < this.antarchy$nextAttackTick) {
|
||||||
|
cir.setReturnValue(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.antarchy$nextAttackTick = now + TimeDilationApi.scaleCooldownTicks(mob, 20);
|
||||||
|
}
|
||||||
|
}
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import net.minecraft.client.particle.Particle;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.ModifyArgs;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.invoke.arg.Args;
|
||||||
|
|
||||||
|
@Mixin(Particle.class)
|
||||||
|
public abstract class ParticleTimeDilationMixin {
|
||||||
|
@Shadow
|
||||||
|
protected int age;
|
||||||
|
@Shadow
|
||||||
|
protected double x;
|
||||||
|
@Shadow
|
||||||
|
protected double y;
|
||||||
|
@Shadow
|
||||||
|
protected double z;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private double antarchy$ageProgress;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private double antarchy$sampleRate() {
|
||||||
|
return ClientTimeDilationTicker.rateAt(this.x, this.y, this.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ModifyArgs(
|
||||||
|
method = "tick",
|
||||||
|
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/particle/Particle;move(DDD)V")
|
||||||
|
)
|
||||||
|
private void antarchy$slowParticleMovement(Args args) {
|
||||||
|
double rate = this.antarchy$sampleRate();
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
args.set(0, (Double) args.get(0) * rate);
|
||||||
|
args.set(1, (Double) args.get(1) * rate);
|
||||||
|
args.set(2, (Double) args.get(2) * rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Redirect(
|
||||||
|
method = "tick",
|
||||||
|
at = @At(value = "FIELD", target = "Lnet/minecraft/client/particle/Particle;age:I", opcode = Opcodes.PUTFIELD)
|
||||||
|
)
|
||||||
|
private void antarchy$slowParticleAge(Particle self, int nextAge) {
|
||||||
|
double rate = this.antarchy$sampleRate();
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
this.age = nextAge;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.antarchy$ageProgress += rate;
|
||||||
|
if (this.antarchy$ageProgress >= 1.0D) {
|
||||||
|
this.antarchy$ageProgress -= 1.0D;
|
||||||
|
this.age = nextAge;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
|
||||||
|
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
||||||
|
import net.minecraft.world.entity.item.PrimedTnt;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
@Mixin(PrimedTnt.class)
|
||||||
|
public abstract class PrimedTntTimeDilationMixin {
|
||||||
|
@WrapOperation(
|
||||||
|
method = "tick",
|
||||||
|
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/item/PrimedTnt;setFuse(I)V")
|
||||||
|
)
|
||||||
|
private void antarchy$slowFuse(PrimedTnt tnt, int fuse, Operation<Void> original) {
|
||||||
|
if (TimeDilationApi.consumeTick(tnt, "primed_tnt_fuse")) {
|
||||||
|
original.call(tnt, fuse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||||
|
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||||
|
import net.minecraft.world.entity.projectile.ThrowableProjectile;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin({AbstractArrow.class, ThrowableProjectile.class, AbstractHurtingProjectile.class})
|
||||||
|
public abstract class ProjectileMovementTimeDilationMixin {
|
||||||
|
@Unique
|
||||||
|
private Vec3 antarchy$preTickPos;
|
||||||
|
@Unique
|
||||||
|
private Vec3 antarchy$preTickDelta;
|
||||||
|
|
||||||
|
@Inject(method = "tick", at = @At("HEAD"))
|
||||||
|
private void antarchy$recordPreTickMotion(CallbackInfo ci) {
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (TimeDilationApi.getRate(entity) < TimeDilationMath.NORMAL_RATE) {
|
||||||
|
this.antarchy$preTickPos = entity.position();
|
||||||
|
this.antarchy$preTickDelta = entity.getDeltaMovement();
|
||||||
|
} else {
|
||||||
|
this.antarchy$preTickPos = null;
|
||||||
|
this.antarchy$preTickDelta = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tick", at = @At("RETURN"))
|
||||||
|
private void antarchy$scaleTickDisplacement(CallbackInfo ci) {
|
||||||
|
Vec3 pre = this.antarchy$preTickPos;
|
||||||
|
Vec3 preDelta = this.antarchy$preTickDelta;
|
||||||
|
this.antarchy$preTickPos = null;
|
||||||
|
this.antarchy$preTickDelta = null;
|
||||||
|
if (pre == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity entity = (Entity) (Object) this;
|
||||||
|
if (entity.isRemoved()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double rate = TimeDilationApi.getRate(entity);
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 actual = entity.position().subtract(pre);
|
||||||
|
if (actual.lengthSqr() < 1.0E-12D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (preDelta != null && actual.lengthSqr() + 1.0E-9D < preDelta.lengthSqr()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3 lerped = pre.add(actual.scale(rate));
|
||||||
|
entity.setPos(lerped.x, lerped.y, lerped.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.ai.goal.RangedAttackGoal;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(RangedAttackGoal.class)
|
||||||
|
public abstract class RangedAttackGoalTimeDilationMixin {
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private Mob mob;
|
||||||
|
|
||||||
|
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowRangedGoalTick(CallbackInfo ci) {
|
||||||
|
if (!TimeDilationApi.consumeTick(this.mob, "ranged_goal_tick")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationApi;
|
||||||
|
import net.minecraft.world.entity.Mob;
|
||||||
|
import net.minecraft.world.entity.ai.goal.RangedBowAttackGoal;
|
||||||
|
import net.minecraft.world.entity.monster.Monster;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(RangedBowAttackGoal.class)
|
||||||
|
public abstract class RangedBowAttackGoalTimeDilationMixin {
|
||||||
|
@Unique
|
||||||
|
private Mob antarchy$timeDilationMob;
|
||||||
|
|
||||||
|
@Inject(method = "<init>(Lnet/minecraft/world/entity/monster/Monster;DIF)V", at = @At("RETURN"))
|
||||||
|
private void antarchy$captureMob(Monster mob, double speedModifier, int attackIntervalMin, float attackRadius, CallbackInfo ci) {
|
||||||
|
this.antarchy$timeDilationMob = mob;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void antarchy$slowRangedBowGoalTick(CallbackInfo ci) {
|
||||||
|
if (this.antarchy$timeDilationMob != null && !TimeDilationApi.consumeTick(this.antarchy$timeDilationMob, "ranged_bow_goal_tick")) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
package com.craisinlord.antarchy.mixins.time;
|
||||||
|
|
||||||
|
import com.craisinlord.antarchy.content.client.ClientTimeDilationTicker;
|
||||||
|
import com.craisinlord.antarchy.content.time.TimeDilationMath;
|
||||||
|
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||||
|
import net.minecraft.client.resources.sounds.SoundInstance;
|
||||||
|
import net.minecraft.client.sounds.SoundEngine;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
|
||||||
|
@Mixin(SoundEngine.class)
|
||||||
|
public abstract class SoundEngineTimeDilationMixin {
|
||||||
|
@ModifyReturnValue(method = "calculatePitch", at = @At("RETURN"))
|
||||||
|
private float antarchy$dilatePitch(float pitch, SoundInstance sound) {
|
||||||
|
double rate = ClientTimeDilationTicker.rateAt(sound.getX(), sound.getY(), sound.getZ());
|
||||||
|
if (rate >= TimeDilationMath.NORMAL_RATE) {
|
||||||
|
return pitch;
|
||||||
|
}
|
||||||
|
return (float) (pitch * Math.max(TimeDilationMath.MIN_RATE, rate));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,7 +78,18 @@
|
|||||||
"gravity.ServerPlayerGravityMixin",
|
"gravity.ServerPlayerGravityMixin",
|
||||||
"gravity.ThrowableProjectileGravityMixin",
|
"gravity.ThrowableProjectileGravityMixin",
|
||||||
"gravity.TrackedEntityAccessor",
|
"gravity.TrackedEntityAccessor",
|
||||||
"multipart.EntityMultipartLifecycleMixin"
|
"multipart.EntityMultipartLifecycleMixin",
|
||||||
|
"time.EntityDeltaMovementTimeDilationMixin",
|
||||||
|
"time.EntityMoveTimeDilationMixin",
|
||||||
|
"time.EntityTimeDilationStateMixin",
|
||||||
|
"time.LivingEntityTimeDilationMixin",
|
||||||
|
"time.LookControlTimeDilationMixin",
|
||||||
|
"time.MeleeAttackGoalTimeDilationMixin",
|
||||||
|
"time.MobAttackTimeDilationMixin",
|
||||||
|
"time.PrimedTntTimeDilationMixin",
|
||||||
|
"time.ProjectileMovementTimeDilationMixin",
|
||||||
|
"time.RangedAttackGoalTimeDilationMixin",
|
||||||
|
"time.RangedBowAttackGoalTimeDilationMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"client.AbstractMinecartRendererMixin",
|
"client.AbstractMinecartRendererMixin",
|
||||||
@@ -110,7 +121,10 @@
|
|||||||
"gravity.client.CameraGravityMixin",
|
"gravity.client.CameraGravityMixin",
|
||||||
"gravity.client.ClientPacketListenerGravityMixin",
|
"gravity.client.ClientPacketListenerGravityMixin",
|
||||||
"gravity.client.EntityRenderDispatcherGravityMixin",
|
"gravity.client.EntityRenderDispatcherGravityMixin",
|
||||||
"gravity.client.FallingBlockRendererBlockEntityMixin"
|
"gravity.client.FallingBlockRendererBlockEntityMixin",
|
||||||
|
"time.LivingEntityRendererAnimationTimeDilationMixin",
|
||||||
|
"time.ParticleTimeDilationMixin",
|
||||||
|
"time.SoundEngineTimeDilationMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
"defaultRequire": 1
|
"defaultRequire": 1
|
||||||
|
|||||||
+3903
File diff suppressed because it is too large.
Load diff
@@ -1,16 +1,33 @@
|
|||||||
{
|
{
|
||||||
"variants": {
|
"variants": {
|
||||||
"facing=up,powered=false": { "model": "antarchy:block/vortex_lens" },
|
"facing=up,powered=false,pushing=false": { "model": "antarchy:block/vortex_lens" },
|
||||||
"facing=up,powered=true": { "model": "antarchy:block/vortex_lens_on" },
|
"facing=up,powered=false,pushing=true": { "model": "antarchy:block/vortex_lens" },
|
||||||
"facing=down,powered=false": { "model": "antarchy:block/vortex_lens", "x": 180 },
|
"facing=up,powered=true,pushing=false": { "model": "antarchy:block/vortex_lens_on" },
|
||||||
"facing=down,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 180 },
|
"facing=up,powered=true,pushing=true": { "model": "antarchy:block/vortex_lens_on_bluestone" },
|
||||||
"facing=north,powered=false": { "model": "antarchy:block/vortex_lens", "x": 90 },
|
|
||||||
"facing=north,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 90 },
|
"facing=down,powered=false,pushing=false": { "model": "antarchy:block/vortex_lens", "x": 180 },
|
||||||
"facing=south,powered=false": { "model": "antarchy:block/vortex_lens", "x": 270 },
|
"facing=down,powered=false,pushing=true": { "model": "antarchy:block/vortex_lens", "x": 180 },
|
||||||
"facing=south,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 270 },
|
"facing=down,powered=true,pushing=false": { "model": "antarchy:block/vortex_lens_on", "x": 180 },
|
||||||
"facing=west,powered=false": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 270 },
|
"facing=down,powered=true,pushing=true": { "model": "antarchy:block/vortex_lens_on_bluestone", "x": 180 },
|
||||||
"facing=west,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 90, "y": 270 },
|
|
||||||
"facing=east,powered=false": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 90 },
|
"facing=north,powered=false,pushing=false": { "model": "antarchy:block/vortex_lens", "x": 90 },
|
||||||
"facing=east,powered=true": { "model": "antarchy:block/vortex_lens_on", "x": 90, "y": 90 }
|
"facing=north,powered=false,pushing=true": { "model": "antarchy:block/vortex_lens", "x": 90 },
|
||||||
|
"facing=north,powered=true,pushing=false": { "model": "antarchy:block/vortex_lens_on", "x": 90 },
|
||||||
|
"facing=north,powered=true,pushing=true": { "model": "antarchy:block/vortex_lens_on_bluestone", "x": 90 },
|
||||||
|
|
||||||
|
"facing=south,powered=false,pushing=false": { "model": "antarchy:block/vortex_lens", "x": 270 },
|
||||||
|
"facing=south,powered=false,pushing=true": { "model": "antarchy:block/vortex_lens", "x": 270 },
|
||||||
|
"facing=south,powered=true,pushing=false": { "model": "antarchy:block/vortex_lens_on", "x": 270 },
|
||||||
|
"facing=south,powered=true,pushing=true": { "model": "antarchy:block/vortex_lens_on_bluestone", "x": 270 },
|
||||||
|
|
||||||
|
"facing=west,powered=false,pushing=false": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 270 },
|
||||||
|
"facing=west,powered=false,pushing=true": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 270 },
|
||||||
|
"facing=west,powered=true,pushing=false": { "model": "antarchy:block/vortex_lens_on", "x": 90, "y": 270 },
|
||||||
|
"facing=west,powered=true,pushing=true": { "model": "antarchy:block/vortex_lens_on_bluestone", "x": 90, "y": 270 },
|
||||||
|
|
||||||
|
"facing=east,powered=false,pushing=false": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 90 },
|
||||||
|
"facing=east,powered=false,pushing=true": { "model": "antarchy:block/vortex_lens", "x": 90, "y": 90 },
|
||||||
|
"facing=east,powered=true,pushing=false": { "model": "antarchy:block/vortex_lens_on", "x": 90, "y": 90 },
|
||||||
|
"facing=east,powered=true,pushing=true": { "model": "antarchy:block/vortex_lens_on_bluestone", "x": 90, "y": 90 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
{
|
||||||
|
"format_version": "1.12.0",
|
||||||
|
"minecraft:geometry": [
|
||||||
|
{
|
||||||
|
"description": {
|
||||||
|
"identifier": "geometry.unknown",
|
||||||
|
"texture_width": 256,
|
||||||
|
"texture_height": 256,
|
||||||
|
"visible_bounds_width": 12,
|
||||||
|
"visible_bounds_height": 5.5,
|
||||||
|
"visible_bounds_offset": [0, 2.25, 0]
|
||||||
|
},
|
||||||
|
"bones": [
|
||||||
|
{
|
||||||
|
"name": "Menticore",
|
||||||
|
"pivot": [0, 0, 0]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "body",
|
||||||
|
"parent": "Menticore",
|
||||||
|
"pivot": [0, 17, 2.7]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "back_leg_right",
|
||||||
|
"parent": "body",
|
||||||
|
"pivot": [-7.5, 17, 13.75],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-11, 10, 7], "size": [7, 11, 5], "uv": [95, 26], "mirror": true},
|
||||||
|
{"origin": [-11, 0, 12], "size": [7, 21, 8], "uv": [46, 83], "mirror": true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "back_leg_left",
|
||||||
|
"parent": "body",
|
||||||
|
"pivot": [7.5, 17, 13.75],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [4, 10, 7], "size": [7, 11, 5], "uv": [95, 26]},
|
||||||
|
{"origin": [4, 0, 12], "size": [7, 21, 8], "uv": [46, 83]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "left_leg",
|
||||||
|
"parent": "body",
|
||||||
|
"pivot": [7.5, 17.5, -9],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [4, 0, -13], "size": [7, 21, 8], "uv": [16, 83]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "right_leg",
|
||||||
|
"parent": "body",
|
||||||
|
"pivot": [-7.5, 17.5, -9],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-11, 0, -13], "size": [7, 21, 8], "uv": [16, 83], "mirror": true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "torso",
|
||||||
|
"parent": "body",
|
||||||
|
"pivot": [0, 27, 3],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-8.5, 12, -15], "size": [17, 22, 22], "uv": [0, 0]},
|
||||||
|
{"origin": [-8.5, 16, 7], "size": [17, 18, 14], "uv": [76, 44]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "head",
|
||||||
|
"parent": "torso",
|
||||||
|
"pivot": [0, 27, -7.025],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-2.85, 31, -27.025], "size": [1, 1, 0], "uv": [76, 76]},
|
||||||
|
{"origin": [-10.5, 18, -9], "size": [21, 22, 6], "uv": [0, 151]},
|
||||||
|
{"origin": [-11.5, 17, -22], "size": [23, 24, 15], "uv": [0, 44]},
|
||||||
|
{"origin": [-5, 24, -32.5], "size": [10, 6, 6], "uv": [78, 0]},
|
||||||
|
{"origin": [-5, 18, -32.25], "size": [2, 6, 3], "uv": [78, 27]},
|
||||||
|
{"origin": [3, 18, -32.25], "size": [2, 6, 3], "uv": [0, 83]},
|
||||||
|
{"origin": [-7.5, 22, -27], "size": [15, 14, 8], "uv": [76, 76]},
|
||||||
|
{"origin": [3.025, 31, -27.025], "size": [1, 1, 0], "uv": [76, 76], "mirror": true},
|
||||||
|
{"origin": [-11.499, 17, -7], "size": [0, 24, 2], "uv": [12, 81]},
|
||||||
|
{"origin": [11.499, 17, -7], "size": [0, 24, 2], "uv": [12, 81], "mirror": true},
|
||||||
|
{"origin": [-11.5, 41, -7], "size": [23, 0, 2], "uv": [76, 42]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "jaw",
|
||||||
|
"parent": "head",
|
||||||
|
"pivot": [0, 24, -27],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-4, 22, -32], "size": [8, 2, 5], "uv": [78, 12]},
|
||||||
|
{"origin": [-3, 19, -32], "size": [6, 3, 5], "uv": [78, 19]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "right_wing",
|
||||||
|
"parent": "torso",
|
||||||
|
"pivot": [-8.75, 26.375, -1],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-12.5, 25, -3], "size": [4, 17, 4], "uv": [56, 1], "mirror": true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "right_wing2",
|
||||||
|
"parent": "right_wing",
|
||||||
|
"pivot": [-12.5, 40.5, -1],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-34.5, 25, -1], "size": [22, 39, 0], "uv": [0, 112], "mirror": true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "right_wing3",
|
||||||
|
"parent": "right_wing2",
|
||||||
|
"pivot": [-34.5, 44.5, -1],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-72.5, 25, -1], "size": [38, 39, 0], "uv": [44, 112], "mirror": true}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "left_wing",
|
||||||
|
"parent": "torso",
|
||||||
|
"pivot": [8.75, 26.375, -1],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [8.5, 25, -3], "size": [4, 17, 4], "uv": [56, 1]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "left_wing2",
|
||||||
|
"parent": "left_wing",
|
||||||
|
"pivot": [12.5, 40.5, -1],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [12.5, 25, -1], "size": [22, 39, 0], "uv": [0, 112]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "left_wing3",
|
||||||
|
"parent": "left_wing2",
|
||||||
|
"pivot": [34.5, 44.5, -1],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [34.5, 25, -1], "size": [38, 39, 0], "uv": [44, 112]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tail",
|
||||||
|
"parent": "torso",
|
||||||
|
"pivot": [0, 29, 21],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-3.5, 27, 21], "size": [7, 7, 14], "uv": [54, 151]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tail2",
|
||||||
|
"parent": "tail",
|
||||||
|
"pivot": [0, 27, 35],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-4.5, 27, 35], "size": [9, 7, 23], "uv": [99, 81]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tail3",
|
||||||
|
"parent": "tail2",
|
||||||
|
"pivot": [0, 27, 58],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-3.5, 27, 58], "size": [7, 7, 23], "uv": [114, 0]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sting",
|
||||||
|
"parent": "tail3",
|
||||||
|
"pivot": [0, 34, 75],
|
||||||
|
"cubes": [
|
||||||
|
{"origin": [-3.5, 34, 69], "size": [7, 10, 12], "inflate": 0.01, "uv": [124, 34]},
|
||||||
|
{"origin": [-0.5, 44, 69], "size": [0, 10, 6], "uv": [124, 30]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -236,6 +236,7 @@
|
|||||||
"block.antarchy.bluestone_ore": "Bluestone Ore",
|
"block.antarchy.bluestone_ore": "Bluestone Ore",
|
||||||
"block.antarchy.bluestone_block": "Bluestone Block",
|
"block.antarchy.bluestone_block": "Bluestone Block",
|
||||||
"block.antarchy.vortex_lens": "Vortex Lens",
|
"block.antarchy.vortex_lens": "Vortex Lens",
|
||||||
|
"tooltip.antarchy.vortex_lens": "Redstone power sucks entities into its beam; Bluestone power blasts them away. Stronger signal, bigger vortex.",
|
||||||
"block.antarchy.bluestone_repeater": "Bluestone Repeater",
|
"block.antarchy.bluestone_repeater": "Bluestone Repeater",
|
||||||
"block.antarchy.bluestone_comparator": "Bluestone Comparator",
|
"block.antarchy.bluestone_comparator": "Bluestone Comparator",
|
||||||
"block.antarchy.bluestone_torch": "Bluestone Torch",
|
"block.antarchy.bluestone_torch": "Bluestone Torch",
|
||||||
@@ -527,8 +528,8 @@
|
|||||||
"tooltip.antarchy.blood_crystal_katana.dash": "Reaches distant targets you look at; a full swing grants brief immunity.",
|
"tooltip.antarchy.blood_crystal_katana.dash": "Reaches distant targets you look at; a full swing grants brief immunity.",
|
||||||
"tooltip.antarchy.blood_crystal_katana.trail": "Leaves a crimson trail behind you.",
|
"tooltip.antarchy.blood_crystal_katana.trail": "Leaves a crimson trail behind you.",
|
||||||
"item.antarchy.eye_of_the_storm": "Eye of the Storm",
|
"item.antarchy.eye_of_the_storm": "Eye of the Storm",
|
||||||
"tooltip.antarchy.eye_of_the_storm.updraft": "Use to summon a vortex beneath you that flings you skyward.",
|
"tooltip.antarchy.eye_of_the_storm.updraft": "Use to ride a rising vortex skyward.",
|
||||||
"tooltip.antarchy.eye_of_the_storm.surge": "Attack to hurl a vortex that gathers foes, batters them, and flings them back at you.",
|
"tooltip.antarchy.eye_of_the_storm.surge": "Attack to hurl a homing tornado that scoops up foes and drags them along.",
|
||||||
"item.antarchy.royal_guardian_helmet": "Royal Guardian Helmet",
|
"item.antarchy.royal_guardian_helmet": "Royal Guardian Helmet",
|
||||||
"item.antarchy.royal_guardian_chestplate": "Royal Guardian Chestplate",
|
"item.antarchy.royal_guardian_chestplate": "Royal Guardian Chestplate",
|
||||||
"item.antarchy.royal_guardian_leggings": "Royal Guardian Leggings",
|
"item.antarchy.royal_guardian_leggings": "Royal Guardian Leggings",
|
||||||
@@ -540,7 +541,6 @@
|
|||||||
"item.antarchy.royal_assailant_leggings": "Royal Assailant Leggings",
|
"item.antarchy.royal_assailant_leggings": "Royal Assailant Leggings",
|
||||||
"item.antarchy.royal_assailant_boots": "Royal Assailant Boots",
|
"item.antarchy.royal_assailant_boots": "Royal Assailant Boots",
|
||||||
"item.antarchy.royal_assailant_battleaxe": "Royal Assailant Battle Axe",
|
"item.antarchy.royal_assailant_battleaxe": "Royal Assailant Battle Axe",
|
||||||
"tooltip.antarchy.royal_guardian_shield": "An upgraded shield fit for a king's guard.",
|
|
||||||
"tooltip.antarchy.royal_assailant_chestplate.invert": "Press the inversion key to toggle inverted gravity on and off.",
|
"tooltip.antarchy.royal_assailant_chestplate.invert": "Press the inversion key to toggle inverted gravity on and off.",
|
||||||
"tooltip.antarchy.royal_assailant_boots.fall": "Cancels fall damage while falling upward.",
|
"tooltip.antarchy.royal_assailant_boots.fall": "Cancels fall damage while falling upward.",
|
||||||
"item.antarchy.mantis_claw": "Mantis Claw",
|
"item.antarchy.mantis_claw": "Mantis Claw",
|
||||||
@@ -1009,6 +1009,33 @@
|
|||||||
"subtitles.antarchy.water_cannon_fire": "Water Cannon fires",
|
"subtitles.antarchy.water_cannon_fire": "Water Cannon fires",
|
||||||
"subtitles.antarchy.toreterror_jump_up": "Toreterror jumps",
|
"subtitles.antarchy.toreterror_jump_up": "Toreterror jumps",
|
||||||
"subtitles.antarchy.toreterror_jump_land": "Toreterror lands",
|
"subtitles.antarchy.toreterror_jump_land": "Toreterror lands",
|
||||||
|
"subtitles.antarchy.king_idle": "The King rumbles",
|
||||||
|
"subtitles.antarchy.king_walk": "The King's footfalls",
|
||||||
|
"subtitles.antarchy.king_fly_loop": "The King's wings beat",
|
||||||
|
"subtitles.antarchy.king_wing_flap": "The King's wings surge",
|
||||||
|
"subtitles.antarchy.king_bite": "The King bites",
|
||||||
|
"subtitles.antarchy.king_stomp": "The King stomps",
|
||||||
|
"subtitles.antarchy.king_roar": "The King roars",
|
||||||
|
"subtitles.antarchy.king_hurt": "The King is struck",
|
||||||
|
"subtitles.antarchy.king_death": "The King falls",
|
||||||
|
"subtitles.antarchy.king_beam_shoot": "The King fires a beam",
|
||||||
|
"subtitles.antarchy.king_fireball_shoot": "The King breathes fire",
|
||||||
|
"subtitles.antarchy.king_decree_cast": "The King pronounces a Decree",
|
||||||
|
"subtitles.antarchy.queen_idle": "The Queen murmurs",
|
||||||
|
"subtitles.antarchy.queen_walk": "The Queen's footfalls",
|
||||||
|
"subtitles.antarchy.queen_fly_loop": "The Queen's wings beat",
|
||||||
|
"subtitles.antarchy.queen_wing_flap": "The Queen's wings surge",
|
||||||
|
"subtitles.antarchy.queen_bite": "The Queen bites",
|
||||||
|
"subtitles.antarchy.queen_stomp": "The Queen stomps",
|
||||||
|
"subtitles.antarchy.queen_roar": "The Queen roars",
|
||||||
|
"subtitles.antarchy.queen_hurt": "The Queen is struck",
|
||||||
|
"subtitles.antarchy.queen_death": "The Queen falls",
|
||||||
|
"subtitles.antarchy.queen_beam_shoot": "The Queen fires a beam",
|
||||||
|
"subtitles.antarchy.queen_beam_start": "The Queen's beam charges",
|
||||||
|
"subtitles.antarchy.queen_beam_loop": "The Queen's beam sweeps",
|
||||||
|
"subtitles.antarchy.queen_beam_end": "The Queen's beam fades",
|
||||||
|
"subtitles.antarchy.queen_black_hole_shoot": "The Queen tears open a singularity",
|
||||||
|
"subtitles.antarchy.queen_cast_shoot": "The Queen casts",
|
||||||
"subtitles.antarchy.stinky_fly": "Stinky flies buzz",
|
"subtitles.antarchy.stinky_fly": "Stinky flies buzz",
|
||||||
"item.minecraft.potion.effect.inversion": "Potion of Inversion",
|
"item.minecraft.potion.effect.inversion": "Potion of Inversion",
|
||||||
"item.minecraft.potion.effect.long_inversion": "Potion of Inversion",
|
"item.minecraft.potion.effect.long_inversion": "Potion of Inversion",
|
||||||
@@ -1137,6 +1164,9 @@
|
|||||||
"entity.antarchy.hercules_beetle": "Hercules Beetle",
|
"entity.antarchy.hercules_beetle": "Hercules Beetle",
|
||||||
"entity.antarchy.prince": "Prince",
|
"entity.antarchy.prince": "Prince",
|
||||||
"entity.antarchy.princess": "Princess",
|
"entity.antarchy.princess": "Princess",
|
||||||
|
"entity.antarchy.king": "The King",
|
||||||
|
"entity.antarchy.queen": "The Queen",
|
||||||
|
"entity.antarchy.manticore": "Manticore",
|
||||||
"entity.antarchy.royal_bolt": "Royal Bolt",
|
"entity.antarchy.royal_bolt": "Royal Bolt",
|
||||||
"block.antarchy.prince_egg": "Prince Egg",
|
"block.antarchy.prince_egg": "Prince Egg",
|
||||||
"block.antarchy.princess_egg": "Princess Egg",
|
"block.antarchy.princess_egg": "Princess Egg",
|
||||||
@@ -1148,6 +1178,11 @@
|
|||||||
"item.antarchy.creeping_horror_spawn_egg": "Creeping Horror Spawn Egg",
|
"item.antarchy.creeping_horror_spawn_egg": "Creeping Horror Spawn Egg",
|
||||||
"item.antarchy.lurking_terror_spawn_egg": "Lurking Terror Spawn Egg",
|
"item.antarchy.lurking_terror_spawn_egg": "Lurking Terror Spawn Egg",
|
||||||
"item.antarchy.hercules_beetle_spawn_egg": "Hercules Beetle Spawn Egg",
|
"item.antarchy.hercules_beetle_spawn_egg": "Hercules Beetle Spawn Egg",
|
||||||
|
"item.antarchy.king_spawn_egg": "King Spawn Egg",
|
||||||
|
"item.antarchy.queen_spawn_egg": "Queen Spawn Egg",
|
||||||
|
"item.antarchy.manticore_spawn_egg": "Manticore Spawn Egg",
|
||||||
|
"item.antarchy.prince_spawn_egg": "Prince Spawn Egg",
|
||||||
|
"item.antarchy.princess_spawn_egg": "Princess Spawn Egg",
|
||||||
"item.antarchy.chitin": "Chitin",
|
"item.antarchy.chitin": "Chitin",
|
||||||
"block.antarchy.polished_broodstone": "Polished Broodstone",
|
"block.antarchy.polished_broodstone": "Polished Broodstone",
|
||||||
"block.antarchy.chiseled_broodstone": "Chiseled Broodstone",
|
"block.antarchy.chiseled_broodstone": "Chiseled Broodstone",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"format_version": "1.21.11",
|
"format_version": "1.21.11",
|
||||||
"credit": "Made with Blockbench",
|
"credit": "Made with Blockbench",
|
||||||
|
"render_type": "translucent",
|
||||||
"texture_size": [64, 64],
|
"texture_size": [64, 64],
|
||||||
"textures": {
|
"textures": {
|
||||||
"0": "antarchy:block/vortex_lens/vortex_lens_off",
|
"0": "antarchy:block/vortex_lens/vortex_lens_off",
|
||||||
|
|||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"parent": "antarchy:block/vortex_lens",
|
||||||
|
"textures": {
|
||||||
|
"0": "antarchy:block/vortex_lens/vortex_lens_on_bluestone",
|
||||||
|
"particle": "antarchy:block/vortex_lens/vortex_lens_on_bluestone"
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -5,7 +5,7 @@
|
|||||||
"rotation": [
|
"rotation": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
-90
|
0
|
||||||
],
|
],
|
||||||
"translation": [
|
"translation": [
|
||||||
-5.25,
|
-5.25,
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"rotation": [
|
"rotation": [
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
-90
|
0
|
||||||
],
|
],
|
||||||
"translation": [
|
"translation": [
|
||||||
-5.25,
|
-5.25,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/template_spawn_egg"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/template_spawn_egg"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/template_spawn_egg"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/template_spawn_egg"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/template_spawn_egg"
|
||||||
|
}
|
||||||
+3
-3
@@ -629,7 +629,7 @@
|
|||||||
{
|
{
|
||||||
"from": [
|
"from": [
|
||||||
5.5,
|
5.5,
|
||||||
-6,
|
0,
|
||||||
8
|
8
|
||||||
],
|
],
|
||||||
"to": [
|
"to": [
|
||||||
@@ -706,7 +706,7 @@
|
|||||||
{
|
{
|
||||||
"from": [
|
"from": [
|
||||||
6,
|
6,
|
||||||
-6,
|
0,
|
||||||
7.5
|
7.5
|
||||||
],
|
],
|
||||||
"to": [
|
"to": [
|
||||||
@@ -937,7 +937,7 @@
|
|||||||
{
|
{
|
||||||
"from": [
|
"from": [
|
||||||
9.5,
|
9.5,
|
||||||
-6,
|
0,
|
||||||
8
|
8
|
||||||
],
|
],
|
||||||
"to": [
|
"to": [
|
||||||
|
|||||||
@@ -2676,5 +2676,269 @@
|
|||||||
"name": "antarchy:mob/jerry/adult_attack3"
|
"name": "antarchy:mob/jerry/adult_attack3"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"king_idle": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_idle",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/idle_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/idle_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/idle_3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_walk": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_walk",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/walk_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/walk_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/walk_3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_fly_loop": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_fly_loop",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/fly_loop_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/fly_loop_2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_wing_flap": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_wing_flap",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/wing_flap"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_bite": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_bite",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/bite_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/bite_2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_stomp": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_stomp",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/stomp"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_roar": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_roar",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/roar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_hurt": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_hurt",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/hurt_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/hurt_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/hurt_3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_death": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_death",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/death"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_beam_shoot": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_beam_shoot",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/laser_shoot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_fireball_shoot": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_fireball_shoot",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/fireball_shoot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"king_decree_cast": {
|
||||||
|
"subtitle": "subtitles.antarchy.king_decree_cast",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/king/black_hole_shoot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_idle": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_idle",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/idle_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/idle_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/idle_3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_walk": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_walk",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/walk_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/walk_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/walk_3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_fly_loop": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_fly_loop",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/fly_loop_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/fly_loop_2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_wing_flap": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_wing_flap",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/wing_flap"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_bite": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_bite",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/bite_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/bite_2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_stomp": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_stomp",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/stomp"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_roar": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_roar",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/roar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_hurt": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_hurt",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/hurt_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/hurt_2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/hurt_3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_death": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_death",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/death"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_beam_shoot": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_beam_shoot",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/laser_shoot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_beam_start": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_beam_start",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/queen_beam_start"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_beam_loop": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_beam_loop",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/queen_beam_loop"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_beam_end": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_beam_end",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/queen_beam_end"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_black_hole_shoot": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_black_hole_shoot",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/black_hole_shoot"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"queen_cast_shoot": {
|
||||||
|
"subtitle": "subtitles.antarchy.queen_cast_shoot",
|
||||||
|
"sounds": [
|
||||||
|
{
|
||||||
|
"name": "antarchy:mob/queen/fireball_shoot"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Loaded 100 of 181 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user