|
| 1 | +package com.solegendary.reignofnether.unit.units.neutral; |
| 2 | + |
| 3 | +import com.solegendary.reignofnether.ability.Ability; |
| 4 | +import com.solegendary.reignofnether.hud.AbilityButton; |
| 5 | +import com.solegendary.reignofnether.resources.ResourceCost; |
| 6 | +import com.solegendary.reignofnether.resources.ResourceCosts; |
| 7 | +import com.solegendary.reignofnether.unit.Checkpoint; |
| 8 | +import com.solegendary.reignofnether.unit.goals.*; |
| 9 | +import com.solegendary.reignofnether.unit.interfaces.AttackerUnit; |
| 10 | +import com.solegendary.reignofnether.unit.interfaces.Unit; |
| 11 | +import com.solegendary.reignofnether.util.Faction; |
| 12 | +import net.minecraft.core.BlockPos; |
| 13 | +import net.minecraft.nbt.CompoundTag; |
| 14 | +import net.minecraft.network.syncher.EntityDataAccessor; |
| 15 | +import net.minecraft.network.syncher.EntityDataSerializers; |
| 16 | +import net.minecraft.network.syncher.SynchedEntityData; |
| 17 | +import net.minecraft.sounds.SoundEvents; |
| 18 | +import net.minecraft.world.DifficultyInstance; |
| 19 | +import net.minecraft.world.entity.*; |
| 20 | +import net.minecraft.world.entity.ai.attributes.AttributeSupplier; |
| 21 | +import net.minecraft.world.entity.ai.attributes.Attributes; |
| 22 | +import net.minecraft.world.entity.ai.goal.FloatGoal; |
| 23 | +import net.minecraft.world.entity.ai.goal.Goal; |
| 24 | +import net.minecraft.world.entity.animal.PolarBear; |
| 25 | +import net.minecraft.world.entity.animal.Rabbit; |
| 26 | +import net.minecraft.world.entity.item.ItemEntity; |
| 27 | +import net.minecraft.world.entity.monster.Monster; |
| 28 | +import net.minecraft.world.item.ItemStack; |
| 29 | +import net.minecraft.world.level.Level; |
| 30 | +import net.minecraft.world.level.ServerLevelAccessor; |
| 31 | +import net.minecraft.world.level.block.state.BlockState; |
| 32 | + |
| 33 | +import javax.annotation.Nullable; |
| 34 | +import java.util.ArrayList; |
| 35 | +import java.util.List; |
| 36 | + |
| 37 | +// intentionally OP killer rabbit - spawn with cheat 'thebeastofcaerbannog' |
| 38 | + |
| 39 | +public class KillerRabbitUnit extends Rabbit implements Unit, AttackerUnit { |
| 40 | + // region |
| 41 | + private BlockPos anchorPos = new BlockPos(0,0,0); |
| 42 | + public void setAnchor(BlockPos bp) { anchorPos = bp; } |
| 43 | + public BlockPos getAnchor() { return anchorPos; } |
| 44 | + |
| 45 | + private final ArrayList<Checkpoint> checkpoints = new ArrayList<>(); |
| 46 | + public ArrayList<Checkpoint> getCheckpoints() { return checkpoints; }; |
| 47 | + |
| 48 | + public GarrisonGoal getGarrisonGoal() { return null; } |
| 49 | + public boolean canGarrison() { return getGarrisonGoal() != null; } |
| 50 | + |
| 51 | + UsePortalGoal usePortalGoal; |
| 52 | + public UsePortalGoal getUsePortalGoal() { return usePortalGoal; } |
| 53 | + public boolean canUsePortal() { return getUsePortalGoal() != null; } |
| 54 | + |
| 55 | + public Faction getFaction() {return Faction.NONE;} |
| 56 | + public List<AbilityButton> getAbilityButtons() {return abilityButtons;}; |
| 57 | + public List<Ability> getAbilities() {return abilities;} |
| 58 | + public List<ItemStack> getItems() {return items;}; |
| 59 | + public MoveToTargetBlockGoal getMoveGoal() {return moveGoal;} |
| 60 | + public SelectedTargetGoal<? extends LivingEntity> getTargetGoal() {return targetGoal;} |
| 61 | + public ReturnResourcesGoal getReturnResourcesGoal() {return returnResourcesGoal;} |
| 62 | + public int getMaxResources() {return maxResources;} |
| 63 | + |
| 64 | + private MoveToTargetBlockGoal moveGoal; |
| 65 | + private SelectedTargetGoal<? extends LivingEntity> targetGoal; |
| 66 | + private ReturnResourcesGoal returnResourcesGoal; |
| 67 | + private AbstractMeleeAttackUnitGoal attackGoal; |
| 68 | + private MeleeAttackBuildingGoal attackBuildingGoal; |
| 69 | + |
| 70 | + public LivingEntity getFollowTarget() { return followTarget; } |
| 71 | + public boolean getHoldPosition() { return holdPosition; } |
| 72 | + public void setHoldPosition(boolean holdPosition) { this.holdPosition = holdPosition; } |
| 73 | + |
| 74 | + // if true causes moveGoal and attackGoal to work together to allow attack moving |
| 75 | + // moves to a block but will chase/attack nearby monsters in range up to a certain distance away |
| 76 | + private LivingEntity followTarget = null; // if nonnull, continuously moves to the target |
| 77 | + private boolean holdPosition = false; |
| 78 | + private BlockPos attackMoveTarget = null; |
| 79 | + |
| 80 | + // which player owns this unit? this format ensures its synched to client without having to use packets |
| 81 | + public String getOwnerName() { return this.entityData.get(ownerDataAccessor); } |
| 82 | + public void setOwnerName(String name) { this.entityData.set(ownerDataAccessor, name); } |
| 83 | + public static final EntityDataAccessor<String> ownerDataAccessor = |
| 84 | + SynchedEntityData.defineId(KillerRabbitUnit.class, EntityDataSerializers.STRING); |
| 85 | + |
| 86 | + @Override |
| 87 | + protected void defineSynchedData() { |
| 88 | + super.defineSynchedData(); |
| 89 | + this.entityData.define(ownerDataAccessor, ""); |
| 90 | + } |
| 91 | + |
| 92 | + // combat stats |
| 93 | + public float getMovementSpeed() {return movementSpeed;} |
| 94 | + public float getUnitMaxHealth() {return maxHealth;} |
| 95 | + public float getUnitArmorValue() {return armorValue;} |
| 96 | + @Nullable |
| 97 | + public ResourceCost getCost() {return ResourceCosts.GRIZZLY_BEAR;} |
| 98 | + public boolean getWillRetaliate() {return willRetaliate;} |
| 99 | + public int getAttackCooldown() {return (int) (20 / attacksPerSecond);} |
| 100 | + public float getAttacksPerSecond() {return attacksPerSecond;} |
| 101 | + public float getAggroRange() {return aggroRange;} |
| 102 | + public boolean getAggressiveWhenIdle() {return aggressiveWhenIdle && !isVehicle();} |
| 103 | + public float getAttackRange() {return attackRange;} |
| 104 | + public float getUnitAttackDamage() {return attackDamage;} |
| 105 | + public BlockPos getAttackMoveTarget() { return attackMoveTarget; } |
| 106 | + public boolean canAttackBuildings() {return getAttackBuildingGoal() != null;} |
| 107 | + public Goal getAttackGoal() { return attackGoal; } |
| 108 | + public Goal getAttackBuildingGoal() { return attackBuildingGoal; } |
| 109 | + public void setAttackMoveTarget(@Nullable BlockPos bp) { this.attackMoveTarget = bp; } |
| 110 | + public void setFollowTarget(@Nullable LivingEntity target) { this.followTarget = target; } |
| 111 | + |
| 112 | + // endregion |
| 113 | + |
| 114 | + final static public float attackDamage = 100.0f; |
| 115 | + final static public float attacksPerSecond = 0.35f; |
| 116 | + final static public float attackRange = 2; // only used by ranged units or melee building attackers |
| 117 | + final static public float aggroRange = 10; |
| 118 | + final static public boolean willRetaliate = true; // will attack when hurt by an enemy |
| 119 | + final static public boolean aggressiveWhenIdle = true; |
| 120 | + |
| 121 | + final static public float maxHealth = 1000.0f; |
| 122 | + final static public float armorValue = 0.0f; |
| 123 | + final static public float movementSpeed = 0.35f; |
| 124 | + public int maxResources = 100; |
| 125 | + |
| 126 | + private final List<AbilityButton> abilityButtons = new ArrayList<>(); |
| 127 | + private final List<Ability> abilities = new ArrayList<>(); |
| 128 | + private final List<ItemStack> items = new ArrayList<>(); |
| 129 | + |
| 130 | + public KillerRabbitUnit(EntityType<? extends Rabbit> entityType, Level level) { |
| 131 | + super(entityType, level); |
| 132 | + } |
| 133 | + |
| 134 | + @Override |
| 135 | + public boolean removeWhenFarAway(double d) { return false; } |
| 136 | + |
| 137 | + public static AttributeSupplier.Builder createAttributes() { |
| 138 | + return Monster.createMonsterAttributes() |
| 139 | + .add(Attributes.ATTACK_DAMAGE, KillerRabbitUnit.attackDamage) |
| 140 | + .add(Attributes.MOVEMENT_SPEED, KillerRabbitUnit.movementSpeed) |
| 141 | + .add(Attributes.MAX_HEALTH, KillerRabbitUnit.maxHealth) |
| 142 | + .add(Attributes.FOLLOW_RANGE, Unit.getFollowRange()) |
| 143 | + .add(Attributes.ARMOR, KillerRabbitUnit.armorValue); |
| 144 | + } |
| 145 | + |
| 146 | + @Override |
| 147 | + protected float getJumpPower() { |
| 148 | + return super.getJumpPower() * 2; |
| 149 | + } |
| 150 | + |
| 151 | + @Override |
| 152 | + public Variant getVariant() { |
| 153 | + return Variant.EVIL; |
| 154 | + } |
| 155 | + |
| 156 | + @Override // immune to fall damage |
| 157 | + protected void checkFallDamage(double pY, boolean pOnGround, BlockState pState, BlockPos pPos) { } |
| 158 | + |
| 159 | + @Override |
| 160 | + public boolean doHurtTarget(Entity pEntity) { |
| 161 | + this.playSound(SoundEvents.RABBIT_ATTACK, 1.0F, (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F); |
| 162 | + return pEntity.hurt(this.damageSources().mobAttack(this), attackDamage); |
| 163 | + } |
| 164 | + |
| 165 | + @Override // prevent vanilla logic for picking up items |
| 166 | + protected void pickUpItem(ItemEntity pItemEntity) { } |
| 167 | + @Override |
| 168 | + public LivingEntity getTarget() { |
| 169 | + return this.targetGoal.getTarget(); |
| 170 | + } |
| 171 | + |
| 172 | + public void tick() { |
| 173 | + this.setCanPickUpLoot(false); |
| 174 | + super.tick(); |
| 175 | + Unit.tick(this); |
| 176 | + AttackerUnit.tick(this); |
| 177 | + } |
| 178 | + |
| 179 | + public void initialiseGoals() { |
| 180 | + this.usePortalGoal = new UsePortalGoal(this); |
| 181 | + this.moveGoal = new MoveToTargetBlockGoal(this, false, 0); |
| 182 | + this.targetGoal = new SelectedTargetGoal<>(this, true, true); |
| 183 | + this.attackGoal = new MeleeAttackUnitGoal(this, false); |
| 184 | + this.attackBuildingGoal = new MeleeAttackBuildingGoal(this); |
| 185 | + } |
| 186 | + |
| 187 | + @Override |
| 188 | + protected void registerGoals() { |
| 189 | + initialiseGoals(); |
| 190 | + this.goalSelector.addGoal(2, usePortalGoal); |
| 191 | + this.goalSelector.addGoal(1, new FloatGoal(this)); |
| 192 | + this.goalSelector.addGoal(2, attackGoal); |
| 193 | + this.goalSelector.addGoal(2, attackBuildingGoal); |
| 194 | + this.targetSelector.addGoal(2, targetGoal); |
| 195 | + this.goalSelector.addGoal(3, moveGoal); |
| 196 | + this.goalSelector.addGoal(4, new RandomLookAroundUnitGoal(this)); |
| 197 | + } |
| 198 | + |
| 199 | + @Override |
| 200 | + @Nullable |
| 201 | + public SpawnGroupData finalizeSpawn(ServerLevelAccessor pLevel, DifficultyInstance pDifficulty, MobSpawnType pReason, @Nullable SpawnGroupData pSpawnData, @Nullable CompoundTag pDataTag) { |
| 202 | + return pSpawnData; |
| 203 | + } |
| 204 | +} |
0 commit comments