Skip to content
JasperLorelai edited this page Mar 17, 2024 · 15 revisions

Description:

On this page, we will document how to add custom spells, modifier conditions, passive listeners, etc. to MagicSpells.

Jump to a section:

Adding the dependency

MagicSpells uses JitPack as its repository service. You can find guides on how to add MagicSpells as a dependency for your build environment here or use the examples below.

Gradle:

repositories {
    maven {url "https://jitpack.io"}
}

dependencies {
    implementation("com.github.TheComputerGeek2.MagicSpells:core:main-SNAPSHOT") {transitive = false}
}

Maven:

<repository>
    <id>jitpack-repo</id>
    <url>https://jitpack.io</url>
</repository>
<dependency>
    <groupId>com.github.TheComputerGeek2.MagicSpells</groupId>
    <artifactId>core</artifactId>
    <version>main-SNAPSHOT</version>
    <exclusions>
        <exclusion>
            <groupId>*</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Custom Spells:

  • Custom spell classes can be placed in the root folder of the plugin or in any folder in the root starting with "classes".
  • MagicSpells load custom spell classes if a spell uses the classified path in its spell-class property. If the spell is in the com.nisovin.magicspells.spells package, it may be left out (e.g. spell-class: ".MultiSpell").
  • All you have to do is to extend either the Spell, CommandSpell, InstantSpell, TargetedSpell, or BuffSpell classes.
  • TargetedSpell classes may implement the following interfaces: TargetedEntitySpell, TargetedEntityFromLocationSpell, or TargetedLocationSpell.
  • Since Beta 14. Spells may be annotated with @DependsOn which contains a plugin or an array of them which the spell class will depend on being enabled before being loaded.
This example displays a basic instant spell.
package com.example.instant;

import org.bukkit.entity.LivingEntity;

import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.spells.InstantSpell;
import com.nisovin.magicspells.spelleffects.EffectPosition;

public class HelloWorldSpell extends InstantSpell {

	public HelloWorldSpell(MagicConfig config, String spellName) {
		super(config, spellName);
	}

	@Override
	public PostCastAction castSpell(LivingEntity caster, SpellCastState state, float power, String[] args) {
		if (state == SpellCastState.NORMAL) {
			caster.sendMessage("Hello World!");
                        // We should always play the correct effects in the spell.
			playSpellEffects(EffectPosition.CASTER, caster);
		}
		return PostCastAction.HANDLE_NORMALLY;
	}

}
hello_world:
    spell-class: "com.example.instant.HelloWorldSpell"
This example displays a basic targeted spell, and how to handle targets and spell effects in targeted spells.
package com.example.targeted;

import org.bukkit.entity.LivingEntity;

import com.nisovin.magicspells.util.TargetInfo;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.spells.TargetedSpell;
import com.nisovin.magicspells.spells.TargetedEntitySpell;
import com.nisovin.magicspells.spelleffects.EffectPosition;

public class HelloWorldSpell extends TargetedSpell implements TargetedEntitySpell {

	public HelloWorldSpell(MagicConfig config, String spellName) {
		super(config, spellName);
	}

	@Override
	public PostCastAction castSpell(LivingEntity caster, SpellCastState state, float power, String[] args) {
		if (state == SpellCastState.NORMAL) {
			TargetInfo<LivingEntity> targetInfo = getTargetedEntity(caster, power);
			if (targetInfo == null) return noTarget(caster);
			LivingEntity target = targetInfo.getTarget();
			hello(caster, target);
			sendMessages(caster, target);
			return PostCastAction.NO_MESSAGES;
		}
		return PostCastAction.HANDLE_NORMALLY;
	}

	@Override
	public boolean castAtEntity(LivingEntity caster, LivingEntity target, float power) {
		return hello(caster, target);
	}

	@Override
	public boolean castAtEntity(LivingEntity target, float power) {
		return hello(null, target);
	}

	private boolean hello(LivingEntity caster, LivingEntity target) {
		target.sendMessage("Hello World!");
		if (caster == null) playSpellEffects(EffectPosition.TARGET, target);
		else playSpellEffects(caster, target);
		return true;
	}

}
hello_world_targeted:
    spell-class: "com.example.targeted.HelloWorldSpell"
This example includes configuration reading.
package com.example.instant;

import org.bukkit.entity.Player;
import org.bukkit.entity.LivingEntity;

import com.nisovin.magicspells.util.Util;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.spells.InstantSpell;

public class RollDiceSpell extends InstantSpell {

	private int min;
	private int max;
	private final String strMessage;

	public RollDiceSpell(MagicConfig config, String spellName) {
		super(config, spellName);
		min = getConfigInt("min", 0);
		max = getConfigInt("max", 10);
		strMessage = getConfigString("message", "Dice: ");
	}

	@Override
	public PostCastAction castSpell(LivingEntity livingEntity, SpellCastState state, float power, String[] args) {
		// Here we are dealing with a spell that only works for Player casters.
		if (state == SpellCastState.NORMAL && livingEntity instanceof Player caster) {
			// We're using Util methods not to create duplicate code.
			int random = min + Util.getRandomInt(max - min + 1);
			caster.sendMessage(strMessage + random);
		}
		return PostCastAction.HANDLE_NORMALLY;
	}

}
roll_dice:
    spell-class: "com.example.instant.RollDiceSpell"
    min: 0
    max: 100
    message: "You rolled: "

Other managers:

  • This section includes the creation of custom modifier conditions, passive listeners, variables, and spell effects.
  • If you would like to add these features, you can use the API from your custom plugin. However, if you don't want to add a separate plugin, you could utilise a custom spell class to achieve this.
  • If you are using a custom plugin to load these modules, you could use this resource to load these classes more simply. It could also serve as an example of what follows. The plugin must "soft depend" on "MagicSpells".
  • You have to create an event handler for the module you want to add, then add it through its manager there. The events are: ConditionsLoadingEvent, PassiveListenersLoadingEvent, VariablesLoadingEvent, and SpellEffectsLoadingEvent. You can fetch the specific manager from static methods in the MagicSpells class or from the event getters. Each of these managers includes a method to add the module you want.
@EventHandler
public void onConditionLoad(ConditionsLoadingEvent event) {
  MagicSpells.getConditionManager().addCondition("always", AlwaysCondition.class);
}
  • NOTE: Since Beta 14:
    • You can annotate your class with @DependsOn, passing a plugin or an array of plugins required to be enabled before this addon is loaded.
    • You can alternatively annotate your custom class with @Name and add calling the add method without the name parameter.
@Name("always")
public class AlwaysCondition extends Condition { . . . }
. . .
@EventHandler
public void onConditionLoad(ConditionsLoadingEvent event) {
	MagicSpells.getConditionManager().addCondition(AlwaysCondition.class);
}

Custom No Magic Zone types:

A class extending NoMagicZone can be added to the no magic zone type list like this:

@EventHandler
public void onMSLoading(MagicSpellsLoadingEvent event) {
	MagicSpells.getNoMagicZoneManager().addZoneType("cuboid", NoMagicZoneCuboid.class);
}

Since Beta 14 the class may be annotated with @DependsOn listing required plugins that need to be loaded before the zone is and with the @Name annotation holding its name instead of it being passed by the add method:

@Name("cuboid")
public class NoMagicZoneCuboid extends NoMagicZone { . . . }
. . .
@EventHandler
public void onMSLoading(MagicSpellsLoadingEvent event) {
	MagicSpells.getNoMagicZoneManager().addZoneType(NoMagicZoneCuboid.class);
}

Custom Cleansers:

Warning

Since Beta 14.

Registering custom cleansers for the Cleanse Spell to list under its remove option is possible. You can find some examples of how to implement a cleanser here.

import com.nisovin.magicspells.spells.targeted.cleanse.util.Cleansers;
. . .
Cleansers.addCleanserClass(/* <Class which extends Cleanser>*/);

Clone this wiki locally