package instance.pvparenas;
import static com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE.STR_REBIRTH_MASSAGE_ME;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Future;
import com.aionemu.commons.utils.Rnd;
import com.aionemu.gameserver.controllers.attack.AggroInfo;
import com.aionemu.gameserver.instance.handlers.GeneralInstanceHandler;
import com.aionemu.gameserver.model.autogroup.AGPlayer;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.Npc;
import com.aionemu.gameserver.model.gameobjects.VisibleObject;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.instance.InstanceProgressionType;
import com.aionemu.gameserver.model.instance.InstanceScoreType;
import com.aionemu.gameserver.model.instance.instancescore.InstanceScore;
import com.aionemu.gameserver.model.instance.instancescore.PvPArenaScore;
import com.aionemu.gameserver.model.instance.playerreward.HarmonyGroupReward;
import com.aionemu.gameserver.model.instance.playerreward.PvPArenaPlayerReward;
import com.aionemu.gameserver.model.team.TemporaryPlayerTeam;
import com.aionemu.gameserver.model.templates.rewards.ArenaRewardItem;
import com.aionemu.gameserver.model.templates.rewards.RewardItem;
import com.aionemu.gameserver.model.templates.spawns.SpawnTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.questEngine.QuestEngine;
import com.aionemu.gameserver.questEngine.model.QuestEnv;
import com.aionemu.gameserver.services.abyss.AbyssPointsService;
import com.aionemu.gameserver.services.abyss.GloryPointsService;
import com.aionemu.gameserver.services.item.ItemService;
import com.aionemu.gameserver.services.player.PlayerReviveService;
import com.aionemu.gameserver.services.teleport.TeleportService;
import com.aionemu.gameserver.skillengine.SkillEngine;
import com.aionemu.gameserver.skillengine.model.Effect;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
import com.aionemu.gameserver.world.WorldMapInstance;
/**
* @author xTz, Estrayl
*/
public abstract class PvPArenaInstance extends GeneralInstanceHandler {
private static final int START_DELAY = 120000;
private static final int ROUND_DURATION = 180000;
protected static final float RANK_REWARD_RATE = 0.7f;
protected static final float SCORE_REWARD_RATE = 0.3f;
protected int pointsPerKill = 800;
protected int pointsPerDeath = -150;
protected PvPArenaScore instanceScore;
private Future<?> instanceTask;
private boolean isInterrupted;
public PvPArenaInstance(WorldMapInstance instance) {
super(instance);
}
protected PvPArenaScore createNewArenaScore() {
return new PvPArenaScore(instance);
}
protected void setScoreCaps() {
instanceScore.setLowerScoreCap(7000);
instanceScore.setUpperScoreCap(50000);
instanceScore.setMaxScoreGap(43000);
}
@Override
public void onInstanceCreate() {
instanceScore = createNewArenaScore();
setScoreCaps();
instanceScore.setInstanceProgressionType(InstanceProgressionType.PREPARING);
instanceScore.setInstanceStartTime();
spawnRings();
instanceTask = ThreadPoolManager.getInstance().schedule(this::startInstance, START_DELAY);
}
private void startInstance() {
if (instanceScore.isRewarded())
return;
if (!canStart()) {
isInterrupted = true;
endInstance();
return;
}
instance.forEachDoor(door -> door.setOpen(true));
instanceScore.setInstanceProgressionType(InstanceProgressionType.START_PROGRESS);
broadcastUpdate(InstanceScoreType.UPDATE_INSTANCE_PROGRESS);
instanceTask = ThreadPoolManager.getInstance().schedule(this::startNextRound, ROUND_DURATION);
}
private void startNextRound() {
if (instanceScore.isRewarded())
return;
if (isFinalRound()) {
endInstance();
return;
}
instanceScore.incrementRound();
instanceScore.setRndZone();
broadcastUpdate(InstanceScoreType.UPDATE_INSTANCE_PROGRESS);
changeZone();
if (isFinalRound())
sendMsg(SM_SYSTEM_MESSAGE.STR_MSG_INSTANCE_START_SCOREMOD());
instanceTask = ThreadPoolManager.getInstance().schedule(this::startNextRound, ROUND_DURATION);
}
private void endInstance() {
instance.forEachNpc(npc -> npc.getController().delete());
instanceScore.setInstanceProgressionType(InstanceProgressionType.END_PROGRESS);
instanceTask = ThreadPoolManager.getInstance().schedule(() -> instance.forEachPlayer(this::leaveInstance), 60000);
calculateRewards();
reward();
broadcastResults();
}
@Override
public boolean onDie(Player victim, Creature lastAttacker) {
PvPArenaPlayerReward victimReward = getStatReward(victim);
PvPArenaPlayerReward winnerReward = null;
if (lastAttacker != victim && lastAttacker instanceof Player winner) {
winnerReward = getStatReward(winner);
winnerReward.addPvPKill();
QuestEngine.getInstance().onKillInWorld(new QuestEnv(victim, winner, 0), winner.getWorldId()); // Notify Kill-Quests
}
calculateAndUpdatePoints(victim, Math.round(pointsPerKill * getRunnerUpScoreMod(victimReward, winnerReward)));
updatePoints(victimReward, victim, lastAttacker, pointsPerDeath, false); // Update victim points after rewarding the winner
applyMoraleBoost(victim);
return true;
}
@Override
public void onDie(Npc npc) {
int npcId = npc.getNpcId();
if (npcId == 701187 || npcId == 701188)
ThreadPoolManager.getInstance().schedule(this::spawnRndRelics, 30000);
int points = getPoints(npcId);
if (points == 0)
return;
calculateAndUpdatePoints(npc, points);
}
private void calculateAndUpdatePoints(Creature victim, int points) {
if (!instanceScore.isStartProgress())
return;
int totalDamage = victim.getAggroList().getTotalDamage();
for (AggroInfo aggroInfo : victim.getAggroList().getFinalDamageList(shouldMergeGroupDamage())) {
if (aggroInfo.getDamage() == 0)
continue;
int rewardPoints = points * aggroInfo.getDamage() / totalDamage;
if (aggroInfo.getAttacker() instanceof Creature && ((Creature) aggroInfo.getAttacker()).getMaster() instanceof Player attacker) {
updatePoints(getStatReward(attacker), attacker, victim, rewardPoints);
} else if (aggroInfo.getAttacker() instanceof TemporaryPlayerTeam<?> team) {
Player leader = team.getLeaderObject();
updatePoints(getStatReward(leader), leader, victim, rewardPoints);
team.getOnlineMembers().stream().filter(p -> !p.equals(leader)).forEach(p -> sendSystemMsg(p, victim, rewardPoints));
}
}
}
@Override
public void handleUseItemFinish(Player player, Npc npc) {
PvPArenaPlayerReward arenaReward = getStatReward(player);
if (!instanceScore.isStartProgress() || arenaReward == null)
return;
int rewardPoints = getPoints(npc.getNpcId());
int skill = instanceScore.getNpcBonusSkill(npc.getNpcId());
if (skill != 0)
useSkill(npc, player, skill >> 8, skill & 0xFF);
updatePoints(arenaReward, player, npc, rewardPoints);
}
protected void updatePoints(PvPArenaPlayerReward receiver, Player player, VisibleObject victim, int rewardPoints) {
updatePoints(receiver, player, victim, rewardPoints, true);
}
protected void updatePoints(PvPArenaPlayerReward receiver, Player player, VisibleObject victim, int rewardPoints, boolean broadcastPackets) {
if (receiver == null)
return;
receiver.addPoints(rewardPoints, instanceScore);
if (broadcastPackets) {
broadcastUpdate(InstanceScoreType.UPDATE_INSTANCE_BUFFS_AND_SCORE);
broadcastUpdate(player, InstanceScoreType.UPDATE_PLAYER_BUFF_STATUS);
}
sendSystemMsg(player, victim, rewardPoints);
if (instanceScore.reachedScoreGap())
endInstance();
}
protected boolean isFinalRound() {
return instanceScore.getRound() == 3;
}
protected void sendSystemMsg(Player player, VisibleObject creature, int rewardPoints) {
if (rewardPoints <= 0) // Checked with retail, only net gain is sent as msg
return;
if (creature instanceof Player)
PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_MSG_GET_SCORE_FOR_ENEMY(rewardPoints));
else
PacketSendUtility.sendPacket(player, SM_SYSTEM_MESSAGE.STR_MSG_GET_SCORE(creature.getObjectTemplate().getL10n(), rewardPoints));
}
private int calcAndFloor(int number, float rate) {
return (int) (number * rate);
}
private int calcAndFloor(int number, float rate, float configRate) {
return (int) (number * rate * configRate);
}
protected Collection<PvPArenaPlayerReward> getArenaRewards() {
return instanceScore.getPlayerRewards();
}
private int getPoints(int npcId) {
switch (npcId) {
case 701187: // Blessed Relics
case 701188: // Cursed Relics
return 1750;
case 218690: // Pale Carmina
case 218703: // Pale Carmina
case 218716: // Pale Carmina
case 218691: // Corrupt Casus
case 218704: // Corrupt Casus
case 218717: // Corrupt Casus
return 1500;
case 218682: // MuMu Rake Gatherer
case 218695: // MuMu Rake Gatherer
case 218708: // MuMu Rake Gatherer
return 1250;
case 701181: // Cursed Relics
case 701195: // Cursed Relics
case 701209: // Cursed Relics
case 218689: // Casus Manor Noble
case 218702: // Casus Manor Noble
case 218715: // Casus Manor Noble
return 750;
case 218701: // Casus Manor Butler
case 218688: // Casus Manor Butler
case 218714: // Casus Manor Butler
return 650;
case 701172: // Plaza Flame Thrower
case 701171: // Plaza Flame Thrower
case 701170: // Plaza Flame Thrower
case 701169: // Plaza Flame Thrower
case 218806: // Casus Manor Chief Maid
case 218807: // Casus Manor Chief Maid
case 218808: // Casus Manor Chief Maid
case 701317: // Blessed Relics
case 701318: // Blessed Relics
case 701319: // Blessed Relics
return 500;
case 207102: // Recovery Relics
case 207116: // 1st Floor Stunner
case 219277: // Roaming Volcanic Petrahulk Lv 50
case 219278: // Roaming Volcanic Petrahulk Lv 55
case 219279: // Roaming Volcanic Petrahulk Lv 60
case 219481: // Volcanic Heart Crystal Lv 50
case 219485: // Volcanic Heart Crystal Lv 55
case 219486: // Volcanic Heart Crystal Lv 60
case 219648: // Roaming Volcanic Petrahulk Lv 65
case 219652: // Volcanic Heart Crystal Lv 65
return 400;
case 218685: // Casus Manor Guard
case 218698: // Casus Manor Guard
case 218711: // Casus Manor Guard
case 218687: // Casus Manor Maid
case 218700: // Casus Manor Maid
case 218713: // Casus Manor Maid
case 218686: // Casus Manor Maidservant
case 218699: // Casus Manor Maidservant
case 218712: // Casus Manor Maidservant
return 250;
case 207099: // 2nd Floor Bomb
return 200;
case 218683: // Black Claw Scratcher
case 218696: // Black Claw Scratcher
case 218709: // Black Claw Scratcher
case 218684: // Mutated Drakan Fighter
case 218697: // Mutated Drakan Fighter
case 218710: // Mutated Drakan Fighter
case 218693: // Red Sand Tog
case 218706: // Red Sand Tog
case 218719: // Red Sand Tog
case 219280: // Heated Negotiator Grangvolkan Lv 50
case 219281: // Heated Negotiator Grangvolkan Lv 55
case 219282: // Heated Negotiator Grangvolkan Lv 60
case 219649: // Heated Negotiator Grangvolkan Lv 65
case 233058: // Red Sand Tog
case 701215: // Blesed Relic
case 701220: // Blesed Relic
case 701225: // Blesed Relic
case 701216: // Blesed Relic
case 701221: // Blesed Relic
case 701226: // Blesed Relic
return 100;
case 219283: // Lurking Fangwing Lv 50
case 219284: // Lurking Fangwing Lv 55
case 219285: // Lurking Fangwing Lv 60
case 219650: // Lurking Fangwing Lv 65
case 219328: // Plaza Wall
return 50;
default:
return 0;
}
}
private void changeZone() {
ThreadPoolManager.getInstance().schedule(() -> {
for (Player player : instance.getPlayersInside()) {
if (player.isDead()) {
PlayerReviveService.revive(player, 100, 100, false, 0);
player.getGameStats().updateStatsAndSpeedVisually();
}
instanceScore.portToPosition(player);
broadcastUpdate(player, InstanceScoreType.UPDATE_PLAYER_BUFF_STATUS);
}
}, 1000);
}
@Override
public void onEnterInstance(Player player) {
if (instanceScore.regPlayerReward(player)) {
instanceScore.setRndPosition(player.getObjectId());
} else {
instanceScore.portToPosition(player);
getPlayerSpecificReward(player).updateBonusTime();
}
sendEntryPacket(player);
}
@Override
public void onPlayerLogout(Player player) {
getPlayerSpecificReward(player).updateLogoutTime();
}
private void clearDebuffs(Player player) {
for (Effect ef : player.getEffectController().getAbnormalEffects()) {
switch (ef.getSkillTemplate().getDispelCategory()) {
case DEBUFF, DEBUFF_MENTAL, DEBUFF_PHYSICAL, ALL -> ef.endEffect();
}
}
}
protected void useSkill(Npc npc, Player player, int skillId, int level) {
SkillEngine.getInstance().getSkill(npc, skillId, level, player).useNoAnimationSkill();
}
@Override
public boolean onReviveEvent(Player player) {
PacketSendUtility.sendPacket(player, STR_REBIRTH_MASSAGE_ME());
PlayerReviveService.revive(player, 100, 100, false, 0);
player.getGameStats().updateStatsAndSpeedVisually();
instanceScore.portToPosition(player);
return true;
}
@Override
public void leaveInstance(Player player) {
if (player.getWorldMapInstance().equals(instance))
TeleportService.moveToInstanceExit(player, mapId, player.getRace());
}
@Override
public void onLeaveInstance(Player player) {
super.onLeaveInstance(player);
clearDebuffs(player);
PvPArenaPlayerReward playerReward = getPlayerSpecificReward(player);
if (playerReward != null) {
endMoraleBoost(player);
instanceScore.clearPosition(playerReward.getPosition(), Boolean.FALSE);
instanceScore.removePlayerReward(playerReward);
broadcastUpdate(InstanceScoreType.UPDATE_INSTANCE_BUFFS_AND_SCORE);
}
}
@Override
public void onInstanceDestroy() {
instanceScore.clear();
if (instanceTask != null && !instanceTask.isCancelled())
instanceTask.cancel(true);
}
private void applyMoraleBoost(Player player) {
PvPArenaPlayerReward reward = getPlayerSpecificReward(player);
if (reward == null)
return;
reward.applyBoostMoraleEffect(player, getBoostMoraleEffectDuration(instanceScore.getRank(reward)));
broadcastUpdate(player, InstanceScoreType.UPDATE_PLAYER_BUFF_STATUS);
}
private void endMoraleBoost(Player player) {
PvPArenaPlayerReward reward = getPlayerSpecificReward(player);
if (reward != null && reward.hasBoostMorale()) {
reward.endBoostMoraleEffect(player);
}
broadcastUpdate(player, InstanceScoreType.UPDATE_PLAYER_BUFF_STATUS);
}
private void spawnRndRelics() {
if (instanceScore != null && !instanceScore.isRewarded())
spawn(Rnd.get(1, 2) == 1 ? 701187 : 701188, 1841.951f, 1733.968f, 300.242f, (byte) 0);
}
@Override
public InstanceScore<?> getInstanceScore() {
return instanceScore;
}
/**
* Overridden in HarmonyTrainingGroundsInstance to differentiate between player and group specific reward objects
*/
protected PvPArenaPlayerReward getStatReward(Player player) {
return getPlayerSpecificReward(player);
}
protected PvPArenaPlayerReward getPlayerSpecificReward(Player player) {
return instanceScore.getPlayerReward(player.getObjectId());
}
protected boolean canStart() {
return instance.getPlayersInside().size() > 1;
}
protected void spawnRings() {
}
protected float getRunnerUpScoreMod(PvPArenaPlayerReward victim, PvPArenaPlayerReward winner) {
if (winner == null || !isFinalRound())
return 1f;
int victimRank = instanceScore.getRank(victim);
return victimRank < instanceScore.getRank(winner) ? getRunnerUpScoreMod(victimRank) : 1f;
}
protected int getBoostMoraleEffectDuration(int rank) {
return 15000; // Retail Default
}
protected float getRunnerUpScoreMod(int victimRank) {
return 3f;
}
protected boolean shouldMergeGroupDamage() {
return false;
}
protected BaseRewards getBaseRewardsPerPlayer(int difficultyId) {
return new BaseRewards(0, 0, 0, 0);
}
protected BaseRewards getBaseRewards(int difficultyId) {
return new BaseRewards(0, 0, 0, 0);
}
protected float getRewardRate(int rank, int difficultyId) {
return 0f;
}
protected void setRewardItems(PvPArenaPlayerReward reward, int rank, int difficultyId) {
}
protected float getConfigRate(Player player) {
return 1f;
}
protected void calculateRewards() {
int difficultyId = instanceScore.getDifficultyId();
BaseRewards baseValues = getBaseRewardsPerPlayer(difficultyId);
int playerCount = instanceScore.getPlayerRewards().size();
int totalAp = baseValues.ap() * playerCount;
int totalGp = baseValues.gp() * playerCount;
int totalCrucibleInsignia = baseValues.crucibleInsignia() * playerCount;
int totalCourageInsignia = baseValues.courageInsignia() * playerCount;
int rankAp = calcAndFloor(totalAp, RANK_REWARD_RATE);
int rankGp = calcAndFloor(totalGp, RANK_REWARD_RATE);
int rankCrucibleInsignia = calcAndFloor(totalCrucibleInsignia, RANK_REWARD_RATE);
int rankCourageInsignia = calcAndFloor(totalCourageInsignia, RANK_REWARD_RATE);
int scoreAp = calcAndFloor(totalAp, SCORE_REWARD_RATE);
int scoreGp = calcAndFloor(totalGp, SCORE_REWARD_RATE);
int scoreCrucibleInsignia = calcAndFloor(totalCrucibleInsignia, SCORE_REWARD_RATE);
int scoreCourageInsignia = calcAndFloor(totalCourageInsignia, SCORE_REWARD_RATE);
int totalPoints = instanceScore.getTotalPoints();
for (PvPArenaPlayerReward reward : getArenaRewards()) {
if (reward.isRewarded())
continue;
Player player = instance.getPlayer(reward.getOwnerId());
if (!(reward instanceof HarmonyGroupReward) && player == null) // player left
continue;
float configRate = getConfigRate(player);
int score = reward.getScorePoints();
// Score Formula to verify: floor(scoreAp * winnerKills * winnerPoints / (winnerKills * winnerPoints + loserKills * loserPoints))
float scoreRate = score / (float) totalPoints;
int rank = instanceScore.getRank(reward);
if (isInterrupted)
rank = reward instanceof HarmonyGroupReward ? 1 : instance.getMaxPlayers() - 1;
float rankRewardRate = getRewardRate(rank, difficultyId);
int rankRewardAp = calcAndFloor(rankAp, rankRewardRate, configRate);
int rankRewardGp = calcAndFloor(rankGp, rankRewardRate, 1f);
int rankRewardCrucibleInsignia = calcAndFloor(rankCrucibleInsignia, rankRewardRate, configRate);
int rankRewardCourageInsignia = calcAndFloor(rankCourageInsignia, rankRewardRate, configRate);
int scoreRewardAp = calcAndFloor(scoreAp, scoreRate, configRate);
int scoreRewardGp = calcAndFloor(scoreGp, scoreRate, 1f);
int scoreRewardCrucibleInsignia = calcAndFloor(scoreCrucibleInsignia, scoreRate, configRate);
int scoreRewardCourageInsignia = calcAndFloor(scoreCourageInsignia, scoreRate, configRate);
BaseRewards baseRewards = getBaseRewards(difficultyId);
reward.setAp(new ArenaRewardItem(0, baseRewards.ap(), rankRewardAp, scoreRewardAp));
reward.setGp(new ArenaRewardItem(0, baseRewards.gp(), rankRewardGp, scoreRewardGp));
ArenaRewardItem crucibleInsignia = new ArenaRewardItem(186000130, baseRewards.crucibleInsignia(), rankRewardCrucibleInsignia,
scoreRewardCrucibleInsignia);
ArenaRewardItem courageInsignia = new ArenaRewardItem(186000137, baseRewards.courageInsignia(), rankRewardCourageInsignia,
scoreRewardCourageInsignia);
if (crucibleInsignia.getTotalCount() > 0)
reward.setCrucibleInsignia(crucibleInsignia);
if (courageInsignia.getTotalCount() > 0)
reward.setCourageInsignia(courageInsignia);
setRewardItems(reward, rank, difficultyId);
if (reward instanceof HarmonyGroupReward harmonyGroupReward) {
splitGroupRewards(harmonyGroupReward);
}
}
}
private void splitGroupRewards(HarmonyGroupReward groupReward) {
List<AGPlayer> associatedPlayers = groupReward.getAssociatedPlayers();
if (associatedPlayers.isEmpty())
return;
int size = associatedPlayers.size();
for (AGPlayer agPlayer : associatedPlayers) {
PvPArenaPlayerReward apr = instanceScore.getPlayerReward(agPlayer.objectId());
Player player = instance.getPlayer(agPlayer.objectId());
if (apr == null || player == null)
continue;
float configRate = getConfigRate(player);
apr.setAp(calculateIndividualReward(groupReward.getAp(), size, configRate));
apr.setGp(calculateIndividualReward(groupReward.getGp(), size, 1f));
apr.setCrucibleInsignia(calculateIndividualReward(groupReward.getCrucibleInsignia(), size, configRate));
apr.setCourageInsignia(calculateIndividualReward(groupReward.getCourageInsignia(), size, configRate));
apr.setRewardItem1(groupReward.getRewardItem1());
apr.setRewardItem2(groupReward.getRewardItem2());
}
}
private ArenaRewardItem calculateIndividualReward(ArenaRewardItem rewardItem, int size, float configRate) {
int baseCount = Math.round(rewardItem.baseCount() * configRate / size);
int rankingCount = Math.round(rewardItem.rankingCount() * configRate / size);
int scoreCount = Math.round(rewardItem.scoreCount() * configRate / size);
return new ArenaRewardItem(rewardItem.itemId(), baseCount, rankingCount, scoreCount);
}
private void reward() {
for (Player player : instance.getPlayersInside()) {
if (player.isDead())
PlayerReviveService.duelRevive(player);
PvPArenaPlayerReward reward = getPlayerSpecificReward(player);
if (!reward.isRewarded()) {
reward.setRewarded();
ArenaRewardItem apReward = reward.getAp();
if (apReward.getTotalCount() > 0)
AbyssPointsService.addAp(player, apReward.getTotalCount());
ArenaRewardItem gpReward = reward.getGp();
if (gpReward.getTotalCount() > 0)
GloryPointsService.increaseGpBy(player.getObjectId(), gpReward.getTotalCount(), false, true);
ArenaRewardItem courageInsigniaReward = reward.getCourageInsignia();
if (courageInsigniaReward.getTotalCount() > 0)
ItemService.addItem(player, courageInsigniaReward.itemId(), courageInsigniaReward.getTotalCount());
ArenaRewardItem crucibleInsigniaReward = reward.getCrucibleInsignia();
if (crucibleInsigniaReward.getTotalCount() > 0)
ItemService.addItem(player, crucibleInsigniaReward.itemId(), crucibleInsigniaReward.getTotalCount());
RewardItem rewardItem1 = reward.getRewardItem1();
if (rewardItem1 != null)
ItemService.addItem(player, rewardItem1.getId(), rewardItem1.getCount());
RewardItem rewardItem2 = reward.getRewardItem2();
if (rewardItem2 != null)
ItemService.addItem(player, rewardItem2.getId(), rewardItem2.getCount());
}
}
}
protected Npc getNpc(float x, float y, float z) {
for (Npc npc : instance.getNpcs()) {
SpawnTemplate st = npc.getSpawn();
if (st.getX() == x && st.getY() == y && st.getZ() == z)
return npc;
}
return null;
}
protected void sendEntryPacket(Player player) {
sendPacket(null, null);
}
protected void broadcastUpdate(Player target, InstanceScoreType scoreType) {
sendPacket(null, null);
}
protected void broadcastUpdate(InstanceScoreType scoreType) {
sendPacket(null, null);
}
protected void broadcastResults() {
instance.forEachPlayer(player -> sendPacket(player, InstanceScoreType.SHOW_REWARD));
}
protected void sendPacket(Player receiver, InstanceScoreType scoreType) {
}
@Override
public boolean allowSelfReviveBySkill() {
return false;
}
@Override
public boolean allowSelfReviveByItem() {
return false;
}
protected record BaseRewards(int ap, int gp, int crucibleInsignia, int courageInsignia) {}
}