Skeleton go pew pew

Also zombie go boom
This commit is contained in:
Bruno Rybársky 2024-07-29 23:32:42 +02:00
parent 8d00672806
commit 653171cbb2
17 changed files with 623 additions and 139 deletions

@ -109,3 +109,7 @@ publishing {
// retrieving dependencies.
}
}
loom {
accessWidenerPath = file("src/main/resources/plasticgun.accesswidener")
}

@ -9,6 +9,7 @@ import net.fabricmc.fabric.api.event.player.UseItemCallback;
import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.item.Item;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import org.slf4j.Logger;
@ -27,7 +28,9 @@ import systems.brn.plasticgun.shurikens.ShurikenItem;
import systems.brn.plasticgun.testing.DamageTester;
import java.util.ArrayList;
import java.util.Map;
import static systems.brn.plasticgun.lib.Util.generateItemMap;
import static systems.brn.plasticgun.lib.Util.id;
public class PlasticGun implements ModInitializer {
@ -44,6 +47,11 @@ public class PlasticGun implements ModInitializer {
public static final ArrayList<CraftingItem> craftingItems = new ArrayList<>();
public static Map<Item, Gun> itemGunMap;
public static Map<Item, BulletItem> itemBulletItemMap;
public static Map<Item, GrenadeItem> itemGrenadeItemMap;
public static Map<Item, ShurikenItem> itemShurikenItemMap;
public static EntityType<BulletEntity> BULLET_ENTITY_TYPE;
public static EntityType<GrenadeEntity> GRENADE_ENTITY_TYPE;
@ -80,32 +88,32 @@ public class PlasticGun implements ModInitializer {
bullets.add(new BulletItem("force_container", 99, 0, 888, false, 0, 1));
// Guns
guns.add(new Gun("357_revolver", 1, 8, 5, 6, 45, 357, 14, 0, 0, 2, 4, 0.2f, 0.5f, -1, 1));
guns.add(new Gun("colt_1903", 0.3, 10, 5, 8, 38, 32, 5, 0, 0, 1, 3, 0.1f, 0.3f, -1, 1));
guns.add(new Gun("colt_45", 0.4, 9, 5, 7, 48, 45, 5, 0, 0, 1.5f, 2, 0.15f, 0.4f, -1, 1));
guns.add(new Gun("colt_peacemaker", 0.6, 8, 5, 6, 43, 45, 5, 0, 0, 0.9f, 2, 0.2f, 0.5f, -1, 1));
guns.add(new Gun("p2022", 0.2, 12, 5, 10, 41, 9, 5, 0, 0, 1f, 4, 0.1f, 0.25f, -1, 1));
guns.add(new Gun("snub_nosed_revolver", 0.4, 7, 3, 5, 36, 38, 14, 0, 0, 1f, 2, 0.2f, 0.45f, -1, 1));
guns.add(new Gun("tokarev_tt_33", 0.7, 10, 5, 8, 45, 762, 5, 0, 0, 1.5f, 2.5f, 0.25f, 0.5f, -1, 1));
guns.add(new Gun("ak_47", 0.2, 4, 5, 30, 45, 762, 0, 0, 0, 1f, 2, 0.2f, 0.4f, -1, 1));
guns.add(new Gun("awp", 1, 4, 20, 1, 75, 762, 20, 0, 0, 2f, 8, 0.3f, 0.6f, -1, 1));
guns.add(new Gun("rpg9", 2, 4, 20, 1, 10, 999, 8, 20, 0, 3f, 0.5f, 1, 2, -1, 1));
guns.add(new Gun("forcegun", 0, 2, 5, 20, 10, 888, 0, 0, 20, 0f, 0f, 5f, 10f, 0, 0));
guns.add(new Gun("forcegun", 0, 2, 5, 20, 10, 888, 0, 0, 20, 0f, 0f, 5f, 10f, 0, 0)); // 0
guns.add(new Gun("p2022", 0.2, 12, 5, 10, 41, 9, 5, 0, 0, 1f, 4, 0.1f, 0.25f, -1, 1)); // 1.8
guns.add(new Gun("colt_1903", 0.3, 10, 5, 8, 38, 32, 5, 0, 0, 1, 3, 0.1f, 0.3f, -1, 1)); // 3
guns.add(new Gun("ak_47", 0.2, 4, 5, 30, 45, 762, 0, 0, 0, 1f, 2, 0.2f, 0.4f, -1, 1)); // 9
guns.add(new Gun("colt_45", 0.4, 9, 5, 7, 48, 45, 5, 0, 0, 1.5f, 2, 0.15f, 0.4f, -1, 1)); // 3.6
guns.add(new Gun("snub_nosed_revolver", 0.4, 7, 3, 5, 36, 38, 14, 0, 0, 1f, 2, 0.2f, 0.45f, -1, 1)); // 2.8
guns.add(new Gun("colt_peacemaker", 0.6, 8, 5, 6, 43, 45, 5, 0, 0, 0.9f, 2, 0.2f, 0.5f, -1, 1)); // 4.8
guns.add(new Gun("tokarev_tt_33", 0.7, 10, 5, 8, 45, 762, 5, 0, 0, 1.5f, 2.5f, 0.25f, 0.5f, -1, 1)); // 7
guns.add(new Gun("357_revolver", 1, 8, 5, 6, 45, 357, 14, 0, 0, 2, 4, 0.2f, 0.5f, -1, 1)); // 8
guns.add(new Gun("awp", 1, 4, 20, 1, 75, 762, 20, 0, 0, 2f, 8, 0.3f, 0.6f, -1, 1)); // 4
guns.add(new Gun("rpg9", 2, 4, 20, 1, 10, 999, 8, 20, 0, 3f, 0.5f, 1, 2, -1, 1)); // 8
grenades.add(new GrenadeItem("grenade_an_m14", 1, 5f, 0.5f, 40, true, false, 0, 0, 0, 8, 0)); // AN-M14 Incendiary Grenade
grenades.add(new GrenadeItem("grenade_m34", 1, 10f, 0.5f, 60, true, true, 0, 0, 0, 10, 0)); // M34 White Phosphorus Incendiary Fragmentation Grenade
grenades.add(new GrenadeItem("grenade_m18", 1, 0.1f, 0.2f, 50, false, false, 0, 0, 100, 15, 30)); // M18 Smoke Grenade
grenades.add(new GrenadeItem("grenade_m84", 1, 0.5f, 0.2f, 120, false, false, 10, 10, 5, 12, 10)); // M84 Stun Grenade (Flashbang)
grenades.add(new GrenadeItem("grenade_rgd_5", 1, 6.5f, 0.5f, 60, false, true, 0, 0, 0, 10, 0)); // RGD-5 Fragmentation Grenade
grenades.add(new GrenadeItem("grenade_thermite", 1, 4f, 0.3f, 80, true, false, 0, 0, 0, 8, 15)); // Thermite Grenade
grenades.add(new GrenadeItem("grenade_f1", 1, 7f, 0.5f, 60, false, true, 0, 0, 0, 10, 0)); // F1 Soviet Fragmentation Grenade
grenades.add(new GrenadeItem("grenade_mk3a2", 1, 6f, 0.4f, 60, false, false, 0, 0, 0, 10, 0)); // Mk3A2 Offensive Grenade
grenades.add(new GrenadeItem("grenade_m7a3", 1, 0.1f, 0.2f, 90, false, false, 0, 0, 50, 8, 40)); // M7A3 CS Gas Grenade
grenades.add(new GrenadeItem("grenade_no_69", 1, 5.5f, 0.4f, 60, false, false, 0, 0, 0, 10, 0)); // No. 69 British Offensive Grenade
grenades.add(new GrenadeItem("grenade_rgo", 1, 6.5f, 0.5f, 90, false, true, 0, 0, 0, 10, 0)); // RGO Fragmentation Grenade
grenades.add(new GrenadeItem("grenade_k417", 1, 7f, 0.5f, 70, false, true, 0, 0, 0, 10, 0)); // K417 Fragmentation Grenade
grenades.add(new GrenadeItem("grenade_m18", 1, 0.1f, 0.2f, 50, false, false, 0, 0, 100, 15, 30)); // 0.02
grenades.add(new GrenadeItem("grenade_m7a3", 1, 0.1f, 0.2f, 90, false, false, 80, 40, 50, 8, 40)); // 0.02
grenades.add(new GrenadeItem("grenade_m84", 1, 0.5f, 0.2f, 120, false, false, 160, 160, 5, 12, 10)); // 0.1
grenades.add(new GrenadeItem("grenade_no_69", 1, 5.5f, 0.4f, 60, false, false, 0, 0, 0, 10, 0)); // 2.2
grenades.add(new GrenadeItem("grenade_an_m14", 1, 5f, 0.5f, 40, true, false, 0, 0, 0, 8, 0)); // 2.5
grenades.add(new GrenadeItem("grenade_thermite", 1, 4f, 0.3f, 80, true, false, 0, 0, 0, 8, 15)); // 1.2
grenades.add(new GrenadeItem("grenade_mk3a2", 1, 6f, 0.4f, 60, false, false, 0, 0, 0, 10, 0)); // 2.4
grenades.add(new GrenadeItem("grenade_m34", 1, 10f, 0.5f, 60, true, true, 0, 0, 0, 10, 0)); // 5
grenades.add(new GrenadeItem("grenade_f1", 1, 7f, 0.5f, 60, false, true, 0, 0, 0, 10, 0)); // 3.5
grenades.add(new GrenadeItem("grenade_rgd_5", 1, 6.5f, 0.5f, 60, false, true, 0, 0, 0, 10, 0)); // 3.25
grenades.add(new GrenadeItem("grenade_rgo", 1, 6.5f, 0.5f, 90, false, true, 0, 0, 0, 10, 0)); // 3.25
grenades.add(new GrenadeItem("grenade_k417", 1, 7f, 0.5f, 70, false, true, 0, 0, 0, 10, 0)); // 3.5
weaponArmors.add(new WeaponArmor("kevlar_vest", 200, 0.8, 0.8, 0.4, 0.3));
weaponArmors.add(new WeaponArmor("flak_vest", 500, 0.8, 0.4, 0.8, 0.2));
@ -142,6 +150,10 @@ public class PlasticGun implements ModInitializer {
craftingItems.add(new CraftingItem("titanium_alloy"));
craftingItems.add(new CraftingItem("trigger_mechanism"));
itemGunMap = generateItemMap(guns);
itemBulletItemMap = generateItemMap(bullets);
itemGrenadeItemMap = generateItemMap(grenades);
itemShurikenItemMap = generateItemMap(shurikens);
GRENADE_ENTITY_TYPE = Registry.register(
Registries.ENTITY_TYPE,

@ -33,10 +33,10 @@ public class BulletEntity extends PersistentProjectileEntity implements PolymerE
private ItemStack itemStack = Items.ARROW.getDefaultStack();
private final float scale;
public BulletEntity(ServerPlayerEntity player, ItemStack stack, Hand hand, Gun gun, float scale, double damage, float speed, double explosionPower, double repulsionPower, boolean isIncendiary) {
super(BULLET_ENTITY_TYPE, player.getPos().x, player.getPos().y + 1.5d, player.getPos().z, player.getServerWorld(), stack, player.getStackInHand(hand));
this.setOwner(player);
this.setVelocity(player, player.getPitch(), player.getYaw(), 0.0F, speed, 0);
public BulletEntity(LivingEntity livingEntity, ItemStack stack, Hand hand, Gun gun, float scale, double damage, float speed, double explosionPower, double repulsionPower, boolean isIncendiary) {
super(BULLET_ENTITY_TYPE, livingEntity.getPos().x, livingEntity.getPos().y + 1.75d, livingEntity.getPos().z, livingEntity.getEntityWorld(), stack, livingEntity.getStackInHand(hand));
this.setOwner(livingEntity);
this.setVelocity(livingEntity, livingEntity.getPitch(), livingEntity.getYaw(), 0.0F, speed, 0);
this.pickupType = PickupPermission.DISALLOWED;
this.setDamage(damage);
this.setSilent(true);

@ -128,7 +128,7 @@ public class GrenadeEntity extends ThrowableProjectile implements PolymerEntity
if (flashBangDuration > 0) {
for (Entity entity : nearbyEntities) {
if (entity instanceof LivingEntity livingEntity) {
livingEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, stunDuration, 255, true, false));
livingEntity.addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, flashBangDuration, 255, true, false));
}
}
flashBangDuration = 0;

@ -3,6 +3,7 @@ package systems.brn.plasticgun.grenades;
import eu.pb4.polymer.core.api.item.PolymerItem;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.LoreComponent;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.registry.Registries;
@ -57,7 +58,7 @@ public class GrenadeItem extends SimpleItem implements PolymerItem {
Text.translatable("gun.description.particle_count", smokeCount)
)))
.maxDamage(explosionTarget + 1)
, id(path), Items.FLOWER_POT
, id(path), Items.STICK
);
this.explosionTarget = explosionTarget;
this.isIncendiary = isIncendiary;
@ -103,19 +104,25 @@ public class GrenadeItem extends SimpleItem implements PolymerItem {
if (!player.isCreative()) {
stack.decrement(1);
}
if (!stack.isEmpty()) {
if (!stack.isEmpty()) {
stack.setDamage(0);
}
}
}
}
private void turnIntoEntity(ServerPlayerEntity player, @Nullable ItemStack stack, int speed, int timer) {
GrenadeEntity grenadeEntity = new GrenadeEntity(player, stack, timer, 1f, speed, explosionPower, repulsionPower, isIncendiary, isFragmentation, flashBangDuration, stunDuration, smokeTicks, 8, smokeCount);
public void turnIntoEntity(ServerPlayerEntity player, @Nullable ItemStack stack, int speed, int timer) {
GrenadeEntity grenadeEntity = new GrenadeEntity(player, stack, timer, 0.5f, speed, explosionPower, repulsionPower, isIncendiary, isFragmentation, flashBangDuration, stunDuration, smokeTicks, 8, smokeCount);
player.getServerWorld().spawnEntity(grenadeEntity);
player.getServerWorld().playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
}
public void turnIntoEntity(Entity entity, @Nullable ItemStack stack, int speed, int timer) {
GrenadeEntity grenadeEntity = new GrenadeEntity(entity.getEntityWorld(), entity.getPos(), stack, timer, 1f, explosionPower, repulsionPower, isIncendiary, isFragmentation, flashBangDuration, stunDuration, smokeTicks, 8, smokeCount);
entity.getEntityWorld().spawnEntity(grenadeEntity);
entity.getEntityWorld().playSound(null, entity.getX(), entity.getY(), entity.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
}
public void checkExplosions(ServerWorld world, PlayerEntity playerEntity, ItemStack stackInSlot) {
if (playerEntity instanceof ServerPlayerEntity player && !world.isClient()) {
int timer = stackInSlot.getOrDefault(GRENADE_TIMER_COMPONENT, -1);

@ -3,6 +3,9 @@ package systems.brn.plasticgun.guns;
import eu.pb4.polymer.core.api.item.PolymerItem;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.LoreComponent;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.network.packet.s2c.play.PositionFlag;
@ -16,7 +19,9 @@ import net.minecraft.text.Text;
import net.minecraft.util.Hand;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.LocalDifficulty;
import net.minecraft.world.World;
import org.jetbrains.annotations.NotNull;
import systems.brn.plasticgun.bullets.BulletEntity;
import systems.brn.plasticgun.bullets.BulletItem;
import systems.brn.plasticgun.lib.SimpleItem;
@ -25,6 +30,7 @@ import java.util.ArrayList;
import java.util.List;
import static systems.brn.plasticgun.PlasticGun.bullets;
import static systems.brn.plasticgun.PlasticGun.itemBulletItemMap;
import static systems.brn.plasticgun.lib.GunComponents.*;
import static systems.brn.plasticgun.lib.Util.*;
@ -112,6 +118,7 @@ public class Gun extends SimpleItem implements PolymerItem {
stack.remove(GUN_AMMO_COMPONENT);
} else {
stack.set(GUN_AMMO_COMPONENT, chamber);
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.PLAYERS, 0.5f, 1.0f);
}
stack.set(GUN_LOADING_COMPONENT, 1);
@ -126,6 +133,7 @@ public class Gun extends SimpleItem implements PolymerItem {
stack.remove(GUN_AMMO_COMPONENT);
} else {
stack.set(GUN_AMMO_COMPONENT, chamber);
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BLOCK_LEVER_CLICK, SoundCategory.PLAYERS, 1f, 2.5f);
}
bulletStack.decrement(targetCount);
@ -136,6 +144,7 @@ public class Gun extends SimpleItem implements PolymerItem {
}
if (player.isCreative()) {
stack.set(GUN_AMMO_COMPONENT, new ItemStack(ammo.getFirst(), clipSize)); // Ensure ammo.get(0) is a valid item
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
}
updateDamage(stack);
} else {
@ -144,6 +153,36 @@ public class Gun extends SimpleItem implements PolymerItem {
}
}
public void reload(World world, MobEntity mobEntity, Hand hand, Random random, LocalDifficulty localDifficulty) {
if (!world.isClient()) {
ItemStack stack = mobEntity.getStackInHand(hand);
int currentReloadCooldown = stack.getOrDefault(GUN_RELOAD_COOLDOWN_COMPONENT, 0);
ItemStack chamber = stack.getOrDefault(GUN_AMMO_COMPONENT, ItemStack.EMPTY);
int bulletsInChamber = chamber.getCount();
int currentReload = stack.getOrDefault(GUN_LOADING_COMPONENT, 1);
if (currentReload == 1 && bulletsInChamber > 0) {
return;
}
if (currentReloadCooldown == 0) {
stack.set(GUN_RELOAD_COOLDOWN_COMPONENT, reloadTarget);
ItemStack oldChamber = stack.getOrDefault(GUN_LAST_LOADED_AMMO, ItemStack.EMPTY);
Item ammoItem = (oldChamber == null || oldChamber.isEmpty())
? ammo.get(selectWeaponIndex(random, localDifficulty, ammo.size()))
: oldChamber.getItem();
ItemStack bulletStack = new ItemStack(ammoItem, world.getRandom().nextBetween(1, ammoItem.getMaxCount()));
if (!bulletStack.isEmpty()) { // we have ammo
if (currentReload < reloadCount) { // still reloading
stack.set(GUN_LOADING_COMPONENT, currentReload + 1);
} else if (currentReload == reloadCount) { // now reload
stack.set(GUN_AMMO_COMPONENT, bulletStack);
stack.set(GUN_LAST_LOADED_AMMO, bulletStack);
stack.set(GUN_LOADING_COMPONENT, 1);
}
}
}
}
}
public void updateDamage(ItemStack stack) {
ItemStack chamber = stack.getOrDefault(GUN_AMMO_COMPONENT, ItemStack.EMPTY).copy();
BulletItem bulletItem = null;
@ -194,67 +233,70 @@ public class Gun extends SimpleItem implements PolymerItem {
stack.set(DataComponentTypes.LORE, newLore);
}
public void doRecoil(ServerPlayerEntity player) {
Random rng = player.getServerWorld().getRandom();
// Get the player's current position and yaw
Vec3d pos = player.getPos();
float yaw = player.getYaw();
float newPitch = player.getPitch();
Vec3d currentLook = player.getRotationVector().multiply(-1);
newPitch -= verticalRecoilMin + rng.nextFloat() * (verticalRecoilMax - verticalRecoilMin);
yaw -= (float) (horizontalRecoilMin + rng.nextFloat() * (horizontalRecoilMax - horizontalRecoilMin));
public void doRecoil(LivingEntity entity) {
if (entity.getEntityWorld() instanceof ServerWorld serverWorld) {
Random rng = entity.getWorld().getRandom();
// Get the entity's current position and yaw
Vec3d pos = entity.getPos();
float yaw = entity.getYaw();
float newPitch = entity.getPitch();
Vec3d currentLook = entity.getRotationVector().multiply(-1);
newPitch -= verticalRecoilMin + rng.nextFloat() * (verticalRecoilMax - verticalRecoilMin);
yaw -= (float) (horizontalRecoilMin + rng.nextFloat() * (horizontalRecoilMax - horizontalRecoilMin));
player.teleport(player.getServerWorld(), pos.x, pos.y, pos.z, PositionFlag.ROT, yaw, newPitch);
double velocityRecoil = rng.nextDouble() * (velocityRecoilMax - velocityRecoilMin);
if (velocityRecoil > 0) {
player.setVelocity(currentLook.multiply(velocityRecoil));
entity.teleport(serverWorld, pos.x, pos.y, pos.z, PositionFlag.ROT, yaw, newPitch);
double velocityRecoil = rng.nextDouble() * (velocityRecoilMax - velocityRecoilMin);
if (velocityRecoil > 0) {
entity.setVelocity(currentLook.multiply(velocityRecoil));
}
}
}
public void shoot(ServerWorld world, PlayerEntity user, Hand hand) {
if (user instanceof ServerPlayerEntity player && !world.isClient()) {
public void shoot(ServerWorld world, LivingEntity user, Hand hand) {
if (!world.isClient()) {
ItemStack stack = user.getStackInHand(hand);
int currentReload = stack.getOrDefault(GUN_LOADING_COMPONENT, 1);
int currentCooldown = stack.getOrDefault(GUN_COOLDOWN_COMPONENT, 0);
ItemStack chamber = stack.getOrDefault(GUN_AMMO_COMPONENT, ItemStack.EMPTY).copy();
BulletItem bullet = null;
for (BulletItem bulletTemp : bullets) {
if (bulletTemp == chamber.getItem()) {
bullet = bulletTemp;
break;
}
if (itemBulletItemMap.containsKey(chamber.getItem())) {
bullet = itemBulletItemMap.get(chamber.getItem());
}
if (!chamber.isEmpty() && currentReload == 1 && currentCooldown == 0) {
boolean isIncendiary = false;
double explosionPower = explosionPowerGun;
double repulsionPower = repulsionPowerGun;
if (bullet != null) {
isIncendiary = bullet.isIncendiary;
explosionPower *= bullet.explosionPowerCoefficient;
repulsionPower *= bullet.repulsionPowerCoefficient;
}
BulletEntity bulletEntity = new BulletEntity(player, chamber, hand, this, 1f, damage, speed, explosionPower, repulsionPower, isIncendiary);
BulletEntity bulletEntity = getBulletEntity(user, hand, bullet, chamber);
world.spawnEntity(bulletEntity);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENTITY_GENERIC_EXPLODE.value(), SoundCategory.PLAYERS, 0.1f, 1.2f);
world.playSound(null, user.getX(), user.getY(), user.getZ(), SoundEvents.ENTITY_GENERIC_EXPLODE.value(), SoundCategory.PLAYERS, 0.1f, 1.2f);
chamber.decrement(1);
stack.set(GUN_COOLDOWN_COMPONENT, cooldownTarget);
doRecoil(player);
doRecoil(user);
if (chamber.isEmpty()) {
stack.remove(GUN_AMMO_COMPONENT);
} else {
stack.set(GUN_AMMO_COMPONENT, chamber);
}
} else if (cooldownTarget > 0) {
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.PLAYERS, 1.0f, 2.0f);
world.playSound(null, user.getX(), user.getY(), user.getZ(), SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.PLAYERS, 1.0f, 2.0f);
} else if (currentReload > 1) {
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
world.playSound(null, user.getX(), user.getY(), user.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
}
updateDamage(stack);
}
}
private @NotNull BulletEntity getBulletEntity(LivingEntity entity, Hand hand, BulletItem bullet, ItemStack chamber) {
boolean isIncendiary = false;
double explosionPower = explosionPowerGun;
double repulsionPower = repulsionPowerGun;
if (bullet != null) {
isIncendiary = bullet.isIncendiary;
explosionPower *= bullet.explosionPowerCoefficient;
repulsionPower *= bullet.repulsionPowerCoefficient;
}
return new BulletEntity(entity, chamber, hand, this, 0.25f, damage, speed, explosionPower, repulsionPower, isIncendiary);
}
}

@ -0,0 +1,181 @@
package systems.brn.plasticgun.guns;
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
import java.util.EnumSet;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.RangedAttackMob;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.item.BowItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Hand;
import net.minecraft.util.math.MathHelper;
import static systems.brn.plasticgun.PlasticGun.guns;
import static systems.brn.plasticgun.PlasticGun.itemGunMap;
import static systems.brn.plasticgun.lib.GunComponents.*;
public class WeaponShootGoal<T extends HostileEntity & RangedAttackMob> extends Goal {
private final T actor;
private final double speed;
private final float squaredRange;
private int targetSeeingTicker;
private boolean movingToLeft;
private boolean backward;
private int combatTicks = -1;
private int lockedTicks = 0;
public WeaponShootGoal(T actor, double speed, float range) {
this.actor = actor;
this.speed = speed;
this.squaredRange = range * range;
this.setControls(EnumSet.of(Control.MOVE, Control.LOOK));
}
public boolean canStart() {
return this.actor.getTarget() != null && this.isHoldingGun();
}
protected boolean isHoldingGun() {
ItemStack mainHandStack = this.actor.getMainHandStack();
ItemStack offhandHandStack = this.actor.getOffHandStack();
return itemGunMap.containsKey(mainHandStack.getItem()) || itemGunMap.containsKey(offhandHandStack.getItem());
}
public boolean shouldContinue() {
return (this.canStart() || !this.actor.getNavigation().isIdle()) && this.isHoldingGun();
}
public void start() {
super.start();
this.actor.setAttacking(true);
}
public void stop() {
super.stop();
this.actor.setAttacking(false);
this.targetSeeingTicker = 0;
this.actor.clearActiveItem();
}
public boolean shouldRunEveryTick() {
return true;
}
public boolean isLookingAtEntity(Entity targetEntity, float yawThreshold, float pitchThreshold) {
double deltaX = targetEntity.getX() - this.actor.getX();
double deltaZ = targetEntity.getZ() - this.actor.getZ();
double deltaY;
if (targetEntity instanceof LivingEntity livingEntity) {
deltaY = livingEntity.getEyeY() - this.actor.getEyeY();
} else {
deltaY = (targetEntity.getBoundingBox().minY + targetEntity.getBoundingBox().maxY) / 2.0 - this.actor.getEyeY();
}
double distance = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ);
float targetYaw = (float) (MathHelper.atan2(deltaZ, deltaX) * (180 / Math.PI)) - 90.0F;
float targetPitch = (float) (-(MathHelper.atan2(deltaY, distance) * (180 / Math.PI)));
float currentYaw = this.actor.getYaw();
float currentPitch = this.actor.getPitch();
float yawDifference = MathHelper.wrapDegrees(currentYaw - targetYaw);
float pitchDifference = MathHelper.wrapDegrees(currentPitch - targetPitch);
return Math.abs(yawDifference) < yawThreshold && Math.abs(pitchDifference) < pitchThreshold;
}
public void tick() {
LivingEntity livingEntity = this.actor.getTarget();
if (livingEntity != null) {
double d = this.actor.squaredDistanceTo(livingEntity.getX(), livingEntity.getY(), livingEntity.getZ());
boolean canSeeTarget = this.actor.getVisibilityCache().canSee(livingEntity);
boolean wasSeeingTarget = this.targetSeeingTicker > 0;
// Update target seeing ticker based on visibility
if (canSeeTarget != wasSeeingTarget) {
this.targetSeeingTicker = 0;
}
this.targetSeeingTicker = canSeeTarget ? this.targetSeeingTicker + 1 : this.targetSeeingTicker - 1;
// Manage navigation and combat ticks
if (d <= this.squaredRange && this.targetSeeingTicker >= 20) {
this.actor.getNavigation().stop();
this.combatTicks++;
} else {
this.actor.getNavigation().startMovingTo(livingEntity, this.speed);
this.combatTicks = -1;
}
// Randomize movement directions
if (this.combatTicks >= 20) {
if (this.actor.getRandom().nextFloat() < 0.3) {
this.movingToLeft = !this.movingToLeft;
}
if (this.actor.getRandom().nextFloat() < 0.3) {
this.backward = !this.backward;
}
this.combatTicks = 0;
}
// Update strafing behavior
if (this.combatTicks > -1) {
if (d > this.squaredRange * 0.75) {
this.backward = false;
} else if (d < this.squaredRange * 0.25) {
this.backward = true;
}
this.actor.getMoveControl().strafeTo(this.backward ? -0.5F : 0.5F, this.movingToLeft ? 0.5F : -0.5F);
}
// Simplified looking at the target
this.actor.lookAtEntity(livingEntity, 30.0F, 30.0F);
if (isLookingAtEntity(livingEntity, 1, 1)) {
lockedTicks++;
} else {
lockedTicks = 0;
}
Hand gunHand = this.actor.getActiveHand();
ItemStack gunStack = this.actor.getStackInHand(gunHand);
if (itemGunMap.containsKey(gunStack.getItem())) {
Gun gun = itemGunMap.get(gunStack.getItem());
// Handle item usage
gun.reload(this.actor.getEntityWorld(), this.actor, gunHand, this.actor.getRandom(), this.actor.getWorld().getLocalDifficulty(this.actor.getBlockPos()));
if (!canSeeTarget && this.targetSeeingTicker < -60) {
this.actor.clearActiveItem();
} else if (canSeeTarget) {
this.actor.clearActiveItem();
int currentReload = gunStack.getOrDefault(GUN_LOADING_COMPONENT, 1);
int currentCooldown = gunStack.getOrDefault(GUN_COOLDOWN_COMPONENT, 1);
ItemStack chamber = gunStack.getOrDefault(GUN_AMMO_COMPONENT, ItemStack.EMPTY).copy();
if (!chamber.isEmpty() && currentReload == 1 && currentCooldown == 0 && lockedTicks >= 10) {
if (this.actor.getEntityWorld() instanceof ServerWorld serverWorld) {
gun.shoot(serverWorld, this.actor, gunHand);
}
}
}
} else if (this.targetSeeingTicker >= -60) {
ItemStack mainHand = this.actor.getStackInHand(Hand.MAIN_HAND);
ItemStack offHand = this.actor.getStackInHand(Hand.OFF_HAND);
if (itemGunMap.containsKey(mainHand.getItem())) {
this.actor.setCurrentHand(Hand.MAIN_HAND);
}
if (itemGunMap.containsKey(offHand.getItem())) {
this.actor.setCurrentHand(Hand.OFF_HAND);
}
}
}
}
}

@ -1,7 +1,9 @@
package systems.brn.plasticgun.lib;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.mob.SkeletonEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.Item;
@ -26,24 +28,14 @@ public class EventHandler {
ItemStack stack = playerEntity.getStackInHand(hand);
if (!world.isClient) {
Item stackInHand = playerEntity.getStackInHand(hand).getItem();
for (Gun gun : guns) {
if (gun == stackInHand) {
gun.reload(world, playerEntity, hand);
break;
}
if (itemGunMap.containsKey(stackInHand)) {
itemGunMap.get(stackInHand).reload(world, playerEntity, hand);
}
for (GrenadeItem grenade : grenades) {
if (grenade != null && grenade == stackInHand) {
grenade.unpin(world, playerEntity, hand);
break;
}
if (itemGrenadeItemMap.containsKey(stackInHand)) {
itemGrenadeItemMap.get(stackInHand).unpin(world, playerEntity, hand);
}
for (ShurikenItem shuriken : shurikens) {
if (shuriken != null && shuriken == stackInHand) {
shuriken.chuck(world, playerEntity, hand);
break;
}
if (itemShurikenItemMap.containsKey(stackInHand)) {
itemShurikenItemMap.get(stackInHand).chuck(world, playerEntity, hand);
}
}
@ -58,75 +50,64 @@ public class EventHandler {
Hand hand = player.getActiveHand();
ItemStack stackInHand = player.getStackInHand(hand);
Item itemInHand = stackInHand.getItem();
for (Gun gun : guns) {
if (gun == itemInHand) {
decrementComponent(GUN_COOLDOWN_COMPONENT, stackInHand);
decrementComponent(GUN_RELOAD_COOLDOWN_COMPONENT, stackInHand);
if (player.handSwinging && player.handSwingTicks == -1) {
gun.shoot(world, player, hand);
}
break;
if (itemGunMap.containsKey(itemInHand)) {
decrementComponent(GUN_COOLDOWN_COMPONENT, stackInHand);
decrementComponent(GUN_RELOAD_COOLDOWN_COMPONENT, stackInHand);
if (player.handSwinging && player.handSwingTicks == -1) {
itemGunMap.get(itemInHand).shoot(world, player, hand);
}
}
for (GrenadeItem grenade : grenades) {
if (grenade != null && grenade == itemInHand) {
if (player.handSwinging && player.handSwingTicks == -1) {
grenade.chuck(world, player, hand);
}
break;
}
if (itemGrenadeItemMap.containsKey(itemInHand)) {
itemGrenadeItemMap.get(itemInHand).chuck(world, player, hand);
}
for (ShurikenItem shuriken : shurikens) {
if (shuriken != null && shuriken == itemInHand) {
if (player.handSwinging && player.handSwingTicks == -1) {
shuriken.chuck(world, player, hand);
}
break;
}
if (itemShurikenItemMap.containsKey(itemInHand)) {
itemShurikenItemMap.get(itemInHand).chuck(world, player, hand);
}
PlayerInventory playerInventory = player.getInventory();
for (int i = 1; i < playerInventory.main.size(); i++) {
ItemStack stackInSlot = playerInventory.main.get(i);
Item itemInSlot = stackInSlot.getItem();
for (GrenadeItem grenadeItem : grenades) {
if (grenadeItem == itemInSlot) {
decrementComponent(GRENADE_TIMER_COMPONENT, stackInSlot);
GrenadeItem.updateDamage(stackInSlot, grenadeItem);
grenadeItem.checkExplosions(world, player, stackInSlot);
}
if (itemGrenadeItemMap.containsKey(itemInSlot)) {
decrementComponent(GRENADE_TIMER_COMPONENT, stackInSlot);
GrenadeItem grenadeItem = itemGrenadeItemMap.get(itemInHand);
GrenadeItem.updateDamage(stackInSlot, grenadeItem);
grenadeItem.checkExplosions(world, player, stackInSlot);
}
}
}
}
for (SkeletonEntity skeletonEntity : world.getEntitiesByType(EntityType.SKELETON, entity -> true)) {
for (ItemStack itemStack : skeletonEntity.getEquippedItems()) {
if (itemGunMap.containsKey(itemStack.getItem())) {
decrementComponent(GUN_COOLDOWN_COMPONENT, itemStack);
decrementComponent(GUN_RELOAD_COOLDOWN_COMPONENT, itemStack);
}
}
}
}
public static void onEntityLoad(Entity entity, ServerWorld world) {
if (entity instanceof ItemEntity itemEntity) {
ItemStack entityStack = itemEntity.getStack();
for (GrenadeItem grenadeItem : grenades) {
if (entityStack.getItem() == grenadeItem) {
Entity owner = itemEntity.getOwner();
int timer = (1 + grenadeItem.explosionTarget) - entityStack.getDamage();
if (timer <= grenadeItem.explosionTarget) {
if (owner instanceof ServerPlayerEntity player) {
GrenadeEntity grenadeEntity = new GrenadeEntity(player, entityStack, timer, 1f, 0, grenadeItem.explosionPower, grenadeItem.repulsionPower, grenadeItem.isIncendiary, grenadeItem.isFragmentation, grenadeItem.flashBangDuration, grenadeItem.stunDuration, grenadeItem.smokeTicks, grenadeItem.smokeRadius, grenadeItem.smokeCount);
grenadeEntity.setVelocity(entity.getVelocity());
world.spawnEntity(grenadeEntity);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
} else {
GrenadeEntity grenadeEntity = new GrenadeEntity(world, entity.getPos(), entityStack, timer, 1f, grenadeItem.explosionPower, grenadeItem.repulsionPower, grenadeItem.isIncendiary, grenadeItem.isFragmentation, grenadeItem.flashBangDuration, grenadeItem.stunDuration, grenadeItem.smokeTicks, grenadeItem.smokeRadius, grenadeItem.smokeCount);
grenadeEntity.setVelocity(entity.getVelocity());
world.spawnEntity(grenadeEntity);
}
entity.discard();
Item item = entityStack.getItem();
if (itemGrenadeItemMap.containsKey(item)) {
GrenadeItem grenadeItem = itemGrenadeItemMap.get(item);
Entity owner = itemEntity.getOwner();
int timer = (1 + grenadeItem.explosionTarget) - entityStack.getDamage();
if (timer <= grenadeItem.explosionTarget) {
if (owner instanceof ServerPlayerEntity player) {
GrenadeEntity grenadeEntity = new GrenadeEntity(player, entityStack, timer, 0.5f, 0, grenadeItem.explosionPower, grenadeItem.repulsionPower, grenadeItem.isIncendiary, grenadeItem.isFragmentation, grenadeItem.flashBangDuration, grenadeItem.stunDuration, grenadeItem.smokeTicks, grenadeItem.smokeRadius, grenadeItem.smokeCount);
grenadeEntity.setVelocity(entity.getVelocity());
world.spawnEntity(grenadeEntity);
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.UI_BUTTON_CLICK.value(), SoundCategory.PLAYERS, 1.0f, 2.0f);
} else {
GrenadeEntity grenadeEntity = new GrenadeEntity(world, entity.getPos(), entityStack, timer, 1f, grenadeItem.explosionPower, grenadeItem.repulsionPower, grenadeItem.isIncendiary, grenadeItem.isFragmentation, grenadeItem.flashBangDuration, grenadeItem.stunDuration, grenadeItem.smokeTicks, grenadeItem.smokeRadius, grenadeItem.smokeCount);
grenadeEntity.setVelocity(entity.getVelocity());
world.spawnEntity(grenadeEntity);
}
break;
entity.discard();
}
}
}

@ -3,6 +3,7 @@ package systems.brn.plasticgun.lib;
import com.mojang.serialization.Codec;
import eu.pb4.polymer.core.api.other.PolymerComponent;
import net.minecraft.component.ComponentType;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
@ -15,6 +16,7 @@ public class GunComponents {
public static final ComponentType<Integer> GUN_LOADING_COMPONENT = register("gun_load", builder -> builder.codec(Codec.INT));
public static final ComponentType<Integer> GUN_COOLDOWN_COMPONENT = register("gun_cooldown", builder -> builder.codec(Codec.INT));
public static final ComponentType<Integer> GUN_RELOAD_COOLDOWN_COMPONENT = register("gun_reload_cooldown", builder -> builder.codec(Codec.INT));
public static final ComponentType<ItemStack> GUN_LAST_LOADED_AMMO = register("gun_last_load", builder -> builder.codec(ItemStack.CODEC));
public static final ComponentType<Integer> GRENADE_TIMER_COMPONENT = register("grenade_tuner", builder -> builder.codec(Codec.INT));
private static <T> ComponentType<T> register(String id, UnaryOperator<ComponentType.Builder<T>> builderOperator) {

@ -22,16 +22,18 @@ import net.minecraft.util.Pair;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.Difficulty;
import net.minecraft.world.LocalDifficulty;
import net.minecraft.world.World;
import net.minecraft.world.explosion.Explosion;
import net.minecraft.world.explosion.ExplosionBehavior;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import systems.brn.plasticgun.PlasticGun;
import systems.brn.plasticgun.defence.WeaponArmor;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.*;
import static net.minecraft.world.explosion.Explosion.getExposure;
import static systems.brn.plasticgun.PlasticGun.MOD_ID;
@ -220,4 +222,43 @@ public class Util {
}
return damage;
}
public static <T extends Item> Map<Item, T> generateItemMap(List<T> extendedItems) {
Map<Item, T> itemMap = new HashMap<>();
for (T item : extendedItems) {
itemMap.put(item, item);
}
return itemMap;
}
public static int getDifficultyAdjustedChance(LocalDifficulty localDifficulty, World world) {
Difficulty worldDifficulty = world.getDifficulty();
// Calculate chance modifiers based on difficulties
float localDifficultyFactor = localDifficulty.getLocalDifficulty();
int worldDifficultyFactor = switch (worldDifficulty) {
case PEACEFUL -> 0;
case EASY -> 1;
case NORMAL -> 2;
case HARD -> 3;
default -> 1;
};
// Determine the chance to equip a gun
int baseChance = 20; // Base chance denominator
return (int) (baseChance / (localDifficultyFactor * worldDifficultyFactor));
}
public static int selectWeaponIndex(Random random, LocalDifficulty localDifficulty, int size) {
double difficultyFactor = localDifficulty.getClampedLocalDifficulty();
double biasFactor = 1.0 - difficultyFactor; // Higher difficulty means lower index less likely
// Bias towards lower indices
double r = random.nextDouble() * biasFactor;
int index = (int) (r * size * size);
// Ensure index is within bounds
return Math.min(index, size - 1);
}
}

@ -0,0 +1,107 @@
package systems.brn.plasticgun.mixins;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.ai.goal.BowAttackGoal;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.entity.mob.AbstractSkeletonEntity;
import net.minecraft.entity.projectile.ProjectileUtil;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.RangedWeaponItem;
import net.minecraft.util.Hand;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.Difficulty;
import net.minecraft.world.LocalDifficulty;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import systems.brn.plasticgun.PlasticGun;
import systems.brn.plasticgun.guns.Gun;
import systems.brn.plasticgun.guns.WeaponShootGoal;
import static systems.brn.plasticgun.PlasticGun.guns;
import static systems.brn.plasticgun.PlasticGun.itemGunMap;
import static systems.brn.plasticgun.lib.Util.getDifficultyAdjustedChance;
@Mixin(AbstractSkeletonEntity.class)
public class AbstractSkeletonEntityGunMixin {
@Unique
protected boolean isHoldingGun() {
AbstractSkeletonEntity thisObject = (AbstractSkeletonEntity) (Object) this;
ItemStack mainHandStack = thisObject.getMainHandStack();
ItemStack offhandHandStack = thisObject.getOffHandStack();
return itemGunMap.containsKey(mainHandStack.getItem()) || itemGunMap.containsKey(offhandHandStack.getItem());
}
@Inject(method = "canUseRangedWeapon", at = @At("HEAD"), cancellable = true)
public void canUseRangedWeapon(RangedWeaponItem weapon, CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(weapon == Items.BOW || itemGunMap.containsKey(weapon));
}
@Inject(method = "updateAttackType", at = @At("HEAD"), cancellable = true)
public void updateAttackType(CallbackInfo ci) {
AbstractSkeletonEntity thisObject = (AbstractSkeletonEntity) (Object) this;
// Remove existing attack goals
thisObject.goalSelector.remove(thisObject.bowAttackGoal);
thisObject.goalSelector.remove(thisObject.meleeAttackGoal);
// Add WeaponShootGoal if holding a gun
if (isHoldingGun()) {
thisObject.goalSelector.add(4, new WeaponShootGoal<>(thisObject, 1.0, 15.0F));
} else {
// Keep existing logic for bows
ItemStack itemStack = thisObject.getStackInHand(ProjectileUtil.getHandPossiblyHolding(thisObject, Items.BOW));
if (itemStack.isOf(Items.BOW)) {
int attackInterval = thisObject.getWorld().getDifficulty() == Difficulty.HARD ? 20 : 40;
BowAttackGoal<AbstractSkeletonEntity> bowAttackGoal = new BowAttackGoal<>(thisObject, 1.0, attackInterval, 15.0F);
thisObject.goalSelector.add(4, bowAttackGoal);
} else {
// Default to melee attack if no bow
MeleeAttackGoal meleeAttackGoal = new MeleeAttackGoal(thisObject, 1.2, false) {
@Override
public void stop() {
super.stop();
thisObject.setAttacking(false);
}
@Override
public void start() {
super.start();
thisObject.setAttacking(true);
}
};
thisObject.goalSelector.add(4, meleeAttackGoal);
}
}
ci.cancel();
}
@Inject(method = "initEquipment", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/AbstractSkeletonEntity;equipStack(Lnet/minecraft/entity/EquipmentSlot;Lnet/minecraft/item/ItemStack;)V"), cancellable = true)
protected void initEquipment(Random random, LocalDifficulty localDifficulty, CallbackInfo ci) {
AbstractSkeletonEntity thisObject = (AbstractSkeletonEntity) (Object) this;
// Get world difficulty
World world = thisObject.getWorld();
int difficultyAdjustedChance = getDifficultyAdjustedChance(localDifficulty, world);
// Equip item based on adjusted chance
if (random.nextInt(difficultyAdjustedChance) == 0) {
thisObject.equipStack(EquipmentSlot.MAINHAND, new ItemStack(guns.get(random.nextInt(guns.size()))));
} else {
thisObject.equipStack(EquipmentSlot.MAINHAND, new ItemStack(Items.BOW));
}
ci.cancel();
}
}

@ -0,0 +1,83 @@
package systems.brn.plasticgun.mixins;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.mob.ZombieEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.Difficulty;
import net.minecraft.world.LocalDifficulty;
import net.minecraft.world.World;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import systems.brn.plasticgun.PlasticGun;
import systems.brn.plasticgun.grenades.GrenadeItem;
import java.util.Arrays;
import static systems.brn.plasticgun.PlasticGun.grenades;
import static systems.brn.plasticgun.lib.Util.getDifficultyAdjustedChance;
import static systems.brn.plasticgun.lib.Util.selectWeaponIndex;
@Mixin(ZombieEntity.class)
public abstract class ZombieGrenadeMixin extends MobEntity {
@Shadow
public abstract void tick();
// Constructor required for the Mixin
protected ZombieGrenadeMixin(EntityType<? extends MobEntity> entityType, World world) {
super(entityType, world);
}
@Inject(method = "initEquipment", at = @At("HEAD"), cancellable = true)
protected void initEquipment(Random random, LocalDifficulty localDifficulty, CallbackInfo ci) {
super.initEquipment(random, localDifficulty);
World world = this.getWorld();
int difficultyAdjustedChance = getDifficultyAdjustedChance(localDifficulty, world);
// Equip item based on adjusted chance
if (random.nextInt(difficultyAdjustedChance) == 0) {
int i = random.nextInt(20);
ItemStack stackToEquip;
if (i < 8) {
stackToEquip = new ItemStack(Items.IRON_SWORD);
} else if (i < 14) {
int grenadeIndex = selectWeaponIndex(random, localDifficulty, grenades.size());
stackToEquip = new ItemStack(grenades.get(grenadeIndex));
Arrays.fill(this.handDropChances, 0F);
} else {
stackToEquip = new ItemStack(Items.IRON_SHOVEL);
}
this.equipStack(EquipmentSlot.MAINHAND, stackToEquip);
}
ci.cancel();
}
@Inject(method = "dropEquipment", at = @At("RETURN"))
protected void dropEquipment(ServerWorld world, DamageSource source, boolean causedByPlayer, CallbackInfo ci) {
ItemStack mainHandItem = this.getEquippedStack(EquipmentSlot.MAINHAND);
ItemStack offHandItem = this.getEquippedStack(EquipmentSlot.OFFHAND);
for (GrenadeItem grenadeItem : grenades) {
if (mainHandItem.getItem() == grenadeItem) {
grenadeItem.turnIntoEntity(this, mainHandItem, 0, grenadeItem.explosionTarget);
break;
}
if (offHandItem.getItem() == grenadeItem) {
grenadeItem.turnIntoEntity(this, offHandItem, 0, grenadeItem.explosionTarget);
break;
}
}
}
}

@ -20,7 +20,7 @@ import static systems.brn.plasticgun.lib.Util.getFinalDamage;
public class ShurikenEntity extends ThrowableProjectile implements PolymerEntity {
public ShurikenEntity(ServerPlayerEntity player, ItemStack itemStack, float speed, double damage) {
super(SHURIKEN_ENTITY_TYPE, player, itemStack, 1f, speed, damage, PickupPermission.ALLOWED, (byte) 0);
super(SHURIKEN_ENTITY_TYPE, player, itemStack, 0.5f, speed, damage, PickupPermission.ALLOWED, (byte) 0);
}
public ShurikenEntity(EntityType<ShurikenEntity> bulletEntityEntityType, World world) {

@ -20,7 +20,7 @@ public class ThrowableProjectile extends PersistentProjectileEntity implements P
private final float scale;
public ThrowableProjectile(EntityType<? extends ThrowableProjectile> entityType, World world, Vec3d pos, ItemStack itemStack, float scale, double damage, PickupPermission pickupPermission, byte penetration) {
super(entityType, pos.getX(), pos.getY() + 1.5d, pos.getZ(), world, itemStack, itemStack);
super(entityType, pos.getX(), pos.getY() + 1.5d, pos.getZ(), world, itemStack, null);
this.pickupType = pickupPermission;
this.setDamage(damage);
this.setSilent(true);

@ -8,6 +8,10 @@
"contact": {},
"license": "MIT",
"icon": "assets/plasticgun/icon.png",
"accessWidener" : "plasticgun.accesswidener",
"mixins": [
"plasticgun.mixins.json"
],
"environment": "*",
"entrypoints": {
"main": [

@ -0,0 +1,5 @@
accessWidener v2 named
accessible field net/minecraft/entity/mob/MobEntity goalSelector Lnet/minecraft/entity/ai/goal/GoalSelector;
accessible field net/minecraft/entity/mob/AbstractSkeletonEntity bowAttackGoal Lnet/minecraft/entity/ai/goal/BowAttackGoal;
accessible field net/minecraft/entity/mob/AbstractSkeletonEntity meleeAttackGoal Lnet/minecraft/entity/ai/goal/MeleeAttackGoal;
accessible method net/minecraft/entity/mob/MobEntity initEquipment (Lnet/minecraft/util/math/random/Random;Lnet/minecraft/world/LocalDifficulty;)V

@ -0,0 +1,15 @@
{
"required": true,
"minVersion": "0.8",
"package": "systems.brn.plasticgun.mixins",
"compatibilityLevel": "JAVA_21",
"mixins": [
"AbstractSkeletonEntityGunMixin",
"ZombieGrenadeMixin"
],
"client": [],
"server": [],
"injectors": {
"defaultRequire": 1
}
}