code doesn't have to compile it's not real
This commit is contained in:
parent
e37d08d81e
commit
b9a742f645
11 changed files with 210 additions and 161 deletions
|
@ -3,6 +3,7 @@ package at.petrak.hexcasting.api;
|
|||
import at.petrak.hexcasting.api.addldata.ADMediaHolder;
|
||||
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
|
||||
import at.petrak.hexcasting.api.casting.castables.SpecialHandler;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import at.petrak.hexcasting.api.player.Sentinel;
|
||||
import com.google.common.base.Suppliers;
|
||||
import net.minecraft.ChatFormatting;
|
||||
|
@ -12,6 +13,7 @@ import net.minecraft.resources.ResourceLocation;
|
|||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
@ -102,6 +104,10 @@ public interface HexAPI {
|
|||
return null;
|
||||
}
|
||||
|
||||
default FrozenColorizer getColorizer(Player player) {
|
||||
return FrozenColorizer.DEFAULT.get();
|
||||
}
|
||||
|
||||
static HexAPI instance() {
|
||||
return INSTANCE.get();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package at.petrak.hexcasting.api.casting.eval;
|
||||
|
||||
import at.petrak.hexcasting.api.casting.ActionRegistryEntry;
|
||||
import at.petrak.hexcasting.api.casting.ParticleSpray;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.MishapDisallowedSpell;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.MishapEntityTooFarAway;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import at.petrak.hexcasting.api.mod.HexConfig;
|
||||
import at.petrak.hexcasting.api.utils.NBTHelper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
@ -29,28 +29,28 @@ import java.util.function.Predicate;
|
|||
* Stuff like "the player with a staff," "the player with a trinket," "spell circles,"
|
||||
*/
|
||||
public abstract class CastingEnvironment {
|
||||
protected final CompoundTag userData;
|
||||
protected final ServerLevel world;
|
||||
// TODO move this to the env?
|
||||
protected final Set<Entity> entitiesGivenMotion;
|
||||
|
||||
protected final ServerLevel world;
|
||||
|
||||
protected CastingEnvironment(ServerLevel world) {
|
||||
this.userData = new CompoundTag();
|
||||
this.entitiesGivenMotion = new HashSet<>();
|
||||
this.world = world;
|
||||
this.entitiesGivenMotion = new HashSet<>();
|
||||
}
|
||||
|
||||
public final ServerLevel getWorld() {
|
||||
return this.world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a tag within which you can put whatever you like.
|
||||
* Get the caster. Might be null!
|
||||
* <p>
|
||||
* Use this to do stuff like implement custom ravenminds.
|
||||
* <p>
|
||||
* If there isn't a value associated with the given key, it makes and returns a new empty tag.
|
||||
* Implementations should NOT rely on this in general, use the methods on this class instead.
|
||||
* This is mostly for things like mishaps.
|
||||
*/
|
||||
public CompoundTag getUserData(ResourceLocation key) {
|
||||
var strKey = key.toString();
|
||||
return NBTHelper.getOrCreateCompound(this.userData, strKey);
|
||||
}
|
||||
@Nullable
|
||||
public abstract ServerPlayer getCaster();
|
||||
|
||||
|
||||
/**
|
||||
* If something about this ARE itself is invalid, mishap.
|
||||
|
@ -63,6 +63,13 @@ public abstract class CastingEnvironment {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do whatever you like after a pattern is executed.
|
||||
*/
|
||||
public abstract void postExecution(CastResult result);
|
||||
|
||||
public abstract Vec3 mishapSprayPos();
|
||||
|
||||
/**
|
||||
* Attempt to extract the given amount of media. Returns the amount of media left in the cost.
|
||||
* <p>
|
||||
|
@ -199,7 +206,7 @@ public abstract class CastingEnvironment {
|
|||
/**
|
||||
* The order/mode stacks should be discovered in
|
||||
*/
|
||||
public enum StackDiscoveryMode {
|
||||
protected enum StackDiscoveryMode {
|
||||
/**
|
||||
* When finding items to pick (hotbar)
|
||||
*/
|
||||
|
@ -209,4 +216,8 @@ public abstract class CastingEnvironment {
|
|||
*/
|
||||
EXTRACTION,
|
||||
}
|
||||
|
||||
public abstract FrozenColorizer getColorizer();
|
||||
|
||||
public abstract void produceParticles(ParticleSpray particles, FrozenColorizer colorizer);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package at.petrak.hexcasting.api.casting.eval
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI
|
||||
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers
|
||||
import at.petrak.hexcasting.api.block.circle.BlockEntityAbstractImpetus
|
||||
import at.petrak.hexcasting.api.casting.ParticleSpray
|
||||
import at.petrak.hexcasting.api.casting.PatternShapeMatch
|
||||
import at.petrak.hexcasting.api.casting.PatternShapeMatch.*
|
||||
|
@ -20,9 +18,6 @@ import at.petrak.hexcasting.api.casting.math.HexPattern
|
|||
import at.petrak.hexcasting.api.casting.mishaps.*
|
||||
import at.petrak.hexcasting.api.misc.DiscoveryHandlers
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer
|
||||
import at.petrak.hexcasting.api.misc.HexDamageSources
|
||||
import at.petrak.hexcasting.api.mod.HexConfig
|
||||
import at.petrak.hexcasting.api.mod.HexStatistics
|
||||
import at.petrak.hexcasting.api.mod.HexTags
|
||||
import at.petrak.hexcasting.api.utils.*
|
||||
import at.petrak.hexcasting.common.casting.PatternRegistryManifest
|
||||
|
@ -35,11 +30,8 @@ import net.minecraft.nbt.Tag
|
|||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.sounds.SoundSource
|
||||
import net.minecraft.util.Mth
|
||||
import net.minecraft.world.level.gameevent.GameEvent
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Keeps track of a player casting a spell on the server.
|
||||
|
@ -486,93 +478,6 @@ class CastingHarness private constructor(
|
|||
return out
|
||||
}
|
||||
|
||||
/**
|
||||
* Might cast from hitpoints.
|
||||
* Returns the media cost still remaining after we deplete everything. It will be <= 0 if we could pay for it.
|
||||
*
|
||||
* Also awards stats and achievements and such
|
||||
*/
|
||||
fun withdrawMedia(mediaCost: Int, allowOvercast: Boolean): Int {
|
||||
// prevent poor impls from gaining you media
|
||||
if (mediaCost <= 0) return 0
|
||||
var costLeft = mediaCost
|
||||
|
||||
val fake = this.ctx.caster.isCreative
|
||||
|
||||
if (this.ctx.spellCircle != null) {
|
||||
if (fake)
|
||||
return 0
|
||||
|
||||
val tile = this.ctx.world.getBlockEntity(this.ctx.spellCircle.impetusPos)
|
||||
if (tile is BlockEntityAbstractImpetus) {
|
||||
val mediaAvailable = tile.media
|
||||
if (mediaAvailable < 0)
|
||||
return 0
|
||||
|
||||
val mediaToTake = min(costLeft, mediaAvailable)
|
||||
costLeft -= mediaToTake
|
||||
tile.media = mediaAvailable - mediaToTake
|
||||
}
|
||||
} else {
|
||||
val casterStack = this.ctx.caster.getItemInHand(this.ctx.castingHand)
|
||||
val casterMediaHolder = IXplatAbstractions.INSTANCE.findMediaHolder(casterStack)
|
||||
val casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack)
|
||||
val hexHolderDrawsFromInventory = if (casterHexHolder != null) {
|
||||
if (casterMediaHolder != null) {
|
||||
val mediaAvailable = casterMediaHolder.withdrawMedia(-1, true)
|
||||
val mediaToTake = min(costLeft, mediaAvailable)
|
||||
if (!fake) casterMediaHolder.withdrawMedia(mediaToTake, false)
|
||||
costLeft -= mediaToTake
|
||||
}
|
||||
casterHexHolder.canDrawMediaFromInventory()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
if (casterStack.`is`(HexTags.Items.STAVES) || hexHolderDrawsFromInventory) {
|
||||
val mediaSources = DiscoveryHandlers.collectMediaHolders(this)
|
||||
.sortedWith(Comparator(::compareMediaItem).reversed())
|
||||
for (source in mediaSources) {
|
||||
costLeft -= extractMedia(source, costLeft, simulate = fake)
|
||||
if (costLeft <= 0)
|
||||
break
|
||||
}
|
||||
|
||||
if (allowOvercast && costLeft > 0) {
|
||||
// Cast from HP!
|
||||
val mediaToHealth = HexConfig.common().mediaToHealthRate()
|
||||
val healthToRemove = max(costLeft.toDouble() / mediaToHealth, 0.5)
|
||||
val mediaAbleToCastFromHP = this.ctx.caster.health * mediaToHealth
|
||||
|
||||
val mediaToActuallyPayFor = min(mediaAbleToCastFromHP.toInt(), costLeft)
|
||||
costLeft -= if (!fake) {
|
||||
Mishap.trulyHurt(this.ctx.caster, HexDamageSources.OVERCAST, healthToRemove.toFloat())
|
||||
|
||||
val actuallyTaken = Mth.ceil(mediaAbleToCastFromHP - (this.ctx.caster.health * mediaToHealth))
|
||||
|
||||
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.ctx.caster, actuallyTaken)
|
||||
this.ctx.caster.awardStat(HexStatistics.MEDIA_OVERCAST, mediaCost - costLeft)
|
||||
actuallyTaken
|
||||
} else {
|
||||
mediaToActuallyPayFor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fake) {
|
||||
// this might be more than the media cost! for example if we waste a lot of media from an item
|
||||
this.ctx.caster.awardStat(HexStatistics.MEDIA_USED, mediaCost - costLeft)
|
||||
HexAdvancementTriggers.SPEND_MEDIA_TRIGGER.trigger(
|
||||
this.ctx.caster,
|
||||
mediaCost - costLeft,
|
||||
if (costLeft < 0) -costLeft else 0
|
||||
)
|
||||
}
|
||||
|
||||
return if (fake) 0 else costLeft
|
||||
}
|
||||
|
||||
fun getColorizer(): FrozenColorizer {
|
||||
if (this.prepackagedColorizer != null)
|
||||
return this.prepackagedColorizer
|
||||
|
|
|
@ -23,7 +23,7 @@ sealed class OperatorSideEffect {
|
|||
|
||||
data class RequiredEnlightenment(val awardStat: Boolean) : OperatorSideEffect() {
|
||||
override fun performEffect(harness: CastingHarness): Boolean {
|
||||
harness.ctx.caster.sendSystemMessage("hexcasting.message.cant_great_spell".asTranslatedComponent)
|
||||
harness.ctx.caster?.sendSystemMessage("hexcasting.message.cant_great_spell".asTranslatedComponent)
|
||||
|
||||
if (awardStat)
|
||||
HexAdvancementTriggers.FAIL_GREAT_SPELL_TRIGGER.trigger(harness.ctx.caster)
|
||||
|
@ -42,7 +42,7 @@ sealed class OperatorSideEffect {
|
|||
override fun performEffect(harness: CastingHarness): Boolean {
|
||||
this.spell.cast(harness.ctx)
|
||||
if (awardStat)
|
||||
harness.ctx.caster.awardStat(HexStatistics.SPELLS_CAST)
|
||||
harness.ctx.caster?.awardStat(HexStatistics.SPELLS_CAST)
|
||||
|
||||
return false
|
||||
}
|
||||
|
@ -50,17 +50,14 @@ sealed class OperatorSideEffect {
|
|||
|
||||
data class ConsumeMedia(val amount: Int) : OperatorSideEffect() {
|
||||
override fun performEffect(harness: CastingHarness): Boolean {
|
||||
val overcastOk = harness.ctx.canOvercast
|
||||
val leftoverMedia = harness.withdrawMedia(this.amount, overcastOk)
|
||||
if (leftoverMedia > 0 && !overcastOk) {
|
||||
harness.ctx.caster.sendSystemMessage("hexcasting.message.cant_overcast".asTranslatedComponent)
|
||||
}
|
||||
val leftoverMedia = harness.ctx.extractMedia(this.amount.toLong())
|
||||
return leftoverMedia > 0
|
||||
}
|
||||
}
|
||||
|
||||
data class Particles(val spray: ParticleSpray) : OperatorSideEffect() {
|
||||
override fun performEffect(harness: CastingHarness): Boolean {
|
||||
harness.ctx.produceParticles(this.spray, harness.ctx.colorizer)
|
||||
this.spray.sprayParticles(harness.ctx.world, harness.getColorizer())
|
||||
|
||||
return false
|
||||
|
|
|
@ -6,15 +6,14 @@ import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType
|
|||
import at.petrak.hexcasting.api.casting.iota.Iota
|
||||
import at.petrak.hexcasting.api.casting.math.HexPattern
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer
|
||||
import at.petrak.hexcasting.api.mod.HexTags
|
||||
import at.petrak.hexcasting.api.utils.asTranslatedComponent
|
||||
import at.petrak.hexcasting.api.utils.lightPurple
|
||||
import at.petrak.hexcasting.common.lib.HexItems
|
||||
import at.petrak.hexcasting.ktxt.*
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
|
@ -28,7 +27,10 @@ abstract class Mishap : Throwable() {
|
|||
abstract fun accentColor(ctx: CastingEnvironment, errorCtx: Context): FrozenColorizer
|
||||
|
||||
open fun particleSpray(ctx: CastingEnvironment): ParticleSpray {
|
||||
return ParticleSpray(ctx.position.add(0.0, 0.2, 0.0), Vec3(0.0, 2.0, 0.0), 0.2, Math.PI / 4, 40)
|
||||
return ParticleSpray(
|
||||
ctx.mishapSprayPos().add(0.0, 0.2, 0.0),
|
||||
Vec3(0.0, 2.0, 0.0),
|
||||
0.2, Math.PI / 4, 40)
|
||||
}
|
||||
|
||||
open fun resolutionType(ctx: CastingEnvironment): ResolvedPatternType = ResolvedPatternType.ERRORED
|
||||
|
@ -40,7 +42,7 @@ abstract class Mishap : Throwable() {
|
|||
*/
|
||||
abstract fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>)
|
||||
|
||||
abstract protected fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component
|
||||
protected abstract fun errorMessage(ctx: CastingEnvironment, errorCtx: Context): Component
|
||||
|
||||
/**
|
||||
* Every error message should be prefixed with the name of the action...
|
||||
|
@ -67,44 +69,33 @@ abstract class Mishap : Throwable() {
|
|||
protected fun actionName(name: Component?): Component =
|
||||
name ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple
|
||||
|
||||
protected fun yeetHeldItemsTowards(ctx: CastingEnvironment, targetPos: Vec3) {
|
||||
protected fun yeetHeldItemsTowards(env: CastingEnvironment, caster: ServerPlayer, targetPos: Vec3) {
|
||||
// Knock the player's items out of their hands
|
||||
val items = mutableListOf<ItemStack>()
|
||||
for (hand in InteractionHand.values()) {
|
||||
if (hand != ctx.castingHand || ctx.caster.getItemInHand(hand).`is`(HexTags.Items.STAVES)) {
|
||||
items.add(ctx.caster.getItemInHand(hand).copy())
|
||||
ctx.caster.setItemInHand(hand, ItemStack.EMPTY)
|
||||
}
|
||||
items.add(caster.getItemInHand(hand).copy())
|
||||
caster.setItemInHand(hand, ItemStack.EMPTY)
|
||||
}
|
||||
|
||||
val delta = targetPos.subtract(ctx.position).normalize().scale(0.5)
|
||||
val pos = caster.position()
|
||||
val delta = targetPos.subtract(pos).normalize().scale(0.5)
|
||||
|
||||
for (item in items) {
|
||||
yeetItem(item, ctx, delta)
|
||||
yeetItem(env, item, pos, delta)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun yeetHeldItem(ctx: CastingEnvironment, hand: InteractionHand) {
|
||||
val item = ctx.caster.getItemInHand(hand).copy()
|
||||
if (hand == ctx.castingHand && IXplatAbstractions.INSTANCE.findHexHolder(item) != null)
|
||||
return
|
||||
ctx.caster.setItemInHand(hand, ItemStack.EMPTY)
|
||||
|
||||
val delta = ctx.caster.lookAngle.scale(0.5)
|
||||
yeetItem(item, ctx, delta)
|
||||
}
|
||||
|
||||
protected fun yeetItem(stack: ItemStack, ctx: CastingEnvironment, delta: Vec3) {
|
||||
protected fun yeetItem(env: CastingEnvironment, stack: ItemStack, pos: Vec3, delta: Vec3) {
|
||||
val entity = ItemEntity(
|
||||
ctx.world,
|
||||
ctx.position.x, ctx.position.y, ctx.position.z,
|
||||
env.world,
|
||||
pos.x, pos.y, pos.z,
|
||||
stack,
|
||||
delta.x + (Math.random() - 0.5) * 0.1,
|
||||
delta.y + (Math.random() - 0.5) * 0.1,
|
||||
delta.z + (Math.random() - 0.5) * 0.1
|
||||
)
|
||||
entity.setPickUpDelay(40)
|
||||
ctx.world.addWithUUID(entity)
|
||||
env.world.addWithUUID(entity)
|
||||
}
|
||||
|
||||
protected fun blockAtPos(ctx: CastingEnvironment, pos: BlockPos): Component {
|
||||
|
@ -114,7 +105,7 @@ abstract class Mishap : Throwable() {
|
|||
data class Context(val pattern: HexPattern, val name: Component?)
|
||||
|
||||
companion object {
|
||||
fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
|
||||
public fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) {
|
||||
entity.setHurtWithStamp(source, entity.level.gameTime)
|
||||
|
||||
val targetHealth = entity.health - amount
|
||||
|
|
|
@ -71,7 +71,9 @@ fun scanPlayerForMediaStuff(player: ServerPlayer): List<ADMediaHolder> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
sources.sortWith(::compareMediaItem)
|
||||
sources.reverse()
|
||||
return sources
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
47
Common/src/main/java/at/petrak/hexcasting/common/casting/env/PackagedItemCastEnv.java
vendored
Normal file
47
Common/src/main/java/at/petrak/hexcasting/common/casting/env/PackagedItemCastEnv.java
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package at.petrak.hexcasting.common.casting.env;
|
||||
|
||||
import at.petrak.hexcasting.api.casting.eval.CastResult;
|
||||
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
|
||||
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
||||
public class PackagedItemCastEnv extends PlayerBasedCastEnv {
|
||||
|
||||
protected EvalSound sound = HexEvalSounds.NOTHING;
|
||||
|
||||
public PackagedItemCastEnv(ServerPlayer caster, InteractionHand castingHand) {
|
||||
super(caster, castingHand);
|
||||
}
|
||||
|
||||
public EvalSound getFinalSound() {
|
||||
return sound;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postExecution(CastResult result) {
|
||||
this.sound = this.sound.greaterOf(result.getSound());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long extractMedia(long costLeft) {
|
||||
var casterStack = this.caster.getItemInHand(this.castingHand);
|
||||
var casterHexHolder = IXplatAbstractions.INSTANCE.findHexHolder(casterStack);
|
||||
var canCastFromInv = casterHexHolder.canDrawMediaFromInventory();
|
||||
|
||||
var casterMediaHolder = IXplatAbstractions.INSTANCE.findMediaHolder(casterStack);
|
||||
|
||||
// The contracts on the AD and on this function are different.
|
||||
// ADs return the amount extracted, this wants the amount left
|
||||
if (casterMediaHolder != null) {
|
||||
long extracted = casterMediaHolder.withdrawMedia((int) costLeft, false);
|
||||
costLeft -= extracted;
|
||||
}
|
||||
if (canCastFromInv && costLeft > 0) {
|
||||
costLeft = this.extractMediaFromInventory(costLeft, this.canOvercast());
|
||||
}
|
||||
|
||||
return costLeft;
|
||||
}
|
||||
}
|
|
@ -1,18 +1,31 @@
|
|||
package at.petrak.hexcasting.common.casting.env;
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI;
|
||||
import at.petrak.hexcasting.api.addldata.ADMediaHolder;
|
||||
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers;
|
||||
import at.petrak.hexcasting.api.casting.ParticleSpray;
|
||||
import at.petrak.hexcasting.api.casting.castables.Action;
|
||||
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
|
||||
import at.petrak.hexcasting.api.casting.mishaps.Mishap;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import at.petrak.hexcasting.api.misc.HexDamageSources;
|
||||
import at.petrak.hexcasting.api.mod.HexConfig;
|
||||
import at.petrak.hexcasting.api.mod.HexStatistics;
|
||||
import at.petrak.hexcasting.api.utils.HexUtils;
|
||||
import at.petrak.hexcasting.api.utils.MediaHelper;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
||||
public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
||||
protected final ServerPlayer caster;
|
||||
protected final InteractionHand castingHand;
|
||||
|
@ -23,6 +36,11 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
this.castingHand = castingHand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ServerPlayer getCaster() {
|
||||
return this.caster;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<ItemStack> getUsableStacks(StackDiscoveryMode mode) {
|
||||
return switch (mode) {
|
||||
|
@ -78,7 +96,7 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
var sentinel = HexAPI.instance().getSentinel(this.caster);
|
||||
if (sentinel != null
|
||||
&& sentinel.extendsRange()
|
||||
&& world.dimension() == sentinel.dimension()
|
||||
&& this.caster.getLevel().dimension() == sentinel.dimension()
|
||||
&& vec.distanceToSqr(sentinel.position()) <= Action.MAX_DISTANCE_FROM_SENTINEL * Action.MAX_DISTANCE_FROM_SENTINEL
|
||||
) {
|
||||
return true;
|
||||
|
@ -100,13 +118,44 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
|
|||
|
||||
/**
|
||||
* Search the player's inventory for media ADs and use them.
|
||||
* <p>
|
||||
* TODO it looks like i'm going to strip out DiscoveryHandlers entirely and replace it. Was anyone hoping to make a
|
||||
* media source that isn't item-based? Might be worth scanning for ADMediaHolders on the player themself.
|
||||
* <p>
|
||||
* TODO vis a vis that stop special-casing overcasting
|
||||
*/
|
||||
protected long extractMediaFromInventory(long cost) {
|
||||
protected long extractMediaFromInventory(long costLeft, boolean allowOvercast) {
|
||||
List<ADMediaHolder> sources = MediaHelper.scanPlayerForMediaStuff(this.caster);
|
||||
|
||||
for (var source : sources) {
|
||||
var found = MediaHelper.extractMedia(source, (int) costLeft, true, false);
|
||||
costLeft -= found;
|
||||
if (costLeft <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (costLeft > 0 && allowOvercast) {
|
||||
var mediaToHealth = HexConfig.common().mediaToHealthRate();
|
||||
var healthToRemove = Math.max(costLeft / mediaToHealth, 0.5);
|
||||
var mediaAbleToCastFromHP = this.caster.getHealth() * mediaToHealth;
|
||||
|
||||
Mishap.trulyHurt(this.caster, HexDamageSources.OVERCAST, healthToRemove);
|
||||
|
||||
var actuallyTaken = Mth.ceil(mediaAbleToCastFromHP - (this.caster.getHealth() * mediaToHealth));
|
||||
|
||||
HexAdvancementTriggers.OVERCAST_TRIGGER.trigger(this.caster, actuallyTaken);
|
||||
this.caster.awardStat(HexStatistics.MEDIA_OVERCAST, actuallyTaken);
|
||||
|
||||
costLeft -= actuallyTaken;
|
||||
}
|
||||
|
||||
return costLeft;
|
||||
}
|
||||
|
||||
protected boolean canOvercast() {
|
||||
var adv = this.world.getServer().getAdvancements().getAdvancement(modLoc("y_u_no_cast_angy"));
|
||||
var advs = this.caster.getAdvancements();
|
||||
return advs.getOrStartProgress(adv).isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void produceParticles(ParticleSpray particles, FrozenColorizer colorizer) {
|
||||
particles.sprayParticles(this.world, colorizer);
|
||||
}
|
||||
}
|
||||
|
|
34
Common/src/main/java/at/petrak/hexcasting/common/casting/env/StaffCastEnv.java
vendored
Normal file
34
Common/src/main/java/at/petrak/hexcasting/common/casting/env/StaffCastEnv.java
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
package at.petrak.hexcasting.common.casting.env;
|
||||
|
||||
import at.petrak.hexcasting.api.HexAPI;
|
||||
import at.petrak.hexcasting.api.casting.eval.CastResult;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
||||
public class StaffCastEnv extends PlayerBasedCastEnv {
|
||||
public StaffCastEnv(ServerPlayer caster, InteractionHand castingHand) {
|
||||
super(caster, castingHand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postExecution(CastResult result) {
|
||||
// TODO: send information to client
|
||||
}
|
||||
|
||||
@Override
|
||||
public long extractMedia(long cost) {
|
||||
var canOvercast = this.canOvercast();
|
||||
var remaining = this.extractMediaFromInventory(cost, canOvercast);
|
||||
if (remaining > 0 && !canOvercast) {
|
||||
this.caster.sendSystemMessage(Component.translatable("hexcasting.message.cant_overcast"));
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrozenColorizer getColorizer() {
|
||||
return HexAPI.instance().getColorizer(this.caster);
|
||||
}
|
||||
}
|
|
@ -2,11 +2,13 @@ package at.petrak.hexcasting.common.impl;
|
|||
|
||||
import at.petrak.hexcasting.api.HexAPI;
|
||||
import at.petrak.hexcasting.api.addldata.ADMediaHolder;
|
||||
import at.petrak.hexcasting.api.misc.FrozenColorizer;
|
||||
import at.petrak.hexcasting.api.player.Sentinel;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
@ -43,4 +45,9 @@ public class HexAPIImpl implements HexAPI {
|
|||
public @Nullable ADMediaHolder findMediaHolder(ItemStack stack) {
|
||||
return IXplatAbstractions.INSTANCE.findMediaHolder(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrozenColorizer getColorizer(Player player) {
|
||||
return IXplatAbstractions.INSTANCE.getColorizer(player);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,6 @@ package at.petrak.hexcasting.common.lib.hex;
|
|||
|
||||
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
|
||||
import at.petrak.hexcasting.common.lib.HexSounds;
|
||||
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
@ -13,8 +11,6 @@ import java.util.function.BiConsumer;
|
|||
import static at.petrak.hexcasting.api.HexAPI.modLoc;
|
||||
|
||||
public class HexEvalSounds {
|
||||
public static final Registry<EvalSound> REGISTRY = IXplatAbstractions.INSTANCE.getEvalSoundRegistry();
|
||||
|
||||
private static final Map<ResourceLocation, EvalSound> SOUNDS = new LinkedHashMap<>();
|
||||
|
||||
public static final EvalSound NOTHING = make("nothing",
|
||||
|
@ -23,12 +19,16 @@ public class HexEvalSounds {
|
|||
new EvalSound(HexSounds.ADD_PATTERN, 0));
|
||||
public static final EvalSound SPELL = make("spell",
|
||||
new EvalSound(HexSounds.ACTUALLY_CAST, 1000));
|
||||
public static final EvalSound MISHAP = make("mishap",
|
||||
new EvalSound(HexSounds.FAIL_PATTERN, Integer.MAX_VALUE));
|
||||
public static final EvalSound HERMES = make("hermes",
|
||||
new EvalSound(HexSounds.CAST_HERMES, Integer.MAX_VALUE));
|
||||
new EvalSound(HexSounds.CAST_HERMES, 2000));
|
||||
public static final EvalSound THOTH = make("thoth",
|
||||
new EvalSound(HexSounds.CAST_THOTH, Integer.MAX_VALUE));
|
||||
new EvalSound(HexSounds.CAST_THOTH, 2000));
|
||||
|
||||
public static final EvalSound MUTE = make("mute",
|
||||
new EvalSound(null, 3000));
|
||||
|
||||
public static final EvalSound MISHAP = make("mishap",
|
||||
new EvalSound(HexSounds.FAIL_PATTERN, 4000));
|
||||
|
||||
private static EvalSound make(String name, EvalSound sound) {
|
||||
var old = SOUNDS.put(modLoc(name), sound);
|
||||
|
|
Loading…
Reference in a new issue