Skip to content

Commit

Permalink
Health Trait will now respawn NPCs who have entered the void. Note: T…
Browse files Browse the repository at this point in the history
…he default 'respawn location' will not suffice since it picks the location of death. Instead, make a flag or constant with a 'home location' and use /npc health --respawnlocation <npc.flag[home]> (or something similar).
  • Loading branch information
aufdemrand committed Jul 15, 2013
1 parent 4a95390 commit dfa4a01
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 78 deletions.
15 changes: 11 additions & 4 deletions src/main/java/net/aufdemrand/denizen/npc/dNPCRegistry.java
Expand Up @@ -3,6 +3,7 @@
import net.aufdemrand.denizen.Denizen;
import net.aufdemrand.denizen.objects.dNPC;
import net.aufdemrand.denizen.npc.actions.ActionHandler;
import net.aufdemrand.denizen.scripts.containers.core.WorldScriptHelper;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.utilities.debugging.dB;
import net.citizensnpcs.api.event.NPCDespawnEvent;
Expand All @@ -13,10 +14,7 @@
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
Expand Down Expand Up @@ -114,12 +112,21 @@ else if (npc.getValue().isSpawned())
@EventHandler
public void onSpawn(NPCSpawnEvent event) {
_registerNPC(event.getNPC());
// Do world script event 'On NPC Completes Navigation'
WorldScriptHelper.doEvents(Arrays.asList
("npc spawns"),
dNPC.mirrorCitizensNPC(event.getNPC()), null, null).toUpperCase();
// On Spawn action
plugin.getNPCRegistry().getDenizen(event.getNPC()).action("spawn", null);
}

@EventHandler
public void despawn(NPCDespawnEvent event) {
// Do world script event 'On NPC Completes Navigation'
WorldScriptHelper.doEvents(Arrays.asList
("npc despawns"),
dNPC.mirrorCitizensNPC(event.getNPC()), null, null).toUpperCase();

plugin.getNPCRegistry().getDenizen(event.getNPC()).action("despawn", null);
}

Expand Down
152 changes: 78 additions & 74 deletions src/main/java/net/aufdemrand/denizen/npc/traits/HealthTrait.java
@@ -1,11 +1,10 @@
package net.aufdemrand.denizen.npc.traits;

import net.aufdemrand.denizen.Settings;
import net.aufdemrand.denizen.objects.dPlayer;
import net.aufdemrand.denizen.objects.*;
import net.aufdemrand.denizen.tags.TagManager;
import net.aufdemrand.denizen.utilities.DenizenAPI;
import net.aufdemrand.denizen.objects.Duration;
import net.aufdemrand.denizen.objects.aH;
import net.citizensnpcs.api.event.DespawnReason;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;

Expand All @@ -30,8 +29,6 @@ public class HealthTrait extends Trait implements Listener {

@Persist("animatedeath")
private boolean animatedeath = Settings.HealthTraitAnimatedDeathEnabled();
@Persist("animatedeathdelayinseconds")
private String animationDelay = "3s";

@Persist("respawnondeath")
private boolean respawn = Settings.HealthTraitRespawnEnabled();
Expand All @@ -41,17 +38,14 @@ public class HealthTrait extends Trait implements Listener {
private String respawnLocation = "<npc.location>";

// internal
private dPlayer player = null;
private dPlayer player = null;
private boolean dying = false;
private Location loc;
private int entityId = -1;

public double getAnimationDelay() {
return Duration.valueOf(animationDelay).getSeconds();
}

public double getRespawnDelay() {
return (Duration.valueOf(respawnDelay).getSeconds());
public Duration getRespawnDelay() {
return Duration.valueOf(respawnDelay);
}

public void setRespawnLocation(String string) {
Expand All @@ -73,16 +67,7 @@ public String getRespawnLocationAsString() {
}

public Location getRespawnLocation() {
return aH.getLocationFrom(respawnLocation);
}

public void setDeathAnimationDelay(int seconds) {
animationDelay = String.valueOf(seconds);
}

public void setDeathAnimationDelay(String string) {
if (aH.matchesDuration("duration:" + string))
animationDelay = string;
return dLocation.valueOf(TagManager.tag(null, dNPC.mirrorCitizensNPC(npc), respawnLocation));
}

public void setRespawnable(boolean respawnable) {
Expand All @@ -102,6 +87,7 @@ public boolean animatesOnDeath() {
}


public Integer void_watcher_task = null;

/**
* Listens for spawn of an NPC and updates its health with the max health
Expand All @@ -111,6 +97,24 @@ public boolean animatesOnDeath() {
@Override public void onSpawn() {
dying = false;
setHealth();

void_watcher_task = Bukkit.getScheduler().scheduleSyncRepeatingTask(DenizenAPI.getCurrentInstance(), new Runnable() {
@Override
public void run() {
if (!npc.isSpawned()) {
Bukkit.getScheduler().cancelTask(void_watcher_task);
return;
}
if (npc.getBukkitEntity().getLocation().getY() < -1000) {
npc.despawn(DespawnReason.DEATH);
if (respawn) {
if (npc.isSpawned()) npc.getBukkitEntity().teleport(getRespawnLocation());
else npc.spawn(getRespawnLocation());
}
}
}
}, 200, 200);

}

public HealthTrait() {
Expand All @@ -124,8 +128,8 @@ public HealthTrait() {
*
*/
public double getHealth() {
if (!npc.isSpawned()) return 0;
else return npc.getBukkitEntity().getHealth();
if (!npc.isSpawned()) return 0;
else return npc.getBukkitEntity().getHealth();
}

/**
Expand All @@ -135,7 +139,7 @@ public double getHealth() {
*
*/
public void setMaxhealth(int newMax) {
npc.getBukkitEntity().setMaxHealth(newMax);
npc.getBukkitEntity().setMaxHealth(newMax);
}

/**
Expand All @@ -144,7 +148,7 @@ public void setMaxhealth(int newMax) {
* @return maximum health
*/
public double getMaxhealth() {
return npc.getBukkitEntity().getMaxHealth();
return npc.getBukkitEntity().getMaxHealth();
}

/**
Expand All @@ -161,7 +165,7 @@ public void heal(int health) {
*
*/
public void setHealth() {
setHealth(npc.getBukkitEntity().getMaxHealth());
setHealth(npc.getBukkitEntity().getMaxHealth());
}

/**
Expand All @@ -171,26 +175,26 @@ public void setHealth() {
*/
public void setHealth(double health) {
if (npc.getBukkitEntity() != null)
npc.getBukkitEntity().setHealth(health);
npc.getBukkitEntity().setHealth(health);
}

public void die() {
npc.getBukkitEntity().damage(npc.getBukkitEntity().getHealth());
npc.getBukkitEntity().damage(npc.getBukkitEntity().getHealth());
}

// Listen for deaths to clear drops
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onDeath(EntityDeathEvent event) {
if (event.getEntity().getEntityId() != entityId) return;
event.getDrops().clear();

if (event.getEntity().getEntityId() != entityId) return;

event.getDrops().clear();
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onDamage(EntityDamageEvent event) {
// Don't use NPCDamageEvent because it doesn't work well
// Don't use NPCDamageEvent because it doesn't work well

// Check if the event pertains to this NPC
if (event.getEntity() != npc.getBukkitEntity() || dying) return;

Expand All @@ -200,66 +204,66 @@ public void onDamage(EntityDamageEvent event) {

dying = true;
player = null;

// Save entityId for EntityDeath event
entityId = npc.getBukkitEntity().getEntityId();
String deathCause = event.getCause().toString().toLowerCase().replace('_', ' ');

String deathCause = event.getCause().toString().toLowerCase().replace('_', ' ');

// Check if the entity has been killed by another entity
if (event instanceof EntityDamageByEntityEvent)
{
Entity killerEntity = ((EntityDamageByEntityEvent) event).getDamager();
// Check if the damager was a player and, if so, attach
// that player to the action's ScriptEntry
if (killerEntity instanceof Player)
player = dPlayer.mirrorBukkitPlayer((Player) killerEntity);
// If the damager was a projectile, take its shooter into
// account as well
else if (killerEntity instanceof Projectile)
{
LivingEntity shooter = ((Projectile) killerEntity).getShooter();
if (shooter instanceof Player)
player = dPlayer.mirrorBukkitPlayer((Player) shooter);
DenizenAPI.getDenizenNPC(npc).action("death by " +
shooter.getType().toString(), player);
}
DenizenAPI.getDenizenNPC(npc).action("death by entity", player);
DenizenAPI.getDenizenNPC(npc).action("death by " +
killerEntity.getType().toString(), player);
Entity killerEntity = ((EntityDamageByEntityEvent) event).getDamager();

// Check if the damager was a player and, if so, attach
// that player to the action's ScriptEntry
if (killerEntity instanceof Player)
player = dPlayer.mirrorBukkitPlayer((Player) killerEntity);

// If the damager was a projectile, take its shooter into
// account as well
else if (killerEntity instanceof Projectile)
{
LivingEntity shooter = ((Projectile) killerEntity).getShooter();

if (shooter instanceof Player)
player = dPlayer.mirrorBukkitPlayer((Player) shooter);

DenizenAPI.getDenizenNPC(npc).action("death by " +
shooter.getType().toString(), player);
}

DenizenAPI.getDenizenNPC(npc).action("death by entity", player);
DenizenAPI.getDenizenNPC(npc).action("death by " +
killerEntity.getType().toString(), player);

}
// If not, check if the entity has been killed by a block
else if (event instanceof EntityDamageByBlockEvent)
{
DenizenAPI.getDenizenNPC(npc).action("death by block", player);
DenizenAPI.getDenizenNPC(npc).action("death by block", player);

// TODO:
// The line of code below should work, but a Bukkit bug makes the damager
// return null. Uncomment it once the bug is fixed.
// DenizenAPI.getDenizenNPC(npc).action("death by " +
// ((EntityDamageByBlockEvent) event).getDamager().getType().name(), null);
// The line of code below should work, but a Bukkit bug makes the damager
// return null. Uncomment it once the bug is fixed.

// DenizenAPI.getDenizenNPC(npc).action("death by " +
// ((EntityDamageByBlockEvent) event).getDamager().getType().name(), null);
}

DenizenAPI.getDenizenNPC(npc).action("death", player);
DenizenAPI.getDenizenNPC(npc).action("death by " + deathCause, player);

// One of the actions above may have removed the NPC, so check if the
// NPC's entity still exists before proceeding
if (npc.getBukkitEntity() == null)
return;
return;

loc = aH.getLocationFrom(
TagManager.tag(null, DenizenAPI.getDenizenNPC(npc), respawnLocation, false));

if (loc == null) loc = npc.getBukkitEntity().getLocation();

if (animatedeath) {
// Cancel navigation to keep the NPC from damaging players
// while the death animation is being carried out.
Expand Down

0 comments on commit dfa4a01

Please sign in to comment.