Add stricter pattern page validation

This commit is contained in:
object-Object 2023-08-23 08:34:06 -04:00
parent 2fa96babde
commit 036579607c
8 changed files with 71 additions and 39 deletions

View file

@ -599,9 +599,7 @@
append: "Integration Distillation", append: "Integration Distillation",
unappend: "Derivation Distillation", unappend: "Derivation Distillation",
concat: "Combination Distillation",
index: "Selection Distillation", index: "Selection Distillation",
list_size: "Abacus Purification",
singleton: "Single's Purification", singleton: "Single's Purification",
empty_list: "Vacant Reflection", empty_list: "Vacant Reflection",
reverse: "Retrograde Purification", reverse: "Retrograde Purification",
@ -1604,7 +1602,7 @@
numlist: "Set operations are odd, in that some of them can accept two numbers or two lists, but not a combination thereof. Such arguments will be written as \"(num, num)|(list, list)\".$(br2)When numbers are used in those operations, they are being used as so-called binary \"bitsets\", lists of 1 and 0, true and false, \"on\" and \"off\".", numlist: "Set operations are odd, in that some of them can accept two numbers or two lists, but not a combination thereof. Such arguments will be written as \"(num, num)|(list, list)\".$(br2)When numbers are used in those operations, they are being used as so-called binary \"bitsets\", lists of 1 and 0, true and false, \"on\" and \"off\".",
"or.1": "Unifies two sets.", "or.1": "Unifies two sets.",
"or.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit in either bitset.$(li)With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to $(l:patterns/lists#hexcasting:concat)$(action)Combination Distillation/$.", "or.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit in either bitset.$(li)With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to $(l:patterns/lists#hexcasting:add)$(action)Combination Distillation/$.",
"and.1": "Takes the intersection of two sets.", "and.1": "Takes the intersection of two sets.",
"and.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit present in $(italics)both/$ bitsets.$(li)With two lists, this creates a list of every element from the first list that is also in the second list.", "and.2": "As such:$(li)With two numbers at the top of the stack, combines them into a bitset containing every \"on\" bit present in $(italics)both/$ bitsets.$(li)With two lists, this creates a list of every element from the first list that is also in the second list.",
@ -1709,10 +1707,10 @@
slice: "Remove the two numbers at the top of the stack, then take a sublist of the list at the top of the stack between those indices, lower bound inclusive, upper bound exclusive. For example, the 0, 2 sublist of [0, 1, 2, 3, 4] would be [0, 1].", slice: "Remove the two numbers at the top of the stack, then take a sublist of the list at the top of the stack between those indices, lower bound inclusive, upper bound exclusive. For example, the 0, 2 sublist of [0, 1, 2, 3, 4] would be [0, 1].",
append: "Remove the top of the stack, then add it to the end of the list at the top of the stack.", append: "Remove the top of the stack, then add it to the end of the list at the top of the stack.",
unappend: "Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.", unappend: "Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.",
concat: "Remove the list at the top of the stack, then add all its elements to the end of the list at the top of the stack.", add: "Remove the list at the top of the stack, then add all its elements to the end of the list at the top of the stack.",
empty_list: "Push an empty list to the top of the stack.", empty_list: "Push an empty list to the top of the stack.",
singleton: "Remove the top of the stack, then push a list containing only that element.", singleton: "Remove the top of the stack, then push a list containing only that element.",
list_size: "Remove the list at the top of the stack, then push the number of elements in the list to the stack.", abs: "Remove the list at the top of the stack, then push the number of elements in the list to the stack.",
reverse: "Reverse the list at the top of the stack.", reverse: "Reverse the list at the top of the stack.",
index_of: "Remove the iota at the top of the stack, then replace the list at the top with the first index of that iota within the list (starting from 0). Replaces the list with -1 if the iota doesn't exist in the list.", index_of: "Remove the iota at the top of the stack, then replace the list at the top with the first index of that iota within the list (starting from 0). Replaces the list with -1 if the iota doesn't exist in the list.",
remove_from: "Remove the number at the top of the stack, then remove the nth element of the list at the top of the stack (where n is the number you removed).", remove_from: "Remove the number at the top of the stack, then remove the nth element of the list at the top of the stack (where n is the number you removed).",

View file

@ -9,6 +9,7 @@
{ {
"type": "hexcasting:pattern", "type": "hexcasting:pattern",
"op_id": "hexcasting:sentinel/create/great", "op_id": "hexcasting:sentinel/create/great",
"anchor": "hexcasting:sentinel/create/great",
"text": "hexcasting.page.greater_sentinel.1", "text": "hexcasting.page.greater_sentinel.1",
"input": "vector", "input": "vector",
"output": "" "output": ""

View file

@ -40,12 +40,12 @@
}, },
{ {
"type": "hexcasting:pattern", "type": "hexcasting:pattern",
"header": "hexcasting.action.hexcasting:concat", "header": "hexcasting.action.hexcasting:add",
"op_id": "hexcasting:add", "op_id": "hexcasting:add",
"anchor": "hexcasting:concat", "anchor": "hexcasting:add",
"input": "list, list", "input": "list, list",
"output": "list", "output": "list",
"text": "hexcasting.page.lists.concat" "text": "hexcasting.page.lists.add"
}, },
{ {
"type": "hexcasting:pattern", "type": "hexcasting:pattern",
@ -65,12 +65,12 @@
}, },
{ {
"type": "hexcasting:pattern", "type": "hexcasting:pattern",
"header": "hexcasting.action.hexcasting:list_size", "header": "hexcasting.action.hexcasting:abs",
"op_id": "hexcasting:abs", "op_id": "hexcasting:abs",
"anchor": "hexcasting:list_size", "anchor": "hexcasting:abs",
"input": "list", "input": "list",
"output": "num", "output": "num",
"text": "hexcasting.page.lists.list_size" "text": "hexcasting.page.lists.abs"
}, },
{ {
"type": "hexcasting:pattern", "type": "hexcasting:pattern",

View file

@ -12,7 +12,6 @@ from hexdoc.utils.deserialize import cast_or_raise
from ..pattern import RawPatternInfo from ..pattern import RawPatternInfo
# TODO: make anchor required (breaks because of Greater Sentinel)
class PageWithPattern(PageWithText, type=None): class PageWithPattern(PageWithText, type=None):
header: LocalizedStr header: LocalizedStr
patterns: list[RawPatternInfo] patterns: list[RawPatternInfo]
@ -44,6 +43,7 @@ class PageWithPattern(PageWithText, type=None):
class PageWithOpPattern(PageWithPattern, type=None): class PageWithOpPattern(PageWithPattern, type=None):
op_id: ResourceLocation op_id: ResourceLocation
anchor: str
@model_validator(mode="before") @model_validator(mode="before")
def _pre_root_header(cls, values: Any, info: ValidationInfo): def _pre_root_header(cls, values: Any, info: ValidationInfo):

View file

@ -1,4 +1,4 @@
from typing import Any from typing import Any, Self
from pydantic import ValidationInfo, model_validator from pydantic import ValidationInfo, model_validator
@ -32,6 +32,12 @@ class LookupPatternPage(PageWithOpPattern, type="hexcasting:pattern"):
case _: case _:
return values return values
@model_validator(mode="after")
def _check_anchor(self) -> Self:
if str(self.op_id) != self.anchor:
raise ValueError(f"op_id={self.op_id} does not equal anchor={self.anchor}")
return self
class ManualOpPatternPage( class ManualOpPatternPage(
PageWithOpPattern, PageWithOpPattern,

View file

@ -32,7 +32,7 @@ class Args:
properties_file: Path properties_file: Path
output_file: Path | None output_file: Path | None
verbose: bool verbose: int
ci: bool ci: bool
@classmethod @classmethod
@ -41,7 +41,7 @@ class Args:
parser.add_argument("properties_file", type=Path) parser.add_argument("properties_file", type=Path)
parser.add_argument("--output_file", "-o", type=Path) parser.add_argument("--output_file", "-o", type=Path)
parser.add_argument("--verbose", "-v", action="store_true") parser.add_argument("--verbose", "-v", action="count", default=0)
parser.add_argument("--ci", action="store_true") parser.add_argument("--ci", action="store_true")
return cls(**vars(parser.parse_args(args))) return cls(**vars(parser.parse_args(args)))
@ -55,6 +55,16 @@ class Args:
if self.ci and os.getenv("RUNNER_DEBUG") == "1": if self.ci and os.getenv("RUNNER_DEBUG") == "1":
self.verbose = True self.verbose = True
@property
def log_level(self) -> int:
match self.verbose:
case 0:
return logging.WARNING
case 1:
return logging.INFO
case _:
return logging.DEBUG
def main(args: Args | None = None) -> None: def main(args: Args | None = None) -> None:
# allow passing Args for test cases, but parse by default # allow passing Args for test cases, but parse by default
@ -72,11 +82,8 @@ def main(args: Args | None = None) -> None:
logging.basicConfig( logging.basicConfig(
style="{", style="{",
format="\033[1m[{relativeCreated:.02f} | {levelname} | {name}]\033[0m {message}", format="\033[1m[{relativeCreated:.02f} | {levelname} | {name}]\033[0m {message}",
level=args.log_level,
) )
logger = logging.getLogger(__name__)
if args.verbose:
logging.getLogger().setLevel(logging.DEBUG)
logger.debug("Log level set to DEBUG")
# load the book # load the book
props = Properties.load(args.properties_file) props = Properties.load(args.properties_file)

View file

@ -202,7 +202,9 @@ class ModResourceLoader:
if not path.is_file(): if not path.is_file():
raise FileNotFoundError(path) raise FileNotFoundError(path)
logging.getLogger(__name__).debug(f"Loading {path}") logger = logging.getLogger(__name__)
logger.info(f"Loading {path}")
data = path.read_text("utf-8") data = path.read_text("utf-8")
value = decode(data) value = decode(data)
@ -210,7 +212,7 @@ class ModResourceLoader:
out_path = self.props.export_dir / path.relative_to(resource_dir.path) out_path = self.props.export_dir / path.relative_to(resource_dir.path)
out_path.parent.mkdir(parents=True, exist_ok=True) out_path.parent.mkdir(parents=True, exist_ok=True)
logging.getLogger(__name__).debug(f"Exporting {path} to {out_path}") logger.debug(f"Exporting {path} to {out_path}")
match export: match export:
case None: case None:
out_data = data out_data = data

View file

@ -3762,9 +3762,9 @@
<p>Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.</p> <p>Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.</p>
</div> </div>
<br /> <br />
<div id="patterns/lists@hexcasting:concat"> <div id="patterns/lists@hexcasting:add">
<h4 class="pattern-title">Additive Distillation (list, list → list)<a <h4 class="pattern-title">Additive Distillation (list, list → list)<a
href="#patterns/lists@hexcasting:concat" href="#patterns/lists@hexcasting:add"
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4> ><i class="bi bi-link-45deg"></i></a></h4>
@ -3822,9 +3822,9 @@
<p>Remove the top of the stack, then push a list containing only that element.</p> <p>Remove the top of the stack, then push a list containing only that element.</p>
</div> </div>
<br /> <br />
<div id="patterns/lists@hexcasting:list_size"> <div id="patterns/lists@hexcasting:abs">
<h4 class="pattern-title">Length Purification (list → num)<a <h4 class="pattern-title">Length Purification (list → num)<a
href="#patterns/lists@hexcasting:list_size" href="#patterns/lists@hexcasting:abs"
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4> ><i class="bi bi-link-45deg"></i></a></h4>
@ -4530,7 +4530,7 @@
<p>Unifies two sets.</p> <p>Unifies two sets.</p>
</div> </div>
<br /> <br />
<p>As such:</p><p class='fake-li'>With two numbers at the top of the stack, combines them into a bitset containing every &#34;on&#34; bit in either bitset.</p><p class='fake-li'>With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to <a href='#patterns/lists@hexcasting:concat'><span style='color: #fc77be'>Combination Distillation</span></a>.</p> <p>As such:</p><p class='fake-li'>With two numbers at the top of the stack, combines them into a bitset containing every &#34;on&#34; bit in either bitset.</p><p class='fake-li'>With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to <a href='#patterns/lists@hexcasting:add'><span style='color: #fc77be'>Combination Distillation</span></a>.</p>
<br /> <br />
<div id="patterns/sets@hexcasting:and"> <div id="patterns/sets@hexcasting:and">
<h4 class="pattern-title">Conjunction Distillation ((num, num)|(list, list) → num|list)<a <h4 class="pattern-title">Conjunction Distillation ((num, num)|(list, list) → num|list)<a
@ -5943,7 +5943,12 @@
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h3> ><i class="bi bi-link-45deg"></i></a></h3>
<h4 class="pattern-title">Summon Greater Sentinel (vector →)</h4> <div id="patterns/great_spells/greater_sentinel@hexcasting:sentinel/create/great">
<h4 class="pattern-title">Summon Greater Sentinel (vector →)<a
href="#patterns/great_spells/greater_sentinel@hexcasting:sentinel/create/great"
class="permalink small"
title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4>
<details class="spell-collapsible"> <details class="spell-collapsible">
<summary class="collapse-spell"></summary> <summary class="collapse-spell"></summary>
<canvas <canvas
@ -5956,6 +5961,7 @@
>Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq</canvas> >Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq</canvas>
</details> </details>
<p>Summon a greater version of my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>Sentinel</span></a>. Costs about two <a href='#items/amethyst'><span style='color: #b0b'>Amethyst Dust</span></a>.</p> <p>Summon a greater version of my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>Sentinel</span></a>. Costs about two <a href='#items/amethyst'><span style='color: #b0b'>Amethyst Dust</span></a>.</p>
</div>
<br /> <br />
<p>The stronger <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a>, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> (the mysterious forces of chunkloading notwithstanding).</p> <p>The stronger <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a>, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> (the mysterious forces of chunkloading notwithstanding).</p>
<br /> <br />
@ -9794,9 +9800,9 @@
<p>Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.</p> <p>Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.</p>
</div> </div>
<br /> <br />
<div id="patterns/lists@hexcasting:concat"> <div id="patterns/lists@hexcasting:add">
<h4 class="pattern-title">Additive Distillation (list, list → list)<a <h4 class="pattern-title">Additive Distillation (list, list → list)<a
href="#patterns/lists@hexcasting:concat" href="#patterns/lists@hexcasting:add"
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4> ><i class="bi bi-link-45deg"></i></a></h4>
@ -9854,9 +9860,9 @@
<p>Remove the top of the stack, then push a list containing only that element.</p> <p>Remove the top of the stack, then push a list containing only that element.</p>
</div> </div>
<br /> <br />
<div id="patterns/lists@hexcasting:list_size"> <div id="patterns/lists@hexcasting:abs">
<h4 class="pattern-title">Length Purification (list → num)<a <h4 class="pattern-title">Length Purification (list → num)<a
href="#patterns/lists@hexcasting:list_size" href="#patterns/lists@hexcasting:abs"
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4> ><i class="bi bi-link-45deg"></i></a></h4>
@ -10562,7 +10568,7 @@
<p>Unifies two sets.</p> <p>Unifies two sets.</p>
</div> </div>
<br /> <br />
<p>As such:</p><p class='fake-li'>With two numbers at the top of the stack, combines them into a bitset containing every &#34;on&#34; bit in either bitset.</p><p class='fake-li'>With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to <a href='#patterns/lists@hexcasting:concat'><span style='color: #fc77be'>Combination Distillation</span></a>.</p> <p>As such:</p><p class='fake-li'>With two numbers at the top of the stack, combines them into a bitset containing every &#34;on&#34; bit in either bitset.</p><p class='fake-li'>With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to <a href='#patterns/lists@hexcasting:add'><span style='color: #fc77be'>Combination Distillation</span></a>.</p>
<br /> <br />
<div id="patterns/sets@hexcasting:and"> <div id="patterns/sets@hexcasting:and">
<h4 class="pattern-title">Conjunction Distillation ((num, num)|(list, list) → num|list)<a <h4 class="pattern-title">Conjunction Distillation ((num, num)|(list, list) → num|list)<a
@ -11975,7 +11981,12 @@
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h3> ><i class="bi bi-link-45deg"></i></a></h3>
<h4 class="pattern-title">Summon Greater Sentinel (vector →)</h4> <div id="patterns/great_spells/greater_sentinel@hexcasting:sentinel/create/great">
<h4 class="pattern-title">Summon Greater Sentinel (vector →)<a
href="#patterns/great_spells/greater_sentinel@hexcasting:sentinel/create/great"
class="permalink small"
title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4>
<details class="spell-collapsible"> <details class="spell-collapsible">
<summary class="collapse-spell"></summary> <summary class="collapse-spell"></summary>
<canvas <canvas
@ -11988,6 +11999,7 @@
>Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq</canvas> >Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq</canvas>
</details> </details>
<p>Summon a greater version of my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>Sentinel</span></a>. Costs about two <a href='#items/amethyst'><span style='color: #b0b'>Amethyst Dust</span></a>.</p> <p>Summon a greater version of my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>Sentinel</span></a>. Costs about two <a href='#items/amethyst'><span style='color: #b0b'>Amethyst Dust</span></a>.</p>
</div>
<br /> <br />
<p>The stronger <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a>, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> (the mysterious forces of chunkloading notwithstanding).</p> <p>The stronger <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a>, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> (the mysterious forces of chunkloading notwithstanding).</p>
<br /> <br />
@ -15828,9 +15840,9 @@
<p>Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.</p> <p>Remove the iota on the end of the list at the top of the stack, and add it to the top of the stack.</p>
</div> </div>
<br /> <br />
<div id="patterns/lists@hexcasting:concat"> <div id="patterns/lists@hexcasting:add">
<h4 class="pattern-title">Additive Distillation (list, list → list)<a <h4 class="pattern-title">Additive Distillation (list, list → list)<a
href="#patterns/lists@hexcasting:concat" href="#patterns/lists@hexcasting:add"
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4> ><i class="bi bi-link-45deg"></i></a></h4>
@ -15888,9 +15900,9 @@
<p>Remove the top of the stack, then push a list containing only that element.</p> <p>Remove the top of the stack, then push a list containing only that element.</p>
</div> </div>
<br /> <br />
<div id="patterns/lists@hexcasting:list_size"> <div id="patterns/lists@hexcasting:abs">
<h4 class="pattern-title">Length Purification (list → num)<a <h4 class="pattern-title">Length Purification (list → num)<a
href="#patterns/lists@hexcasting:list_size" href="#patterns/lists@hexcasting:abs"
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4> ><i class="bi bi-link-45deg"></i></a></h4>
@ -16596,7 +16608,7 @@
<p>Unifies two sets.</p> <p>Unifies two sets.</p>
</div> </div>
<br /> <br />
<p>As such:</p><p class='fake-li'>With two numbers at the top of the stack, combines them into a bitset containing every &#34;on&#34; bit in either bitset.</p><p class='fake-li'>With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to <a href='#patterns/lists@hexcasting:concat'><span style='color: #fc77be'>Combination Distillation</span></a>.</p> <p>As such:</p><p class='fake-li'>With two numbers at the top of the stack, combines them into a bitset containing every &#34;on&#34; bit in either bitset.</p><p class='fake-li'>With two lists, this creates a list of every element from the first list, plus every element from the second list that is not in the first list. This is similar to <a href='#patterns/lists@hexcasting:add'><span style='color: #fc77be'>Combination Distillation</span></a>.</p>
<br /> <br />
<div id="patterns/sets@hexcasting:and"> <div id="patterns/sets@hexcasting:and">
<h4 class="pattern-title">Conjunction Distillation ((num, num)|(list, list) → num|list)<a <h4 class="pattern-title">Conjunction Distillation ((num, num)|(list, list) → num|list)<a
@ -18009,7 +18021,12 @@
class="permalink small" class="permalink small"
title="Permalink" title="Permalink"
><i class="bi bi-link-45deg"></i></a></h3> ><i class="bi bi-link-45deg"></i></a></h3>
<h4 class="pattern-title">Summon Greater Sentinel (vector →)</h4> <div id="patterns/great_spells/greater_sentinel@hexcasting:sentinel/create/great">
<h4 class="pattern-title">Summon Greater Sentinel (vector →)<a
href="#patterns/great_spells/greater_sentinel@hexcasting:sentinel/create/great"
class="permalink small"
title="Permalink"
><i class="bi bi-link-45deg"></i></a></h4>
<details class="spell-collapsible"> <details class="spell-collapsible">
<summary class="collapse-spell"></summary> <summary class="collapse-spell"></summary>
<canvas <canvas
@ -18022,6 +18039,7 @@
>Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq</canvas> >Your browser does not support visualizing patterns. Pattern code: waeawaeqqqwqwqqwq</canvas>
</details> </details>
<p>Summon a greater version of my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>Sentinel</span></a>. Costs about two <a href='#items/amethyst'><span style='color: #b0b'>Amethyst Dust</span></a>.</p> <p>Summon a greater version of my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>Sentinel</span></a>. Costs about two <a href='#items/amethyst'><span style='color: #b0b'>Amethyst Dust</span></a>.</p>
</div>
<br /> <br />
<p>The stronger <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a>, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> (the mysterious forces of chunkloading notwithstanding).</p> <p>The stronger <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> acts like the normal one I can summon without the use of a Great Spell, if a little more visually interesting. However, the range in which my spells can work is extended to a small region around my greater <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a>, about 16 blocks. In other words, no matter where in the world I am, I can interact with things around my <a href='#patterns/spells/sentinels'><span style='color: #8d6acc'>sentinel</span></a> (the mysterious forces of chunkloading notwithstanding).</p>
<br /> <br />