From da3db5fb07e8393bf9a33553c16ffc7200bf21a3 Mon Sep 17 00:00:00 2001 From: Shinare Date: Thu, 10 Apr 2025 17:31:42 +0300 Subject: [PATCH] Fixing archers not following warband leader --- .../MixinLOTREntityAIAttackOnCollide.java | 34 +++-- ...REntityAINearestAttackableTargetBasic.java | 28 ++--- .../mixins/MixinLOTREntityAIRangedAttack.java | 119 ++++++++++++++++++ .../zivilon/cinder_loe/util/Utilities.java | 9 ++ .../cinder_loe/world/event/Warband.java | 33 +++++ 5 files changed, 189 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java index a4af150..b671c2d 100644 --- a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIAttackOnCollide.java @@ -4,6 +4,7 @@ import com.zivilon.cinder_loe.CinderLoE; import com.zivilon.cinder_loe.client.model.*; import com.zivilon.cinder_loe.entity.Renegade; import com.zivilon.cinder_loe.util.IEntityLivingBase; +import com.zivilon.cinder_loe.util.Utilities; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -27,35 +28,41 @@ import java.util.UUID; @Mixin(LOTREntityAIAttackOnCollide.class) public class MixinLOTREntityAIAttackOnCollide { - @Shadow + @Shadow(remap = false) protected World worldObj; - @Shadow + @Shadow(remap = false) protected EntityCreature theOwner; - @Shadow + @Shadow(remap = false) protected EntityLivingBase attackTarget; - @Shadow + @Shadow(remap = false) protected int attackTick; - @Shadow + @Shadow(remap = false) protected void updateLookAndPathing() {} public UUID leader_id; public Entity leader; @Overwrite public void updateTask() { + if (warband_task()) return; + update_vanilla_task(); + } + + private boolean warband_task() { EntityCreature entity = this.theOwner; UUID leader_id = ((IEntityLivingBase)entity).get_warband_uuid(); if (leader_id != null) { if (leader == null) - leader = find_entity_by_uuid(entity.worldObj, leader_id); + leader = Utilities.find_entity_by_uuid(entity.worldObj, leader_id); if (leader != null && entity.getDistanceSqToEntity(leader) > 576.0D) { entity.setAttackTarget(null); + ((IEntityLivingBase)entity).set_follow_target(leader); entity.getNavigator().tryMoveToEntityLiving(leader, 1.3D); - return; // Return here to not run default logic + return true; // Return here to not run default logic } } - - update_vanilla_task(); + ((IEntityLivingBase)entity).set_follow_target(null); + return false; } private void update_vanilla_task() { @@ -95,13 +102,4 @@ public class MixinLOTREntityAIAttackOnCollide { this.theOwner.swingItem(); } } - - private Entity find_entity_by_uuid(World world, UUID uuid) { - for (Object obj : world.loadedEntityList) { - if (obj instanceof Entity && uuid.equals(((Entity) obj).getUniqueID())) { - return (Entity)obj; - } - } - return null; - } } diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java index a3e8f1f..2c9e518 100644 --- a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAINearestAttackableTargetBasic.java @@ -3,6 +3,7 @@ package com.zivilon.cinder_loe.mixins; import com.zivilon.cinder_loe.entity.Renegade; import com.zivilon.cinder_loe.potion.LoEPotions; import com.zivilon.cinder_loe.util.IEntityLivingBase; +import com.zivilon.cinder_loe.util.Utilities; import lotr.common.LOTRLevelData; import lotr.common.LOTRMod; @@ -51,25 +52,29 @@ public abstract class MixinLOTREntityAINearestAttackableTargetBasic extends Enti @Overwrite(remap = true) public boolean shouldExecute() { + if (warband_should_execute()) return false; + return original_should_execute(); + } + + private boolean warband_should_execute() { EntityCreature self = taskOwner; - if (!(self instanceof IEntityLivingBase)) return original_should_execute(); + if (!(self instanceof IEntityLivingBase)) return false; UUID leader_id = ((IEntityLivingBase) self).get_warband_uuid(); - if (leader_id == null) return original_should_execute(); + if (leader_id == null) return false; - Entity leader = find_entity_by_uuid(self.worldObj, leader_id); - if (leader == null) return original_should_execute(); + Entity leader = Utilities.find_entity_by_uuid(self.worldObj, leader_id); + if (leader == null) return false; double distance_squared = self.getDistanceSqToEntity(leader); if (distance_squared > 576.0D) { self.setAttackTarget(null); self.getNavigator().tryMoveToEntityLiving(leader, 1.3D); - return false; + return true; } - return original_should_execute(); + return false; } - public boolean original_should_execute() { if (this.targetChance > 0 && this.taskOwner.getRNG().nextInt(this.targetChance) != 0) return false; @@ -96,15 +101,6 @@ public abstract class MixinLOTREntityAINearestAttackableTargetBasic extends Enti return true; } - private Entity find_entity_by_uuid(World world, UUID uuid) { - for (Object obj : world.loadedEntityList) { - if (obj instanceof Entity && uuid.equals(((Entity) obj).getUniqueID())) { - return (Entity)obj; - } - } - return null; - } - /** * @author Shinare * @reason Added corrupting potion effect that makes all NPCs hostile diff --git a/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java new file mode 100644 index 0000000..dad0ebb --- /dev/null +++ b/src/main/java/com/zivilon/cinder_loe/mixins/MixinLOTREntityAIRangedAttack.java @@ -0,0 +1,119 @@ +package com.zivilon.cinder_loe.mixins; + +import com.zivilon.cinder_loe.CinderLoE; +import com.zivilon.cinder_loe.client.model.*; +import com.zivilon.cinder_loe.entity.Renegade; +import com.zivilon.cinder_loe.util.IEntityLivingBase; +import com.zivilon.cinder_loe.util.Utilities; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Overwrite; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.EntityCreature; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.IEntityLivingData; +import net.minecraft.entity.IRangedAttackMob; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.util.MathHelper; +import net.minecraft.util.Vec3; + +import lotr.common.entity.npc.LOTREntityNPC; +import lotr.common.entity.ai.LOTREntityAIRangedAttack; +import lotr.common.item.LOTRItemSpear; +import lotr.common.item.LOTRWeaponStats; + +import java.util.UUID; + +@Mixin(LOTREntityAIRangedAttack.class) +public class MixinLOTREntityAIRangedAttack { + + @Shadow(remap = false) + private EntityLiving theOwner; + @Shadow(remap = false) + private IRangedAttackMob theOwnerRanged; + @Shadow(remap = false) + private EntityLivingBase attackTarget; + @Shadow(remap = false) + private int rangedAttackTime; + @Shadow(remap = false) + private double moveSpeed; + @Shadow(remap = false) + private double moveSpeedFlee = 1.5D; + @Shadow(remap = false) + private int repathDelay; + @Shadow(remap = false) + private int attackTimeMin; + @Shadow(remap = false) + private int attackTimeMax; + @Shadow(remap = false) + private float attackRange; + @Shadow(remap = false) + private float attackRangeSq; + @Shadow(remap = false) + public static Vec3 findPositionAwayFrom(EntityLivingBase entity, EntityLivingBase target, int min, int max) {return null;} + + public UUID leader_id; + public Entity leader; + + @Overwrite + public void updateTask() { + if (warband_task()) return; + update_vanilla_task(); + } + + private boolean warband_task() { + EntityLiving entity = this.theOwner; + UUID leader_id = ((IEntityLivingBase)entity).get_warband_uuid(); + + if (leader_id != null) { + if (leader == null) + leader = Utilities.find_entity_by_uuid(entity.worldObj, leader_id); + if (leader != null && entity.getDistanceSqToEntity(leader) > 576.0D) { + entity.setAttackTarget(null); + entity.getNavigator().tryMoveToEntityLiving(leader, 1.3D); + return true; // Return here to not run default logic + } + } + return false; + } + + private void update_vanilla_task() { + double distanceSq = this.theOwner.getDistanceSq(this.attackTarget.posX, this.attackTarget.boundingBox.minY, this.attackTarget.posZ); + boolean canSee = this.theOwner.getEntitySenses().canSee((Entity)this.attackTarget); + if (canSee) { + this.repathDelay++; + } else { + this.repathDelay = 0; + } + if (distanceSq <= this.attackRangeSq) { + if (this.theOwner.getDistanceSqToEntity((Entity)this.attackTarget) < 25.0D) { + Vec3 vec = findPositionAwayFrom((EntityLivingBase)this.theOwner, this.attackTarget, 8, 16); + if (vec != null) + this.theOwner.getNavigator().tryMoveToXYZ(vec.xCoord, vec.yCoord, vec.zCoord, this.moveSpeedFlee); + } else if (this.repathDelay >= 20) { + this.theOwner.getNavigator().clearPathEntity(); + this.repathDelay = 0; + } + } else { + this.theOwner.getNavigator().tryMoveToEntityLiving((Entity)this.attackTarget, this.moveSpeed); + } + this.theOwner.getLookHelper().setLookPositionWithEntity((Entity)this.attackTarget, 30.0F, 30.0F); + this.rangedAttackTime--; + if (this.rangedAttackTime == 0) { + if (distanceSq > this.attackRangeSq || !canSee) + return; + float distanceRatio = MathHelper.sqrt_double(distanceSq) / this.attackRange; + float power = distanceRatio; + power = MathHelper.clamp_float(power, 0.1F, 1.0F); + this.theOwnerRanged.attackEntityWithRangedAttack(this.attackTarget, power); + this.rangedAttackTime = MathHelper.floor_float(distanceRatio * (this.attackTimeMax - this.attackTimeMin) + this.attackTimeMin); + } else if (this.rangedAttackTime < 0) { + float distanceRatio = MathHelper.sqrt_double(distanceSq) / this.attackRange; + this.rangedAttackTime = MathHelper.floor_float(distanceRatio * (this.attackTimeMax - this.attackTimeMin) + this.attackTimeMin); + } + } +} diff --git a/src/main/java/com/zivilon/cinder_loe/util/Utilities.java b/src/main/java/com/zivilon/cinder_loe/util/Utilities.java index 8f9f5fe..d38ee6b 100644 --- a/src/main/java/com/zivilon/cinder_loe/util/Utilities.java +++ b/src/main/java/com/zivilon/cinder_loe/util/Utilities.java @@ -47,6 +47,7 @@ import net.minecraft.nbt.NBTTagString; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; public class Utilities { @@ -329,4 +330,12 @@ public class Utilities { } return true; } + public static Entity find_entity_by_uuid(World world, UUID uuid) { + for (Object obj : world.loadedEntityList) { + if (obj instanceof Entity && uuid.equals(((Entity) obj).getUniqueID())) { + return (Entity)obj; + } + } + return null; + } } diff --git a/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java b/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java index 07687a8..cddfa70 100644 --- a/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java +++ b/src/main/java/com/zivilon/cinder_loe/world/event/Warband.java @@ -24,8 +24,11 @@ import lotr.common.LOTRDimension; import lotr.common.LOTRMod; import lotr.common.entity.npc.LOTRSpeech; import lotr.common.entity.npc.LOTREntityNPC; +import lotr.common.fac.LOTRFaction; import lotr.common.world.biome.LOTRBiome; import lotr.common.world.map.LOTRWaypoint; +import lotr.common.world.map.LOTRConquestGrid; +import lotr.common.world.map.LOTRConquestZone; import java.util.ArrayList; import java.util.List; @@ -147,6 +150,7 @@ public class Warband { } }).start(); broadcast_warband(world, warband.faction.warband_name, warband.direction, warband.waypoint_name); + do_radial_conquest(world, warband.x, warband.z, warband.faction.faction, 50); last_warband_timestamp = System.currentTimeMillis() / 1000L; } public static void spawn_boss_entity(Warband warband, int x, int y, int z) { @@ -241,4 +245,33 @@ public class Warband { LOTRSpeech.messageAllPlayersInWorld(world, message); } + + public static void do_radial_conquest(World world, int posX, int posZ, LOTRFaction faction, float amount) { + if (!LOTRConquestGrid.conquestEnabled(world)) { + return; + } + + LOTRConquestZone zone = LOTRConquestGrid.getZoneByWorldCoords(posX, posZ); + if (zone == null || zone.isDummyZone) { + return; + } + + float current_strength = zone.getConquestStrength(faction, world); + float target_strength = current_strength + amount; + if (target_strength > 100000.0F) { + amount = 100000.0F - current_strength; + } else if (target_strength < 0.0F) { + amount = -current_strength; + } + + if (amount == 0.0F) { + return; + } + + if (amount < 0.0F) { + LOTRConquestGrid.doRadialConquest(world, zone, null, null, faction, -amount, -amount); + } else { + LOTRConquestGrid.doRadialConquest(world, zone, null, faction, null, amount, amount); + } + } }