Buff redirection, pathfinding, and branching projectiles#1075
Buff redirection, pathfinding, and branching projectiles#1075DragonsAscent wants to merge 7 commits intoTheComputerGeek2:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds several new gameplay mechanics to the MagicSpells core: a targeted pathfinding spell, a branching projectile instant spell, a proxy/redirect buff spell, and a scoreboard-based cast modifier condition.
Changes:
- Added
PathfindSpellwith a 3D A* path search and per-node subspell/effect execution. - Added
BranchingProjectileSpellto simulate a projectile that can spawn branching sub-projectiles and cast a subspell on nearby hit entities. - Added
ProxySpellto redirect spell targeting/pre-impact and damage events from a protected entity to a proxy entity, plusScoreConditionfor scoreboard objective comparisons.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| core/src/main/java/com/nisovin/magicspells/spells/targeted/PathfindSpell.java | New targeted spell implementing A* pathfinding and traversal filtering. |
| core/src/main/java/com/nisovin/magicspells/spells/instant/BranchingProjectileSpell.java | New instant spell that advances a projectile over time and spawns branch tasks probabilistically. |
| core/src/main/java/com/nisovin/magicspells/spells/buff/ProxySpell.java | New buff spell that redirects spell target/pre-impact and damage from one entity to another. |
| core/src/main/java/com/nisovin/magicspells/castmodifiers/conditions/ScoreCondition.java | New cast condition that compares a target’s scoreboard score against a configured value/operator. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
core/src/main/java/com/nisovin/magicspells/spells/instant/BranchingProjectileSpell.java
Outdated
Show resolved
Hide resolved
| public CastResult cast(SpellData data) { | ||
| Location start = data.caster().getEyeLocation(); | ||
| Vector direction = start.getDirection().normalize(); | ||
| double maxDist = maxDistance.get(data); | ||
| int maxTicks = maxDuration.get(data); | ||
| new BranchTask(start, direction, maxDist, maxTicks, data, 0, false).runTaskTimer(MagicSpells.plugin, 0, 1); | ||
| return new CastResult(PostCastAction.HANDLE_NORMALLY, data); |
There was a problem hiding this comment.
cast dereferences data.caster() without checking data.hasCaster(). Many spells in this codebase guard against null casters (e.g., ProjectileSpell/ParticleProjectileSpell); please add the same guard (and return ALREADY_HANDLED/noTarget as appropriate) to avoid NPEs when the spell is triggered without a caster (subcasts/console/etc.).
| // Branching | ||
| if (!isBranch && Math.random() < branchProbability.get(data)) { | ||
| Vector branchDir = getBranchDirection(direction, branchAngle.get(data)); | ||
| new BranchTask(current.clone(), branchDir, maxDist, maxTicks, data, branchDepth + 1, true).runTaskTimer(MagicSpells.plugin, 0, 1); | ||
| } |
There was a problem hiding this comment.
Branching currently has no cap: the trunk can spawn a new BranchTask every tick while the random check passes, and branchDepth is incremented but never used to limit recursion/branch count. This can create many scheduled tasks and cause server lag; consider adding a configurable max branch count/depth (or ensure only one branch can spawn per trunk) and either remove or use branchDepth.
core/src/main/java/com/nisovin/magicspells/spells/targeted/PathfindSpell.java
Outdated
Show resolved
Hide resolved
| for (int dy = -1; dy <= 2; dy++) { | ||
| int y = by + dy; | ||
| if (y < world.getMinHeight() || y > world.getMaxHeight()) continue; | ||
|
|
||
| Block feetBlock = world.getBlockAt(bx, y, bz); | ||
| if (isWalkable(feetBlock, throughBlocks)) { | ||
| return new Location(world, feetBlock.getX() + 0.5, feetBlock.getY(), feetBlock.getZ() + 0.5); |
There was a problem hiding this comment.
World Y upper bound check is off by one: valid block Y coordinates are < world.getMaxHeight(). The current y > world.getMaxHeight() allows y == getMaxHeight() which can produce out-of-range block queries. Use y >= world.getMaxHeight() instead.
core/src/main/java/com/nisovin/magicspells/castmodifiers/conditions/ScoreCondition.java
Outdated
Show resolved
Hide resolved
…chingProjectileSpell.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…tions/ScoreCondition.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…hfindSpell.java Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
|
Built artifact: |
Branching Projectile Spell:
BranchingProjectileSpell, a new instant spell that creates a main projectile which can randomly branch into additional projectiles. The spell supports configurable parameters such as maximum distance, duration, branching probability, angles, and spell effects on hit entities. This allows for complex, visually dynamic spell effects with hit detection and subspell casting. (core/src/main/java/com/nisovin/magicspells/spells/instant/BranchingProjectileSpell.java)Proxy Spell:
ProxySpell, a new buff spell that allows redirection of spell effects and damage from one entity to another (the proxy). It manages active proxies, handles spell target and damage events, and ensures effects and costs are properly redirected. This enables advanced spell interactions such as decoys or bodyguard mechanics. (core/src/main/java/com/nisovin/magicspells/spells/buff/ProxySpell.java)Score Modifier:
ScoreCondition, a new cast modifier condition that checks a player's score in a specified scoreboard objective (core/src/main/java/com/nisovin/magicspells/castmodifiers/conditions/ScoreCondition.java)