Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
27c0683
Restored June 4th/5th Mystic Branch spells, Witch Hand abilities, Por…
brianjcc2-stack Jun 6, 2026
cf5d2ca
Restored missing Mystic Branch spells (Glacius, Petrificus Totalus, E…
brianjcc2-stack Jun 6, 2026
be65fbc
Checkpoint: spells, Witch Hand, Portkey, rites work + build tooling
brianjcc2-stack Jun 6, 2026
f65dbdf
feat: implement new brewing potions, ritual patterns, and magical eff…
brianjcc2-stack Jun 6, 2026
2fe133c
refactor: improve particle effects, fix player sync logic, and add sa…
brianjcc2-stack Jun 6, 2026
f35abd0
feat: add colored aura telegraphs for prepared spells and improve UI …
brianjcc2-stack Jun 6, 2026
9523203
feat: announce spell casting to all players in server chat and remove…
brianjcc2-stack Jun 6, 2026
125c989
Refactor strokes and merge redundant spells
brianjcc2-stack Jun 6, 2026
6631b20
fix: add null checks for MovingObjectPosition in effect registry and …
brianjcc2-stack Jun 7, 2026
649c5d3
feat: add new brewing effects, potions, and registry entries with upd…
brianjcc2-stack Jun 7, 2026
ee88970
feat: expand block removal list and add blindness/invisibility effect…
brianjcc2-stack Jun 7, 2026
12e383f
refactor: resolve spell stroke prefix conflicts and add Lumos toggle …
brianjcc2-stack Jun 7, 2026
c295485
fix: synchronize glow globe world placement and removal with player i…
brianjcc2-stack Jun 8, 2026
2c4c984
feat: add ritual localization entries and automate language file patc…
brianjcc2-stack Jun 18, 2026
ff43de1
feat: add witcherylevel command for managing player attributes and re…
brianjcc2-stack Jun 19, 2026
ec44dc6
feat: implement astral projection state and add fire-starting functio…
brianjcc2-stack Jun 19, 2026
f1ff1b3
feat: add spirit shapeshift transformation, energy maintenance for as…
brianjcc2-stack Jun 19, 2026
390f3b5
feat: implement spell blocking with Mystic Branch and add Imperio and…
brianjcc2-stack Jun 20, 2026
9640e3c
refactor: remove redundant code blocks and cleanup event logic in Com…
brianjcc2-stack Jun 20, 2026
9d16922
refactor: overhaul Leviosa mechanics and improve infusion energy/clea…
brianjcc2-stack Jun 20, 2026
7bb18d7
feat: add CommandHobgoblin and PotionSpellPower, and refactor Brazier…
brianjcc2-stack Jun 20, 2026
50446c4
refactor: replace Spell Power potion mechanic with coven-based castin…
brianjcc2-stack Jun 21, 2026
46d72e5
feat: implement Unbreakable Vow mechanics for health, damage, and pot…
brianjcc2-stack Jun 22, 2026
b867e0e
fix: update Mystic Branch check to use held item instead of item in use
brianjcc2-stack Jun 22, 2026
afaadba
refactor: implement task-based AI for goblin following and sitting an…
brianjcc2-stack Jun 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .arsmagica2_temp
Submodule .arsmagica2_temp added at 6d6b68
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ Desktop.ini
$RECYCLE.BIN/
.DS_Store
/fb/

# Local toolchain (do not commit)
/gradle-4.4.1/
/gradle-4.4.1-bin.zip
/zulu8.94.0.17-ca-jdk8.0.492-macosx_aarch64/
/zulu8.94.0.17-ca-jdk8.0.492-macosx_aarch64.tar.gz
/.arsmagica2_temp/
36 changes: 6 additions & 30 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ buildscript {
mavenCentral()
maven {
name = "forge"
url = "http://files.minecraftforge.net/maven"
url = "https://maven.minecraftforge.net/"
}
maven {
name = "sonatype"
url = "https://oss.sonatype.org/content/repositories/snapshots/"
name = "anatawa12"
url = "https://maven.anatawa12.com/"
}
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT'
classpath 'com.anatawa12.forge:ForgeGradle:1.2-1.0.+'
}
}

Expand All @@ -35,40 +35,16 @@ minecraft {

repositories {
mavenLocal()
maven {
name = "ic2"
url = "http://maven.ic2.player.to/"
}
ivy {
name "BuildCraft"
artifactPattern "http://www.mod-buildcraft.com/releases/BuildCraft/[revision]/[module]-[revision]-[classifier].[ext]"
}
maven {
name = "chickenbones"
url = "http://chickenbones.net/maven/"
}
maven{
name "tterrag Repo"
url "http://maven.tterrag.com/"
}
maven {
url "http://jcenter.bintray.com"
url "https://jcenter.bintray.com"
}
maven {
name 'Forge'
url 'http://files.minecraftforge.net/maven'
}
maven {
name "Mobius Repo"
url "http://mobiusstrip.eu/maven/"
}
maven {
name = "K4 maven"
url = "http://maven.k-4u.nl/"
}
maven {
name "FireBall API Depot"
url "http://dl.tsr.me/artifactory/libs-release-local"
url 'https://maven.minecraftforge.net/'
}
}

Expand Down
63 changes: 63 additions & 0 deletions find_prefixes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import re
import sys

def parse_strokesets(filepath):
with open(filepath, 'r') as f:
content = f.read()

# Find all SymbolEffect additions.
# We will look for new StrokeSet(..., new byte[]{...})
strokes = []

# Regex to match new StrokeSet(level, new byte[]{(byte)X, (byte)Y, ...})
# We want to keep track of the spell name if possible, or just the byte arrays.

# Actually, we can just find all new byte[]{(byte)X, ...} inside StrokeSet
matches = re.finditer(r'new\s+StrokeSet\s*\(\s*(\d+)\s*,\s*new\s+byte\s*\[\s*\]\s*\{([^}]+)\}\s*\)', content)

for m in matches:
level = int(m.group(1))
bytes_str = m.group(2)
# Extract numbers
nums = re.findall(r'\d+', bytes_str)
# The first number in each (byte)X is the stroke direction.
# Wait, the regex \d+ will capture the stroke numbers.
# Let's just strip (byte) and spaces.
stroke_list = [int(x.strip()) for x in bytes_str.replace('(byte)', '').split(',')]

strokes.append((m.group(0), stroke_list, m.start(), m.end()))

return strokes

def main():
filepath = sys.argv[1]
strokes = parse_strokesets(filepath)

prefixes = []

for i in range(len(strokes)):
for j in range(len(strokes)):
if i == j:
continue

str1 = strokes[i][1]
str2 = strokes[j][1]

if len(str1) < len(str2):
if str2[:len(str1)] == str1:
prefixes.append((strokes[i], strokes[j]))

# Print out the prefixes to modify.
seen = set()
for p1, p2 in prefixes:
# We only need to modify p1 (the shorter one) to make it not a prefix, OR p2.
# The user wants them unique. Usually changing the last stroke of the shorter one,
# or just adding a stroke to the shorter one.
# Actually we should just print them out.
if tuple(p1[1]) not in seen:
print(f"Prefix: {p1[1]} (Found in {p1[0]})")
print(f" Is prefix of: {p2[1]}")
seen.add(tuple(p1[1]))

if __name__ == "__main__":
main()
17 changes: 17 additions & 0 deletions fix_mop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import re

file_path = "/Users/brianchirinos/Documents/WitcheryRepo/src/main/java/com/emoniph/witchery/infusion/infusions/symbols/EffectRegistry.java"

with open(file_path, "r") as f:
content = f.read()

# Pattern 1: if (mop.typeOfHit -> if (mop != null && mop.typeOfHit
content = re.sub(r'if \(\s*mop\.typeOfHit', 'if (mop != null && mop.typeOfHit', content)
content = re.sub(r'else if \(\s*mop\.typeOfHit', 'else if (mop != null && mop.typeOfHit', content)

# Pattern 2: int cx = mop.typeOfHit == -> if (mop == null) return; int cx = mop.typeOfHit ==
content = re.sub(r'(int cx = mop\.typeOfHit == MovingObjectPosition\.MovingObjectType\.BLOCK \? mop\.blockX : \(int\)spell\.posX;)', r'if (mop == null) return;\n \1', content)

with open(file_path, "w") as f:
f.write(content)
print("Done")
73 changes: 73 additions & 0 deletions make_unique.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import re
import sys

def make_unique(filepath):
with open(filepath, 'r') as f:
content = f.read()

# Find all StrokeSets
matches = list(re.finditer(r'new\s+StrokeSet\s*\(\s*(\d+)\s*,\s*new\s+byte\s*\[\s*\]\s*\{([^}]+)\}\s*\)', content))

strokes = []
for m in matches:
level = int(m.group(1))
bytes_str = m.group(2)
stroke_list = [int(x.strip()) for x in bytes_str.replace('(byte)', '').split(',')]
strokes.append((m, stroke_list))

prefixes = set()

for i in range(len(strokes)):
for j in range(len(strokes)):
if i == j: continue
str1 = strokes[i][1]
str2 = strokes[j][1]

if len(str1) < len(str2):
if str2[:len(str1)] == str1:
prefixes.add(i)

# We will modify the shorter strokes by appending one stroke to them.
# We will append `(byte)3` (which is typically 'Left') or something else if it creates another conflict.
# Let's just append `(byte)X` where X is the opposite of the next byte in the longer spell,
# but actually just appending a byte is fine as long as we check if it conflicts.

all_stroke_tuples = {tuple(s[1]) for s in strokes}

replacements = []
for idx in prefixes:
m, s = strokes[idx]

# Try appending 0, 1, 2, 3 until we find one that is not a prefix of anything, and doesn't exist.
for candidate in [0, 1, 2, 3]:
new_stroke = s + [candidate]
# check if new_stroke is a prefix of any other
is_prefix = False
for j in range(len(strokes)):
if idx == j: continue
s2 = strokes[j][1]
if len(new_stroke) <= len(s2) and s2[:len(new_stroke)] == new_stroke:
is_prefix = True
break

if not is_prefix and tuple(new_stroke) not in all_stroke_tuples:
replacements.append((m, new_stroke))
all_stroke_tuples.add(tuple(new_stroke))
all_stroke_tuples.remove(tuple(s))
break

# Now we apply replacements in reverse order of match position to not mess up offsets.
replacements.sort(key=lambda x: x[0].start(), reverse=True)

for m, new_stroke in replacements:
bytes_str = ",".join(f"(byte){b}" for b in new_stroke)
replacement_str = f"new StrokeSet({m.group(1)}, new byte[]{{{bytes_str}}})"
content = content[:m.start()] + replacement_str + content[m.end():]

with open(filepath, 'w') as f:
f.write(content)

print(f"Made {len(replacements)} strokes unique.")

if __name__ == "__main__":
make_unique(sys.argv[1])
31 changes: 31 additions & 0 deletions patch_lang.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import re

with open('src/main/resources/assets/witchery/lang/en_US.lang', 'r') as f:
content = f.read()

new_rituals_list = """[br]> [url=ritualreparo Reparo][br]> [url=ritualidentify Identify][br]> [url=ritualaparecium Aparecium][br]> [url=ritualvociferador Vociferador][br]> [url=rituallumosmaxima Lumos Maxima][br]> [url=ritualdimensionalanchor Dimensional Anchor][br]> [url=ritualempaticlink Empatic Link][br]> [url=ritualherbivicus Herbivicus][br]> [url=ritualmagicalprison Magical Prison]"""

content = content.replace(
"[br]> [url=ritualfind Find Structure]",
"[br]> [url=ritualfind Find Structure]" + new_rituals_list
)

new_rituals_text = """
witchery:cauldronbook.ritualreparo=[h1 Ritual: Reparo]Repair damaged items. Draw a line of 5 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Diamond and Spectral Dust.
witchery:cauldronbook.ritualidentify=[h1 Ritual: Identify]Identify an unknown item. Draw a polygon of 4 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop an Eye of Ender and Exhale of the Horned One.
witchery:cauldronbook.ritualaparecium=[h1 Ritual: Aparecium]Reveal hidden things. Draw a polygon of 3 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Golden Carrot and Tear of the Goddess.
witchery:cauldronbook.ritualvociferador=[h1 Ritual: Vociferador]Create a howler. Draw a line of 5 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Jukebox and Mandrake Root.
witchery:cauldronbook.rituallumosmaxima=[h1 Ritual: Lumos Maxima]Create a powerful light. Draw a polygon of 5 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop Glowstone Dust and Breath of the Goddess.
witchery:cauldronbook.ritualdimensionalanchor=[h1 Ritual: Dimensional Anchor]Anchor a dimension. Draw a polygon of 5 red chalk:[br][img=witchery:textures/gui/circles_tinyred.png|center|top|32|32][br]Drop an Ender Pearl, Obsidian, and Charged Attuned Stone.
witchery:cauldronbook.ritualempaticlink=[h1 Ritual: Empatic Link]Create an empathic link. Draw a polygon of 6 infernal chalk:[br][img=witchery:textures/gui/circles_tinyinfernal.png|center|top|32|32][br]Drop a Golden Apple, Drop of Luck, and Brew of Love.
witchery:cauldronbook.ritualherbivicus=[h1 Ritual: Herbivicus]Accelerate plant growth. Draw a polygon of 4 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop Bonemeal and Mutandis Extremis.
witchery:cauldronbook.ritualmagicalprison=[h1 Ritual: Magical Prison]Trap an entity. Draw a polygon of 4 red chalk:[br][img=witchery:textures/gui/circles_tinyred.png|center|top|32|32][br]Drop a Web and Soul Sand.
"""

content = content.replace(
"witchery:cauldronbook.ritualfind=[h1 Ritual: Find Structure]Summon a spirit that flys towards the closest village (or nether fortress). Draw a 3x3 white-chalk circle:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Subdued Spirit or Attuned Stone in the center and wait.",
"witchery:cauldronbook.ritualfind=[h1 Ritual: Find Structure]Summon a spirit that flys towards the closest village (or nether fortress). Draw a 3x3 white-chalk circle:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Subdued Spirit or Attuned Stone in the center and wait." + new_rituals_text
)

with open('src/main/resources/assets/witchery/lang/en_US.lang', 'w') as f:
f.write(content)
23 changes: 23 additions & 0 deletions patch_lang_text.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import re

with open('src/main/resources/assets/witchery/lang/en_US.lang', 'r') as f:
content = f.read()

new_rituals_text = """
witchery:cauldronbook.ritualreparo=[h1 Ritual: Reparo]Repair damaged items. Draw a line of 5 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Diamond and Spectral Dust.
witchery:cauldronbook.ritualidentify=[h1 Ritual: Identify]Identify an unknown item. Draw a polygon of 4 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop an Eye of Ender and Exhale of the Horned One.
witchery:cauldronbook.ritualaparecium=[h1 Ritual: Aparecium]Reveal hidden things. Draw a polygon of 3 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Golden Carrot and Tear of the Goddess.
witchery:cauldronbook.ritualvociferador=[h1 Ritual: Vociferador]Create a howler. Draw a line of 5 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Jukebox and Mandrake Root.
witchery:cauldronbook.rituallumosmaxima=[h1 Ritual: Lumos Maxima]Create a powerful light. Draw a polygon of 5 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop Glowstone Dust and Breath of the Goddess.
witchery:cauldronbook.ritualdimensionalanchor=[h1 Ritual: Dimensional Anchor]Anchor a dimension. Draw a polygon of 5 otherwhere chalk:[br][img=witchery:textures/gui/circles_tinyred.png|center|top|32|32][br]Drop an Ender Pearl, Obsidian, and Charged Attuned Stone.
witchery:cauldronbook.ritualempaticlink=[h1 Ritual: Empatic Link]Create an empathic link. Draw a polygon of 6 infernal chalk:[br][img=witchery:textures/gui/circles_tinyinfernal.png|center|top|32|32][br]Drop a Golden Apple, Drop of Luck, and Brew of Love.
witchery:cauldronbook.ritualherbivicus=[h1 Ritual: Herbivicus]Accelerate plant growth. Draw a polygon of 4 white chalk:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Dye and Mutandis Extremis.
witchery:cauldronbook.ritualmagicalprison=[h1 Ritual: Magical Prison]Trap an entity. Draw a polygon of 4 otherwhere chalk:[br][img=witchery:textures/gui/circles_tinyred.png|center|top|32|32][br]Drop a Web and Soul Sand.
"""

target = "witchery:cauldronbook.ritualfind=[h1 Ritual: Find Structure]Summon a spirit that flys towards the closest village (or nether fortress). Draw a 3x3 white-chalk circle:[br][img=witchery:textures/gui/circles_tinywhite.png|center|top|32|32][br]Drop a Subdued Spirit or Attuned Stone in the center and wait."

content = content.replace(target, target + new_rituals_text)

with open('src/main/resources/assets/witchery/lang/en_US.lang', 'w') as f:
f.write(content)
6 changes: 6 additions & 0 deletions src/main/java/com/emoniph/witchery/Witchery.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import com.emoniph.witchery.client.KeyboardHandler;
import com.emoniph.witchery.client.PlayerRender;
import com.emoniph.witchery.common.ChantCommand;
import com.emoniph.witchery.common.CommandWitcheryLevel;
import com.emoniph.witchery.common.CommonProxy;
import com.emoniph.witchery.common.PowerSources;
import com.emoniph.witchery.common.ServerTickEvents;
Expand Down Expand Up @@ -280,6 +281,11 @@ public void postInit(FMLPostInitializationEvent event) {
@EventHandler
public void serverLoad(FMLServerStartingEvent event) {
event.registerServerCommand(new ChantCommand());
event.registerServerCommand(new CommandWitcheryLevel());
event.registerServerCommand(new com.emoniph.witchery.commands.CommandImperio());
event.registerServerCommand(new com.emoniph.witchery.commands.CommandHobgoblin());
event.registerServerCommand(new com.emoniph.witchery.commands.CommandPet());
event.registerServerCommand(new com.emoniph.witchery.commands.CommandCrucio());
PowerSources.initiate();
BlockAreaMarker.AreaMarkerRegistry.serverStart();
worldGenerator.initiate();
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/com/emoniph/witchery/WitcheryBlocks.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.emoniph.witchery.blocks.BlockDreamCatcher;
import com.emoniph.witchery.blocks.BlockEmberMoss;
import com.emoniph.witchery.blocks.BlockFetish;
import com.emoniph.witchery.blocks.BlockFlooFire;
import com.emoniph.witchery.blocks.BlockFlowingSpirit;
import com.emoniph.witchery.blocks.BlockForce;
import com.emoniph.witchery.blocks.BlockFumeFunnel;
Expand Down Expand Up @@ -211,6 +212,7 @@ public final class WitcheryBlocks {
public final Block GLYPH_RITUAL;
public final Block GLYPH_OTHERWHERE;
public final Block GLYPH_INFERNAL;
public final Block FLOO_FIRE;
public final Block FLOWING_SPIRIT;
public final Block HOLLOW_TEARS;
public final Block DISEASE;
Expand Down Expand Up @@ -306,6 +308,7 @@ public WitcheryBlocks() {
this.GLYPH_RITUAL = (new BlockCircleGlyph(0, false)).setBlockName("witchery:circleglyphritual").setBlockTextureName("witchery:circleglyph");
this.GLYPH_OTHERWHERE = (new BlockCircleGlyph(1, false)).setBlockName("witchery:circleglyphotherwhere").setBlockTextureName("witchery:circleglyph");
this.GLYPH_INFERNAL = (new BlockCircleGlyph(2, false)).setBlockName("witchery:circleglyphinfernal").setBlockTextureName("witchery:circleglyph");
this.FLOO_FIRE = (new BlockFlooFire()).setBlockName("witchery:floofire");
this.FLOWING_SPIRIT = (new BlockFlowingSpirit(Witchery.Fluids.FLOWING_SPIRIT, new PotionEffect(Potion.regeneration.id, 100, 1), new PotionEffect(Potion.weakness.id, 300, 1), true, true)).setBlockName("witchery:spiritflowing").setBlockTextureName("witchery:flowspirit");
this.HOLLOW_TEARS = (new BlockFlowingSpirit(Witchery.Fluids.HOLLOW_TEARS, new PotionEffect(Potion.weakness.id, 100, 1), new PotionEffect(Potion.regeneration.id, 100, 1), false, false)).setBlockName("witchery:hollowtears").setBlockTextureName("witchery:tears");
this.DISEASE = (new BlockDisease(Witchery.Fluids.DISEASE)).setBlockName("witchery:disease").setBlockTextureName("witchery:disease");
Expand Down
Loading