Gun firing AI improvements and skeletons are only given guns when soot is high enough, higher soot adds more powerful weapons

This commit is contained in:
George Paton 2024-10-24 15:17:31 +11:00
parent b6bab36c7f
commit 5103577f1d
2 changed files with 153 additions and 75 deletions

View File

@ -13,72 +13,124 @@ import net.minecraft.item.ItemStack;
public class EntityAIFireGun extends EntityAIBase {
private final EntityLiving host;
private final EntityLiving host;
private double attackMoveSpeed = 1.0D;
private double attackMoveSpeed = 1.0D; // how fast we move while in this state
private double maxRange = 20; // how far our target can be before we stop shooting
private int burstTime = 6; // maximum number of ticks in a burst (for automatic weapons)
private int minWait = 10; // minimum number of ticks to wait between bursts/shots
private int maxWait = 60; // maximum number of ticks to wait between bursts/shots
private float inaccuracy = 30; // how many degrees of inaccuracy does the AI have
private int attackTimer = 0;
private double maxRange = 20;
public EntityAIFireGun(EntityLiving host) {
this.host = host;
}
// state timers
private int attackTimer = 0;
private FireState state = FireState.IDLE;
private int stateTimer = 0;
@Override
public boolean shouldExecute() {
return host.getAttackTarget() != null && getYerGun() != null;
}
private static enum FireState {
IDLE,
WAIT,
FIRING,
RELOADING,
}
public EntityAIFireGun(EntityLiving host) {
this.host = host;
}
@Override
public void updateTask() {
EntityLivingBase target = host.getAttackTarget();
ItemStack stack = host.getHeldItem();
ItemGunBaseNT gun = getYerGun();
@Override
public boolean shouldExecute() {
return host.getAttackTarget() != null && getYerGun() != null;
}
gun.onUpdate(stack, host.worldObj, host, 0, true);
@Override
public void updateTask() {
EntityLivingBase target = host.getAttackTarget();
ItemStack stack = host.getHeldItem();
ItemGunBaseNT gun = getYerGun();
double distanceToTargetSquared = host.getDistanceSq(target.posX, target.posY, target.posZ);
boolean canSeeTarget = host.getEntitySenses().canSee(target);
gun.onUpdate(stack, host.worldObj, host, 0, true);
if(canSeeTarget) {
attackTimer++;
} else {
attackTimer = 0;
}
double distanceToTargetSquared = host.getDistanceSq(target.posX, target.posY, target.posZ);
boolean canSeeTarget = host.getEntitySenses().canSee(target);
if(distanceToTargetSquared < maxRange * maxRange && attackTimer > 20) {
host.getNavigator().clearPathEntity();
} else {
host.getNavigator().tryMoveToEntityLiving(target, attackMoveSpeed);
}
if(canSeeTarget) {
attackTimer++;
} else {
attackTimer = 0;
}
host.getLookHelper().setLookPositionWithEntity(target, 30.0F, 30.0F);
if(distanceToTargetSquared < maxRange * maxRange && attackTimer > 20) {
host.getNavigator().clearPathEntity();
} else {
host.getNavigator().tryMoveToEntityLiving(target, attackMoveSpeed);
}
if(canSeeTarget && distanceToTargetSquared < maxRange * maxRange) {
GunConfig config = gun.getConfig(stack, 0);
Receiver rec = config.getReceivers(stack)[0];
if(rec.getMagazine(stack).getAmount(stack) <= 0) {
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_PRIMARY, false);
gun.handleKeybind(host, null, stack, EnumKeybind.RELOAD, true);
} else if(ItemGunBaseNT.getState(stack, 0) == GunState.IDLE) {
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_PRIMARY, true);
gun.handleKeybind(host, null, stack, EnumKeybind.RELOAD, false);
} else {
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_PRIMARY, false);
gun.handleKeybind(host, null, stack, EnumKeybind.RELOAD, false);
}
} else {
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_PRIMARY, false);
gun.handleKeybind(host, null, stack, EnumKeybind.RELOAD, false);
}
}
host.getLookHelper().setLookPositionWithEntity(target, 30.0F, 30.0F);
public ItemGunBaseNT getYerGun() {
ItemStack stack = host.getHeldItem();
stateTimer--;
if(stateTimer < 0) {
stateTimer = 0;
if(stack == null || !(stack.getItem() instanceof ItemGunBaseNT)) return null;
if(state == FireState.WAIT) {
updateState(FireState.IDLE, 0, gun, stack);
} else if(state != FireState.IDLE) {
updateState(FireState.WAIT, host.worldObj.rand.nextInt(maxWait - minWait) + minWait, gun, stack);
}
} else if(state == FireState.FIRING) {
// Keep the trigger held throughout the duration of firing
updateKeybind(gun, stack, EnumKeybind.GUN_PRIMARY);
}
return (ItemGunBaseNT) stack.getItem();
}
if(canSeeTarget && distanceToTargetSquared < maxRange * maxRange) {
if(state == FireState.IDLE) {
GunConfig config = gun.getConfig(stack, 0);
Receiver rec = config.getReceivers(stack)[0];
if(rec.getMagazine(stack).getAmount(stack) <= 0) {
updateState(FireState.RELOADING, 40, gun, stack);
} else if(ItemGunBaseNT.getState(stack, 0) == GunState.IDLE) {
updateState(FireState.FIRING, host.worldObj.rand.nextInt(burstTime), gun, stack);
}
}
}
}
private void updateState(FireState toState, int time, ItemGunBaseNT gun, ItemStack stack) {
state = toState;
stateTimer = time;
switch(state) {
case FIRING: updateKeybind(gun, stack, EnumKeybind.GUN_PRIMARY);
case RELOADING: updateKeybind(gun, stack, EnumKeybind.RELOAD);
default: clearKeybinds(gun, stack); break;
}
}
private void clearKeybinds(ItemGunBaseNT gun, ItemStack stack) {
updateKeybind(gun, stack, null);
}
private void updateKeybind(ItemGunBaseNT gun, ItemStack stack, EnumKeybind bind) {
// Turn body to face firing direction, since the gun is attached to that, not the head
// Also apply accuracy debuff just before firing
if(bind != null && bind != EnumKeybind.RELOAD) {
host.rotationYawHead += (host.worldObj.rand.nextFloat() - 0.5F) * 2 * inaccuracy;
host.rotationPitch += (host.worldObj.rand.nextFloat() - 0.5F) * 2 * inaccuracy;
host.rotationYaw = host.rotationYawHead;
}
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_PRIMARY, bind == EnumKeybind.GUN_PRIMARY);
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_SECONDARY, bind == EnumKeybind.GUN_SECONDARY);
gun.handleKeybind(host, null, stack, EnumKeybind.GUN_TERTIARY, bind == EnumKeybind.GUN_TERTIARY);
gun.handleKeybind(host, null, stack, EnumKeybind.RELOAD, bind == EnumKeybind.RELOAD);
}
public ItemGunBaseNT getYerGun() {
ItemStack stack = host.getHeldItem();
if(stack == null || !(stack.getItem() instanceof ItemGunBaseNT)) return null;
return (ItemGunBaseNT) stack.getItem();
}
}

View File

@ -54,6 +54,7 @@ import com.hbm.items.armor.ItemModShackles;
import com.hbm.items.food.ItemConserve.EnumFoodType;
import com.hbm.items.tool.ItemGuideBook.BookType;
import com.hbm.items.weapon.ItemGunBase;
import com.hbm.items.weapon.sedna.ItemGunBaseNT;
import com.hbm.lib.HbmCollection;
import com.hbm.lib.ModDamageSource;
import com.hbm.lib.RefStrings;
@ -65,14 +66,7 @@ import com.hbm.saveddata.AuxSavedData;
import com.hbm.tileentity.machine.TileEntityMachineRadarNT;
import com.hbm.tileentity.network.RTTYSystem;
import com.hbm.tileentity.network.RequestNetwork;
import com.hbm.util.AchievementHandler;
import com.hbm.util.ArmorRegistry;
import com.hbm.util.ArmorUtil;
import com.hbm.util.ContaminationUtil;
import com.hbm.util.EnchantmentUtil;
import com.hbm.util.EnumUtil;
import com.hbm.util.InventoryUtil;
import com.hbm.util.ShadyUtil;
import com.hbm.util.*;
import com.hbm.util.ArmorRegistry.HazardClass;
import com.hbm.world.generator.TimedGenerator;
@ -89,8 +83,10 @@ import net.minecraft.block.Block;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.EntityAITasks;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.EntityCaveSpider;
@ -116,13 +112,7 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.Potion;
import net.minecraft.potion.PotionEffect;
import net.minecraft.tileentity.TileEntitySign;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatStyle;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.FoodStats;
import net.minecraft.util.MathHelper;
import net.minecraft.util.Vec3;
import net.minecraft.util.*;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import net.minecraftforge.common.util.ForgeDirection;
@ -423,12 +413,48 @@ public class ModEventHandler {
}
if(rand.nextInt(64) == 0)
entity.setCurrentItemOrArmor(3, new ItemStack(ModItems.steel_plate, 1, world.rand.nextInt(ModItems.steel_plate.getMaxDamage())));
// Give them a gun and the AI task to fire it
entity.setCurrentItemOrArmor(0, new ItemStack(ModItems.gun_am180));
float soot = PollutionHandler.getPollution(entity.worldObj, MathHelper.floor_double(event.x), MathHelper.floor_double(event.y), MathHelper.floor_double(event.z), PollutionType.SOOT);
ItemStack bowReplacement = getSkelegun(soot, entity.worldObj.rand);
if(bowReplacement != null) {
entity.setCurrentItemOrArmor(0, bowReplacement);
addFireTask((EntityLiving) entity);
}
}
}
EntitySkeleton skeleton = (EntitySkeleton) entity;
skeleton.tasks.addTask(3, new EntityAIFireGun(skeleton));
private static ItemStack getSkelegun(float soot, Random rand) {
if(rand.nextDouble() > Math.log(soot) * 0.25) return null;
ArrayList<WeightedRandomObject> pool = new ArrayList<WeightedRandomObject>();
pool.add(new WeightedRandomObject(new ItemStack(ModItems.gun_heavy_revolver), 12));
if(soot > 8) pool.add(new WeightedRandomObject(new ItemStack(ModItems.gun_am180), 4));
WeightedRandomObject selected = (WeightedRandomObject) WeightedRandom.getRandomItem(rand, pool);
return selected.asStack();
}
// these fucking tasks keep stacking on top of themselves
private static void addFireTask(EntityLiving entity) {
for(Object entry : entity.tasks.taskEntries) {
EntityAITasks.EntityAITaskEntry task = (EntityAITasks.EntityAITaskEntry) entry;
if(task.action instanceof EntityAIFireGun) return;
}
entity.tasks.addTask(3, new EntityAIFireGun(entity));
}
@SubscribeEvent
public void addAITasks(EntityJoinWorldEvent event) {
if(event.world.isRemote || !(event.entity instanceof EntityLiving)) return;
EntityLiving living = (EntityLiving) event.entity;
ItemStack held = living.getHeldItem();
if(held != null && held.getItem() instanceof ItemGunBaseNT) {
addFireTask(living);
}
}