Skip to content

Commit

Permalink
Add boomerang weapon.
Browse files Browse the repository at this point in the history
  • Loading branch information
Provismet committed Jan 26, 2024
1 parent caa099c commit aedd6b1
Show file tree
Hide file tree
Showing 22 changed files with 441 additions and 2 deletions.
8 changes: 8 additions & 0 deletions src/main/generated/assets/additional-armoury/lang/en_us.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"death.attack.boomerang": "%1$s was struck by a boomerang from %2$s",
"death.attack.boomerang.item": "%1$s was struck by a boomerang from %2$s using %3$s",
"death.attack.eruption_spell": "%1$s was launched by %2$s",
"death.attack.eruption_spell.item": "%1$s was launched by %2$s using %3$s",
"death.attack.fireball_spell": "%1$s was blasted by %2$s",
Expand All @@ -18,8 +20,14 @@
"enchantment.additional-armoury.frostball.desc": "Shoot a frostball that freezes on hit.",
"enchantment.additional-armoury.jump": "Soaring",
"enchantment.additional-armoury.jump.desc": "Launch into the air and gain slow-fall.",
"enchantment.additional-armoury.multithrow": "MultiThrow",
"enchantment.additional-armoury.multithrow.desc": "Throws 3 boomerangs at once.",
"enchantment.additional-armoury.ricochet": "Ricochet",
"enchantment.additional-armoury.ricochet.desc": "Increases the number of boomerang bounces.",
"entity.additional-armoury.boomerang_projectile": "Boomerang",
"entity.additional-armoury.fireball_spell": "Fireball Spell",
"entity.additional-armoury.frostball_spell": "Frostball Spell",
"item.additional-armoury.boomerang": "Boomerang",
"item.additional-armoury.diamond_dagger": "Diamond Dagger",
"item.additional-armoury.diamond_dagger.effect.awkward": "Diamond Dagger",
"item.additional-armoury.diamond_dagger.effect.fire_resistance": "Fire Resistance-Tipped Diamond Dagger",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/handheld",
"textures": {
"layer0": "additional-armoury:item/boomerang"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.provismet.AdditionalArmoury.asm;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

import com.provismet.AdditionalArmoury.items.BoomerangItem;

import net.minecraft.enchantment.EnchantmentTarget;
import net.minecraft.item.Item;

public class BoomerangEnchantmentTarget extends BoomerangEnchantmentTargetMixin {
@Override
public boolean isAcceptableItem (Item item) {
return item instanceof BoomerangItem;
}
}


@Mixin(EnchantmentTarget.class)
abstract class BoomerangEnchantmentTargetMixin {
@Shadow
abstract boolean isAcceptableItem (Item item);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public void run () {
ClassTinkerers.enumBuilder(enchantmentTarget)
.addEnumSubclass("ADDITIONALARMOURY$STAFF", "com.provismet.AdditionalArmoury.asm.StaffEnchantmentTarget")
.addEnumSubclass("ADDITIONALARMOURY$DAGGER", "com.provismet.AdditionalArmoury.asm.DaggerEnchantmentTarget")
.addEnumSubclass("ADDITIONALARMOURY$BOOMERANG", "com.provismet.AdditionalArmoury.asm.BoomerangEnchantmentTarget")
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.provismet.AdditionalArmoury.enchantments.boomerang;

import com.provismet.AdditionalArmoury.registries.AAEnchantmentTargets;

import net.minecraft.enchantment.Enchantment;
import net.minecraft.entity.EquipmentSlot;

public abstract class BoomerangEnchantment extends Enchantment {
protected BoomerangEnchantment (Rarity weight) {
super(weight, AAEnchantmentTargets.BOOMERANG, new EquipmentSlot[] {EquipmentSlot.MAINHAND});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.provismet.AdditionalArmoury.enchantments.boomerang;

import net.minecraft.enchantment.Enchantment;

public class MultiThrowEnchantment extends BoomerangEnchantment {
public MultiThrowEnchantment () {
super(Rarity.UNCOMMON);
}

@Override
public int getMinPower (int level) {
return 20;
}

@Override
public int getMaxPower (int level) {
return 50;
}

@Override
public boolean canAccept (Enchantment other) {
return super.canAccept(other) && !(other instanceof RicochetEnchantment);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.provismet.AdditionalArmoury.enchantments.boomerang;

public class RicochetEnchantment extends BoomerangEnchantment {
public RicochetEnchantment () {
super(Rarity.COMMON);
}

@Override
public int getMaxLevel () {
return 4;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package com.provismet.AdditionalArmoury.entity;

import org.jetbrains.annotations.NotNull;

import com.provismet.AdditionalArmoury.AdditionalArmouryMain;
import com.provismet.AdditionalArmoury.registries.AAEntityTypes;
import com.provismet.AdditionalArmoury.registries.AAItems;
import com.provismet.AdditionalArmoury.utility.AADamageSources;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.ProjectileEntity;
import net.minecraft.entity.projectile.thrown.ThrownItemEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;

public class BoomerangProjectileEntity extends ThrownItemEntity {
private static final String RICOCHET_KEY = "ricochet_count";
private static final String FLIGHT_TIME_KEY = "flight_time";
private static final String RESETS_COOLDOWN_KEY = "resets_cooldown";

protected final int maxTime;
protected int flightTime;
protected int ricochetCount;

private int ricochetCounterCooldown = 0;
private boolean resetsCooldown = true;

public BoomerangProjectileEntity (EntityType<? extends BoomerangProjectileEntity> entityType, World world) {
super(entityType, world);
this.maxTime = 40;
this.flightTime = 0;
this.ricochetCount = 1;
}

public BoomerangProjectileEntity (World world, @NotNull LivingEntity owner) {
super(AAEntityTypes.BOOMERANG, owner, world);
this.maxTime = 40;
this.flightTime = 0;
this.ricochetCount = 1;
}

@Override
public void writeCustomDataToNbt (NbtCompound nbt) {
super.writeCustomDataToNbt(nbt);
nbt.putInt(RICOCHET_KEY, this.ricochetCount);
nbt.putInt(FLIGHT_TIME_KEY, this.flightTime);
nbt.putBoolean(RESETS_COOLDOWN_KEY, this.resetsCooldown);
}

@Override
public void readCustomDataFromNbt (NbtCompound nbt) {
super.readCustomDataFromNbt(nbt);
if (nbt.contains(RICOCHET_KEY)) this.ricochetCount = nbt.getInt(RICOCHET_KEY);
if (nbt.contains(FLIGHT_TIME_KEY)) this.flightTime = nbt.getInt(FLIGHT_TIME_KEY);
if (nbt.contains(RESETS_COOLDOWN_KEY)) this.resetsCooldown = nbt.getBoolean(RESETS_COOLDOWN_KEY);
}

@Override
public void tick () {
if (!this.getWorld().isClient()) {
if (this.ricochetCount > 0 && ++this.flightTime >= this.maxTime) {
this.ricochet(false, true);
}
if (this.ricochetCounterCooldown > 0) --this.ricochetCounterCooldown;
}
super.tick();
}

@Override
protected void onBlockHit (BlockHitResult blockHitResult) {
super.onBlockHit(blockHitResult);
if (!this.getWorld().isClient()) {
if (this.ricochetCount <= 0) this.discard();
else this.ricochetBlock(blockHitResult.getSide());
}
}

@Override
protected void onEntityHit (EntityHitResult entityHitResult) {
super.onEntityHit(entityHitResult);
if (!this.getWorld().isClient()) {
if (this.getOwner() instanceof PlayerEntity player && entityHitResult.getEntity() == player) {
if (this.resetsCooldown) player.getItemCooldownManager().remove(AAItems.BOOMERANG);
this.discard();
}
else if (!(entityHitResult.getEntity() instanceof ProjectileEntity)) {
if (this.ricochetCount > 0) this.ricochet();
if (entityHitResult.getEntity() instanceof LivingEntity target) {
target.damage(AADamageSources.boomerang(this, this.getOwner()), 4f);
}
}
}
}

protected boolean ricochet (boolean doFallback, boolean returnToUser) {
if (this.ricochetCounterCooldown <= 0) {
this.ricochetCounterCooldown = 2;
--this.ricochetCount;
}
this.flightTime = 0;

if ((this.ricochetCount <= 0 || returnToUser) && this.getOwner() != null) {
this.ricochetCount = 0;
Entity owner = this.getOwner();
this.setVelocity(owner.getX() - this.getX(), owner.getEyeY() - this.getY(), owner.getZ() - this.getZ(), 1f, 0.5f);
AdditionalArmouryMain.LOGGER.info("Ricochet Count: " + this.ricochetCount + " (player ricochet)");
return true;
}
else if (doFallback) {
this.setVelocity(-this.getVelocity().getX(), -this.getVelocity().getY(), -this.getVelocity().getZ(), 1f, 1f);
AdditionalArmouryMain.LOGGER.info("Ricochet Count: " + this.ricochetCount + " (used fallback)");
return true;
}

AdditionalArmouryMain.LOGGER.info("Ricochet Count: " + this.ricochetCount);
return false;
}

protected boolean ricochet () {
return this.ricochet(true, false);
}

protected void ricochetBlock (Direction direction) {
if (!this.ricochet(false, false)) {
switch (direction) {
case UP:
case DOWN:
this.setVelocity(this.getVelocity().getX(), this.getVelocity().getY() * -1, this.getVelocity().getZ(), 1f, 0f);
break;

case NORTH:
case SOUTH:
this.setVelocity(this.getVelocity().getX(), this.getVelocity().getY(), this.getVelocity().getZ() * -1, 1f, 0f);
break;

case EAST:
case WEST:
this.setVelocity(this.getVelocity().getX() * -1, this.getVelocity().getY(), this.getVelocity().getZ(), 1f, 0f);

default:
break;
}
}
}

@Override
public ItemStack getStack () {
return AAItems.BOOMERANG.getDefaultStack();
}

@Override
protected Item getDefaultItem () {
return AAItems.BOOMERANG;
}

@Override
protected float getGravity () {
return 0.005f;
}

public void setRicochetCount (int value) {
this.ricochetCount = value;
}

public void setCanResetCooldown (boolean value) {
this.resetsCooldown = value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.provismet.AdditionalArmoury.items;

import com.provismet.AdditionalArmoury.entity.BoomerangProjectileEntity;
import com.provismet.AdditionalArmoury.registries.AAEnchantments;
import com.provismet.AdditionalArmoury.registries.AAItems;

import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Vanishable;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.stat.Stats;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.util.UseAction;
import net.minecraft.world.World;

public class BoomerangItem extends Item implements Vanishable {
public BoomerangItem (Settings settings) {
super(settings);
}

@Override
public UseAction getUseAction (ItemStack stack) {
return UseAction.SPEAR;
}

@Override
public int getMaxUseTime (ItemStack stack) {
return 72000;
}

@Override
public TypedActionResult<ItemStack> use (World world, PlayerEntity user, Hand hand) {
ItemStack itemStack = user.getStackInHand(hand);
if (itemStack.getDamage() >= itemStack.getMaxDamage() - 1) {
return TypedActionResult.fail(itemStack);
}
user.setCurrentHand(hand);
return TypedActionResult.consume(itemStack);
}

@Override
public void onStoppedUsing (ItemStack itemStack, World world, LivingEntity user, int remainingUseTicks) {
if (!(user instanceof PlayerEntity)) return;
if (this.getMaxUseTime(itemStack) - remainingUseTicks < 10) return;

PlayerEntity player = (PlayerEntity)user;

if (!world.isClient()) {
BoomerangProjectileEntity boomerang = new BoomerangProjectileEntity(world, player);
boomerang.setVelocity(player, player.getPitch(), player.getYaw(), 0f, 1f, 1f);

int ricochetLevel = 1 + EnchantmentHelper.getLevel(AAEnchantments.RICOCHET, itemStack);
boomerang.setRicochetCount(ricochetLevel);
world.spawnEntity(boomerang);

int damage = 1 + (EnchantmentHelper.getLevel(AAEnchantments.MULTITHROW, itemStack) > 0 ? 2 : 0);
if (damage > 1) {
for (int i = 0; i < 2; ++i) {
BoomerangProjectileEntity newBoomerang = new BoomerangProjectileEntity(world, player);
newBoomerang.setVelocity(player, player.getPitch(), player.getYaw() + (i == 0 ? 10f : -10f), 0f, 1f, 1f);
newBoomerang.setCanResetCooldown(false);
world.spawnEntity(newBoomerang);
}
}

itemStack.damage(damage, player, p -> p.sendToolBreakStatus(player.getActiveHand()));
player.getItemCooldownManager().set(AAItems.BOOMERANG, 100);
}
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENTITY_ARROW_SHOOT, SoundCategory.PLAYERS, 1.0f, 1.0f / (world.getRandom().nextFloat() * 0.4f + 1.2f) + 0.5f);
player.incrementStat(Stats.USED.getOrCreateStat(this));
}

@Override
public int getEnchantability () {
return 1;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@
public class AAEnchantmentTargets {
public static final EnchantmentTarget STAFF = ClassTinkerers.getEnum(EnchantmentTarget.class, "ADDITIONALARMOURY$STAFF");
public static final EnchantmentTarget DAGGER = ClassTinkerers.getEnum(EnchantmentTarget.class, "ADDITIONALARMOURY$DAGGER");
public static final EnchantmentTarget BOOMERANG = ClassTinkerers.getEnum(EnchantmentTarget.class, "ADDITIONALARMOURY$BOOMERANG");
}
Loading

0 comments on commit aedd6b1

Please sign in to comment.