ah
This commit is contained in:
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
||||
yarn_mappings=1.20.1+build.10
|
||||
loader_version=0.18.3
|
||||
# Mod Properties
|
||||
mod_version=26.2.26.1
|
||||
mod_version=26.2.27
|
||||
maven_group=dev.tggamesyt
|
||||
archives_base_name=szar
|
||||
# Dependencies
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.EquipmentSlot;
|
||||
import net.minecraft.entity.ItemEntity;
|
||||
import net.minecraft.entity.TntEntity;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.ai.TargetPredicate;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.ai.goal.LookAroundGoal;
|
||||
@@ -15,13 +13,24 @@ import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.mob.PathAwareEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.LocalDifficulty;
|
||||
import net.minecraft.world.ServerWorldAccess;
|
||||
import net.minecraft.world.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class IslamTerrorist extends PathAwareEntity implements Arrestable{
|
||||
|
||||
private BlockPos targetCoreBlock = null; // the core block this mob is attacking
|
||||
private Vec3d taxiDirection;
|
||||
private Vec3d currentDirection = null; // direction plane is moving
|
||||
private BlockPos taxiTarget;
|
||||
private int flyStraightTicks = 0;
|
||||
private int planeTaxiTicks = 0;
|
||||
public static boolean arrestable = false;
|
||||
private int BlowUpCooldown = 0;
|
||||
private int panicTicks = 0;
|
||||
@@ -56,6 +65,108 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{
|
||||
super.tick();
|
||||
|
||||
if (BlowUpCooldown > 0) BlowUpCooldown--;
|
||||
|
||||
Entity vehicle = this.getVehicle();
|
||||
if (!(vehicle instanceof PlaneEntity plane) || targetCoreBlock == null) return;
|
||||
|
||||
Vec3d vel = plane.getVelocity();
|
||||
|
||||
// -------------------------
|
||||
// TAXI PHASE: ground, random direction
|
||||
// -------------------------
|
||||
if (planeTaxiTicks > 0) {
|
||||
planeTaxiTicks--;
|
||||
|
||||
if (taxiTarget != null) {
|
||||
Vec3d toTarget = Vec3d.ofCenter(taxiTarget).subtract(plane.getPos());
|
||||
if (toTarget.length() > 0.5) {
|
||||
Vec3d desired = toTarget.normalize().multiply(0.4);
|
||||
plane.setVelocity(vel.lerp(desired, 0.1));
|
||||
}
|
||||
}
|
||||
|
||||
// small lift near end
|
||||
if (planeTaxiTicks < 20) {
|
||||
plane.setVelocity(plane.getVelocity().x, 0.08, plane.getVelocity().z);
|
||||
}
|
||||
|
||||
// Face movement
|
||||
Vec3d look = plane.getVelocity().normalize();
|
||||
if (look.length() > 0) {
|
||||
plane.setYaw((float) Math.toDegrees(Math.atan2(-look.x, look.z)));
|
||||
plane.setPitch((float) -Math.toDegrees(Math.asin(look.y)));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// FLY STRAIGHT PHASE
|
||||
// -------------------------
|
||||
if (flyStraightTicks > 0) {
|
||||
flyStraightTicks--;
|
||||
|
||||
plane.setVelocity(currentDirection.x * 1.4, 0.25, currentDirection.z * 1.4);
|
||||
|
||||
Vec3d look = plane.getVelocity().normalize();
|
||||
if (look.length() > 0) {
|
||||
plane.setYaw((float) Math.toDegrees(Math.atan2(-look.x, look.z)));
|
||||
plane.setPitch((float) -Math.toDegrees(Math.asin(look.y)));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// HOMING PHASE
|
||||
// -------------------------
|
||||
Vec3d target = Vec3d.ofCenter(targetCoreBlock);
|
||||
Vec3d toTarget = target.subtract(plane.getPos());
|
||||
Vec3d desired = toTarget.normalize().multiply(1.8);
|
||||
|
||||
// Add small upward lift if below target
|
||||
if (plane.getY() < target.y - 10) {
|
||||
desired = desired.add(0, 0.2, 0);
|
||||
}
|
||||
|
||||
// Smooth turning toward target
|
||||
currentDirection = currentDirection.lerp(desired.normalize(), 0.03).normalize();
|
||||
|
||||
plane.setVelocity(currentDirection.multiply(1.8));
|
||||
|
||||
// Face movement
|
||||
Vec3d look = plane.getVelocity().normalize();
|
||||
if (look.length() > 0) {
|
||||
plane.setYaw((float) Math.toDegrees(Math.atan2(-look.x, look.z)));
|
||||
plane.setPitch((float) -Math.toDegrees(Math.asin(look.y)));
|
||||
}
|
||||
|
||||
// -------------------------
|
||||
// IMPACT
|
||||
// -------------------------
|
||||
if (!getWorld().isClient &&
|
||||
(plane.horizontalCollision || plane.verticalCollision)) {
|
||||
|
||||
getWorld().createExplosion(
|
||||
plane,
|
||||
plane.getX(),
|
||||
plane.getY(),
|
||||
plane.getZ(),
|
||||
7.0f,
|
||||
World.ExplosionSourceType.TNT
|
||||
);
|
||||
|
||||
plane.discard();
|
||||
this.discard();
|
||||
|
||||
BlockEntity be = getWorld().getBlockEntity(targetCoreBlock);
|
||||
if (be instanceof ObeliskCoreBlockEntity core) {
|
||||
core.setHasPlaneMob(false);
|
||||
core.markDirty();
|
||||
}
|
||||
|
||||
targetCoreBlock = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ================= VISIBILITY =================
|
||||
@@ -96,6 +207,19 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{
|
||||
this.velocityDirty = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath(DamageSource source) {
|
||||
super.onDeath(source);
|
||||
|
||||
if (targetCoreBlock == null) return;
|
||||
|
||||
BlockEntity be = getWorld().getBlockEntity(targetCoreBlock);
|
||||
if (be instanceof ObeliskCoreBlockEntity core) {
|
||||
core.setHasPlaneMob(false);
|
||||
core.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ================= DAMAGE =================
|
||||
|
||||
@@ -119,6 +243,70 @@ public class IslamTerrorist extends PathAwareEntity implements Arrestable{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityData initialize(
|
||||
ServerWorldAccess worldAccess,
|
||||
LocalDifficulty difficulty,
|
||||
SpawnReason spawnReason,
|
||||
@Nullable EntityData entityData,
|
||||
@Nullable NbtCompound entityNbt
|
||||
) {
|
||||
EntityData data = super.initialize(worldAccess, difficulty, spawnReason, entityData, entityNbt);
|
||||
|
||||
if (!(worldAccess instanceof ServerWorld world)) return data;
|
||||
|
||||
BlockPos corePos = findNearbyCoreBlock(this.getBlockPos(), 100);
|
||||
if (corePos == null) return data;
|
||||
|
||||
BlockEntity be = world.getBlockEntity(corePos);
|
||||
if (!(be instanceof ObeliskCoreBlockEntity core)) return data;
|
||||
|
||||
if (!core.hasPlaneMob() && world.random.nextInt(100) == 0) {
|
||||
|
||||
PlaneEntity plane = new PlaneEntity(Szar.PLANE_ENTITY_TYPE, world);
|
||||
plane.refreshPositionAndAngles(getX(), getY(), getZ(), getYaw(), getPitch());
|
||||
|
||||
world.spawnEntity(plane);
|
||||
this.startRiding(plane, true);
|
||||
|
||||
core.setHasPlaneMob(true);
|
||||
core.markDirty();
|
||||
|
||||
this.targetCoreBlock = corePos;
|
||||
|
||||
// Taxi + straight flight setup
|
||||
this.planeTaxiTicks = 60; // 3 seconds ground taxi
|
||||
this.flyStraightTicks = 40; // 2 seconds straight flight before homing
|
||||
|
||||
// Random horizontal direction
|
||||
float randomYaw = world.random.nextFloat() * 360f;
|
||||
this.currentDirection = Vec3d.fromPolar(0, randomYaw).normalize();
|
||||
|
||||
// Taxi target 20 blocks ahead in random direction
|
||||
this.taxiTarget = this.getBlockPos().add(
|
||||
(int)(currentDirection.x * 20),
|
||||
0,
|
||||
(int)(currentDirection.z * 20)
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private BlockPos findNearbyCoreBlock(BlockPos pos, int radius) {
|
||||
for (int dx = -radius; dx <= radius; dx++) {
|
||||
for (int dy = -radius; dy <= radius; dy++) {
|
||||
for (int dz = -radius; dz <= radius; dz++) {
|
||||
BlockPos check = pos.add(dx, dy, dz);
|
||||
if (getWorld().getBlockState(check).getBlock() == Szar.OBELISK_CORE) {
|
||||
return check;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 🔴 Flee from only specific victim, hide behind others
|
||||
private static class FleeSpecificPlayerGoal extends Goal {
|
||||
private final IslamTerrorist mob;
|
||||
|
||||
@@ -1,17 +1,28 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockEntityProvider;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.explosion.Explosion;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ObeliskCoreBlock extends Block {
|
||||
public class ObeliskCoreBlock extends Block implements BlockEntityProvider {
|
||||
|
||||
public ObeliskCoreBlock(Settings settings) {
|
||||
super(settings);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ObeliskCoreBlockEntity createBlockEntity(BlockPos pos, BlockState state) {
|
||||
return new ObeliskCoreBlockEntity(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyedByExplosion(World world, BlockPos pos, Explosion explosion) {
|
||||
super.onDestroyedByExplosion(world, pos, explosion);
|
||||
@@ -19,5 +30,12 @@ public class ObeliskCoreBlock extends Block {
|
||||
if (!(world instanceof ServerWorld serverWorld)) return;
|
||||
|
||||
TwoTowersUtil.grantNearbyAdvancement(serverWorld, pos, 100);
|
||||
|
||||
BlockEntity be = world.getBlockEntity(pos);
|
||||
if (be instanceof ObeliskCoreBlockEntity core) {
|
||||
core.setHasPlaneMob(false); // reset in case a plane was active
|
||||
core.markDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
31
src/main/java/dev/tggamesyt/szar/ObeliskCoreBlockEntity.java
Normal file
31
src/main/java/dev/tggamesyt/szar/ObeliskCoreBlockEntity.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package dev.tggamesyt.szar;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class ObeliskCoreBlockEntity extends BlockEntity {
|
||||
|
||||
private boolean hasPlaneMob = false;
|
||||
|
||||
public ObeliskCoreBlockEntity(BlockPos pos, BlockState state) {
|
||||
super(Szar.OBELISK_CORE_ENTITY, pos, state);
|
||||
}
|
||||
|
||||
// NBT serialization
|
||||
@Override
|
||||
public void writeNbt(NbtCompound nbt) {
|
||||
super.writeNbt(nbt);
|
||||
nbt.putBoolean("hasPlaneMob", hasPlaneMob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNbt(NbtCompound nbt) {
|
||||
super.readNbt(nbt);
|
||||
hasPlaneMob = nbt.getBoolean("hasPlaneMob");
|
||||
}
|
||||
|
||||
public boolean hasPlaneMob() { return hasPlaneMob; }
|
||||
public void setHasPlaneMob(boolean value) { hasPlaneMob = value; }
|
||||
}
|
||||
@@ -17,12 +17,15 @@ import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
|
||||
import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper;
|
||||
import net.minecraft.advancement.Advancement;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.damage.DamageType;
|
||||
import net.minecraft.entity.data.DataTracker;
|
||||
@@ -649,6 +652,26 @@ public class Szar implements ModInitializer {
|
||||
return count;
|
||||
})
|
||||
);
|
||||
dispatcher.register(
|
||||
LiteralArgumentBuilder.<ServerCommandSource>literal("getnearestobeliskcore")
|
||||
.requires(context -> context.hasPermissionLevel(2))
|
||||
.executes(context -> {
|
||||
ServerCommandSource source = context.getSource();
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
assert source.getEntity() != null;
|
||||
ObeliskCoreBlockEntity nearest = findNearestObelisk(world, source.getEntity().getBlockPos(), 100);
|
||||
if (nearest != null) {
|
||||
boolean hasPlane = nearest.hasPlaneMob();
|
||||
|
||||
source.sendMessage(Text.literal(
|
||||
"HasPlane: " + hasPlane
|
||||
));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
);
|
||||
});
|
||||
Registry.register(
|
||||
Registries.ITEM,
|
||||
@@ -656,6 +679,36 @@ public class Szar implements ModInitializer {
|
||||
new BlockItem(OBELISK_CORE, new Item.Settings())
|
||||
);
|
||||
}
|
||||
public static ObeliskCoreBlockEntity findNearestObelisk(ServerWorld world, BlockPos center, int radius) {
|
||||
ObeliskCoreBlockEntity closest = null;
|
||||
double closestDistance = Double.MAX_VALUE;
|
||||
|
||||
BlockPos.Mutable mutable = new BlockPos.Mutable();
|
||||
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
|
||||
mutable.set(center.getX() + x,
|
||||
center.getY() + y,
|
||||
center.getZ() + z);
|
||||
|
||||
BlockEntity be = world.getBlockEntity(mutable);
|
||||
|
||||
if (be instanceof ObeliskCoreBlockEntity obelisk) {
|
||||
double distance = center.getSquaredDistance(mutable);
|
||||
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
closest = obelisk;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
public static final Item CNDM = Registry.register(
|
||||
Registries.ITEM,
|
||||
new Identifier(MOD_ID, "cndm"),
|
||||
@@ -691,7 +744,14 @@ public class Szar implements ModInitializer {
|
||||
.copy(Blocks.DIRT) // soft block
|
||||
.strength(0.5f, 1.0f) // very easy to break, low blast resistance
|
||||
)
|
||||
|
||||
);
|
||||
public static final BlockEntityType<ObeliskCoreBlockEntity> OBELISK_CORE_ENTITY = Registry.register(
|
||||
Registries.BLOCK_ENTITY_TYPE,
|
||||
new Identifier(MOD_ID, "obelisk_core"),
|
||||
FabricBlockEntityTypeBuilder.create(
|
||||
ObeliskCoreBlockEntity::new,
|
||||
OBELISK_CORE // block(s) this BE is linked to
|
||||
).build(null)
|
||||
);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user