Skip to content

Commit

Permalink
Merge pull request #64 from enjarai/need-branch-for-this-methinks
Browse files Browse the repository at this point in the history
Mana system overhaul
  • Loading branch information
enjarai authored Nov 12, 2024
2 parents acd5421 + 2480756 commit 4431530
Show file tree
Hide file tree
Showing 339 changed files with 6,309 additions and 2,895 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ replay_*.log
.direnv/

# wiki

wiki/

# idk something

.factorypath
45 changes: 44 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1,44 @@
- Undid Sodium compat changes temporarily due to a crash on world load. (@enjarai)
- Redesigned the mana system significantly, making mana a semi-limited resource. (@enjarai and @StellarWitch7)
- Players and entities no longer have mana pools.
- Bloodcasting is no longer possible.
- Instead, mana is contained in items called Knots.
- These gemstones encased in glass orbs hold a certain amount of mana based on their rarity.
- Some Knot types may have unique properties that manipulate mana in special ways.
- Most Knots can be passively recharged under moonlight.
- Knots charge most strongly under a new or full moon, but may not charge at all on some phases inbetween.
- Mana over time is now measured in Merlins.
- `Merlins = Gandalfs / Tick`
- Many trick costs have been rebalanced to accommodate these changes.
- Multiple tricks have also been added to automatically move mana around between knots.
- Introduced Spell Constructs. (@enjarai and @StellarWitch7)
- These artificial spellcasting devices directly replace in-world spell circles, which have been removed.
- Spell Constructs do not have an up-front mana cost, but must be crafted instead.
- Once crafted, a spell can be inscribed onto the Construct.
- When placed in the world, this spell will be cast persistently until completion.
- If a mana source is required, a Knot may be inserted into the Construct.
- Also introduced Modular Spell Constructs. (@enjarai and @StellarWitch7)
- These variations of the normal Construct contain four slots for Spell Cores.
- Instead of casting a spell directly, Cores must be inserted containing the spells to be cast.
- All inserted spells will be cast and run concurrently.
- All cores share the same crowmind and mana pool from the provided knot.
- Multiple tricks have been added to delegate to and manipulate other cores on the same Construct.
- This allows for practical and persistent multithreaded spell design.
- Added Macros. (@Master-Bw3, @enjarai, and @StellarWitch7)
- A list of Macros may be defined by inscribing a map of patterns to spells onto a common ring.
- When wearing this ring, any pattern defined in the map can be drawn while spell-scribing to invoke the corresponding spell.
- The given spell will be cast and given the circle the pattern was drawn in as an argument.
- The spell may then construct a new circle using meta-programming to replace the given one.
- A few changes were made to support this.
- Any fragment can now be inscribed onto an item, not just spells.
- Map fragments were added.
- Wards and the Closure Stratagem have been tweaked to make use of this.
- Pattern literals were added.
- Removed shadow blocks. (@StellarWitch7)
- This feature has been moved to a separate addon mod due to Sodium incompatibilities.
- Added internal caching for pure tricks. (@StellarWitch7)
- Significantly increased viable spell depth, making it effectively™ infinite. (@StellarWitch7)
- Impulse cost scaling now accounts for multiple casts within the same tick. (@StellarWitch7)
- As a consequence, tricks may now internally attach arbitrary data to a spell which persists for the remaining executions in the current tick.
- Added a trick to guarantee a spell's full execution within a single tick. (@StellarWitch7)
- Fixed a couple things which appeared to cause incompatibility with Connector. (@unilock)
- Might not be everything, given #64 changed a lot.
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,36 +25,35 @@ Spells can do literally anything you can imagine*!
<sub>*Assumes your imagination is limited by the scope of available glyphs.
Library inc. takes no responsibility for overactive imagination or other forms of undue creativity.</sub>

![A persistent multi-core spell construct](https://i.enjarai.dev/u/pRQrnj.png)

## That's a pretty bold statement isnt it?

Yes it is, but we don't think its unfounded.

For one, spells will not stop casting until they are complete, which can, in fact, be never!
Spells run concurrently with the rest of the game and can be saved to and loaded from disk at any moment, just like everything else in Minecraft. This means you can leave a spell running, log out, come back two days later, and have it continue where you left off.

Secondly, spells can be infinitely* big and complex. While there *is* a limit to the speed spells execute at (to avoid straining the server) the spell itself can be as convoluted or as simple as you want!
Secondly, spells can be infinitely big and complex. While there *is* a limit to the speed spells execute at (to avoid straining the server) the spell itself can be as convoluted or as simple as you want!

And last but not least, while mana is a resource required by all world-altering effects, it is possible to theoretically infinitely scale the amount of mana available to you. Mana is intended more as a balancing measure than a limiter on your potential.

<sub>*Spell circles can't quite be infinitely nested yet due to recursion limitations at extreme depth, we plan to resolve this issue in the near future.</sub>

## So how do I begin?

Well, we've made that part pretty easy.

All glyphs, tricks, and ways of spell-scribing are neatly documented in the Tome of Tomfoolery™,
the go-to guide for being up to no good. Making use of the excellent [Lavender](https://modrinth.com/mod/lavender),
the go-to guide for being up to no good.
Making use of the excellent [Lavender](https://modrinth.com/mod/lavender) and fully custom interactive widgets,
the Tome™ provides a state-of-the-art guidebook experience for all of your magical needs.

![Documentation](https://i.enjarai.dev/u/Edmujx.png)
![Documentation](https://i.enjarai.dev/u/OmfF44.png)

## What else can I expect?

As any good magic mod should, we provide a handful of tools and trinkets to facilitate spellcasting.
As any good magic mod should, we provide a solid selection of tools and trinkets to facilitate spellcasting.

For example, the Top Hat can hold a bunch of spell scrolls and easily select any of them for quick access:

![Spellcasting from a hat](https://i.enjarai.dev/u/MBojDM.png)
![A few of the available toys](https://i.enjarai.dev/u/UghuSY.png)

## Functional as in Functional Programming

Expand All @@ -70,6 +69,9 @@ This combines with other functional paradigms to create a very clean, but powerf

## Credits

Many of the item textures are courtesy of @midnightcartridge on Discord.
Some of the item textures are courtesy of @midnightcartridge on Discord.

Thanks to @crephan as well for help with a bunch of item textures and models.

Thanks to @crephan as well for help with the Top Hat model.
This mod was originally made for [Modfest: Carnival](https://modfest.net/carnival),
but has since been further developed far beyond its original scope.
42 changes: 39 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ loom {
mods {
"trickster" {
sourceSet sourceSets.main
sourceSet sourceSets.client
sourceSet sourceSets.client
}
}

Expand Down Expand Up @@ -98,14 +98,15 @@ dependencies {
include "io.wispforest:owo-sentinel:${property('deps.owo-lib')}"

modApi "io.wispforest:lavender:${property('deps.lavender')}"
// implementation "io.wispforest:endec:0.1.0-pre.8"
// implementation "io.wispforest:endec:0.1.0-pre.8"
include modLocalRuntime("io.wispforest.lavender-md:owo-ui:0.1.2+1.21")

modApi("nl.enjarai:cicada-lib:${property('deps.cicada')}")

include modApi("org.ladysnake.cardinal-components-api:cardinal-components-base:${property('deps.cardinal-components-api')}")
include modApi("org.ladysnake.cardinal-components-api:cardinal-components-chunk:${property('deps.cardinal-components-api')}")
include modApi("org.ladysnake.cardinal-components-api:cardinal-components-world:${property('deps.cardinal-components-api')}")
include modApi("org.ladysnake.cardinal-components-api:cardinal-components-scoreboard:${property('deps.cardinal-components-api')}")
include modApi("org.ladysnake.cardinal-components-api:cardinal-components-entity:${property('deps.cardinal-components-api')}")

modCompileOnly modLocalRuntime("com.terraformersmc:modmenu:${property('deps.modmenu')}")
Expand Down Expand Up @@ -179,7 +180,7 @@ publishMods {
displayName = "${property('mod_version')} for ${property('deps.minecraft')}"
version = project.version
changelog = getRootProject().file("CHANGELOG.md").text
type = ALPHA
type = BETA
modLoaders.add("fabric")

def min = property('publish_target_min')
Expand Down Expand Up @@ -220,6 +221,41 @@ publishMods {
}
}

if (providers.gradleProperty('enjaraiCurseforgeToken').present) {
curseforge {
projectId = property('mod_curseforge')
accessToken = providers.gradleProperty('enjaraiCurseforgeToken').get()

if (min == max) {
minecraftVersions.add(min)
} else {
minecraftVersionRange {
start = min
end = max
}
}

requires {
slug = "fabric-api"
}
requires {
slug = "cicada"
}
requires {
slug = "owo-lib"
}
requires {
slug = "lavender"
}
requires {
slug = "accessories"
}
embeds {
slug = "cardinal-components-api"
}
}
}

if (providers.gradleProperty('enjaraiGithubToken').present) {
github {
repository = property('mod_github')
Expand Down
60 changes: 1 addition & 59 deletions debug.sh
Original file line number Diff line number Diff line change
@@ -1,61 +1,3 @@
#!/usr/bin/env bash

# thanks to https://github.com/Pathoschild/SMAPI/blob/ab34b6142dcd04e629012a1c30d37bc9c7e5df5e/src/SMAPI.Installer/assets/unix-launcher.sh#L95-L147
run() {
COMMAND="./gradlew runClient --debug-jvm"

# select terminal (prefer xterm for best compatibility, then known supported terminals)
for terminal in xterm gnome-terminal kitty terminator xfce4-terminal konsole terminal termite alacritty mate-terminal x-terminal-emulator; do
if command -v "$terminal" 2>/dev/null; then
export TERMINAL_NAME=$terminal
break;
fi
done

# find the true shell behind x-terminal-emulator
if [ "$TERMINAL_NAME" = "x-terminal-emulator" ]; then
TERMINAL_NAME="$(basename "$(readlink -f "$(command -v x-terminal-emulator)")")"
export TERMINAL_NAME
fi

# run in selected terminal and account for quirks
TERMINAL_PATH="$(command -v "$TERMINAL_NAME")"
export TERMINAL_PATH
if [ -x "$TERMINAL_PATH" ]; then
case $TERMINAL_NAME in
terminal|termite)
# consumes only one argument after -e
# options containing space characters are unsupported
"$TERMINAL_NAME" -e "$COMMAND" 1>/dev/null 2>&1 &
;;

xterm|konsole|alacritty)
# consumes all arguments after -e
"$TERMINAL_NAME" -e $COMMAND 1>/dev/null 2>&1 &
;;

terminator|xfce4-terminal|mate-terminal)
# consumes all arguments after -x
"$TERMINAL_NAME" -x $COMMAND 1>/dev/null 2>&1 &
;;

gnome-terminal)
# consumes all arguments after --
"$TERMINAL_NAME" -- $COMMAND 1>/dev/null 2>&1 &
;;

kitty)
# consumes all trailing arguments
"$TERMINAL_NAME" $COMMAND 1>/dev/null 2>&1 &
;;

*)
exit -1
esac
else
exit -1
fi
}

run
read -p "Press ENTER to debug" && jdb -attach 5005
./gradlew "$@" --debug-jvm
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ deps.yarn=1.21+build.2
loader_version=0.15.11

# Mod Properties
mod_version=2.0.0-alpha.39
mod_version=2.0.0-beta.1
maven_group=dev.enjarai
archives_base_name=trickster

publish_target_min=1.21
publish_target_max=1.21.1
mod_modrinth=ZdEfcqro
mod_curseforge=1137971
mod_github=enjarai/trickster
git_branch=master

Expand Down
Binary file added img/icon_x640.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 44 additions & 37 deletions src/client/java/dev/enjarai/trickster/TricksterClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,52 +33,59 @@
import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;

public class TricksterClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ScrollAndQuillItem.screenOpener = (text, hand) -> {
MinecraftClient.getInstance().setScreen(new SignScrollScreen(text, hand));
};
public static final MerlinKeeperTracker merlinKeeperTracker = new MerlinKeeperTracker(5);

FleckRenderer.register();
FragmentRenderer.register();
@Override
public void onInitializeClient() {
ScrollAndQuillItem.screenOpener = (text, hand) -> {
MinecraftClient.getInstance().setScreen(new SignScrollScreen(text, hand));
};

ModHandledScreens.register();
ModKeyBindings.register();
ModClientNetworking.register();
FleckRenderer.register();
FragmentRenderer.register();

BlockEntityRendererFactories.register(ModBlocks.SPELL_CIRCLE_ENTITY, SpellCircleBlockEntityRenderer::new);
BlockEntityRendererFactories.register(ModBlocks.SCROLL_SHELF_ENTITY, ScrollShelfBlockEntityRenderer::new);
ModHandledScreens.register();
ModKeyBindings.register();
ModClientNetworking.register();

UIParsing.registerFactory(Trickster.id("glyph"), GlyphComponent::parseTrick);
UIParsing.registerFactory(Trickster.id("pattern"), GlyphComponent::parseList);
UIParsing.registerFactory(Trickster.id("spell-preview"), SpellPreviewComponent::parse);
UIParsing.registerFactory(Trickster.id("item-tag"), ItemTagComponent::parse);
BlockEntityRendererFactories.register(ModBlocks.SPELL_CONSTRUCT_ENTITY, SpellConstructBlockEntityRenderer::new);
BlockEntityRendererFactories.register(ModBlocks.MODULAR_SPELL_CONSTRUCT_ENTITY, ModularSpellConstructBlockEntityRenderer::new);
BlockEntityRendererFactories.register(ModBlocks.SCROLL_SHELF_ENTITY, ScrollShelfBlockEntityRenderer::new);

ParticleFactoryRegistry.getInstance().register(ModParticles.PROTECTED_BLOCK, ProtectedBlockParticle.Factory::new);
ParticleFactoryRegistry.getInstance().register(ModParticles.SPELL, SpellParticle.Factory::new);
UIParsing.registerFactory(Trickster.id("glyph"), GlyphComponent::parseTrick);
UIParsing.registerFactory(Trickster.id("pattern"), GlyphComponent::parseList);
UIParsing.registerFactory(Trickster.id("spell-preview"), SpellPreviewComponent::parse);
UIParsing.registerFactory(Trickster.id("item-tag"), ItemTagComponent::parse);

AccessoriesRendererRegistry.registerRenderer(ModItems.TOP_HAT, HoldableHatRenderer::new);
AccessoriesRendererRegistry.registerRenderer(ModItems.WITCH_HAT, HoldableHatRenderer::new);
AccessoriesRendererRegistry.registerRenderer(ModItems.FEZ, HoldableHatRenderer::new);
AccessoriesRendererRegistry.registerNoRenderer(ModItems.MACRO_RING);
ParticleFactoryRegistry.getInstance().register(ModParticles.PROTECTED_BLOCK, ProtectedBlockParticle.Factory::new);
ParticleFactoryRegistry.getInstance().register(ModParticles.SPELL, SpellParticle.Factory::new);

BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.SPELL_RESONATOR, RenderLayer.getCutout());
AccessoriesRendererRegistry.registerRenderer(ModItems.TOP_HAT, HoldableHatRenderer::new);
AccessoriesRendererRegistry.registerRenderer(ModItems.WITCH_HAT, HoldableHatRenderer::new);
AccessoriesRendererRegistry.registerRenderer(ModItems.FEZ, HoldableHatRenderer::new);
AccessoriesRendererRegistry.registerNoRenderer(ModItems.MACRO_RING);

ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (client.player != null) {
var editing = client.currentScreen instanceof ScrollAndQuillScreen;
var serverEditing = ModEntityComponents.IS_EDITING_SCROLL.get(client.player).isEditing();
if (editing != serverEditing) {
ModNetworking.CHANNEL.clientHandle().send(new IsEditingScrollPacket(editing));
}
}
});
BlockRenderLayerMap.INSTANCE.putBlock(ModBlocks.SPELL_RESONATOR, RenderLayer.getCutout());

WorldRenderEvents.AFTER_ENTITIES.register(FlecksRenderer::render);
ClientTickEvents.END_CLIENT_TICK.register(client -> {
if (client.player != null) {
var editing = client.currentScreen instanceof ScrollAndQuillScreen;
var serverEditing = ModEntityComponents.IS_EDITING_SCROLL.get(client.player).isEditing();
if (editing != serverEditing) {
ModNetworking.CHANNEL.clientHandle().send(new IsEditingScrollPacket(editing));
}
}
});
ClientTickEvents.END_CLIENT_TICK.register(merlinKeeperTracker::tick);

HudRenderCallback.EVENT.register(BarsRenderer::render);
HudRenderCallback.EVENT.register(CircleErrorRenderer::render);
Trickster.merlinTooltipAppender = merlinKeeperTracker::appendTooltip;

EntityModelLayerRegistry.registerModelLayer(ScrollShelfBlockEntityRenderer.MODEL_LAYER, ScrollShelfBlockEntityRenderer::getTexturedModelData);
}
WorldRenderEvents.AFTER_ENTITIES.register(FlecksRenderer::render);

HudRenderCallback.EVENT.register(BarsRenderer::render);
HudRenderCallback.EVENT.register(SpellConstructErrorRenderer::render);

EntityModelLayerRegistry.registerModelLayer(ScrollShelfBlockEntityRenderer.MODEL_LAYER, ScrollShelfBlockEntityRenderer::getTexturedModelData);
EntityModelLayerRegistry.registerModelLayer(ModularSpellConstructBlockEntityRenderer.MODEL_LAYER, ModularSpellConstructBlockEntityRenderer::getTexturedModelData);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.enjarai.trickster.mixin.client;

import dev.enjarai.trickster.Trickster;
import dev.enjarai.trickster.render.ModularSpellConstructBlockEntityRenderer;
import dev.enjarai.trickster.render.ScrollShelfBlockEntityRenderer;
import net.minecraft.client.render.model.BakedModelManager;
import net.minecraft.util.Identifier;
Expand Down Expand Up @@ -28,5 +29,6 @@ public class BakedModelManagerMixin {
private static void appendToAtlases(CallbackInfo ci) {
LAYERS_TO_LOADERS = new HashMap<>(LAYERS_TO_LOADERS);
LAYERS_TO_LOADERS.put(ScrollShelfBlockEntityRenderer.ATLAS_ID, Trickster.id("scroll_shelf"));
LAYERS_TO_LOADERS.put(ModularSpellConstructBlockEntityRenderer.ATLAS_ID, Trickster.id("modular_spell_construct"));
}
}
Loading

0 comments on commit 4431530

Please sign in to comment.