Add deathScreen game rule; resolves #734

This commit is contained in:
Daniel Saukel 2020-04-05 17:00:09 +02:00
parent 1928fafdfe
commit ef46da7e36
8 changed files with 250 additions and 98 deletions

View File

@ -81,6 +81,11 @@ public class GameRule<V> {
* If the food levels of the players change. * If the food levels of the players change.
*/ */
public static final GameRule<Boolean> FOOD_LEVEL = new GameRule<>(Boolean.class, "foodLevel", true); public static final GameRule<Boolean> FOOD_LEVEL = new GameRule<>(Boolean.class, "foodLevel", true);
/**
* Sets if death screens are enabled. If false, players that would have died are healed and teleported to the respawn location;
* their inventory and experience are dropped if {@link #KEEP_INVENTORY_ON_DEATH} is set to false.
*/
public static final GameRule<Boolean> DEATH_SCREEN = new GameRule<>(Boolean.class, "deathScreen", false);
/** /**
* If players may fly. * If players may fly.
*/ */

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2014-2020 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.player;
import de.erethon.dungeonsxl.api.player.GamePlayer;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* @author Daniel Saukel
*/
public class GamePlayerDeathEvent extends GamePlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private boolean keepInventory;
private int lostLives;
public GamePlayerDeathEvent(GamePlayer gamePlayer, boolean keepInventory, int lostLives) {
super(gamePlayer);
this.lostLives = lostLives;
this.keepInventory = keepInventory;
}
/**
* If the player's state - including his inventory, EXP etc. - is kept.
*
* @return if the player's state is kept
*/
public boolean isInventoryKept() {
return keepInventory;
}
/**
* Sets if the player's state - including his inventory, EXP etc. - is kept.
*
* @param keepInventory if the player's state is kept
*/
public void setInventoryKept(boolean keepInventory) {
this.keepInventory = keepInventory;
}
/**
* Returns the amount of lives the player loses.
*
* @return the amount of lives the player loses
*/
public int getLostLives() {
return lostLives;
}
/**
* Sets the amount of lives the player loses.
*
* @param lostLives the lives the player loses
*/
public void setLostLives(int lostLives) {
this.lostLives = lostLives;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2014-2020 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.player;
import de.erethon.dungeonsxl.api.player.GamePlayer;
/**
* Superclass for events involving {@link de.erethon.dungeonsxl.api.player.GamePlayer GamePlayers}.
*
* @author Daniel Saukel
*/
public abstract class GamePlayerEvent extends GlobalPlayerEvent {
public GamePlayerEvent(GamePlayer gamePlayer) {
super(gamePlayer);
}
public GamePlayer getGamePlayer() {
return (GamePlayer) globalPlayer;
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2014-2020 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.player;
import de.erethon.dungeonsxl.api.player.GlobalPlayer;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
/**
* Superclass for events involving DungeonsXL players.
*
* @author Daniel Saukel
*/
public abstract class GlobalPlayerEvent extends Event {
protected GlobalPlayer globalPlayer;
public GlobalPlayerEvent(GlobalPlayer globalPlayer) {
this.globalPlayer = globalPlayer;
}
/**
* Returns the GlobalPlayer involved in this event
*
* @return the GlobalPlayer involved in this event
*/
public GlobalPlayer getGlobalPlayer() {
return globalPlayer;
}
/**
* Returns the Bukkit Player involved in this event
*
* @return the Bukkit Player involved in this event
*/
public Player getBukkitPlayer() {
if (globalPlayer == null) {
return null;
}
return globalPlayer.getPlayer();
}
}

View File

@ -1,88 +0,0 @@
/*
* Copyright (C) 2012-2020 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.event.dplayer.instance.game;
import de.erethon.dungeonsxl.player.DGamePlayer;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.bukkit.event.entity.PlayerDeathEvent;
/**
* @author Daniel Saukel
*/
public class DGamePlayerDeathEvent extends DGamePlayerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private PlayerDeathEvent bukkitEvent;
private int lostLives;
public DGamePlayerDeathEvent(DGamePlayer dPlayer, PlayerDeathEvent bukkitEvent, int lostLives) {
super(dPlayer);
this.bukkitEvent = bukkitEvent;
this.lostLives = lostLives;
}
/**
* @return the bukkitEvent
*/
public PlayerDeathEvent getBukkitEvent() {
return bukkitEvent;
}
/**
* @param bukkitEvent the bukkitEvent to set
*/
public void setBukkitEvent(PlayerDeathEvent bukkitEvent) {
this.bukkitEvent = bukkitEvent;
}
/**
* @return the lostLives
*/
public int getLostLives() {
return lostLives;
}
/**
* @param lostLives the lostLives to set
*/
public void setLostLives(int lostLives) {
this.lostLives = lostLives;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -17,6 +17,7 @@
package de.erethon.dungeonsxl.player; package de.erethon.dungeonsxl.player;
import de.erethon.caliburn.item.VanillaItem; import de.erethon.caliburn.item.VanillaItem;
import de.erethon.caliburn.mob.VanillaMob;
import de.erethon.commons.chat.MessageUtil; import de.erethon.commons.chat.MessageUtil;
import de.erethon.commons.player.PlayerUtil; import de.erethon.commons.player.PlayerUtil;
import de.erethon.dungeonsxl.DungeonsXL; import de.erethon.dungeonsxl.DungeonsXL;
@ -27,6 +28,7 @@ import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.dungeon.GameGoal; import de.erethon.dungeonsxl.api.dungeon.GameGoal;
import de.erethon.dungeonsxl.api.dungeon.GameRule; import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.dungeon.GameRuleContainer; import de.erethon.dungeonsxl.api.dungeon.GameRuleContainer;
import de.erethon.dungeonsxl.api.event.player.GamePlayerDeathEvent;
import de.erethon.dungeonsxl.api.mob.DungeonMob; import de.erethon.dungeonsxl.api.mob.DungeonMob;
import de.erethon.dungeonsxl.api.player.GamePlayer; import de.erethon.dungeonsxl.api.player.GamePlayer;
import de.erethon.dungeonsxl.api.player.PlayerClass; import de.erethon.dungeonsxl.api.player.PlayerClass;
@ -36,7 +38,6 @@ import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.dungeon.DGame; import de.erethon.dungeonsxl.dungeon.DGame;
import de.erethon.dungeonsxl.event.dplayer.DPlayerKickEvent; import de.erethon.dungeonsxl.event.dplayer.DPlayerKickEvent;
import de.erethon.dungeonsxl.event.dplayer.instance.DInstancePlayerUpdateEvent; import de.erethon.dungeonsxl.event.dplayer.instance.DInstancePlayerUpdateEvent;
import de.erethon.dungeonsxl.event.dplayer.instance.game.DGamePlayerDeathEvent;
import de.erethon.dungeonsxl.event.dplayer.instance.game.DGamePlayerFinishEvent; import de.erethon.dungeonsxl.event.dplayer.instance.game.DGamePlayerFinishEvent;
import de.erethon.dungeonsxl.event.dplayer.instance.game.DGamePlayerRewardEvent; import de.erethon.dungeonsxl.event.dplayer.instance.game.DGamePlayerRewardEvent;
import de.erethon.dungeonsxl.event.requirement.RequirementCheckEvent; import de.erethon.dungeonsxl.event.requirement.RequirementCheckEvent;
@ -52,6 +53,7 @@ import org.bukkit.GameMode;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Damageable; import org.bukkit.entity.Damageable;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Wolf; import org.bukkit.entity.Wolf;
import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent;
@ -744,24 +746,51 @@ public class DGamePlayer extends DInstancePlayer implements GamePlayer {
if (game == null) { if (game == null) {
return; return;
} }
GameRuleContainer rules = game.getRules();
boolean keepInventory = rules.getState(GameRule.KEEP_INVENTORY_ON_DEATH);
DGamePlayerDeathEvent dPlayerDeathEvent = new DGamePlayerDeathEvent(this, event, 1); GamePlayerDeathEvent dPlayerDeathEvent = new GamePlayerDeathEvent(this, keepInventory, 1);
Bukkit.getPluginManager().callEvent(dPlayerDeathEvent); Bukkit.getPluginManager().callEvent(dPlayerDeathEvent);
if (dPlayerDeathEvent.isCancelled()) { if (dPlayerDeathEvent.isCancelled()) {
return; return;
} }
if (config.areGlobalDeathMessagesDisabled()) { Location deathLocation = player.getLocation();
event.setDeathMessage(null); if (keepInventory && event != null) {
}
GameRuleContainer rules = game.getRules();
if (rules.getState(GameRule.KEEP_INVENTORY_ON_DEATH)) {
event.setKeepInventory(true); event.setKeepInventory(true);
event.getDrops().clear(); event.getDrops().clear();
event.setKeepLevel(true); event.setKeepLevel(true);
event.setDroppedExp(0); event.setDroppedExp(0);
} else if (!keepInventory && event == null) {
for (ItemStack itemStack : player.getInventory().getContents()) {
if (itemStack == null) {
continue;
}
getWorld().dropItemNaturally(deathLocation, itemStack);
}
player.getInventory().clear();
ExperienceOrb orb = (ExperienceOrb) VanillaMob.EXPERIENCE_ORB.toEntity(deathLocation);
int expDrop = 7 * player.getLevel();
expDrop = expDrop > 100 ? 100 : expDrop;
orb.setExperience(expDrop);
player.setLevel(player.getLevel() - 7);
player.setExp(0);
}
if (event == null) {
Location respawn = getLastCheckpoint();
if (respawn == null) {
respawn = gameWorld.getStartLocation(getGroup());
}
player.teleport(respawn);
heal();
if (getWolf() != null) {
getWolf().teleport(respawn);
}
} else if (config.areGlobalDeathMessagesDisabled()) {
event.setDeathMessage(null);
} }
if (getGroup() != null && dGroup.getLives() != -1) { if (getGroup() != null && dGroup.getLives() != -1) {

View File

@ -259,6 +259,19 @@ public class DGlobalPlayer implements GlobalPlayer {
MessageUtil.sendMessage(player, message); MessageUtil.sendMessage(player, message);
} }
public void heal() {
if (is1_9) {
player.setHealth(player.getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue());
} else {
player.setHealth(player.getMaxHealth());
}
player.setFoodLevel(20);
player.setFireTicks(0);
for (PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
}
@Override @Override
public void reset(boolean keepInventory) { public void reset(boolean keepInventory) {
final Location tpLoc = data.getOldLocation().getWorld() != null ? data.getOldLocation() : Bukkit.getWorlds().get(0).getSpawnLocation(); final Location tpLoc = data.getOldLocation().getWorld() != null ? data.getOldLocation() : Bukkit.getWorlds().get(0).getSpawnLocation();

View File

@ -101,7 +101,18 @@ public class DPlayerListener implements Listener {
} }
boolean dead = ((LivingEntity) event.getEntity()).getHealth() - event.getFinalDamage() <= 0; boolean dead = ((LivingEntity) event.getEntity()).getHealth() - event.getFinalDamage() <= 0;
if (dead && plugin.getDungeonMob((LivingEntity) event.getEntity()) != null) { if (!dead) {
return;
}
if (event.getEntity() instanceof Player && !gameWorld.getDungeon().getRules().getState(GameRule.DEATH_SCREEN)) {
GamePlayer gamePlayer = plugin.getPlayerCache().getGamePlayer((Player) event.getEntity());
if (gamePlayer == null) {
return;
}
((DGamePlayer) gamePlayer).onDeath(null);
}
if (plugin.getDungeonMob((LivingEntity) event.getEntity()) != null) {
String killer = null; String killer = null;
if (event instanceof EntityDamageByEntityEvent) { if (event instanceof EntityDamageByEntityEvent) {