diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergy.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergy.java index 5891b5742..980293c17 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergy.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergy.java @@ -5,11 +5,14 @@ import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.client.renderer.lightning.AttachedLightningRenderer; import kamkeel.npcs.entity.EntityEnergyAbility; import kamkeel.npcs.entity.EntityEnergyProjectile; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.entity.Render; import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ResourceLocation; +import noppes.npcs.config.ConfigClient; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; @@ -338,6 +341,68 @@ public abstract class RenderEnergy extends Render { state.render(); } + // ==================== PROXIMITY ALPHA ==================== + + /** + * Calculate a proximity-based alpha multiplier for owner's energy projectiles. + * Returns a factor between ProximityAlphaMin and 1.0 based on: + * - Distance from camera (close = faded, far = full) + * - Entity age (young = faded, old = full; ignored while charging) + *

+ * Only applies to the owning player's client. Non-owners always get 1.0. + * + * @param entity the energy projectile entity + * @param x camera-relative X (from doRender) + * @param y camera-relative Y (from doRender) + * @param z camera-relative Z (from doRender) + * @return alpha multiplier between ProximityAlphaMin and 1.0 + */ + protected float getProximityAlphaFactor(EntityEnergyAbility entity, double x, double y, double z) { + return getProximityAlphaFactor(entity, x, y, z, false); + } + + /** + * Overload that allows forcing proximity-only fade (no age fade-out). + * Used for attached beams and lasers that stay connected to the owner. + * + * @param alwaysUseProximity if true, age factor is ignored (proximity fade never expires) + */ + protected float getProximityAlphaFactor(EntityEnergyAbility entity, double x, double y, double z, boolean alwaysUseProximity) { + float minAlpha = ConfigClient.ProximityAlphaMin; + if (minAlpha >= 1.0f) return 1.0f; + + // Only apply to the owner's client + EntityPlayer player = Minecraft.getMinecraft().thePlayer; + if (player == null || entity.getOwnerEntityId() != player.getEntityId()) { + return 1.0f; + } + + // Distance factor: ramp from minAlpha at 0 to 1.0 at maxDist + float maxDist = ConfigClient.ProximityAlphaDistance; + float dist = (float) Math.sqrt(x * x + y * y + z * z); + float distFactor = Math.min(1.0f, dist / maxDist); + + // Age factor: ramp from 0 to 1.0 over ageTicks + // Charging, attached beams/lasers, and alwaysUseProximity skip age fade + float ageFactor; + if (entity.isCharging() || alwaysUseProximity) { + ageFactor = 0.0f; // Always apply full proximity fade + } else { + int ageTicks = ConfigClient.ProximityAlphaAgeTicks; + if (ageTicks <= 0) { + ageFactor = 1.0f; // Age fade disabled + } else { + ageFactor = Math.min(1.0f, (float) entity.ticksExisted / ageTicks); + } + } + + // Combined: take the max of both factors (either being far OR being old restores alpha) + float combinedFactor = Math.max(distFactor, ageFactor); + + // Lerp between minAlpha and 1.0 + return minAlpha + (1.0f - minAlpha) * combinedFactor; + } + @Override protected ResourceLocation getEntityTexture(Entity entity) { return WHITE_TEXTURE; diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java index c5335d2ab..c870f6a07 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java @@ -34,9 +34,12 @@ public class RenderEnergyBeam extends RenderEnergy { setupRenderState(); + // Proximity alpha fade for owner (attached beams always use proximity, never age out) + float proximityAlpha = getProximityAlphaFactor(beam, x, y, z, beam.isAttachedToOwner()); + // Handle charging state (windup phase) - render only growing orb if (beam.isCharging()) { - renderChargingOrb(beam, x, y, z, partialTicks); + renderChargingOrb(beam, x, y, z, partialTicks, proximityAlpha); restoreRenderState(); return; } @@ -65,7 +68,7 @@ public class RenderEnergyBeam extends RenderEnergy { float headSize = beam.getHeadSize(); int innerColor = beam.getInnerColor(); int outerColor = beam.getOuterColor(); - float outerAlpha = beam.getOuterColorAlpha(); + float outerAlpha = beam.getOuterColorAlpha() * proximityAlpha; // Render everything relative to origin position GL11.glPushMatrix(); @@ -77,10 +80,10 @@ public class RenderEnergyBeam extends RenderEnergy { // Render tail orb at origin (0,0,0) - only in anchored mode // Don't render if head is too close to origin (would cause overlap/extra orb appearance) if (beam.shouldRenderTailOrb() && headDistFromOrigin > headSize * 0.5) { - renderTailOrb(headSize * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, beam.getInnerAlpha()); + renderTailOrb(headSize * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, beam.getInnerAlpha() * proximityAlpha); } - float innerAlpha = beam.getInnerAlpha(); + float innerAlpha = beam.getInnerAlpha() * proximityAlpha; // Render trail segments with smooth connections (with fading for non-anchored) if (beam.hasFadingTrail()) { @@ -101,7 +104,7 @@ public class RenderEnergyBeam extends RenderEnergy { * Render the charging orb during windup phase. * Grows from 0 to headSize based on charge progress. */ - private void renderChargingOrb(EntityAbilityBeam beam, double x, double y, double z, float partialTicks) { + private void renderChargingOrb(EntityAbilityBeam beam, double x, double y, double z, float partialTicks, float proximityAlpha) { float headSize = beam.getHeadSize(); float chargeProgress = beam.getInterpolatedChargeProgress(partialTicks); float size = headSize * chargeProgress; @@ -133,7 +136,7 @@ public class RenderEnergyBeam extends RenderEnergy { // Render outer glow only if enabled if (beam.isOuterColorEnabled()) { float outerScale = innerScale + beam.getOuterColorWidth(); - float outerAlpha = beam.getOuterColorAlpha(); + float outerAlpha = beam.getOuterColorAlpha() * proximityAlpha; GL11.glDepthMask(false); GL11.glPushMatrix(); GL11.glScalef(outerScale, outerScale, outerScale); @@ -144,7 +147,7 @@ public class RenderEnergyBeam extends RenderEnergy { // Render inner core GL11.glScalef(innerScale, innerScale, innerScale); - renderCube(innerColor, beam.getInnerAlpha(), 0.5f); + renderCube(innerColor, beam.getInnerAlpha() * proximityAlpha, 0.5f); GL11.glPopMatrix(); GL11.glPopMatrix(); diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java index e71e17a02..eb4d9f21c 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java @@ -77,17 +77,20 @@ public class RenderEnergyDisc extends RenderEnergy { // Inner scale defines the core size float innerScale = 0.6f; + // Proximity alpha fade for owner + float proximityAlpha = getProximityAlphaFactor(disc, x, y, z); + // Render outer square (translucent) - only if enabled // outerColorWidth is an additive offset from inner size if (disc.isOuterColorEnabled()) { float outerScale = innerScale + disc.getOuterColorWidth(); GL11.glDepthMask(false); - renderFlatSquare(disc.getOuterColor(), disc.getOuterColorAlpha(), radius * outerScale, thickness); + renderFlatSquare(disc.getOuterColor(), disc.getOuterColorAlpha() * proximityAlpha, radius * outerScale, thickness); GL11.glDepthMask(true); } // Render inner square (solid) - renderFlatSquare(disc.getInnerColor(), disc.getInnerAlpha(), radius * innerScale, thickness * 1.2f); + renderFlatSquare(disc.getInnerColor(), disc.getInnerAlpha() * proximityAlpha, radius * innerScale, thickness * 1.2f); GL11.glPopMatrix(); GL11.glPopMatrix(); diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java index 469076d17..c2cfe716a 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java @@ -27,8 +27,11 @@ public class RenderEnergyLaser extends RenderEnergy { setupRenderState(); + // Proximity alpha fade for owner (lasers are always attached, never age out) + float proximityAlpha = getProximityAlphaFactor(laser, x, y, z, true); + if (laser.isCharging()) { - renderChargingOrb(laser, x, y, z, partialTicks); + renderChargingOrb(laser, x, y, z, partialTicks, proximityAlpha); restoreRenderState(); return; } @@ -126,14 +129,14 @@ public class RenderEnergyLaser extends RenderEnergy { renderBeamRectangle(renderStartX, renderStartY, renderStartZ, renderEndX, renderEndY, renderEndZ, horzX, horzY, horzZ, vertX, vertY, vertZ, - outerWidth, laser.getOuterColor(), alpha * 0.4f); + outerWidth, laser.getOuterColor(), alpha * 0.4f * proximityAlpha); // Render middle layer (halfway between inner and outer) float midWidth = innerWidth + (outerWidth - innerWidth) * 0.5f; renderBeamRectangle(renderStartX, renderStartY, renderStartZ, renderEndX, renderEndY, renderEndZ, horzX, horzY, horzZ, vertX, vertY, vertZ, - midWidth, laser.getOuterColor(), alpha * 0.7f); + midWidth, laser.getOuterColor(), alpha * 0.7f * proximityAlpha); GL11.glDepthMask(true); } @@ -141,7 +144,7 @@ public class RenderEnergyLaser extends RenderEnergy { renderBeamRectangle(renderStartX, renderStartY, renderStartZ, renderEndX, renderEndY, renderEndZ, horzX, horzY, horzZ, vertX, vertY, vertZ, - innerWidth, laser.getInnerColor(), alpha * laser.getInnerAlpha()); + innerWidth, laser.getInnerColor(), alpha * laser.getInnerAlpha() * proximityAlpha); // Render lightning along the laser beam if (laser.hasLightningEffect() && laser.getCurrentLength() > 0.1f) { @@ -152,7 +155,7 @@ public class RenderEnergyLaser extends RenderEnergy { restoreRenderState(); } - private void renderChargingOrb(EntityAbilityLaser laser, double x, double y, double z, float partialTicks) { + private void renderChargingOrb(EntityAbilityLaser laser, double x, double y, double z, float partialTicks, float proximityAlpha) { float headSize = laser.getLaserWidth() * 0.5f; float chargeProgress = laser.getInterpolatedChargeProgress(partialTicks); float size = headSize * chargeProgress; @@ -184,7 +187,7 @@ public class RenderEnergyLaser extends RenderEnergy { // Render outer glow only if enabled if (laser.isOuterColorEnabled()) { float outerScale = innerScale + laser.getOuterColorWidth(); - float outerAlpha = laser.getOuterColorAlpha(); + float outerAlpha = laser.getOuterColorAlpha() * proximityAlpha; GL11.glDepthMask(false); GL11.glPushMatrix(); GL11.glScalef(outerScale, outerScale, outerScale); @@ -195,7 +198,7 @@ public class RenderEnergyLaser extends RenderEnergy { // Render inner core GL11.glScalef(innerScale, innerScale, innerScale); - renderCube(innerColor, laser.getInnerAlpha(), 0.5f); + renderCube(innerColor, laser.getInnerAlpha() * proximityAlpha, 0.5f); GL11.glPopMatrix(); GL11.glPopMatrix(); diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyOrb.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyOrb.java index 08f77a522..5efe83222 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyOrb.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyOrb.java @@ -69,6 +69,9 @@ public class RenderEnergyOrb extends RenderEnergy { // Inner scale defines the core size float innerScale = 0.6f; + // Proximity alpha fade for owner + float proximityAlpha = getProximityAlphaFactor(orb, x, y, z); + // Render outer cube (translucent) - only if enabled // outerColorWidth is an additive offset from inner size if (orb.isOuterColorEnabled()) { @@ -76,14 +79,14 @@ public class RenderEnergyOrb extends RenderEnergy { GL11.glDepthMask(false); GL11.glPushMatrix(); GL11.glScalef(outerScale, outerScale, outerScale); - renderCube(orb.getOuterColor(), orb.getOuterColorAlpha(), 0.5f); + renderCube(orb.getOuterColor(), orb.getOuterColorAlpha() * proximityAlpha, 0.5f); GL11.glPopMatrix(); GL11.glDepthMask(true); } // Render inner cube (solid) GL11.glScalef(innerScale, innerScale, innerScale); - renderCube(orb.getInnerColor(), orb.getInnerAlpha(), 0.5f); + renderCube(orb.getInnerColor(), orb.getInnerAlpha() * proximityAlpha, 0.5f); GL11.glPopMatrix(); GL11.glPopMatrix(); diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergySlicer.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergySlicer.java index f661442c1..589818905 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergySlicer.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergySlicer.java @@ -47,17 +47,20 @@ public class RenderEnergySlicer extends RenderEnergy { float innerScale = 0.7f; + // Proximity alpha fade for owner + float proximityAlpha = getProximityAlphaFactor(slicer, x, y, z); + // Render outer blade (translucent glow) if (slicer.isOuterColorEnabled()) { float outerScale = 1.0f + slicer.getOuterColorWidth() * 0.2f; GL11.glDepthMask(false); - renderBlade(slicer.getOuterColor(), slicer.getOuterColorAlpha(), + renderBlade(slicer.getOuterColor(), slicer.getOuterColorAlpha() * proximityAlpha, width * 0.5f * outerScale, thickness * 2.0f, 0.05f); GL11.glDepthMask(true); } // Render inner blade (solid core) - renderBlade(slicer.getInnerColor(), slicer.getInnerAlpha(), + renderBlade(slicer.getInnerColor(), slicer.getInnerAlpha() * proximityAlpha, width * 0.5f * innerScale, thickness, 0.03f); GL11.glPopMatrix(); diff --git a/src/main/java/noppes/npcs/config/ConfigClient.java b/src/main/java/noppes/npcs/config/ConfigClient.java index ef0650db0..cee8c8759 100644 --- a/src/main/java/noppes/npcs/config/ConfigClient.java +++ b/src/main/java/noppes/npcs/config/ConfigClient.java @@ -57,6 +57,16 @@ public class ConfigClient { public static Property LowResExplosionProperty; public static boolean LowResExplosion = false; + // Proximity Alpha (owner-only fade for energy projectiles near camera) + public static Property ProximityAlphaMinProperty; + public static float ProximityAlphaMin = 0.15f; + + public static Property ProximityAlphaDistanceProperty; + public static float ProximityAlphaDistance = 7.0f; + + public static Property ProximityAlphaAgeTicksProperty; + public static int ProximityAlphaAgeTicks = 60; + /** * Questing Properties **/ @@ -291,6 +301,30 @@ public class ConfigClient { ); LowResExplosion = LowResExplosionProperty.getBoolean(false); + ProximityAlphaMinProperty = config.get( + RENDERING, + "Proximity Alpha Min", + 0.15, + "Minimum alpha for owner's energy projectiles when very close to camera. Set to 1.0 to disable proximity fade." + ); + ProximityAlphaMin = (float) Math.max(0.0, Math.min(1.0, ProximityAlphaMinProperty.getDouble(0.15))); + + ProximityAlphaDistanceProperty = config.get( + RENDERING, + "Proximity Alpha Distance", + 7.0, + "Distance in blocks at which owner's energy projectiles reach full alpha." + ); + ProximityAlphaDistance = (float) Math.max(1.0, ProximityAlphaDistanceProperty.getDouble(7.0)); + + ProximityAlphaAgeTicksProperty = config.get( + RENDERING, + "Proximity Alpha Age Ticks", + 60, + "After this many ticks alive, proximity alpha fade is disabled (projectile always renders at full alpha). Does not apply while charging or to attached beams/lasers." + ); + ProximityAlphaAgeTicks = Math.max(0, ProximityAlphaAgeTicksProperty.getInt(60)); + DialogSpeedProperty = config.get(VISUAL, "Dialog Speed", true, "Only set for gradual dialogs"); DialogSpeed = DialogSpeedProperty.getInt(10);