Index: L2Kryos_GameServer/config/system_config/fun/npc_Protector.ini ===================================================================== +#============================================================# +# L2NpcProtectorInstance Config +#============================================================# +# Tables; 1,2,3,4,5,6,7,8,9,10,15,16,17,18. +# Default = 15 +NpcProtectorTextCreatureSay = 15 +# Prefix to be displayed before the message +NpcMessagePrefix = [Anti-PK] +# Message after eliminating a player with karma. +ScreenNpcProtectorMessageText = PK is prohibited. +# Damage that the NPC will inflict. +NpcProtectorPAtk = 30000 +NpcProtectorMAtk = 30000 Index: head-src/kryos/Config.java ================================== + + // ===============================FUN=============================== + public static int NPC_PROTECTOR_P_ATK; + public static int NPC_PROTECTOR_M_ATK; + + public static int NPC_PROTECTOR_TEXT_CREATURE_SAY; + public static String NPC_MESSAGE_PREFIX; + public static String NPC_PROTECTOR_MESSAGE_TEXT; + + //================================================================== + public static void loadNpcProtectorConfig() + { + final String NPCSYSTEM = FService.NPCSYSTEM_FILE; + + try + { + final Properties NpcConfig = new Properties(); + final InputStream is = new FileInputStream(new File(NPCSYSTEM)); + NpcConfig.load(is); + is.close(); + // =============================================FUN============================================= + + NPC_PROTECTOR_P_ATK = Integer.parseInt(NpcConfig.getProperty("NpcProtectorPAtk", "30000")); + NPC_PROTECTOR_M_ATK = Integer.parseInt(NpcConfig.getProperty("NpcProtectorMAtk", "30000")); + + NPC_PROTECTOR_TEXT_CREATURE_SAY = Integer.parseInt(NpcConfig.getProperty("NpcProtectorTextCreatureSay", "15")); + NPC_MESSAGE_PREFIX = NpcConfig.getProperty("NpcMessagePrefix", "[Anti-PK]"); + NPC_PROTECTOR_MESSAGE_TEXT = NpcConfig.getProperty("ScreenNpcProtectorMessageText", "PK is prohibited."); + + // ============================================================================================= + } + catch (Exception e) + { + e.printStackTrace(); + throw new Error("Failed to Load " + NPCSYSTEM + " File."); + } + } + @@ loadRewardSystemConfig(); + loadNpcProtectorConfig(); Index: head-src/kryos/FService.java ==================================== +public static final String NPCSYSTEM_FILE = "./config/system_config/fun/npc_Protector.ini"; Index: head-src/kryos/gameserver/model/actor/knownlist/ProtectorKnownList.java =============================================================================== +package kryos.gameserver.model.actor.knownlist; + +import kryos.gameserver.model.L2Object; +import kryos.gameserver.model.actor.instance.L2NpcProtectorInstance; + +public class ProtectorKnownList extends AttackableKnownList +{ + private static final int DISTANCE_TO_WATCH = 10000; + + public ProtectorKnownList(L2NpcProtectorInstance activeChar) + { + super(activeChar); + } + + @Override + public boolean addKnownObject(L2Object object) + { + + double distance = getDistance(object); + if (distance > DISTANCE_TO_WATCH) + { + return false; + } + return super.addKnownObject(object); + } + + private double getDistance(L2Object object) + { + int dx = getActiveChar().getX() - object.getX(); + int dy = getActiveChar().getY() - object.getY(); + int dz = getActiveChar().getZ() - object.getZ(); + return Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + @Override + public L2NpcProtectorInstance getActiveChar() + { + return (L2NpcProtectorInstance) super.getActiveChar(); + } +} Index: head-src/kryos/gameserver/model/actor/instance/L2NpcProtectorInstance.java ================================================================================== +package kryos.gameserver.model.actor.instance; + +import kryos.gameserver.model.L2Character; +import kryos.gameserver.model.L2Attackable; +import kryos.gameserver.model.actor.knownlist.ProtectorKnownList; +import kryos.gameserver.network.serverpackets.ActionFailed; +import kryos.gameserver.templates.L2NpcTemplate; +import kryos.gameserver.thread.ThreadPoolManager; +import kryos.gameserver.model.L2Object; +import kryos.gameserver.model.L2World; +import kryos.Config; +import kryos.gameserver.ai.CtrlIntention; + +public class L2NpcProtectorInstance extends L2Attackable +{ + private int spawnX, spawnY, spawnZ; + private double pAtk; + private double mAtk; + + public L2NpcProtectorInstance(int objectId, L2NpcTemplate template) + { + super(objectId, template); + setKnownList(new ProtectorKnownList(this)); + } + + @Override + public void onSpawn() + { + super.onSpawn(); + + spawnX = getX(); + spawnY = getY(); + spawnZ = getZ(); + + pAtk = Config.NPC_PROTECTOR_P_ATK; + mAtk = Config.NPC_PROTECTOR_M_ATK; + + ThreadPoolManager.getInstance().scheduleGeneralAtFixedRate(() -> + { + try + { + scanForPKs(); + } + catch (Exception e) + { + e.printStackTrace(); + } + }, 100, 100); + } + + private void scanForPKs() + { + L2PcInstance targetPK = null; + double minDistance = Double.MAX_VALUE; + + for (L2Character cha : getAggroList().keySet()) + { + if (cha instanceof L2PcInstance) + { + L2PcInstance pc = (L2PcInstance) cha; + if (pc.isDead() || pc.getKarma() <= 0) + { + stopHating(pc); + } + } + } + + for (L2PcInstance pc : L2World.getInstance().getAllPlayers()) + { + if (pc.getKarma() <= 0 || pc.isDead()) + continue; + + double distance = getDistance(pc); + if (distance > 10000) + continue; + + if (!getKnownList().knowsObject(pc)) + { + getKnownList().addKnownObject(pc); + } + + if (distance < minDistance) + { + targetPK = pc; + minDistance = distance; + } + } + + if (targetPK != null) + { + if (getAI().getIntention() != CtrlIntention.AI_INTENTION_ATTACK || getTarget() != targetPK) + { + getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, targetPK); + } + double physDamage = pAtk - targetPK.getPDef(this); + if (physDamage < 0) physDamage = 1000; + + double magicDamage = mAtk - targetPK.getMDef(this, null); + if (magicDamage < 0) magicDamage = 500; + + double totalDamage = physDamage + magicDamage; + targetPK.reduceCurrentHp(totalDamage, this, true); + } + else + { + if (getX() != spawnX || getY() != spawnY) + { + teleToLocation(spawnX, spawnY, spawnZ); + } + if (getAI().getIntention() != CtrlIntention.AI_INTENTION_IDLE) + { + getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE, null); + } + } + } + + private double getDistance(L2Object obj) + { + int dx = getX() - obj.getX(); + int dy = getY() - obj.getY(); + int dz = getZ() - obj.getZ(); + return Math.sqrt(dx*dx + dy*dy + dz*dz); + } + + @Override + public void onAction(L2PcInstance player) + { + player.sendPacket(new ActionFailed()); + } + + @Override + public boolean isAutoAttackable(L2Character attacker) + { + return false; + } +} Index: head-src/kryos/gameserver/model/actor/instance/L2PcInstance.java ======================================================================== @@ @Override public boolean doDie(final L2Character killer) { castle = CastleManager.getInstance().getCastleByOwner(getClan()); if (castle != null) { castle.destroyClanGate(); castle = null; } } if (killer != null) { final L2PcInstance pk = killer.getActingPlayer(); + + // Message sent by the L2NpcProtectorInstance + if (killer instanceof L2NpcProtectorInstance) + { + L2NpcProtectorInstance npc = (L2NpcProtectorInstance) killer; + if (getKarma() > 0) + { + String regionName = MapRegionTable.getInstance().getClosestTownName(this); + + CreatureSay cs = new CreatureSay(npc.getObjectId(),Config.NPC_PROTECTOR_TEXT_CREATURE_SAY, "", Config.NPC_MESSAGE_PREFIX +" " + getName() + " (" + regionName + ") " + Config.NPC_PROTECTOR_MESSAGE_TEXT ); + Broadcast.toAllOnlinePlayers(cs); + } + } + // ///////////////////////////// + if (pk != null) { if (Config.ENABLE_PK_INFO) { doPkInfo(pk); } if (atEvent) { pk.kills.add(getName()); } if (_inEventTvT && pk._inEventTvT)