Added additional anointments as well as some misc things

Added several Anointments (still need to list them fully).
Also made it so that the Charges can be thrown.
This commit is contained in:
WayofTime 2021-01-15 10:10:55 -05:00
parent e2ce9a473b
commit 5713d6db2a
42 changed files with 1222 additions and 446 deletions

View file

@ -49,6 +49,7 @@ public class Anointment extends ForgeRegistryEntry<Anointment>
private IAttributeProvider attributeProvider;
private IDamageProvider damageProvider;
private boolean consumeOnAttack = false;
private boolean consumeOnUseFinish = false;
private boolean consumeOnHarvest = false;
public Anointment(ResourceLocation key)
@ -204,6 +205,17 @@ public class Anointment extends ForgeRegistryEntry<Anointment>
return this.consumeOnAttack;
}
public Anointment setConsumeOnUseFinish()
{
this.consumeOnUseFinish = true;
return this;
}
public boolean consumeOnUseFinish()
{
return this.consumeOnUseFinish;
}
public Anointment setConsumeOnHarvest()
{
this.consumeOnHarvest = true;

View file

@ -117,6 +117,33 @@ public class AnointmentHolder
return didConsume;
}
public boolean consumeAnointmentDurabilityOnUseFinish(ItemStack weaponStack, EquipmentSlotType type)
{
boolean didConsume = false;
List<Anointment> removedAnointments = new ArrayList<Anointment>();
for (Entry<Anointment, AnointmentData> entry : anointments.entrySet())
{
Anointment annointment = entry.getKey();
if (annointment.consumeOnUseFinish())
{
AnointmentData data = entry.getValue();
data.damage(1);
didConsume = true;
if (data.isMaxDamage())
{
removedAnointments.add(annointment);
}
}
}
for (Anointment anointment : removedAnointments)
{
removeAnointment(weaponStack, type, anointment);
}
return didConsume;
}
public boolean consumeAnointmentDurabilityOnHarvest(ItemStack weaponStack, EquipmentSlotType type)
{
boolean didConsume = false;

View file

@ -32,6 +32,7 @@ import wayoftime.bloodmagic.client.render.block.RenderAlchemyArray;
import wayoftime.bloodmagic.client.render.block.RenderAltar;
import wayoftime.bloodmagic.client.render.block.RenderDemonCrucible;
import wayoftime.bloodmagic.client.render.entity.BloodLightRenderer;
import wayoftime.bloodmagic.client.render.entity.EntityShapedChargeRenderer;
import wayoftime.bloodmagic.client.render.entity.SoulSnareRenderer;
import wayoftime.bloodmagic.client.screens.ScreenAlchemicalReactionChamber;
import wayoftime.bloodmagic.client.screens.ScreenAlchemyTable;
@ -68,7 +69,7 @@ public class ClientEvents
public static void colorHandlerEvent(ColorHandlerEvent.Item event)
{
event.getItemColors().register(new AnointmentColor(), BloodMagicItems.MELEE_DAMAGE_ANOINTMENT.get(), BloodMagicItems.SILK_TOUCH_ANOINTMENT.get(), BloodMagicItems.FORTUNE_ANOINTMENT.get(), BloodMagicItems.HOLY_WATER_ANOINTMENT.get(), BloodMagicItems.HIDDEN_KNOWLEDGE_ANOINTMENT.get());
event.getItemColors().register(new AnointmentColor(), BloodMagicItems.MELEE_DAMAGE_ANOINTMENT.get(), BloodMagicItems.SILK_TOUCH_ANOINTMENT.get(), BloodMagicItems.FORTUNE_ANOINTMENT.get(), BloodMagicItems.HOLY_WATER_ANOINTMENT.get(), BloodMagicItems.HIDDEN_KNOWLEDGE_ANOINTMENT.get(), BloodMagicItems.QUICK_DRAW_ANOINTMENT.get(), BloodMagicItems.LOOTING_ANOINTMENT.get(), BloodMagicItems.BOW_POWER_ANOINTMENT.get(), BloodMagicItems.WILL_POWER_ANOINTMENT.get(), BloodMagicItems.SMELTING_ANOINTMENT.get());
}
@SuppressWarnings("deprecation")
@ -76,6 +77,7 @@ public class ClientEvents
{
RenderingRegistry.registerEntityRenderingHandler(BloodMagicEntityTypes.SNARE.getEntityType(), SoulSnareRenderer::new);
RenderingRegistry.registerEntityRenderingHandler(BloodMagicEntityTypes.BLOOD_LIGHT.getEntityType(), BloodLightRenderer::new);
RenderingRegistry.registerEntityRenderingHandler(BloodMagicEntityTypes.SHAPED_CHARGE.getEntityType(), EntityShapedChargeRenderer::new);
DeferredWorkQueue.runLater(() -> {
RenderType rendertype = RenderType.getCutoutMipped();

View file

@ -0,0 +1,68 @@
package wayoftime.bloodmagic.client.render.entity;
import java.util.Random;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.block.BlockRenderType;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.BlockRendererDispatcher;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.client.renderer.entity.EntityRendererManager;
import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import wayoftime.bloodmagic.entity.projectile.EntityShapedCharge;
@OnlyIn(Dist.CLIENT)
public class EntityShapedChargeRenderer extends EntityRenderer<EntityShapedCharge>
{
public EntityShapedChargeRenderer(EntityRendererManager renderManagerIn)
{
super(renderManagerIn);
this.shadowSize = 0.5F;
}
public void render(EntityShapedCharge entityIn, float entityYaw, float partialTicks, MatrixStack matrixStackIn, IRenderTypeBuffer bufferIn, int packedLightIn)
{
// System.out.println("Testing~");
BlockState blockstate = entityIn.getBlockState();
if (blockstate.getRenderType() == BlockRenderType.MODEL)
{
World world = entityIn.getWorldObj();
if (blockstate != world.getBlockState(entityIn.getPosition()) && blockstate.getRenderType() != BlockRenderType.INVISIBLE)
{
matrixStackIn.push();
BlockPos blockpos = new BlockPos(entityIn.getPosX(), entityIn.getBoundingBox().maxY, entityIn.getPosZ());
matrixStackIn.translate(-0.5D, 0.0D, -0.5D);
BlockRendererDispatcher blockrendererdispatcher = Minecraft.getInstance().getBlockRendererDispatcher();
for (net.minecraft.client.renderer.RenderType type : net.minecraft.client.renderer.RenderType.getBlockRenderTypes())
{
if (RenderTypeLookup.canRenderInLayer(blockstate, type))
{
net.minecraftforge.client.ForgeHooksClient.setRenderLayer(type);
blockrendererdispatcher.getBlockModelRenderer().renderModel(world, blockrendererdispatcher.getModelForState(blockstate), blockstate, blockpos, matrixStackIn, bufferIn.getBuffer(type), false, new Random(), 0, OverlayTexture.NO_OVERLAY);
}
}
net.minecraftforge.client.ForgeHooksClient.setRenderLayer(null);
matrixStackIn.pop();
super.render(entityIn, entityYaw, partialTicks, matrixStackIn, bufferIn, packedLightIn);
}
}
}
/**
* Returns the location of an entity's texture.
*/
public ResourceLocation getEntityTexture(EntityShapedCharge entity)
{
return AtlasTexture.LOCATION_BLOCKS_TEXTURE;
}
}

View file

@ -98,6 +98,12 @@ public class GeneratorItemModels extends ItemModelProvider
registerMultiLayerItem(BloodMagicItems.FORTUNE_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
registerMultiLayerItem(BloodMagicItems.HOLY_WATER_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
registerMultiLayerItem(BloodMagicItems.HIDDEN_KNOWLEDGE_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
registerMultiLayerItem(BloodMagicItems.QUICK_DRAW_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
registerMultiLayerItem(BloodMagicItems.LOOTING_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
registerMultiLayerItem(BloodMagicItems.BOW_POWER_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
registerMultiLayerItem(BloodMagicItems.WILL_POWER_ANOINTMENT.get(), modLoc("item/alchemic_vial_will"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon_will"));
registerMultiLayerItem(BloodMagicItems.SMELTING_ANOINTMENT.get(), modLoc("item/alchemic_vial"), modLoc("item/alchemic_liquid"), modLoc("item/alchemic_ribbon"));
}
private void registerCustomFullTexture(Block block, String texturePath)

View file

@ -352,6 +352,9 @@ public class GeneratorLanguage extends LanguageProvider
add("anointment.bloodmagic.fortune", "Fortunate");
add("anointment.bloodmagic.holy_water", "Holy Light");
add("anointment.bloodmagic.hidden_knowledge", "Hidden Knowledge");
add("anointment.bloodmagic.quick_draw", "Deft Hands");
add("anointment.bloodmagic.bow_power", "Heavy Shot");
add("anointment.bloodmagic.looting", "Plundering");
// Guide
add("guide.bloodmagic.name", "Sanguine Scientiem");
@ -538,6 +541,9 @@ public class GeneratorLanguage extends LanguageProvider
addItem(BloodMagicItems.FORTUNE_ANOINTMENT, "Fortuna Extract");
addItem(BloodMagicItems.HOLY_WATER_ANOINTMENT, "Holy Water");
addItem(BloodMagicItems.HIDDEN_KNOWLEDGE_ANOINTMENT, "Liquid Knowledge");
addItem(BloodMagicItems.QUICK_DRAW_ANOINTMENT, "Dexterity Alkahest");
addItem(BloodMagicItems.BOW_POWER_ANOINTMENT, "Iron Tip");
addItem(BloodMagicItems.LOOTING_ANOINTMENT, "Plunderer's Glint");
// Alchemy Items
addItem(BloodMagicItems.PLANT_OIL, "Plant Oil");

View file

@ -13,6 +13,7 @@ import wayoftime.bloodmagic.common.block.BloodMagicBlocks;
import wayoftime.bloodmagic.common.item.arc.ItemARCToolBase;
import wayoftime.bloodmagic.common.item.block.ItemBlockAlchemyTable;
import wayoftime.bloodmagic.common.item.block.ItemBlockMimic;
import wayoftime.bloodmagic.common.item.block.ItemBlockShapedCharge;
import wayoftime.bloodmagic.common.item.sigil.ItemSigilAir;
import wayoftime.bloodmagic.common.item.sigil.ItemSigilBloodLight;
import wayoftime.bloodmagic.common.item.sigil.ItemSigilDivination;
@ -97,8 +98,8 @@ public class BloodMagicItems
public static final RegistryObject<Item> NETHE_SOIL_ITEM = ITEMS.register("nether_soil", () -> new BlockItem(BloodMagicBlocks.NETHER_SOIL.get(), new Item.Properties().group(BloodMagic.TAB)));
public static final RegistryObject<Item> GROWING_DOUBT_ITEM = ITEMS.register("growing_doubt", () -> new BlockItem(BloodMagicBlocks.GROWING_DOUBT.get(), new Item.Properties().group(BloodMagic.TAB)));
public static final RegistryObject<Item> SHAPED_CHARGE_ITEM = ITEMS.register("shaped_charge", () -> new BlockItem(BloodMagicBlocks.SHAPED_CHARGE.get(), new Item.Properties().group(BloodMagic.TAB)));
public static final RegistryObject<Item> DEFORESTER_CHARGE_ITEM = ITEMS.register("deforester_charge", () -> new BlockItem(BloodMagicBlocks.DEFORESTER_CHARGE.get(), new Item.Properties().group(BloodMagic.TAB)));
public static final RegistryObject<Item> SHAPED_CHARGE_ITEM = ITEMS.register("shaped_charge", () -> new ItemBlockShapedCharge(BloodMagicBlocks.SHAPED_CHARGE.get(), new Item.Properties().group(BloodMagic.TAB)));
public static final RegistryObject<Item> DEFORESTER_CHARGE_ITEM = ITEMS.register("deforester_charge", () -> new ItemBlockShapedCharge(BloodMagicBlocks.DEFORESTER_CHARGE.get(), new Item.Properties().group(BloodMagic.TAB)));
// TODO: Need to rework the above instantiations for the ItemBlocks so that it's
// done with the Blocks.
@ -224,6 +225,11 @@ public class BloodMagicItems
public static final RegistryObject<Item> FORTUNE_ANOINTMENT = ITEMS.register("fortune_anointment", () -> new ItemAnointmentProvider(BloodMagic.rl("fortune"), 3381504, 1, 256));
public static final RegistryObject<Item> HOLY_WATER_ANOINTMENT = ITEMS.register("holy_water_anointment", () -> new ItemAnointmentProvider(BloodMagic.rl("holy_water"), 0xC6E6FB, 1, 256));
public static final RegistryObject<Item> HIDDEN_KNOWLEDGE_ANOINTMENT = ITEMS.register("hidden_knowledge_anointment", () -> new ItemAnointmentProvider(BloodMagic.rl("hidden_knowledge"), 0xC8F902, 1, 256));
public static final RegistryObject<Item> QUICK_DRAW_ANOINTMENT = ITEMS.register("quick_draw_anointment", () -> new ItemBowAnointmentProvider(BloodMagic.rl("quick_draw"), 0xF0E130, 1, 256, true));
public static final RegistryObject<Item> LOOTING_ANOINTMENT = ITEMS.register("looting_anointment", () -> new ItemAnointmentProvider(BloodMagic.rl("looting"), 0x6D2AFF, 1, 256));
public static final RegistryObject<Item> BOW_POWER_ANOINTMENT = ITEMS.register("bow_power_anointment", () -> new ItemBowAnointmentProvider(BloodMagic.rl("bow_power"), 0xD8D8D8, 1, 256, true));
public static final RegistryObject<Item> WILL_POWER_ANOINTMENT = ITEMS.register("will_power_anointment", () -> new ItemAnointmentProvider(BloodMagic.rl("will_power"), 0xD8D8D8, 1, 256));
public static final RegistryObject<Item> SMELTING_ANOINTMENT = ITEMS.register("smelting_anointment", () -> new ItemAnointmentProvider(BloodMagic.rl("smelting"), 0xCE2029, 1, 256));
// Fragments
public static final RegistryObject<Item> IRON_FRAGMENT = BASICITEMS.register("ironfragment", () -> new ItemBase());

View file

@ -77,7 +77,7 @@ public class ItemAnointmentProvider extends Item
}
stack.shrink(1);
holder.toItemStack(weaponStack);
return ActionResult.resultSuccess(stack);
return ActionResult.resultConsume(stack);
}
}
} else
@ -100,6 +100,8 @@ public class ItemAnointmentProvider extends Item
world.addParticle(flag1 ? ParticleTypes.AMBIENT_ENTITY_EFFECT
: ParticleTypes.ENTITY_EFFECT, player.getPosXRandom(0.3D), player.getPosYRandom(), player.getPosZRandom(0.3D), d0, d1, d2);
}
return ActionResult.resultConsume(stack);
}
}
}

View file

@ -0,0 +1,32 @@
package wayoftime.bloodmagic.common.item;
import net.minecraft.item.BowItem;
import net.minecraft.item.CrossbowItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
public class ItemBowAnointmentProvider extends ItemAnointmentProvider
{
boolean crossbowsValid;
public ItemBowAnointmentProvider(ResourceLocation anointRL, int colour, int level, int maxDamage, boolean crossbowsValid)
{
super(anointRL, colour, level, maxDamage);
this.crossbowsValid = crossbowsValid;
}
public boolean isItemValidForApplication(ItemStack stack)
{
return isItemBow(stack) || (crossbowsValid && isItemCrossbow(stack));
}
public static boolean isItemBow(ItemStack stack)
{
return (stack.getItem() instanceof BowItem);
}
public static boolean isItemCrossbow(ItemStack stack)
{
return (stack.getItem() instanceof CrossbowItem);
}
}

View file

@ -0,0 +1,49 @@
package wayoftime.bloodmagic.common.item.block;
import net.minecraft.block.Block;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvents;
import net.minecraft.world.World;
import wayoftime.bloodmagic.entity.projectile.EntityShapedCharge;
public class ItemBlockShapedCharge extends BlockItem
{
public ItemBlockShapedCharge(Block blockIn, Properties builder)
{
super(blockIn, builder);
}
@Override
public ActionResult<ItemStack> onItemRightClick(World worldIn, PlayerEntity playerIn, Hand hand)
{
ItemStack stack = playerIn.getHeldItem(hand);
if (!playerIn.isCreative())
{
stack.shrink(1);
}
worldIn.playSound((PlayerEntity) null, playerIn.getPosX(), playerIn.getPosY(), playerIn.getPosZ(), SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (random.nextFloat() * 0.4F + 0.8F));
if (!worldIn.isRemote)
{
System.out.println("Attempting to spawn");
// EntitySoulSnare snare = new EntitySoulSnare(worldIn, playerIn);
EntityShapedCharge charge = new EntityShapedCharge(worldIn, this.getBlock(), playerIn);
charge.func_234612_a_(playerIn, playerIn.rotationPitch, playerIn.rotationYaw, 0.0F, 1.5F, 1.0F);
worldIn.addEntity(charge);
//
// SnowballEntity snowballentity = new SnowballEntity(worldIn, playerIn);
// snowballentity.setItem(itemstack);
// snowballentity.func_234612_a_(playerIn, playerIn.rotationPitch, playerIn.rotationYaw, 0.0F, 1.5F, 1.0F);
// worldIn.addEntity(snowballentity);
}
return new ActionResult<>(ActionResultType.SUCCESS, stack);
}
}

View file

@ -6,7 +6,6 @@ import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.SnowballItem;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
@ -22,8 +21,7 @@ import wayoftime.bloodmagic.entity.projectile.EntitySoulSnare;
public class ItemSoulSnare extends Item
{
public static String[] names =
{ "base" };
public static String[] names = { "base" };
public ItemSoulSnare()
{
@ -44,14 +42,11 @@ public class ItemSoulSnare extends Item
stack.shrink(1);
}
SnowballItem d;
worldIn.playSound((PlayerEntity) null, playerIn.getPosX(), playerIn.getPosY(), playerIn.getPosZ(), SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F
/ (random.nextFloat() * 0.4F + 0.8F));
worldIn.playSound((PlayerEntity) null, playerIn.getPosX(), playerIn.getPosY(), playerIn.getPosZ(), SoundEvents.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (random.nextFloat() * 0.4F + 0.8F));
if (!worldIn.isRemote)
{
System.out.println("Attempting to spawn");
// System.out.println("Attempting to spawn");
EntitySoulSnare snare = new EntitySoulSnare(worldIn, playerIn);
snare.func_234612_a_(playerIn, playerIn.rotationPitch, playerIn.rotationYaw, 0.0F, 1.5F, 1.0F);
worldIn.addEntity(snare);

View file

@ -29,6 +29,7 @@ public class AlchemyTableRecipeProvider implements ISubRecipeProvider
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(Items.CLAY_BALL, 2), 50, 100, 2).addIngredient(Ingredient.fromTag(Tags.Items.SAND)).addIngredient(Ingredient.fromTag(Tags.Items.SAND)).addIngredient(Ingredient.fromItems(Items.WATER_BUCKET)).build(consumer, BloodMagic.rl(basePath + "clay_from_sand"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(Items.COBWEB), 50, 50, 1).addIngredient(Ingredient.fromTag(Tags.Items.STRING)).addIngredient(Ingredient.fromTag(Tags.Items.STRING)).addIngredient(Ingredient.fromTag(Tags.Items.STRING)).build(consumer, BloodMagic.rl(basePath + "cobweb"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(Items.NETHER_WART), 50, 40, 1).addIngredient(Ingredient.fromItems(Items.NETHER_WART_BLOCK)).build(consumer, BloodMagic.rl(basePath + "nether_wart_from_block"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(Items.GOLD_NUGGET, 9), 200, 100, 2).addIngredient(Ingredient.fromItems(Items.GILDED_BLACKSTONE)).build(consumer, BloodMagic.rl(basePath + "gold_ore_from_gilded"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(Items.GUNPOWDER, 3), 0, 100, 0).addIngredient(Ingredient.fromTag(BloodMagicTags.DUST_SULFUR)).addIngredient(Ingredient.fromTag(BloodMagicTags.DUST_SALTPETER)).addIngredient(Ingredient.fromTag(ItemTags.COALS)).build(consumer, BloodMagic.rl(basePath + "gunpowder"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(BloodMagicItems.PLANT_OIL.get()), 100, 100, 1).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_CARROT)).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_CARROT)).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_CARROT)).addIngredient(Ingredient.fromItems(Items.BONE_MEAL)).build(consumer, BloodMagic.rl(basePath + "plantoil_from_carrots"));
@ -48,5 +49,6 @@ public class AlchemyTableRecipeProvider implements ISubRecipeProvider
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(BloodMagicItems.MELEE_DAMAGE_ANOINTMENT.get()), 500, 100, 1).addIngredient(Ingredient.fromItems(BloodMagicItems.SLATE_VIAL.get())).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_NETHER_WART)).addIngredient(Ingredient.fromItems(Items.BLAZE_POWDER)).addIngredient(Ingredient.fromTag(Tags.Items.GEMS_QUARTZ)).build(consumer, BloodMagic.rl(basePath + "melee_damage_anointment"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(BloodMagicItems.HOLY_WATER_ANOINTMENT.get()), 500, 100, 1).addIngredient(Ingredient.fromItems(BloodMagicItems.SLATE_VIAL.get())).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_NETHER_WART)).addIngredient(Ingredient.fromItems(Items.GLISTERING_MELON_SLICE)).addIngredient(Ingredient.fromTag(Tags.Items.GEMS_QUARTZ)).build(consumer, BloodMagic.rl(basePath + "holy_water_anointment"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(BloodMagicItems.HIDDEN_KNOWLEDGE_ANOINTMENT.get()), 500, 100, 1).addIngredient(Ingredient.fromItems(BloodMagicItems.SLATE_VIAL.get())).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_NETHER_WART)).addIngredient(Ingredient.fromItems(Items.GLASS_BOTTLE)).addIngredient(Ingredient.fromItems(Items.ENCHANTED_BOOK)).build(consumer, BloodMagic.rl(basePath + "hidden_knowledge_anointment"));
AlchemyTableRecipeBuilder.alchemyTable(new ItemStack(BloodMagicItems.QUICK_DRAW_ANOINTMENT.get()), 500, 100, 1).addIngredient(Ingredient.fromItems(BloodMagicItems.SLATE_VIAL.get())).addIngredient(Ingredient.fromTag(Tags.Items.CROPS_NETHER_WART)).addIngredient(Ingredient.fromTag(Tags.Items.STRING)).addIngredient(Ingredient.fromItems(Items.SPECTRAL_ARROW)).build(consumer, BloodMagic.rl(basePath + "quick_draw_anointment"));
}
}

View file

@ -6,6 +6,7 @@ import wayoftime.bloodmagic.BloodMagic;
import wayoftime.bloodmagic.common.registration.impl.EntityTypeDeferredRegister;
import wayoftime.bloodmagic.common.registration.impl.EntityTypeRegistryObject;
import wayoftime.bloodmagic.entity.projectile.EntityBloodLight;
import wayoftime.bloodmagic.entity.projectile.EntityShapedCharge;
import wayoftime.bloodmagic.entity.projectile.EntitySoulSnare;
public class BloodMagicEntityTypes
@ -19,4 +20,6 @@ public class BloodMagicEntityTypes
public static final EntityTypeRegistryObject<EntitySoulSnare> SNARE = ENTITY_TYPES.register("soulsnare", EntityType.Builder.<EntitySoulSnare>create(EntitySoulSnare::new, EntityClassification.MISC).setTrackingRange(64).setUpdateInterval(1).size(0.25f, 0.25f));
public static final EntityTypeRegistryObject<EntityBloodLight> BLOOD_LIGHT = ENTITY_TYPES.register("bloodlight", EntityType.Builder.<EntityBloodLight>create(EntityBloodLight::new, EntityClassification.MISC).setTrackingRange(64).setUpdateInterval(1).size(0.25f, 0.25f));
public static final EntityTypeRegistryObject<EntityShapedCharge> SHAPED_CHARGE = ENTITY_TYPES.register("shapedcharge", EntityType.Builder.<EntityShapedCharge>create(EntityShapedCharge::new, EntityClassification.MISC).setTrackingRange(64).setUpdateInterval(1).size(0.4f, 0.4f));
}

View file

@ -26,6 +26,8 @@ public class AnointmentRegistrar
def.put("melee_damage", BloodMagic.rl("melee_damage"));
def.put("holy_water", BloodMagic.rl("holy_water"));
def.put("hidden_knowledge", BloodMagic.rl("hidden_knowledge"));
def.put("quick_draw", BloodMagic.rl("quick_draw"));
def.put("bow_power", BloodMagic.rl("bow_power"));
// def.put("arrow_shot", BloodMagic.rl("arrow_shot"));
// def.put("critical_strike", BloodMagic.rl("critical_strike"));
// def.put("digging", BloodMagic.rl("digging"));
@ -66,6 +68,16 @@ public class AnointmentRegistrar
public static final AnointmentRegistryObject<Anointment> ANOINTMENT_HIDDEN_KNOWLEDGE = ANOINTMENTS.register("hidden_knowledge", () -> parseDefinition("hidden_knowledge").setConsumeOnHarvest());
public static final AnointmentRegistryObject<Anointment> ANOINTMENT_QUICK_DRAW = ANOINTMENTS.register("quick_draw", () -> parseDefinition("quick_draw").setConsumeOnUseFinish());
public static final AnointmentRegistryObject<Anointment> ANOINTMENT_LOOTING = ANOINTMENTS.register("looting", () -> new Anointment(BloodMagic.rl("looting")).setConsumeOnAttack());
public static final AnointmentRegistryObject<Anointment> ANOINTMENT_BOW_POWER = ANOINTMENTS.register("bow_power", () -> parseDefinition("bow_power").setConsumeOnUseFinish());
public static final AnointmentRegistryObject<Anointment> ANOINTMENT_WILL_POWER = ANOINTMENTS.register("will_power", () -> new Anointment(BloodMagic.rl("will_power")).setConsumeOnAttack());
public static final AnointmentRegistryObject<Anointment> ANOINTMENT_SMELTING = ANOINTMENTS.register("smelting", () -> new Anointment(BloodMagic.rl("smelting")).setConsumeOnHarvest());
public static void register()
{
registerAnointment(ANOINTMENT_MELEE_DAMAGE.get());
@ -73,6 +85,12 @@ public class AnointmentRegistrar
registerAnointment(ANOINTMENT_FORTUNE.get());
registerAnointment(ANOINTMENT_HOLY_WATER.get());
registerAnointment(ANOINTMENT_HIDDEN_KNOWLEDGE.get());
registerAnointment(ANOINTMENT_QUICK_DRAW.get());
registerAnointment(ANOINTMENT_LOOTING.get());
registerAnointment(ANOINTMENT_BOW_POWER.get());
registerAnointment(ANOINTMENT_WILL_POWER.get());
registerAnointment(ANOINTMENT_SMELTING.get());
// Registry.register(UPGRADES, UPGRADE_ARROW_PROTECT.getKey(), UPGRADE_ARROW_PROTECT);
// Registry.register(UPGRADES, UPGRADE_ARROW_SHOT.getKey(), UPGRADE_ARROW_SHOT);
// Registry.register(UPGRADES, UPGRADE_CRITICAL_STRIKE.getKey(), UPGRADE_CRITICAL_STRIKE);

View file

@ -1,6 +1,7 @@
package wayoftime.bloodmagic.entity.projectile;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.projectile.ProjectileHelper;
@ -11,6 +12,7 @@ import net.minecraft.network.IPacket;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
@ -60,7 +62,8 @@ public class EntityBloodLight extends ProjectileItemEntity
{
BlockPos blockpos = ((BlockRayTraceResult) raytraceresult).getPos().offset(((BlockRayTraceResult) raytraceresult).getFace());
BlockState blockstate = this.world.getBlockState(blockpos);
if (blockstate.isAir())
Material material = blockstate.getMaterial();
if (blockstate.isAir() || blockstate.isIn(BlockTags.FIRE) || material.isLiquid() || material.isReplaceable())
{
this.getEntityWorld().setBlockState(blockpos, BloodMagicBlocks.BLOOD_LIGHT.get().getDefaultState());
this.setDead();

View file

@ -0,0 +1,153 @@
package wayoftime.bloodmagic.entity.projectile;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.projectile.ProjectileHelper;
import net.minecraft.entity.projectile.ThrowableEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.NBTUtil;
import net.minecraft.network.IPacket;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.network.NetworkHooks;
import wayoftime.bloodmagic.common.block.BlockShapedExplosive;
import wayoftime.bloodmagic.common.block.BloodMagicBlocks;
import wayoftime.bloodmagic.common.registries.BloodMagicEntityTypes;
public class EntityShapedCharge extends ThrowableEntity
{
// private static final DataParameter<Optional<BlockState>> ITEMSTACK_DATA = EntityDataManager.createKey(ProjectileItemEntity.class, DataSerializers.OPTIONAL_BLOCK_STATE);
private BlockState fallTile = BloodMagicBlocks.SHAPED_CHARGE.get().getDefaultState();
public EntityShapedCharge(EntityType<EntityShapedCharge> p_i50159_1_, World p_i50159_2_)
{
super(p_i50159_1_, p_i50159_2_);
}
public EntityShapedCharge(World worldIn, Block block, LivingEntity throwerIn)
{
super(BloodMagicEntityTypes.SHAPED_CHARGE.getEntityType(), throwerIn, worldIn);
this.fallTile = block.getDefaultState();
}
public EntityShapedCharge(World worldIn, Block block, double x, double y, double z)
{
super(BloodMagicEntityTypes.SHAPED_CHARGE.getEntityType(), x, y, z, worldIn);
this.fallTile = block.getDefaultState();
}
@Override
public void tick()
{
super.tick();
RayTraceResult raytraceresult = ProjectileHelper.func_234618_a_(this, this::func_230298_a_);
// boolean flag = false;
if (raytraceresult.getType() == RayTraceResult.Type.BLOCK)
{
Direction faceHit = ((BlockRayTraceResult) raytraceresult).getFace();
BlockPos blockpos = ((BlockRayTraceResult) raytraceresult).getPos().offset(((BlockRayTraceResult) raytraceresult).getFace());
BlockState blockstate = this.world.getBlockState(blockpos);
Material material = blockstate.getMaterial();
// return state.isAir() || state.isIn(BlockTags.FIRE) || material.isLiquid() || material.isReplaceable();
if (blockstate.isAir() || blockstate.isIn(BlockTags.FIRE) || material.isLiquid() || material.isReplaceable())
{
this.getEntityWorld().setBlockState(blockpos, fallTile.with(BlockShapedExplosive.ATTACHED, faceHit));
this.setDead();
} else
{
// BlockItem d;
this.entityDropItem(fallTile.getBlock());
this.setDead();
// blockstate.isReplaceable(BlockItemUseContext)
}
}
}
@Override
protected void writeAdditional(CompoundNBT compound)
{
compound.put("BlockState", NBTUtil.writeBlockState(this.fallTile));
// compound.putInt("Time", this.fallTime);
// compound.putBoolean("DropItem", this.shouldDropItem);
// compound.putBoolean("HurtEntities", this.hurtEntities);
// compound.putFloat("FallHurtAmount", this.fallHurtAmount);
// compound.putInt("FallHurtMax", this.fallHurtMax);
// if (this.tileEntityData != null) {
// compound.put("TileEntityData", this.tileEntityData);
// }
}
/**
* (abstract) Protected helper method to read subclass entity data from NBT.
*/
@Override
protected void readAdditional(CompoundNBT compound)
{
this.fallTile = NBTUtil.readBlockState(compound.getCompound("BlockState"));
// this.fallTime = compound.getInt("Time");
// if (compound.contains("HurtEntities", 99)) {
// this.hurtEntities = compound.getBoolean("HurtEntities");
// this.fallHurtAmount = compound.getFloat("FallHurtAmount");
// this.fallHurtMax = compound.getInt("FallHurtMax");
// } else if (this.fallTile.isIn(BlockTags.ANVIL)) {
// this.hurtEntities = true;
// }
//
// if (compound.contains("DropItem", 99)) {
// this.shouldDropItem = compound.getBoolean("DropItem");
// }
//
// if (compound.contains("TileEntityData", 10)) {
// this.tileEntityData = compound.getCompound("TileEntityData");
// }
System.out.println("Reading additional data");
if (this.fallTile.isAir())
{
this.fallTile = BloodMagicBlocks.SHAPED_CHARGE.get().getDefaultState();
}
}
@Override
protected void registerData()
{
// TODO Auto-generated method stub
}
public BlockState getBlockState()
{
// TODO Auto-generated method stub
return fallTile;
}
@OnlyIn(Dist.CLIENT)
public World getWorldObj()
{
return this.world;
}
// @Override
// public IPacket<?> createSpawnPacket()
// {
// return new SSpawnObjectPacket(this, Block.getStateId(this.getBlockState()));
// }
@Override
public IPacket<?> createSpawnPacket()
{
return NetworkHooks.getEntitySpawningPacket(this);
}
}

View file

@ -89,6 +89,5 @@ public class EntitySoulSnare extends ProjectileItemEntity
this.world.addParticle(iparticledata, this.getPosX(), this.getPosY(), this.getPosZ(), 0.0D, 0.0D, 0.0D);
}
}
}
}

View file

@ -1,5 +1,6 @@
package wayoftime.bloodmagic.loot;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
@ -8,7 +9,10 @@ import com.google.gson.JsonObject;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipe;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.loot.LootContext;
import net.minecraft.loot.LootParameterSets;
import net.minecraft.loot.LootParameters;
@ -18,6 +22,7 @@ import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.loot.GlobalLootModifierSerializer;
import net.minecraftforge.common.loot.LootModifier;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import wayoftime.bloodmagic.BloodMagic;
@ -29,6 +34,8 @@ public class GlobalLootModifier
public static final DeferredRegister<GlobalLootModifierSerializer<?>> GLM = DeferredRegister.create(ForgeRegistries.LOOT_MODIFIER_SERIALIZERS, BloodMagic.MODID);
public static final RegistryObject<SilkTouchTestModifier.Serializer> SILKTOUCH = GLM.register("silk_touch_bamboo", SilkTouchTestModifier.Serializer::new);
public static final RegistryObject<FortuneModifier.Serializer> FORTUNE = GLM.register("fortune", FortuneModifier.Serializer::new);
public static final RegistryObject<LootingModifier.Serializer> LOOTING = GLM.register("looting", LootingModifier.Serializer::new);
public static final RegistryObject<SmeltingModifier.Serializer> SMELT = GLM.register("smelt", SmeltingModifier.Serializer::new);
private static class SilkTouchTestModifier extends LootModifier
{
@ -114,10 +121,10 @@ public class GlobalLootModifier
return generatedLoot;
}
if (holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_SILK_TOUCH.get()) > 0)
{
return generatedLoot;
}
// if (holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_SILK_TOUCH.get()) > 0)
// {
// return generatedLoot;
// }
ItemStack fakeTool = ctxTool.copy();
fakeTool.getOrCreateTag().putBoolean("bloodmagic:checked_fortune", true);
@ -146,4 +153,128 @@ public class GlobalLootModifier
}
}
}
private static class LootingModifier extends LootModifier
{
public LootingModifier(ILootCondition[] conditionsIn)
{
super(conditionsIn);
}
@Nonnull
@Override
public List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context)
{
// System.out.println("Checking for looting");
ItemStack ctxTool = context.get(LootParameters.TOOL);
// return early if silk-touch is already applied (otherwise we'll get stuck in
// an infinite loop).
if (ctxTool.getTag() != null && ctxTool.getTag().getBoolean("bloodmagic:checked_looting"))
{
return generatedLoot;
}
if (EnchantmentHelper.getEnchantments(ctxTool).containsKey(Enchantments.SILK_TOUCH))
return generatedLoot;
AnointmentHolder holder = AnointmentHolder.fromItemStack(ctxTool);
if (holder == null)
{
return generatedLoot;
}
int additionalLooting = holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_LOOTING.get());
if (additionalLooting <= 0)
{
return generatedLoot;
}
// if (holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_SILK_TOUCH.get()) > 0)
// {
// return generatedLoot;
// }
ItemStack fakeTool = ctxTool.copy();
fakeTool.getOrCreateTag().putBoolean("bloodmagic:checked_looting", true);
int baseLootingLevel = EnchantmentHelper.getEnchantmentLevel(Enchantments.LOOTING, ctxTool);
fakeTool.addEnchantment(Enchantments.LOOTING, baseLootingLevel + additionalLooting);
LootContext.Builder builder = new LootContext.Builder(context);
builder.withParameter(LootParameters.TOOL, fakeTool);
LootContext ctx = builder.build(LootParameterSets.BLOCK);
LootTable loottable = context.getWorld().getServer().getLootTableManager().getLootTableFromLocation(context.get(LootParameters.BLOCK_STATE).getBlock().getLootTable());
return loottable.generate(ctx);
}
private static class Serializer extends GlobalLootModifierSerializer<LootingModifier>
{
@Override
public LootingModifier read(ResourceLocation name, JsonObject json, ILootCondition[] conditionsIn)
{
return new LootingModifier(conditionsIn);
}
@Override
public JsonObject write(LootingModifier instance)
{
return makeConditions(instance.conditions);
}
}
}
private static class SmeltingModifier extends LootModifier
{
public SmeltingModifier(ILootCondition[] conditionsIn)
{
super(conditionsIn);
}
@Nonnull
@Override
public List<ItemStack> doApply(List<ItemStack> generatedLoot, LootContext context)
{
ItemStack ctxTool = context.get(LootParameters.TOOL);
// return early if silk-touch is already applied (otherwise we'll get stuck in
// an infinite loop).
if (ctxTool.getTag() != null)
{
return generatedLoot;
}
AnointmentHolder holder = AnointmentHolder.fromItemStack(ctxTool);
if (holder == null)
{
return generatedLoot;
}
int smeltingLevel = holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_SMELTING.get());
if (smeltingLevel <= 0)
{
return generatedLoot;
}
ArrayList<ItemStack> ret = new ArrayList<ItemStack>();
generatedLoot.forEach((stack) -> ret.add(smelt(stack, context)));
return ret;
}
private static ItemStack smelt(ItemStack stack, LootContext context)
{
return context.getWorld().getRecipeManager().getRecipe(IRecipeType.SMELTING, new Inventory(stack), context.getWorld()).map(FurnaceRecipe::getRecipeOutput).filter(itemStack -> !itemStack.isEmpty()).map(itemStack -> ItemHandlerHelper.copyStackWithSize(itemStack, stack.getCount() * itemStack.getCount())).orElse(stack);
}
private static class Serializer extends GlobalLootModifierSerializer<SmeltingModifier>
{
@Override
public SmeltingModifier read(ResourceLocation name, JsonObject json, ILootCondition[] conditionsIn)
{
return new SmeltingModifier(conditionsIn);
}
@Override
public JsonObject write(SmeltingModifier instance)
{
return makeConditions(instance.conditions);
}
}
}
}

View file

@ -11,16 +11,22 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.entity.projectile.ArrowEntity;
import net.minecraft.inventory.EquipmentSlotType;
import net.minecraft.item.BowItem;
import net.minecraft.item.CrossbowItem;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.EffectInstance;
import net.minecraft.potion.Effects;
import net.minecraft.util.DamageSource;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.Tags;
import net.minecraftforge.common.ToolType;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.event.entity.living.LivingDamageEvent;
import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent;
import net.minecraftforge.event.entity.living.LivingEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingJumpEvent;
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
@ -552,4 +558,108 @@ public class GenericHandler
AnointmentHolder holder = AnointmentHolder.fromItemStack(stack);
AnointmentHolder.appendAnointmentTooltip(holder, event.getToolTip());
}
private static final Map<ItemStack, Double> rollMap = new HashMap<ItemStack, Double>();
@SubscribeEvent
public void onEntityUseTick(LivingEntityUseItemEvent.Tick event)
{
ItemStack stack = event.getItem();
if (stack.getItem() instanceof BowItem || stack.getItem() instanceof CrossbowItem)
{
AnointmentHolder holder = AnointmentHolder.fromItemStack(stack);
int quickDrawLevel = holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_QUICK_DRAW.get());
if (quickDrawLevel > 0)
{
double amount = rollMap.getOrDefault(stack, 0D) + AnointmentRegistrar.ANOINTMENT_QUICK_DRAW.get().getBonusValue("speed", quickDrawLevel).doubleValue();
if (amount >= 1)
{
int drawReduction = (int) amount;
event.setDuration(event.getDuration() - drawReduction);
} else
{
rollMap.put(stack, amount);
}
}
}
}
@SubscribeEvent
public void onEntityFinishUse(LivingEntityUseItemEvent.Stop event)
{
ItemStack stack = event.getItem();
if (stack.getItem() instanceof CrossbowItem)
{
int i = stack.getUseDuration() - event.getDuration();
float f = getCharge(i, stack);
if (f < 0)
{
return;
}
}
AnointmentHolder holder = AnointmentHolder.fromItemStack(stack);
if (holder != null)
{
if (holder.consumeAnointmentDurabilityOnUseFinish(stack, EquipmentSlotType.MAINHAND))
{
holder.toItemStack(stack);
}
}
}
@SubscribeEvent
public void onEntityJoinEvent(EntityJoinWorldEvent event)
{
Entity entity = event.getEntity();
if (entity instanceof ArrowEntity)
{
if (entity.ticksExisted <= 0)
{
// System.out.println("An arrow joined the world! Looking for the shooter...");
ArrowEntity arrowEntity = (ArrowEntity) entity;
Entity shooter = arrowEntity.func_234616_v_();
if (shooter instanceof PlayerEntity)
{
PlayerEntity playerShooter = (PlayerEntity) shooter;
for (Hand hand : Hand.values())
{
ItemStack heldStack = playerShooter.getHeldItem(hand);
AnointmentHolder holder = AnointmentHolder.fromItemStack(heldStack);
if (holder == null)
{
continue;
}
int powerLevel = holder.getAnointmentLevel(AnointmentRegistrar.ANOINTMENT_BOW_POWER.get());
if (powerLevel > 0)
{
arrowEntity.setDamage(arrowEntity.getDamage() * AnointmentRegistrar.ANOINTMENT_BOW_POWER.get().getBonusValue("damage", powerLevel).doubleValue());
// System.out.println("Arrow damage is now: " + arrowEntity.getDamage());
}
break;
}
}
}
}
}
private static float getCharge(int useTime, ItemStack stack)
{
float f = (float) useTime / (float) getChargeTime(stack);
if (f > 1.0F)
{
f = 1.0F;
}
return f;
}
public static int getChargeTime(ItemStack stack)
{
int i = EnchantmentHelper.getEnchantmentLevel(Enchantments.QUICK_CHARGE, stack);
return i == 0 ? 25 : 25 - 5 * i;
}
}