522 lines
14 KiB
Java
522 lines
14 KiB
Java
package com.atsuishio.superbwarfare.item.gun;
|
|
|
|
import com.atsuishio.superbwarfare.Mod;
|
|
import com.atsuishio.superbwarfare.init.ModCapabilities;
|
|
import com.atsuishio.superbwarfare.client.PoseTool;
|
|
import com.atsuishio.superbwarfare.client.tooltip.component.GunImageComponent;
|
|
import com.atsuishio.superbwarfare.init.ModItems;
|
|
import com.atsuishio.superbwarfare.init.ModPerks;
|
|
import com.atsuishio.superbwarfare.init.ModTags;
|
|
import com.atsuishio.superbwarfare.item.CustomRendererItem;
|
|
import com.atsuishio.superbwarfare.item.gun.data.AttachmentType;
|
|
import com.atsuishio.superbwarfare.item.gun.data.GunData;
|
|
import com.atsuishio.superbwarfare.perk.Perk;
|
|
import com.atsuishio.superbwarfare.tools.AmmoType;
|
|
import net.minecraft.client.model.HumanoidModel;
|
|
import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EquipmentSlotGroup;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.inventory.tooltip.TooltipComponent;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.component.ItemAttributeModifiers;
|
|
import net.minecraft.world.item.enchantment.Enchantment;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.neoforged.bus.api.SubscribeEvent;
|
|
import net.neoforged.fml.common.EventBusSubscriber;
|
|
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
|
|
import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent;
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
import javax.annotation.ParametersAreNonnullByDefault;
|
|
import java.util.ArrayList;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
|
|
@EventBusSubscriber(modid = Mod.MODID, bus = EventBusSubscriber.Bus.MOD)
|
|
public abstract class GunItem extends Item implements CustomRendererItem {
|
|
|
|
public GunItem(Properties properties) {
|
|
super(properties);
|
|
}
|
|
|
|
@Override
|
|
@ParametersAreNonnullByDefault
|
|
public boolean canAttackBlock(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
@ParametersAreNonnullByDefault
|
|
public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, boolean selected) {
|
|
if (!(entity instanceof LivingEntity)
|
|
|| !stack.is(ModTags.Items.GUN)
|
|
|| !(stack.getItem() instanceof GunItem gunItem)
|
|
) return;
|
|
|
|
var data = GunData.from(stack);
|
|
var tag = data.tag();
|
|
|
|
if (!data.initialized()) {
|
|
data.initialize();
|
|
if (level.getServer() != null && entity instanceof Player player && player.isCreative()) {
|
|
data.setAmmo(data.magazine());
|
|
}
|
|
}
|
|
tag.putBoolean("draw", false);
|
|
handleGunPerks(data);
|
|
|
|
var hasBulletInBarrel = gunItem.hasBulletInBarrel(stack);
|
|
var ammoCount = data.ammo();
|
|
var magazine = data.magazine();
|
|
|
|
if ((hasBulletInBarrel && ammoCount > magazine + 1) || (!hasBulletInBarrel && ammoCount > magazine)) {
|
|
int count = ammoCount - magazine - (hasBulletInBarrel ? 1 : 0);
|
|
|
|
var capability = entity.getCapability(ModCapabilities.PLAYER_VARIABLE);
|
|
if (capability != null) {
|
|
if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO)) {
|
|
AmmoType.SHOTGUN.add(capability, count);
|
|
} else if (stack.is(ModTags.Items.USE_SNIPER_AMMO)) {
|
|
AmmoType.SNIPER.add(capability, count);
|
|
} else if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) {
|
|
AmmoType.HANDGUN.add(capability, count);
|
|
} else if (stack.is(ModTags.Items.USE_RIFLE_AMMO)) {
|
|
AmmoType.RIFLE.add(capability, count);
|
|
} else if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) {
|
|
AmmoType.HEAVY.add(capability, count);
|
|
}
|
|
capability.syncPlayerVariables(entity);
|
|
}
|
|
data.setAmmo(magazine + (hasBulletInBarrel ? 1 : 0));
|
|
}
|
|
data.save();
|
|
}
|
|
|
|
@Override
|
|
@ParametersAreNonnullByDefault
|
|
public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStack, boolean slotChanged) {
|
|
return false;
|
|
}
|
|
|
|
private static final ResourceLocation SPEED_ID = Mod.loc("gun_movement_speed");
|
|
|
|
@Override
|
|
public @NotNull ItemAttributeModifiers getDefaultAttributeModifiers(@NotNull ItemStack stack) {
|
|
var list = new ArrayList<>(super.getDefaultAttributeModifiers(stack).modifiers());
|
|
var data = GunData.from(stack);
|
|
|
|
list.add(new ItemAttributeModifiers.Entry(
|
|
Attributes.MOVEMENT_SPEED,
|
|
new AttributeModifier(SPEED_ID,
|
|
-0.01f - 0.005f * data.weight(),
|
|
AttributeModifier.Operation.ADD_MULTIPLIED_BASE
|
|
),
|
|
EquipmentSlotGroup.MAINHAND
|
|
));
|
|
|
|
return new ItemAttributeModifiers(list, true);
|
|
}
|
|
|
|
@Override
|
|
public @NotNull Optional<TooltipComponent> getTooltipImage(@NotNull ItemStack pStack) {
|
|
return Optional.of(new GunImageComponent(pStack));
|
|
}
|
|
|
|
public Set<SoundEvent> getReloadSound() {
|
|
return Set.of();
|
|
}
|
|
|
|
public ResourceLocation getGunIcon() {
|
|
return Mod.loc("textures/gun_icon/default_icon.png");
|
|
}
|
|
|
|
public String getGunDisplayName() {
|
|
return "";
|
|
}
|
|
|
|
@Override
|
|
public boolean isFoil(@NotNull ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean isEnchantable(@NotNull ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
@ParametersAreNonnullByDefault
|
|
public boolean supportsEnchantment(ItemStack stack, Holder<Enchantment> enchantment) {
|
|
return false;
|
|
}
|
|
|
|
|
|
private void handleGunPerks(GunData data) {
|
|
var perk = data.perk;
|
|
|
|
perk.reduceCooldown(ModPerks.HEAL_CLIP, "HealClipTime");
|
|
|
|
perk.reduceCooldown(ModPerks.KILL_CLIP, "KillClipReloadTime");
|
|
perk.reduceCooldown(ModPerks.KILL_CLIP, "KillClipTime");
|
|
|
|
perk.reduceCooldown(ModPerks.FOURTH_TIMES_CHARM, "FourthTimesCharmTick");
|
|
|
|
perk.reduceCooldown(ModPerks.HEAD_SEEKER, "HeadSeeker");
|
|
|
|
perk.reduceCooldown(ModPerks.DESPERADO, "DesperadoTime");
|
|
perk.reduceCooldown(ModPerks.DESPERADO, "DesperadoTimePost");
|
|
|
|
if (perk.getLevel(ModPerks.FOURTH_TIMES_CHARM) > 0) {
|
|
var tag = data.perk.getTag(ModPerks.FOURTH_TIMES_CHARM);
|
|
int count = perk.getTag(ModPerks.FOURTH_TIMES_CHARM).getInt("FourthTimesCharmCount");
|
|
|
|
if (count >= 4) {
|
|
tag.remove("FourthTimesCharmTick");
|
|
tag.remove("FourthTimesCharmCount");
|
|
|
|
int mag = data.magazine();
|
|
data.setAmmo(Math.min(mag, data.ammo() + 2));
|
|
}
|
|
}
|
|
|
|
data.save();
|
|
}
|
|
|
|
public boolean canApplyPerk(Perk perk) {
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* 是否使用弹匣换弹
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean isMagazineReload(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 是否使用弹夹换弹
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean isClipReload(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 是否是单发装填换弹
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean isIterativeReload(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 开膛待击
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean isOpenBolt(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 是否允许额外往枪管里塞入一发子弹
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasBulletInBarrel(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否为全自动武器
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean isAutoWeapon(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否直接使用背包内的弹药物品进行发射,而不是使用玩家存储的弹药
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean useBackpackAmmo(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能进行改装
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean isCustomizable(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能更换枪管配件
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasCustomBarrel(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能更换枪托配件
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasCustomGrip(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能更换弹匣配件
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasCustomMagazine(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能更换瞄具配件
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasCustomScope(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能更换枪托配件
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasCustomStock(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否有脚架
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasBipod(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否会抛壳
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean canEjectShell(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 武器是否能进行近战攻击
|
|
*
|
|
* @param stack 武器物品
|
|
*/
|
|
public boolean hasMeleeAttack(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 获取武器可用的开火模式
|
|
*/
|
|
public int getAvailableFireModes() {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外伤害加成
|
|
*/
|
|
public double getCustomDamage(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外爆头伤害加成
|
|
*/
|
|
public double getCustomHeadshot(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外护甲穿透加成
|
|
*/
|
|
public double getCustomBypassArmor(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外弹匣容量加成
|
|
*/
|
|
public int getCustomMagazine(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外缩放倍率加成
|
|
*/
|
|
public double getCustomZoom(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外RPM加成
|
|
*/
|
|
public int getCustomRPM(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外总重量加成
|
|
*/
|
|
public double getCustomWeight(ItemStack stack) {
|
|
var attachment = GunData.from(stack).attachment;
|
|
|
|
double scopeWeight = switch (attachment.get(AttachmentType.SCOPE)) {
|
|
case 1 -> 0.5;
|
|
case 2 -> 1;
|
|
case 3 -> 1.5;
|
|
default -> 0;
|
|
};
|
|
|
|
double barrelWeight = switch (attachment.get(AttachmentType.BARREL)) {
|
|
case 1 -> 0.5;
|
|
case 2 -> 1;
|
|
default -> 0;
|
|
};
|
|
|
|
double magazineWeight = switch (attachment.get(AttachmentType.MAGAZINE)) {
|
|
case 1 -> 1;
|
|
case 2 -> 2;
|
|
default -> 0;
|
|
};
|
|
|
|
double stockWeight = switch (attachment.get(AttachmentType.STOCK)) {
|
|
case 1 -> -2;
|
|
case 2 -> 1.5;
|
|
default -> 0;
|
|
};
|
|
|
|
double gripWeight = switch (attachment.get(AttachmentType.GRIP)) {
|
|
case 1, 2 -> 0.25;
|
|
case 3 -> 1;
|
|
default -> 0;
|
|
};
|
|
|
|
return scopeWeight + barrelWeight + magazineWeight + stockWeight + gripWeight;
|
|
}
|
|
|
|
/**
|
|
* 获取额外弹速加成
|
|
*/
|
|
public double getCustomVelocity(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 获取额外音效半径加成
|
|
*/
|
|
public double getCustomSoundRadius(ItemStack stack) {
|
|
return GunData.from(stack).attachment.get(AttachmentType.BARREL) == 2 ? 0.6 : 1;
|
|
}
|
|
|
|
public int getCustomBoltActionTime(ItemStack stack) {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 是否允许缩放
|
|
*/
|
|
public boolean canAdjustZoom(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 是否允许切换瞄具
|
|
*/
|
|
public boolean canSwitchScope(ItemStack stack) {
|
|
return false;
|
|
}
|
|
|
|
|
|
/**
|
|
* 右下角弹药显示名称
|
|
*/
|
|
public String getAmmoDisplayName(ItemStack stack) {
|
|
if (stack.is(ModTags.Items.USE_RIFLE_AMMO)) {
|
|
return "Rifle Ammo";
|
|
}
|
|
if (stack.is(ModTags.Items.USE_HANDGUN_AMMO)) {
|
|
return "Handgun Ammo";
|
|
}
|
|
if (stack.is(ModTags.Items.USE_SHOTGUN_AMMO)) {
|
|
return "Shotgun Ammo";
|
|
}
|
|
if (stack.is(ModTags.Items.USE_SNIPER_AMMO)) {
|
|
return "Sniper Ammo";
|
|
}
|
|
if (stack.is(ModTags.Items.USE_HEAVY_AMMO)) {
|
|
return "Heavy Ammo";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
public enum FireMode {
|
|
SEMI(1),
|
|
BURST(2),
|
|
AUTO(4);
|
|
|
|
public final int flag;
|
|
|
|
FireMode(int i) {
|
|
this.flag = i;
|
|
}
|
|
}
|
|
|
|
@SubscribeEvent
|
|
private static void registerGunExtensions(RegisterClientExtensionsEvent event) {
|
|
for (var item : ModItems.GUNS.getEntries()) {
|
|
if (item.get() instanceof GunItem gun) {
|
|
event.registerItem(new IClientItemExtensions() {
|
|
private final BlockEntityWithoutLevelRenderer renderer = gun.getRenderer();
|
|
|
|
@Override
|
|
public @NotNull BlockEntityWithoutLevelRenderer getCustomRenderer() {
|
|
return renderer;
|
|
}
|
|
|
|
@Override
|
|
@ParametersAreNonnullByDefault
|
|
public HumanoidModel.ArmPose getArmPose(LivingEntity entityLiving, InteractionHand hand, ItemStack stack) {
|
|
return PoseTool.pose(entityLiving, hand, stack);
|
|
}
|
|
}, item);
|
|
}
|
|
}
|
|
}
|
|
}
|