possibly impl arbitrary brainsweeps. i don't know. i'm in offline mode

This commit is contained in:
petrak@ 2022-11-22 19:31:09 -06:00
parent 30701702c7
commit 7c00cbaec8
18 changed files with 439 additions and 423 deletions

View file

@ -13,9 +13,9 @@ import net.minecraft.core.BlockPos
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.decoration.ArmorStand
import net.minecraft.world.entity.item.ItemEntity
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.phys.Vec3
import java.util.function.DoubleUnaryOperator
import kotlin.math.abs
@ -99,14 +99,14 @@ fun List<Iota>.getPlayer(idx: Int, argc: Int = 0): ServerPlayer {
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.player")
}
fun List<Iota>.getVillager(idx: Int, argc: Int = 0): Villager {
fun List<Iota>.getMob(idx: Int, argc: Int = 0): Mob {
val x = this.getOrElse(idx) { throw MishapNotEnoughArgs(idx + 1, this.size) }
if (x is EntityIota) {
val e = x.entity
if (e is Villager)
if (e is Mob)
return e
}
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.villager")
throw MishapInvalidIota.ofType(x, if (argc == 0) idx else argc - (idx + 1), "entity.mob")
}
fun List<Iota>.getLivingEntityButNotArmorStand(idx: Int, argc: Int = 0): LivingEntity {

View file

@ -2,22 +2,22 @@ package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.casting.CastingContext
import net.minecraft.world.entity.npc.Villager
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.world.entity.Mob
import net.minecraft.world.item.DyeColor
class MishapAlreadyBrainswept(val villager: Villager) : Mishap() {
class MishapAlreadyBrainswept(val mob: Mob) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.GREEN)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
villager.hurt(HexDamageSources.overcastDamageFrom(ctx.caster), villager.health)
mob.hurt(HexDamageSources.overcastDamageFrom(ctx.caster), mob.health)
}
override fun particleSpray(ctx: CastingContext) =
ParticleSpray.burst(villager.eyePosition, 1.0)
ParticleSpray.burst(mob.eyePosition, 1.0)
override fun errorMessage(ctx: CastingContext, errorCtx: Context) =
error("already_brainswept")

View file

@ -3,19 +3,19 @@ package at.petrak.hexcasting.api.spell.mishaps
import at.petrak.hexcasting.api.misc.FrozenColorizer
import at.petrak.hexcasting.api.misc.HexDamageSources
import at.petrak.hexcasting.api.spell.ParticleSpray
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.entity.Mob
import net.minecraft.world.item.DyeColor
import net.minecraft.world.phys.Vec3
class MishapBadBrainsweep(val villager: Villager, val pos: BlockPos) : Mishap() {
class MishapBadBrainsweep(val mob: Mob, val pos: BlockPos) : Mishap() {
override fun accentColor(ctx: CastingContext, errorCtx: Context): FrozenColorizer =
dyeColor(DyeColor.GREEN)
override fun execute(ctx: CastingContext, errorCtx: Context, stack: MutableList<Iota>) {
trulyHurt(villager, HexDamageSources.overcastDamageFrom(ctx.caster), villager.health)
trulyHurt(mob, HexDamageSources.overcastDamageFrom(ctx.caster), mob.health)
}
override fun particleSpray(ctx: CastingContext): ParticleSpray {

View file

@ -1,19 +1,20 @@
package at.petrak.hexcasting.common.casting.operators.spells.great
import at.petrak.hexcasting.api.misc.MediaConstants
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.spell.*
import at.petrak.hexcasting.api.spell.casting.CastingContext
import at.petrak.hexcasting.api.spell.iota.Iota
import at.petrak.hexcasting.api.spell.mishaps.MishapAlreadyBrainswept
import at.petrak.hexcasting.api.spell.mishaps.MishapBadBrainsweep
import at.petrak.hexcasting.common.misc.Brainsweeping
import at.petrak.hexcasting.common.recipe.BrainsweepRecipe
import at.petrak.hexcasting.common.recipe.HexRecipeStuffRegistry
import at.petrak.hexcasting.ktxt.tellWitnessesThatIWasMurdered
import at.petrak.hexcasting.mixin.accessor.AccessorLivingEntity
import at.petrak.hexcasting.xplat.IXplatAbstractions
import net.minecraft.core.BlockPos
import net.minecraft.sounds.SoundEvents
import net.minecraft.sounds.SoundSource
import net.minecraft.world.entity.Mob
import net.minecraft.world.entity.npc.Villager
import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.phys.Vec3
@ -30,12 +31,12 @@ object OpBrainsweep : SpellAction {
args: List<Iota>,
ctx: CastingContext
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val sacrifice = args.getVillager(0, argc)
val sacrifice = args.getMob(0, argc)
val pos = args.getBlockPos(1, argc)
ctx.assertVecInRange(pos)
ctx.assertEntityInRange(sacrifice)
if (Brainsweeping.isBrainswept(sacrifice))
if (IXplatAbstractions.INSTANCE.isBrainswept(sacrifice))
throw MishapAlreadyBrainswept(sacrifice)
val state = ctx.world.getBlockState(pos)
@ -45,12 +46,12 @@ object OpBrainsweep : SpellAction {
val recman = ctx.world.recipeManager
val recipes = recman.getAllRecipesFor(HexRecipeStuffRegistry.BRAINSWEEP_TYPE)
val recipe = recipes.find { it.matches(state, sacrifice) }
val recipe = recipes.find { it.matches(state, sacrifice, ctx.world) }
?: throw MishapBadBrainsweep(sacrifice, pos)
return Triple(
Spell(pos, state, sacrifice, recipe),
10 * MediaConstants.CRYSTAL_UNIT,
recipe.mediaCost,
listOf(ParticleSpray.cloud(sacrifice.position(), 1.0), ParticleSpray.burst(Vec3.atCenterOf(pos), 0.3, 100))
)
}
@ -58,18 +59,20 @@ object OpBrainsweep : SpellAction {
private data class Spell(
val pos: BlockPos,
val state: BlockState,
val sacrifice: Villager,
val sacrifice: Mob,
val recipe: BrainsweepRecipe
) : RenderedSpell {
override fun cast(ctx: CastingContext) {
ctx.world.setBlockAndUpdate(pos, BrainsweepRecipe.copyProperties(state, recipe.result))
Brainsweeping.brainsweep(sacrifice)
if (HexConfig.server().doVillagersTakeOffenseAtMindMurder()) {
IXplatAbstractions.INSTANCE.brainsweep(sacrifice)
if (sacrifice is Villager && HexConfig.server().doVillagersTakeOffenseAtMindMurder()) {
sacrifice.tellWitnessesThatIWasMurdered(ctx.caster)
}
ctx.world.playSound(null, sacrifice, SoundEvents.VILLAGER_DEATH, SoundSource.AMBIENT, 0.8f, 1f)
val sound = (sacrifice as AccessorLivingEntity).`hex$getDeathSound`()
if (sound != null)
ctx.world.playSound(null, sacrifice, sound, SoundSource.AMBIENT, 0.8f, 1f)
ctx.world.playSound(null, sacrifice, SoundEvents.PLAYER_LEVELUP, SoundSource.AMBIENT, 0.5f, 0.8f)
}
}

View file

@ -6,43 +6,24 @@ import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.npc.VillagerDataHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.EntityHitResult;
import org.jetbrains.annotations.Nullable;
public class Brainsweeping {
// Keeping these functions in Brainsweeping just so we have to change less code
public static void brainsweep(Mob entity) {
if (isValidTarget(entity)) {
IXplatAbstractions.INSTANCE.brainsweep(entity);
}
}
public static boolean isBrainswept(Mob entity) {
return isValidTarget(entity) && IXplatAbstractions.INSTANCE.isBrainswept(entity);
}
// TODO: make this a tag
public static boolean isValidTarget(Mob mob) {
return mob instanceof VillagerDataHolder || mob instanceof Raider;
}
public static InteractionResult tradeWithVillager(Player player, Level world, InteractionHand hand, Entity entity,
@Nullable EntityHitResult hitResult) {
if (entity instanceof Villager v && IXplatAbstractions.INSTANCE.isBrainswept(v)) {
public static InteractionResult interactWithBrainswept(Player player, Level world, InteractionHand hand,
Entity entity, @Nullable EntityHitResult hitResult) {
if (entity instanceof Mob mob && IXplatAbstractions.INSTANCE.isBrainswept(mob)) {
return InteractionResult.FAIL;
}
return InteractionResult.PASS;
}
public static InteractionResult copyBrainsweepFromVillager(LivingEntity original, LivingEntity outcome) {
public static InteractionResult copyBrainsweepPostTransformation(LivingEntity original, LivingEntity outcome) {
if (original instanceof Mob mOriginal && outcome instanceof Mob mOutcome
&& IXplatAbstractions.INSTANCE.isBrainswept(mOriginal) && Brainsweeping.isValidTarget(mOutcome)) {
&& IXplatAbstractions.INSTANCE.isBrainswept(mOriginal)) {
IXplatAbstractions.INSTANCE.brainsweep(mOutcome);
}
return InteractionResult.PASS;

View file

@ -6,9 +6,10 @@ import at.petrak.hexcasting.common.recipe.ingredient.brainsweep.BrainsweepIngred
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.Container;
import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
@ -23,11 +24,12 @@ import org.jetbrains.annotations.NotNull;
public record BrainsweepRecipe(
ResourceLocation id,
StateIngredient blockIn,
BrainsweepIngredient villagerIn,
BrainsweepIngredient entityIn,
int mediaCost,
BlockState result
) implements Recipe<Container> {
public boolean matches(BlockState blockIn, Villager villagerIn) {
return this.blockIn.test(blockIn) && this.villagerIn.test(villagerIn);
public boolean matches(BlockState blockIn, Entity victim, ServerLevel level) {
return this.blockIn.test(blockIn) && this.entityIn.test(victim, level);
}
@Override
@ -84,15 +86,17 @@ public record BrainsweepRecipe(
@Override
public @NotNull BrainsweepRecipe fromJson(ResourceLocation recipeID, JsonObject json) {
var blockIn = StateIngredientHelper.deserialize(GsonHelper.getAsJsonObject(json, "blockIn"));
var villagerIn = BrainsweepIngredient.deserialize(GsonHelper.getAsJsonObject(json, "villagerIn"));
var villagerIn = BrainsweepIngredient.deserialize(GsonHelper.getAsJsonObject(json, "entityIn"));
var cost = GsonHelper.getAsInt(json, "cost");
var result = StateIngredientHelper.readBlockState(GsonHelper.getAsJsonObject(json, "result"));
return new BrainsweepRecipe(recipeID, blockIn, villagerIn, result);
return new BrainsweepRecipe(recipeID, blockIn, villagerIn, cost, result);
}
@Override
public void toNetwork(FriendlyByteBuf buf, BrainsweepRecipe recipe) {
recipe.blockIn.write(buf);
recipe.villagerIn.write(buf);
recipe.entityIn.write(buf);
buf.writeVarInt(recipe.mediaCost);
buf.writeVarInt(Block.getId(recipe.result));
}
@ -100,8 +104,9 @@ public record BrainsweepRecipe(
public @NotNull BrainsweepRecipe fromNetwork(ResourceLocation recipeID, FriendlyByteBuf buf) {
var blockIn = StateIngredientHelper.read(buf);
var villagerIn = BrainsweepIngredient.read(buf);
var cost = buf.readVarInt();
var result = Block.stateById(buf.readVarInt());
return new BrainsweepRecipe(recipeID, blockIn, villagerIn, result);
return new BrainsweepRecipe(recipeID, blockIn, villagerIn, cost, result);
}
}
}

View file

@ -3,14 +3,16 @@ package at.petrak.hexcasting.common.recipe.ingredient.brainsweep;
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.GsonHelper;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity;
import java.util.List;
import java.util.function.Predicate;
public abstract class BrainsweepIngredient implements Predicate<Entity> {
public abstract class BrainsweepIngredient {
public abstract boolean test(Entity entity, ServerLevel level);
public abstract List<Component> getTooltip(boolean advanced);
public abstract JsonObject serialize();
@ -21,8 +23,7 @@ public abstract class BrainsweepIngredient implements Predicate<Entity> {
var type = buf.readVarInt();
return switch (Type.values()[type]) {
case VILLAGER -> VillagerBrainsweepIngredient.read(buf);
case ENTITY -> {
}
case ENTITY -> EntityBrainsweepIngredient.read(buf);
};
}
@ -31,7 +32,7 @@ public abstract class BrainsweepIngredient implements Predicate<Entity> {
var type = Type.valueOf(typestr);
return switch (type) {
case VILLAGER -> VillagerBrainsweepIngredient.deserialize(json);
case ENTITY -> null;
case ENTITY -> EntityBrainsweepIngredient.deserialize(json);
};
}

View file

@ -1,30 +1,35 @@
package at.petrak.hexcasting.common.recipe.ingredient.brainsweep;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.advancements.critereon.DeserializationContext;
import net.minecraft.advancements.critereon.EntityPredicate;
import net.minecraft.advancements.critereon.SerializationContext;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import java.util.List;
// Code based on:
// https://github.com/SlimeKnights/Mantle/blob/1.18.2/src/main/java/slimeknights/mantle/recipe/ingredient/EntityIngredient.java
// Licensed under MIT
public class EntityBrainsweepIngredient extends BrainsweepIngredient {
public final EntityPredicate.Composite requirements;
public static final Gson GSON = new GsonBuilder().create();
public final EntityPredicate requirements;
// Just tell the player what it is you want
public final Component tooltip;
protected EntityBrainsweepIngredient(EntityPredicate.Composite requirements, Component tooltip) {
super();
public EntityBrainsweepIngredient(EntityPredicate requirements, Component tooltip) {
this.requirements = requirements;
this.tooltip = tooltip;
}
@Override
public boolean test(Entity entity) {
return false;
public boolean test(Entity entity, ServerLevel level) {
return this.requirements.matches(level, null, entity);
}
@Override
@ -35,17 +40,32 @@ public class EntityBrainsweepIngredient extends BrainsweepIngredient {
@Override
public JsonObject serialize() {
var obj = new JsonObject();
obj.add("requirements", this.requirements.toJson(SerializationContext.INSTANCE));
obj.addProperty("type", "entity");
obj.add("requirements", this.requirements.serializeToJson());
obj.addProperty("tooltip", Component.Serializer.toJson(this.tooltip));
return obj;
}
@Override
public void write(FriendlyByteBuf buf) {
buf.writeVarInt(Type.ENTITY.ordinal());
buf.writeUtf(this.requirements.serializeToJson().toString());
buf.writeUtf(Component.Serializer.toJson(this.tooltip));
}
public static EntityBrainsweepIngredient deserialize(JsonObject obj) {
var reqs = EntityPredicate.Composite.fromJson(obj, "requirements", DeserializationContext)
var reqs = EntityPredicate.fromJson(obj.get("requirements"));
var tooltip = Component.Serializer.fromJson(obj.get("tooltip"));
return new EntityBrainsweepIngredient(reqs, tooltip);
}
public static EntityBrainsweepIngredient read(FriendlyByteBuf buf) {
var reqsObj = GSON.fromJson(buf.readUtf(), JsonElement.class);
var reqs = EntityPredicate.fromJson(reqsObj);
var tooltip = Component.Serializer.fromJson(buf.readUtf());
return new EntityBrainsweepIngredient(reqs, tooltip);
}
}

View file

@ -8,6 +8,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
@ -26,19 +27,18 @@ public class VillagerBrainsweepIngredient extends BrainsweepIngredient {
private final @Nullable ResourceLocation biome;
private final int minLevel;
protected VillagerBrainsweepIngredient(
public VillagerBrainsweepIngredient(
@Nullable ResourceLocation profession,
@Nullable ResourceLocation biome, // aka their "type"
int minLevel
) {
super();
this.profession = profession;
this.biome = biome;
this.minLevel = minLevel;
}
@Override
public boolean test(Entity entity) {
public boolean test(Entity entity, ServerLevel level) {
if (!(entity instanceof Villager villager)) return false;
var data = villager.getVillagerData();
@ -153,14 +153,15 @@ public class VillagerBrainsweepIngredient extends BrainsweepIngredient {
public static VillagerBrainsweepIngredient deserialize(JsonObject json) {
ResourceLocation profession = null;
if (json.has("profession")) {
if (json.has("profession") && !json.get("profession").isJsonNull()) {
profession = new ResourceLocation(GsonHelper.getAsString(json, "profession"));
}
ResourceLocation biome = null;
if (json.has("biome")) {
if (json.has("biome") && !json.get("biome").isJsonNull()) {
biome = new ResourceLocation(GsonHelper.getAsString(json, "biome"));
}
int minLevel = GsonHelper.getAsInt(json, "minLevel");
int cost = GsonHelper.getAsInt(json, "cost");
return new VillagerBrainsweepIngredient(profession, biome, minLevel);
}

View file

@ -2,6 +2,7 @@ package at.petrak.hexcasting.datagen.recipe
import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.advancements.OvercastTrigger
import at.petrak.hexcasting.api.misc.MediaConstants
import at.petrak.hexcasting.api.mod.HexItemTags
import at.petrak.hexcasting.common.items.ItemStaff
import at.petrak.hexcasting.common.items.colorizer.ItemPrideColorizer
@ -10,7 +11,7 @@ import at.petrak.hexcasting.common.lib.HexItems
import at.petrak.hexcasting.common.recipe.SealFocusRecipe
import at.petrak.hexcasting.common.recipe.SealSpellbookRecipe
import at.petrak.hexcasting.common.recipe.ingredient.StateIngredientHelper
import at.petrak.hexcasting.common.recipe.ingredient.brainsweep.BrainsweepIngredient
import at.petrak.hexcasting.common.recipe.ingredient.brainsweep.VillagerBrainsweepIngredient
import at.petrak.hexcasting.datagen.IXplatConditionsBuilder
import at.petrak.hexcasting.datagen.IXplatIngredients
import at.petrak.hexcasting.datagen.recipe.builders.BrainsweepRecipeBuilder
@ -351,38 +352,38 @@ class HexplatRecipes(
.unlockedBy("enlightenment", enlightenment).save(recipes)
BrainsweepRecipeBuilder(StateIngredientHelper.of(Blocks.AMETHYST_BLOCK),
BrainsweepIngredient(null, null, 3),
Blocks.BUDDING_AMETHYST.defaultBlockState())
VillagerBrainsweepIngredient(null, null, 3),
Blocks.BUDDING_AMETHYST.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10)
.unlockedBy("enlightenment", enlightenment)
.save(recipes, modLoc("brainsweep/budding_amethyst"))
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
BrainsweepIngredient(ResourceLocation("toolsmith"), null, 2),
HexBlocks.IMPETUS_RIGHTCLICK.defaultBlockState())
VillagerBrainsweepIngredient(ResourceLocation("toolsmith"), null, 2),
HexBlocks.IMPETUS_RIGHTCLICK.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10)
.unlockedBy("enlightenment", enlightenment)
.save(recipes, modLoc("brainsweep/impetus_rightclick"))
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
BrainsweepIngredient(ResourceLocation("fletcher"), null, 2),
HexBlocks.IMPETUS_LOOK.defaultBlockState())
VillagerBrainsweepIngredient(ResourceLocation("fletcher"), null, 2),
HexBlocks.IMPETUS_LOOK.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10)
.unlockedBy("enlightenment", enlightenment)
.save(recipes, modLoc("brainsweep/impetus_look"))
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_IMPETUS),
BrainsweepIngredient(ResourceLocation("cleric"), null, 2),
HexBlocks.IMPETUS_STOREDPLAYER.defaultBlockState())
VillagerBrainsweepIngredient(ResourceLocation("cleric"), null, 2),
HexBlocks.IMPETUS_STOREDPLAYER.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10)
.unlockedBy("enlightenment", enlightenment)
.save(recipes, modLoc("brainsweep/impetus_storedplayer"))
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.EMPTY_DIRECTRIX),
BrainsweepIngredient(ResourceLocation("mason"), null, 1),
HexBlocks.DIRECTRIX_REDSTONE.defaultBlockState())
VillagerBrainsweepIngredient(ResourceLocation("mason"), null, 1),
HexBlocks.DIRECTRIX_REDSTONE.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10)
.unlockedBy("enlightenment", enlightenment)
.save(recipes, modLoc("brainsweep/directrix_redstone"))
BrainsweepRecipeBuilder(StateIngredientHelper.of(HexBlocks.AKASHIC_LIGATURE),
BrainsweepIngredient(ResourceLocation("librarian"), null, 5),
HexBlocks.AKASHIC_RECORD.defaultBlockState())
VillagerBrainsweepIngredient(ResourceLocation("librarian"), null, 5),
HexBlocks.AKASHIC_RECORD.defaultBlockState(), MediaConstants.CRYSTAL_UNIT * 10)
.unlockedBy("enlightenment", enlightenment)
.save(recipes, modLoc("brainsweep/akashic_record"))

View file

@ -21,16 +21,19 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
public class BrainsweepRecipeBuilder implements RecipeBuilder {
private StateIngredient blockIn;
private BrainsweepIngredient villagerIn;
private final StateIngredient blockIn;
private final BrainsweepIngredient villagerIn;
private final int mediaCost;
private final BlockState result;
private final Advancement.Builder advancement;
public BrainsweepRecipeBuilder(StateIngredient blockIn, BrainsweepIngredient villagerIn, BlockState result) {
public BrainsweepRecipeBuilder(StateIngredient blockIn, BrainsweepIngredient villagerIn, BlockState result,
int mediaCost) {
this.blockIn = blockIn;
this.villagerIn = villagerIn;
this.result = result;
this.mediaCost = mediaCost;
this.advancement = Advancement.Builder.advancement();
}
@ -62,18 +65,19 @@ public class BrainsweepRecipeBuilder implements RecipeBuilder {
.requirements(RequirementsStrategy.OR);
pFinishedRecipeConsumer.accept(new Result(
pRecipeId,
this.blockIn, this.villagerIn, this.result,
this.blockIn, this.villagerIn, this.mediaCost, this.result,
this.advancement,
new ResourceLocation(pRecipeId.getNamespace(), "recipes/brainsweep/" + pRecipeId.getPath())));
}
public record Result(ResourceLocation id, StateIngredient blockIn, BrainsweepIngredient villagerIn,
BlockState result, Advancement.Builder advancement,
int mediaCost, BlockState result, Advancement.Builder advancement,
ResourceLocation advancementId) implements FinishedRecipe {
@Override
public void serializeRecipeData(JsonObject json) {
json.add("blockIn", this.blockIn.serialize());
json.add("villagerIn", this.villagerIn.serialize());
json.add("entityIn", this.villagerIn.serialize());
json.addProperty("cost", this.mediaCost);
json.add("result", StateIngredientHelper.serializeBlockState(this.result));
}

View file

@ -47,11 +47,11 @@ public class BrainsweepProcessor implements IComponentProcessor {
}
case "entity" -> {
var profession = Objects.requireNonNullElse(this.recipe.villagerIn().profession(),
var profession = Objects.requireNonNullElse(this.recipe.entityIn().profession(),
new ResourceLocation("toolsmith"));
var biome = Objects.requireNonNullElse(this.recipe.villagerIn().biome(),
var biome = Objects.requireNonNullElse(this.recipe.entityIn().biome(),
new ResourceLocation("plains"));
var level = this.recipe.villagerIn().minLevel();
var level = this.recipe.entityIn().minLevel();
var iHatePatchouli = String.format(
"minecraft:villager{VillagerData:{profession:'%s',type:'%s',level:%d}}",
profession, biome, level);
@ -59,7 +59,7 @@ public class BrainsweepProcessor implements IComponentProcessor {
}
case "entityTooltip" -> {
Minecraft mc = Minecraft.getInstance();
return IVariable.wrapList(this.recipe.villagerIn()
return IVariable.wrapList(this.recipe.entityIn()
.getTooltip(mc.options.advancedItemTooltips)
.stream()
.map(IVariable::from)

View file

@ -1,6 +1,6 @@
package at.petrak.hexcasting.mixin;
import at.petrak.hexcasting.common.misc.Brainsweeping;
import at.petrak.hexcasting.xplat.IXplatAbstractions;
import net.minecraft.world.entity.Mob;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -13,7 +13,7 @@ public class MixinMob {
@Inject(method = "serverAiStep", at = @At("HEAD"), cancellable = true)
private void onRegisterBrainGoals(CallbackInfo ci) {
var self = (Mob) (Object) this;
if (Brainsweeping.isBrainswept(self)) {
if (IXplatAbstractions.INSTANCE.isBrainswept(self)) {
ci.cancel();
}
}
@ -21,7 +21,7 @@ public class MixinMob {
@Inject(method = "playAmbientSound", at = @At("HEAD"), cancellable = true)
protected void onPlayAmbientSound(CallbackInfo ci) {
var self = (Mob) (Object) this;
if (Brainsweeping.isBrainswept(self)) {
if (IXplatAbstractions.INSTANCE.isBrainswept(self)) {
ci.cancel();
}
}

View file

@ -253,7 +253,7 @@
"command.hexcasting.pats.specific.success": "Gave %s with id %s to %s",
"command.hexcasting.recalc": "Recalculated patterns",
"command.hexcasting.brainsweep": "Brainswept %s",
"command.hexcasting.brainsweep.fail.badtype": "%s is not a villager",
"command.hexcasting.brainsweep.fail.badtype": "%s is not a mob",
"command.hexcasting.brainsweep.fail.already": "%s is already empty",
"hexcasting.pattern.unknown": "Unknown pattern resource location %s",
"hexcasting.debug.media_withdrawn": "%s - Media withdrawn: %s",
@ -561,8 +561,8 @@
"hexcasting.mishap.bad_block": "Expected %s at %s, but got %s",
"hexcasting.mishap.bad_block.sapling": "a sapling",
"hexcasting.mishap.bad_block.replaceable": "somewhere to place a block",
"hexcasting.mishap.bad_brainsweep": "The %s rejected the villager's mind",
"hexcasting.mishap.already_brainswept": "The villager has already been used",
"hexcasting.mishap.bad_brainsweep": "The %s rejected the being's mind",
"hexcasting.mishap.already_brainswept": "The mind has already been used",
"hexcasting.mishap.no_spell_circle": "%s requires a spell circle",
"hexcasting.mishap.others_name": "Tried to invade the privacy of %s's soul",
"hexcasting.mishap.others_name.self": "Tried to divulge my Name too recklessly",
@ -714,7 +714,7 @@
"hexcasting.entry.mishaps2": "Enlightened Mishaps",
"hexcasting.page.mishaps2.1": "I have discovered new and horrifying modes of failure. I must not succumb to them.",
"hexcasting.page.mishaps2.bad_mindflay.title": "Inert Mindflay",
"hexcasting.page.mishaps2.bad_mindflay": "Attempted to flay the mind of a villager that I have either already used, or of a character not suitable for the target block.$(br2)Causes dark green sparks, and kills the subject. If another villager sees that, I doubt they would look on it favorably.",
"hexcasting.page.mishaps2.bad_mindflay": "Attempted to flay the mind of something that I have either already used, or of a character not suitable for the target block.$(br2)Causes dark green sparks, and kills the subject. If a villager sees that, I doubt they would look on it favorably.",
"hexcasting.page.mishaps2.no_circle.title": "Lack Spell Circle",
"hexcasting.page.mishaps2.no_circle": "Tried to cast an action requiring a spell circle without a spell circle.$(br2)Causes light blue sparks, and upends my inventory onto the ground.",
"hexcasting.page.mishaps2.no_record.title": "Lack Akashic Record",

View file

@ -63,8 +63,8 @@ object FabricHexInitializer : ModInitializer {
}
fun initListeners() {
UseEntityCallback.EVENT.register(Brainsweeping::tradeWithVillager)
VillagerConversionCallback.EVENT.register(Brainsweeping::copyBrainsweepFromVillager)
UseEntityCallback.EVENT.register(Brainsweeping::interactWithBrainswept)
VillagerConversionCallback.EVENT.register(Brainsweeping::copyBrainsweepPostTransformation)
AttackBlockCallback.EVENT.register { player, world, _, pos, _ ->
// SUCCESS cancels further processing and, on the client, sends a packet to the server.
// PASS falls back to further processing.

View file

@ -73,7 +73,7 @@ public class HexEMIPlugin implements EmiPlugin {
.getAllRecipesFor(HexRecipeStuffRegistry.BRAINSWEEP_TYPE)) {
var inputs = EmiIngredient.of(recipe.blockIn().getDisplayedStacks().stream()
.map(EmiStack::of).toList());
var villagerInput = VillagerEmiStack.atLevelOrHigher(recipe.villagerIn(), true);
var villagerInput = VillagerEmiStack.atLevelOrHigher(recipe.entityIn(), true);
var output = EmiStack.of(recipe.result().getBlock());
registry.addRecipe(new EmiBrainsweepRecipe(inputs, villagerInput, output, recipe.getId()));
}

View file

@ -159,7 +159,7 @@ public class ForgeHexInitializer {
HexAPI.LOGGER.info(PatternRegistry.getPatternCountInfo()));
evBus.addListener((PlayerInteractEvent.EntityInteract evt) -> {
var res = Brainsweeping.tradeWithVillager(
var res = Brainsweeping.interactWithBrainswept(
evt.getEntity(), evt.getLevel(), evt.getHand(), evt.getTarget(), null);
if (res.consumesAction()) {
evt.setCanceled(true);
@ -167,7 +167,7 @@ public class ForgeHexInitializer {
}
});
evBus.addListener((LivingConversionEvent.Post evt) ->
Brainsweeping.copyBrainsweepFromVillager(evt.getEntity(), evt.getOutcome()));
Brainsweeping.copyBrainsweepPostTransformation(evt.getEntity(), evt.getOutcome()));
evBus.addListener((LivingEvent.LivingTickEvent evt) -> {
OpFlight.INSTANCE.tickDownFlight(evt.getEntity());

View file

@ -70,7 +70,7 @@ public class BrainsweepRecipeCategory implements IRecipeCategory<BrainsweepRecip
@NotNull IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
if (37 <= mouseX && mouseX <= 37 + 26 && 19 <= mouseY && mouseY <= 19 + 48) {
Minecraft mc = Minecraft.getInstance();
return recipe.villagerIn().getTooltip(mc.options.advancedItemTooltips);
return recipe.entityIn().getTooltip(mc.options.advancedItemTooltips);
}
return Collections.emptyList();
@ -81,7 +81,7 @@ public class BrainsweepRecipeCategory implements IRecipeCategory<BrainsweepRecip
@NotNull PoseStack stack, double mouseX, double mouseY) {
ClientLevel level = Minecraft.getInstance().level;
if (level != null) {
Villager villager = RenderLib.prepareVillagerForRendering(recipe.villagerIn(), level);
Villager villager = RenderLib.prepareVillagerForRendering(recipe.entityIn(), level);
RenderSystem.enableBlend();
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);