Iron's Spells

KubeJS Iron's Spells is an addon that allows for creating custom spells, spell schools, and listening to Iron's Spells events like ChangeManaEvent and SpellCastEvent.

#Custom Spells

If you change the properties of a spell between restarts, you'll need to regenerate the Iron's Spells server config by deleting it and joining the world again.
Example script:
// Spell registry goes in the startup_scripts folder

StartupEvents.registry('irons_spellbooks:spells', event => {
		.setCastTime(60)                           // Sets the cast time
		.setCooldownSeconds(10)                    // Sets the cooldown in seconds
		.setManaCostPerLevel(20)                   // Sets the mana cost per level
		.setCastType('continuous')                 // Sets the cast type
		.setSchool('irons_spellbooks:blood')       // Sets the school
		.setMinRarity('epic')                      // Sets the minimal rarity
		.setMaxLevel(2)                            // Sets the maximum level
		.setStartSound('item.honey_bottle.drink')  // Sets the start sound
		.setFinishSound('item.honey_bottle.drink') // Sets the finish sound
		.onCast(ctx => global.bloodfed(ctx))       // Calls global.bloodfed when the spell is casted
		// Other methods like these also exist:
		// .onClientCast(ctx => {})
		// .onPreCast(ctx => {})
		// .onPreClientCast(ctx => {})
		// .setAllowLooting(true)
		// .needsLearning(false)
		// .canBeCraftedBy(player => true)
		// .setUniqueInfo([Component.translatable("ui.irons_spellbooks.damage", "3"), Component.of("test")])

// The functions for certain methods with callbacks like onCast can go in a global variable if you want it to be reloadable by using /kubejs reload startup_scripts
global.bloodfed = (/** @type {Internal.CustomSpell$CastContext} */ ctx) => {
	let /** @type {Internal.ServerPlayer} */ player = ctx.entity
	if ((player.getFoodData().getFoodLevel() * (ctx.getSpellLevel() / 2)) < 2
	|| !ctx.entity.isPlayer()) return
	player.heal(ctx.getSpellLevel() / 2)
	player.getFoodData().setFoodLevel(player.getFoodData().getFoodLevel() - 2 * (ctx.getSpellLevel() / 2))

#Listening to Iron's Spells Events

// These go in server_scripts

PlayerEvents.changeMana(event => {
	// This makes it so that casting any spell consumes only 10 mana 
	if (event.getMagicData().getCastSource() != 'SPELLBOOK') return
	event.setNewMana(event.getOldMana() - 10)

// There is also spellPreCast, which is cancelable
PlayerEvents.spellOnCast(event => {
	// Casting any spell kills the player who casted it

#Creating Spell Schools

This feature may be a little difficult to understand. If you need help, you can always ask in the support channel in the Discord.
To create a spell school, you'll first need to create two attributes for spell power and spell resistance.
// This goes in startup_scripts

// We create an object within the global object so that we can store the attributes inside.
global.attributes = {}

StartupEvents.registry("attribute", event => {
	// Use the `spell` type for these attributes and set all the values needed. The default value has to be higher than the minimum value and lower than the maximum value.
	global.attributes.TEST_SPELL_POWER = event.create("test_spell_power", "irons_spells_js:spell").setDefaultValue(1.0).setMinimumValue(0.0).setMaximumValue(10.0)
	global.attributes.TEST_SPELL_RESISTANCE = event.create("test_spell_resistance", "irons_spells_js:spell").setDefaultValue(1.0).setMinimumValue(0.0).setMaximumValue(10.0)
Then, in the next few lines, you need to apply these attributes to entities by listening to the mod bus event EntityAttributeModificationEvent.
// You can listen to mod bus events by using `ForgeModEvents.onEvent`, and then inputting the event class.
ForgeModEvents.onEvent("net.minecraftforge.event.entity.EntityAttributeModificationEvent", event => {
	// Here, we loop through all the entity types and add both attributes to each and every one of them. 
	// This makes sure that every entity that has magic capabilities can use these attributes.
	event.types.forEach(type => {
		event.add(type, global.attributes.TEST_SPELL_POWER.get())
		event.add(type, global.attributes.TEST_SPELL_RESISTANCE.get())
Finally, we need to register the school.
StartupEvents.registry("irons_spellbooks:schools", event => {
	// This creates a school named `Test` with the ID `kubejs:test`.
	// You can use the ID of this school in any spell you create, or to change the school of an existing spell using the Iron's Spells server config.
		.setName(Component.of("Test").aqua()) // This sets what the school will be displayed as. This needs to be a Component.
		.setFocus("kubejs:test_focus") // The focus needs to be an item tag. You can add this same tag to an item to make it the focus.
		.setPowerAttribute("kubejs:test_spell_power") // This sets the power attribute.
		.setResistanceAttribute("kubejs:test_spell_resistance") // This sets the resistance attribute.
		.setDefaultCastSound('minecraft:entity.chicken.death') // You can also set a default cast sound for each spell in the school.
		// In 1.20.1 and up, creating spell schools requires a damage type to be inputted.
		// You can create a damage type using datapacks.
		// .setDamageType('kubejs:test_spell_damage_type')

#Custom Spell Books, Staves, and Magic Swords

// These all go in startup scripts
StartupEvents.registry("item", event => {
	// Other item methods also work on these builders. It is recommended to give the spell books the proper Curios item tag for them to work properly.
	// (that being "curios:spellbook")

	//This just creates a basic spell book with nothing special to it. It is given 3 spell slots as defined.
    	event.create("test_spellbook", "irons_spells_js:spellbook")

	// You can add attributes to the spell book, including custom attributes.
	// This spell book is given 8 total spell slots and two attributes.
    	event.create("test_attribute_spellbook", "irons_spells_js:spellbook")
        	.addDefaultAttribute("kubejs:test_spell_power", "Test Spell Power", 2.0, "multiply_total")
        	.addDefaultAttribute("minecraft:generic.movement_speed", "Test Movement Speed", 1.2, "multiply_total")

	// If you give a spell book default spells, it is converted to a Unique spell book. 
	// This spell book has been given two extra attributes and a single default spell, being Firebolt at level 1.
    	event.create("test_unique_spellbook", "irons_spells_js:spellbook")
        	.addDefaultAttribute("kubejs:test_spell_power", "Test Spell Power", 2.0, "multiply_total")
        	.addDefaultAttribute("minecraft:generic.movement_speed", "Test Movement Speed", 1.2, "multiply_total")
        	.addDefaultSpell(SpellRegistry.FIREBOLT_SPELL, 1)

	// You can create custom staves too, and give them additional custom attributes.
	// This staff deals 50 base damage and gives the user 200% more spell power for the school Test, shown in a previous example.
    	event.create("test_staff", "irons_spells_js:staff")
        	.addAdditionalAttribute("kubejs:test_spell_power", "Test Spell Power", 2.0, "multiply_total")

	// Along with custom staves, you can also create custom magic swords that come with default spells.
	// This sword deals 100 damage, has 3 attack speed, and has two pre-inscribed spells, being Firebolt and Blood Slash.
    	event.create("test_magic_sword", "irons_spells_js:magic_sword")
        	.addAdditionalAttribute("kubejs:test_spell_power", "Test Spell Power", 2.0, "multiply_total")
        	.addDefaultSpell(SpellRegistry.FIREBOLT_SPELL, 1)
        	.addDefaultSpell(SpellRegistry.BLOOD_SLASH_SPELL, 2)

	// Also, you don't need to use a registry object for spells. You can input a string as the spell ID and it works just fine as well. 
    	event.create("test_magic_sword_2", "irons_spells_js:magic_sword")
        	.addAdditionalAttribute("kubejs:test_spell_power", "Test Spell Power", 2.0, "multiply_total")
        	.addDefaultSpell("irons_spellbooks:starfall", 1)
        	.addDefaultSpell("irons_spellbooks:planar_sight", 2)