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)