diff --git a/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.kt b/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.kt index 8ee4fe2f..d8027d4a 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/PatternRegistry.kt @@ -27,6 +27,7 @@ import java.util.concurrent.ConcurrentMap */ object PatternRegistry { private val operatorLookup = ConcurrentHashMap() + private val keyLookup = ConcurrentHashMap() private val specialHandlers: ConcurrentLinkedDeque = ConcurrentLinkedDeque() // Map signatures to the "preferred" direction they start in and their operator ID. @@ -48,6 +49,7 @@ object PatternRegistry { } this.operatorLookup[id] = operator + this.keyLookup[operator] = id if (isPerWorld) { this.perWorldPatternLookup[id] = PerWorldEntry(pattern, id) } else { @@ -120,6 +122,12 @@ object PatternRegistry { return perWorldPatterns.lookup } + /** + * Internal use only. + */ + @JvmStatic + fun lookupPattern(op: Operator): ResourceLocation? = this.keyLookup[op] + /** * Internal use only. */ diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt index a5b24adc..46d9c658 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/Operator.kt @@ -1,8 +1,14 @@ package at.petrak.hexcasting.api.spell +import at.petrak.hexcasting.api.PatternRegistry import at.petrak.hexcasting.api.spell.casting.CastingContext import at.petrak.hexcasting.api.spell.casting.SpellContinuation +import at.petrak.hexcasting.api.utils.asTranslatedComponent +import at.petrak.hexcasting.api.utils.lightPurple +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation import net.minecraft.world.phys.Vec3 +import java.text.DecimalFormat /** * Manipulates the stack in some way, usually by popping some number of values off the stack @@ -40,6 +46,11 @@ interface Operator { */ val causesBlindDiversion: Boolean get() = this is SpellOperator + /** + * The component for displaying this pattern's name. Override for dynamic patterns. + */ + val displayName: Component get() = "hexcasting.spell.${PatternRegistry.lookupPattern(this)}".asTranslatedComponent.lightPurple + companion object { // I see why vzakii did this: you can't raycast out to infinity! const val MAX_DISTANCE: Double = 32.0 @@ -57,6 +68,20 @@ interface Operator { override fun execute(args: List>, ctx: CastingContext): List> = listOf(x) } + + private val DOUBLE_FORMATTER = DecimalFormat("####.####") + + @JvmStatic + fun makeConstantOp(x: Double, key: ResourceLocation): Operator = object : ConstManaOperator { + override val argc: Int + get() = 0 + + override fun execute(args: List>, ctx: CastingContext): List> = + x.asSpellResult + + override val displayName: Component + get() = "hexcasting.spell.$key".asTranslatedComponent(DOUBLE_FORMATTER.format(x)).lightPurple + } } } diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt index 9a2cd337..d4493fce 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/casting/CastingHarness.kt @@ -47,6 +47,24 @@ class CastingHarness private constructor( */ fun executeIota(iota: SpellDatum<*>, world: ServerLevel): ControllerInfo = executeIotas(listOf(iota), world) + private fun getOperatorForPattern(iota: SpellDatum<*>, world: ServerLevel): Operator? { + if (iota.getType() == DatumType.PATTERN) + return PatternRegistry.matchPattern(iota.payload as HexPattern, world) + return null + } + + private fun getPatternForFrame(frame: ContinuationFrame): HexPattern? { + if (frame !is ContinuationFrame.Evaluate) return null + + return frame.list.car.payload as? HexPattern + } + + private fun getOperatorForFrame(frame: ContinuationFrame, world: ServerLevel): Operator? { + if (frame !is ContinuationFrame.Evaluate) return null + + return getOperatorForPattern(frame.list.car, world) + } + /** * Given a list of iotas, execute them in sequence. */ @@ -63,6 +81,8 @@ class CastingHarness private constructor( val result = try { next.evaluate(continuation.next, world, this) } catch (mishap: Mishap) { + val pattern = getPatternForFrame(next) + val operator = getOperatorForFrame(next, world) CastResult( continuation, null, @@ -70,7 +90,7 @@ class CastingHarness private constructor( listOf( OperatorSideEffect.DoMishap( mishap, - Mishap.Context(HexPattern(HexDir.WEST), null) + Mishap.Context(pattern ?: HexPattern(HexDir.WEST), operator) ) ) ) @@ -126,7 +146,7 @@ class CastingHarness private constructor( listOf( OperatorSideEffect.DoMishap( mishap, - Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null) + Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), getOperatorForPattern(iota, world)) ) ), ) @@ -139,7 +159,7 @@ class CastingHarness private constructor( listOf( OperatorSideEffect.DoMishap( MishapError(exception), - Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), null) + Mishap.Context(iota.payload as? HexPattern ?: HexPattern(HexDir.WEST), getOperatorForPattern(iota, world)) ) ) ) @@ -218,7 +238,7 @@ class CastingHarness private constructor( continuation, null, mishap.resolutionType(ctx), - listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.second))), + listOf(OperatorSideEffect.DoMishap(mishap, Mishap.Context(newPat, operatorIdPair?.first))), ) } catch (exception: Exception) { exception.printStackTrace() @@ -229,7 +249,7 @@ class CastingHarness private constructor( listOf( OperatorSideEffect.DoMishap( MishapError(exception), - Mishap.Context(newPat, operatorIdPair?.second) + Mishap.Context(newPat, operatorIdPair?.first) ) ) ) diff --git a/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/Mishap.kt b/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/Mishap.kt index 6b5784f7..807c5b1d 100644 --- a/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/Mishap.kt +++ b/Common/src/main/java/at/petrak/hexcasting/api/spell/mishaps/Mishap.kt @@ -2,6 +2,7 @@ package at.petrak.hexcasting.api.spell.mishaps import at.petrak.hexcasting.api.misc.FrozenColorizer import at.petrak.hexcasting.api.mod.HexItemTags +import at.petrak.hexcasting.api.spell.Operator import at.petrak.hexcasting.api.spell.ParticleSpray import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext @@ -15,7 +16,6 @@ import at.petrak.hexcasting.xplat.IXplatAbstractions import net.minecraft.Util import net.minecraft.core.BlockPos import net.minecraft.network.chat.Component -import net.minecraft.resources.ResourceLocation import net.minecraft.world.InteractionHand import net.minecraft.world.damagesource.DamageSource import net.minecraft.world.entity.LivingEntity @@ -54,8 +54,8 @@ sealed class Mishap : Throwable() { protected fun error(stub: String, vararg args: Any): Component = "hexcasting.mishap.$stub".asTranslatedComponent(*args) - protected fun actionName(action: ResourceLocation?): Component = - "hexcasting.spell.${action ?: "unknown"}".asTranslatedComponent.lightPurple + protected fun actionName(action: Operator?): Component = + action?.displayName ?: "hexcasting.spell.null".asTranslatedComponent.lightPurple protected fun yeetHeldItemsTowards(ctx: CastingContext, targetPos: Vec3) { // Knock the player's items out of their hands @@ -101,7 +101,7 @@ sealed class Mishap : Throwable() { return ctx.world.getBlockState(pos).block.name } - data class Context(val pattern: HexPattern, val action: ResourceLocation?) + data class Context(val pattern: HexPattern, val action: Operator?) companion object { fun trulyHurt(entity: LivingEntity, source: DamageSource, amount: Float) { diff --git a/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt b/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt index 8d01bbb6..c7a6a934 100644 --- a/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt +++ b/Common/src/main/java/at/petrak/hexcasting/client/gui/GuiSpellcasting.kt @@ -207,10 +207,6 @@ class GuiSpellcasting( is PatternDrawState.JustStarted -> { // Well, we never managed to get anything on the stack this go-around. this.drawState = PatternDrawState.BetweenPatterns - if (this.patterns.isEmpty()) { - Minecraft.getInstance().setScreen(null) - Minecraft.getInstance().soundManager.stop(HexSounds.CASTING_AMBIANCE.location, null) - } } is PatternDrawState.Drawing -> { val (start, _, pat) = this.drawState as PatternDrawState.Drawing diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java b/Common/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java index 169889f9..520a04d2 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/RegisterPatterns.java @@ -500,7 +500,7 @@ public class RegisterPatterns { if (negate) { accumulator = -accumulator; } - return Operator.makeConstantOp(SpellDatum.make(accumulator)); + return Operator.makeConstantOp(accumulator, modLoc("number")); } else { return null; } @@ -536,7 +536,7 @@ public class RegisterPatterns { return null; } - return new OpMask(mask); + return new OpMask(mask, modLoc("mask")); }); } } diff --git a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpMask.kt b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpMask.kt index 40631da9..94dd22db 100644 --- a/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpMask.kt +++ b/Common/src/main/java/at/petrak/hexcasting/common/casting/operators/stack/OpMask.kt @@ -3,9 +3,13 @@ package at.petrak.hexcasting.common.casting.operators.stack import at.petrak.hexcasting.api.spell.ConstManaOperator import at.petrak.hexcasting.api.spell.SpellDatum import at.petrak.hexcasting.api.spell.casting.CastingContext +import at.petrak.hexcasting.api.utils.asTranslatedComponent +import at.petrak.hexcasting.api.utils.lightPurple import it.unimi.dsi.fastutil.booleans.BooleanList +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation -class OpMask(val mask: BooleanList) : ConstManaOperator { +class OpMask(val mask: BooleanList, val key: ResourceLocation) : ConstManaOperator { override val argc: Int get() = mask.size @@ -17,4 +21,7 @@ class OpMask(val mask: BooleanList) : ConstManaOperator { } return out } + + override val displayName: Component + get() = "hexcasting.spell.$key".asTranslatedComponent(mask.map { if (it) '-' else 'v' }.joinToString("")).lightPurple } diff --git a/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java new file mode 100644 index 00000000..1d61a943 --- /dev/null +++ b/Common/src/main/java/at/petrak/hexcasting/interop/patchouli/PatternProcessor.java @@ -0,0 +1,33 @@ +package at.petrak.hexcasting.interop.patchouli; + +import net.minecraft.client.resources.language.I18n; +import vazkii.patchouli.api.IComponentProcessor; +import vazkii.patchouli.api.IVariable; +import vazkii.patchouli.api.IVariableProvider; + +public class PatternProcessor implements IComponentProcessor { + private String translationKey; + + @Override + public void setup(IVariableProvider vars) { + if (vars.has("header")) + translationKey = vars.get("header").asString(); + else { + IVariable key = vars.get("op_id"); + String opName = key.asString(); + + String prefix = "hexcasting.spell."; + boolean hasOverride = I18n.exists(prefix + "book." + opName); + translationKey = prefix + (hasOverride ? "book." : "") + opName; + } + } + + @Override + public IVariable process(String key) { + if (key.equals("translation_key")) { + return IVariable.wrap(translationKey); + } + + return null; + } +} diff --git a/Common/src/main/resources/assets/hexcasting/lang/en_us.json b/Common/src/main/resources/assets/hexcasting/lang/en_us.json index 9de13af6..767ca2fb 100644 --- a/Common/src/main/resources/assets/hexcasting/lang/en_us.json +++ b/Common/src/main/resources/assets/hexcasting/lang/en_us.json @@ -207,10 +207,40 @@ "hexcasting.subtitles.impetus.fletcher.tick": "Fletcher Impetus ticks", "hexcasting.subtitles.impetus.cleric.register": "Cleric Impetus dings", + "_comment": "hexcasting.spell.book keys override the name of a pattern in the patchouli book if present", + + "hexcasting.spell.book.hexcasting:get_entity_height": "Stadiometer's Prfn.", + "hexcasting.spell.book.hexcasting:get_entity/animal": "Entity Prfn.: Animal", + "hexcasting.spell.book.hexcasting:get_entity/monster": "Entity Prfn.: Monster", + "hexcasting.spell.book.hexcasting:get_entity/item": "Entity Prfn.: Item", + "hexcasting.spell.book.hexcasting:get_entity/player": "Entity Prfn.: Player", + "hexcasting.spell.book.hexcasting:get_entity/living": "Entity Prfn.: Living", + "hexcasting.spell.book.hexcasting:zone_entity": "Zone Dstl.: Any", + "hexcasting.spell.book.hexcasting:zone_entity/animal": "Zone Dstl.: Animal", + "hexcasting.spell.book.hexcasting:zone_entity/monster": "Zone Dstl.: Monster", + "hexcasting.spell.book.hexcasting:zone_entity/item": "Zone Dstl.: Item", + "hexcasting.spell.book.hexcasting:zone_entity/player": "Zone Dstl.: Player", + "hexcasting.spell.book.hexcasting:zone_entity/living": "Zone Dstl.: Living", + "hexcasting.spell.book.hexcasting:zone_entity/not_animal": "Zone Dstl.: Non-Animal", + "hexcasting.spell.book.hexcasting:zone_entity/not_monster": "Zone Dstl.: Non-Monster", + "hexcasting.spell.book.hexcasting:zone_entity/not_item": "Zone Dstl.: Non-Item", + "hexcasting.spell.book.hexcasting:zone_entity/not_player": "Zone Dstl.: Non-Player", + "hexcasting.spell.book.hexcasting:zone_entity/not_living": "Zone Dstl.: Non-Living", + "hexcasting.spell.book.hexcasting:mul_dot": "Multiplicative Dstl.", + "hexcasting.spell.book.hexcasting:div_cross": "Division Dstl.", + "hexcasting.spell.book.hexcasting:arcsin": "Inverse Sine Prfn.", + "hexcasting.spell.book.hexcasting:arccos": "Inverse Cosine Prfn.", + "hexcasting.spell.book.hexcasting:arctan": "Inverse Tangent Prfn.", + "hexcasting.spell.book.hexcasting:const/vec/x": "Vector Rfln. +X/-X", + "hexcasting.spell.book.hexcasting:const/vec/y": "Vector Rfln. +Y/-Y", + "hexcasting.spell.book.hexcasting:const/vec/z": "Vector Rfln. +Z/-Z", + "hexcasting.spell.book.hexcasting:number": "Numerical Reflection", + "hexcasting.spell.book.hexcasting:mask": "Bookkeeper's Gambit", + "hexcasting.spell.hexcasting:get_caster": "Mind's Reflection", "hexcasting.spell.hexcasting:get_entity_pos": "Compass' Purification", "hexcasting.spell.hexcasting:get_entity_look": "Alidade's Purification", - "hexcasting.spell.hexcasting:get_entity_height": "Stadiometer's Prfn.", + "hexcasting.spell.hexcasting:get_entity_height": "Stadiometer's Purification", "hexcasting.spell.hexcasting:get_entity_velocity": "Pace Purification", "hexcasting.spell.hexcasting:raycast": "Archer's Distillation", "hexcasting.spell.hexcasting:raycast/axis": "Architect's Distillation", @@ -236,22 +266,22 @@ "hexcasting.spell.hexcasting:construct": "Speaker's Distillation", "hexcasting.spell.hexcasting:deconstruct": "Speaker's Decomposition", "hexcasting.spell.hexcasting:get_entity": "Entity Purification", - "hexcasting.spell.hexcasting:get_entity/animal": "Entity Prfn.: Animal", - "hexcasting.spell.hexcasting:get_entity/monster": "Entity Prfn.: Monster", - "hexcasting.spell.hexcasting:get_entity/item": "Entity Prfn.: Item", - "hexcasting.spell.hexcasting:get_entity/player": "Entity Prfn.: Player", - "hexcasting.spell.hexcasting:get_entity/living": "Entity Prfn.: Living", - "hexcasting.spell.hexcasting:zone_entity": "Zone Dstl.: Any", - "hexcasting.spell.hexcasting:zone_entity/animal": "Zone Dstl.: Animal", - "hexcasting.spell.hexcasting:zone_entity/monster": "Zone Dstl.: Monster", - "hexcasting.spell.hexcasting:zone_entity/item": "Zone Dstl.: Item", - "hexcasting.spell.hexcasting:zone_entity/player": "Zone Dstl.: Player", - "hexcasting.spell.hexcasting:zone_entity/living": "Zone Dstl.: Living", - "hexcasting.spell.hexcasting:zone_entity/not_animal": "Zone Dstl.: Non-Animal", - "hexcasting.spell.hexcasting:zone_entity/not_monster": "Zone Dstl.: Non-Monster", - "hexcasting.spell.hexcasting:zone_entity/not_item": "Zone Dstl.: Non-Item", - "hexcasting.spell.hexcasting:zone_entity/not_player": "Zone Dstl.: Non-Player", - "hexcasting.spell.hexcasting:zone_entity/not_living": "Zone Dstl.: Non-Living", + "hexcasting.spell.hexcasting:get_entity/animal": "Entity Purification: Animal", + "hexcasting.spell.hexcasting:get_entity/monster": "Entity Purification: Monster", + "hexcasting.spell.hexcasting:get_entity/item": "Entity Purification: Item", + "hexcasting.spell.hexcasting:get_entity/player": "Entity Purification: Player", + "hexcasting.spell.hexcasting:get_entity/living": "Entity Purification: Living", + "hexcasting.spell.hexcasting:zone_entity": "Zone Distillation: Any", + "hexcasting.spell.hexcasting:zone_entity/animal": "Zone Distillation: Animal", + "hexcasting.spell.hexcasting:zone_entity/monster": "Zone Distillation: Monster", + "hexcasting.spell.hexcasting:zone_entity/item": "Zone Distillation: Item", + "hexcasting.spell.hexcasting:zone_entity/player": "Zone Distillation: Player", + "hexcasting.spell.hexcasting:zone_entity/living": "Zone Distillation: Living", + "hexcasting.spell.hexcasting:zone_entity/not_animal": "Zone Distillation: Non-Animal", + "hexcasting.spell.hexcasting:zone_entity/not_monster": "Zone Distillation: Non-Monster", + "hexcasting.spell.hexcasting:zone_entity/not_item": "Zone Distillation: Non-Item", + "hexcasting.spell.hexcasting:zone_entity/not_player": "Zone Distillation: Non-Player", + "hexcasting.spell.hexcasting:zone_entity/not_living": "Zone Distillation: Non-Living", "hexcasting.spell.hexcasting:const/null": "Nullary Reflection", "hexcasting.spell.hexcasting:duplicate": "Gemini Decomposition", "hexcasting.spell.hexcasting:duplicate_n": "Gemini's Gambit", @@ -261,8 +291,8 @@ "hexcasting.spell.hexcasting:swizzle": "Swindler's Gambit", "hexcasting.spell.hexcasting:add": "Additive Distillation", "hexcasting.spell.hexcasting:sub": "Subtractive Distillation", - "hexcasting.spell.hexcasting:mul_dot": "Multiplicative Dstl.", - "hexcasting.spell.hexcasting:div_cross": "Division Dstl.", + "hexcasting.spell.hexcasting:mul_dot": "Multiplicative Distillation", + "hexcasting.spell.hexcasting:div_cross": "Division Distillation", "hexcasting.spell.hexcasting:abs_len": "Length Purification", "hexcasting.spell.hexcasting:pow_proj": "Power Distillation", "hexcasting.spell.hexcasting:construct_vec": "Vector Exaltation", @@ -289,9 +319,9 @@ "hexcasting.spell.hexcasting:sin": "Sine Purification", "hexcasting.spell.hexcasting:cos": "Cosine Purification", "hexcasting.spell.hexcasting:tan": "Tangent Purification", - "hexcasting.spell.hexcasting:arcsin": "Inverse Sine Prfn.", - "hexcasting.spell.hexcasting:arccos": "Inverse Cosine Prfn.", - "hexcasting.spell.hexcasting:arctan": "Inverse Tangent Prfn.", + "hexcasting.spell.hexcasting:arcsin": "Inverse Sine Purification", + "hexcasting.spell.hexcasting:arccos": "Inverse Cosine Purification", + "hexcasting.spell.hexcasting:arctan": "Inverse Tangent Purification", "hexcasting.spell.hexcasting:random": "Entropy Reflection", "hexcasting.spell.hexcasting:logarithm": "Logarithmic Distillation", "hexcasting.spell.hexcasting:coerce_axial": "Axial Purification", @@ -361,16 +391,13 @@ "hexcasting.spell.hexcasting:const/vec/nx": "Vector Reflection -X", "hexcasting.spell.hexcasting:const/vec/ny": "Vector Reflection -Y", "hexcasting.spell.hexcasting:const/vec/nz": "Vector Reflection -Z", - "hexcasting.spell.hexcasting:const/vec/x": "Vector Rfln. +X/-X", - "hexcasting.spell.hexcasting:const/vec/y": "Vector Rfln. +Y/-Y", - "hexcasting.spell.hexcasting:const/vec/z": "Vector Rfln. +Z/-Z", "hexcasting.spell.hexcasting:const/vec/0": "Vector Reflection Zero", "hexcasting.spell.hexcasting:const/double/pi": "Arc's Reflection", "hexcasting.spell.hexcasting:const/double/tau": "Circle's Reflection", "hexcasting.spell.hexcasting:const/double/e": "Euler's Reflection", - "hexcasting.spell.hexcasting:number": "Numerical Reflection", - "hexcasting.spell.hexcasting:mask": "Bookkeeper's Gambit", - "hexcasting.spell.unknown": "Special Handler", + "hexcasting.spell.hexcasting:number": "Numerical Reflection: %s", + "hexcasting.spell.hexcasting:mask": "Bookkeeper's Gambit: %s", + "hexcasting.spell.null": "Unknown Pattern", "hexcasting.spell.hexcasting:interop/gravity/get": "Gravitational Purification", "hexcasting.spell.hexcasting:interop/gravity/set": "Alter Gravity", @@ -731,7 +758,6 @@ "hexcasting.page.basics_pattern.raycast/entity": "Like $(l:patterns/basics#hexcasting:raycast)$(action)Archer's Distillation/$, but instead returns the $(italic)entity/$ I am looking at. Costs a negligible amount of _media.", "hexcasting.entry.numbers": "Number Literals", - "hexcasting.page.numbers.1.header": "Numerical Reflection", "hexcasting.page.numbers.1": "Irritatingly, there is no easy way to draw numbers. Here is the method Nature deigned to give us.", "hexcasting.page.numbers.2": "First, I draw one of the two shapes shown on the other page. Next, the $(italic)angles/$ following will modify a running count starting at 0.$(li)Forward: Add 1$(li)Left: Add 5$(li)Right: Add 10$(li)Sharp Left: Multiply by 2$(li)Sharp Right: Divide by 2.$(br)The clockwise version of the pattern, on the right of the other page, will negate the value at the very end. (The left-hand counter-clockwise version keeps the number positive).$(p)Once I finish drawing, the number's pushed to the top of the stack.", "hexcasting.page.numbers.example.10.header": "Example 1", @@ -805,7 +831,6 @@ "hexcasting.page.stackmanip.splat": "Remove the list at the top of the stack, then push its contents to the stack.", "hexcasting.page.stackmanip.duplicate": "Duplicates the top iota of the stack.", "hexcasting.page.stackmanip.duplicate_n": "Removes the number at the top of the stack, then copies the top iota of the stack that number of times. (A count of 2 results in two of the iota on the stack, not three.)", - "hexcasting.page.stackmanip.mask.header": "Bookkeeper's Gambits", "hexcasting.page.stackmanip.mask.1": "An infinite family of actions that keep or remove elements at the top of the stack based on the sequence of dips and lines.", "hexcasting.page.stackmanip.mask.2": "Assuming that I draw a Bookkeeper's Gambit pattern left-to-right, the number of iotas the action will require is determined by the horizontal distance covered by the pattern. From deepest in the stack to shallowest, a flat line will keep the iota, whereas a triangle dipping down will remove it.$(br2)If my stack contains $(italic)0, 1, 2/$ from deepest to shallowest, drawing the first pattern opposite will give me $(italic)1/$, the second will give me $(italic)0/$, and the third will give me $(italic)0, 2/$ (the 0 at the bottom is left untouched).", "hexcasting.page.stackmanip.swizzle.1": "Rearranges the top elements of the stack based on the given numerical code, which is the index of the permutation wanted. Costs an amount of media that starts negligible and scales up as the numerical code does.", diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/consts.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/consts.json index 4d6508dd..906c6e56 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/consts.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/consts.json @@ -8,7 +8,7 @@ "pages": [ { "type": "hexcasting:manual_pattern", - "header": "hexcasting.spell.hexcasting:const/vec/x", + "op_id": "hexcasting:const/vec/x", "anchor": "hexcasting:const/vec/x", "input": "", "output": "vector", @@ -28,7 +28,7 @@ }, { "type": "hexcasting:manual_pattern", - "header": "hexcasting.spell.hexcasting:const/vec/y", + "op_id": "hexcasting:const/vec/y", "anchor": "hexcasting:const/vec/y", "input": "", "output": "vector", @@ -48,7 +48,7 @@ }, { "type": "hexcasting:manual_pattern", - "header": "hexcasting.spell.hexcasting:const/vec/z", + "op_id": "hexcasting:const/vec/z", "anchor": "hexcasting:const/vec/z", "input": "", "output": "vector", diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/numbers.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/numbers.json index 87e06a53..e0e6115f 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/numbers.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/numbers.json @@ -8,7 +8,7 @@ "pages": [ { "type": "hexcasting:manual_pattern", - "header": "hexcasting.page.numbers.1.header", + "op_id": "hexcasting:number", "anchor": "Numbers", "input": "", "output": "number", diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/stackmanip.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/stackmanip.json index 6ddab4c2..e9a2219b 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/stackmanip.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/entries/patterns/stackmanip.json @@ -68,8 +68,8 @@ }, { "type": "hexcasting:manual_pattern", - "header": "hexcasting.page.stackmanip.mask.header", - "anchor": "Numbers", + "op_id": "hexcasting:mask", + "anchor": "hexcasting:mask", "input": "many", "output": "many", "text": "hexcasting.page.stackmanip.mask.1", diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern.json index 385f795d..4c8ea5fa 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern.json @@ -1,8 +1,9 @@ { + "processor": "at.petrak.hexcasting.interop.patchouli.PatternProcessor", "components": [ { "type": "patchouli:header", - "text": "#header", + "text": "#translation_key", "x": -1, "y": -1 }, diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern_nosig.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern_nosig.json index d12c586d..845d7e4d 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern_nosig.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/manual_pattern_nosig.json @@ -1,8 +1,9 @@ { + "processor": "at.petrak.hexcasting.interop.patchouli.PatternProcessor", "components": [ { "type": "patchouli:header", - "text": "#header", + "text": "#translation_key", "x": -1, "y": -1 }, diff --git a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/pattern.json b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/pattern.json index 805422e6..9f5c0bb9 100644 --- a/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/pattern.json +++ b/Common/src/main/resources/data/hexcasting/patchouli_books/thehexbook/en_us/templates/pattern.json @@ -1,8 +1,9 @@ { + "processor": "at.petrak.hexcasting.interop.patchouli.PatternProcessor", "components": [ { "type": "patchouli:header", - "text": "hexcasting.spell.#op_id#", + "text": "#translation_key", "x": -1, "y": -1 }, diff --git a/doc/collate_data.py b/doc/collate_data.py index 04bde1ad..0bf422a1 100755 --- a/doc/collate_data.py +++ b/doc/collate_data.py @@ -104,15 +104,15 @@ def parse_style(sty): return "", Style("base", None) if sty in types: return "", Style(types[sty], True) - if sty in colors: + if sty in colors: return "", Style("color", colors[sty]) if sty.startswith("#") and len(sty) in [4, 7]: return "", Style("color", sty[1:]) # TODO more style parse raise ValueError("Unknown style: " + sty) -def localize(i18n, string): - return i18n.get(string, string) if i18n else string +def localize(i18n, string, default=None): + return i18n.get(string, default if default else string) if i18n else string format_re = re.compile(r"\$\(([^)]*)\)") def format_string(root_data, string): @@ -144,7 +144,7 @@ def format_string(root_data, string): text_nodes.append(extra_text + string[last_end:]) first_node, *text_nodes = text_nodes - # parse + # parse style_stack = [FormatTree(Style("base", True), []), FormatTree(Style("para", {}), [first_node])] for style, text in zip(styles, text_nodes): tmp_stylestack = [] @@ -174,6 +174,11 @@ def format_string(root_data, string): test_root = {"i18n": {}, "macros": default_macros, "resource_dir": "Common/src/main/resources", "modid": "hexcasting"} test_str = "Write the given iota to my $(l:patterns/readwrite#hexcasting:write/local)$(#490)local$().$(br)The $(l:patterns/readwrite#hexcasting:write/local)$(#490)local$() is a lot like a $(l:items/focus)$(#b0b)Focus$(). It's cleared when I stop casting a Hex, starts with $(l:casting/influences)$(#490)Null$() in it, and is preserved between casts of $(l:patterns/meta#hexcasting:for_each)$(#fc77be)Thoth's Gambit$(). " +def localize_pattern(root_data, op_id): + return localize(root_data["i18n"], "hexcasting.spell.book." + op_id, + localize(root_data["i18n"], "hexcasting.spell." + op_id)) + + def do_localize(root_data, obj, *names): for name in names: if name in obj: @@ -204,10 +209,12 @@ def resolve_pattern(root_data, page): if "pattern_reg" not in root_data: root_data["pattern_reg"] = fetch_patterns(root_data) page["op"] = [root_data["pattern_reg"][page["op_id"]]] - page["name"] = localize(root_data["i18n"], "hexcasting.spell." + page["op_id"]) + page["name"] = localize_pattern(root_data, page["op_id"]) def fixup_pattern(do_sig, root_data, page): patterns = page["patterns"] + if "op_id" in page: + page["header"] = localize_pattern(root_data, page["op_id"]) if not isinstance(patterns, list): patterns = [patterns] if do_sig: inp = page.get("input", None) or "" @@ -261,7 +268,7 @@ def parse_entry(root_data, entry_path, ent_name): if isinstance(page, str): page = {"type": "patchouli:text", "text": page} data["pages"][i] = page - + do_localize(root_data, page, "title", "header") do_format(root_data, page, "text") if page["type"] in page_types: @@ -473,7 +480,7 @@ def write_page(out, pageid, page): with out.pair_tag("code"): out.text(i) out.text(".") if "text" in page: write_block(out, page["text"]) - elif ty == "hexcasting:brainsweep": + elif ty == "hexcasting:brainsweep": with out.pair_tag("blockquote", clazz="crafting-info"): out.text(f"Depicted in the book: A mind-flaying recipe producing the ") with out.pair_tag("code"): out.text(page["output_name"])