updated weed joint, plane crash and atomic bomb explosion
This commit is contained in:
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
|||||||
yarn_mappings=1.20.1+build.10
|
yarn_mappings=1.20.1+build.10
|
||||||
loader_version=0.18.3
|
loader_version=0.18.3
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=26.3.9
|
mod_version=26.3.11
|
||||||
maven_group=dev.tggamesyt
|
maven_group=dev.tggamesyt
|
||||||
archives_base_name=szar
|
archives_base_name=szar
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import net.minecraft.client.gui.screen.ingame.HandledScreens;
|
|||||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||||
import net.minecraft.client.network.OtherClientPlayerEntity;
|
import net.minecraft.client.network.OtherClientPlayerEntity;
|
||||||
import net.minecraft.client.option.KeyBinding;
|
import net.minecraft.client.option.KeyBinding;
|
||||||
|
import net.minecraft.client.render.entity.EmptyEntityRenderer;
|
||||||
import net.minecraft.client.render.entity.EntityRenderer;
|
import net.minecraft.client.render.entity.EntityRenderer;
|
||||||
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
|
import net.minecraft.client.render.entity.FlyingItemEntityRenderer;
|
||||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||||
@@ -61,7 +62,9 @@ import static dev.tggamesyt.szar.client.ClientCosmetics.loadTextureFromURL;
|
|||||||
import static dev.tggamesyt.szar.client.UraniumUtils.updateUranium;
|
import static dev.tggamesyt.szar.client.UraniumUtils.updateUranium;
|
||||||
|
|
||||||
public class SzarClient implements ClientModInitializer {
|
public class SzarClient implements ClientModInitializer {
|
||||||
private static boolean addedFeature = false;
|
// add this field to your client init class
|
||||||
|
private float drogOverlayProgress = 0.0F;
|
||||||
|
private long lastTime = 0;
|
||||||
private static final Map<KeyBinding, KeyBinding> activeScramble = new HashMap<>();
|
private static final Map<KeyBinding, KeyBinding> activeScramble = new HashMap<>();
|
||||||
public static final EntityModelLayer PLANE =
|
public static final EntityModelLayer PLANE =
|
||||||
new EntityModelLayer(
|
new EntityModelLayer(
|
||||||
@@ -88,6 +91,7 @@ public class SzarClient implements ClientModInitializer {
|
|||||||
int loopStart = startOffset + startLength;
|
int loopStart = startOffset + startLength;
|
||||||
@Override
|
@Override
|
||||||
public void onInitializeClient() {
|
public void onInitializeClient() {
|
||||||
|
EntityRendererRegistry.register(Szar.RADIATION_AREA, EmptyEntityRenderer::new);
|
||||||
ClientPlayNetworking.registerGlobalReceiver(Szar.PLAY_VIDEO,
|
ClientPlayNetworking.registerGlobalReceiver(Szar.PLAY_VIDEO,
|
||||||
(client, handler, buf, responseSender) -> {
|
(client, handler, buf, responseSender) -> {
|
||||||
String player = buf.readString();
|
String player = buf.readString();
|
||||||
@@ -358,53 +362,59 @@ public class SzarClient implements ClientModInitializer {
|
|||||||
);
|
);
|
||||||
HudRenderCallback.EVENT.register((drawContext, tickDelta) -> {
|
HudRenderCallback.EVENT.register((drawContext, tickDelta) -> {
|
||||||
MinecraftClient client = MinecraftClient.getInstance();
|
MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
|
||||||
if (client.player == null) return;
|
if (client.player == null) return;
|
||||||
if (!client.player.hasStatusEffect(Szar.DROG_EFFECT)) return;
|
|
||||||
|
|
||||||
var effect = client.player.getStatusEffect(Szar.DROG_EFFECT);
|
boolean hasEffect = client.player.hasStatusEffect(Szar.DROG_EFFECT);
|
||||||
int amplifier = effect.getAmplifier(); // 0 = level I
|
|
||||||
if (amplifier > 2) {amplifier = 2;}
|
// ease in/out — 0.02F controls speed, lower = slower transition
|
||||||
|
if (hasEffect) {
|
||||||
|
drogOverlayProgress = Math.min(1.0F, drogOverlayProgress + tickDelta * 0.02F);
|
||||||
|
} else {
|
||||||
|
drogOverlayProgress = Math.max(0.0F, drogOverlayProgress - tickDelta * 0.02F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drogOverlayProgress <= 0.0F) return;
|
||||||
|
|
||||||
|
// S-curve easing so it accelerates then decelerates
|
||||||
|
float eased = drogOverlayProgress * drogOverlayProgress * (3.0F - 2.0F * drogOverlayProgress);
|
||||||
|
|
||||||
|
var effect = hasEffect ? client.player.getStatusEffect(Szar.DROG_EFFECT) : null;
|
||||||
|
int amplifier = effect != null ? Math.min(effect.getAmplifier(), 2) : 0;
|
||||||
|
|
||||||
float level = amplifier + 1f;
|
float level = amplifier + 1f;
|
||||||
float time = client.player.age + tickDelta;
|
float time = client.player.age + tickDelta;
|
||||||
|
|
||||||
/* ───── Color speed (gentle ramp) ───── */
|
|
||||||
float speed = 0.015f + amplifier * 0.012f;
|
float speed = 0.015f + amplifier * 0.012f;
|
||||||
float hue = (time * speed) % 1.0f;
|
float hue = (time * speed) % 1.0f;
|
||||||
|
|
||||||
int rgb = MathHelper.hsvToRgb(hue, 0.95f, 1f);
|
int rgb = MathHelper.hsvToRgb(hue, 0.95f, 1f);
|
||||||
|
|
||||||
/* ───── Alpha (mostly stable) ───── */
|
|
||||||
float pulse =
|
float pulse =
|
||||||
(MathHelper.sin(time * (0.04f + amplifier * 0.015f)) + 1f) * 0.5f;
|
(MathHelper.sin(time * (0.04f + amplifier * 0.015f)) + 1f) * 0.5f;
|
||||||
|
|
||||||
|
// multiply alpha by eased so it fades in/out smoothly
|
||||||
float alpha = MathHelper.clamp(
|
float alpha = MathHelper.clamp(
|
||||||
0.20f + amplifier * 0.10f + pulse * 0.10f,
|
(0.20f + amplifier * 0.10f + pulse * 0.10f) * eased,
|
||||||
0.20f,
|
0.0f,
|
||||||
0.70f
|
0.70f
|
||||||
);
|
);
|
||||||
|
|
||||||
/* ───── Very subtle jitter ───── */
|
// jitter also scales with eased so it doesn't pop in suddenly
|
||||||
float jitter = 0.15f * amplifier;
|
float jitter = 0.15f * amplifier * eased;
|
||||||
float jitterX = (client.world.random.nextFloat() - 0.5f) * jitter;
|
float jitterX = (client.world.random.nextFloat() - 0.5f) * jitter;
|
||||||
float jitterY = (client.world.random.nextFloat() - 0.5f) * jitter;
|
float jitterY = (client.world.random.nextFloat() - 0.5f) * jitter;
|
||||||
|
|
||||||
int width = client.getWindow().getScaledWidth();
|
int width = client.getWindow().getScaledWidth();
|
||||||
int height = client.getWindow().getScaledHeight();
|
int height = client.getWindow().getScaledHeight();
|
||||||
|
|
||||||
int color =
|
int color = ((int)(alpha * 255) << 24) | (rgb & 0x00FFFFFF);
|
||||||
((int)(alpha * 255) << 24)
|
|
||||||
| (rgb & 0x00FFFFFF);
|
|
||||||
|
|
||||||
RenderSystem.enableBlend();
|
RenderSystem.enableBlend();
|
||||||
RenderSystem.defaultBlendFunc();
|
RenderSystem.defaultBlendFunc();
|
||||||
|
|
||||||
drawContext.getMatrices().push();
|
drawContext.getMatrices().push();
|
||||||
drawContext.getMatrices().translate(jitterX, jitterY, 0);
|
drawContext.getMatrices().translate(jitterX, jitterY, 0);
|
||||||
|
|
||||||
drawContext.fill(0, 0, width, height, color);
|
drawContext.fill(0, 0, width, height, color);
|
||||||
|
|
||||||
drawContext.getMatrices().pop();
|
drawContext.getMatrices().pop();
|
||||||
|
|
||||||
RenderSystem.disableBlend();
|
RenderSystem.disableBlend();
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package dev.tggamesyt.szar.client.mixin;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Joint;
|
||||||
|
import net.minecraft.client.model.ModelPart;
|
||||||
|
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.util.Arm;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
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(BipedEntityModel.class)
|
||||||
|
public abstract class BipedEntityModelMixin<T extends LivingEntity> {
|
||||||
|
|
||||||
|
@Shadow public ModelPart rightArm;
|
||||||
|
@Shadow public ModelPart leftArm;
|
||||||
|
@Shadow public ModelPart head;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "setAngles",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
// hat.copyTransform(head) is the absolute last call in setAngles
|
||||||
|
target = "Lnet/minecraft/client/model/ModelPart;copyTransform(Lnet/minecraft/client/model/ModelPart;)V",
|
||||||
|
shift = At.Shift.AFTER
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void injectJointPose(T entity, float f, float g, float h, float i, float j, CallbackInfo ci) {
|
||||||
|
if (!entity.isUsingItem()) return;
|
||||||
|
if (!(entity.getActiveItem().getItem() instanceof Joint)) return;
|
||||||
|
|
||||||
|
boolean mainHand = entity.getActiveHand() == Hand.MAIN_HAND;
|
||||||
|
boolean rightHanded = entity.getMainArm() == Arm.RIGHT;
|
||||||
|
boolean useRight = (mainHand && rightHanded) || (!mainHand && !rightHanded);
|
||||||
|
|
||||||
|
if (useRight) {
|
||||||
|
this.rightArm.pitch = MathHelper.clamp(
|
||||||
|
this.head.pitch - 1.7F - (entity.isInSneakingPose() ? 0.2617994F : 0.0F),
|
||||||
|
-2.4F, 3.3F
|
||||||
|
);
|
||||||
|
this.rightArm.yaw = this.head.yaw - 0.4F;
|
||||||
|
} else {
|
||||||
|
this.leftArm.pitch = MathHelper.clamp(
|
||||||
|
this.head.pitch - 1.7F - (entity.isInSneakingPose() ? 0.2617994F : 0.0F),
|
||||||
|
-2.4F, 3.3F
|
||||||
|
);
|
||||||
|
this.leftArm.yaw = this.head.yaw + 0.4F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package dev.tggamesyt.szar.client.mixin;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Joint;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.Camera;
|
||||||
|
import net.minecraft.client.render.GameRenderer;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
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.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(GameRenderer.class)
|
||||||
|
public abstract class GameRendererMixin {
|
||||||
|
|
||||||
|
@Shadow @Final private MinecraftClient client;
|
||||||
|
|
||||||
|
// smooth value between 0.0 (no zoom) and 1.0 (full zoom)
|
||||||
|
@Unique private float szar$jointZoomProgress = 0.0F;
|
||||||
|
|
||||||
|
@Inject(method = "getFov", at = @At("RETURN"), cancellable = true)
|
||||||
|
private void injectJointFov(Camera camera, float tickDelta, boolean changingFov, CallbackInfoReturnable<Double> cir) {
|
||||||
|
if (this.client.player == null) return;
|
||||||
|
|
||||||
|
boolean isUsing = this.client.player.isUsingItem()
|
||||||
|
&& this.client.player.getActiveItem().getItem() instanceof Joint;
|
||||||
|
|
||||||
|
// ease in when using, ease out when not
|
||||||
|
if (isUsing) {
|
||||||
|
szar$jointZoomProgress = Math.min(1.0F, szar$jointZoomProgress + tickDelta * 0.1F);
|
||||||
|
} else {
|
||||||
|
szar$jointZoomProgress = Math.max(0.0F, szar$jointZoomProgress - tickDelta * 0.1F);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (szar$jointZoomProgress <= 0.0F) return;
|
||||||
|
|
||||||
|
// smooth S-curve easing
|
||||||
|
float eased = szar$jointZoomProgress * szar$jointZoomProgress * (3.0F - 2.0F * szar$jointZoomProgress);
|
||||||
|
|
||||||
|
double currentFov = cir.getReturnValue();
|
||||||
|
// lerp toward 90% of normal FOV (10% zoom)
|
||||||
|
cir.setReturnValue(currentFov * (1.0 - 0.1 * eased));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package dev.tggamesyt.szar.client.mixin;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Joint;
|
||||||
|
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
|
import net.minecraft.client.render.item.HeldItemRenderer;
|
||||||
|
import net.minecraft.client.render.model.json.ModelTransformationMode;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.Arm;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.math.RotationAxis;
|
||||||
|
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(HeldItemRenderer.class)
|
||||||
|
public abstract class HeldItemRendererMixin {
|
||||||
|
|
||||||
|
@Inject(method = "renderFirstPersonItem", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void injectJointFirstPerson(
|
||||||
|
AbstractClientPlayerEntity player,
|
||||||
|
float tickDelta,
|
||||||
|
float pitch,
|
||||||
|
Hand hand,
|
||||||
|
float swingProgress,
|
||||||
|
ItemStack item,
|
||||||
|
float equipProgress,
|
||||||
|
MatrixStack matrices,
|
||||||
|
VertexConsumerProvider vertexConsumers,
|
||||||
|
int light,
|
||||||
|
CallbackInfo ci
|
||||||
|
) {
|
||||||
|
if (!(item.getItem() instanceof Joint)) return;
|
||||||
|
// only override position while actively using, otherwise let normal rendering handle equip/unequip
|
||||||
|
if (!player.isUsingItem() || player.getActiveHand() != hand || player.getItemUseTimeLeft() <= 0) return;
|
||||||
|
|
||||||
|
boolean isMainHand = hand == Hand.MAIN_HAND;
|
||||||
|
Arm arm = isMainHand ? player.getMainArm() : player.getMainArm().getOpposite();
|
||||||
|
boolean isRight = arm == Arm.RIGHT;
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
// rotate 80 degrees toward player (around Y axis, so it faces them)
|
||||||
|
matrices.translate(
|
||||||
|
0.0F,
|
||||||
|
-0.15F, // was -0.35F, more negative = higher up
|
||||||
|
-0.5F
|
||||||
|
);
|
||||||
|
|
||||||
|
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(80.0F));
|
||||||
|
matrices.translate(0.0F, equipProgress * -0.6F, 0.0F);
|
||||||
|
|
||||||
|
HeldItemRenderer self = (HeldItemRenderer)(Object)this;
|
||||||
|
self.renderItem(
|
||||||
|
player,
|
||||||
|
item,
|
||||||
|
isRight ? ModelTransformationMode.FIRST_PERSON_RIGHT_HAND : ModelTransformationMode.FIRST_PERSON_LEFT_HAND,
|
||||||
|
!isRight,
|
||||||
|
matrices,
|
||||||
|
vertexConsumers,
|
||||||
|
light
|
||||||
|
);
|
||||||
|
|
||||||
|
matrices.pop();
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
package dev.tggamesyt.szar.client.mixin;
|
package dev.tggamesyt.szar.client.mixin;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Joint;
|
||||||
import dev.tggamesyt.szar.client.VideoHeadFeature;
|
import dev.tggamesyt.szar.client.VideoHeadFeature;
|
||||||
|
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||||
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
import net.minecraft.client.render.entity.PlayerEntityRenderer;
|
||||||
|
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
@Mixin(PlayerEntityRenderer.class)
|
@Mixin(PlayerEntityRenderer.class)
|
||||||
public abstract class PlayerEntityRendererMixin {
|
public abstract class PlayerEntityRendererMixin {
|
||||||
@@ -18,4 +24,20 @@ public abstract class PlayerEntityRendererMixin {
|
|||||||
|
|
||||||
renderer.addFeature(new VideoHeadFeature(renderer));
|
renderer.addFeature(new VideoHeadFeature(renderer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "getArmPose", at = @At("RETURN"), cancellable = true)
|
||||||
|
private static void injectJointArmPose(
|
||||||
|
AbstractClientPlayerEntity player,
|
||||||
|
Hand hand,
|
||||||
|
CallbackInfoReturnable<BipedEntityModel.ArmPose> cir
|
||||||
|
) {
|
||||||
|
ItemStack stack = player.getStackInHand(hand);
|
||||||
|
if (!stack.isEmpty()
|
||||||
|
&& player.getActiveHand() == hand
|
||||||
|
&& player.getItemUseTimeLeft() > 0
|
||||||
|
&& stack.getItem() instanceof Joint) {
|
||||||
|
// SPYGLASS pose raises the arm, then BipedEntityModelMixin overrides the exact angles
|
||||||
|
cir.setReturnValue(BipedEntityModel.ArmPose.SPYGLASS);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package dev.tggamesyt.szar.client.mixin;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Joint;
|
||||||
|
import net.minecraft.client.model.ModelPart;
|
||||||
|
import net.minecraft.client.render.VertexConsumerProvider;
|
||||||
|
import net.minecraft.client.render.entity.feature.PlayerHeldItemFeatureRenderer;
|
||||||
|
import net.minecraft.client.render.entity.model.ModelWithHead;
|
||||||
|
import net.minecraft.client.render.item.HeldItemRenderer;
|
||||||
|
import net.minecraft.client.render.model.json.ModelTransformationMode;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.Arm;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
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(PlayerHeldItemFeatureRenderer.class)
|
||||||
|
public abstract class PlayerHeldItemFeatureRendererMixin<T extends net.minecraft.entity.player.PlayerEntity, M extends net.minecraft.client.render.entity.model.EntityModel<T> & net.minecraft.client.render.entity.model.ModelWithArms & ModelWithHead> extends net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer<T, M> {
|
||||||
|
|
||||||
|
@Shadow @Final private HeldItemRenderer playerHeldItemRenderer;
|
||||||
|
|
||||||
|
public PlayerHeldItemFeatureRendererMixin(net.minecraft.client.render.entity.feature.FeatureRendererContext<T, M> context, HeldItemRenderer heldItemRenderer) {
|
||||||
|
super(context, heldItemRenderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "renderItem", at = @At("HEAD"), cancellable = true)
|
||||||
|
private void injectJointRender(
|
||||||
|
LivingEntity entity,
|
||||||
|
ItemStack stack,
|
||||||
|
ModelTransformationMode transformationMode,
|
||||||
|
Arm arm,
|
||||||
|
MatrixStack matrices,
|
||||||
|
VertexConsumerProvider vertexConsumers,
|
||||||
|
int light,
|
||||||
|
CallbackInfo ci
|
||||||
|
) {
|
||||||
|
if (stack.getItem() instanceof Joint
|
||||||
|
&& entity.getActiveItem() == stack
|
||||||
|
&& entity.handSwingTicks == 0) {
|
||||||
|
|
||||||
|
matrices.push();
|
||||||
|
|
||||||
|
ModelPart head = ((ModelWithHead) this.getContextModel()).getHead();
|
||||||
|
float savedPitch = head.pitch;
|
||||||
|
|
||||||
|
// clamp head pitch so the joint doesn't clip into the head when looking up/down
|
||||||
|
head.pitch = MathHelper.clamp(head.pitch, -(float)(Math.PI / 6F), (float)(Math.PI / 2F));
|
||||||
|
head.rotate(matrices);
|
||||||
|
head.pitch = savedPitch;
|
||||||
|
|
||||||
|
net.minecraft.client.render.entity.feature.HeadFeatureRenderer.translate(matrices, false);
|
||||||
|
|
||||||
|
boolean isLeft = arm == Arm.LEFT;
|
||||||
|
|
||||||
|
matrices.translate(
|
||||||
|
0F,
|
||||||
|
-0.3F,
|
||||||
|
0.1F
|
||||||
|
);
|
||||||
|
|
||||||
|
this.playerHeldItemRenderer.renderItem(entity, stack, ModelTransformationMode.HEAD, false, matrices, vertexConsumers, light);
|
||||||
|
|
||||||
|
matrices.pop();
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,13 @@
|
|||||||
"package": "dev.tggamesyt.szar.client.mixin",
|
"package": "dev.tggamesyt.szar.client.mixin",
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"client": [
|
"client": [
|
||||||
|
"BipedEntityModelMixin",
|
||||||
|
"GameRendererMixin",
|
||||||
|
"HeldItemRendererMixin",
|
||||||
"ItemRendererMixin",
|
"ItemRendererMixin",
|
||||||
"MouseMixin",
|
"MouseMixin",
|
||||||
"PlayerEntityRendererMixin",
|
"PlayerEntityRendererMixin",
|
||||||
|
"PlayerHeldItemFeatureRendererMixin",
|
||||||
"PlayerModelMixin",
|
"PlayerModelMixin",
|
||||||
"RadiatedItemRendererMixin",
|
"RadiatedItemRendererMixin",
|
||||||
"RadiationHeartMixin",
|
"RadiationHeartMixin",
|
||||||
|
|||||||
@@ -2,17 +2,30 @@ package dev.tggamesyt.szar;
|
|||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.MovementType;
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.particle.ParticleTypes;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AtomEntity extends Entity {
|
public class AtomEntity extends Entity {
|
||||||
|
|
||||||
private static final int NUKE_RADIUS = 100;
|
private static final int NUKE_RADIUS = 100;
|
||||||
|
// vanilla clamps explosion power at 5 internally for block destruction,
|
||||||
|
// but we can still call createExplosion with higher values for damage/visuals
|
||||||
|
// the absolute max that does anything meaningful is around 200F
|
||||||
|
private static final float MAX_EXPLOSION_POWER = 200.0F;
|
||||||
|
|
||||||
private boolean armed = false;
|
private boolean armed = false;
|
||||||
private boolean wasFallingFast = false;
|
private boolean wasFallingFast = false;
|
||||||
|
|
||||||
public AtomEntity(EntityType<?> type, World world) {
|
public AtomEntity(EntityType<?> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
}
|
}
|
||||||
@@ -28,7 +41,6 @@ public class AtomEntity extends Entity {
|
|||||||
this.setVelocity(this.getVelocity().add(0, -0.08, 0));
|
this.setVelocity(this.getVelocity().add(0, -0.08, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track if it was falling fast enough to count as impact
|
|
||||||
if (this.getVelocity().y < -0.5) {
|
if (this.getVelocity().y < -0.5) {
|
||||||
wasFallingFast = true;
|
wasFallingFast = true;
|
||||||
}
|
}
|
||||||
@@ -36,68 +48,94 @@ public class AtomEntity extends Entity {
|
|||||||
this.move(MovementType.SELF, this.getVelocity());
|
this.move(MovementType.SELF, this.getVelocity());
|
||||||
|
|
||||||
if (!getWorld().isClient) {
|
if (!getWorld().isClient) {
|
||||||
|
if (this.isOnFire()) armed = true;
|
||||||
|
|
||||||
// 🔥 If on fire, arm it
|
|
||||||
if (this.isOnFire()) {
|
|
||||||
armed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 💥 Explode only if:
|
|
||||||
// 1. It was falling fast OR
|
|
||||||
// 2. It is armed
|
|
||||||
if (this.isOnGround() && (wasFallingFast || armed)) {
|
if (this.isOnGround() && (wasFallingFast || armed)) {
|
||||||
explode();
|
explode();
|
||||||
this.discard();
|
this.discard();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void explode() {
|
private void explode() {
|
||||||
ServerWorld world = (ServerWorld) this.getWorld();
|
ServerWorld world = (ServerWorld) this.getWorld();
|
||||||
|
Vec3d center = this.getPos();
|
||||||
|
|
||||||
// Visual / sound explosion only
|
world.createExplosion(this, center.x, center.y, center.z,
|
||||||
world.createExplosion(
|
MAX_EXPLOSION_POWER, World.ExplosionSourceType.TNT);
|
||||||
this,
|
|
||||||
getX(),
|
|
||||||
getY(),
|
|
||||||
getZ(),
|
|
||||||
50.0F, // just visuals
|
|
||||||
World.ExplosionSourceType.TNT
|
|
||||||
);
|
|
||||||
|
|
||||||
clearSphere(world, this.getBlockPos(), NUKE_RADIUS);
|
int rings = 6;
|
||||||
|
for (int ring = 1; ring <= rings; ring++) {
|
||||||
|
double ringRadius = (NUKE_RADIUS / (double) rings) * ring;
|
||||||
|
float ringPower = MAX_EXPLOSION_POWER * (1.0F - (ring / (float) rings));
|
||||||
|
ringPower = Math.max(ringPower, 4.0F);
|
||||||
|
|
||||||
|
int pointsOnRing = 6 + ring * 4;
|
||||||
|
for (int i = 0; i < pointsOnRing; i++) {
|
||||||
|
double angle = (2 * Math.PI / pointsOnRing) * i;
|
||||||
|
double ex = center.x + Math.cos(angle) * ringRadius;
|
||||||
|
double ey = center.y;
|
||||||
|
double ez = center.z + Math.sin(angle) * ringRadius;
|
||||||
|
world.createExplosion(this, ex, ey, ez, ringPower, World.ExplosionSourceType.TNT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no clearSphere call anymore
|
||||||
|
spawnRadiationZones(world, center);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void spawnRadiationZones(ServerWorld world, Vec3d center) {
|
||||||
|
int zoneCount = 40;
|
||||||
|
|
||||||
|
for (int wave = 0; wave < 3; wave++) {
|
||||||
|
for (int i = 0; i < zoneCount; i++) {
|
||||||
|
double angle = world.random.nextDouble() * 2 * Math.PI;
|
||||||
|
double dist = world.random.nextDouble() * NUKE_RADIUS;
|
||||||
|
double rx = center.x + Math.cos(angle) * dist;
|
||||||
|
double rz = center.z + Math.sin(angle) * dist;
|
||||||
|
|
||||||
|
double ry;
|
||||||
|
if (wave == 0) {
|
||||||
|
// wave 1: starts on ground, falls with gravity — spawn at ground level
|
||||||
|
ry = center.y + world.random.nextDouble() * 5;
|
||||||
|
} else if (wave == 1) {
|
||||||
|
// wave 2: mid air, will fall then float
|
||||||
|
ry = center.y + 10 + world.random.nextDouble() * 20;
|
||||||
|
} else {
|
||||||
|
// wave 3: high up, no gravity at all
|
||||||
|
ry = center.y + 30 + world.random.nextDouble() * 40;
|
||||||
|
}
|
||||||
|
|
||||||
|
float proximity = (float)(1.0 - (dist / NUKE_RADIUS));
|
||||||
|
|
||||||
|
RadiationAreaEntity rad = new RadiationAreaEntity(Szar.RADIATION_AREA, world);
|
||||||
|
rad.setPosition(rx, ry, rz);
|
||||||
|
rad.setLifetime((int)(1200 + proximity * 4800));
|
||||||
|
rad.setRadius(3.0F + proximity * 8.0F);
|
||||||
|
rad.setWave(wave);
|
||||||
|
world.spawnEntity(rad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void clearSphere(ServerWorld world, BlockPos center, int radius) {
|
private void clearSphere(ServerWorld world, BlockPos center, int radius) {
|
||||||
int rSquared = radius * radius;
|
int rSquared = radius * radius;
|
||||||
|
|
||||||
BlockPos.Mutable mutable = new BlockPos.Mutable();
|
BlockPos.Mutable mutable = new BlockPos.Mutable();
|
||||||
|
|
||||||
for (int x = -radius; x <= radius; x++) {
|
for (int x = -radius; x <= radius; x++) {
|
||||||
for (int y = -radius; y <= radius; y++) {
|
for (int y = -radius; y <= radius; y++) {
|
||||||
for (int z = -radius; z <= radius; z++) {
|
for (int z = -radius; z <= radius; z++) {
|
||||||
|
|
||||||
if (x * x + y * y + z * z > rSquared) continue;
|
if (x * x + y * y + z * z > rSquared) continue;
|
||||||
|
mutable.set(center.getX() + x, center.getY() + y, center.getZ() + z);
|
||||||
mutable.set(
|
|
||||||
center.getX() + x,
|
|
||||||
center.getY() + y,
|
|
||||||
center.getZ() + z
|
|
||||||
);
|
|
||||||
|
|
||||||
// Skip void / out of world
|
|
||||||
if (!world.isInBuildLimit(mutable)) continue;
|
if (!world.isInBuildLimit(mutable)) continue;
|
||||||
|
|
||||||
world.setBlockState(mutable, net.minecraft.block.Blocks.AIR.getDefaultState(), 3);
|
world.setBlockState(mutable, net.minecraft.block.Blocks.AIR.getDefaultState(), 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readCustomDataFromNbt(NbtCompound nbt) {}
|
protected void readCustomDataFromNbt(NbtCompound nbt) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void writeCustomDataToNbt(NbtCompound nbt) {}
|
protected void writeCustomDataToNbt(NbtCompound nbt) {}
|
||||||
}
|
}
|
||||||
@@ -165,6 +165,37 @@ public class Joint extends SpyglassItem {
|
|||||||
|
|
||||||
// Optional: play inhale / stop sound
|
// Optional: play inhale / stop sound
|
||||||
user.playSound(SoundEvents.ITEM_HONEY_BOTTLE_DRINK, 1.0F, 1.0F);
|
user.playSound(SoundEvents.ITEM_HONEY_BOTTLE_DRINK, 1.0F, 1.0F);
|
||||||
|
if (world.isClient) {
|
||||||
|
// get the direction the player is facing
|
||||||
|
double yawRad = Math.toRadians(user.getYaw());
|
||||||
|
|
||||||
|
// position in front of the player's face
|
||||||
|
double baseX = user.getX() - Math.sin(yawRad) * 0.5;
|
||||||
|
double baseY = user.getEyeY() - 0.1; // slightly below eye level (mouth)
|
||||||
|
double baseZ = user.getZ() + Math.cos(yawRad) * 0.5;
|
||||||
|
|
||||||
|
for (int p = 0; p < 8; p++) {
|
||||||
|
// randomize spread slightly
|
||||||
|
double offsetX = (RANDOM.nextDouble() - 0.5) * 0.15;
|
||||||
|
double offsetY = (RANDOM.nextDouble() - 0.5) * 0.1;
|
||||||
|
double offsetZ = (RANDOM.nextDouble() - 0.5) * 0.15;
|
||||||
|
|
||||||
|
// velocity: mostly upward, slight outward drift
|
||||||
|
double velX = (RANDOM.nextDouble() - 0.5) * 0.02;
|
||||||
|
double velY = 0.04 + RANDOM.nextDouble() * 0.03; // upward
|
||||||
|
double velZ = (RANDOM.nextDouble() - 0.5) * 0.02;
|
||||||
|
|
||||||
|
world.addParticle(
|
||||||
|
net.minecraft.particle.ParticleTypes.CAMPFIRE_COSY_SMOKE,
|
||||||
|
baseX + offsetX,
|
||||||
|
baseY + offsetY,
|
||||||
|
baseZ + offsetZ,
|
||||||
|
velX,
|
||||||
|
velY,
|
||||||
|
velZ
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,23 +4,33 @@ import net.fabricmc.api.EnvType;
|
|||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.minecraft.entity.*;
|
import net.minecraft.entity.*;
|
||||||
import net.minecraft.entity.damage.DamageSource;
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.damage.DamageType;
|
||||||
import net.minecraft.entity.data.DataTracker;
|
import net.minecraft.entity.data.DataTracker;
|
||||||
import net.minecraft.entity.data.TrackedData;
|
import net.minecraft.entity.data.TrackedData;
|
||||||
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.vehicle.BoatEntity;
|
import net.minecraft.entity.vehicle.BoatEntity;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.registry.RegistryKeys;
|
||||||
|
import net.minecraft.registry.entry.RegistryEntry;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.GameRules;
|
import net.minecraft.world.GameRules;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
public class PlaneEntity extends Entity {
|
import java.util.List;
|
||||||
|
|
||||||
|
import static dev.tggamesyt.szar.Szar.MOD_ID;
|
||||||
|
|
||||||
|
public class PlaneEntity extends Entity {
|
||||||
|
public static final RegistryKey<DamageType> PLANE_CRASH =
|
||||||
|
RegistryKey.of(RegistryKeys.DAMAGE_TYPE, new Identifier(MOD_ID, "plane_crash"));
|
||||||
private static final TrackedData<Float> ENGINE_TARGET =
|
private static final TrackedData<Float> ENGINE_TARGET =
|
||||||
DataTracker.registerData(PlaneEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
DataTracker.registerData(PlaneEntity.class, TrackedDataHandlerRegistry.FLOAT);
|
||||||
private static final TrackedData<Integer> DAMAGE_WOBBLE_TICKS =
|
private static final TrackedData<Integer> DAMAGE_WOBBLE_TICKS =
|
||||||
@@ -193,7 +203,36 @@ public class PlaneEntity extends Entity {
|
|||||||
|
|
||||||
boolean crash = (horizontalImpact > 1.5 && horizontalCollision) || (verticalImpact > explodeSpeed && verticalCollision);
|
boolean crash = (horizontalImpact > 1.5 && horizontalCollision) || (verticalImpact > explodeSpeed && verticalCollision);
|
||||||
if (crash) {
|
if (crash) {
|
||||||
getWorld().createExplosion(this, getX(), getY(), getZ(), 9.0f, World.ExplosionSourceType.TNT);
|
PlayerEntity pilot = getControllingPassenger();
|
||||||
|
|
||||||
|
RegistryEntry<DamageType> planeCrashType =
|
||||||
|
getWorld().getRegistryManager()
|
||||||
|
.get(RegistryKeys.DAMAGE_TYPE)
|
||||||
|
.entryOf(PLANE_CRASH);
|
||||||
|
|
||||||
|
float explosionRadius = 9.0f;
|
||||||
|
|
||||||
|
List<Entity> targets = getWorld().getOtherEntities(this, getBoundingBox().expand(explosionRadius));
|
||||||
|
if (pilot != null) targets.add(pilot); // make sure pilot is included
|
||||||
|
|
||||||
|
for (Entity entity : targets) {
|
||||||
|
if (!(entity instanceof LivingEntity living)) continue;
|
||||||
|
|
||||||
|
double dist = entity.getPos().distanceTo(getPos());
|
||||||
|
if (dist > explosionRadius) continue;
|
||||||
|
|
||||||
|
double exposure = 1.0;
|
||||||
|
double intensity = (1.0 - (dist / explosionRadius)) * exposure;
|
||||||
|
float damage = (float)((intensity * intensity + intensity) / 2.0 * 7.0 * explosionRadius + 1.0);
|
||||||
|
|
||||||
|
DamageSource crashSource = pilot != null && entity != pilot
|
||||||
|
? new DamageSource(planeCrashType, pilot) // "X was killed when Pilot crashed"
|
||||||
|
: new DamageSource(planeCrashType); // pilot just gets "X crashed their plane"
|
||||||
|
|
||||||
|
living.damage(crashSource, damage);
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorld().createExplosion(null, getX(), getY(), getZ(), explosionRadius, World.ExplosionSourceType.TNT);
|
||||||
remove(RemovalReason.KILLED);
|
remove(RemovalReason.KILLED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
142
src/main/java/dev/tggamesyt/szar/RadiationAreaEntity.java
Normal file
142
src/main/java/dev/tggamesyt/szar/RadiationAreaEntity.java
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||||
|
import net.minecraft.entity.effect.StatusEffects;
|
||||||
|
import net.minecraft.nbt.NbtCompound;
|
||||||
|
import net.minecraft.particle.DustParticleEffect;
|
||||||
|
import net.minecraft.particle.ParticleTypes;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RadiationAreaEntity extends Entity {
|
||||||
|
|
||||||
|
private int lifetime = 2400;
|
||||||
|
private float radius = 5.0F;
|
||||||
|
private int age = 0;
|
||||||
|
private int wave = 0; // 0 = full gravity, 1 = gravity then float, 2 = no gravity
|
||||||
|
|
||||||
|
public RadiationAreaEntity(EntityType<?> type, World world) {
|
||||||
|
super(type, world);
|
||||||
|
this.noClip = true;
|
||||||
|
this.setNoGravity(false); // default on, wave logic overrides
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLifetime(int ticks) { this.lifetime = ticks; }
|
||||||
|
public void setRadius(float r) { this.radius = r; }
|
||||||
|
public void setWave(int wave) {
|
||||||
|
this.wave = wave;
|
||||||
|
// wave 2 starts with no gravity immediately
|
||||||
|
if (wave == 2) this.setNoGravity(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
age++;
|
||||||
|
|
||||||
|
// ── Gravity behaviour per wave ──────────────────────────────────
|
||||||
|
if (wave == 0) {
|
||||||
|
// full gravity always — entity falls and stays on ground
|
||||||
|
this.setNoGravity(false);
|
||||||
|
if (!getWorld().isClient) {
|
||||||
|
Vec3d vel = this.getVelocity().add(0, -0.04, 0).multiply(0.98);
|
||||||
|
this.setVelocity(vel);
|
||||||
|
this.move(MovementType.SELF, vel);
|
||||||
|
}
|
||||||
|
} else if (wave == 1) {
|
||||||
|
if (age <= 45) {
|
||||||
|
// first 45 ticks: fall with gravity
|
||||||
|
this.setNoGravity(false);
|
||||||
|
if (!getWorld().isClient) {
|
||||||
|
Vec3d vel = this.getVelocity().add(0, -0.04, 0).multiply(0.98);
|
||||||
|
this.setVelocity(vel);
|
||||||
|
this.move(MovementType.SELF, vel);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// after 45 ticks: float in place
|
||||||
|
this.setNoGravity(true);
|
||||||
|
this.setVelocity(this.getVelocity().multiply(0.1)); // bleed off remaining velocity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// wave 2: noGravity already set to true, no movement needed
|
||||||
|
|
||||||
|
if (!getWorld().isClient) {
|
||||||
|
if (age >= lifetime) {
|
||||||
|
this.discard();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply radiation every second
|
||||||
|
if (age % 20 == 0) {
|
||||||
|
List<LivingEntity> nearby = getWorld().getEntitiesByClass(
|
||||||
|
LivingEntity.class,
|
||||||
|
new Box(getPos().subtract(radius, radius, radius),
|
||||||
|
getPos().add(radius, radius, radius)),
|
||||||
|
e -> e.squaredDistanceTo(this) < radius * radius
|
||||||
|
);
|
||||||
|
|
||||||
|
for (LivingEntity entity : nearby) {
|
||||||
|
entity.addStatusEffect(new StatusEffectInstance(
|
||||||
|
Szar.RADIATION, 200, 1, false, true, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// particles
|
||||||
|
ServerWorld serverWorld = (ServerWorld) getWorld();
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
double px = getX() + (getWorld().random.nextDouble() - 0.5) * radius * 2;
|
||||||
|
double py = getY() + getWorld().random.nextDouble() * 2;
|
||||||
|
double pz = getZ() + (getWorld().random.nextDouble() - 0.5) * radius * 2;
|
||||||
|
|
||||||
|
if (getPos().squaredDistanceTo(px, py, pz) > radius * radius) continue;
|
||||||
|
|
||||||
|
// green glowing dust particles
|
||||||
|
serverWorld.spawnParticles(
|
||||||
|
new DustParticleEffect(
|
||||||
|
new Vector3f(0.224f, 1.0f, 0.078f),
|
||||||
|
1.5F
|
||||||
|
),
|
||||||
|
px, py, pz, 1, 0, 0.02, 0, 0.0
|
||||||
|
);
|
||||||
|
|
||||||
|
// warped spore for extra green floaty effect
|
||||||
|
serverWorld.spawnParticles(ParticleTypes.WARPED_SPORE,
|
||||||
|
px, py, pz, 1, 0, 0.05, 0, 0.01);
|
||||||
|
|
||||||
|
// occasional smoke
|
||||||
|
if (getWorld().random.nextInt(10) == 0) {
|
||||||
|
serverWorld.spawnParticles(ParticleTypes.CAMPFIRE_COSY_SMOKE,
|
||||||
|
px, py + 1, pz, 1, 0, 0.05, 0, 0.01);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initDataTracker() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readCustomDataFromNbt(NbtCompound nbt) {
|
||||||
|
this.lifetime = nbt.getInt("Lifetime");
|
||||||
|
this.radius = nbt.getFloat("Radius");
|
||||||
|
this.age = nbt.getInt("Age");
|
||||||
|
this.wave = nbt.getInt("Wave");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeCustomDataToNbt(NbtCompound nbt) {
|
||||||
|
nbt.putInt("Lifetime", lifetime);
|
||||||
|
nbt.putFloat("Radius", radius);
|
||||||
|
nbt.putInt("Age", age);
|
||||||
|
nbt.putInt("Wave", wave);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1032,6 +1032,13 @@ public class Szar implements ModInitializer {
|
|||||||
new DrogEffect()
|
new DrogEffect()
|
||||||
);
|
);
|
||||||
public static final StatusEffect ARRESTED = Registry.register(Registries.STATUS_EFFECT, new Identifier(MOD_ID, "arrested"), new ArrestedEffect());
|
public static final StatusEffect ARRESTED = Registry.register(Registries.STATUS_EFFECT, new Identifier(MOD_ID, "arrested"), new ArrestedEffect());
|
||||||
|
public static final EntityType<RadiationAreaEntity> RADIATION_AREA = Registry.register(
|
||||||
|
Registries.ENTITY_TYPE,
|
||||||
|
new Identifier(MOD_ID, "radiation_area"),
|
||||||
|
FabricEntityTypeBuilder.create(SpawnGroup.MISC, RadiationAreaEntity::new)
|
||||||
|
.dimensions(EntityDimensions.fixed(0.5F, 0.5F))
|
||||||
|
.build()
|
||||||
|
);
|
||||||
public static final StatusEffect RADIATION = Registry.register(
|
public static final StatusEffect RADIATION = Registry.register(
|
||||||
Registries.STATUS_EFFECT,
|
Registries.STATUS_EFFECT,
|
||||||
new Identifier(MOD_ID, "radiation"),
|
new Identifier(MOD_ID, "radiation"),
|
||||||
|
|||||||
@@ -85,5 +85,8 @@
|
|||||||
"block.szar.roulette": "Roulette",
|
"block.szar.roulette": "Roulette",
|
||||||
"item.szar.firtana": "Firtana",
|
"item.szar.firtana": "Firtana",
|
||||||
"item.szar.hello": "Music Disc",
|
"item.szar.hello": "Music Disc",
|
||||||
"item.szar.hello.desc": "Alex Savage - OMFG - Hello (Dark Remix)"
|
"item.szar.hello.desc": "Alex Savage - OMFG - Hello (Dark Remix)",
|
||||||
|
|
||||||
|
"death.attack.plane_crash": "%1$s crashed their plane",
|
||||||
|
"death.attack.plane_crash.player": "%1$s was killed when %2$s crashed their plane"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,17 +7,51 @@
|
|||||||
},
|
},
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"from": [7, 0, 7],
|
"from": [7, 8.5, 7],
|
||||||
"to": [9, 12, 9],
|
"to": [9, 13.5, 9],
|
||||||
"rotation": {"angle": 0, "axis": "y", "origin": [7, 0, 7]},
|
"rotation": {"angle": 0, "axis": "y", "origin": [7, 8.5, 7]},
|
||||||
"faces": {
|
"faces": {
|
||||||
"north": {"uv": [0, 0, 2, 12], "texture": "#0"},
|
"north": {"uv": [0, 0, 2, 5], "texture": "#0"},
|
||||||
"east": {"uv": [2, 0, 4, 12], "texture": "#0"},
|
"east": {"uv": [2, 0, 4, 5], "texture": "#0"},
|
||||||
"south": {"uv": [4, 0, 6, 12], "texture": "#0"},
|
"south": {"uv": [4, 0, 6, 5], "texture": "#0"},
|
||||||
"west": {"uv": [6, 0, 8, 12], "texture": "#0"},
|
"west": {"uv": [6, 0, 8, 5], "texture": "#0"},
|
||||||
|
"up": {"uv": [10, 2, 8, 0], "texture": "#0"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from": [6.9, 2.4, 6.9],
|
||||||
|
"to": [9.1, 8.6, 9.1],
|
||||||
|
"rotation": {"angle": 0, "axis": "y", "origin": [6.9, 2.4, 6.9]},
|
||||||
|
"faces": {
|
||||||
|
"north": {"uv": [0, 5, 2, 12], "texture": "#0"},
|
||||||
|
"east": {"uv": [2, 5, 4, 12], "texture": "#0"},
|
||||||
|
"south": {"uv": [4, 5, 6, 12], "texture": "#0"},
|
||||||
|
"west": {"uv": [6, 5, 8, 12], "texture": "#0"},
|
||||||
"up": {"uv": [10, 2, 8, 0], "texture": "#0"},
|
"up": {"uv": [10, 2, 8, 0], "texture": "#0"},
|
||||||
"down": {"uv": [10, 2, 8, 4], "texture": "#0"}
|
"down": {"uv": [10, 2, 8, 4], "texture": "#0"}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"gui_light": "front",
|
||||||
|
"display": {
|
||||||
|
"thirdperson_righthand": {
|
||||||
|
"translation": [0, -2, 0]
|
||||||
|
},
|
||||||
|
"ground": {
|
||||||
|
"rotation": [90, 0, 0]
|
||||||
|
},
|
||||||
|
"gui": {
|
||||||
|
"rotation": [-67.5, 0, 45],
|
||||||
|
"scale": [1.5, 1.5, 1.5]
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"rotation": [90, 0, 0],
|
||||||
|
"translation": [0, 0, -16],
|
||||||
|
"scale": [1.6, 1.6, 1.6]
|
||||||
|
},
|
||||||
|
"fixed": {
|
||||||
|
"translation": [0, 0, -1.5],
|
||||||
|
"scale": [1.5, 1.5, 1.5]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"message_id": "plane_crash",
|
||||||
|
"scaling": "never",
|
||||||
|
"exhaustion": 0.0
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user