Skip to content
Open
Changes from 13 commits
Commits
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
108 changes: 108 additions & 0 deletions core/src/main/java/com/nisovin/magicspells/spells/buff/ProxySpell.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.nisovin.magicspells.spells.buff;

import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Collection;

import org.jetbrains.annotations.NotNull;

import org.bukkit.event.EventHandler;
import org.bukkit.entity.LivingEntity;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;

import com.nisovin.magicspells.util.SpellData;
import com.nisovin.magicspells.spells.BuffSpell;
import com.nisovin.magicspells.util.MagicConfig;
import com.nisovin.magicspells.events.SpellTargetEvent;
import com.nisovin.magicspells.spelleffects.EffectPosition;

public class ProxySpell extends BuffSpell {

private final Set<UUID> redirecting = new HashSet<>();
private final Map<UUID, LivingEntity> proxies = new HashMap<>();

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

@Override
public boolean castBuff(SpellData data) {
if (data.target().equals(data.caster())) return false;
proxies.put(data.target().getUniqueId(), data.caster());
return true;
}

@Override
public boolean recastBuff(SpellData data) {
stopEffects(data.target());
Comment thread
DragonsAscent marked this conversation as resolved.
turnOffBuff(data.target());
return castBuff(data);
}

@Override
public boolean isActive(LivingEntity entity) {
return proxies.containsKey(entity.getUniqueId());
}

@Override
public void turnOffBuff(LivingEntity entity) {
proxies.remove(entity.getUniqueId());
}

@Override
protected @NotNull Collection<UUID> getActiveEntities() {
return proxies.keySet();
}

@EventHandler(ignoreCancelled = true)
public void onSpellTarget(SpellTargetEvent event) {
LivingEntity target = event.getTarget();
if (target == null || !isActive(target)) return;

LivingEntity proxyTarget = getProxyTarget(target);
if (proxyTarget == null) return;

event.setTarget(proxyTarget);
Comment thread
JasperLorelai marked this conversation as resolved.
playRedirectEffects(target, proxyTarget, event.getSpellData());

addUseAndChargeCost(target);
}

@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onEntityDamage(EntityDamageByEntityEvent event) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the proxy receive damage from events not dealt by another entity?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel like it should be a config option

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, idk. The only purpose the damager has in this handler atm is that it's used for the spell effects. So imo, if a proxy receives any damage, it should be relayed, even if it wasn't caused by a third entity.

if (!(event.getEntity() instanceof LivingEntity target) || !isActive(target)) return;

LivingEntity proxyTarget = getProxyTarget(target);
if (proxyTarget == null) return;
if (!redirecting.add(proxyTarget.getUniqueId())) return;

SpellData subData = new SpellData(event.getDamager() instanceof LivingEntity damager ? damager : null, proxyTarget);
playRedirectEffects(target, proxyTarget, subData);

event.setCancelled(true);
try {
proxyTarget.damage(event.getDamage(), event.getDamageSource());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not actually sure if the causing/direct entity should be swapped here as well.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your PR description says:

Allows the caster to designate an entity as a "proxy". Any spell / damage will be redirected to the caster treating that entity as if it were the caster themself.

If the ending bit is a typo, meant to be "target", then this can be left alone.

Otherwise, if you implied that the proxy should become the caster of these spells, the original caster forgotten, then the causing entity should be swapped, but the SpellTargetEvent is missing the caster swap too. Imo, the original caster/damager should remain.

Comment thread
DragonsAscent marked this conversation as resolved.
Outdated
addUseAndChargeCost(target);
} finally {
redirecting.remove(proxyTarget.getUniqueId());
}
}

private LivingEntity getProxyTarget(LivingEntity target) {
LivingEntity proxyTarget = proxies.get(target.getUniqueId());
if (proxyTarget != null && proxyTarget.isValid()) return proxyTarget;

turnOff(target);
return null;
}

private void playRedirectEffects(LivingEntity target, LivingEntity proxyTarget, SpellData data) {
playSpellEffects(EffectPosition.START_POSITION, target, data);
playSpellEffects(EffectPosition.END_POSITION, proxyTarget, data);
}

}
Loading