Skeleton go pew pew
Also zombie go boom
This commit is contained in:
parent
8d00672806
commit
653171cbb2
@ -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);
|
||||
}
|
||||
}
|
181
src/main/java/systems/brn/plasticgun/guns/WeaponShootGoal.java
Normal file
181
src/main/java/systems/brn/plasticgun/guns/WeaponShootGoal.java
Normal file
@ -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": [
|
||||
|
5
src/main/resources/plasticgun.accesswidener
Normal file
5
src/main/resources/plasticgun.accesswidener
Normal file
@ -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
|
15
src/main/resources/plasticgun.mixins.json
Normal file
15
src/main/resources/plasticgun.mixins.json
Normal file
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user