fix up mishaps some more and fix a few spells

This commit is contained in:
petrak@ 2023-02-15 00:50:46 -06:00
parent 2233c7697d
commit 1750f29a69
12 changed files with 120 additions and 85 deletions

View file

@ -112,6 +112,12 @@ public interface HexAPI {
* Location in the userdata of the ravenmind * Location in the userdata of the ravenmind
*/ */
String RAVENMIND_USERDATA = modLoc("ravenmind").toString(); String RAVENMIND_USERDATA = modLoc("ravenmind").toString();
/**
* Location in the userdata of the evaluation depth
*/
String EVAL_DEPTH_USERDATA = modLoc("eval_depth").toString();
String MARKED_MOVED_USERDATA = modLoc("impulsed").toString();
static HexAPI instance() { static HexAPI instance() {
return INSTANCE.get(); return INSTANCE.get();

View file

@ -22,6 +22,12 @@ interface SpellAction : Action {
ctx: CastingEnvironment ctx: CastingEnvironment
): Triple<RenderedSpell, Int, List<ParticleSpray>>? ): Triple<RenderedSpell, Int, List<ParticleSpray>>?
fun executeWithUserdata(
args: List<Iota>, ctx: CastingEnvironment, userData: CompoundTag
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
return this.execute(args, ctx)
}
override fun operate( override fun operate(
env: CastingEnvironment, env: CastingEnvironment,
stack: MutableList<Iota>, stack: MutableList<Iota>,
@ -32,7 +38,8 @@ interface SpellAction : Action {
throw MishapNotEnoughArgs(this.argc, stack.size) throw MishapNotEnoughArgs(this.argc, stack.size)
val args = stack.takeLast(this.argc) val args = stack.takeLast(this.argc)
for (_i in 0 until this.argc) stack.removeLast() for (_i in 0 until this.argc) stack.removeLast()
val executeResult = this.execute(args, env) ?: return OperationResult(stack, userData, listOf(), continuation) val executeResult = this.executeWithUserdata(args, env, userData)
?: return OperationResult(stack, userData, listOf(), continuation)
val (spell, media, particles) = executeResult val (spell, media, particles) = executeResult
val sideEffects = mutableListOf<OperatorSideEffect>() val sideEffects = mutableListOf<OperatorSideEffect>()

View file

@ -9,6 +9,7 @@ import at.petrak.hexcasting.api.casting.mishaps.MishapEntityTooFarAway;
import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway; import at.petrak.hexcasting.api.casting.mishaps.MishapLocationTooFarAway;
import at.petrak.hexcasting.api.misc.FrozenColorizer; import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexConfig; import at.petrak.hexcasting.api.mod.HexConfig;
import at.petrak.hexcasting.api.utils.HexUtils;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
@ -20,9 +21,7 @@ import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Predicate; import java.util.function.Predicate;
/** /**
@ -32,12 +31,9 @@ import java.util.function.Predicate;
*/ */
public abstract class CastingEnvironment { public abstract class CastingEnvironment {
protected final ServerLevel world; protected final ServerLevel world;
// TODO move this to the env?
protected final Set<Entity> entitiesGivenMotion;
protected CastingEnvironment(ServerLevel world) { protected CastingEnvironment(ServerLevel world) {
this.world = world; this.world = world;
this.entitiesGivenMotion = new HashSet<>();
} }
public final ServerLevel getWorld() { public final ServerLevel getWorld() {
@ -59,8 +55,7 @@ public abstract class CastingEnvironment {
public abstract MishapEnvironment getMishapEnvironment(); public abstract MishapEnvironment getMishapEnvironment();
/** /**
* Get the sound that this I/O module makes. * Get the sound that this I/O module makes upon receiving a pattern
* <p>
*/ */
public abstract EvalSound getSoundType(); public abstract EvalSound getSoundType();
@ -162,12 +157,10 @@ public abstract class CastingEnvironment {
} }
} }
public void markEntityAsImpulsed(Entity e) { public abstract InteractionHand castingHand();
this.entitiesGivenMotion.add(e);
}
public boolean hasBeenGivenMotion(Entity e) { public InteractionHand otherHand() {
return this.entitiesGivenMotion.contains(e); return HexUtils.otherHand(this.castingHand());
} }
/** /**

View file

@ -3,10 +3,13 @@ package at.petrak.hexcasting.api.casting.eval.vm
import at.petrak.hexcasting.api.HexAPI import at.petrak.hexcasting.api.HexAPI
import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.casting.iota.IotaType import at.petrak.hexcasting.api.casting.iota.IotaType
import at.petrak.hexcasting.api.casting.mishaps.MishapEvalTooDeep
import at.petrak.hexcasting.api.mod.HexConfig
import at.petrak.hexcasting.api.utils.* import at.petrak.hexcasting.api.utils.*
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.Tag import net.minecraft.nbt.Tag
import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerLevel
import net.minecraft.world.entity.Entity
/** /**
* The state of a casting VM, containing the stack and all * The state of a casting VM, containing the stack and all
@ -18,10 +21,9 @@ data class CastingImage private constructor(
val parenthesized: List<Iota>, val parenthesized: List<Iota>,
val escapeNext: Boolean, val escapeNext: Boolean,
val iterationSteps: Int,
val userData: CompoundTag val userData: CompoundTag
) { ) {
public constructor() : this(listOf(), 0, listOf(), false, CompoundTag()) constructor() : this(listOf(), 0, listOf(), false, CompoundTag())
fun serializeToNbt() = NBTBuilder { fun serializeToNbt() = NBTBuilder {
TAG_STACK %= stack.serializeToNBT() TAG_STACK %= stack.serializeToNBT()
@ -33,17 +35,6 @@ data class CastingImage private constructor(
TAG_USERDATA %= userData TAG_USERDATA %= userData
} }
/**
* Throws if we get too deep.
*/
fun incDepth(): CastingImage {
val maxAllowedDepth = HexConfig.server().maxRecurseDepth()
if (this.iterationSteps + 1 > maxAllowedDepth) {
throw MishapEvalTooDeep()
}
return copy(iterationSteps = iterationSteps + 1)
}
companion object { companion object {
const val TAG_STACK = "stack" const val TAG_STACK = "stack"
const val TAG_PAREN_COUNT = "open_parens" const val TAG_PAREN_COUNT = "open_parens"
@ -87,5 +78,31 @@ data class CastingImage private constructor(
CastingImage() CastingImage()
} }
} }
/**
* Throws if we get too deep.
*/
@JvmStatic
fun incDepth(userData: CompoundTag): CompoundTag {
val maxAllowedDepth = HexConfig.server().maxRecurseDepth()
val depth = userData.getInt(HexAPI.EVAL_DEPTH_USERDATA)
if (depth + 1 > maxAllowedDepth) {
throw MishapEvalTooDeep()
}
userData.putInt(HexAPI.EVAL_DEPTH_USERDATA, depth + 1)
return userData
}
@JvmStatic
fun checkAndMarkGivenMotion(userData: CompoundTag, entity: Entity): Boolean {
val marked = userData.getOrCreateCompound(HexAPI.MARKED_MOVED_USERDATA)
return if (marked.contains(entity.stringUUID)) {
true
} else {
marked.putBoolean(entity.stringUUID, true)
false
}
}
} }
} }

View file

@ -83,7 +83,7 @@ class CastingVM(var image: CastingImage, val env: CastingEnvironment) {
// ALSO TODO need to add reader macro-style things // ALSO TODO need to add reader macro-style things
try { try {
this.handleParentheses(iota)?.let { (data, resolutionType) -> this.handleParentheses(iota)?.let { (data, resolutionType) ->
return@executeInner CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.OPERATOR) return@executeInner CastResult(continuation, data, listOf(), resolutionType, HexEvalSounds.ADD_PATTERN)
} }
} catch (e: MishapTooManyCloseParens) { } catch (e: MishapTooManyCloseParens) {
// This is ridiculous and needs to be fixed // This is ridiculous and needs to be fixed

View file

@ -12,7 +12,7 @@ class MishapImmuneEntity(val entity: Entity) : Mishap() {
dyeColor(DyeColor.BLUE) dyeColor(DyeColor.BLUE)
override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) { override fun execute(ctx: CastingEnvironment, errorCtx: Context, stack: MutableList<Iota>) {
yeetHeldItemsTowards(ctx, entity.position()) ctx.mishapEnvironment.yeetHeldItemsTowards(entity.position())
} }
override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) = override fun errorMessage(ctx: CastingEnvironment, errorCtx: Context) =

View file

@ -5,6 +5,8 @@ import at.petrak.hexcasting.api.addldata.ADMediaHolder;
import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers; import at.petrak.hexcasting.api.advancements.HexAdvancementTriggers;
import at.petrak.hexcasting.api.casting.ParticleSpray; import at.petrak.hexcasting.api.casting.ParticleSpray;
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment; import at.petrak.hexcasting.api.casting.eval.CastingEnvironment;
import at.petrak.hexcasting.api.casting.eval.MishapEnvironment;
import at.petrak.hexcasting.api.casting.eval.sideeffects.EvalSound;
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect; import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect;
import at.petrak.hexcasting.api.casting.mishaps.Mishap; import at.petrak.hexcasting.api.casting.mishaps.Mishap;
import at.petrak.hexcasting.api.misc.FrozenColorizer; import at.petrak.hexcasting.api.misc.FrozenColorizer;
@ -13,6 +15,7 @@ import at.petrak.hexcasting.api.mod.HexConfig;
import at.petrak.hexcasting.api.mod.HexStatistics; import at.petrak.hexcasting.api.mod.HexStatistics;
import at.petrak.hexcasting.api.utils.HexUtils; import at.petrak.hexcasting.api.utils.HexUtils;
import at.petrak.hexcasting.api.utils.MediaHelper; import at.petrak.hexcasting.api.utils.MediaHelper;
import at.petrak.hexcasting.common.lib.hex.HexEvalSounds;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionHand;
@ -44,6 +47,11 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
return this.caster; return this.caster;
} }
@Override
public EvalSound getSoundType() {
return HexEvalSounds.ADD_PATTERN;
}
@Override @Override
protected List<ItemStack> getUsableStacks(StackDiscoveryMode mode) { protected List<ItemStack> getUsableStacks(StackDiscoveryMode mode) {
return switch (mode) { return switch (mode) {
@ -167,9 +175,13 @@ public abstract class PlayerBasedCastEnv extends CastingEnvironment {
return this.caster.position(); return this.caster.position();
} }
@Override
public MishapEnvironment getMishapEnvironment() {
return new PlayerBasedMishapEnv(this.caster);
}
protected void sendMishapMsgToPlayer(OperatorSideEffect.DoMishap mishap) { protected void sendMishapMsgToPlayer(OperatorSideEffect.DoMishap mishap) {
var msg = mishap.getMishap().errorMessageWithName(this, mishap.getErrorCtx()); var msg = mishap.getMishap().errorMessageWithName(this, mishap.getErrorCtx());
this.caster.sendSystemMessage(msg); this.caster.sendSystemMessage(msg);
} }
} }

View file

@ -4,13 +4,11 @@ import at.petrak.hexcasting.api.HexAPI;
import at.petrak.hexcasting.api.casting.eval.CastResult; import at.petrak.hexcasting.api.casting.eval.CastResult;
import at.petrak.hexcasting.api.casting.eval.ExecutionClientView; import at.petrak.hexcasting.api.casting.eval.ExecutionClientView;
import at.petrak.hexcasting.api.casting.eval.ResolvedPattern; import at.petrak.hexcasting.api.casting.eval.ResolvedPattern;
import at.petrak.hexcasting.api.casting.eval.ResolvedPatternType;
import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect; import at.petrak.hexcasting.api.casting.eval.sideeffects.OperatorSideEffect;
import at.petrak.hexcasting.api.casting.iota.PatternIota; import at.petrak.hexcasting.api.casting.iota.PatternIota;
import at.petrak.hexcasting.api.casting.math.HexCoord; import at.petrak.hexcasting.api.casting.math.HexCoord;
import at.petrak.hexcasting.api.misc.FrozenColorizer; import at.petrak.hexcasting.api.misc.FrozenColorizer;
import at.petrak.hexcasting.api.mod.HexStatistics; import at.petrak.hexcasting.api.mod.HexStatistics;
import at.petrak.hexcasting.api.mod.HexTags;
import at.petrak.hexcasting.common.network.MsgNewSpellPatternAck; import at.petrak.hexcasting.common.network.MsgNewSpellPatternAck;
import at.petrak.hexcasting.common.network.MsgNewSpellPatternSyn; import at.petrak.hexcasting.common.network.MsgNewSpellPatternSyn;
import at.petrak.hexcasting.xplat.IXplatAbstractions; import at.petrak.hexcasting.xplat.IXplatAbstractions;
@ -51,9 +49,7 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
} }
public static void handleNewPatternOnServer(ServerPlayer sender, MsgNewSpellPatternSyn msg) { public static void handleNewPatternOnServer(ServerPlayer sender, MsgNewSpellPatternSyn msg) {
var held = sender.getItemInHand(msg.handUsed()); boolean cheatedPatternOverlap = false;
if (held.is(HexTags.Items.STAVES)) {
boolean autoFail = false;
List<ResolvedPattern> resolvedPatterns = msg.resolvedPatterns(); List<ResolvedPattern> resolvedPatterns = msg.resolvedPatterns();
if (!resolvedPatterns.isEmpty()) { if (!resolvedPatterns.isEmpty()) {
@ -66,22 +62,19 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
var currentSpellPoints = currentResolvedPattern.getPattern() var currentSpellPoints = currentResolvedPattern.getPattern()
.positions(currentResolvedPattern.getOrigin()); .positions(currentResolvedPattern.getOrigin());
if (currentSpellPoints.stream().anyMatch(allPoints::contains)) { if (currentSpellPoints.stream().anyMatch(allPoints::contains)) {
autoFail = true; cheatedPatternOverlap = true;
} }
} }
if (cheatedPatternOverlap) {
return;
}
sender.awardStat(HexStatistics.PATTERNS_DRAWN); sender.awardStat(HexStatistics.PATTERNS_DRAWN);
var harness = IXplatAbstractions.INSTANCE.getStaffHarness(sender, msg.handUsed()); var harness = IXplatAbstractions.INSTANCE.getStaffHarness(sender, msg.handUsed());
ExecutionClientView clientInfo; ExecutionClientView clientInfo = harness.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
if (autoFail) {
var descs = harness.generateDescs();
clientInfo = new ExecutionClientView(harness.getStack().isEmpty(), ResolvedPatternType.INVALID,
descs.getFirst(), descs.getSecond(), descs.getThird(), harness.getParenCount());
} else {
clientInfo = harness.queueAndExecuteIota(new PatternIota(msg.pattern()), sender.getLevel());
}
if (clientInfo.isStackClear()) { if (clientInfo.isStackClear()) {
IXplatAbstractions.INSTANCE.setHarness(sender, null); IXplatAbstractions.INSTANCE.setHarness(sender, null);
@ -97,6 +90,4 @@ public class StaffCastEnv extends PlayerBasedCastEnv {
IXplatAbstractions.INSTANCE.sendPacketToPlayer(sender, IXplatAbstractions.INSTANCE.sendPacketToPlayer(sender,
new MsgNewSpellPatternAck(clientInfo, resolvedPatterns.size() - 1)); new MsgNewSpellPatternAck(clientInfo, resolvedPatterns.size() - 1));
} }
}
} }

View file

@ -1,9 +1,11 @@
package at.petrak.hexcasting.common.casting.operators.eval package at.petrak.hexcasting.common.casting.operators.eval
import at.petrak.hexcasting.api.casting.SpellList import at.petrak.hexcasting.api.casting.SpellList
import at.petrak.hexcasting.api.casting.asActionResult
import at.petrak.hexcasting.api.casting.castables.Action import at.petrak.hexcasting.api.casting.castables.Action
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.OperationResult import at.petrak.hexcasting.api.casting.eval.OperationResult
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage
import at.petrak.hexcasting.api.casting.eval.vm.FrameEvaluate import at.petrak.hexcasting.api.casting.eval.vm.FrameEvaluate
import at.petrak.hexcasting.api.casting.eval.vm.FrameFinishEval import at.petrak.hexcasting.api.casting.eval.vm.FrameFinishEval
import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation import at.petrak.hexcasting.api.casting.eval.vm.SpellContinuation
@ -23,9 +25,9 @@ object OpEval : Action {
val datum = stack.removeLastOrNull() ?: throw MishapNotEnoughArgs(1, 0) val datum = stack.removeLastOrNull() ?: throw MishapNotEnoughArgs(1, 0)
val instrs = evaluatable(datum, 0) val instrs = evaluatable(datum, 0)
val stack = instrs.ifRight { instrs.ifRight {
// FIXME: Casting depth increment not implemented yet CastingImage.incDepth(userData)
//env.incDepth() it.asActionResult
} }
// if not installed already... // if not installed already...
@ -39,6 +41,6 @@ object OpEval : Action {
val instrsList = instrs.map({ SpellList.LList(0, listOf(PatternIota(it))) }, { it }) val instrsList = instrs.map({ SpellList.LList(0, listOf(PatternIota(it))) }, { it })
val frame = FrameEvaluate(instrsList, true) val frame = FrameEvaluate(instrsList, true)
return OperationResult(stack, userData, listOf(), newCont.pushFrame(frame)) return OperationResult(listOf(), userData, listOf(), newCont.pushFrame(frame))
} }
} }

View file

@ -4,10 +4,12 @@ import at.petrak.hexcasting.api.casting.ParticleSpray
import at.petrak.hexcasting.api.casting.RenderedSpell import at.petrak.hexcasting.api.casting.RenderedSpell
import at.petrak.hexcasting.api.casting.castables.SpellAction import at.petrak.hexcasting.api.casting.castables.SpellAction
import at.petrak.hexcasting.api.casting.eval.CastingEnvironment import at.petrak.hexcasting.api.casting.eval.CastingEnvironment
import at.petrak.hexcasting.api.casting.eval.vm.CastingImage
import at.petrak.hexcasting.api.casting.getEntity import at.petrak.hexcasting.api.casting.getEntity
import at.petrak.hexcasting.api.casting.getVec3 import at.petrak.hexcasting.api.casting.getVec3
import at.petrak.hexcasting.api.casting.iota.Iota import at.petrak.hexcasting.api.casting.iota.Iota
import at.petrak.hexcasting.api.misc.MediaConstants import at.petrak.hexcasting.api.misc.MediaConstants
import net.minecraft.nbt.CompoundTag
import net.minecraft.world.entity.Entity import net.minecraft.world.entity.Entity
import net.minecraft.world.phys.Vec3 import net.minecraft.world.phys.Vec3
@ -18,17 +20,18 @@ object OpAddMotion : SpellAction {
// for bug #387 // for bug #387
val MAX_MOTION: Double = 8192.0 val MAX_MOTION: Double = 8192.0
override fun execute( override fun executeWithUserdata(
args: List<Iota>, args: List<Iota>,
ctx: CastingEnvironment ctx: CastingEnvironment,
): Triple<RenderedSpell, Int, List<ParticleSpray>> { userData: CompoundTag
): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
val target = args.getEntity(0, argc) val target = args.getEntity(0, argc)
val motion = args.getVec3(1, argc) val motion = args.getVec3(1, argc)
ctx.assertEntityInRange(target) ctx.assertEntityInRange(target)
var motionForCost = motion.lengthSqr() var motionForCost = motion.lengthSqr()
if (ctx.hasBeenGivenMotion(target)) if (CastingImage.checkAndMarkGivenMotion(userData, target))
motionForCost++ motionForCost++
ctx.markEntityAsMotionAdded(target)
val shrunkMotion = if (motion.lengthSqr() > MAX_MOTION * MAX_MOTION) val shrunkMotion = if (motion.lengthSqr() > MAX_MOTION * MAX_MOTION)
motion.normalize().scale(MAX_MOTION) motion.normalize().scale(MAX_MOTION)
@ -48,6 +51,10 @@ object OpAddMotion : SpellAction {
) )
} }
override fun execute(args: List<Iota>, ctx: CastingEnvironment): Triple<RenderedSpell, Int, List<ParticleSpray>>? {
throw IllegalStateException()
}
private data class Spell(val target: Entity, val motion: Vec3) : RenderedSpell { private data class Spell(val target: Entity, val motion: Vec3) : RenderedSpell {
override fun cast(ctx: CastingEnvironment) { override fun cast(ctx: CastingEnvironment) {
target.push(motion.x, motion.y, motion.z) target.push(motion.x, motion.y, motion.z)

View file

@ -49,7 +49,7 @@ class OpCreateFluid(val cost: Int, val bucket: Item, val cauldron: BlockState, v
ctx.world.setBlock(pos, cauldron, 3) ctx.world.setBlock(pos, cauldron, 3)
else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid( else if (!IXplatAbstractions.INSTANCE.tryPlaceFluid(
ctx.world, ctx.world,
ctx.castingHand, ctx.castingHand(),
pos, pos,
fluid fluid
) && bucket is BucketItem) { ) && bucket is BucketItem) {

View file

@ -15,14 +15,14 @@ public class HexEvalSounds {
public static final EvalSound NOTHING = make("nothing", public static final EvalSound NOTHING = make("nothing",
new EvalSound(null, Integer.MIN_VALUE)); new EvalSound(null, Integer.MIN_VALUE));
public static final EvalSound OPERATOR = make("operator", public static final EvalSound ADD_PATTERN = make("operator",
new EvalSound(HexSounds.ADD_PATTERN, 0)); new EvalSound(HexSounds.ADD_PATTERN, 0));
public static final EvalSound SPELL = make("spell", public static final EvalSound SPELL = make("spell",
new EvalSound(HexSounds.ACTUALLY_CAST, 1000)); new EvalSound(HexSounds.ACTUALLY_CAST, 1000));
public static final EvalSound HERMES = make("hermes", public static final EvalSound HERMES = make("hermes",
new EvalSound(HexSounds.CAST_HERMES, 2000)); new EvalSound(HexSounds.CAST_HERMES, 2000));
public static final EvalSound THOTH = make("thoth", public static final EvalSound THOTH = make("thoth",
new EvalSound(HexSounds.CAST_THOTH, 2000)); new EvalSound(HexSounds.CAST_THOTH, 2500));
public static final EvalSound MUTE = make("mute", public static final EvalSound MUTE = make("mute",
new EvalSound(null, 3000)); new EvalSound(null, 3000));