Add heuristic for the THORNS enchantment.

This commit is contained in:
asofold 2013-03-16 04:25:16 +01:00
parent 20b28f950f
commit ab99e871f9
3 changed files with 60 additions and 20 deletions

View File

@ -86,6 +86,10 @@ public class FightData extends ACheckData {
public double lastAttackedX = Integer.MAX_VALUE; public double lastAttackedX = Integer.MAX_VALUE;
public double lastAttackedY; public double lastAttackedY;
public double lastAttackedZ; public double lastAttackedZ;
/** The entity id which might get counter-attacked. */
public int thornsId = Integer.MIN_VALUE;
/** Any kind of health regeneration. */ /** Any kind of health regeneration. */
public long regainHealthTime = 0; public long regainHealthTime = 0;
// public double lastAttackedDist = 0.0; // public double lastAttackedDist = 0.0;

View File

@ -1,6 +1,7 @@
package fr.neatmonster.nocheatplus.checks.fight; package fr.neatmonster.nocheatplus.checks.fight;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -14,6 +15,7 @@ import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
import org.bukkit.event.player.PlayerAnimationEvent; import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerToggleSprintEvent; import org.bukkit.event.player.PlayerToggleSprintEvent;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import fr.neatmonster.nocheatplus.checks.CheckListener; import fr.neatmonster.nocheatplus.checks.CheckListener;
import fr.neatmonster.nocheatplus.checks.CheckType; import fr.neatmonster.nocheatplus.checks.CheckType;
@ -87,7 +89,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
* The EntityDamageByEntityEvent * The EntityDamageByEntityEvent
* @return * @return
*/ */
private boolean handleNormalDamage(final Player player, final Entity damaged) { private boolean handleNormalDamage(final Player player, final Entity damaged, int damage) {
final FightConfig cc = FightConfig.getConfig(player); final FightConfig cc = FightConfig.getConfig(player);
final FightData data = FightData.getData(player); final FightData data = FightData.getData(player);
@ -136,9 +138,10 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
if (cc.debug && damagedPlayer.hasPermission(Permissions.ADMINISTRATION_DEBUG)){ if (cc.debug && damagedPlayer.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
damagedPlayer.sendMessage("Attacked by " + player.getName() + ": inv=" + mcAccess.getInvulnerableTicks(damagedPlayer) + " ndt=" + damagedPlayer.getNoDamageTicks()); damagedPlayer.sendMessage("Attacked by " + player.getName() + ": inv=" + mcAccess.getInvulnerableTicks(damagedPlayer) + " ndt=" + damagedPlayer.getNoDamageTicks());
} }
if (selfHit.isEnabled(player) && selfHit.check(player, damagedPlayer, data, cc)) if (selfHit.isEnabled(player) && selfHit.check(player, damagedPlayer, data, cc)) {
cancelled = true; cancelled = true;
} }
}
if (cc.cancelDead){ if (cc.cancelDead){
if (damaged.isDead()) cancelled = true; if (damaged.isDead()) cancelled = true;
@ -148,7 +151,15 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
} }
} }
if (data.thornsId == damaged.getEntityId() && damage <= 4 && tick == data.damageTakenByEntityTick){
// Don't handle further, but do respect selfhit/canceldead.
data.thornsId = Integer.MIN_VALUE;
System.out.println("*** SKIP THORNS: " + player.getName());
return cancelled;
}
else {
data.thornsId = Integer.MIN_VALUE;
}
// Run through the main checks. // Run through the main checks.
if (!cancelled && speed.isEnabled(player)){ if (!cancelled && speed.isEnabled(player)){
@ -227,6 +238,23 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
return cancelled; return cancelled;
} }
/**
* Check if a player might return some damage due to the "thorns" enchantment.
* @param player
* @return
*/
public static final boolean hasThorns(final Player player){
final PlayerInventory inv = player.getInventory();
final ItemStack[] contents = inv.getArmorContents();
for (int i = 0; i < contents.length; i++){
final ItemStack stack = contents[i];
if (stack != null && stack.getEnchantmentLevel(Enchantment.THORNS) > 0){
return true;
}
}
return false;
}
/** /**
* We listen to EntityDamage events for obvious reasons. * We listen to EntityDamage events for obvious reasons.
* *
@ -245,38 +273,48 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
*/ */
final Entity damaged = event.getEntity(); final Entity damaged = event.getEntity();
final boolean damagedIsPlayer = damaged instanceof Player; final Player damagedPlayer = damaged instanceof Player ? (Player) damaged : null;
final FightData damagedData = damagedPlayer == null ? null : FightData.getData(damagedPlayer);
final boolean damagedIsDead = damaged.isDead(); final boolean damagedIsDead = damaged.isDead();
if (damagedIsPlayer && !damagedIsDead) { if (damagedPlayer != null && !damagedIsDead) {
final Player player = (Player) event.getEntity();
// if (godMode.isEnabled(player) && godMode.check(player)){ // if (godMode.isEnabled(player) && godMode.check(player)){
if (!player.isDead() && godMode.isEnabled(player) && godMode.check(player, event.getDamage())){ if (!damagedPlayer.isDead() && godMode.isEnabled(damagedPlayer) && godMode.check(damagedPlayer, event.getDamage(), damagedData)){
// It requested to "cancel" the players invulnerability, so set his noDamageTicks to 0. // It requested to "cancel" the players invulnerability, so set his noDamageTicks to 0.
player.setNoDamageTicks(0); damagedPlayer.setNoDamageTicks(0);
} }
if (player.getHealth() == player.getMaxHealth()){ if (damagedPlayer.getHealth() == damagedPlayer.getMaxHealth()){
final FightData data = FightData.getData(player);
// TODO: Might use the same FightData instance for GodMode. // TODO: Might use the same FightData instance for GodMode.
if (data.fastHealBuffer < 0){ if (damagedData.fastHealBuffer < 0){
// Reduce negative buffer with each full health. // Reduce negative buffer with each full health.
data.fastHealBuffer /= 2; damagedData.fastHealBuffer /= 2;
} }
// Set reference time. // Set reference time.
data.fastHealRefTime = System.currentTimeMillis(); damagedData.fastHealRefTime = System.currentTimeMillis();
} }
} }
// Attacking entities. // Attacking entities.
if (event instanceof EntityDamageByEntityEvent) { if (event instanceof EntityDamageByEntityEvent) {
final EntityDamageByEntityEvent e = (EntityDamageByEntityEvent) event; final EntityDamageByEntityEvent e = (EntityDamageByEntityEvent) event;
if (damagedIsPlayer && !damagedIsDead){
// TODO: check once more when to set this (!) in terms of order.
FightData.getData((Player) damaged).damageTakenByEntityTick = TickTask.getTick();
}
final Entity damager = e.getDamager(); final Entity damager = e.getDamager();
if (damagedPlayer != null && !damagedIsDead){
// TODO: check once more when to set this (!) in terms of order.
FightData.getData(damagedPlayer).damageTakenByEntityTick = TickTask.getTick();
if (hasThorns(damagedPlayer)){
// TODO: Cleanup here.
// Remember the id of the attacker to allow counter damage.
damagedData.thornsId = damager.getEntityId();
}
else{
damagedData.thornsId = Integer.MIN_VALUE;
}
}
if (damager instanceof Player){ if (damager instanceof Player){
final Player player = (Player) damager; final Player player = (Player) damager;
if (e.getCause() == DamageCause.ENTITY_ATTACK){ if (e.getCause() == DamageCause.ENTITY_ATTACK){
if (handleNormalDamage(player, damaged)) e.setCancelled(true);
if (handleNormalDamage(player, damaged, e.getDamage())){
e.setCancelled(true);
}
} }
} }
} }

View File

@ -93,9 +93,7 @@ public class GodMode extends Check {
* @param damage * @param damage
* @return * @return
*/ */
public boolean check(final Player player, final int damage){ public boolean check(final Player player, final int damage, final FightData data){
final FightData data = FightData.getData(player);
final int tick = TickTask.getTick(); final int tick = TickTask.getTick();
final int noDamageTicks = Math.max(0, player.getNoDamageTicks()); final int noDamageTicks = Math.max(0, player.getNoDamageTicks());