diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml b/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml
index 171e08cb12..f9067f1377 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml
@@ -392,6 +392,9 @@
+
+
+
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini
new file mode 100644
index 0000000000..f745b0d31e
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini
@@ -0,0 +1,33 @@
+# ---------------------------------------------------------------------------
+# Fake players
+# ---------------------------------------------------------------------------
+
+# Enable fake players.
+EnableFakePlayers = False
+
+# Enable chatting with fake players.
+FakePlayerChat = True
+
+# Enable shots usage for fake players.
+FakePlayerUseShots = True
+
+# Reward PvP kills by killing fake players.
+FakePlayerKillsRewardPvP = True
+
+# Fake player kills apply karma rules.
+FakePlayerUnflaggedKillsKarma = True
+
+# Aggressive AI fake players attack nearby monsters.
+FakePlayerAggroMonsters = True
+
+# Aggressive AI fake players attack nearby players.
+FakePlayerAggroPlayers = False
+
+# Aggressive AI fake players attack nearby fake players.
+FakePlayerAggroFPC = False
+
+# Fake players can drop items when killing monsters.
+FakePlayerCanDropItems = True
+
+# Fake players can pickup dropped items.
+FakePlayerCanPickup = True
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml
new file mode 100644
index 0000000000..f5da5bfc8e
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml
new file mode 100644
index 0000000000..f36096ed4a
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml
index 98e0d38815..96e8e6ed81 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml
@@ -2402,4 +2402,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
index 6f29855cc3..d12ee2e7c4 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
@@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI
final L2Character creature = event.getSeen();
final L2Npc npc = (L2Npc) event.getSeer();
- if (creature.isPlayer())
+ if (creature.isPlayer() || creature.isFakePlayer())
{
npc.setTarget(creature);
npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill());
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
new file mode 100644
index 0000000000..e1dde7324e
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+import ai.AbstractNpcAI;
+
+/**
+ * TODO: Move it to L2Character.
+ * @author Mobius
+ */
+public class PvpFlaggingStopTask extends AbstractNpcAI
+{
+ private PvpFlaggingStopTask()
+ {
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if ((npc == null) || npc.isDead())
+ {
+ return null;
+ }
+
+ if (event.startsWith("FLAG_CHECK"))
+ {
+ final L2Object target = npc.getTarget();
+ if ((target != null) && (target.isPlayable() || target.isFakePlayer()))
+ {
+ npc.setScriptValue(1); // in combat
+ cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null);
+ cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null);
+ startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null);
+ startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null);
+ }
+ }
+ else if (event.startsWith("FINISH_FLAG"))
+ {
+ if (npc.isScriptValue(1))
+ {
+ npc.setScriptValue(2); // blink status
+ npc.broadcastInfo(); // update flag status
+ startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null);
+ }
+ }
+ else if (event.startsWith("REMOVE_FLAG"))
+ {
+ if (npc.isScriptValue(2))
+ {
+ npc.setScriptValue(0); // not in combat
+ npc.broadcastInfo(); // update flag status
+ }
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ public static void main(String[] args)
+ {
+ new PvpFlaggingStopTask();
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
new file mode 100644
index 0000000000..dec3449549
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.CommonUtil;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.base.ClassId;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
+import com.l2jmobius.gameserver.model.skills.SkillCaster;
+
+import ai.AbstractNpcAI;
+
+/**
+ * Town Fake Player walkers that receive buffs from Adventurer NPC.
+ * @author Mobius
+ */
+public class RecieveAdventurerBuffs extends AbstractNpcAI
+{
+ // NPCs
+ private static final int[] ADVENTURERS_GUIDE =
+ {
+ 32327,
+ 33950,
+ };
+ private static final int[] FAKE_PLAYER_IDS =
+ {
+ 80000
+ };
+ // Skills
+ // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
+ private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
+ private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
+ private static final SkillHolder[] GROUP_BUFFS =
+ {
+ new SkillHolder(15642, 1), // Horn Melody (Adventurer)
+ new SkillHolder(15643, 1), // Drum Melody (Adventurer)
+ new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
+ new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
+ new SkillHolder(15646, 1), // Harp Melody (Adventurer)
+ new SkillHolder(15647, 1), // Lute Melody (Adventurer)
+ new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
+ new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
+ new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
+ };
+
+ private RecieveAdventurerBuffs()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ addSpawnId(FAKE_PLAYER_IDS);
+ }
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead())
+ {
+ if (!npc.isMoving())
+ {
+ for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100))
+ {
+ if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId()))
+ {
+ for (SkillHolder holder : GROUP_BUFFS)
+ {
+ SkillCaster.triggerCast(nearby, npc, holder.getSkill());
+ }
+ if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage())
+ {
+ SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill());
+ }
+ else
+ {
+ SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill());
+ }
+ break;
+ }
+ }
+ }
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null);
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ @Override
+ public String onSpawn(L2Npc npc)
+ {
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null);
+ return super.onSpawn(npc);
+ }
+
+ public static void main(String[] args)
+ {
+ new RecieveAdventurerBuffs();
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java
index 666585bcab..ec9218857e 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
+import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -408,6 +409,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
+ AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
index 6b02816d9e..d6d6a99080 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
@@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (Config.ALT_GAME_VIEWNPC)
{
- if (!target.isNpc())
+ if (!target.isNpc() || target.isFakePlayer())
{
return false;
}
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
new file mode 100644
index 0000000000..99926f0df7
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package handlers.admincommandhandlers;
+
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author Mobius
+ */
+public class AdminFakePlayers implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_fakechat"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ if (command.startsWith("admin_fakechat"))
+ {
+ final String[] words = command.substring(15).split(" ");
+ if (words.length < 3)
+ {
+ activeChar.sendMessage("Usage: //fakechat playername fpcname message");
+ return false;
+ }
+ final L2PcInstance player = L2World.getInstance().getPlayer(words[0]);
+ if (player == null)
+ {
+ activeChar.sendMessage("Player not found.");
+ return false;
+ }
+ final String fpcName = FakePlayerData.getInstance().getProperName(words[1]);
+ if (fpcName == null)
+ {
+ activeChar.sendMessage("Fake player not found.");
+ return false;
+ }
+ String message = "";
+ for (int i = 0; i < words.length; i++)
+ {
+ if (i < 2)
+ {
+ continue;
+ }
+ message += (words[i] + " ");
+ }
+ FakePlayerChatManager.getInstance().sendChat(player, fpcName, message);
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
index 5da8e115b2..4799a7aa53 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
@@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
+ case "fakeplayers":
+ {
+ FakePlayerData.getInstance().load();
+ for (L2Object obj : L2World.getInstance().getVisibleObjects())
+ {
+ if (obj.isFakePlayer())
+ {
+ obj.broadcastInfo();
+ }
+ }
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
+ break;
+ }
+ case "fakeplayerchat":
+ {
+ FakePlayerChatManager.getInstance().load();
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
+ break;
+ }
default:
{
activeChar.sendMessage(RELOAD_USAGE);
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
index 99f2e9e9d7..7db79fe31d 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
@@ -17,8 +17,10 @@
package handlers.chathandlers;
import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IChatHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PcCondOverride;
@@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
+ if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
+ {
+ if (FakePlayerData.getInstance().isTalkable(target))
+ {
+ if (Config.FAKE_PLAYER_CHAT)
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target);
+ activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
+ FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
+ }
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
+ }
+ return;
+ }
+
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
index 41b1f99bcf..b38f5ca16d 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
@@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
-
}
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java
index 1e34a0d148..087112cc73 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java
@@ -16,9 +16,11 @@
*/
package handlers.playeractions;
+import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
+ player.onTransactionResponse();
+ }
+ }
+
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
- if ((target == null) || !target.isPlayer())
+ if ((target == null))
+ {
+ player.sendPacket(SystemMessageId.INVALID_TARGET);
+ return;
+ }
+
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
+ sm.addString(target.getName());
+ player.sendPacket(sm);
+ if (!player.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
+ player.blockRequest();
+ }
+ return;
+ }
+
+ if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
index b79fe7475a..5e1b48e51b 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
@@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest
@Id(WINDY_HEALING_POTION_1)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(4, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ {
+ qs.setCond(4, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
index 0efb5383f4..34594dbc40 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
@@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest
@Id(HIGH_GRADE_LOVE_POTION)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(2, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ {
+ qs.setCond(2, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml
new file mode 100644
index 0000000000..ea77878c2c
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml
new file mode 100644
index 0000000000..8470293122
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml
@@ -0,0 +1,341 @@
+
+
+
+
+ HUMAN
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ORC
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DWARF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KAMAEL
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HUMAN
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DARK_ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml
new file mode 100644
index 0000000000..589f29b215
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd
new file mode 100644
index 0000000000..2b2c94e75b
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd
new file mode 100644
index 0000000000..0628acefc3
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd
index 6f00944cff..ae80c3ff63 100644
--- a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd
+++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd
@@ -201,6 +201,8 @@
+
+
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java
index dd62606fa2..c4ea987b4d 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java
@@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
+ public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@@ -1146,6 +1147,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
+ public static boolean FAKE_PLAYERS_ENABLED;
+ public static boolean FAKE_PLAYER_CHAT;
+ public static boolean FAKE_PLAYER_USE_SHOTS;
+ public static boolean FAKE_PLAYER_KILL_PVP;
+ public static boolean FAKE_PLAYER_KILL_KARMA;
+ public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
+ public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
+ public static boolean FAKE_PLAYER_AGGRO_FPC;
+ public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
+ public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@@ -2558,6 +2569,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
+ // Load FakePlayers config file (if exists)
+ final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
+ FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
+ FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
+ FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
+ FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
+ FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
+ FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
+ FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
+ FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
+ FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
+ FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
+
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java
index 8fbd70bb6f..e2d108f174 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java
@@ -60,6 +60,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnchantSkillGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -109,6 +110,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
@@ -282,6 +284,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
+ FakePlayerData.getInstance();
+ FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
WalkingManager.getInstance();
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
index 6253fa9329..1da1b21546 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
@@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
- if (npc.isAggressive() || (npc instanceof L2GuardInstance))
+ if (npc.isFakePlayer() && npc.isAggressive())
+ {
+ final List droppedItems = npc.getFakePlayerDrops();
+ if (droppedItems.isEmpty())
+ {
+ L2Character nearestTarget = null;
+ double closestDistance = Double.MAX_VALUE;
+ for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange()))
+ {
+ if ((t == _actor) || (t == null) || t.isDead())
+ {
+ continue;
+ }
+ if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer()))
+ {
+ final int hating = npc.getHating(t);
+ final double distance = npc.calculateDistance(t, false, false);
+ if ((hating == 0) && (closestDistance > distance))
+ {
+ nearestTarget = t;
+ closestDistance = distance;
+ }
+ }
+ }
+ if (nearestTarget != null)
+ {
+ npc.addDamageHate(nearestTarget, 0, 1);
+ }
+ }
+ else if (!npc.isInCombat()) // must pickup items
+ {
+ final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped
+ final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex);
+ if ((droppedItem != null) && droppedItem.isSpawned())
+ {
+ if (npc.calculateDistance(droppedItem, false, false) > 50)
+ {
+ moveTo(droppedItem);
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ droppedItem.pickupMe(npc);
+ if (Config.SAVE_DROPPED_ITEM)
+ {
+ ItemsOnGroundManager.getInstance().removeObject(droppedItem);
+ }
+ if (droppedItem.getItem().hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills())
+ {
+ SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
+ }
+ npc.broadcastInfo(); // ? check if this is necessary
+ }
+ }
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ }
+ npc.setRunning();
+ }
+ }
+ else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
- if (t.isPlayable())
+ if (t.isFakePlayer())
+ {
+ if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
+ {
+ final int hating = npc.getHating(t);
+ if (hating == 0)
+ {
+ npc.addDamageHate(t, 0, 1);
+ }
+ }
+ }
+ else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
new file mode 100644
index 0000000000..0a6ca5267a
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerData implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName());
+
+ private final Map _fakePlayerInfos = new HashMap<>();
+ private final Map _fakePlayerNames = new HashMap<>();
+ private final Map _fakePlayerIds = new HashMap<>();
+ private final List _talkableFakePlayerNames = new ArrayList<>();
+
+ protected FakePlayerData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ _fakePlayerInfos.clear();
+ _fakePlayerNames.clear();
+ _fakePlayerIds.clear();
+ _talkableFakePlayerNames.clear();
+ parseDatapackFile("data/FakePlayerVisualData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode));
+ final int npcId = set.getInt("npcId");
+ final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
+ final String name = template.getName();
+ if (CharNameTable.getInstance().getIdByName(name) > 0)
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists.");
+ }
+ else
+ {
+ _fakePlayerIds.put(name, npcId); // name - npcId
+ _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name
+ _fakePlayerInfos.put(npcId, new FakePlayerHolder(set));
+ if (template.isFakePlayerTalkable())
+ {
+ _talkableFakePlayerNames.add(name.toLowerCase());
+ }
+ }
+ }));
+ }
+
+ public int getNpcIdByName(String name)
+ {
+ return _fakePlayerIds.get(name);
+ }
+
+ public String getProperName(String name)
+ {
+ return _fakePlayerNames.get(name.toLowerCase());
+ }
+
+ public Boolean isTalkable(String name)
+ {
+ return _talkableFakePlayerNames.contains(name.toLowerCase());
+ }
+
+ public FakePlayerHolder getInfo(int npcId)
+ {
+ return _fakePlayerInfos.get(npcId);
+ }
+
+ public static FakePlayerData getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerData _instance = new FakePlayerData();
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
index 883e877bc7..f03a2395f1 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
@@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader
set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty"));
+ set.set("fakePlayer", parseBoolean(attrs, "fakePlayer"));
+ set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable"));
break;
}
case "skill_list":
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
index 2ff4c9322d..15bd310bd6 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
@@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
+ if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
+ {
+ return;
+ }
+
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
index a145b65dba..d525c02a6a 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
@@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
-
if (target == null)
{
return false;
}
- final L2PcInstance bot = target.getActingPlayer();
+ final L2Character bot = ((L2Character) target);
- if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
+ if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
- if (bot.isInOlympiadMode())
+ if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
- if (bot.getExp() == bot.getStat().getStartingExp())
+ if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
- handleReport(bot, rcd);
+ if (bot.isPlayer())
+ {
+ handleReport(bot.getActingPlayer(), rcd);
+ }
return true;
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java
index 7454554076..ace19486b5 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
@@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
- * @param actor : L2PcInstance Player requesting the item creation
+ * @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
- public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
+ public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
index b621b4c4cb..bb0e928daf 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
@@ -217,6 +217,7 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
+ cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
// If the clan does not exist...
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
new file mode 100644
index 0000000000..16a0da92bc
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.instancemanager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.datatables.SpawnTable;
+import com.l2jmobius.gameserver.enums.ChatType;
+import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.model.L2Spawn;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
+import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
+
+/**
+ * @author Mobius
+ */
+public final class FakePlayerChatManager implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
+ final List MESSAGES = new ArrayList<>();
+ private static final int MIN_DELAY = 5000;
+ private static final int MAX_DELAY = 15000;
+
+ protected FakePlayerChatManager()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT)
+ {
+ MESSAGES.clear();
+ parseDatapackFile("data/FakePlayerChatData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode));
+ MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers")));
+ }));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
+ }
+
+ private void manageResponce(L2PcInstance player, String fpcName, String message)
+ {
+ if (player == null)
+ {
+ return;
+ }
+
+ final String text = message.toLowerCase();
+
+ // tricky question
+ if (text.contains("can you see me"))
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ if (npc.calculateDistance(player, false, false) < 3000)
+ {
+ if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
+ }
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
+ }
+ return;
+ }
+ }
+ }
+
+ for (FakePlayerChatHolder chatHolder : MESSAGES)
+ {
+ if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
+ {
+ continue;
+ }
+
+ switch (chatHolder.getSearchMethod())
+ {
+ case "EQUALS":
+ {
+ if (text.equals(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "STARTS_WITH":
+ {
+ if (text.startsWith(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "CONTAINS":
+ {
+ boolean allFound = true;
+ for (String word : chatHolder.getSearchText())
+ {
+ if (!text.contains(word))
+ {
+ allFound = false;
+ }
+ }
+ if (allFound)
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public void sendChat(L2PcInstance player, String fpcName, String message)
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
+ }
+ }
+ }
+
+ public static FakePlayerChatManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java
index 1a62714f0e..50a3cc2145 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
@@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class DropProtection implements Runnable
{
private volatile boolean _isProtected = false;
- private L2PcInstance _owner = null;
+ private L2Character _owner = null;
private ScheduledFuture> _task = null;
private static final long PROTECTED_MILLIS_TIME = 15000;
@@ -46,7 +47,7 @@ public class DropProtection implements Runnable
return _isProtected;
}
- public L2PcInstance getOwner()
+ public L2Character getOwner()
{
return _owner;
}
@@ -91,12 +92,12 @@ public class DropProtection implements Runnable
_task = null;
}
- public synchronized void protect(L2PcInstance player)
+ public synchronized void protect(L2Character character)
{
unprotect();
_isProtected = true;
- _owner = player;
+ _owner = character;
if (_owner == null)
{
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java
index 16c28a08d1..cc6e623f78 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java
@@ -365,6 +365,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
return false;
}
+ /**
+ * Verify if object is a fake player.
+ * @return {@code true} if object is a fake player, {@code false} otherwise
+ */
+ public boolean isFakePlayer()
+ {
+ return false;
+ }
+
/**
* Verify if object is instance of L2ServitorInstance.
* @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
index 5af3de0701..dd23f482b8 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
@@ -70,6 +70,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@@ -279,7 +280,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
- return _mustGiveExpSp;
+ return _mustGiveExpSp && !isFakePlayer();
}
/**
@@ -958,6 +959,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
+ // unless its a fake player and they can drop items
+ if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
+ {
+ final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);
+ if (deathItems != null)
+ {
+ for (ItemHolder drop : deathItems)
+ {
+ final L2Item item = ItemTable.getInstance().getTemplate(drop.getId());
+ // Check if the autoLoot mode is active
+ if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
+ {
+ // do nothing
+ }
+ else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : item.getAllSkills())
+ {
+ SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false);
+ }
+ mainDamageDealer.broadcastInfo(); // ? check if this is necessary
+ }
+ else
+ {
+ final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
+ if (Config.FAKE_PLAYER_CAN_PICKUP)
+ {
+ mainDamageDealer.getFakePlayerDrops().add(droppedItem);
+ }
+ }
+ }
+ }
+ }
return;
}
@@ -1045,7 +1079,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
- if (lastAttacker == null)
+ if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@@ -1419,6 +1453,15 @@ public class L2Attackable extends L2Npc
_harvestItem.set(null);
_sweepItems.set(null);
+ // fake players
+ if (isFakePlayer())
+ {
+ getFakePlayerDrops().clear(); // Clear existing fake player drops
+ setReputation(0); // reset reputation
+ setScriptValue(0); // remove pvp flag
+ setRunning(); // don't walk
+ }
+
// Clear mod Seeded stat
_seeded = false;
_seed = null;
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java
index be5178c202..b098378730 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java
@@ -29,6 +29,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -61,6 +62,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList;
@@ -136,6 +138,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -202,6 +205,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
+ private int _reputation = 0;
+
/** Map containing all skills of this character. */
private final Map _skills = new ConcurrentSkipListMap<>();
/** Map containing the skill reuse time stamps. */
@@ -270,6 +275,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
/** A map holding info about basic property mesmerizing system. */
private volatile Map _basicPropertyResists;
+ /** A list containing the dropped items of this fake player. */
+ private final List _fakePlayerDrops = new CopyOnWriteArrayList<>();
+
/**
* Creates a creature.
* @param template the creature template
@@ -1207,6 +1215,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
broadcastPacket(attack);
}
+ if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
+ {
+ final L2Npc npc = ((L2Npc) this);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+
// Notify AI with EVT_READY_TO_ACT
ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
}
@@ -2317,7 +2336,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -2945,7 +2968,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -4127,7 +4154,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
final Instance instanceWorld = getInstanceWorld();
- if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
+ if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
{
return false;
}
@@ -5535,6 +5562,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist());
}
+ public int getReputation()
+ {
+ return _reputation;
+ }
+
+ public void setReputation(int reputation)
+ {
+ _reputation = reputation;
+ }
+
/**
* Gets the distance to target.
* @param target the target
@@ -5549,4 +5586,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
+
+ public List getFakePlayerDrops()
+ {
+ return _fakePlayerDrops;
+ }
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
index 314ddd1f47..4802655840 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
@@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.enums.Team;
+import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.handler.BypassHandler;
import com.l2jmobius.gameserver.handler.IBypassHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
+import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
@@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
+import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@@ -125,6 +130,7 @@ public class L2Npc extends L2Character
private boolean _isRandomAnimationEnabled = true;
private boolean _isRandomWalkingEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
+ private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@@ -365,7 +371,11 @@ public class L2Npc extends L2Character
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@@ -902,6 +912,78 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
+ if (isFakePlayer() && (killer != null) && killer.isPlayable())
+ {
+ final L2PcInstance player = killer.getActingPlayer();
+ if (isScriptValue(0) && (getReputation() >= 0))
+ {
+ if (Config.FAKE_PLAYER_KILL_KARMA)
+ {
+ player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
+ player.setPkKills(player.getPkKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ player.checkItemRestriction();
+ // pk item rewards
+ if (Config.REWARD_PK_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
+ // announce pk
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+ else if (Config.FAKE_PLAYER_KILL_PVP)
+ {
+ player.setPvpKills(player.getPvpKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ // pvp item rewards
+ if (Config.REWARD_PVP_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ }
+ // announce pvp
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+
DecayTaskManager.getInstance().add(this);
final L2Spawn spawn = getSpawn();
@@ -1211,7 +1293,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ activeChar.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@@ -1455,12 +1541,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
- * @param player the last attacker or main damage dealer
+ * @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
+ public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@@ -1476,15 +1562,15 @@ public class L2Npc extends L2Character
return null;
}
- item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
+ item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
- if (player != null)
+ if (character != null)
{
- item.getDropProtection().protect(player);
+ item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@@ -1509,14 +1595,14 @@ public class L2Npc extends L2Character
}
/**
- * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
- * @param player the last attacker or main damage dealer
+ * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
+ * @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
+ public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
- return dropItem(player, item.getId(), item.getCount());
+ return dropItem(character, item.getId(), item.getCount());
}
@Override
@@ -1580,6 +1666,12 @@ public class L2Npc extends L2Character
return Config.SHOP_MIN_RANGE_FROM_NPC;
}
+ @Override
+ public boolean isFakePlayer()
+ {
+ return _isFakePlayer;
+ }
+
/**
* @return The player's object Id this NPC is cloning.
*/
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
index 34550c3dd8..10ad419ea4 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
@@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
- public abstract int getReputation();
-
public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove);
public abstract void storeMe();
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
index d58adad4db..42d728ea31 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
@@ -725,7 +725,7 @@ public abstract class L2Summon extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -743,7 +743,7 @@ public abstract class L2Summon extends L2Playable
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
@@ -905,6 +905,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
+ if (target.isFakePlayer())
+ {
+ getOwner().updatePvPStatus();
+ }
}
}
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
index a5fd31dedd..44ee919058 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
@@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
index aa4f132fce..6a94be63b5 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
@@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
- if (attacker.isMonster())
+ if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
+ if (isFakePlayer() && isInCombat())
+ {
+ interact = false;
+ // TODO: Fix normal targeting
+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
+ }
+
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
index e9a9976e87..fe55288a3a 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
@@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
+ if (isFakePlayer())
+ {
+ return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
+ }
+
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
@@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable
if (attacker.isMonster())
{
- return false;
+ return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
index 7f5114956a..3201c86040 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
@@ -445,9 +445,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
- /** The Reputation of the L2PcInstance */
- private int _reputation;
-
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@@ -1992,24 +1989,16 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
- /**
- * @return the reputation of the PlayerInstance.
- */
- @Override
- public int getReputation()
- {
- return _reputation;
- }
-
public void setInitialReputation(int reputation)
{
- _reputation = reputation;
+ super.setReputation(reputation);
}
/**
* Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param reputation
*/
+ @Override
public void setReputation(int reputation)
{
// Notify to scripts.
@@ -2035,7 +2024,9 @@ public final class L2PcInstance extends L2Playable
}
});
}
- _reputation = reputation;
+
+ super.setReputation(reputation);
+
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation()));
broadcastReputation();
}
@@ -4655,6 +4646,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
+ if (target.isFakePlayer())
+ {
+ updatePvPStatus();
+ }
}
@Override
@@ -4982,22 +4977,42 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
- if (pk != null)
+ final boolean fpcKill = killer.isFakePlayer();
+ if ((pk != null) || fpcKill)
{
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
-
- if (L2Event.isParticipant(pk))
+ if (pk != null)
{
- pk.getEventStatus().addKill(this);
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
+
+ if (L2Event.isParticipant(pk))
+ {
+ pk.getEventStatus().addKill(this);
+ }
+
+ // pvp/pk item rewards
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ // pvp
+ if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
+ {
+ pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ // pk
+ if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
+ {
+ pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
}
// announce pvp/pk
- if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
+ if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
- msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5011,7 +5026,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
- msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5025,20 +5040,9 @@ public final class L2PcInstance extends L2Playable
}
}
- // pvp/pk item rewards
- if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
- !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0))
{
- // pvp
- if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
- {
- pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
- }
- // pk
- if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
- {
- pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
- }
+ killer.setReputation(killer.getReputation() - 150);
}
}
@@ -5631,6 +5635,14 @@ public final class L2PcInstance extends L2Playable
return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks());
}
+ /**
+ * Used by fake players to emulate proper behavior.
+ */
+ public void blockRequest()
+ {
+ _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
+ }
+
/**
* Select the Warehouse to be used in next activity.
* @param partner
@@ -11568,7 +11580,7 @@ public final class L2PcInstance extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addPcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), -damage);
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
index fb6b184e67..8383d1efc9 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
@@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
+ @Override
public int getReputation()
{
return _owner != null ? _owner.getReputation() : 0;
@@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addCharName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
_owner.sendPacket(sm);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
index a97eab382d..26a51be541 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
@@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (attacker.isPlayable() && (caster.getCurrentCp() > 0))
+ if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (!ignoreCP && attacker.isPlayable())
+ if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{
@@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus
// Send a System Message to the L2PcInstance
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
smsg.addString(getActiveChar().getName());
- smsg.addCharName(attacker);
+ smsg.addString(attacker.getName());
smsg.addInt(fullValue);
getActiveChar().sendPacket(smsg);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
index 2d7f41e9d0..f5bee5dab6 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
@@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _randomWalk;
private boolean _randomAnimation;
private boolean _flying;
+ private boolean _fakePlayer;
+ private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard"));
_randomAnimation = set.getBoolean("randomAnimation", true);
_flying = set.getBoolean("flying", false);
+ _fakePlayer = set.getBoolean("fakePlayer", false);
+ _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
+ public boolean isFakePlayer()
+ {
+ return _fakePlayer;
+ }
+
+ public boolean isFakePlayerTalkable()
+ {
+ return _fakePlayerTalkable;
+ }
+
public boolean canMove()
{
return _canMove;
@@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
case LUCKY_DROP:
{
// try chance before luck
- if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck())
+ if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck())
{
return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax()));
}
@@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// chance
double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE;
}
@@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// amount is calculated after chance returned success
double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER;
// premium amount
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT;
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
index df9698d3c3..6cbe42b242 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
@@ -16,7 +16,7 @@
*/
package com.l2jmobius.gameserver.model.events.impl.item;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
@@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent
{
private final String _process;
private final L2ItemInstance _item;
- private final L2PcInstance _activeChar;
+ private final L2Character _activeChar;
private final Object _reference;
- public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference)
+ public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference)
{
_process = process;
_item = item;
@@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent
return _item;
}
- public L2PcInstance getActiveChar()
+ public L2Character getActiveChar()
{
return _activeChar;
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
new file mode 100644
index 0000000000..3008d340b3
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerChatHolder
+{
+ private final String _fpcName;
+ private final String _searchMethod;
+ private final List _searchText;
+ private final List _answers;
+
+ public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers)
+ {
+ _fpcName = fpcName;
+ _searchMethod = searchMethod;
+ _searchText = new ArrayList<>(Arrays.asList(searchText.split(";")));
+ _answers = new ArrayList<>(Arrays.asList(answers.split(";")));
+ }
+
+ public String getFpcName()
+ {
+ return _fpcName;
+ }
+
+ public String getSearchMethod()
+ {
+ return _searchMethod;
+ }
+
+ public List getSearchText()
+ {
+ return _searchText;
+ }
+
+ public List getAnswers()
+ {
+ return _answers;
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
new file mode 100644
index 0000000000..2f8aa1fa6d
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerHolder
+{
+ private final int _classId;
+ private final int _hair;
+ private final int _hairColor;
+ private final int _face;
+ private final int _nameColor;
+ private final int _titleColor;
+ private final int _equipHead;
+ private final int _equipRHand;
+ private final int _equipLHand;
+ private final int _equipGloves;
+ private final int _equipChest;
+ private final int _equipLegs;
+ private final int _equipFeet;
+ private final int _equipCloak;
+ private final int _equipHair;
+ private final int _equipHair2;
+ private final int _agathionId;
+ private final int _weaponEnchantLevel;
+ private final int _armorEnchantLevel;
+ private final boolean _fishing;
+ private final int _baitLocationX;
+ private final int _baitLocationY;
+ private final int _baitLocationZ;
+ private final int _recommends;
+ private final int _nobleLevel;
+ private final boolean _hero;
+ private final int _clanId;
+ private final int _pledgeStatus;
+
+ public FakePlayerHolder(StatsSet set)
+ {
+ _classId = set.getInt("classId", 182);
+
+ _hair = set.getInt("hair", 1);
+ _hairColor = set.getInt("hairColor", 1);
+ _face = set.getInt("face", 1);
+
+ _nameColor = set.getInt("nameColor", 0xFFFFFF);
+ _titleColor = set.getInt("titleColor", 0xECF9A2);
+
+ _equipHead = set.getInt("equipHead", 0);
+ _equipRHand = set.getInt("equipRHand", 0); // or dual hand
+ _equipLHand = set.getInt("equipLHand", 0);
+ _equipGloves = set.getInt("equipGloves", 0);
+ _equipChest = set.getInt("equipChest", 0);
+ _equipLegs = set.getInt("equipLegs", 0);
+ _equipFeet = set.getInt("equipFeet", 0);
+ _equipCloak = set.getInt("equipCloak", 0);
+ _equipHair = set.getInt("equipHair", 0);
+ _equipHair2 = set.getInt("equipHair2", 0);
+ _agathionId = set.getInt("agathionId", 0);
+
+ _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0);
+ _armorEnchantLevel = set.getInt("armorEnchantLevel", 0);
+
+ _fishing = set.getBoolean("fishing", false);
+ _baitLocationX = set.getInt("baitLocationX", 0);
+ _baitLocationY = set.getInt("baitLocationY", 0);
+ _baitLocationZ = set.getInt("baitLocationZ", 0);
+
+ _recommends = set.getInt("recommends", 0);
+ _nobleLevel = set.getInt("nobleLevel", 0);
+ _hero = set.getBoolean("hero", false);
+ _clanId = set.getInt("clanId", 0);
+ _pledgeStatus = set.getInt("pledgeStatus", 0);
+ }
+
+ public int getClassId()
+ {
+ return _classId;
+ }
+
+ public int getHair()
+ {
+ return _hair;
+ }
+
+ public int getHairColor()
+ {
+ return _hairColor;
+ }
+
+ public int getFace()
+ {
+ return _face;
+ }
+
+ public int getNameColor()
+ {
+ return _nameColor;
+ }
+
+ public int getTitleColor()
+ {
+ return _titleColor;
+ }
+
+ public int getEquipHead()
+ {
+ return _equipHead;
+ }
+
+ public int getEquipRHand()
+ {
+ return _equipRHand;
+ }
+
+ public int getEquipLHand()
+ {
+ return _equipLHand;
+ }
+
+ public int getEquipGloves()
+ {
+ return _equipGloves;
+ }
+
+ public int getEquipChest()
+ {
+ return _equipChest;
+ }
+
+ public int getEquipLegs()
+ {
+ return _equipLegs;
+ }
+
+ public int getEquipFeet()
+ {
+ return _equipFeet;
+ }
+
+ public int getEquipCloak()
+ {
+ return _equipCloak;
+ }
+
+ public int getEquipHair()
+ {
+ return _equipHair;
+ }
+
+ public int getEquipHair2()
+ {
+ return _equipHair2;
+ }
+
+ public int getAgathionId()
+ {
+ return _agathionId;
+ }
+
+ public int getWeaponEnchantLevel()
+ {
+ return _weaponEnchantLevel;
+ }
+
+ public int getArmorEnchantLevel()
+ {
+ return _armorEnchantLevel;
+ }
+
+ public boolean isFishing()
+ {
+ return _fishing;
+ }
+
+ public int getBaitLocationX()
+ {
+ return _baitLocationX;
+ }
+
+ public int getBaitLocationY()
+ {
+ return _baitLocationY;
+ }
+
+ public int getBaitLocationZ()
+ {
+ return _baitLocationZ;
+ }
+
+ public int getRecommends()
+ {
+ return _recommends;
+ }
+
+ public int getNobleLevel()
+ {
+ return _nobleLevel;
+ }
+
+ public boolean isHero()
+ {
+ return _hero;
+ }
+
+ public int getClanId()
+ {
+ return _clanId;
+ }
+
+ public int getPledgeStatus()
+ {
+ return _pledgeStatus;
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
index 65e361596b..190b26d291 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
@@ -277,16 +277,16 @@ public final class L2ItemInstance extends L2Object
*
* Do Pickup Item : PCInstance and Pet
*
- * @param player Player that pick up the item
+ * @param character Character that pick up the item
*/
- public final void pickupMe(L2Character player)
+ public final void pickupMe(L2Character character)
{
assert getWorldRegion() != null;
final L2WorldRegion oldregion = getWorldRegion();
// Create a server->client GetItem packet to pick up the L2ItemInstance
- player.broadcastPacket(new GetItem(this, player.getObjectId()));
+ character.broadcastPacket(new GetItem(this, character.getObjectId()));
synchronized (this)
{
@@ -305,10 +305,10 @@ public final class L2ItemInstance extends L2Object
// Remove the L2ItemInstance from the world
L2World.getInstance().removeVisibleObject(this, oldregion);
- if (player.isPlayer())
+ if (character.isPlayer())
{
// Notify to scripts
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem());
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem());
}
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java
index 98f374c294..ab8234a6e8 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java
@@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable
public boolean checkCondition(L2Character activeChar, L2Object object)
{
- if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)
+ if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION))
{
return true;
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
index b7eda58d00..13932008ff 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -159,7 +160,7 @@ public class SkillCaster implements Runnable
}
// You should not heal/buff monsters without pressing the ctrl button.
- if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed)
+ if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed)
{
caster.sendPacket(SystemMessageId.INVALID_TARGET);
return null;
@@ -609,6 +610,10 @@ public class SkillCaster implements Runnable
// Add hate to the attackable, and put it in the attack list.
((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint());
((L2Character) obj).addAttackerToAttackByList(caster);
+ if (obj.isFakePlayer())
+ {
+ player.updatePvPStatus();
+ }
}
// notify target AI about the attack
@@ -617,10 +622,19 @@ public class SkillCaster implements Runnable
((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster);
}
}
- else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0))))
+ else if (((skill.getEffectPoint() > 0) && obj.isMonster()) //
+ || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) //
+ || (((L2Character) obj).getReputation() < 0) //
+ )))
{
// Supporting players or monsters result in pvpflag.
- player.updatePvPStatus();
+ if (!obj.isFakePlayer() //
+ || (obj.isFakePlayer() //
+ && (!((L2Npc) obj).isScriptValue(0) //
+ || (((L2Npc) obj).getReputation() < 0))))
+ {
+ player.updatePvPStatus();
+ }
}
}
@@ -630,7 +644,7 @@ public class SkillCaster implements Runnable
EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob);
// On Skill See logic
- if (npcMob.isAttackable())
+ if (npcMob.isAttackable() && !npcMob.isFakePlayer())
{
final L2Attackable attackable = (L2Attackable) npcMob;
@@ -652,6 +666,19 @@ public class SkillCaster implements Runnable
}
});
}
+ else if (caster.isFakePlayer()) // fake player attacks player
+ {
+ if (target.isPlayable() || target.isFakePlayer())
+ {
+ final L2Npc npc = ((L2Npc) caster);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ npc.broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+ }
}
catch (Exception e)
{
@@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable
return false;
}
}
-
return true;
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
index fdf0dadf55..06bea1b4cf 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
@@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
@@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
@@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
index 91a9ce830a..ccd2d1d13a 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
@@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket
}
case 1:
{
- if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC))
+ if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer()))
{
obj.onAction(activeChar, false);
}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
index 876c53c093..06464d9911 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket
return;
}
- if (Config.FORBIDDEN_NAMES.length > 1)
+ if (Config.FORBIDDEN_NAMES.length > 0)
{
for (String st : Config.FORBIDDEN_NAMES)
{
@@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
+ return;
+ }
+
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
index 06bfa3c200..01c8b0c67f 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
@@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class RequestBlock implements IClientIncomingPacket
{
@@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket
case BLOCK:
case UNBLOCK:
{
+ // TODO: Save in database? :P
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (_type == BLOCK)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
// can't use block/unblock for locating invisible characters
if (targetId <= 0)
{
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
index ceb67b0f5f..cf79bdb24c 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable;
import com.l2jmobius.gameserver.util.Util;
@@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket
{
result = NAME_ALREADY_EXISTS;
}
+ else if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ result = NAME_ALREADY_EXISTS;
+ }
else if (_name.length() > 16)
{
result = INVALID_LENGTH;
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
index b0ace828dc..ee8bcd656b 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
@@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart;
@@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance activeChar = client.getActiveChar();
- final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (activeChar == null)
{
return;
}
+
+ if (FakePlayerData.getInstance().isTalkable(_player))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(_player);
+ if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ if (activeChar.isProcessingRequest())
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(name);
+ activeChar.sendPacket(msg);
+ return;
+ }
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000);
+ activeChar.blockRequest();
+ return;
+ }
+
+ final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (targetChar == null)
{
activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
index f104c94161..c0042d45c5 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
@@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Party;
@@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ if (player.getParty() == null)
+ {
+ player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED);
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY);
+ }
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance requestor = client.getActiveChar();
- final L2PcInstance target = L2World.getInstance().getPlayer(_name);
-
if (requestor == null)
{
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ requestor.sendPacket(sm);
+ if (!requestor.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000);
+ requestor.blockRequest();
+ }
+ else
+ {
+ requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY);
+ }
+ return;
+ }
+
+ final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (target == null)
{
requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
index 292153afd8..37c539556f 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
@@ -17,12 +17,15 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class ...
@@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return;
}
+ if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName())))
+ {
+ if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0)
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN);
+ }
+ else
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(activeChar.getTarget().getName());
+ activeChar.sendPacket(msg);
+ }
+ }
+ return;
+ }
+
final L2PcInstance target = L2World.getInstance().getPlayer(_target);
if (target == null)
{
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
index 3d5bcaeca5..9cbb114e88 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
@@ -23,6 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.BlockList;
@@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().isTalkable(_receiver))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1);
+ sm.addString(FakePlayerData.getInstance().getProperName(_receiver));
+ activeChar.sendPacket(sm);
+ return;
+ }
+
final int receiverId = CharNameTable.getInstance().getIdByName(_receiver);
if (receiverId <= 0)
{
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
index 8156905e94..1336c2bdb7 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
@@ -17,6 +17,7 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
@@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket
}
final L2Object object = activeChar.getTarget();
-
if (!(object instanceof L2PcInstance))
{
if (object == null)
{
client.sendPacket(SystemMessageId.SELECT_TARGET);
}
+ else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName()))
+ {
+ if (activeChar.getRecomLeft() <= 0)
+ {
+ client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER);
+ return;
+ }
+
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT);
+ sm.addString(FakePlayerData.getInstance().getProperName(object.getName()));
+ sm.addInt(activeChar.getRecomLeft());
+ client.sendPacket(sm);
+
+ activeChar.setRecomLeft(activeChar.getRecomLeft() - 1);
+ client.sendPacket(new UserInfo(activeChar));
+ client.sendPacket(new ExVoteSystemInfo(activeChar));
+ }
else
{
client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
index d77dc881b3..5d7e35eb43 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
@@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.skills.AbnormalType;
@@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target.getName());
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE));
+ return;
+ }
+ if (!player.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1);
+ sm.addString(name);
+ player.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000);
+ player.blockRequest();
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE);
+ }
+ return;
+ }
+
if (!target.isPlayer())
{
client.sendPacket(SystemMessageId.INVALID_TARGET);
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
index 4fa25283a7..530a6d7a01 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
@@ -17,6 +17,8 @@
package com.l2jmobius.gameserver.network.clientpackets.friend;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST));
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
final L2PcInstance friend = L2World.getInstance().getPlayer(_name);
// Target is not found in the game.
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
index 2170ef2e94..017541bd86 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
@@ -22,6 +22,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
- if (receiver.getFriendList().contains(sender.getObjectId()))
+ if (receiver != null)
{
- _mask |= 0x01;
- }
- if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
- {
- _mask |= 0x02;
- }
- if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
- {
- _mask |= 0x04;
- }
- if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
- {
- _mask |= 0x08;
+ if (receiver.getFriendList().contains(sender.getObjectId()))
+ {
+ _mask |= 0x01;
+ }
+ if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
+ {
+ _mask |= 0x02;
+ }
+ if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
+ {
+ _mask |= 0x04;
+ }
+ if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
+ {
+ _mask |= 0x08;
+ }
}
// Does not shows level
@@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket
}
}
+ /**
+ * Used by fake players.
+ * @param sender
+ * @param receiver
+ * @param name
+ * @param messageType
+ * @param text
+ */
+ public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
+ {
+ _objectId = sender.getObjectId();
+ _charName = name;
+ _charLevel = sender.getLevel();
+ _textType = messageType;
+ _text = text;
+ }
+
/**
* @param objectId
* @param messageType
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
new file mode 100644
index 0000000000..9ba3b311b6
--- /dev/null
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import java.util.Set;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.enums.Sex;
+import com.l2jmobius.gameserver.model.L2Clan;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerInfo implements IClientOutgoingPacket
+{
+ private final L2Npc _npc;
+ private final int _objId;
+ private final int _x, _y, _z, _heading;
+ private final int _mAtkSpd, _pAtkSpd;
+ private final int _runSpd, _walkSpd;
+ private final int _swimRunSpd;
+ private final int _swimWalkSpd;
+ private final int _flyRunSpd;
+ private final int _flyWalkSpd;
+ private final double _moveMultiplier;
+ private final float _attackSpeedMultiplier;
+ private final FakePlayerHolder _fpcHolder;
+ private final L2Clan _clan;
+
+ public FakePlayerInfo(L2Npc npc)
+ {
+ _npc = npc;
+ _objId = npc.getObjectId();
+ _x = npc.getX();
+ _y = npc.getY();
+ _z = npc.getZ();
+ _heading = npc.getHeading();
+ _mAtkSpd = npc.getMAtkSpd();
+ _pAtkSpd = npc.getPAtkSpd();
+ _attackSpeedMultiplier = npc.getAttackSpeedMultiplier();
+ _moveMultiplier = npc.getMovementSpeedMultiplier();
+ _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier);
+ _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier);
+ _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier);
+ _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier);
+ _flyRunSpd = npc.isFlying() ? _runSpd : 0;
+ _flyWalkSpd = npc.isFlying() ? _walkSpd : 0;
+ _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId());
+ _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId());
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.CHAR_INFO.writeId(packet);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(0x00); // vehicleId
+ packet.writeD(_objId);
+ packet.writeS(_npc.getName());
+
+ packet.writeH(_npc.getRace().ordinal());
+ packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00);
+ packet.writeD(_fpcHolder.getClassId());
+
+ packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER
+ packet.writeD(_fpcHolder.getEquipHead());
+ packet.writeD(_fpcHolder.getEquipRHand());
+ packet.writeD(_fpcHolder.getEquipLHand());
+ packet.writeD(_fpcHolder.getEquipGloves());
+ packet.writeD(_fpcHolder.getEquipChest());
+ packet.writeD(_fpcHolder.getEquipLegs());
+ packet.writeD(_fpcHolder.getEquipFeet());
+ packet.writeD(_fpcHolder.getEquipCloak());
+ packet.writeD(_fpcHolder.getEquipRHand()); // dual hand
+ packet.writeD(_fpcHolder.getEquipHair());
+ packet.writeD(_fpcHolder.getEquipHair2());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderAugument())
+ {
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(_fpcHolder.getArmorEnchantLevel());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderVisualId())
+ {
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(_npc.getScriptValue()); // getPvpFlag()
+ packet.writeD(_npc.getReputation());
+
+ packet.writeD(_mAtkSpd);
+ packet.writeD(_pAtkSpd);
+
+ packet.writeH(_runSpd);
+ packet.writeH(_walkSpd);
+ packet.writeH(_swimRunSpd);
+ packet.writeH(_swimWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeF(_moveMultiplier);
+ packet.writeF(_attackSpeedMultiplier);
+
+ packet.writeF(_npc.getCollisionRadius());
+ packet.writeF(_npc.getCollisionHeight());
+
+ packet.writeD(_fpcHolder.getHair());
+ packet.writeD(_fpcHolder.getHairColor());
+ packet.writeD(_fpcHolder.getFace());
+
+ packet.writeS(_npc.getTemplate().getTitle());
+
+ if (_clan != null)
+ {
+ packet.writeD(_clan.getId());
+ packet.writeD(_clan.getCrestId());
+ packet.writeD(_clan.getAllyId());
+ packet.writeD(_clan.getAllyCrestId());
+ }
+ else
+ {
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked)
+ packet.writeC(_npc.isRunning() ? 0x01 : 0x00);
+ packet.writeC(_npc.isInCombat() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isInvisible() ? 0x01 : 0x00);
+
+ packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount
+ packet.writeC(0x00); // getPrivateStoreType().getId()
+
+ packet.writeH(0x00); // getCubics().size()
+ // getCubics().keySet().forEach(packet::writeH);
+
+ packet.writeC(0x00);
+
+ packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0);
+ packet.writeH(_fpcHolder.getRecommends());
+ packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000
+
+ packet.writeD(_fpcHolder.getClassId());
+ packet.writeD(0x00);
+ packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel
+
+ packet.writeC(_npc.getTeam().getId());
+
+ packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00);
+ packet.writeC(_fpcHolder.getNobleLevel());
+ packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00);
+
+ packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00);
+
+ packet.writeD(_fpcHolder.getBaitLocationX());
+ packet.writeD(_fpcHolder.getBaitLocationY());
+ packet.writeD(_fpcHolder.getBaitLocationZ());
+
+ packet.writeD(_fpcHolder.getNameColor());
+
+ packet.writeD(_heading);
+
+ packet.writeC(_fpcHolder.getPledgeStatus());
+ packet.writeH(0x00); // getPledgeType()
+
+ packet.writeD(_fpcHolder.getTitleColor());
+
+ packet.writeC(0x00); // isCursedWeaponEquipped
+
+ packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0
+ packet.writeD(0x00); // getTransformationDisplayId()
+ packet.writeD(_fpcHolder.getAgathionId());
+
+ packet.writeC(0x00);
+
+ packet.writeD(0x00); // getCurrentCp()
+ packet.writeD(_npc.getMaxHp());
+ packet.writeD((int) Math.round(_npc.getCurrentHp()));
+ packet.writeD(_npc.getMaxMp());
+ packet.writeD((int) Math.round(_npc.getCurrentMp()));
+
+ packet.writeC(0x00);
+ final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects();
+ packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0));
+ for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects)
+ {
+ packet.writeH(abnormalVisualEffect.getClientId());
+ }
+ if (_npc.isInvisible())
+ {
+ packet.writeH(AbnormalVisualEffect.STEALTH.getClientId());
+ }
+ packet.writeC(0x00); // cocPlayer.getPosition()
+ packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00);
+ packet.writeC(0x00); // Used Ability Points
+ return true;
+ }
+}
diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
index 4fb1a757e6..c294edab2a 100644
--- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
+++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
@@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket
addComponentType(NpcInfoType.TITLE_NPCSTRINGID);
}
+ if (_npc.getReputation() != 0)
+ {
+ addComponentType(NpcInfoType.REPUTATION);
+ }
+
if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible())
{
addComponentType(NpcInfoType.ABNORMALS);
@@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket
}
if (containsMask(NpcInfoType.REPUTATION))
{
- packet.writeD(0x00); // Name color
+ packet.writeD(_npc.getReputation()); // Reputation
}
if (containsMask(NpcInfoType.CLAN))
{
diff --git a/L2J_Mobius_1.0_Ertheia/readme.txt b/L2J_Mobius_1.0_Ertheia/readme.txt
index a5606e61ff..324c1e9e52 100644
--- a/L2J_Mobius_1.0_Ertheia/readme.txt
+++ b/L2J_Mobius_1.0_Ertheia/readme.txt
@@ -82,6 +82,7 @@ Customs:
-Classmaster
-Community board
-Faction system
+-Fake players
-Find PvP
-NPC stat multipliers
-Realtime offline trade
diff --git a/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml b/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml
index 171e08cb12..f9067f1377 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml
@@ -392,6 +392,9 @@
+
+
+
diff --git a/L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini
new file mode 100644
index 0000000000..f745b0d31e
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini
@@ -0,0 +1,33 @@
+# ---------------------------------------------------------------------------
+# Fake players
+# ---------------------------------------------------------------------------
+
+# Enable fake players.
+EnableFakePlayers = False
+
+# Enable chatting with fake players.
+FakePlayerChat = True
+
+# Enable shots usage for fake players.
+FakePlayerUseShots = True
+
+# Reward PvP kills by killing fake players.
+FakePlayerKillsRewardPvP = True
+
+# Fake player kills apply karma rules.
+FakePlayerUnflaggedKillsKarma = True
+
+# Aggressive AI fake players attack nearby monsters.
+FakePlayerAggroMonsters = True
+
+# Aggressive AI fake players attack nearby players.
+FakePlayerAggroPlayers = False
+
+# Aggressive AI fake players attack nearby fake players.
+FakePlayerAggroFPC = False
+
+# Fake players can drop items when killing monsters.
+FakePlayerCanDropItems = True
+
+# Fake players can pickup dropped items.
+FakePlayerCanPickup = True
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml
new file mode 100644
index 0000000000..f5da5bfc8e
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml
new file mode 100644
index 0000000000..f36096ed4a
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml
index 98e0d38815..96e8e6ed81 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml
@@ -2402,4 +2402,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
index 6f29855cc3..d12ee2e7c4 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
@@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI
final L2Character creature = event.getSeen();
final L2Npc npc = (L2Npc) event.getSeer();
- if (creature.isPlayer())
+ if (creature.isPlayer() || creature.isFakePlayer())
{
npc.setTarget(creature);
npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill());
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
new file mode 100644
index 0000000000..e1dde7324e
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+import ai.AbstractNpcAI;
+
+/**
+ * TODO: Move it to L2Character.
+ * @author Mobius
+ */
+public class PvpFlaggingStopTask extends AbstractNpcAI
+{
+ private PvpFlaggingStopTask()
+ {
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if ((npc == null) || npc.isDead())
+ {
+ return null;
+ }
+
+ if (event.startsWith("FLAG_CHECK"))
+ {
+ final L2Object target = npc.getTarget();
+ if ((target != null) && (target.isPlayable() || target.isFakePlayer()))
+ {
+ npc.setScriptValue(1); // in combat
+ cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null);
+ cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null);
+ startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null);
+ startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null);
+ }
+ }
+ else if (event.startsWith("FINISH_FLAG"))
+ {
+ if (npc.isScriptValue(1))
+ {
+ npc.setScriptValue(2); // blink status
+ npc.broadcastInfo(); // update flag status
+ startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null);
+ }
+ }
+ else if (event.startsWith("REMOVE_FLAG"))
+ {
+ if (npc.isScriptValue(2))
+ {
+ npc.setScriptValue(0); // not in combat
+ npc.broadcastInfo(); // update flag status
+ }
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ public static void main(String[] args)
+ {
+ new PvpFlaggingStopTask();
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
new file mode 100644
index 0000000000..dec3449549
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.CommonUtil;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.base.ClassId;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
+import com.l2jmobius.gameserver.model.skills.SkillCaster;
+
+import ai.AbstractNpcAI;
+
+/**
+ * Town Fake Player walkers that receive buffs from Adventurer NPC.
+ * @author Mobius
+ */
+public class RecieveAdventurerBuffs extends AbstractNpcAI
+{
+ // NPCs
+ private static final int[] ADVENTURERS_GUIDE =
+ {
+ 32327,
+ 33950,
+ };
+ private static final int[] FAKE_PLAYER_IDS =
+ {
+ 80000
+ };
+ // Skills
+ // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
+ private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
+ private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
+ private static final SkillHolder[] GROUP_BUFFS =
+ {
+ new SkillHolder(15642, 1), // Horn Melody (Adventurer)
+ new SkillHolder(15643, 1), // Drum Melody (Adventurer)
+ new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
+ new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
+ new SkillHolder(15646, 1), // Harp Melody (Adventurer)
+ new SkillHolder(15647, 1), // Lute Melody (Adventurer)
+ new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
+ new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
+ new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
+ };
+
+ private RecieveAdventurerBuffs()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ addSpawnId(FAKE_PLAYER_IDS);
+ }
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead())
+ {
+ if (!npc.isMoving())
+ {
+ for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100))
+ {
+ if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId()))
+ {
+ for (SkillHolder holder : GROUP_BUFFS)
+ {
+ SkillCaster.triggerCast(nearby, npc, holder.getSkill());
+ }
+ if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage())
+ {
+ SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill());
+ }
+ else
+ {
+ SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill());
+ }
+ break;
+ }
+ }
+ }
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null);
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ @Override
+ public String onSpawn(L2Npc npc)
+ {
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null);
+ return super.onSpawn(npc);
+ }
+
+ public static void main(String[] args)
+ {
+ new RecieveAdventurerBuffs();
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java
index 01015c4d55..fd223930e4 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
+import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -409,6 +410,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
+ AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
index 6b02816d9e..d6d6a99080 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
@@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (Config.ALT_GAME_VIEWNPC)
{
- if (!target.isNpc())
+ if (!target.isNpc() || target.isFakePlayer())
{
return false;
}
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
new file mode 100644
index 0000000000..99926f0df7
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package handlers.admincommandhandlers;
+
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author Mobius
+ */
+public class AdminFakePlayers implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_fakechat"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ if (command.startsWith("admin_fakechat"))
+ {
+ final String[] words = command.substring(15).split(" ");
+ if (words.length < 3)
+ {
+ activeChar.sendMessage("Usage: //fakechat playername fpcname message");
+ return false;
+ }
+ final L2PcInstance player = L2World.getInstance().getPlayer(words[0]);
+ if (player == null)
+ {
+ activeChar.sendMessage("Player not found.");
+ return false;
+ }
+ final String fpcName = FakePlayerData.getInstance().getProperName(words[1]);
+ if (fpcName == null)
+ {
+ activeChar.sendMessage("Fake player not found.");
+ return false;
+ }
+ String message = "";
+ for (int i = 0; i < words.length; i++)
+ {
+ if (i < 2)
+ {
+ continue;
+ }
+ message += (words[i] + " ");
+ }
+ FakePlayerChatManager.getInstance().sendChat(player, fpcName, message);
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
index 5da8e115b2..4799a7aa53 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
@@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
+ case "fakeplayers":
+ {
+ FakePlayerData.getInstance().load();
+ for (L2Object obj : L2World.getInstance().getVisibleObjects())
+ {
+ if (obj.isFakePlayer())
+ {
+ obj.broadcastInfo();
+ }
+ }
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
+ break;
+ }
+ case "fakeplayerchat":
+ {
+ FakePlayerChatManager.getInstance().load();
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
+ break;
+ }
default:
{
activeChar.sendMessage(RELOAD_USAGE);
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
index 99f2e9e9d7..7db79fe31d 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
@@ -17,8 +17,10 @@
package handlers.chathandlers;
import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IChatHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PcCondOverride;
@@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
+ if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
+ {
+ if (FakePlayerData.getInstance().isTalkable(target))
+ {
+ if (Config.FAKE_PLAYER_CHAT)
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target);
+ activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
+ FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
+ }
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
+ }
+ return;
+ }
+
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
index 41b1f99bcf..b38f5ca16d 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
@@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
-
}
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java
index 1e34a0d148..087112cc73 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java
@@ -16,9 +16,11 @@
*/
package handlers.playeractions;
+import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
+ player.onTransactionResponse();
+ }
+ }
+
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
- if ((target == null) || !target.isPlayer())
+ if ((target == null))
+ {
+ player.sendPacket(SystemMessageId.INVALID_TARGET);
+ return;
+ }
+
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
+ sm.addString(target.getName());
+ player.sendPacket(sm);
+ if (!player.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
+ player.blockRequest();
+ }
+ return;
+ }
+
+ if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
index b79fe7475a..5e1b48e51b 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
@@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest
@Id(WINDY_HEALING_POTION_1)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(4, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ {
+ qs.setCond(4, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
index 0efb5383f4..34594dbc40 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
@@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest
@Id(HIGH_GRADE_LOVE_POTION)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(2, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ {
+ qs.setCond(2, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml
new file mode 100644
index 0000000000..ea77878c2c
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml
new file mode 100644
index 0000000000..8470293122
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml
@@ -0,0 +1,341 @@
+
+
+
+
+ HUMAN
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ORC
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DWARF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KAMAEL
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HUMAN
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DARK_ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml
new file mode 100644
index 0000000000..589f29b215
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd
new file mode 100644
index 0000000000..2b2c94e75b
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd
new file mode 100644
index 0000000000..0628acefc3
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd
index 6f00944cff..ae80c3ff63 100644
--- a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd
+++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd
@@ -201,6 +201,8 @@
+
+
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java
index f74df8f22f..1da64a6c7e 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java
@@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
+ public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@@ -1147,6 +1148,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
+ public static boolean FAKE_PLAYERS_ENABLED;
+ public static boolean FAKE_PLAYER_CHAT;
+ public static boolean FAKE_PLAYER_USE_SHOTS;
+ public static boolean FAKE_PLAYER_KILL_PVP;
+ public static boolean FAKE_PLAYER_KILL_KARMA;
+ public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
+ public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
+ public static boolean FAKE_PLAYER_AGGRO_FPC;
+ public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
+ public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@@ -2560,6 +2571,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
+ // Load FakePlayers config file (if exists)
+ final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
+ FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
+ FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
+ FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
+ FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
+ FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
+ FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
+ FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
+ FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
+ FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
+ FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
+
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java
index 802ea4e498..09ca886b87 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java
@@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
@@ -288,6 +290,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
+ FakePlayerData.getInstance();
+ FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
WalkingManager.getInstance();
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
index 6253fa9329..1da1b21546 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
@@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
- if (npc.isAggressive() || (npc instanceof L2GuardInstance))
+ if (npc.isFakePlayer() && npc.isAggressive())
+ {
+ final List droppedItems = npc.getFakePlayerDrops();
+ if (droppedItems.isEmpty())
+ {
+ L2Character nearestTarget = null;
+ double closestDistance = Double.MAX_VALUE;
+ for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange()))
+ {
+ if ((t == _actor) || (t == null) || t.isDead())
+ {
+ continue;
+ }
+ if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer()))
+ {
+ final int hating = npc.getHating(t);
+ final double distance = npc.calculateDistance(t, false, false);
+ if ((hating == 0) && (closestDistance > distance))
+ {
+ nearestTarget = t;
+ closestDistance = distance;
+ }
+ }
+ }
+ if (nearestTarget != null)
+ {
+ npc.addDamageHate(nearestTarget, 0, 1);
+ }
+ }
+ else if (!npc.isInCombat()) // must pickup items
+ {
+ final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped
+ final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex);
+ if ((droppedItem != null) && droppedItem.isSpawned())
+ {
+ if (npc.calculateDistance(droppedItem, false, false) > 50)
+ {
+ moveTo(droppedItem);
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ droppedItem.pickupMe(npc);
+ if (Config.SAVE_DROPPED_ITEM)
+ {
+ ItemsOnGroundManager.getInstance().removeObject(droppedItem);
+ }
+ if (droppedItem.getItem().hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills())
+ {
+ SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
+ }
+ npc.broadcastInfo(); // ? check if this is necessary
+ }
+ }
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ }
+ npc.setRunning();
+ }
+ }
+ else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
- if (t.isPlayable())
+ if (t.isFakePlayer())
+ {
+ if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
+ {
+ final int hating = npc.getHating(t);
+ if (hating == 0)
+ {
+ npc.addDamageHate(t, 0, 1);
+ }
+ }
+ }
+ else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
new file mode 100644
index 0000000000..0a6ca5267a
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerData implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName());
+
+ private final Map _fakePlayerInfos = new HashMap<>();
+ private final Map _fakePlayerNames = new HashMap<>();
+ private final Map _fakePlayerIds = new HashMap<>();
+ private final List _talkableFakePlayerNames = new ArrayList<>();
+
+ protected FakePlayerData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ _fakePlayerInfos.clear();
+ _fakePlayerNames.clear();
+ _fakePlayerIds.clear();
+ _talkableFakePlayerNames.clear();
+ parseDatapackFile("data/FakePlayerVisualData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode));
+ final int npcId = set.getInt("npcId");
+ final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
+ final String name = template.getName();
+ if (CharNameTable.getInstance().getIdByName(name) > 0)
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists.");
+ }
+ else
+ {
+ _fakePlayerIds.put(name, npcId); // name - npcId
+ _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name
+ _fakePlayerInfos.put(npcId, new FakePlayerHolder(set));
+ if (template.isFakePlayerTalkable())
+ {
+ _talkableFakePlayerNames.add(name.toLowerCase());
+ }
+ }
+ }));
+ }
+
+ public int getNpcIdByName(String name)
+ {
+ return _fakePlayerIds.get(name);
+ }
+
+ public String getProperName(String name)
+ {
+ return _fakePlayerNames.get(name.toLowerCase());
+ }
+
+ public Boolean isTalkable(String name)
+ {
+ return _talkableFakePlayerNames.contains(name.toLowerCase());
+ }
+
+ public FakePlayerHolder getInfo(int npcId)
+ {
+ return _fakePlayerInfos.get(npcId);
+ }
+
+ public static FakePlayerData getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerData _instance = new FakePlayerData();
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
index 883e877bc7..f03a2395f1 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
@@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader
set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty"));
+ set.set("fakePlayer", parseBoolean(attrs, "fakePlayer"));
+ set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable"));
break;
}
case "skill_list":
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
index 2ff4c9322d..15bd310bd6 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
@@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
+ if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
+ {
+ return;
+ }
+
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
index a145b65dba..d525c02a6a 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
@@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
-
if (target == null)
{
return false;
}
- final L2PcInstance bot = target.getActingPlayer();
+ final L2Character bot = ((L2Character) target);
- if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
+ if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
- if (bot.isInOlympiadMode())
+ if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
- if (bot.getExp() == bot.getStat().getStartingExp())
+ if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
- handleReport(bot, rcd);
+ if (bot.isPlayer())
+ {
+ handleReport(bot.getActingPlayer(), rcd);
+ }
return true;
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java
index 7454554076..ace19486b5 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
@@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
- * @param actor : L2PcInstance Player requesting the item creation
+ * @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
- public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
+ public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
index b621b4c4cb..bb0e928daf 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
@@ -217,6 +217,7 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
+ cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
// If the clan does not exist...
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
new file mode 100644
index 0000000000..16a0da92bc
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.instancemanager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.datatables.SpawnTable;
+import com.l2jmobius.gameserver.enums.ChatType;
+import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.model.L2Spawn;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
+import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
+
+/**
+ * @author Mobius
+ */
+public final class FakePlayerChatManager implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
+ final List MESSAGES = new ArrayList<>();
+ private static final int MIN_DELAY = 5000;
+ private static final int MAX_DELAY = 15000;
+
+ protected FakePlayerChatManager()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT)
+ {
+ MESSAGES.clear();
+ parseDatapackFile("data/FakePlayerChatData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode));
+ MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers")));
+ }));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
+ }
+
+ private void manageResponce(L2PcInstance player, String fpcName, String message)
+ {
+ if (player == null)
+ {
+ return;
+ }
+
+ final String text = message.toLowerCase();
+
+ // tricky question
+ if (text.contains("can you see me"))
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ if (npc.calculateDistance(player, false, false) < 3000)
+ {
+ if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
+ }
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
+ }
+ return;
+ }
+ }
+ }
+
+ for (FakePlayerChatHolder chatHolder : MESSAGES)
+ {
+ if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
+ {
+ continue;
+ }
+
+ switch (chatHolder.getSearchMethod())
+ {
+ case "EQUALS":
+ {
+ if (text.equals(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "STARTS_WITH":
+ {
+ if (text.startsWith(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "CONTAINS":
+ {
+ boolean allFound = true;
+ for (String word : chatHolder.getSearchText())
+ {
+ if (!text.contains(word))
+ {
+ allFound = false;
+ }
+ }
+ if (allFound)
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public void sendChat(L2PcInstance player, String fpcName, String message)
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
+ }
+ }
+ }
+
+ public static FakePlayerChatManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java
index 1a62714f0e..50a3cc2145 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
@@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class DropProtection implements Runnable
{
private volatile boolean _isProtected = false;
- private L2PcInstance _owner = null;
+ private L2Character _owner = null;
private ScheduledFuture> _task = null;
private static final long PROTECTED_MILLIS_TIME = 15000;
@@ -46,7 +47,7 @@ public class DropProtection implements Runnable
return _isProtected;
}
- public L2PcInstance getOwner()
+ public L2Character getOwner()
{
return _owner;
}
@@ -91,12 +92,12 @@ public class DropProtection implements Runnable
_task = null;
}
- public synchronized void protect(L2PcInstance player)
+ public synchronized void protect(L2Character character)
{
unprotect();
_isProtected = true;
- _owner = player;
+ _owner = character;
if (_owner == null)
{
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java
index 459660c7ca..92837e4b25 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java
@@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
return false;
}
+ /**
+ * Verify if object is a fake player.
+ * @return {@code true} if object is a fake player, {@code false} otherwise
+ */
+ public boolean isFakePlayer()
+ {
+ return false;
+ }
+
/**
* Verify if object is instance of L2ServitorInstance.
* @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
index 2ecce60d39..ddc1a1b8d4 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
@@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
- return _mustGiveExpSp;
+ return _mustGiveExpSp && !isFakePlayer();
}
/**
@@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
+ // unless its a fake player and they can drop items
+ if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
+ {
+ final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);
+ if (deathItems != null)
+ {
+ for (ItemHolder drop : deathItems)
+ {
+ final L2Item item = ItemTable.getInstance().getTemplate(drop.getId());
+ // Check if the autoLoot mode is active
+ if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
+ {
+ // do nothing
+ }
+ else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : item.getAllSkills())
+ {
+ SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false);
+ }
+ mainDamageDealer.broadcastInfo(); // ? check if this is necessary
+ }
+ else
+ {
+ final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
+ if (Config.FAKE_PLAYER_CAN_PICKUP)
+ {
+ mainDamageDealer.getFakePlayerDrops().add(droppedItem);
+ }
+ }
+ }
+ }
+ }
return;
}
@@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
- if (lastAttacker == null)
+ if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc
_harvestItem.set(null);
_sweepItems.set(null);
+ // fake players
+ if (isFakePlayer())
+ {
+ getFakePlayerDrops().clear(); // Clear existing fake player drops
+ setReputation(0); // reset reputation
+ setScriptValue(0); // remove pvp flag
+ setRunning(); // don't walk
+ }
+
// Clear mod Seeded stat
_seeded = false;
_seed = null;
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java
index 226b8e981a..6dd50e079f 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java
@@ -30,6 +30,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList;
@@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
+ private int _reputation = 0;
+
/** Map containing all skills of this character. */
private final Map _skills = new ConcurrentSkipListMap<>();
/** Map containing the skill reuse time stamps. */
@@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
/** A set containing the shot types currently charged. */
private Set _chargedShots = EnumSet.noneOf(ShotType.class);
+ /** A list containing the dropped items of this fake player. */
+ private final List _fakePlayerDrops = new CopyOnWriteArrayList<>();
+
/**
* Creates a creature.
* @param template the creature template
@@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
broadcastPacket(attack);
}
+ if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
+ {
+ final L2Npc npc = ((L2Npc) this);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+
// Notify AI with EVT_READY_TO_ACT
ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
}
@@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
final Instance instanceWorld = getInstanceWorld();
- if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
+ if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
{
return false;
}
@@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist());
}
+ public int getReputation()
+ {
+ return _reputation;
+ }
+
+ public void setReputation(int reputation)
+ {
+ _reputation = reputation;
+ }
+
/**
* Gets the distance to target.
* @param target the target
@@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
+
+ public List getFakePlayerDrops()
+ {
+ return _fakePlayerDrops;
+ }
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
index 5742c07807..b669e16e76 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
@@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.enums.Team;
+import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.handler.BypassHandler;
import com.l2jmobius.gameserver.handler.IBypassHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
+import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
@@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
+import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@@ -125,6 +130,7 @@ public class L2Npc extends L2Character
private boolean _isRandomAnimationEnabled = true;
private boolean _isRandomWalkingEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
+ private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@@ -364,7 +370,11 @@ public class L2Npc extends L2Character
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@@ -901,6 +911,78 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
+ if (isFakePlayer() && (killer != null) && killer.isPlayable())
+ {
+ final L2PcInstance player = killer.getActingPlayer();
+ if (isScriptValue(0) && (getReputation() >= 0))
+ {
+ if (Config.FAKE_PLAYER_KILL_KARMA)
+ {
+ player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
+ player.setPkKills(player.getPkKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ player.checkItemRestriction();
+ // pk item rewards
+ if (Config.REWARD_PK_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
+ // announce pk
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+ else if (Config.FAKE_PLAYER_KILL_PVP)
+ {
+ player.setPvpKills(player.getPvpKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ // pvp item rewards
+ if (Config.REWARD_PVP_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ }
+ // announce pvp
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+
DecayTaskManager.getInstance().add(this);
final L2Spawn spawn = getSpawn();
@@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ activeChar.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character
@Override
public void rechargeShots(boolean physical, boolean magic, boolean fish)
{
- if (physical && (_soulshotamount > 0))
+ if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS)
{
- if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ if (physical)
{
- return;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic)
+ {
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _soulshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
- chargeShot(ShotType.SOULSHOTS);
}
-
- if (magic && (_spiritshotamount > 0))
+ else
{
- if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ if (physical && (_soulshotamount > 0))
{
- return;
+ if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ {
+ return;
+ }
+ _soulshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic && (_spiritshotamount > 0))
+ {
+ if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ {
+ return;
+ }
+ _spiritshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _spiritshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
- chargeShot(ShotType.SPIRITSHOTS);
}
}
@@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
- * @param player the last attacker or main damage dealer
+ * @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
+ public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character
return null;
}
- item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
+ item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
- if (player != null)
+ if (character != null)
{
- item.getDropProtection().protect(player);
+ item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character
}
/**
- * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
- * @param player the last attacker or main damage dealer
+ * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
+ * @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
+ public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
- return dropItem(player, item.getId(), item.getCount());
+ return dropItem(character, item.getId(), item.getCount());
}
@Override
@@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character
return Config.SHOP_MIN_RANGE_FROM_NPC;
}
+ @Override
+ public boolean isFakePlayer()
+ {
+ return _isFakePlayer;
+ }
+
/**
* @return The player's object Id this NPC is cloning.
*/
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
index 34550c3dd8..10ad419ea4 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
@@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
- public abstract int getReputation();
-
public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove);
public abstract void storeMe();
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
index dab0c5323a..80c2783883 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
@@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
@@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
+ if (target.isFakePlayer())
+ {
+ getOwner().updatePvPStatus();
+ }
}
}
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
index a5fd31dedd..44ee919058 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
@@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
index aa4f132fce..6a94be63b5 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
@@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
- if (attacker.isMonster())
+ if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
+ if (isFakePlayer() && isInCombat())
+ {
+ interact = false;
+ // TODO: Fix normal targeting
+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
+ }
+
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
index e9a9976e87..fe55288a3a 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
@@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
+ if (isFakePlayer())
+ {
+ return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
+ }
+
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
@@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable
if (attacker.isMonster())
{
- return false;
+ return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
index 6a4bd24efe..9429bcdb82 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
@@ -444,9 +444,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
- /** The Reputation of the L2PcInstance */
- private int _reputation;
-
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@@ -1991,24 +1988,16 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
- /**
- * @return the reputation of the PlayerInstance.
- */
- @Override
- public int getReputation()
- {
- return _reputation;
- }
-
public void setInitialReputation(int reputation)
{
- _reputation = reputation;
+ super.setReputation(reputation);
}
/**
* Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param reputation
*/
+ @Override
public void setReputation(int reputation)
{
// Notify to scripts.
@@ -2034,7 +2023,9 @@ public final class L2PcInstance extends L2Playable
}
});
}
- _reputation = reputation;
+
+ super.setReputation(reputation);
+
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation()));
broadcastReputation();
}
@@ -4654,6 +4645,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
+ if (target.isFakePlayer())
+ {
+ updatePvPStatus();
+ }
}
@Override
@@ -4981,22 +4976,42 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
- if (pk != null)
+ final boolean fpcKill = killer.isFakePlayer();
+ if ((pk != null) || fpcKill)
{
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
-
- if (L2Event.isParticipant(pk))
+ if (pk != null)
{
- pk.getEventStatus().addKill(this);
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
+
+ if (L2Event.isParticipant(pk))
+ {
+ pk.getEventStatus().addKill(this);
+ }
+
+ // pvp/pk item rewards
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ // pvp
+ if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
+ {
+ pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ // pk
+ if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
+ {
+ pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
}
// announce pvp/pk
- if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
+ if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
- msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5010,7 +5025,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
- msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5024,20 +5039,9 @@ public final class L2PcInstance extends L2Playable
}
}
- // pvp/pk item rewards
- if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
- !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0))
{
- // pvp
- if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
- {
- pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
- }
- // pk
- if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
- {
- pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
- }
+ killer.setReputation(killer.getReputation() - 150);
}
}
@@ -5630,6 +5634,14 @@ public final class L2PcInstance extends L2Playable
return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks());
}
+ /**
+ * Used by fake players to emulate proper behavior.
+ */
+ public void blockRequest()
+ {
+ _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
+ }
+
/**
* Select the Warehouse to be used in next activity.
* @param partner
@@ -11569,7 +11581,7 @@ public final class L2PcInstance extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addPcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), -damage);
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
index fb6b184e67..8383d1efc9 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
@@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
+ @Override
public int getReputation()
{
return _owner != null ? _owner.getReputation() : 0;
@@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addCharName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
_owner.sendPacket(sm);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
index a97eab382d..26a51be541 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
@@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (attacker.isPlayable() && (caster.getCurrentCp() > 0))
+ if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (!ignoreCP && attacker.isPlayable())
+ if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{
@@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus
// Send a System Message to the L2PcInstance
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
smsg.addString(getActiveChar().getName());
- smsg.addCharName(attacker);
+ smsg.addString(attacker.getName());
smsg.addInt(fullValue);
getActiveChar().sendPacket(smsg);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
index 2d7f41e9d0..f5bee5dab6 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
@@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _randomWalk;
private boolean _randomAnimation;
private boolean _flying;
+ private boolean _fakePlayer;
+ private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard"));
_randomAnimation = set.getBoolean("randomAnimation", true);
_flying = set.getBoolean("flying", false);
+ _fakePlayer = set.getBoolean("fakePlayer", false);
+ _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
+ public boolean isFakePlayer()
+ {
+ return _fakePlayer;
+ }
+
+ public boolean isFakePlayerTalkable()
+ {
+ return _fakePlayerTalkable;
+ }
+
public boolean canMove()
{
return _canMove;
@@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
case LUCKY_DROP:
{
// try chance before luck
- if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck())
+ if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck())
{
return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax()));
}
@@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// chance
double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE;
}
@@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// amount is calculated after chance returned success
double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER;
// premium amount
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT;
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
index df9698d3c3..6cbe42b242 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
@@ -16,7 +16,7 @@
*/
package com.l2jmobius.gameserver.model.events.impl.item;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
@@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent
{
private final String _process;
private final L2ItemInstance _item;
- private final L2PcInstance _activeChar;
+ private final L2Character _activeChar;
private final Object _reference;
- public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference)
+ public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference)
{
_process = process;
_item = item;
@@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent
return _item;
}
- public L2PcInstance getActiveChar()
+ public L2Character getActiveChar()
{
return _activeChar;
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
new file mode 100644
index 0000000000..3008d340b3
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerChatHolder
+{
+ private final String _fpcName;
+ private final String _searchMethod;
+ private final List _searchText;
+ private final List _answers;
+
+ public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers)
+ {
+ _fpcName = fpcName;
+ _searchMethod = searchMethod;
+ _searchText = new ArrayList<>(Arrays.asList(searchText.split(";")));
+ _answers = new ArrayList<>(Arrays.asList(answers.split(";")));
+ }
+
+ public String getFpcName()
+ {
+ return _fpcName;
+ }
+
+ public String getSearchMethod()
+ {
+ return _searchMethod;
+ }
+
+ public List getSearchText()
+ {
+ return _searchText;
+ }
+
+ public List getAnswers()
+ {
+ return _answers;
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
new file mode 100644
index 0000000000..2f8aa1fa6d
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerHolder
+{
+ private final int _classId;
+ private final int _hair;
+ private final int _hairColor;
+ private final int _face;
+ private final int _nameColor;
+ private final int _titleColor;
+ private final int _equipHead;
+ private final int _equipRHand;
+ private final int _equipLHand;
+ private final int _equipGloves;
+ private final int _equipChest;
+ private final int _equipLegs;
+ private final int _equipFeet;
+ private final int _equipCloak;
+ private final int _equipHair;
+ private final int _equipHair2;
+ private final int _agathionId;
+ private final int _weaponEnchantLevel;
+ private final int _armorEnchantLevel;
+ private final boolean _fishing;
+ private final int _baitLocationX;
+ private final int _baitLocationY;
+ private final int _baitLocationZ;
+ private final int _recommends;
+ private final int _nobleLevel;
+ private final boolean _hero;
+ private final int _clanId;
+ private final int _pledgeStatus;
+
+ public FakePlayerHolder(StatsSet set)
+ {
+ _classId = set.getInt("classId", 182);
+
+ _hair = set.getInt("hair", 1);
+ _hairColor = set.getInt("hairColor", 1);
+ _face = set.getInt("face", 1);
+
+ _nameColor = set.getInt("nameColor", 0xFFFFFF);
+ _titleColor = set.getInt("titleColor", 0xECF9A2);
+
+ _equipHead = set.getInt("equipHead", 0);
+ _equipRHand = set.getInt("equipRHand", 0); // or dual hand
+ _equipLHand = set.getInt("equipLHand", 0);
+ _equipGloves = set.getInt("equipGloves", 0);
+ _equipChest = set.getInt("equipChest", 0);
+ _equipLegs = set.getInt("equipLegs", 0);
+ _equipFeet = set.getInt("equipFeet", 0);
+ _equipCloak = set.getInt("equipCloak", 0);
+ _equipHair = set.getInt("equipHair", 0);
+ _equipHair2 = set.getInt("equipHair2", 0);
+ _agathionId = set.getInt("agathionId", 0);
+
+ _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0);
+ _armorEnchantLevel = set.getInt("armorEnchantLevel", 0);
+
+ _fishing = set.getBoolean("fishing", false);
+ _baitLocationX = set.getInt("baitLocationX", 0);
+ _baitLocationY = set.getInt("baitLocationY", 0);
+ _baitLocationZ = set.getInt("baitLocationZ", 0);
+
+ _recommends = set.getInt("recommends", 0);
+ _nobleLevel = set.getInt("nobleLevel", 0);
+ _hero = set.getBoolean("hero", false);
+ _clanId = set.getInt("clanId", 0);
+ _pledgeStatus = set.getInt("pledgeStatus", 0);
+ }
+
+ public int getClassId()
+ {
+ return _classId;
+ }
+
+ public int getHair()
+ {
+ return _hair;
+ }
+
+ public int getHairColor()
+ {
+ return _hairColor;
+ }
+
+ public int getFace()
+ {
+ return _face;
+ }
+
+ public int getNameColor()
+ {
+ return _nameColor;
+ }
+
+ public int getTitleColor()
+ {
+ return _titleColor;
+ }
+
+ public int getEquipHead()
+ {
+ return _equipHead;
+ }
+
+ public int getEquipRHand()
+ {
+ return _equipRHand;
+ }
+
+ public int getEquipLHand()
+ {
+ return _equipLHand;
+ }
+
+ public int getEquipGloves()
+ {
+ return _equipGloves;
+ }
+
+ public int getEquipChest()
+ {
+ return _equipChest;
+ }
+
+ public int getEquipLegs()
+ {
+ return _equipLegs;
+ }
+
+ public int getEquipFeet()
+ {
+ return _equipFeet;
+ }
+
+ public int getEquipCloak()
+ {
+ return _equipCloak;
+ }
+
+ public int getEquipHair()
+ {
+ return _equipHair;
+ }
+
+ public int getEquipHair2()
+ {
+ return _equipHair2;
+ }
+
+ public int getAgathionId()
+ {
+ return _agathionId;
+ }
+
+ public int getWeaponEnchantLevel()
+ {
+ return _weaponEnchantLevel;
+ }
+
+ public int getArmorEnchantLevel()
+ {
+ return _armorEnchantLevel;
+ }
+
+ public boolean isFishing()
+ {
+ return _fishing;
+ }
+
+ public int getBaitLocationX()
+ {
+ return _baitLocationX;
+ }
+
+ public int getBaitLocationY()
+ {
+ return _baitLocationY;
+ }
+
+ public int getBaitLocationZ()
+ {
+ return _baitLocationZ;
+ }
+
+ public int getRecommends()
+ {
+ return _recommends;
+ }
+
+ public int getNobleLevel()
+ {
+ return _nobleLevel;
+ }
+
+ public boolean isHero()
+ {
+ return _hero;
+ }
+
+ public int getClanId()
+ {
+ return _clanId;
+ }
+
+ public int getPledgeStatus()
+ {
+ return _pledgeStatus;
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
index c5af087f72..551733f42a 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
@@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object
*
* Do Pickup Item : PCInstance and Pet
*
- * @param player Player that pick up the item
+ * @param character Character that pick up the item
*/
- public final void pickupMe(L2Character player)
+ public final void pickupMe(L2Character character)
{
assert getWorldRegion() != null;
final L2WorldRegion oldregion = getWorldRegion();
// Create a server->client GetItem packet to pick up the L2ItemInstance
- player.broadcastPacket(new GetItem(this, player.getObjectId()));
+ character.broadcastPacket(new GetItem(this, character.getObjectId()));
synchronized (this)
{
@@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object
// Remove the L2ItemInstance from the world
L2World.getInstance().removeVisibleObject(this, oldregion);
- if (player.isPlayer())
+ if (character.isPlayer())
{
// Notify to scripts
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem());
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem());
}
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java
index 83f6e88b77..7505001c60 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java
@@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable
public boolean checkCondition(L2Character activeChar, L2Object object)
{
- if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)
+ if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION))
{
return true;
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
index b7eda58d00..13932008ff 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -159,7 +160,7 @@ public class SkillCaster implements Runnable
}
// You should not heal/buff monsters without pressing the ctrl button.
- if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed)
+ if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed)
{
caster.sendPacket(SystemMessageId.INVALID_TARGET);
return null;
@@ -609,6 +610,10 @@ public class SkillCaster implements Runnable
// Add hate to the attackable, and put it in the attack list.
((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint());
((L2Character) obj).addAttackerToAttackByList(caster);
+ if (obj.isFakePlayer())
+ {
+ player.updatePvPStatus();
+ }
}
// notify target AI about the attack
@@ -617,10 +622,19 @@ public class SkillCaster implements Runnable
((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster);
}
}
- else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0))))
+ else if (((skill.getEffectPoint() > 0) && obj.isMonster()) //
+ || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) //
+ || (((L2Character) obj).getReputation() < 0) //
+ )))
{
// Supporting players or monsters result in pvpflag.
- player.updatePvPStatus();
+ if (!obj.isFakePlayer() //
+ || (obj.isFakePlayer() //
+ && (!((L2Npc) obj).isScriptValue(0) //
+ || (((L2Npc) obj).getReputation() < 0))))
+ {
+ player.updatePvPStatus();
+ }
}
}
@@ -630,7 +644,7 @@ public class SkillCaster implements Runnable
EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob);
// On Skill See logic
- if (npcMob.isAttackable())
+ if (npcMob.isAttackable() && !npcMob.isFakePlayer())
{
final L2Attackable attackable = (L2Attackable) npcMob;
@@ -652,6 +666,19 @@ public class SkillCaster implements Runnable
}
});
}
+ else if (caster.isFakePlayer()) // fake player attacks player
+ {
+ if (target.isPlayable() || target.isFakePlayer())
+ {
+ final L2Npc npc = ((L2Npc) caster);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ npc.broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+ }
}
catch (Exception e)
{
@@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable
return false;
}
}
-
return true;
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
index fdf0dadf55..06bea1b4cf 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
@@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
@@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
@@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
index 91a9ce830a..ccd2d1d13a 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
@@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket
}
case 1:
{
- if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC))
+ if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer()))
{
obj.onAction(activeChar, false);
}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
index 876c53c093..06464d9911 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket
return;
}
- if (Config.FORBIDDEN_NAMES.length > 1)
+ if (Config.FORBIDDEN_NAMES.length > 0)
{
for (String st : Config.FORBIDDEN_NAMES)
{
@@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
+ return;
+ }
+
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
index 06bfa3c200..01c8b0c67f 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
@@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class RequestBlock implements IClientIncomingPacket
{
@@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket
case BLOCK:
case UNBLOCK:
{
+ // TODO: Save in database? :P
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (_type == BLOCK)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
// can't use block/unblock for locating invisible characters
if (targetId <= 0)
{
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
index ceb67b0f5f..cf79bdb24c 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable;
import com.l2jmobius.gameserver.util.Util;
@@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket
{
result = NAME_ALREADY_EXISTS;
}
+ else if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ result = NAME_ALREADY_EXISTS;
+ }
else if (_name.length() > 16)
{
result = INVALID_LENGTH;
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
index b0ace828dc..ee8bcd656b 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
@@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart;
@@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance activeChar = client.getActiveChar();
- final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (activeChar == null)
{
return;
}
+
+ if (FakePlayerData.getInstance().isTalkable(_player))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(_player);
+ if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ if (activeChar.isProcessingRequest())
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(name);
+ activeChar.sendPacket(msg);
+ return;
+ }
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000);
+ activeChar.blockRequest();
+ return;
+ }
+
+ final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (targetChar == null)
{
activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
index f104c94161..c0042d45c5 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
@@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Party;
@@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ if (player.getParty() == null)
+ {
+ player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED);
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY);
+ }
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance requestor = client.getActiveChar();
- final L2PcInstance target = L2World.getInstance().getPlayer(_name);
-
if (requestor == null)
{
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ requestor.sendPacket(sm);
+ if (!requestor.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000);
+ requestor.blockRequest();
+ }
+ else
+ {
+ requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY);
+ }
+ return;
+ }
+
+ final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (target == null)
{
requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
index 292153afd8..37c539556f 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
@@ -17,12 +17,15 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class ...
@@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return;
}
+ if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName())))
+ {
+ if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0)
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN);
+ }
+ else
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(activeChar.getTarget().getName());
+ activeChar.sendPacket(msg);
+ }
+ }
+ return;
+ }
+
final L2PcInstance target = L2World.getInstance().getPlayer(_target);
if (target == null)
{
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
index 3d5bcaeca5..9cbb114e88 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
@@ -23,6 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.BlockList;
@@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().isTalkable(_receiver))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1);
+ sm.addString(FakePlayerData.getInstance().getProperName(_receiver));
+ activeChar.sendPacket(sm);
+ return;
+ }
+
final int receiverId = CharNameTable.getInstance().getIdByName(_receiver);
if (receiverId <= 0)
{
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
index 8156905e94..1336c2bdb7 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
@@ -17,6 +17,7 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
@@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket
}
final L2Object object = activeChar.getTarget();
-
if (!(object instanceof L2PcInstance))
{
if (object == null)
{
client.sendPacket(SystemMessageId.SELECT_TARGET);
}
+ else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName()))
+ {
+ if (activeChar.getRecomLeft() <= 0)
+ {
+ client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER);
+ return;
+ }
+
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT);
+ sm.addString(FakePlayerData.getInstance().getProperName(object.getName()));
+ sm.addInt(activeChar.getRecomLeft());
+ client.sendPacket(sm);
+
+ activeChar.setRecomLeft(activeChar.getRecomLeft() - 1);
+ client.sendPacket(new UserInfo(activeChar));
+ client.sendPacket(new ExVoteSystemInfo(activeChar));
+ }
else
{
client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
index d77dc881b3..5d7e35eb43 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
@@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.skills.AbnormalType;
@@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target.getName());
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE));
+ return;
+ }
+ if (!player.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1);
+ sm.addString(name);
+ player.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000);
+ player.blockRequest();
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE);
+ }
+ return;
+ }
+
if (!target.isPlayer())
{
client.sendPacket(SystemMessageId.INVALID_TARGET);
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
index 4fa25283a7..530a6d7a01 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
@@ -17,6 +17,8 @@
package com.l2jmobius.gameserver.network.clientpackets.friend;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST));
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
final L2PcInstance friend = L2World.getInstance().getPlayer(_name);
// Target is not found in the game.
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
index 2170ef2e94..017541bd86 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
@@ -22,6 +22,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
- if (receiver.getFriendList().contains(sender.getObjectId()))
+ if (receiver != null)
{
- _mask |= 0x01;
- }
- if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
- {
- _mask |= 0x02;
- }
- if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
- {
- _mask |= 0x04;
- }
- if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
- {
- _mask |= 0x08;
+ if (receiver.getFriendList().contains(sender.getObjectId()))
+ {
+ _mask |= 0x01;
+ }
+ if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
+ {
+ _mask |= 0x02;
+ }
+ if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
+ {
+ _mask |= 0x04;
+ }
+ if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
+ {
+ _mask |= 0x08;
+ }
}
// Does not shows level
@@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket
}
}
+ /**
+ * Used by fake players.
+ * @param sender
+ * @param receiver
+ * @param name
+ * @param messageType
+ * @param text
+ */
+ public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
+ {
+ _objectId = sender.getObjectId();
+ _charName = name;
+ _charLevel = sender.getLevel();
+ _textType = messageType;
+ _text = text;
+ }
+
/**
* @param objectId
* @param messageType
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
new file mode 100644
index 0000000000..d1b7900f12
--- /dev/null
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import java.util.Set;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.enums.Sex;
+import com.l2jmobius.gameserver.model.L2Clan;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerInfo implements IClientOutgoingPacket
+{
+ private final L2Npc _npc;
+ private final int _objId;
+ private final int _x, _y, _z, _heading;
+ private final int _mAtkSpd, _pAtkSpd;
+ private final int _runSpd, _walkSpd;
+ private final int _swimRunSpd;
+ private final int _swimWalkSpd;
+ private final int _flyRunSpd;
+ private final int _flyWalkSpd;
+ private final double _moveMultiplier;
+ private final float _attackSpeedMultiplier;
+ private final FakePlayerHolder _fpcHolder;
+ private final L2Clan _clan;
+
+ public FakePlayerInfo(L2Npc npc)
+ {
+ _npc = npc;
+ _objId = npc.getObjectId();
+ _x = npc.getX();
+ _y = npc.getY();
+ _z = npc.getZ();
+ _heading = npc.getHeading();
+ _mAtkSpd = npc.getMAtkSpd();
+ _pAtkSpd = npc.getPAtkSpd();
+ _attackSpeedMultiplier = npc.getAttackSpeedMultiplier();
+ _moveMultiplier = npc.getMovementSpeedMultiplier();
+ _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier);
+ _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier);
+ _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier);
+ _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier);
+ _flyRunSpd = npc.isFlying() ? _runSpd : 0;
+ _flyWalkSpd = npc.isFlying() ? _walkSpd : 0;
+ _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId());
+ _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId());
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.CHAR_INFO.writeId(packet);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(0x00); // vehicleId
+ packet.writeD(_objId);
+ packet.writeS(_npc.getName());
+
+ packet.writeH(_npc.getRace().ordinal());
+ packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00);
+ packet.writeD(_fpcHolder.getClassId());
+
+ packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER
+ packet.writeD(_fpcHolder.getEquipHead());
+ packet.writeD(_fpcHolder.getEquipRHand());
+ packet.writeD(_fpcHolder.getEquipLHand());
+ packet.writeD(_fpcHolder.getEquipGloves());
+ packet.writeD(_fpcHolder.getEquipChest());
+ packet.writeD(_fpcHolder.getEquipLegs());
+ packet.writeD(_fpcHolder.getEquipFeet());
+ packet.writeD(_fpcHolder.getEquipCloak());
+ packet.writeD(_fpcHolder.getEquipRHand()); // dual hand
+ packet.writeD(_fpcHolder.getEquipHair());
+ packet.writeD(_fpcHolder.getEquipHair2());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderAugument())
+ {
+ packet.writeQ(0x00);
+ }
+
+ packet.writeC(_fpcHolder.getArmorEnchantLevel());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderVisualId())
+ {
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(_npc.getScriptValue()); // getPvpFlag()
+ packet.writeD(_npc.getReputation());
+
+ packet.writeD(_mAtkSpd);
+ packet.writeD(_pAtkSpd);
+
+ packet.writeH(_runSpd);
+ packet.writeH(_walkSpd);
+ packet.writeH(_swimRunSpd);
+ packet.writeH(_swimWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeF(_moveMultiplier);
+ packet.writeF(_attackSpeedMultiplier);
+
+ packet.writeF(_npc.getCollisionRadius());
+ packet.writeF(_npc.getCollisionHeight());
+
+ packet.writeD(_fpcHolder.getHair());
+ packet.writeD(_fpcHolder.getHairColor());
+ packet.writeD(_fpcHolder.getFace());
+
+ packet.writeS(_npc.getTemplate().getTitle());
+
+ if (_clan != null)
+ {
+ packet.writeD(_clan.getId());
+ packet.writeD(_clan.getCrestId());
+ packet.writeD(_clan.getAllyId());
+ packet.writeD(_clan.getAllyCrestId());
+ }
+ else
+ {
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked)
+ packet.writeC(_npc.isRunning() ? 0x01 : 0x00);
+ packet.writeC(_npc.isInCombat() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isInvisible() ? 0x01 : 0x00);
+
+ packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount
+ packet.writeC(0x00); // getPrivateStoreType().getId()
+
+ packet.writeH(0x00); // getCubics().size()
+ // getCubics().keySet().forEach(packet::writeH);
+
+ packet.writeC(0x00);
+
+ packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0);
+ packet.writeH(_fpcHolder.getRecommends());
+ packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000
+
+ packet.writeD(_fpcHolder.getClassId());
+ packet.writeD(0x00);
+ packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel
+
+ packet.writeC(_npc.getTeam().getId());
+
+ packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00);
+ packet.writeC(_fpcHolder.getNobleLevel());
+ packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00);
+
+ packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00);
+
+ packet.writeD(_fpcHolder.getBaitLocationX());
+ packet.writeD(_fpcHolder.getBaitLocationY());
+ packet.writeD(_fpcHolder.getBaitLocationZ());
+
+ packet.writeD(_fpcHolder.getNameColor());
+
+ packet.writeD(_heading);
+
+ packet.writeC(_fpcHolder.getPledgeStatus());
+ packet.writeH(0x00); // getPledgeType()
+
+ packet.writeD(_fpcHolder.getTitleColor());
+
+ packet.writeC(0x00); // isCursedWeaponEquipped
+
+ packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0
+ packet.writeD(0x00); // getTransformationDisplayId()
+ packet.writeD(_fpcHolder.getAgathionId());
+
+ packet.writeC(0x00);
+
+ packet.writeD(0x00); // getCurrentCp()
+ packet.writeD(_npc.getMaxHp());
+ packet.writeD((int) Math.round(_npc.getCurrentHp()));
+ packet.writeD(_npc.getMaxMp());
+ packet.writeD((int) Math.round(_npc.getCurrentMp()));
+
+ packet.writeC(0x00);
+ final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects();
+ packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0));
+ for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects)
+ {
+ packet.writeH(abnormalVisualEffect.getClientId());
+ }
+ if (_npc.isInvisible())
+ {
+ packet.writeH(AbnormalVisualEffect.STEALTH.getClientId());
+ }
+ packet.writeC(0x00); // cocPlayer.getPosition()
+ packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00);
+ packet.writeC(0x00); // Used Ability Points
+ return true;
+ }
+}
diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
index 4fb1a757e6..c294edab2a 100644
--- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
+++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
@@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket
addComponentType(NpcInfoType.TITLE_NPCSTRINGID);
}
+ if (_npc.getReputation() != 0)
+ {
+ addComponentType(NpcInfoType.REPUTATION);
+ }
+
if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible())
{
addComponentType(NpcInfoType.ABNORMALS);
@@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket
}
if (containsMask(NpcInfoType.REPUTATION))
{
- packet.writeD(0x00); // Name color
+ packet.writeD(_npc.getReputation()); // Reputation
}
if (containsMask(NpcInfoType.CLAN))
{
diff --git a/L2J_Mobius_2.5_Underground/readme.txt b/L2J_Mobius_2.5_Underground/readme.txt
index 51ce661fc2..96437b02b9 100644
--- a/L2J_Mobius_2.5_Underground/readme.txt
+++ b/L2J_Mobius_2.5_Underground/readme.txt
@@ -94,6 +94,7 @@ Customs:
-Classmaster
-Community board
-Faction system
+-Fake players
-Find PvP
-NPC stat multipliers
-Realtime offline trade
diff --git a/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml b/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml
index 171e08cb12..f9067f1377 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml
@@ -392,6 +392,9 @@
+
+
+
diff --git a/L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini
new file mode 100644
index 0000000000..f745b0d31e
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini
@@ -0,0 +1,33 @@
+# ---------------------------------------------------------------------------
+# Fake players
+# ---------------------------------------------------------------------------
+
+# Enable fake players.
+EnableFakePlayers = False
+
+# Enable chatting with fake players.
+FakePlayerChat = True
+
+# Enable shots usage for fake players.
+FakePlayerUseShots = True
+
+# Reward PvP kills by killing fake players.
+FakePlayerKillsRewardPvP = True
+
+# Fake player kills apply karma rules.
+FakePlayerUnflaggedKillsKarma = True
+
+# Aggressive AI fake players attack nearby monsters.
+FakePlayerAggroMonsters = True
+
+# Aggressive AI fake players attack nearby players.
+FakePlayerAggroPlayers = False
+
+# Aggressive AI fake players attack nearby fake players.
+FakePlayerAggroFPC = False
+
+# Fake players can drop items when killing monsters.
+FakePlayerCanDropItems = True
+
+# Fake players can pickup dropped items.
+FakePlayerCanPickup = True
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml
new file mode 100644
index 0000000000..f5da5bfc8e
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml
new file mode 100644
index 0000000000..f36096ed4a
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml
index 98e0d38815..e87880bdd1 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml
@@ -2402,4 +2402,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
index 6f29855cc3..d12ee2e7c4 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
@@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI
final L2Character creature = event.getSeen();
final L2Npc npc = (L2Npc) event.getSeer();
- if (creature.isPlayer())
+ if (creature.isPlayer() || creature.isFakePlayer())
{
npc.setTarget(creature);
npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill());
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
new file mode 100644
index 0000000000..e1dde7324e
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+import ai.AbstractNpcAI;
+
+/**
+ * TODO: Move it to L2Character.
+ * @author Mobius
+ */
+public class PvpFlaggingStopTask extends AbstractNpcAI
+{
+ private PvpFlaggingStopTask()
+ {
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if ((npc == null) || npc.isDead())
+ {
+ return null;
+ }
+
+ if (event.startsWith("FLAG_CHECK"))
+ {
+ final L2Object target = npc.getTarget();
+ if ((target != null) && (target.isPlayable() || target.isFakePlayer()))
+ {
+ npc.setScriptValue(1); // in combat
+ cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null);
+ cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null);
+ startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null);
+ startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null);
+ }
+ }
+ else if (event.startsWith("FINISH_FLAG"))
+ {
+ if (npc.isScriptValue(1))
+ {
+ npc.setScriptValue(2); // blink status
+ npc.broadcastInfo(); // update flag status
+ startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null);
+ }
+ }
+ else if (event.startsWith("REMOVE_FLAG"))
+ {
+ if (npc.isScriptValue(2))
+ {
+ npc.setScriptValue(0); // not in combat
+ npc.broadcastInfo(); // update flag status
+ }
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ public static void main(String[] args)
+ {
+ new PvpFlaggingStopTask();
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
new file mode 100644
index 0000000000..dec3449549
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.CommonUtil;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.base.ClassId;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
+import com.l2jmobius.gameserver.model.skills.SkillCaster;
+
+import ai.AbstractNpcAI;
+
+/**
+ * Town Fake Player walkers that receive buffs from Adventurer NPC.
+ * @author Mobius
+ */
+public class RecieveAdventurerBuffs extends AbstractNpcAI
+{
+ // NPCs
+ private static final int[] ADVENTURERS_GUIDE =
+ {
+ 32327,
+ 33950,
+ };
+ private static final int[] FAKE_PLAYER_IDS =
+ {
+ 80000
+ };
+ // Skills
+ // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
+ private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
+ private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
+ private static final SkillHolder[] GROUP_BUFFS =
+ {
+ new SkillHolder(15642, 1), // Horn Melody (Adventurer)
+ new SkillHolder(15643, 1), // Drum Melody (Adventurer)
+ new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
+ new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
+ new SkillHolder(15646, 1), // Harp Melody (Adventurer)
+ new SkillHolder(15647, 1), // Lute Melody (Adventurer)
+ new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
+ new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
+ new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
+ };
+
+ private RecieveAdventurerBuffs()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ addSpawnId(FAKE_PLAYER_IDS);
+ }
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead())
+ {
+ if (!npc.isMoving())
+ {
+ for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100))
+ {
+ if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId()))
+ {
+ for (SkillHolder holder : GROUP_BUFFS)
+ {
+ SkillCaster.triggerCast(nearby, npc, holder.getSkill());
+ }
+ if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage())
+ {
+ SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill());
+ }
+ else
+ {
+ SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill());
+ }
+ break;
+ }
+ }
+ }
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null);
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ @Override
+ public String onSpawn(L2Npc npc)
+ {
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null);
+ return super.onSpawn(npc);
+ }
+
+ public static void main(String[] args)
+ {
+ new RecieveAdventurerBuffs();
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java
index 3c72228c33..3228e5fe09 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
+import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -410,6 +411,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
+ AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
index 6b02816d9e..d6d6a99080 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
@@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (Config.ALT_GAME_VIEWNPC)
{
- if (!target.isNpc())
+ if (!target.isNpc() || target.isFakePlayer())
{
return false;
}
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
new file mode 100644
index 0000000000..99926f0df7
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package handlers.admincommandhandlers;
+
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author Mobius
+ */
+public class AdminFakePlayers implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_fakechat"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ if (command.startsWith("admin_fakechat"))
+ {
+ final String[] words = command.substring(15).split(" ");
+ if (words.length < 3)
+ {
+ activeChar.sendMessage("Usage: //fakechat playername fpcname message");
+ return false;
+ }
+ final L2PcInstance player = L2World.getInstance().getPlayer(words[0]);
+ if (player == null)
+ {
+ activeChar.sendMessage("Player not found.");
+ return false;
+ }
+ final String fpcName = FakePlayerData.getInstance().getProperName(words[1]);
+ if (fpcName == null)
+ {
+ activeChar.sendMessage("Fake player not found.");
+ return false;
+ }
+ String message = "";
+ for (int i = 0; i < words.length; i++)
+ {
+ if (i < 2)
+ {
+ continue;
+ }
+ message += (words[i] + " ");
+ }
+ FakePlayerChatManager.getInstance().sendChat(player, fpcName, message);
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
index 5da8e115b2..4799a7aa53 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
@@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
+ case "fakeplayers":
+ {
+ FakePlayerData.getInstance().load();
+ for (L2Object obj : L2World.getInstance().getVisibleObjects())
+ {
+ if (obj.isFakePlayer())
+ {
+ obj.broadcastInfo();
+ }
+ }
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
+ break;
+ }
+ case "fakeplayerchat":
+ {
+ FakePlayerChatManager.getInstance().load();
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
+ break;
+ }
default:
{
activeChar.sendMessage(RELOAD_USAGE);
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
index 99f2e9e9d7..7db79fe31d 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
@@ -17,8 +17,10 @@
package handlers.chathandlers;
import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IChatHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PcCondOverride;
@@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
+ if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
+ {
+ if (FakePlayerData.getInstance().isTalkable(target))
+ {
+ if (Config.FAKE_PLAYER_CHAT)
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target);
+ activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
+ FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
+ }
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
+ }
+ return;
+ }
+
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
index 41b1f99bcf..b38f5ca16d 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
@@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
-
}
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java
index 1e34a0d148..087112cc73 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java
@@ -16,9 +16,11 @@
*/
package handlers.playeractions;
+import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
+ player.onTransactionResponse();
+ }
+ }
+
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
- if ((target == null) || !target.isPlayer())
+ if ((target == null))
+ {
+ player.sendPacket(SystemMessageId.INVALID_TARGET);
+ return;
+ }
+
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
+ sm.addString(target.getName());
+ player.sendPacket(sm);
+ if (!player.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
+ player.blockRequest();
+ }
+ return;
+ }
+
+ if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
index 12f33e2bbc..9dd91055b9 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
@@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest
@Id(WINDY_HEALING_POTION_1)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(4, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ {
+ qs.setCond(4, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
index 0efb5383f4..34594dbc40 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
@@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest
@Id(HIGH_GRADE_LOVE_POTION)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(2, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ {
+ qs.setCond(2, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml
new file mode 100644
index 0000000000..ea77878c2c
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml
new file mode 100644
index 0000000000..8470293122
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml
@@ -0,0 +1,341 @@
+
+
+
+
+ HUMAN
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ORC
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DWARF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KAMAEL
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HUMAN
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DARK_ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml
new file mode 100644
index 0000000000..589f29b215
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd
new file mode 100644
index 0000000000..2b2c94e75b
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd
new file mode 100644
index 0000000000..0628acefc3
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd
index 6f00944cff..ae80c3ff63 100644
--- a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd
+++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd
@@ -201,6 +201,8 @@
+
+
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java
index 0a047f9679..bf72ea7ba4 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java
@@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
+ public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@@ -1155,6 +1156,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
+ public static boolean FAKE_PLAYERS_ENABLED;
+ public static boolean FAKE_PLAYER_CHAT;
+ public static boolean FAKE_PLAYER_USE_SHOTS;
+ public static boolean FAKE_PLAYER_KILL_PVP;
+ public static boolean FAKE_PLAYER_KILL_KARMA;
+ public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
+ public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
+ public static boolean FAKE_PLAYER_AGGRO_FPC;
+ public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
+ public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@@ -2577,6 +2588,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
+ // Load FakePlayers config file (if exists)
+ final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
+ FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
+ FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
+ FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
+ FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
+ FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
+ FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
+ FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
+ FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
+ FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
+ FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
+
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java
index 3d1ce4387e..810ed1ae09 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java
@@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
@@ -288,6 +290,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
+ FakePlayerData.getInstance();
+ FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
WalkingManager.getInstance();
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
index 6253fa9329..1da1b21546 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
@@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
- if (npc.isAggressive() || (npc instanceof L2GuardInstance))
+ if (npc.isFakePlayer() && npc.isAggressive())
+ {
+ final List droppedItems = npc.getFakePlayerDrops();
+ if (droppedItems.isEmpty())
+ {
+ L2Character nearestTarget = null;
+ double closestDistance = Double.MAX_VALUE;
+ for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange()))
+ {
+ if ((t == _actor) || (t == null) || t.isDead())
+ {
+ continue;
+ }
+ if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer()))
+ {
+ final int hating = npc.getHating(t);
+ final double distance = npc.calculateDistance(t, false, false);
+ if ((hating == 0) && (closestDistance > distance))
+ {
+ nearestTarget = t;
+ closestDistance = distance;
+ }
+ }
+ }
+ if (nearestTarget != null)
+ {
+ npc.addDamageHate(nearestTarget, 0, 1);
+ }
+ }
+ else if (!npc.isInCombat()) // must pickup items
+ {
+ final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped
+ final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex);
+ if ((droppedItem != null) && droppedItem.isSpawned())
+ {
+ if (npc.calculateDistance(droppedItem, false, false) > 50)
+ {
+ moveTo(droppedItem);
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ droppedItem.pickupMe(npc);
+ if (Config.SAVE_DROPPED_ITEM)
+ {
+ ItemsOnGroundManager.getInstance().removeObject(droppedItem);
+ }
+ if (droppedItem.getItem().hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills())
+ {
+ SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
+ }
+ npc.broadcastInfo(); // ? check if this is necessary
+ }
+ }
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ }
+ npc.setRunning();
+ }
+ }
+ else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
- if (t.isPlayable())
+ if (t.isFakePlayer())
+ {
+ if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
+ {
+ final int hating = npc.getHating(t);
+ if (hating == 0)
+ {
+ npc.addDamageHate(t, 0, 1);
+ }
+ }
+ }
+ else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
new file mode 100644
index 0000000000..0a6ca5267a
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerData implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName());
+
+ private final Map _fakePlayerInfos = new HashMap<>();
+ private final Map _fakePlayerNames = new HashMap<>();
+ private final Map _fakePlayerIds = new HashMap<>();
+ private final List _talkableFakePlayerNames = new ArrayList<>();
+
+ protected FakePlayerData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ _fakePlayerInfos.clear();
+ _fakePlayerNames.clear();
+ _fakePlayerIds.clear();
+ _talkableFakePlayerNames.clear();
+ parseDatapackFile("data/FakePlayerVisualData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode));
+ final int npcId = set.getInt("npcId");
+ final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
+ final String name = template.getName();
+ if (CharNameTable.getInstance().getIdByName(name) > 0)
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists.");
+ }
+ else
+ {
+ _fakePlayerIds.put(name, npcId); // name - npcId
+ _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name
+ _fakePlayerInfos.put(npcId, new FakePlayerHolder(set));
+ if (template.isFakePlayerTalkable())
+ {
+ _talkableFakePlayerNames.add(name.toLowerCase());
+ }
+ }
+ }));
+ }
+
+ public int getNpcIdByName(String name)
+ {
+ return _fakePlayerIds.get(name);
+ }
+
+ public String getProperName(String name)
+ {
+ return _fakePlayerNames.get(name.toLowerCase());
+ }
+
+ public Boolean isTalkable(String name)
+ {
+ return _talkableFakePlayerNames.contains(name.toLowerCase());
+ }
+
+ public FakePlayerHolder getInfo(int npcId)
+ {
+ return _fakePlayerInfos.get(npcId);
+ }
+
+ public static FakePlayerData getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerData _instance = new FakePlayerData();
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
index 883e877bc7..f03a2395f1 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
@@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader
set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty"));
+ set.set("fakePlayer", parseBoolean(attrs, "fakePlayer"));
+ set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable"));
break;
}
case "skill_list":
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
index 2ff4c9322d..15bd310bd6 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
@@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
+ if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
+ {
+ return;
+ }
+
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
index a145b65dba..d525c02a6a 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
@@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
-
if (target == null)
{
return false;
}
- final L2PcInstance bot = target.getActingPlayer();
+ final L2Character bot = ((L2Character) target);
- if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
+ if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
- if (bot.isInOlympiadMode())
+ if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
- if (bot.getExp() == bot.getStat().getStartingExp())
+ if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
- handleReport(bot, rcd);
+ if (bot.isPlayer())
+ {
+ handleReport(bot.getActingPlayer(), rcd);
+ }
return true;
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java
index 7454554076..ace19486b5 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
@@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
- * @param actor : L2PcInstance Player requesting the item creation
+ * @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
- public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
+ public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
index b621b4c4cb..bb0e928daf 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
@@ -217,6 +217,7 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
+ cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
// If the clan does not exist...
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
new file mode 100644
index 0000000000..16a0da92bc
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.instancemanager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.datatables.SpawnTable;
+import com.l2jmobius.gameserver.enums.ChatType;
+import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.model.L2Spawn;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
+import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
+
+/**
+ * @author Mobius
+ */
+public final class FakePlayerChatManager implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
+ final List MESSAGES = new ArrayList<>();
+ private static final int MIN_DELAY = 5000;
+ private static final int MAX_DELAY = 15000;
+
+ protected FakePlayerChatManager()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT)
+ {
+ MESSAGES.clear();
+ parseDatapackFile("data/FakePlayerChatData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode));
+ MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers")));
+ }));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
+ }
+
+ private void manageResponce(L2PcInstance player, String fpcName, String message)
+ {
+ if (player == null)
+ {
+ return;
+ }
+
+ final String text = message.toLowerCase();
+
+ // tricky question
+ if (text.contains("can you see me"))
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ if (npc.calculateDistance(player, false, false) < 3000)
+ {
+ if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
+ }
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
+ }
+ return;
+ }
+ }
+ }
+
+ for (FakePlayerChatHolder chatHolder : MESSAGES)
+ {
+ if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
+ {
+ continue;
+ }
+
+ switch (chatHolder.getSearchMethod())
+ {
+ case "EQUALS":
+ {
+ if (text.equals(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "STARTS_WITH":
+ {
+ if (text.startsWith(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "CONTAINS":
+ {
+ boolean allFound = true;
+ for (String word : chatHolder.getSearchText())
+ {
+ if (!text.contains(word))
+ {
+ allFound = false;
+ }
+ }
+ if (allFound)
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public void sendChat(L2PcInstance player, String fpcName, String message)
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
+ }
+ }
+ }
+
+ public static FakePlayerChatManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java
index 1a62714f0e..50a3cc2145 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
@@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class DropProtection implements Runnable
{
private volatile boolean _isProtected = false;
- private L2PcInstance _owner = null;
+ private L2Character _owner = null;
private ScheduledFuture> _task = null;
private static final long PROTECTED_MILLIS_TIME = 15000;
@@ -46,7 +47,7 @@ public class DropProtection implements Runnable
return _isProtected;
}
- public L2PcInstance getOwner()
+ public L2Character getOwner()
{
return _owner;
}
@@ -91,12 +92,12 @@ public class DropProtection implements Runnable
_task = null;
}
- public synchronized void protect(L2PcInstance player)
+ public synchronized void protect(L2Character character)
{
unprotect();
_isProtected = true;
- _owner = player;
+ _owner = character;
if (_owner == null)
{
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java
index 459660c7ca..92837e4b25 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java
@@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
return false;
}
+ /**
+ * Verify if object is a fake player.
+ * @return {@code true} if object is a fake player, {@code false} otherwise
+ */
+ public boolean isFakePlayer()
+ {
+ return false;
+ }
+
/**
* Verify if object is instance of L2ServitorInstance.
* @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
index 2ecce60d39..ddc1a1b8d4 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
@@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
- return _mustGiveExpSp;
+ return _mustGiveExpSp && !isFakePlayer();
}
/**
@@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
+ // unless its a fake player and they can drop items
+ if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
+ {
+ final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);
+ if (deathItems != null)
+ {
+ for (ItemHolder drop : deathItems)
+ {
+ final L2Item item = ItemTable.getInstance().getTemplate(drop.getId());
+ // Check if the autoLoot mode is active
+ if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
+ {
+ // do nothing
+ }
+ else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : item.getAllSkills())
+ {
+ SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false);
+ }
+ mainDamageDealer.broadcastInfo(); // ? check if this is necessary
+ }
+ else
+ {
+ final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
+ if (Config.FAKE_PLAYER_CAN_PICKUP)
+ {
+ mainDamageDealer.getFakePlayerDrops().add(droppedItem);
+ }
+ }
+ }
+ }
+ }
return;
}
@@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
- if (lastAttacker == null)
+ if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc
_harvestItem.set(null);
_sweepItems.set(null);
+ // fake players
+ if (isFakePlayer())
+ {
+ getFakePlayerDrops().clear(); // Clear existing fake player drops
+ setReputation(0); // reset reputation
+ setScriptValue(0); // remove pvp flag
+ setRunning(); // don't walk
+ }
+
// Clear mod Seeded stat
_seeded = false;
_seed = null;
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java
index 226b8e981a..6dd50e079f 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java
@@ -30,6 +30,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList;
@@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
+ private int _reputation = 0;
+
/** Map containing all skills of this character. */
private final Map _skills = new ConcurrentSkipListMap<>();
/** Map containing the skill reuse time stamps. */
@@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
/** A set containing the shot types currently charged. */
private Set _chargedShots = EnumSet.noneOf(ShotType.class);
+ /** A list containing the dropped items of this fake player. */
+ private final List _fakePlayerDrops = new CopyOnWriteArrayList<>();
+
/**
* Creates a creature.
* @param template the creature template
@@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
broadcastPacket(attack);
}
+ if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
+ {
+ final L2Npc npc = ((L2Npc) this);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+
// Notify AI with EVT_READY_TO_ACT
ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
}
@@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
final Instance instanceWorld = getInstanceWorld();
- if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
+ if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
{
return false;
}
@@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist());
}
+ public int getReputation()
+ {
+ return _reputation;
+ }
+
+ public void setReputation(int reputation)
+ {
+ _reputation = reputation;
+ }
+
/**
* Gets the distance to target.
* @param target the target
@@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
+
+ public List getFakePlayerDrops()
+ {
+ return _fakePlayerDrops;
+ }
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
index 5742c07807..b669e16e76 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
@@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.enums.Team;
+import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.handler.BypassHandler;
import com.l2jmobius.gameserver.handler.IBypassHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
+import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
@@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
+import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@@ -125,6 +130,7 @@ public class L2Npc extends L2Character
private boolean _isRandomAnimationEnabled = true;
private boolean _isRandomWalkingEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
+ private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@@ -364,7 +370,11 @@ public class L2Npc extends L2Character
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@@ -901,6 +911,78 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
+ if (isFakePlayer() && (killer != null) && killer.isPlayable())
+ {
+ final L2PcInstance player = killer.getActingPlayer();
+ if (isScriptValue(0) && (getReputation() >= 0))
+ {
+ if (Config.FAKE_PLAYER_KILL_KARMA)
+ {
+ player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
+ player.setPkKills(player.getPkKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ player.checkItemRestriction();
+ // pk item rewards
+ if (Config.REWARD_PK_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
+ // announce pk
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+ else if (Config.FAKE_PLAYER_KILL_PVP)
+ {
+ player.setPvpKills(player.getPvpKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ // pvp item rewards
+ if (Config.REWARD_PVP_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ }
+ // announce pvp
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+
DecayTaskManager.getInstance().add(this);
final L2Spawn spawn = getSpawn();
@@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ activeChar.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character
@Override
public void rechargeShots(boolean physical, boolean magic, boolean fish)
{
- if (physical && (_soulshotamount > 0))
+ if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS)
{
- if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ if (physical)
{
- return;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic)
+ {
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _soulshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
- chargeShot(ShotType.SOULSHOTS);
}
-
- if (magic && (_spiritshotamount > 0))
+ else
{
- if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ if (physical && (_soulshotamount > 0))
{
- return;
+ if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ {
+ return;
+ }
+ _soulshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic && (_spiritshotamount > 0))
+ {
+ if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ {
+ return;
+ }
+ _spiritshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _spiritshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
- chargeShot(ShotType.SPIRITSHOTS);
}
}
@@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
- * @param player the last attacker or main damage dealer
+ * @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
+ public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character
return null;
}
- item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
+ item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
- if (player != null)
+ if (character != null)
{
- item.getDropProtection().protect(player);
+ item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character
}
/**
- * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
- * @param player the last attacker or main damage dealer
+ * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
+ * @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
+ public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
- return dropItem(player, item.getId(), item.getCount());
+ return dropItem(character, item.getId(), item.getCount());
}
@Override
@@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character
return Config.SHOP_MIN_RANGE_FROM_NPC;
}
+ @Override
+ public boolean isFakePlayer()
+ {
+ return _isFakePlayer;
+ }
+
/**
* @return The player's object Id this NPC is cloning.
*/
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
index 34550c3dd8..10ad419ea4 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
@@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
- public abstract int getReputation();
-
public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove);
public abstract void storeMe();
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
index 8427885746..87cc552765 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
@@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
@@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
+ if (target.isFakePlayer())
+ {
+ getOwner().updatePvPStatus();
+ }
}
}
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
index a5fd31dedd..44ee919058 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
@@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
index aa4f132fce..6a94be63b5 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
@@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
- if (attacker.isMonster())
+ if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
+ if (isFakePlayer() && isInCombat())
+ {
+ interact = false;
+ // TODO: Fix normal targeting
+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
+ }
+
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
index e9a9976e87..fe55288a3a 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
@@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
+ if (isFakePlayer())
+ {
+ return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
+ }
+
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
@@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable
if (attacker.isMonster())
{
- return false;
+ return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
index fc00a851c3..cff16174ad 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
@@ -446,9 +446,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
- /** The Reputation of the L2PcInstance */
- private int _reputation;
-
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@@ -1993,24 +1990,16 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
- /**
- * @return the reputation of the PlayerInstance.
- */
- @Override
- public int getReputation()
- {
- return _reputation;
- }
-
public void setInitialReputation(int reputation)
{
- _reputation = reputation;
+ super.setReputation(reputation);
}
/**
* Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param reputation
*/
+ @Override
public void setReputation(int reputation)
{
// Notify to scripts.
@@ -2036,7 +2025,9 @@ public final class L2PcInstance extends L2Playable
}
});
}
- _reputation = reputation;
+
+ super.setReputation(reputation);
+
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation()));
broadcastReputation();
}
@@ -4656,6 +4647,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
+ if (target.isFakePlayer())
+ {
+ updatePvPStatus();
+ }
}
@Override
@@ -4983,22 +4978,42 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
- if (pk != null)
+ final boolean fpcKill = killer.isFakePlayer();
+ if ((pk != null) || fpcKill)
{
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
-
- if (L2Event.isParticipant(pk))
+ if (pk != null)
{
- pk.getEventStatus().addKill(this);
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
+
+ if (L2Event.isParticipant(pk))
+ {
+ pk.getEventStatus().addKill(this);
+ }
+
+ // pvp/pk item rewards
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ // pvp
+ if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
+ {
+ pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ // pk
+ if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
+ {
+ pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
}
// announce pvp/pk
- if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
+ if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
- msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5012,7 +5027,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
- msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5026,20 +5041,9 @@ public final class L2PcInstance extends L2Playable
}
}
- // pvp/pk item rewards
- if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
- !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0))
{
- // pvp
- if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
- {
- pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
- }
- // pk
- if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
- {
- pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
- }
+ killer.setReputation(killer.getReputation() - 150);
}
}
@@ -5632,6 +5636,14 @@ public final class L2PcInstance extends L2Playable
return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks());
}
+ /**
+ * Used by fake players to emulate proper behavior.
+ */
+ public void blockRequest()
+ {
+ _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
+ }
+
/**
* Select the Warehouse to be used in next activity.
* @param partner
@@ -11579,7 +11591,7 @@ public final class L2PcInstance extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addPcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), -damage);
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
index fb6b184e67..8383d1efc9 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
@@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
+ @Override
public int getReputation()
{
return _owner != null ? _owner.getReputation() : 0;
@@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addCharName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
_owner.sendPacket(sm);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
index a97eab382d..26a51be541 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
@@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (attacker.isPlayable() && (caster.getCurrentCp() > 0))
+ if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (!ignoreCP && attacker.isPlayable())
+ if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{
@@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus
// Send a System Message to the L2PcInstance
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
smsg.addString(getActiveChar().getName());
- smsg.addCharName(attacker);
+ smsg.addString(attacker.getName());
smsg.addInt(fullValue);
getActiveChar().sendPacket(smsg);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
index 2d7f41e9d0..f5bee5dab6 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
@@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _randomWalk;
private boolean _randomAnimation;
private boolean _flying;
+ private boolean _fakePlayer;
+ private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard"));
_randomAnimation = set.getBoolean("randomAnimation", true);
_flying = set.getBoolean("flying", false);
+ _fakePlayer = set.getBoolean("fakePlayer", false);
+ _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
+ public boolean isFakePlayer()
+ {
+ return _fakePlayer;
+ }
+
+ public boolean isFakePlayerTalkable()
+ {
+ return _fakePlayerTalkable;
+ }
+
public boolean canMove()
{
return _canMove;
@@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
case LUCKY_DROP:
{
// try chance before luck
- if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck())
+ if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck())
{
return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax()));
}
@@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// chance
double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE;
}
@@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// amount is calculated after chance returned success
double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER;
// premium amount
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT;
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
index df9698d3c3..6cbe42b242 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
@@ -16,7 +16,7 @@
*/
package com.l2jmobius.gameserver.model.events.impl.item;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
@@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent
{
private final String _process;
private final L2ItemInstance _item;
- private final L2PcInstance _activeChar;
+ private final L2Character _activeChar;
private final Object _reference;
- public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference)
+ public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference)
{
_process = process;
_item = item;
@@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent
return _item;
}
- public L2PcInstance getActiveChar()
+ public L2Character getActiveChar()
{
return _activeChar;
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
new file mode 100644
index 0000000000..3008d340b3
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerChatHolder
+{
+ private final String _fpcName;
+ private final String _searchMethod;
+ private final List _searchText;
+ private final List _answers;
+
+ public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers)
+ {
+ _fpcName = fpcName;
+ _searchMethod = searchMethod;
+ _searchText = new ArrayList<>(Arrays.asList(searchText.split(";")));
+ _answers = new ArrayList<>(Arrays.asList(answers.split(";")));
+ }
+
+ public String getFpcName()
+ {
+ return _fpcName;
+ }
+
+ public String getSearchMethod()
+ {
+ return _searchMethod;
+ }
+
+ public List getSearchText()
+ {
+ return _searchText;
+ }
+
+ public List getAnswers()
+ {
+ return _answers;
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
new file mode 100644
index 0000000000..2f8aa1fa6d
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerHolder
+{
+ private final int _classId;
+ private final int _hair;
+ private final int _hairColor;
+ private final int _face;
+ private final int _nameColor;
+ private final int _titleColor;
+ private final int _equipHead;
+ private final int _equipRHand;
+ private final int _equipLHand;
+ private final int _equipGloves;
+ private final int _equipChest;
+ private final int _equipLegs;
+ private final int _equipFeet;
+ private final int _equipCloak;
+ private final int _equipHair;
+ private final int _equipHair2;
+ private final int _agathionId;
+ private final int _weaponEnchantLevel;
+ private final int _armorEnchantLevel;
+ private final boolean _fishing;
+ private final int _baitLocationX;
+ private final int _baitLocationY;
+ private final int _baitLocationZ;
+ private final int _recommends;
+ private final int _nobleLevel;
+ private final boolean _hero;
+ private final int _clanId;
+ private final int _pledgeStatus;
+
+ public FakePlayerHolder(StatsSet set)
+ {
+ _classId = set.getInt("classId", 182);
+
+ _hair = set.getInt("hair", 1);
+ _hairColor = set.getInt("hairColor", 1);
+ _face = set.getInt("face", 1);
+
+ _nameColor = set.getInt("nameColor", 0xFFFFFF);
+ _titleColor = set.getInt("titleColor", 0xECF9A2);
+
+ _equipHead = set.getInt("equipHead", 0);
+ _equipRHand = set.getInt("equipRHand", 0); // or dual hand
+ _equipLHand = set.getInt("equipLHand", 0);
+ _equipGloves = set.getInt("equipGloves", 0);
+ _equipChest = set.getInt("equipChest", 0);
+ _equipLegs = set.getInt("equipLegs", 0);
+ _equipFeet = set.getInt("equipFeet", 0);
+ _equipCloak = set.getInt("equipCloak", 0);
+ _equipHair = set.getInt("equipHair", 0);
+ _equipHair2 = set.getInt("equipHair2", 0);
+ _agathionId = set.getInt("agathionId", 0);
+
+ _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0);
+ _armorEnchantLevel = set.getInt("armorEnchantLevel", 0);
+
+ _fishing = set.getBoolean("fishing", false);
+ _baitLocationX = set.getInt("baitLocationX", 0);
+ _baitLocationY = set.getInt("baitLocationY", 0);
+ _baitLocationZ = set.getInt("baitLocationZ", 0);
+
+ _recommends = set.getInt("recommends", 0);
+ _nobleLevel = set.getInt("nobleLevel", 0);
+ _hero = set.getBoolean("hero", false);
+ _clanId = set.getInt("clanId", 0);
+ _pledgeStatus = set.getInt("pledgeStatus", 0);
+ }
+
+ public int getClassId()
+ {
+ return _classId;
+ }
+
+ public int getHair()
+ {
+ return _hair;
+ }
+
+ public int getHairColor()
+ {
+ return _hairColor;
+ }
+
+ public int getFace()
+ {
+ return _face;
+ }
+
+ public int getNameColor()
+ {
+ return _nameColor;
+ }
+
+ public int getTitleColor()
+ {
+ return _titleColor;
+ }
+
+ public int getEquipHead()
+ {
+ return _equipHead;
+ }
+
+ public int getEquipRHand()
+ {
+ return _equipRHand;
+ }
+
+ public int getEquipLHand()
+ {
+ return _equipLHand;
+ }
+
+ public int getEquipGloves()
+ {
+ return _equipGloves;
+ }
+
+ public int getEquipChest()
+ {
+ return _equipChest;
+ }
+
+ public int getEquipLegs()
+ {
+ return _equipLegs;
+ }
+
+ public int getEquipFeet()
+ {
+ return _equipFeet;
+ }
+
+ public int getEquipCloak()
+ {
+ return _equipCloak;
+ }
+
+ public int getEquipHair()
+ {
+ return _equipHair;
+ }
+
+ public int getEquipHair2()
+ {
+ return _equipHair2;
+ }
+
+ public int getAgathionId()
+ {
+ return _agathionId;
+ }
+
+ public int getWeaponEnchantLevel()
+ {
+ return _weaponEnchantLevel;
+ }
+
+ public int getArmorEnchantLevel()
+ {
+ return _armorEnchantLevel;
+ }
+
+ public boolean isFishing()
+ {
+ return _fishing;
+ }
+
+ public int getBaitLocationX()
+ {
+ return _baitLocationX;
+ }
+
+ public int getBaitLocationY()
+ {
+ return _baitLocationY;
+ }
+
+ public int getBaitLocationZ()
+ {
+ return _baitLocationZ;
+ }
+
+ public int getRecommends()
+ {
+ return _recommends;
+ }
+
+ public int getNobleLevel()
+ {
+ return _nobleLevel;
+ }
+
+ public boolean isHero()
+ {
+ return _hero;
+ }
+
+ public int getClanId()
+ {
+ return _clanId;
+ }
+
+ public int getPledgeStatus()
+ {
+ return _pledgeStatus;
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
index c5af087f72..551733f42a 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
@@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object
*
* Do Pickup Item : PCInstance and Pet
*
- * @param player Player that pick up the item
+ * @param character Character that pick up the item
*/
- public final void pickupMe(L2Character player)
+ public final void pickupMe(L2Character character)
{
assert getWorldRegion() != null;
final L2WorldRegion oldregion = getWorldRegion();
// Create a server->client GetItem packet to pick up the L2ItemInstance
- player.broadcastPacket(new GetItem(this, player.getObjectId()));
+ character.broadcastPacket(new GetItem(this, character.getObjectId()));
synchronized (this)
{
@@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object
// Remove the L2ItemInstance from the world
L2World.getInstance().removeVisibleObject(this, oldregion);
- if (player.isPlayer())
+ if (character.isPlayer())
{
// Notify to scripts
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem());
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem());
}
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java
index 83f6e88b77..7505001c60 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java
@@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable
public boolean checkCondition(L2Character activeChar, L2Object object)
{
- if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)
+ if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION))
{
return true;
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
index b7eda58d00..13932008ff 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -159,7 +160,7 @@ public class SkillCaster implements Runnable
}
// You should not heal/buff monsters without pressing the ctrl button.
- if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed)
+ if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed)
{
caster.sendPacket(SystemMessageId.INVALID_TARGET);
return null;
@@ -609,6 +610,10 @@ public class SkillCaster implements Runnable
// Add hate to the attackable, and put it in the attack list.
((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint());
((L2Character) obj).addAttackerToAttackByList(caster);
+ if (obj.isFakePlayer())
+ {
+ player.updatePvPStatus();
+ }
}
// notify target AI about the attack
@@ -617,10 +622,19 @@ public class SkillCaster implements Runnable
((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster);
}
}
- else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0))))
+ else if (((skill.getEffectPoint() > 0) && obj.isMonster()) //
+ || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) //
+ || (((L2Character) obj).getReputation() < 0) //
+ )))
{
// Supporting players or monsters result in pvpflag.
- player.updatePvPStatus();
+ if (!obj.isFakePlayer() //
+ || (obj.isFakePlayer() //
+ && (!((L2Npc) obj).isScriptValue(0) //
+ || (((L2Npc) obj).getReputation() < 0))))
+ {
+ player.updatePvPStatus();
+ }
}
}
@@ -630,7 +644,7 @@ public class SkillCaster implements Runnable
EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob);
// On Skill See logic
- if (npcMob.isAttackable())
+ if (npcMob.isAttackable() && !npcMob.isFakePlayer())
{
final L2Attackable attackable = (L2Attackable) npcMob;
@@ -652,6 +666,19 @@ public class SkillCaster implements Runnable
}
});
}
+ else if (caster.isFakePlayer()) // fake player attacks player
+ {
+ if (target.isPlayable() || target.isFakePlayer())
+ {
+ final L2Npc npc = ((L2Npc) caster);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ npc.broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+ }
}
catch (Exception e)
{
@@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable
return false;
}
}
-
return true;
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
index fdf0dadf55..06bea1b4cf 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
@@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
@@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
@@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
index 91a9ce830a..ccd2d1d13a 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
@@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket
}
case 1:
{
- if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC))
+ if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer()))
{
obj.onAction(activeChar, false);
}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
index 876c53c093..06464d9911 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket
return;
}
- if (Config.FORBIDDEN_NAMES.length > 1)
+ if (Config.FORBIDDEN_NAMES.length > 0)
{
for (String st : Config.FORBIDDEN_NAMES)
{
@@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
+ return;
+ }
+
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
index 06bfa3c200..01c8b0c67f 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
@@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class RequestBlock implements IClientIncomingPacket
{
@@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket
case BLOCK:
case UNBLOCK:
{
+ // TODO: Save in database? :P
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (_type == BLOCK)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
// can't use block/unblock for locating invisible characters
if (targetId <= 0)
{
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
index ceb67b0f5f..cf79bdb24c 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable;
import com.l2jmobius.gameserver.util.Util;
@@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket
{
result = NAME_ALREADY_EXISTS;
}
+ else if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ result = NAME_ALREADY_EXISTS;
+ }
else if (_name.length() > 16)
{
result = INVALID_LENGTH;
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
index b0ace828dc..ee8bcd656b 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
@@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart;
@@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance activeChar = client.getActiveChar();
- final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (activeChar == null)
{
return;
}
+
+ if (FakePlayerData.getInstance().isTalkable(_player))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(_player);
+ if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ if (activeChar.isProcessingRequest())
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(name);
+ activeChar.sendPacket(msg);
+ return;
+ }
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000);
+ activeChar.blockRequest();
+ return;
+ }
+
+ final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (targetChar == null)
{
activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
index f104c94161..c0042d45c5 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
@@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Party;
@@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ if (player.getParty() == null)
+ {
+ player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED);
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY);
+ }
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance requestor = client.getActiveChar();
- final L2PcInstance target = L2World.getInstance().getPlayer(_name);
-
if (requestor == null)
{
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ requestor.sendPacket(sm);
+ if (!requestor.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000);
+ requestor.blockRequest();
+ }
+ else
+ {
+ requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY);
+ }
+ return;
+ }
+
+ final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (target == null)
{
requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
index 292153afd8..37c539556f 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
@@ -17,12 +17,15 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class ...
@@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return;
}
+ if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName())))
+ {
+ if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0)
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN);
+ }
+ else
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(activeChar.getTarget().getName());
+ activeChar.sendPacket(msg);
+ }
+ }
+ return;
+ }
+
final L2PcInstance target = L2World.getInstance().getPlayer(_target);
if (target == null)
{
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
index 3d5bcaeca5..9cbb114e88 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
@@ -23,6 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.BlockList;
@@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().isTalkable(_receiver))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1);
+ sm.addString(FakePlayerData.getInstance().getProperName(_receiver));
+ activeChar.sendPacket(sm);
+ return;
+ }
+
final int receiverId = CharNameTable.getInstance().getIdByName(_receiver);
if (receiverId <= 0)
{
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
index 8156905e94..1336c2bdb7 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
@@ -17,6 +17,7 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
@@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket
}
final L2Object object = activeChar.getTarget();
-
if (!(object instanceof L2PcInstance))
{
if (object == null)
{
client.sendPacket(SystemMessageId.SELECT_TARGET);
}
+ else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName()))
+ {
+ if (activeChar.getRecomLeft() <= 0)
+ {
+ client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER);
+ return;
+ }
+
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT);
+ sm.addString(FakePlayerData.getInstance().getProperName(object.getName()));
+ sm.addInt(activeChar.getRecomLeft());
+ client.sendPacket(sm);
+
+ activeChar.setRecomLeft(activeChar.getRecomLeft() - 1);
+ client.sendPacket(new UserInfo(activeChar));
+ client.sendPacket(new ExVoteSystemInfo(activeChar));
+ }
else
{
client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
index d77dc881b3..5d7e35eb43 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
@@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.skills.AbnormalType;
@@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target.getName());
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE));
+ return;
+ }
+ if (!player.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1);
+ sm.addString(name);
+ player.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000);
+ player.blockRequest();
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE);
+ }
+ return;
+ }
+
if (!target.isPlayer())
{
client.sendPacket(SystemMessageId.INVALID_TARGET);
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
index 4fa25283a7..530a6d7a01 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
@@ -17,6 +17,8 @@
package com.l2jmobius.gameserver.network.clientpackets.friend;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST));
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
final L2PcInstance friend = L2World.getInstance().getPlayer(_name);
// Target is not found in the game.
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
index 2170ef2e94..017541bd86 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
@@ -22,6 +22,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
- if (receiver.getFriendList().contains(sender.getObjectId()))
+ if (receiver != null)
{
- _mask |= 0x01;
- }
- if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
- {
- _mask |= 0x02;
- }
- if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
- {
- _mask |= 0x04;
- }
- if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
- {
- _mask |= 0x08;
+ if (receiver.getFriendList().contains(sender.getObjectId()))
+ {
+ _mask |= 0x01;
+ }
+ if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
+ {
+ _mask |= 0x02;
+ }
+ if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
+ {
+ _mask |= 0x04;
+ }
+ if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
+ {
+ _mask |= 0x08;
+ }
}
// Does not shows level
@@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket
}
}
+ /**
+ * Used by fake players.
+ * @param sender
+ * @param receiver
+ * @param name
+ * @param messageType
+ * @param text
+ */
+ public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
+ {
+ _objectId = sender.getObjectId();
+ _charName = name;
+ _charLevel = sender.getLevel();
+ _textType = messageType;
+ _text = text;
+ }
+
/**
* @param objectId
* @param messageType
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
new file mode 100644
index 0000000000..d1b7900f12
--- /dev/null
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import java.util.Set;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.enums.Sex;
+import com.l2jmobius.gameserver.model.L2Clan;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerInfo implements IClientOutgoingPacket
+{
+ private final L2Npc _npc;
+ private final int _objId;
+ private final int _x, _y, _z, _heading;
+ private final int _mAtkSpd, _pAtkSpd;
+ private final int _runSpd, _walkSpd;
+ private final int _swimRunSpd;
+ private final int _swimWalkSpd;
+ private final int _flyRunSpd;
+ private final int _flyWalkSpd;
+ private final double _moveMultiplier;
+ private final float _attackSpeedMultiplier;
+ private final FakePlayerHolder _fpcHolder;
+ private final L2Clan _clan;
+
+ public FakePlayerInfo(L2Npc npc)
+ {
+ _npc = npc;
+ _objId = npc.getObjectId();
+ _x = npc.getX();
+ _y = npc.getY();
+ _z = npc.getZ();
+ _heading = npc.getHeading();
+ _mAtkSpd = npc.getMAtkSpd();
+ _pAtkSpd = npc.getPAtkSpd();
+ _attackSpeedMultiplier = npc.getAttackSpeedMultiplier();
+ _moveMultiplier = npc.getMovementSpeedMultiplier();
+ _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier);
+ _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier);
+ _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier);
+ _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier);
+ _flyRunSpd = npc.isFlying() ? _runSpd : 0;
+ _flyWalkSpd = npc.isFlying() ? _walkSpd : 0;
+ _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId());
+ _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId());
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.CHAR_INFO.writeId(packet);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(0x00); // vehicleId
+ packet.writeD(_objId);
+ packet.writeS(_npc.getName());
+
+ packet.writeH(_npc.getRace().ordinal());
+ packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00);
+ packet.writeD(_fpcHolder.getClassId());
+
+ packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER
+ packet.writeD(_fpcHolder.getEquipHead());
+ packet.writeD(_fpcHolder.getEquipRHand());
+ packet.writeD(_fpcHolder.getEquipLHand());
+ packet.writeD(_fpcHolder.getEquipGloves());
+ packet.writeD(_fpcHolder.getEquipChest());
+ packet.writeD(_fpcHolder.getEquipLegs());
+ packet.writeD(_fpcHolder.getEquipFeet());
+ packet.writeD(_fpcHolder.getEquipCloak());
+ packet.writeD(_fpcHolder.getEquipRHand()); // dual hand
+ packet.writeD(_fpcHolder.getEquipHair());
+ packet.writeD(_fpcHolder.getEquipHair2());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderAugument())
+ {
+ packet.writeQ(0x00);
+ }
+
+ packet.writeC(_fpcHolder.getArmorEnchantLevel());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderVisualId())
+ {
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(_npc.getScriptValue()); // getPvpFlag()
+ packet.writeD(_npc.getReputation());
+
+ packet.writeD(_mAtkSpd);
+ packet.writeD(_pAtkSpd);
+
+ packet.writeH(_runSpd);
+ packet.writeH(_walkSpd);
+ packet.writeH(_swimRunSpd);
+ packet.writeH(_swimWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeF(_moveMultiplier);
+ packet.writeF(_attackSpeedMultiplier);
+
+ packet.writeF(_npc.getCollisionRadius());
+ packet.writeF(_npc.getCollisionHeight());
+
+ packet.writeD(_fpcHolder.getHair());
+ packet.writeD(_fpcHolder.getHairColor());
+ packet.writeD(_fpcHolder.getFace());
+
+ packet.writeS(_npc.getTemplate().getTitle());
+
+ if (_clan != null)
+ {
+ packet.writeD(_clan.getId());
+ packet.writeD(_clan.getCrestId());
+ packet.writeD(_clan.getAllyId());
+ packet.writeD(_clan.getAllyCrestId());
+ }
+ else
+ {
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked)
+ packet.writeC(_npc.isRunning() ? 0x01 : 0x00);
+ packet.writeC(_npc.isInCombat() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isInvisible() ? 0x01 : 0x00);
+
+ packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount
+ packet.writeC(0x00); // getPrivateStoreType().getId()
+
+ packet.writeH(0x00); // getCubics().size()
+ // getCubics().keySet().forEach(packet::writeH);
+
+ packet.writeC(0x00);
+
+ packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0);
+ packet.writeH(_fpcHolder.getRecommends());
+ packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000
+
+ packet.writeD(_fpcHolder.getClassId());
+ packet.writeD(0x00);
+ packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel
+
+ packet.writeC(_npc.getTeam().getId());
+
+ packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00);
+ packet.writeC(_fpcHolder.getNobleLevel());
+ packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00);
+
+ packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00);
+
+ packet.writeD(_fpcHolder.getBaitLocationX());
+ packet.writeD(_fpcHolder.getBaitLocationY());
+ packet.writeD(_fpcHolder.getBaitLocationZ());
+
+ packet.writeD(_fpcHolder.getNameColor());
+
+ packet.writeD(_heading);
+
+ packet.writeC(_fpcHolder.getPledgeStatus());
+ packet.writeH(0x00); // getPledgeType()
+
+ packet.writeD(_fpcHolder.getTitleColor());
+
+ packet.writeC(0x00); // isCursedWeaponEquipped
+
+ packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0
+ packet.writeD(0x00); // getTransformationDisplayId()
+ packet.writeD(_fpcHolder.getAgathionId());
+
+ packet.writeC(0x00);
+
+ packet.writeD(0x00); // getCurrentCp()
+ packet.writeD(_npc.getMaxHp());
+ packet.writeD((int) Math.round(_npc.getCurrentHp()));
+ packet.writeD(_npc.getMaxMp());
+ packet.writeD((int) Math.round(_npc.getCurrentMp()));
+
+ packet.writeC(0x00);
+ final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects();
+ packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0));
+ for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects)
+ {
+ packet.writeH(abnormalVisualEffect.getClientId());
+ }
+ if (_npc.isInvisible())
+ {
+ packet.writeH(AbnormalVisualEffect.STEALTH.getClientId());
+ }
+ packet.writeC(0x00); // cocPlayer.getPosition()
+ packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00);
+ packet.writeC(0x00); // Used Ability Points
+ return true;
+ }
+}
diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
index 4fb1a757e6..c294edab2a 100644
--- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
+++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
@@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket
addComponentType(NpcInfoType.TITLE_NPCSTRINGID);
}
+ if (_npc.getReputation() != 0)
+ {
+ addComponentType(NpcInfoType.REPUTATION);
+ }
+
if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible())
{
addComponentType(NpcInfoType.ABNORMALS);
@@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket
}
if (containsMask(NpcInfoType.REPUTATION))
{
- packet.writeD(0x00); // Name color
+ packet.writeD(_npc.getReputation()); // Reputation
}
if (containsMask(NpcInfoType.CLAN))
{
diff --git a/L2J_Mobius_3.0_Helios/readme.txt b/L2J_Mobius_3.0_Helios/readme.txt
index 613ec18d32..03c043d22c 100644
--- a/L2J_Mobius_3.0_Helios/readme.txt
+++ b/L2J_Mobius_3.0_Helios/readme.txt
@@ -101,6 +101,7 @@ Customs:
-Classmaster
-Community board
-Faction system
+-Fake players
-Find PvP
-NPC stat multipliers
-Realtime offline trade
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml
index 171e08cb12..f9067f1377 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml
@@ -392,6 +392,9 @@
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini
new file mode 100644
index 0000000000..f745b0d31e
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini
@@ -0,0 +1,33 @@
+# ---------------------------------------------------------------------------
+# Fake players
+# ---------------------------------------------------------------------------
+
+# Enable fake players.
+EnableFakePlayers = False
+
+# Enable chatting with fake players.
+FakePlayerChat = True
+
+# Enable shots usage for fake players.
+FakePlayerUseShots = True
+
+# Reward PvP kills by killing fake players.
+FakePlayerKillsRewardPvP = True
+
+# Fake player kills apply karma rules.
+FakePlayerUnflaggedKillsKarma = True
+
+# Aggressive AI fake players attack nearby monsters.
+FakePlayerAggroMonsters = True
+
+# Aggressive AI fake players attack nearby players.
+FakePlayerAggroPlayers = False
+
+# Aggressive AI fake players attack nearby fake players.
+FakePlayerAggroFPC = False
+
+# Fake players can drop items when killing monsters.
+FakePlayerCanDropItems = True
+
+# Fake players can pickup dropped items.
+FakePlayerCanPickup = True
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml
new file mode 100644
index 0000000000..f5da5bfc8e
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml
new file mode 100644
index 0000000000..f36096ed4a
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml
index 98e0d38815..4a7f998b00 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml
@@ -2402,4 +2402,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
index 6f29855cc3..d12ee2e7c4 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java
@@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI
final L2Character creature = event.getSeen();
final L2Npc npc = (L2Npc) event.getSeer();
- if (creature.isPlayer())
+ if (creature.isPlayer() || creature.isFakePlayer())
{
npc.setTarget(creature);
npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill());
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
new file mode 100644
index 0000000000..e1dde7324e
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+import ai.AbstractNpcAI;
+
+/**
+ * TODO: Move it to L2Character.
+ * @author Mobius
+ */
+public class PvpFlaggingStopTask extends AbstractNpcAI
+{
+ private PvpFlaggingStopTask()
+ {
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if ((npc == null) || npc.isDead())
+ {
+ return null;
+ }
+
+ if (event.startsWith("FLAG_CHECK"))
+ {
+ final L2Object target = npc.getTarget();
+ if ((target != null) && (target.isPlayable() || target.isFakePlayer()))
+ {
+ npc.setScriptValue(1); // in combat
+ cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null);
+ cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null);
+ startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null);
+ startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null);
+ }
+ }
+ else if (event.startsWith("FINISH_FLAG"))
+ {
+ if (npc.isScriptValue(1))
+ {
+ npc.setScriptValue(2); // blink status
+ npc.broadcastInfo(); // update flag status
+ startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null);
+ }
+ }
+ else if (event.startsWith("REMOVE_FLAG"))
+ {
+ if (npc.isScriptValue(2))
+ {
+ npc.setScriptValue(0); // not in combat
+ npc.broadcastInfo(); // update flag status
+ }
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ public static void main(String[] args)
+ {
+ new PvpFlaggingStopTask();
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
new file mode 100644
index 0000000000..dec3449549
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.CommonUtil;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.base.ClassId;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
+import com.l2jmobius.gameserver.model.skills.SkillCaster;
+
+import ai.AbstractNpcAI;
+
+/**
+ * Town Fake Player walkers that receive buffs from Adventurer NPC.
+ * @author Mobius
+ */
+public class RecieveAdventurerBuffs extends AbstractNpcAI
+{
+ // NPCs
+ private static final int[] ADVENTURERS_GUIDE =
+ {
+ 32327,
+ 33950,
+ };
+ private static final int[] FAKE_PLAYER_IDS =
+ {
+ 80000
+ };
+ // Skills
+ // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
+ private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
+ private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
+ private static final SkillHolder[] GROUP_BUFFS =
+ {
+ new SkillHolder(15642, 1), // Horn Melody (Adventurer)
+ new SkillHolder(15643, 1), // Drum Melody (Adventurer)
+ new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
+ new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
+ new SkillHolder(15646, 1), // Harp Melody (Adventurer)
+ new SkillHolder(15647, 1), // Lute Melody (Adventurer)
+ new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
+ new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
+ new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
+ };
+
+ private RecieveAdventurerBuffs()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ addSpawnId(FAKE_PLAYER_IDS);
+ }
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead())
+ {
+ if (!npc.isMoving())
+ {
+ for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100))
+ {
+ if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId()))
+ {
+ for (SkillHolder holder : GROUP_BUFFS)
+ {
+ SkillCaster.triggerCast(nearby, npc, holder.getSkill());
+ }
+ if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage())
+ {
+ SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill());
+ }
+ else
+ {
+ SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill());
+ }
+ break;
+ }
+ }
+ }
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null);
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ @Override
+ public String onSpawn(L2Npc npc)
+ {
+ startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null);
+ return super.onSpawn(npc);
+ }
+
+ public static void main(String[] args)
+ {
+ new RecieveAdventurerBuffs();
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java
index 3c72228c33..3228e5fe09 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
+import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -410,6 +411,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
+ AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
index 6b02816d9e..d6d6a99080 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
@@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (Config.ALT_GAME_VIEWNPC)
{
- if (!target.isNpc())
+ if (!target.isNpc() || target.isFakePlayer())
{
return false;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
new file mode 100644
index 0000000000..99926f0df7
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package handlers.admincommandhandlers;
+
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author Mobius
+ */
+public class AdminFakePlayers implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_fakechat"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ if (command.startsWith("admin_fakechat"))
+ {
+ final String[] words = command.substring(15).split(" ");
+ if (words.length < 3)
+ {
+ activeChar.sendMessage("Usage: //fakechat playername fpcname message");
+ return false;
+ }
+ final L2PcInstance player = L2World.getInstance().getPlayer(words[0]);
+ if (player == null)
+ {
+ activeChar.sendMessage("Player not found.");
+ return false;
+ }
+ final String fpcName = FakePlayerData.getInstance().getProperName(words[1]);
+ if (fpcName == null)
+ {
+ activeChar.sendMessage("Fake player not found.");
+ return false;
+ }
+ String message = "";
+ for (int i = 0; i < words.length; i++)
+ {
+ if (i < 2)
+ {
+ continue;
+ }
+ message += (words[i] + " ");
+ }
+ FakePlayerChatManager.getInstance().sendChat(player, fpcName, message);
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
index fee328deb5..f3dfff6e7d 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
@@ -31,6 +31,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@@ -44,9 +45,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@@ -294,6 +298,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
+ case "fakeplayers":
+ {
+ FakePlayerData.getInstance().load();
+ for (L2Object obj : L2World.getInstance().getVisibleObjects())
+ {
+ if (obj.isFakePlayer())
+ {
+ obj.broadcastInfo();
+ }
+ }
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
+ break;
+ }
+ case "fakeplayerchat":
+ {
+ FakePlayerChatManager.getInstance().load();
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
+ break;
+ }
default:
{
activeChar.sendMessage(RELOAD_USAGE);
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
index 99f2e9e9d7..7db79fe31d 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
@@ -17,8 +17,10 @@
package handlers.chathandlers;
import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IChatHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PcCondOverride;
@@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
+ if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
+ {
+ if (FakePlayerData.getInstance().isTalkable(target))
+ {
+ if (Config.FAKE_PLAYER_CHAT)
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target);
+ activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
+ FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
+ }
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
+ }
+ return;
+ }
+
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
index 41b1f99bcf..b38f5ca16d 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
@@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
-
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java
index 766844c759..2191ab4581 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java
@@ -16,9 +16,11 @@
*/
package handlers.playeractions;
+import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
+ player.onTransactionResponse();
+ }
+ }
+
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
- if ((target == null) || !target.isPlayer())
+ if ((target == null))
+ {
+ player.sendPacket(SystemMessageId.INVALID_TARGET);
+ return;
+ }
+
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
+ sm.addString(target.getName());
+ player.sendPacket(sm);
+ if (!player.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
+ player.blockRequest();
+ }
+ return;
+ }
+
+ if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
index 12f33e2bbc..9dd91055b9 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java
@@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest
@Id(WINDY_HEALING_POTION_1)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(4, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
+ {
+ qs.setCond(4, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
index 0efb5383f4..34594dbc40 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java
@@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest
@Id(HIGH_GRADE_LOVE_POTION)
public void onItemCreate(OnItemCreate event)
{
- final L2PcInstance player = event.getActiveChar();
- final QuestState qs = getQuestState(player, false);
- if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ final L2PcInstance player = event.getActiveChar().getActingPlayer();
+ if (player != null)
{
- qs.setCond(2, true);
+ final QuestState qs = getQuestState(player, false);
+ if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
+ {
+ qs.setCond(2, true);
+ }
}
}
}
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml
new file mode 100644
index 0000000000..ea77878c2c
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml
new file mode 100644
index 0000000000..8470293122
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml
@@ -0,0 +1,341 @@
+
+
+
+
+ HUMAN
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ORC
+ MALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DWARF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KAMAEL
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HUMAN
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DARK_ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FAKE_PLAYER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml
new file mode 100644
index 0000000000..589f29b215
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ ERTHEIA
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd
new file mode 100644
index 0000000000..2b2c94e75b
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd
new file mode 100644
index 0000000000..0628acefc3
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd
index 6f00944cff..ae80c3ff63 100644
--- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd
+++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd
@@ -201,6 +201,8 @@
+
+
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java
index e7a921883b..841ae086c8 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java
@@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
+ public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@@ -1154,6 +1155,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
+ public static boolean FAKE_PLAYERS_ENABLED;
+ public static boolean FAKE_PLAYER_CHAT;
+ public static boolean FAKE_PLAYER_USE_SHOTS;
+ public static boolean FAKE_PLAYER_KILL_PVP;
+ public static boolean FAKE_PLAYER_KILL_KARMA;
+ public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
+ public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
+ public static boolean FAKE_PLAYER_AGGRO_FPC;
+ public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
+ public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@@ -2575,6 +2586,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
+ // Load FakePlayers config file (if exists)
+ final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
+ FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
+ FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
+ FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
+ FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
+ FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
+ FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
+ FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
+ FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
+ FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
+ FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
+
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java
index 8be60100d7..f90fd5cedc 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java
@@ -61,6 +61,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
@@ -287,6 +289,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
+ FakePlayerData.getInstance();
+ FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
MonsterBookData.getInstance();
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
index 6253fa9329..1da1b21546 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
@@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
- if (npc.isAggressive() || (npc instanceof L2GuardInstance))
+ if (npc.isFakePlayer() && npc.isAggressive())
+ {
+ final List droppedItems = npc.getFakePlayerDrops();
+ if (droppedItems.isEmpty())
+ {
+ L2Character nearestTarget = null;
+ double closestDistance = Double.MAX_VALUE;
+ for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange()))
+ {
+ if ((t == _actor) || (t == null) || t.isDead())
+ {
+ continue;
+ }
+ if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer()))
+ {
+ final int hating = npc.getHating(t);
+ final double distance = npc.calculateDistance(t, false, false);
+ if ((hating == 0) && (closestDistance > distance))
+ {
+ nearestTarget = t;
+ closestDistance = distance;
+ }
+ }
+ }
+ if (nearestTarget != null)
+ {
+ npc.addDamageHate(nearestTarget, 0, 1);
+ }
+ }
+ else if (!npc.isInCombat()) // must pickup items
+ {
+ final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped
+ final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex);
+ if ((droppedItem != null) && droppedItem.isSpawned())
+ {
+ if (npc.calculateDistance(droppedItem, false, false) > 50)
+ {
+ moveTo(droppedItem);
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ droppedItem.pickupMe(npc);
+ if (Config.SAVE_DROPPED_ITEM)
+ {
+ ItemsOnGroundManager.getInstance().removeObject(droppedItem);
+ }
+ if (droppedItem.getItem().hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills())
+ {
+ SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
+ }
+ npc.broadcastInfo(); // ? check if this is necessary
+ }
+ }
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ }
+ npc.setRunning();
+ }
+ }
+ else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
- if (t.isPlayable())
+ if (t.isFakePlayer())
+ {
+ if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
+ {
+ final int hating = npc.getHating(t);
+ if (hating == 0)
+ {
+ npc.addDamageHate(t, 0, 1);
+ }
+ }
+ }
+ else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
new file mode 100644
index 0000000000..0a6ca5267a
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerData implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName());
+
+ private final Map _fakePlayerInfos = new HashMap<>();
+ private final Map _fakePlayerNames = new HashMap<>();
+ private final Map _fakePlayerIds = new HashMap<>();
+ private final List _talkableFakePlayerNames = new ArrayList<>();
+
+ protected FakePlayerData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ _fakePlayerInfos.clear();
+ _fakePlayerNames.clear();
+ _fakePlayerIds.clear();
+ _talkableFakePlayerNames.clear();
+ parseDatapackFile("data/FakePlayerVisualData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode));
+ final int npcId = set.getInt("npcId");
+ final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
+ final String name = template.getName();
+ if (CharNameTable.getInstance().getIdByName(name) > 0)
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists.");
+ }
+ else
+ {
+ _fakePlayerIds.put(name, npcId); // name - npcId
+ _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name
+ _fakePlayerInfos.put(npcId, new FakePlayerHolder(set));
+ if (template.isFakePlayerTalkable())
+ {
+ _talkableFakePlayerNames.add(name.toLowerCase());
+ }
+ }
+ }));
+ }
+
+ public int getNpcIdByName(String name)
+ {
+ return _fakePlayerIds.get(name);
+ }
+
+ public String getProperName(String name)
+ {
+ return _fakePlayerNames.get(name.toLowerCase());
+ }
+
+ public Boolean isTalkable(String name)
+ {
+ return _talkableFakePlayerNames.contains(name.toLowerCase());
+ }
+
+ public FakePlayerHolder getInfo(int npcId)
+ {
+ return _fakePlayerInfos.get(npcId);
+ }
+
+ public static FakePlayerData getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerData _instance = new FakePlayerData();
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
index 883e877bc7..f03a2395f1 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
@@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader
set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty"));
+ set.set("fakePlayer", parseBoolean(attrs, "fakePlayer"));
+ set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable"));
break;
}
case "skill_list":
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
index 2ff4c9322d..15bd310bd6 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
@@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
+ if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
+ {
+ return;
+ }
+
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
index a145b65dba..d525c02a6a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
@@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
-
if (target == null)
{
return false;
}
- final L2PcInstance bot = target.getActingPlayer();
+ final L2Character bot = ((L2Character) target);
- if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
+ if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
- if (bot.isInOlympiadMode())
+ if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
- if (bot.getExp() == bot.getStat().getStartingExp())
+ if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
- handleReport(bot, rcd);
+ if (bot.isPlayer())
+ {
+ handleReport(bot.getActingPlayer(), rcd);
+ }
return true;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java
index 7454554076..ace19486b5 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
@@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
- * @param actor : L2PcInstance Player requesting the item creation
+ * @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
- public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
+ public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
index b621b4c4cb..bb0e928daf 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
@@ -217,6 +217,7 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
+ cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
// If the clan does not exist...
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
new file mode 100644
index 0000000000..16a0da92bc
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.instancemanager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.datatables.SpawnTable;
+import com.l2jmobius.gameserver.enums.ChatType;
+import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.model.L2Spawn;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
+import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
+
+/**
+ * @author Mobius
+ */
+public final class FakePlayerChatManager implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
+ final List MESSAGES = new ArrayList<>();
+ private static final int MIN_DELAY = 5000;
+ private static final int MAX_DELAY = 15000;
+
+ protected FakePlayerChatManager()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT)
+ {
+ MESSAGES.clear();
+ parseDatapackFile("data/FakePlayerChatData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode));
+ MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers")));
+ }));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
+ }
+
+ private void manageResponce(L2PcInstance player, String fpcName, String message)
+ {
+ if (player == null)
+ {
+ return;
+ }
+
+ final String text = message.toLowerCase();
+
+ // tricky question
+ if (text.contains("can you see me"))
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ if (npc.calculateDistance(player, false, false) < 3000)
+ {
+ if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
+ }
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
+ }
+ return;
+ }
+ }
+ }
+
+ for (FakePlayerChatHolder chatHolder : MESSAGES)
+ {
+ if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
+ {
+ continue;
+ }
+
+ switch (chatHolder.getSearchMethod())
+ {
+ case "EQUALS":
+ {
+ if (text.equals(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "STARTS_WITH":
+ {
+ if (text.startsWith(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "CONTAINS":
+ {
+ boolean allFound = true;
+ for (String word : chatHolder.getSearchText())
+ {
+ if (!text.contains(word))
+ {
+ allFound = false;
+ }
+ }
+ if (allFound)
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public void sendChat(L2PcInstance player, String fpcName, String message)
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
+ }
+ }
+ }
+
+ public static FakePlayerChatManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java
index 1a62714f0e..50a3cc2145 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
@@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class DropProtection implements Runnable
{
private volatile boolean _isProtected = false;
- private L2PcInstance _owner = null;
+ private L2Character _owner = null;
private ScheduledFuture> _task = null;
private static final long PROTECTED_MILLIS_TIME = 15000;
@@ -46,7 +47,7 @@ public class DropProtection implements Runnable
return _isProtected;
}
- public L2PcInstance getOwner()
+ public L2Character getOwner()
{
return _owner;
}
@@ -91,12 +92,12 @@ public class DropProtection implements Runnable
_task = null;
}
- public synchronized void protect(L2PcInstance player)
+ public synchronized void protect(L2Character character)
{
unprotect();
_isProtected = true;
- _owner = player;
+ _owner = character;
if (_owner == null)
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java
index 459660c7ca..92837e4b25 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java
@@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
return false;
}
+ /**
+ * Verify if object is a fake player.
+ * @return {@code true} if object is a fake player, {@code false} otherwise
+ */
+ public boolean isFakePlayer()
+ {
+ return false;
+ }
+
/**
* Verify if object is instance of L2ServitorInstance.
* @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
index 2ecce60d39..ddc1a1b8d4 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
@@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
- return _mustGiveExpSp;
+ return _mustGiveExpSp && !isFakePlayer();
}
/**
@@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
+ // unless its a fake player and they can drop items
+ if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
+ {
+ final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);
+ if (deathItems != null)
+ {
+ for (ItemHolder drop : deathItems)
+ {
+ final L2Item item = ItemTable.getInstance().getTemplate(drop.getId());
+ // Check if the autoLoot mode is active
+ if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
+ {
+ // do nothing
+ }
+ else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : item.getAllSkills())
+ {
+ SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false);
+ }
+ mainDamageDealer.broadcastInfo(); // ? check if this is necessary
+ }
+ else
+ {
+ final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
+ if (Config.FAKE_PLAYER_CAN_PICKUP)
+ {
+ mainDamageDealer.getFakePlayerDrops().add(droppedItem);
+ }
+ }
+ }
+ }
+ }
return;
}
@@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
- if (lastAttacker == null)
+ if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc
_harvestItem.set(null);
_sweepItems.set(null);
+ // fake players
+ if (isFakePlayer())
+ {
+ getFakePlayerDrops().clear(); // Clear existing fake player drops
+ setReputation(0); // reset reputation
+ setScriptValue(0); // remove pvp flag
+ setRunning(); // don't walk
+ }
+
// Clear mod Seeded stat
_seeded = false;
_seed = null;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java
index 226b8e981a..6dd50e079f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java
@@ -30,6 +30,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList;
@@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
+ private int _reputation = 0;
+
/** Map containing all skills of this character. */
private final Map _skills = new ConcurrentSkipListMap<>();
/** Map containing the skill reuse time stamps. */
@@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
/** A set containing the shot types currently charged. */
private Set _chargedShots = EnumSet.noneOf(ShotType.class);
+ /** A list containing the dropped items of this fake player. */
+ private final List _fakePlayerDrops = new CopyOnWriteArrayList<>();
+
/**
* Creates a creature.
* @param template the creature template
@@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
broadcastPacket(attack);
}
+ if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
+ {
+ final L2Npc npc = ((L2Npc) this);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+
// Notify AI with EVT_READY_TO_ACT
ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
}
@@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
final Instance instanceWorld = getInstanceWorld();
- if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
+ if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
{
return false;
}
@@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist());
}
+ public int getReputation()
+ {
+ return _reputation;
+ }
+
+ public void setReputation(int reputation)
+ {
+ _reputation = reputation;
+ }
+
/**
* Gets the distance to target.
* @param target the target
@@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
+
+ public List getFakePlayerDrops()
+ {
+ return _fakePlayerDrops;
+ }
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
index 5742c07807..b669e16e76 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
@@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.enums.Team;
+import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.handler.BypassHandler;
import com.l2jmobius.gameserver.handler.IBypassHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
+import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
@@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
+import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@@ -125,6 +130,7 @@ public class L2Npc extends L2Character
private boolean _isRandomAnimationEnabled = true;
private boolean _isRandomWalkingEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
+ private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@@ -364,7 +370,11 @@ public class L2Npc extends L2Character
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@@ -901,6 +911,78 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
+ if (isFakePlayer() && (killer != null) && killer.isPlayable())
+ {
+ final L2PcInstance player = killer.getActingPlayer();
+ if (isScriptValue(0) && (getReputation() >= 0))
+ {
+ if (Config.FAKE_PLAYER_KILL_KARMA)
+ {
+ player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
+ player.setPkKills(player.getPkKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ player.checkItemRestriction();
+ // pk item rewards
+ if (Config.REWARD_PK_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
+ // announce pk
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+ else if (Config.FAKE_PLAYER_KILL_PVP)
+ {
+ player.setPvpKills(player.getPvpKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ // pvp item rewards
+ if (Config.REWARD_PVP_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ }
+ // announce pvp
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+
DecayTaskManager.getInstance().add(this);
final L2Spawn spawn = getSpawn();
@@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ activeChar.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character
@Override
public void rechargeShots(boolean physical, boolean magic, boolean fish)
{
- if (physical && (_soulshotamount > 0))
+ if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS)
{
- if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ if (physical)
{
- return;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic)
+ {
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _soulshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
- chargeShot(ShotType.SOULSHOTS);
}
-
- if (magic && (_spiritshotamount > 0))
+ else
{
- if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ if (physical && (_soulshotamount > 0))
{
- return;
+ if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ {
+ return;
+ }
+ _soulshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic && (_spiritshotamount > 0))
+ {
+ if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ {
+ return;
+ }
+ _spiritshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _spiritshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
- chargeShot(ShotType.SPIRITSHOTS);
}
}
@@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
- * @param player the last attacker or main damage dealer
+ * @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
+ public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character
return null;
}
- item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
+ item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
- if (player != null)
+ if (character != null)
{
- item.getDropProtection().protect(player);
+ item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character
}
/**
- * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
- * @param player the last attacker or main damage dealer
+ * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
+ * @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
+ public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
- return dropItem(player, item.getId(), item.getCount());
+ return dropItem(character, item.getId(), item.getCount());
}
@Override
@@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character
return Config.SHOP_MIN_RANGE_FROM_NPC;
}
+ @Override
+ public boolean isFakePlayer()
+ {
+ return _isFakePlayer;
+ }
+
/**
* @return The player's object Id this NPC is cloning.
*/
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
index 34550c3dd8..10ad419ea4 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
@@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
- public abstract int getReputation();
-
public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove);
public abstract void storeMe();
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
index 8427885746..87cc552765 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
@@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
@@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
+ if (target.isFakePlayer())
+ {
+ getOwner().updatePvPStatus();
+ }
}
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
index a5fd31dedd..44ee919058 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
@@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
index aa4f132fce..6a94be63b5 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
@@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
- if (attacker.isMonster())
+ if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
+ if (isFakePlayer() && isInCombat())
+ {
+ interact = false;
+ // TODO: Fix normal targeting
+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
+ }
+
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
index e9a9976e87..fe55288a3a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
@@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
+ if (isFakePlayer())
+ {
+ return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
+ }
+
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
@@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable
if (attacker.isMonster())
{
- return false;
+ return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
index c41f46c7d1..b561365375 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
@@ -450,9 +450,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
- /** The Reputation of the L2PcInstance */
- private int _reputation;
-
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@@ -2013,24 +2010,16 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
- /**
- * @return the reputation of the PlayerInstance.
- */
- @Override
- public int getReputation()
- {
- return _reputation;
- }
-
public void setInitialReputation(int reputation)
{
- _reputation = reputation;
+ super.setReputation(reputation);
}
/**
* Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param reputation
*/
+ @Override
public void setReputation(int reputation)
{
// Notify to scripts.
@@ -2056,7 +2045,9 @@ public final class L2PcInstance extends L2Playable
}
});
}
- _reputation = reputation;
+
+ super.setReputation(reputation);
+
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation()));
broadcastReputation();
}
@@ -4655,6 +4646,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
+ if (target.isFakePlayer())
+ {
+ updatePvPStatus();
+ }
}
@Override
@@ -4982,22 +4977,42 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
- if (pk != null)
+ final boolean fpcKill = killer.isFakePlayer();
+ if ((pk != null) || fpcKill)
{
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
-
- if (L2Event.isParticipant(pk))
+ if (pk != null)
{
- pk.getEventStatus().addKill(this);
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
+
+ if (L2Event.isParticipant(pk))
+ {
+ pk.getEventStatus().addKill(this);
+ }
+
+ // pvp/pk item rewards
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ // pvp
+ if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
+ {
+ pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ // pk
+ if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
+ {
+ pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
}
// announce pvp/pk
- if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
+ if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
- msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5011,7 +5026,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
- msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -5025,20 +5040,9 @@ public final class L2PcInstance extends L2Playable
}
}
- // pvp/pk item rewards
- if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
- !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0))
{
- // pvp
- if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
- {
- pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
- }
- // pk
- if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
- {
- pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
- }
+ killer.setReputation(killer.getReputation() - 150);
}
}
@@ -5631,6 +5635,14 @@ public final class L2PcInstance extends L2Playable
return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks());
}
+ /**
+ * Used by fake players to emulate proper behavior.
+ */
+ public void blockRequest()
+ {
+ _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
+ }
+
/**
* Select the Warehouse to be used in next activity.
* @param partner
@@ -11568,7 +11580,7 @@ public final class L2PcInstance extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addPcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), -damage);
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
index fb6b184e67..8383d1efc9 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
@@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
+ @Override
public int getReputation()
{
return _owner != null ? _owner.getReputation() : 0;
@@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addCharName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
_owner.sendPacket(sm);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
index dcb3ab34da..164786d5a4 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
@@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (attacker.isPlayable() && (caster.getCurrentCp() > 0))
+ if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (!ignoreCP && attacker.isPlayable())
+ if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{
@@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus
// Send a System Message to the L2PcInstance
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
smsg.addString(getActiveChar().getName());
- smsg.addCharName(attacker);
+ smsg.addString(attacker.getName());
smsg.addInt(fullValue);
getActiveChar().sendPacket(smsg);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
index 2d7f41e9d0..f5bee5dab6 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
@@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _randomWalk;
private boolean _randomAnimation;
private boolean _flying;
+ private boolean _fakePlayer;
+ private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard"));
_randomAnimation = set.getBoolean("randomAnimation", true);
_flying = set.getBoolean("flying", false);
+ _fakePlayer = set.getBoolean("fakePlayer", false);
+ _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
+ public boolean isFakePlayer()
+ {
+ return _fakePlayer;
+ }
+
+ public boolean isFakePlayerTalkable()
+ {
+ return _fakePlayerTalkable;
+ }
+
public boolean canMove()
{
return _canMove;
@@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
case LUCKY_DROP:
{
// try chance before luck
- if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck())
+ if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck())
{
return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax()));
}
@@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// chance
double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE;
}
@@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// amount is calculated after chance returned success
double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER;
// premium amount
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
index df9698d3c3..6cbe42b242 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
@@ -16,7 +16,7 @@
*/
package com.l2jmobius.gameserver.model.events.impl.item;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
@@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent
{
private final String _process;
private final L2ItemInstance _item;
- private final L2PcInstance _activeChar;
+ private final L2Character _activeChar;
private final Object _reference;
- public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference)
+ public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference)
{
_process = process;
_item = item;
@@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent
return _item;
}
- public L2PcInstance getActiveChar()
+ public L2Character getActiveChar()
{
return _activeChar;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
new file mode 100644
index 0000000000..3008d340b3
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerChatHolder
+{
+ private final String _fpcName;
+ private final String _searchMethod;
+ private final List _searchText;
+ private final List _answers;
+
+ public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers)
+ {
+ _fpcName = fpcName;
+ _searchMethod = searchMethod;
+ _searchText = new ArrayList<>(Arrays.asList(searchText.split(";")));
+ _answers = new ArrayList<>(Arrays.asList(answers.split(";")));
+ }
+
+ public String getFpcName()
+ {
+ return _fpcName;
+ }
+
+ public String getSearchMethod()
+ {
+ return _searchMethod;
+ }
+
+ public List getSearchText()
+ {
+ return _searchText;
+ }
+
+ public List getAnswers()
+ {
+ return _answers;
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
new file mode 100644
index 0000000000..2f8aa1fa6d
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerHolder
+{
+ private final int _classId;
+ private final int _hair;
+ private final int _hairColor;
+ private final int _face;
+ private final int _nameColor;
+ private final int _titleColor;
+ private final int _equipHead;
+ private final int _equipRHand;
+ private final int _equipLHand;
+ private final int _equipGloves;
+ private final int _equipChest;
+ private final int _equipLegs;
+ private final int _equipFeet;
+ private final int _equipCloak;
+ private final int _equipHair;
+ private final int _equipHair2;
+ private final int _agathionId;
+ private final int _weaponEnchantLevel;
+ private final int _armorEnchantLevel;
+ private final boolean _fishing;
+ private final int _baitLocationX;
+ private final int _baitLocationY;
+ private final int _baitLocationZ;
+ private final int _recommends;
+ private final int _nobleLevel;
+ private final boolean _hero;
+ private final int _clanId;
+ private final int _pledgeStatus;
+
+ public FakePlayerHolder(StatsSet set)
+ {
+ _classId = set.getInt("classId", 182);
+
+ _hair = set.getInt("hair", 1);
+ _hairColor = set.getInt("hairColor", 1);
+ _face = set.getInt("face", 1);
+
+ _nameColor = set.getInt("nameColor", 0xFFFFFF);
+ _titleColor = set.getInt("titleColor", 0xECF9A2);
+
+ _equipHead = set.getInt("equipHead", 0);
+ _equipRHand = set.getInt("equipRHand", 0); // or dual hand
+ _equipLHand = set.getInt("equipLHand", 0);
+ _equipGloves = set.getInt("equipGloves", 0);
+ _equipChest = set.getInt("equipChest", 0);
+ _equipLegs = set.getInt("equipLegs", 0);
+ _equipFeet = set.getInt("equipFeet", 0);
+ _equipCloak = set.getInt("equipCloak", 0);
+ _equipHair = set.getInt("equipHair", 0);
+ _equipHair2 = set.getInt("equipHair2", 0);
+ _agathionId = set.getInt("agathionId", 0);
+
+ _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0);
+ _armorEnchantLevel = set.getInt("armorEnchantLevel", 0);
+
+ _fishing = set.getBoolean("fishing", false);
+ _baitLocationX = set.getInt("baitLocationX", 0);
+ _baitLocationY = set.getInt("baitLocationY", 0);
+ _baitLocationZ = set.getInt("baitLocationZ", 0);
+
+ _recommends = set.getInt("recommends", 0);
+ _nobleLevel = set.getInt("nobleLevel", 0);
+ _hero = set.getBoolean("hero", false);
+ _clanId = set.getInt("clanId", 0);
+ _pledgeStatus = set.getInt("pledgeStatus", 0);
+ }
+
+ public int getClassId()
+ {
+ return _classId;
+ }
+
+ public int getHair()
+ {
+ return _hair;
+ }
+
+ public int getHairColor()
+ {
+ return _hairColor;
+ }
+
+ public int getFace()
+ {
+ return _face;
+ }
+
+ public int getNameColor()
+ {
+ return _nameColor;
+ }
+
+ public int getTitleColor()
+ {
+ return _titleColor;
+ }
+
+ public int getEquipHead()
+ {
+ return _equipHead;
+ }
+
+ public int getEquipRHand()
+ {
+ return _equipRHand;
+ }
+
+ public int getEquipLHand()
+ {
+ return _equipLHand;
+ }
+
+ public int getEquipGloves()
+ {
+ return _equipGloves;
+ }
+
+ public int getEquipChest()
+ {
+ return _equipChest;
+ }
+
+ public int getEquipLegs()
+ {
+ return _equipLegs;
+ }
+
+ public int getEquipFeet()
+ {
+ return _equipFeet;
+ }
+
+ public int getEquipCloak()
+ {
+ return _equipCloak;
+ }
+
+ public int getEquipHair()
+ {
+ return _equipHair;
+ }
+
+ public int getEquipHair2()
+ {
+ return _equipHair2;
+ }
+
+ public int getAgathionId()
+ {
+ return _agathionId;
+ }
+
+ public int getWeaponEnchantLevel()
+ {
+ return _weaponEnchantLevel;
+ }
+
+ public int getArmorEnchantLevel()
+ {
+ return _armorEnchantLevel;
+ }
+
+ public boolean isFishing()
+ {
+ return _fishing;
+ }
+
+ public int getBaitLocationX()
+ {
+ return _baitLocationX;
+ }
+
+ public int getBaitLocationY()
+ {
+ return _baitLocationY;
+ }
+
+ public int getBaitLocationZ()
+ {
+ return _baitLocationZ;
+ }
+
+ public int getRecommends()
+ {
+ return _recommends;
+ }
+
+ public int getNobleLevel()
+ {
+ return _nobleLevel;
+ }
+
+ public boolean isHero()
+ {
+ return _hero;
+ }
+
+ public int getClanId()
+ {
+ return _clanId;
+ }
+
+ public int getPledgeStatus()
+ {
+ return _pledgeStatus;
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
index fb63011022..d429fbfee8 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
@@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object
*
* Do Pickup Item : PCInstance and Pet
*
- * @param player Player that pick up the item
+ * @param character Character that pick up the item
*/
- public final void pickupMe(L2Character player)
+ public final void pickupMe(L2Character character)
{
assert getWorldRegion() != null;
final L2WorldRegion oldregion = getWorldRegion();
// Create a server->client GetItem packet to pick up the L2ItemInstance
- player.broadcastPacket(new GetItem(this, player.getObjectId()));
+ character.broadcastPacket(new GetItem(this, character.getObjectId()));
synchronized (this)
{
@@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object
// Remove the L2ItemInstance from the world
L2World.getInstance().removeVisibleObject(this, oldregion);
- if (player.isPlayer())
+ if (character.isPlayer())
{
// Notify to scripts
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem());
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem());
}
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java
index 83f6e88b77..7505001c60 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java
@@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable
public boolean checkCondition(L2Character activeChar, L2Object object)
{
- if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)
+ if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION))
{
return true;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
index b7eda58d00..13932008ff 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -159,7 +160,7 @@ public class SkillCaster implements Runnable
}
// You should not heal/buff monsters without pressing the ctrl button.
- if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed)
+ if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed)
{
caster.sendPacket(SystemMessageId.INVALID_TARGET);
return null;
@@ -609,6 +610,10 @@ public class SkillCaster implements Runnable
// Add hate to the attackable, and put it in the attack list.
((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint());
((L2Character) obj).addAttackerToAttackByList(caster);
+ if (obj.isFakePlayer())
+ {
+ player.updatePvPStatus();
+ }
}
// notify target AI about the attack
@@ -617,10 +622,19 @@ public class SkillCaster implements Runnable
((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster);
}
}
- else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0))))
+ else if (((skill.getEffectPoint() > 0) && obj.isMonster()) //
+ || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) //
+ || (((L2Character) obj).getReputation() < 0) //
+ )))
{
// Supporting players or monsters result in pvpflag.
- player.updatePvPStatus();
+ if (!obj.isFakePlayer() //
+ || (obj.isFakePlayer() //
+ && (!((L2Npc) obj).isScriptValue(0) //
+ || (((L2Npc) obj).getReputation() < 0))))
+ {
+ player.updatePvPStatus();
+ }
}
}
@@ -630,7 +644,7 @@ public class SkillCaster implements Runnable
EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob);
// On Skill See logic
- if (npcMob.isAttackable())
+ if (npcMob.isAttackable() && !npcMob.isFakePlayer())
{
final L2Attackable attackable = (L2Attackable) npcMob;
@@ -652,6 +666,19 @@ public class SkillCaster implements Runnable
}
});
}
+ else if (caster.isFakePlayer()) // fake player attacks player
+ {
+ if (target.isPlayable() || target.isFakePlayer())
+ {
+ final L2Npc npc = ((L2Npc) caster);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ npc.broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+ }
}
catch (Exception e)
{
@@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable
return false;
}
}
-
return true;
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
index fdf0dadf55..06bea1b4cf 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
@@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
@@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
@@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
index 91a9ce830a..ccd2d1d13a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
@@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket
}
case 1:
{
- if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC))
+ if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer()))
{
obj.onAction(activeChar, false);
}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
index 876c53c093..06464d9911 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket
return;
}
- if (Config.FORBIDDEN_NAMES.length > 1)
+ if (Config.FORBIDDEN_NAMES.length > 0)
{
for (String st : Config.FORBIDDEN_NAMES)
{
@@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
+ return;
+ }
+
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
index 06bfa3c200..01c8b0c67f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
@@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class RequestBlock implements IClientIncomingPacket
{
@@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket
case BLOCK:
case UNBLOCK:
{
+ // TODO: Save in database? :P
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (_type == BLOCK)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
// can't use block/unblock for locating invisible characters
if (targetId <= 0)
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
index ceb67b0f5f..cf79bdb24c 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable;
import com.l2jmobius.gameserver.util.Util;
@@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket
{
result = NAME_ALREADY_EXISTS;
}
+ else if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ result = NAME_ALREADY_EXISTS;
+ }
else if (_name.length() > 16)
{
result = INVALID_LENGTH;
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
index b0ace828dc..ee8bcd656b 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
@@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart;
@@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance activeChar = client.getActiveChar();
- final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (activeChar == null)
{
return;
}
+
+ if (FakePlayerData.getInstance().isTalkable(_player))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(_player);
+ if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ if (activeChar.isProcessingRequest())
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(name);
+ activeChar.sendPacket(msg);
+ return;
+ }
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000);
+ activeChar.blockRequest();
+ return;
+ }
+
+ final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (targetChar == null)
{
activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
index f104c94161..c0042d45c5 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
@@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Party;
@@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ if (player.getParty() == null)
+ {
+ player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED);
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY);
+ }
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance requestor = client.getActiveChar();
- final L2PcInstance target = L2World.getInstance().getPlayer(_name);
-
if (requestor == null)
{
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ requestor.sendPacket(sm);
+ if (!requestor.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000);
+ requestor.blockRequest();
+ }
+ else
+ {
+ requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY);
+ }
+ return;
+ }
+
+ final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (target == null)
{
requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
index 292153afd8..37c539556f 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
@@ -17,12 +17,15 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class ...
@@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return;
}
+ if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName())))
+ {
+ if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0)
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN);
+ }
+ else
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(activeChar.getTarget().getName());
+ activeChar.sendPacket(msg);
+ }
+ }
+ return;
+ }
+
final L2PcInstance target = L2World.getInstance().getPlayer(_target);
if (target == null)
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
index 3d5bcaeca5..9cbb114e88 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
@@ -23,6 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.BlockList;
@@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().isTalkable(_receiver))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1);
+ sm.addString(FakePlayerData.getInstance().getProperName(_receiver));
+ activeChar.sendPacket(sm);
+ return;
+ }
+
final int receiverId = CharNameTable.getInstance().getIdByName(_receiver);
if (receiverId <= 0)
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
index 8156905e94..1336c2bdb7 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
@@ -17,6 +17,7 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
@@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket
}
final L2Object object = activeChar.getTarget();
-
if (!(object instanceof L2PcInstance))
{
if (object == null)
{
client.sendPacket(SystemMessageId.SELECT_TARGET);
}
+ else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName()))
+ {
+ if (activeChar.getRecomLeft() <= 0)
+ {
+ client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER);
+ return;
+ }
+
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT);
+ sm.addString(FakePlayerData.getInstance().getProperName(object.getName()));
+ sm.addInt(activeChar.getRecomLeft());
+ client.sendPacket(sm);
+
+ activeChar.setRecomLeft(activeChar.getRecomLeft() - 1);
+ client.sendPacket(new UserInfo(activeChar));
+ client.sendPacket(new ExVoteSystemInfo(activeChar));
+ }
else
{
client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
index d77dc881b3..5d7e35eb43 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
@@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.skills.AbnormalType;
@@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target.getName());
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE));
+ return;
+ }
+ if (!player.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1);
+ sm.addString(name);
+ player.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000);
+ player.blockRequest();
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE);
+ }
+ return;
+ }
+
if (!target.isPlayer())
{
client.sendPacket(SystemMessageId.INVALID_TARGET);
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
index 4fa25283a7..530a6d7a01 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
@@ -17,6 +17,8 @@
package com.l2jmobius.gameserver.network.clientpackets.friend;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST));
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
final L2PcInstance friend = L2World.getInstance().getPlayer(_name);
// Target is not found in the game.
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
index 2170ef2e94..017541bd86 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
@@ -22,6 +22,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
- if (receiver.getFriendList().contains(sender.getObjectId()))
+ if (receiver != null)
{
- _mask |= 0x01;
- }
- if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
- {
- _mask |= 0x02;
- }
- if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
- {
- _mask |= 0x04;
- }
- if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
- {
- _mask |= 0x08;
+ if (receiver.getFriendList().contains(sender.getObjectId()))
+ {
+ _mask |= 0x01;
+ }
+ if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
+ {
+ _mask |= 0x02;
+ }
+ if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
+ {
+ _mask |= 0x04;
+ }
+ if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
+ {
+ _mask |= 0x08;
+ }
}
// Does not shows level
@@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket
}
}
+ /**
+ * Used by fake players.
+ * @param sender
+ * @param receiver
+ * @param name
+ * @param messageType
+ * @param text
+ */
+ public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
+ {
+ _objectId = sender.getObjectId();
+ _charName = name;
+ _charLevel = sender.getLevel();
+ _textType = messageType;
+ _text = text;
+ }
+
/**
* @param objectId
* @param messageType
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
new file mode 100644
index 0000000000..317d7c7312
--- /dev/null
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import java.util.Set;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.enums.Sex;
+import com.l2jmobius.gameserver.model.L2Clan;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerInfo implements IClientOutgoingPacket
+{
+ private final L2Npc _npc;
+ private final int _objId;
+ private final int _x, _y, _z, _heading;
+ private final int _mAtkSpd, _pAtkSpd;
+ private final int _runSpd, _walkSpd;
+ private final int _swimRunSpd;
+ private final int _swimWalkSpd;
+ private final int _flyRunSpd;
+ private final int _flyWalkSpd;
+ private final double _moveMultiplier;
+ private final float _attackSpeedMultiplier;
+ private final FakePlayerHolder _fpcHolder;
+ private final L2Clan _clan;
+
+ public FakePlayerInfo(L2Npc npc)
+ {
+ _npc = npc;
+ _objId = npc.getObjectId();
+ _x = npc.getX();
+ _y = npc.getY();
+ _z = npc.getZ();
+ _heading = npc.getHeading();
+ _mAtkSpd = npc.getMAtkSpd();
+ _pAtkSpd = npc.getPAtkSpd();
+ _attackSpeedMultiplier = npc.getAttackSpeedMultiplier();
+ _moveMultiplier = npc.getMovementSpeedMultiplier();
+ _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier);
+ _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier);
+ _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier);
+ _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier);
+ _flyRunSpd = npc.isFlying() ? _runSpd : 0;
+ _flyWalkSpd = npc.isFlying() ? _walkSpd : 0;
+ _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId());
+ _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId());
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.CHAR_INFO.writeId(packet);
+ packet.writeC(0x00); // Grand Crusade
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(0x00); // vehicleId
+ packet.writeD(_objId);
+ packet.writeS(_npc.getName());
+
+ packet.writeH(_npc.getRace().ordinal());
+ packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00);
+ packet.writeD(_fpcHolder.getClassId());
+
+ packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER
+ packet.writeD(_fpcHolder.getEquipHead());
+ packet.writeD(_fpcHolder.getEquipRHand());
+ packet.writeD(_fpcHolder.getEquipLHand());
+ packet.writeD(_fpcHolder.getEquipGloves());
+ packet.writeD(_fpcHolder.getEquipChest());
+ packet.writeD(_fpcHolder.getEquipLegs());
+ packet.writeD(_fpcHolder.getEquipFeet());
+ packet.writeD(_fpcHolder.getEquipCloak());
+ packet.writeD(_fpcHolder.getEquipRHand()); // dual hand
+ packet.writeD(_fpcHolder.getEquipHair());
+ packet.writeD(_fpcHolder.getEquipHair2());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderAugument())
+ {
+ packet.writeQ(0x00);
+ }
+
+ packet.writeC(_fpcHolder.getArmorEnchantLevel());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderVisualId())
+ {
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(_npc.getScriptValue()); // getPvpFlag()
+ packet.writeD(_npc.getReputation());
+
+ packet.writeD(_mAtkSpd);
+ packet.writeD(_pAtkSpd);
+
+ packet.writeH(_runSpd);
+ packet.writeH(_walkSpd);
+ packet.writeH(_swimRunSpd);
+ packet.writeH(_swimWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeF(_moveMultiplier);
+ packet.writeF(_attackSpeedMultiplier);
+
+ packet.writeF(_npc.getCollisionRadius());
+ packet.writeF(_npc.getCollisionHeight());
+
+ packet.writeD(_fpcHolder.getHair());
+ packet.writeD(_fpcHolder.getHairColor());
+ packet.writeD(_fpcHolder.getFace());
+
+ packet.writeS(_npc.getTemplate().getTitle());
+
+ if (_clan != null)
+ {
+ packet.writeD(_clan.getId());
+ packet.writeD(_clan.getCrestId());
+ packet.writeD(_clan.getAllyId());
+ packet.writeD(_clan.getAllyCrestId());
+ }
+ else
+ {
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked)
+ packet.writeC(_npc.isRunning() ? 0x01 : 0x00);
+ packet.writeC(_npc.isInCombat() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isInvisible() ? 0x01 : 0x00);
+
+ packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount
+ packet.writeC(0x00); // getPrivateStoreType().getId()
+
+ packet.writeH(0x00); // getCubics().size()
+ // getCubics().keySet().forEach(packet::writeH);
+
+ packet.writeC(0x00);
+
+ packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0);
+ packet.writeH(_fpcHolder.getRecommends());
+ packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000
+
+ packet.writeD(_fpcHolder.getClassId());
+ packet.writeD(0x00);
+ packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel
+
+ packet.writeC(_npc.getTeam().getId());
+
+ packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00);
+ packet.writeC(_fpcHolder.getNobleLevel());
+ packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00);
+
+ packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00);
+
+ packet.writeD(_fpcHolder.getBaitLocationX());
+ packet.writeD(_fpcHolder.getBaitLocationY());
+ packet.writeD(_fpcHolder.getBaitLocationZ());
+
+ packet.writeD(_fpcHolder.getNameColor());
+
+ packet.writeD(_heading);
+
+ packet.writeC(_fpcHolder.getPledgeStatus());
+ packet.writeH(0x00); // getPledgeType()
+
+ packet.writeD(_fpcHolder.getTitleColor());
+
+ packet.writeC(0x00); // isCursedWeaponEquipped
+
+ packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0
+ packet.writeD(0x00); // getTransformationDisplayId()
+ packet.writeD(_fpcHolder.getAgathionId());
+
+ packet.writeC(0x00);
+
+ packet.writeD(0x00); // getCurrentCp()
+ packet.writeD(_npc.getMaxHp());
+ packet.writeD((int) Math.round(_npc.getCurrentHp()));
+ packet.writeD(_npc.getMaxMp());
+ packet.writeD((int) Math.round(_npc.getCurrentMp()));
+
+ packet.writeC(0x00);
+ final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects();
+ packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0));
+ for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects)
+ {
+ packet.writeH(abnormalVisualEffect.getClientId());
+ }
+ if (_npc.isInvisible())
+ {
+ packet.writeH(AbnormalVisualEffect.STEALTH.getClientId());
+ }
+ packet.writeC(0x00); // cocPlayer.getPosition()
+ packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00);
+ packet.writeC(0x00); // Used Ability Points
+ return true;
+ }
+}
diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
index 4fb1a757e6..c294edab2a 100644
--- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
+++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
@@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket
addComponentType(NpcInfoType.TITLE_NPCSTRINGID);
}
+ if (_npc.getReputation() != 0)
+ {
+ addComponentType(NpcInfoType.REPUTATION);
+ }
+
if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible())
{
addComponentType(NpcInfoType.ABNORMALS);
@@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket
}
if (containsMask(NpcInfoType.REPUTATION))
{
- packet.writeD(0x00); // Name color
+ packet.writeD(_npc.getReputation()); // Reputation
}
if (containsMask(NpcInfoType.CLAN))
{
diff --git a/L2J_Mobius_4.0_GrandCrusade/readme.txt b/L2J_Mobius_4.0_GrandCrusade/readme.txt
index 5a1848fb6c..a90279520e 100644
--- a/L2J_Mobius_4.0_GrandCrusade/readme.txt
+++ b/L2J_Mobius_4.0_GrandCrusade/readme.txt
@@ -105,6 +105,7 @@ Customs:
-Classmaster
-Community board
-Faction system
+-Fake players
-Find PvP
-NPC stat multipliers
-Realtime offline trade
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml
index f538dfbbf2..d74ab987f6 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml
@@ -392,6 +392,9 @@
+
+
+
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini
new file mode 100644
index 0000000000..f745b0d31e
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini
@@ -0,0 +1,33 @@
+# ---------------------------------------------------------------------------
+# Fake players
+# ---------------------------------------------------------------------------
+
+# Enable fake players.
+EnableFakePlayers = False
+
+# Enable chatting with fake players.
+FakePlayerChat = True
+
+# Enable shots usage for fake players.
+FakePlayerUseShots = True
+
+# Reward PvP kills by killing fake players.
+FakePlayerKillsRewardPvP = True
+
+# Fake player kills apply karma rules.
+FakePlayerUnflaggedKillsKarma = True
+
+# Aggressive AI fake players attack nearby monsters.
+FakePlayerAggroMonsters = True
+
+# Aggressive AI fake players attack nearby players.
+FakePlayerAggroPlayers = False
+
+# Aggressive AI fake players attack nearby fake players.
+FakePlayerAggroFPC = False
+
+# Fake players can drop items when killing monsters.
+FakePlayerCanDropItems = True
+
+# Fake players can pickup dropped items.
+FakePlayerCanPickup = True
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml
new file mode 100644
index 0000000000..f5da5bfc8e
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml
new file mode 100644
index 0000000000..446768c5a3
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml
index e452b77d1c..37f8bfae98 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml
@@ -9,4 +9,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
new file mode 100644
index 0000000000..e1dde7324e
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package custom.FakePlayers;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+import ai.AbstractNpcAI;
+
+/**
+ * TODO: Move it to L2Character.
+ * @author Mobius
+ */
+public class PvpFlaggingStopTask extends AbstractNpcAI
+{
+ private PvpFlaggingStopTask()
+ {
+ }
+
+ @Override
+ public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
+ {
+ if ((npc == null) || npc.isDead())
+ {
+ return null;
+ }
+
+ if (event.startsWith("FLAG_CHECK"))
+ {
+ final L2Object target = npc.getTarget();
+ if ((target != null) && (target.isPlayable() || target.isFakePlayer()))
+ {
+ npc.setScriptValue(1); // in combat
+ cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null);
+ cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null);
+ startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null);
+ startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null);
+ }
+ }
+ else if (event.startsWith("FINISH_FLAG"))
+ {
+ if (npc.isScriptValue(1))
+ {
+ npc.setScriptValue(2); // blink status
+ npc.broadcastInfo(); // update flag status
+ startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null);
+ }
+ }
+ else if (event.startsWith("REMOVE_FLAG"))
+ {
+ if (npc.isScriptValue(2))
+ {
+ npc.setScriptValue(0); // not in combat
+ npc.broadcastInfo(); // update flag status
+ }
+ }
+ return super.onAdvEvent(event, npc, player);
+ }
+
+ public static void main(String[] args)
+ {
+ new PvpFlaggingStopTask();
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java
index 67e0f164e4..b2e61af8eb 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java
@@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
+import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@@ -410,6 +411,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
+ AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
index 6b02816d9e..d6d6a99080 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java
@@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (Config.ALT_GAME_VIEWNPC)
{
- if (!target.isNpc())
+ if (!target.isNpc() || target.isFakePlayer())
{
return false;
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
new file mode 100644
index 0000000000..99926f0df7
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package handlers.admincommandhandlers;
+
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
+import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+
+/**
+ * @author Mobius
+ */
+public class AdminFakePlayers implements IAdminCommandHandler
+{
+ private static final String[] ADMIN_COMMANDS =
+ {
+ "admin_fakechat"
+ };
+
+ @Override
+ public boolean useAdminCommand(String command, L2PcInstance activeChar)
+ {
+ if (command.startsWith("admin_fakechat"))
+ {
+ final String[] words = command.substring(15).split(" ");
+ if (words.length < 3)
+ {
+ activeChar.sendMessage("Usage: //fakechat playername fpcname message");
+ return false;
+ }
+ final L2PcInstance player = L2World.getInstance().getPlayer(words[0]);
+ if (player == null)
+ {
+ activeChar.sendMessage("Player not found.");
+ return false;
+ }
+ final String fpcName = FakePlayerData.getInstance().getProperName(words[1]);
+ if (fpcName == null)
+ {
+ activeChar.sendMessage("Fake player not found.");
+ return false;
+ }
+ String message = "";
+ for (int i = 0; i < words.length; i++)
+ {
+ if (i < 2)
+ {
+ continue;
+ }
+ message += (words[i] + " ");
+ }
+ FakePlayerChatManager.getInstance().sendChat(player, fpcName, message);
+ }
+ return true;
+ }
+
+ @Override
+ public String[] getAdminCommandList()
+ {
+ return ADMIN_COMMANDS;
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
index 5da8e115b2..4799a7aa53 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java
@@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
+import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
+ case "fakeplayers":
+ {
+ FakePlayerData.getInstance().load();
+ for (L2Object obj : L2World.getInstance().getVisibleObjects())
+ {
+ if (obj.isFakePlayer())
+ {
+ obj.broadcastInfo();
+ }
+ }
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
+ break;
+ }
+ case "fakeplayerchat":
+ {
+ FakePlayerChatManager.getInstance().load();
+ AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
+ break;
+ }
default:
{
activeChar.sendMessage(RELOAD_USAGE);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
index 99f2e9e9d7..7db79fe31d 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java
@@ -17,8 +17,10 @@
package handlers.chathandlers;
import com.l2jmobius.Config;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IChatHandler;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PcCondOverride;
@@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
+ if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
+ {
+ if (FakePlayerData.getInstance().isTalkable(target))
+ {
+ if (Config.FAKE_PLAYER_CHAT)
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target);
+ activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
+ FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
+ }
+ }
+ else
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
+ }
+ return;
+ }
+
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
index 41b1f99bcf..b38f5ca16d 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java
@@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
-
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java
index 1e34a0d148..087112cc73 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java
@@ -16,9 +16,11 @@
*/
package handlers.playeractions;
+import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
+ player.onTransactionResponse();
+ }
+ }
+
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
- if ((target == null) || !target.isPlayer())
+ if ((target == null))
+ {
+ player.sendPacket(SystemMessageId.INVALID_TARGET);
+ return;
+ }
+
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
+ sm.addString(target.getName());
+ player.sendPacket(sm);
+ if (!player.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
+ player.blockRequest();
+ }
+ return;
+ }
+
+ if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml
new file mode 100644
index 0000000000..ea77878c2c
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml
new file mode 100644
index 0000000000..bea608ac16
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ DARK_ELF
+ FEMALE
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd
new file mode 100644
index 0000000000..2b2c94e75b
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd
new file mode 100644
index 0000000000..0628acefc3
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd
index 6f00944cff..ae80c3ff63 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd
+++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd
@@ -201,6 +201,8 @@
+
+
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java
index a1d5dff508..d110fd2fa2 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java
@@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
+ public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@@ -1087,6 +1088,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
+ public static boolean FAKE_PLAYERS_ENABLED;
+ public static boolean FAKE_PLAYER_CHAT;
+ public static boolean FAKE_PLAYER_USE_SHOTS;
+ public static boolean FAKE_PLAYER_KILL_PVP;
+ public static boolean FAKE_PLAYER_KILL_KARMA;
+ public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
+ public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
+ public static boolean FAKE_PLAYER_AGGRO_FPC;
+ public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
+ public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@@ -2451,6 +2462,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
+ // Load FakePlayers config file (if exists)
+ final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
+ FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
+ FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
+ FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
+ FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
+ FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
+ FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
+ FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
+ FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
+ FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
+ FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
+
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java
index 6153a97816..d439bda0f7 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java
@@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
+import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
import com.l2jmobius.gameserver.instancemanager.GraciaSeedsManager;
import com.l2jmobius.gameserver.instancemanager.GrandBossManager;
@@ -286,6 +288,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
+ FakePlayerData.getInstance();
+ FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
WalkingManager.getInstance();
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
index 6253fa9329..1da1b21546 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java
@@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
- if (npc.isAggressive() || (npc instanceof L2GuardInstance))
+ if (npc.isFakePlayer() && npc.isAggressive())
+ {
+ final List droppedItems = npc.getFakePlayerDrops();
+ if (droppedItems.isEmpty())
+ {
+ L2Character nearestTarget = null;
+ double closestDistance = Double.MAX_VALUE;
+ for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange()))
+ {
+ if ((t == _actor) || (t == null) || t.isDead())
+ {
+ continue;
+ }
+ if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) //
+ || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer()))
+ {
+ final int hating = npc.getHating(t);
+ final double distance = npc.calculateDistance(t, false, false);
+ if ((hating == 0) && (closestDistance > distance))
+ {
+ nearestTarget = t;
+ closestDistance = distance;
+ }
+ }
+ }
+ if (nearestTarget != null)
+ {
+ npc.addDamageHate(nearestTarget, 0, 1);
+ }
+ }
+ else if (!npc.isInCombat()) // must pickup items
+ {
+ final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped
+ final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex);
+ if ((droppedItem != null) && droppedItem.isSpawned())
+ {
+ if (npc.calculateDistance(droppedItem, false, false) > 50)
+ {
+ moveTo(droppedItem);
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ droppedItem.pickupMe(npc);
+ if (Config.SAVE_DROPPED_ITEM)
+ {
+ ItemsOnGroundManager.getInstance().removeObject(droppedItem);
+ }
+ if (droppedItem.getItem().hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills())
+ {
+ SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
+ }
+ npc.broadcastInfo(); // ? check if this is necessary
+ }
+ }
+ }
+ else
+ {
+ npc.getFakePlayerDrops().remove(itemIndex);
+ }
+ npc.setRunning();
+ }
+ }
+ else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
- if (t.isPlayable())
+ if (t.isFakePlayer())
+ {
+ if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
+ {
+ final int hating = npc.getHating(t);
+ if (hating == 0)
+ {
+ npc.addDamageHate(t, 0, 1);
+ }
+ }
+ }
+ else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
new file mode 100644
index 0000000000..0a6ca5267a
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java
@@ -0,0 +1,125 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.data.xml.impl;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerData implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName());
+
+ private final Map _fakePlayerInfos = new HashMap<>();
+ private final Map _fakePlayerNames = new HashMap<>();
+ private final Map _fakePlayerIds = new HashMap<>();
+ private final List _talkableFakePlayerNames = new ArrayList<>();
+
+ protected FakePlayerData()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED)
+ {
+ _fakePlayerInfos.clear();
+ _fakePlayerNames.clear();
+ _fakePlayerIds.clear();
+ _talkableFakePlayerNames.clear();
+ parseDatapackFile("data/FakePlayerVisualData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode));
+ final int npcId = set.getInt("npcId");
+ final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId);
+ final String name = template.getName();
+ if (CharNameTable.getInstance().getIdByName(name) > 0)
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists.");
+ }
+ else
+ {
+ _fakePlayerIds.put(name, npcId); // name - npcId
+ _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name
+ _fakePlayerInfos.put(npcId, new FakePlayerHolder(set));
+ if (template.isFakePlayerTalkable())
+ {
+ _talkableFakePlayerNames.add(name.toLowerCase());
+ }
+ }
+ }));
+ }
+
+ public int getNpcIdByName(String name)
+ {
+ return _fakePlayerIds.get(name);
+ }
+
+ public String getProperName(String name)
+ {
+ return _fakePlayerNames.get(name.toLowerCase());
+ }
+
+ public Boolean isTalkable(String name)
+ {
+ return _talkableFakePlayerNames.contains(name.toLowerCase());
+ }
+
+ public FakePlayerHolder getInfo(int npcId)
+ {
+ return _fakePlayerInfos.get(npcId);
+ }
+
+ public static FakePlayerData getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerData _instance = new FakePlayerData();
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
index 7e6728d387..2caef85892 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java
@@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader
set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty"));
+ set.set("fakePlayer", parseBoolean(attrs, "fakePlayer"));
+ set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable"));
break;
}
case "skill_list":
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
index 2ff4c9322d..15bd310bd6 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java
@@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
+ if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
+ {
+ return;
+ }
+
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
index a145b65dba..d525c02a6a 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java
@@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
+import com.l2jmobius.gameserver.model.actor.L2Character;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
-
if (target == null)
{
return false;
}
- final L2PcInstance bot = target.getActingPlayer();
+ final L2Character bot = ((L2Character) target);
- if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
+ if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
- if (bot.isInOlympiadMode())
+ if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
- if (bot.getExp() == bot.getStat().getStartingExp())
+ if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
- sm.addCharName(bot);
+ sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
- handleReport(bot, rcd);
+ if (bot.isPlayer())
+ {
+ handleReport(bot.getActingPlayer(), rcd);
+ }
return true;
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java
index 7454554076..ace19486b5 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
@@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
- * @param actor : L2PcInstance Player requesting the item creation
+ * @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
- public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
+ public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
index b621b4c4cb..bb0e928daf 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java
@@ -217,6 +217,7 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
+ cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
// If the clan does not exist...
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
new file mode 100644
index 0000000000..16a0da92bc
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java
@@ -0,0 +1,196 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.instancemanager;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+import org.w3c.dom.Document;
+
+import com.l2jmobius.Config;
+import com.l2jmobius.commons.util.IGameXmlReader;
+import com.l2jmobius.commons.util.Rnd;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.datatables.SpawnTable;
+import com.l2jmobius.gameserver.enums.ChatType;
+import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.model.L2Spawn;
+import com.l2jmobius.gameserver.model.StatsSet;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
+import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
+
+/**
+ * @author Mobius
+ */
+public final class FakePlayerChatManager implements IGameXmlReader
+{
+ private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
+ final List MESSAGES = new ArrayList<>();
+ private static final int MIN_DELAY = 5000;
+ private static final int MAX_DELAY = 15000;
+
+ protected FakePlayerChatManager()
+ {
+ load();
+ }
+
+ @Override
+ public void load()
+ {
+ if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT)
+ {
+ MESSAGES.clear();
+ parseDatapackFile("data/FakePlayerChatData.xml");
+ LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates.");
+ }
+ else
+ {
+ LOGGER.info(getClass().getSimpleName() + ": Disabled.");
+ }
+ }
+
+ @Override
+ public void parseDocument(Document doc, File f)
+ {
+ forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode ->
+ {
+ final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode));
+ MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers")));
+ }));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
+ }
+
+ public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
+ {
+ ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
+ }
+
+ private void manageResponce(L2PcInstance player, String fpcName, String message)
+ {
+ if (player == null)
+ {
+ return;
+ }
+
+ final String text = message.toLowerCase();
+
+ // tricky question
+ if (text.contains("can you see me"))
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ if (npc.calculateDistance(player, false, false) < 3000)
+ {
+ if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
+ }
+ }
+ else
+ {
+ sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
+ }
+ return;
+ }
+ }
+ }
+
+ for (FakePlayerChatHolder chatHolder : MESSAGES)
+ {
+ if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
+ {
+ continue;
+ }
+
+ switch (chatHolder.getSearchMethod())
+ {
+ case "EQUALS":
+ {
+ if (text.equals(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "STARTS_WITH":
+ {
+ if (text.startsWith(chatHolder.getSearchText().get(0)))
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ case "CONTAINS":
+ {
+ boolean allFound = true;
+ for (String word : chatHolder.getSearchText())
+ {
+ if (!text.contains(word))
+ {
+ allFound = false;
+ }
+ }
+ if (allFound)
+ {
+ sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ public void sendChat(L2PcInstance player, String fpcName, String message)
+ {
+ final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
+ if (spawn != null)
+ {
+ final L2Npc npc = spawn.getLastSpawn();
+ if (npc != null)
+ {
+ player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
+ }
+ }
+ }
+
+ public static FakePlayerChatManager getInstance()
+ {
+ return SingletonHolder._instance;
+ }
+
+ private static class SingletonHolder
+ {
+ protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java
index 1a62714f0e..50a3cc2145 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
@@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class DropProtection implements Runnable
{
private volatile boolean _isProtected = false;
- private L2PcInstance _owner = null;
+ private L2Character _owner = null;
private ScheduledFuture> _task = null;
private static final long PROTECTED_MILLIS_TIME = 15000;
@@ -46,7 +47,7 @@ public class DropProtection implements Runnable
return _isProtected;
}
- public L2PcInstance getOwner()
+ public L2Character getOwner()
{
return _owner;
}
@@ -91,12 +92,12 @@ public class DropProtection implements Runnable
_task = null;
}
- public synchronized void protect(L2PcInstance player)
+ public synchronized void protect(L2Character character)
{
unprotect();
_isProtected = true;
- _owner = player;
+ _owner = character;
if (_owner == null)
{
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java
index 459660c7ca..92837e4b25 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java
@@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
return false;
}
+ /**
+ * Verify if object is a fake player.
+ * @return {@code true} if object is a fake player, {@code false} otherwise
+ */
+ public boolean isFakePlayer()
+ {
+ return false;
+ }
+
/**
* Verify if object is instance of L2ServitorInstance.
* @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
index 390cee7b5a..c3f0de92ff 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java
@@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
+import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
- return _mustGiveExpSp;
+ return _mustGiveExpSp && !isFakePlayer();
}
/**
@@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
+ // unless its a fake player and they can drop items
+ if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
+ {
+ final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);
+ if (deathItems != null)
+ {
+ for (ItemHolder drop : deathItems)
+ {
+ final L2Item item = ItemTable.getInstance().getTemplate(drop.getId());
+ // Check if the autoLoot mode is active
+ if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
+ {
+ // do nothing
+ }
+ else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
+ {
+ for (SkillHolder skillHolder : item.getAllSkills())
+ {
+ SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false);
+ }
+ mainDamageDealer.broadcastInfo(); // ? check if this is necessary
+ }
+ else
+ {
+ final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
+ if (Config.FAKE_PLAYER_CAN_PICKUP)
+ {
+ mainDamageDealer.getFakePlayerDrops().add(droppedItem);
+ }
+ }
+ }
+ }
+ }
return;
}
@@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
- if (lastAttacker == null)
+ if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc
_harvestItem.set(null);
_sweepItems.set(null);
+ // fake players
+ if (isFakePlayer())
+ {
+ getFakePlayerDrops().clear(); // Clear existing fake player drops
+ setReputation(0); // reset reputation
+ setScriptValue(0); // remove pvp flag
+ setRunning(); // don't walk
+ }
+
// Clear mod Seeded stat
_seeded = false;
_seed = null;
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java
index 226b8e981a..6dd50e079f 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java
@@ -30,6 +30,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList;
@@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
+ private int _reputation = 0;
+
/** Map containing all skills of this character. */
private final Map _skills = new ConcurrentSkipListMap<>();
/** Map containing the skill reuse time stamps. */
@@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
/** A set containing the shot types currently charged. */
private Set _chargedShots = EnumSet.noneOf(ShotType.class);
+ /** A list containing the dropped items of this fake player. */
+ private final List _fakePlayerDrops = new CopyOnWriteArrayList<>();
+
/**
* Creates a creature.
* @param template the creature template
@@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
broadcastPacket(attack);
}
+ if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
+ {
+ final L2Npc npc = ((L2Npc) this);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+
// Notify AI with EVT_READY_TO_ACT
ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
}
@@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
final Instance instanceWorld = getInstanceWorld();
- if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
+ if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
{
return false;
}
@@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist());
}
+ public int getReputation()
+ {
+ return _reputation;
+ }
+
+ public void setReputation(int reputation)
+ {
+ _reputation = reputation;
+ }
+
/**
* Gets the distance to target.
* @param target the target
@@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
+
+ public List getFakePlayerDrops()
+ {
+ return _fakePlayerDrops;
+ }
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
index dd3a438337..0a27adf635 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java
@@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.enums.Team;
+import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.handler.BypassHandler;
import com.l2jmobius.gameserver.handler.IBypassHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
+import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
@@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
+import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@@ -125,6 +130,7 @@ public class L2Npc extends L2Character
private boolean _isRandomAnimationEnabled = true;
private boolean _isRandomWalkingEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
+ private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@@ -364,7 +370,11 @@ public class L2Npc extends L2Character
return;
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@@ -901,6 +911,78 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
+ if (isFakePlayer() && (killer != null) && killer.isPlayable())
+ {
+ final L2PcInstance player = killer.getActingPlayer();
+ if (isScriptValue(0) && (getReputation() >= 0))
+ {
+ if (Config.FAKE_PLAYER_KILL_KARMA)
+ {
+ player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
+ player.setPkKills(player.getPkKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ player.checkItemRestriction();
+ // pk item rewards
+ if (Config.REWARD_PK_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
+ // announce pk
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+ else if (Config.FAKE_PLAYER_KILL_PVP)
+ {
+ player.setPvpKills(player.getPvpKills() + 1);
+ final UserInfo ui = new UserInfo(player, false);
+ ui.addComponentType(UserInfoType.SOCIAL);
+ player.sendPacket(ui);
+ // pvp item rewards
+ if (Config.REWARD_PVP_ITEM)
+ {
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ }
+ // announce pvp
+ if (Config.ANNOUNCE_PK_PVP && !player.isGM())
+ {
+ final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
+ if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
+ sm.addString(msg);
+ Broadcast.toAllOnlinePlayers(sm);
+ }
+ else
+ {
+ Broadcast.toAllOnlinePlayers(msg, false);
+ }
+ }
+ }
+ }
+
DecayTaskManager.getInstance().add(this);
final L2Spawn spawn = getSpawn();
@@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
- if (getRunSpeed() == 0)
+ if (isFakePlayer())
+ {
+ activeChar.sendPacket(new FakePlayerInfo(this));
+ }
+ else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character
@Override
public void rechargeShots(boolean physical, boolean magic, boolean fish)
{
- if (physical && (_soulshotamount > 0))
+ if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS)
{
- if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ if (physical)
{
- return;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic)
+ {
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _soulshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
- chargeShot(ShotType.SOULSHOTS);
}
-
- if (magic && (_spiritshotamount > 0))
+ else
{
- if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ if (physical && (_soulshotamount > 0))
{
- return;
+ if (Rnd.get(100) > getTemplate().getSoulShotChance())
+ {
+ return;
+ }
+ _soulshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
+ chargeShot(ShotType.SOULSHOTS);
+ }
+ if (magic && (_spiritshotamount > 0))
+ {
+ if (Rnd.get(100) > getTemplate().getSpiritShotChance())
+ {
+ return;
+ }
+ _spiritshotamount--;
+ Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
+ chargeShot(ShotType.SPIRITSHOTS);
}
- _spiritshotamount--;
- Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
- chargeShot(ShotType.SPIRITSHOTS);
}
}
@@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
- * @param player the last attacker or main damage dealer
+ * @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
+ public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character
return null;
}
- item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
+ item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
- if (player != null)
+ if (character != null)
{
- item.getDropProtection().protect(player);
+ item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character
}
/**
- * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
- * @param player the last attacker or main damage dealer
+ * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
+ * @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
- public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
+ public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
- return dropItem(player, item.getId(), item.getCount());
+ return dropItem(character, item.getId(), item.getCount());
}
@Override
@@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character
return Config.SHOP_MIN_RANGE_FROM_NPC;
}
+ @Override
+ public boolean isFakePlayer()
+ {
+ return _isFakePlayer;
+ }
+
/**
* @return The player's object Id this NPC is cloning.
*/
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
index 34550c3dd8..10ad419ea4 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java
@@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
- public abstract int getReputation();
-
public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove);
public abstract void storeMe();
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
index dab0c5323a..80c2783883 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java
@@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
@@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
+ if (target.isFakePlayer())
+ {
+ getOwner().updatePvPStatus();
+ }
}
}
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
index a5fd31dedd..44ee919058 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java
@@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
- sm.addCharName(attacker);
+ sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
index aa4f132fce..6a94be63b5 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java
@@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
- if (attacker.isMonster())
+ if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
+ if (isFakePlayer() && isInCombat())
+ {
+ interact = false;
+ // TODO: Fix normal targeting
+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
+ }
+
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
index e9a9976e87..fe55288a3a 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java
@@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
+ if (isFakePlayer())
+ {
+ return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
+ }
+
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
@@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable
if (attacker.isMonster())
{
- return false;
+ return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
index 96dd03ebdc..abff3608fa 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java
@@ -442,9 +442,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
- /** The Reputation of the L2PcInstance */
- private int _reputation;
-
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@@ -1968,24 +1965,16 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
- /**
- * @return the reputation of the PlayerInstance.
- */
- @Override
- public int getReputation()
- {
- return _reputation;
- }
-
public void setInitialReputation(int reputation)
{
- _reputation = reputation;
+ super.setReputation(reputation);
}
/**
* Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param reputation
*/
+ @Override
public void setReputation(int reputation)
{
// Notify to scripts.
@@ -2011,7 +2000,9 @@ public final class L2PcInstance extends L2Playable
}
});
}
- _reputation = reputation;
+
+ super.setReputation(reputation);
+
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation()));
broadcastReputation();
}
@@ -4625,6 +4616,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
+ if (target.isFakePlayer())
+ {
+ updatePvPStatus();
+ }
}
@Override
@@ -4952,22 +4947,42 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
- if (pk != null)
+ final boolean fpcKill = killer.isFakePlayer();
+ if ((pk != null) || fpcKill)
{
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
-
- if (L2Event.isParticipant(pk))
+ if (pk != null)
{
- pk.getEventStatus().addKill(this);
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
+
+ if (L2Event.isParticipant(pk))
+ {
+ pk.getEventStatus().addKill(this);
+ }
+
+ // pvp/pk item rewards
+ if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
+ !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ {
+ // pvp
+ if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
+ {
+ pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
+ }
+ // pk
+ if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
+ {
+ pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
+ }
+ }
}
// announce pvp/pk
- if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
+ if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
- msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -4981,7 +4996,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
- msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
+ msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@@ -4995,20 +5010,9 @@ public final class L2PcInstance extends L2Playable
}
}
- // pvp/pk item rewards
- if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
- !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
+ if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0))
{
- // pvp
- if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
- {
- pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
- }
- // pk
- if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
- {
- pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
- }
+ killer.setReputation(killer.getReputation() - 150);
}
}
@@ -5601,6 +5605,14 @@ public final class L2PcInstance extends L2Playable
return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks());
}
+ /**
+ * Used by fake players to emulate proper behavior.
+ */
+ public void blockRequest()
+ {
+ _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
+ }
+
/**
* Select the Warehouse to be used in next activity.
* @param partner
@@ -11502,7 +11514,7 @@ public final class L2PcInstance extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addPcName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), -damage);
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
index fb6b184e67..8383d1efc9 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java
@@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
+ @Override
public int getReputation()
{
return _owner != null ? _owner.getReputation() : 0;
@@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addCharName(this);
- sm.addCharName(target);
+ sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
_owner.sendPacket(sm);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
index a97eab382d..26a51be541 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java
@@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (attacker.isPlayable() && (caster.getCurrentCp() > 0))
+ if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus
}
}
- if (!ignoreCP && attacker.isPlayable())
+ if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{
@@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus
// Send a System Message to the L2PcInstance
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
smsg.addString(getActiveChar().getName());
- smsg.addCharName(attacker);
+ smsg.addString(attacker.getName());
smsg.addInt(fullValue);
getActiveChar().sendPacket(smsg);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
index 9abefd2e88..0d276af74d 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java
@@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _randomWalk;
private boolean _randomAnimation;
private boolean _flying;
+ private boolean _fakePlayer;
+ private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard"));
_randomAnimation = set.getBoolean("randomAnimation", true);
_flying = set.getBoolean("flying", false);
+ _fakePlayer = set.getBoolean("fakePlayer", false);
+ _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
+ public boolean isFakePlayer()
+ {
+ return _fakePlayer;
+ }
+
+ public boolean isFakePlayerTalkable()
+ {
+ return _fakePlayerTalkable;
+ }
+
public boolean canMove()
{
return _canMove;
@@ -758,7 +772,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -804,7 +818,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null)
{
@@ -837,7 +851,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// chance
double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
// premium chance
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE;
}
@@ -850,7 +864,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// amount is calculated after chance returned success
double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER;
// premium amount
- if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
+ if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT;
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
index df9698d3c3..6cbe42b242 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java
@@ -16,7 +16,7 @@
*/
package com.l2jmobius.gameserver.model.events.impl.item;
-import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.events.EventType;
import com.l2jmobius.gameserver.model.events.impl.IBaseEvent;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
@@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent
{
private final String _process;
private final L2ItemInstance _item;
- private final L2PcInstance _activeChar;
+ private final L2Character _activeChar;
private final Object _reference;
- public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference)
+ public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference)
{
_process = process;
_item = item;
@@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent
return _item;
}
- public L2PcInstance getActiveChar()
+ public L2Character getActiveChar()
{
return _activeChar;
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
new file mode 100644
index 0000000000..3008d340b3
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java
@@ -0,0 +1,60 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerChatHolder
+{
+ private final String _fpcName;
+ private final String _searchMethod;
+ private final List _searchText;
+ private final List _answers;
+
+ public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers)
+ {
+ _fpcName = fpcName;
+ _searchMethod = searchMethod;
+ _searchText = new ArrayList<>(Arrays.asList(searchText.split(";")));
+ _answers = new ArrayList<>(Arrays.asList(answers.split(";")));
+ }
+
+ public String getFpcName()
+ {
+ return _fpcName;
+ }
+
+ public String getSearchMethod()
+ {
+ return _searchMethod;
+ }
+
+ public List getSearchText()
+ {
+ return _searchText;
+ }
+
+ public List getAnswers()
+ {
+ return _answers;
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
new file mode 100644
index 0000000000..2f8aa1fa6d
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.model.holders;
+
+import com.l2jmobius.gameserver.model.StatsSet;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerHolder
+{
+ private final int _classId;
+ private final int _hair;
+ private final int _hairColor;
+ private final int _face;
+ private final int _nameColor;
+ private final int _titleColor;
+ private final int _equipHead;
+ private final int _equipRHand;
+ private final int _equipLHand;
+ private final int _equipGloves;
+ private final int _equipChest;
+ private final int _equipLegs;
+ private final int _equipFeet;
+ private final int _equipCloak;
+ private final int _equipHair;
+ private final int _equipHair2;
+ private final int _agathionId;
+ private final int _weaponEnchantLevel;
+ private final int _armorEnchantLevel;
+ private final boolean _fishing;
+ private final int _baitLocationX;
+ private final int _baitLocationY;
+ private final int _baitLocationZ;
+ private final int _recommends;
+ private final int _nobleLevel;
+ private final boolean _hero;
+ private final int _clanId;
+ private final int _pledgeStatus;
+
+ public FakePlayerHolder(StatsSet set)
+ {
+ _classId = set.getInt("classId", 182);
+
+ _hair = set.getInt("hair", 1);
+ _hairColor = set.getInt("hairColor", 1);
+ _face = set.getInt("face", 1);
+
+ _nameColor = set.getInt("nameColor", 0xFFFFFF);
+ _titleColor = set.getInt("titleColor", 0xECF9A2);
+
+ _equipHead = set.getInt("equipHead", 0);
+ _equipRHand = set.getInt("equipRHand", 0); // or dual hand
+ _equipLHand = set.getInt("equipLHand", 0);
+ _equipGloves = set.getInt("equipGloves", 0);
+ _equipChest = set.getInt("equipChest", 0);
+ _equipLegs = set.getInt("equipLegs", 0);
+ _equipFeet = set.getInt("equipFeet", 0);
+ _equipCloak = set.getInt("equipCloak", 0);
+ _equipHair = set.getInt("equipHair", 0);
+ _equipHair2 = set.getInt("equipHair2", 0);
+ _agathionId = set.getInt("agathionId", 0);
+
+ _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0);
+ _armorEnchantLevel = set.getInt("armorEnchantLevel", 0);
+
+ _fishing = set.getBoolean("fishing", false);
+ _baitLocationX = set.getInt("baitLocationX", 0);
+ _baitLocationY = set.getInt("baitLocationY", 0);
+ _baitLocationZ = set.getInt("baitLocationZ", 0);
+
+ _recommends = set.getInt("recommends", 0);
+ _nobleLevel = set.getInt("nobleLevel", 0);
+ _hero = set.getBoolean("hero", false);
+ _clanId = set.getInt("clanId", 0);
+ _pledgeStatus = set.getInt("pledgeStatus", 0);
+ }
+
+ public int getClassId()
+ {
+ return _classId;
+ }
+
+ public int getHair()
+ {
+ return _hair;
+ }
+
+ public int getHairColor()
+ {
+ return _hairColor;
+ }
+
+ public int getFace()
+ {
+ return _face;
+ }
+
+ public int getNameColor()
+ {
+ return _nameColor;
+ }
+
+ public int getTitleColor()
+ {
+ return _titleColor;
+ }
+
+ public int getEquipHead()
+ {
+ return _equipHead;
+ }
+
+ public int getEquipRHand()
+ {
+ return _equipRHand;
+ }
+
+ public int getEquipLHand()
+ {
+ return _equipLHand;
+ }
+
+ public int getEquipGloves()
+ {
+ return _equipGloves;
+ }
+
+ public int getEquipChest()
+ {
+ return _equipChest;
+ }
+
+ public int getEquipLegs()
+ {
+ return _equipLegs;
+ }
+
+ public int getEquipFeet()
+ {
+ return _equipFeet;
+ }
+
+ public int getEquipCloak()
+ {
+ return _equipCloak;
+ }
+
+ public int getEquipHair()
+ {
+ return _equipHair;
+ }
+
+ public int getEquipHair2()
+ {
+ return _equipHair2;
+ }
+
+ public int getAgathionId()
+ {
+ return _agathionId;
+ }
+
+ public int getWeaponEnchantLevel()
+ {
+ return _weaponEnchantLevel;
+ }
+
+ public int getArmorEnchantLevel()
+ {
+ return _armorEnchantLevel;
+ }
+
+ public boolean isFishing()
+ {
+ return _fishing;
+ }
+
+ public int getBaitLocationX()
+ {
+ return _baitLocationX;
+ }
+
+ public int getBaitLocationY()
+ {
+ return _baitLocationY;
+ }
+
+ public int getBaitLocationZ()
+ {
+ return _baitLocationZ;
+ }
+
+ public int getRecommends()
+ {
+ return _recommends;
+ }
+
+ public int getNobleLevel()
+ {
+ return _nobleLevel;
+ }
+
+ public boolean isHero()
+ {
+ return _hero;
+ }
+
+ public int getClanId()
+ {
+ return _clanId;
+ }
+
+ public int getPledgeStatus()
+ {
+ return _pledgeStatus;
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
index c5af087f72..551733f42a 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java
@@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object
*
* Do Pickup Item : PCInstance and Pet
*
- * @param player Player that pick up the item
+ * @param character Character that pick up the item
*/
- public final void pickupMe(L2Character player)
+ public final void pickupMe(L2Character character)
{
assert getWorldRegion() != null;
final L2WorldRegion oldregion = getWorldRegion();
// Create a server->client GetItem packet to pick up the L2ItemInstance
- player.broadcastPacket(new GetItem(this, player.getObjectId()));
+ character.broadcastPacket(new GetItem(this, character.getObjectId()));
synchronized (this)
{
@@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object
// Remove the L2ItemInstance from the world
L2World.getInstance().removeVisibleObject(this, oldregion);
- if (player.isPlayer())
+ if (character.isPlayer())
{
// Notify to scripts
- EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem());
+ EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem());
}
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java
index 83f6e88b77..7505001c60 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java
@@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable
public boolean checkCondition(L2Character activeChar, L2Object object)
{
- if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)
+ if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION))
{
return true;
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
index b7eda58d00..13932008ff 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java
@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
+import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@@ -159,7 +160,7 @@ public class SkillCaster implements Runnable
}
// You should not heal/buff monsters without pressing the ctrl button.
- if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed)
+ if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed)
{
caster.sendPacket(SystemMessageId.INVALID_TARGET);
return null;
@@ -609,6 +610,10 @@ public class SkillCaster implements Runnable
// Add hate to the attackable, and put it in the attack list.
((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint());
((L2Character) obj).addAttackerToAttackByList(caster);
+ if (obj.isFakePlayer())
+ {
+ player.updatePvPStatus();
+ }
}
// notify target AI about the attack
@@ -617,10 +622,19 @@ public class SkillCaster implements Runnable
((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster);
}
}
- else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0))))
+ else if (((skill.getEffectPoint() > 0) && obj.isMonster()) //
+ || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) //
+ || (((L2Character) obj).getReputation() < 0) //
+ )))
{
// Supporting players or monsters result in pvpflag.
- player.updatePvPStatus();
+ if (!obj.isFakePlayer() //
+ || (obj.isFakePlayer() //
+ && (!((L2Npc) obj).isScriptValue(0) //
+ || (((L2Npc) obj).getReputation() < 0))))
+ {
+ player.updatePvPStatus();
+ }
}
}
@@ -630,7 +644,7 @@ public class SkillCaster implements Runnable
EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob);
// On Skill See logic
- if (npcMob.isAttackable())
+ if (npcMob.isAttackable() && !npcMob.isFakePlayer())
{
final L2Attackable attackable = (L2Attackable) npcMob;
@@ -652,6 +666,19 @@ public class SkillCaster implements Runnable
}
});
}
+ else if (caster.isFakePlayer()) // fake player attacks player
+ {
+ if (target.isPlayable() || target.isFakePlayer())
+ {
+ final L2Npc npc = ((L2Npc) caster);
+ if (!npc.isScriptValue(1))
+ {
+ npc.setScriptValue(1); // in combat
+ npc.broadcastInfo(); // update flag status
+ QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
+ }
+ }
+ }
}
catch (Exception e)
{
@@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable
return false;
}
}
-
return true;
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
index fdf0dadf55..06bea1b4cf 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java
@@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
@@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
@@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
- if (character.getRunSpeed() == 0)
+ if (character.isFakePlayer())
+ {
+ player.sendPacket(new FakePlayerInfo((L2Npc) character));
+ }
+ else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
index 91a9ce830a..ccd2d1d13a 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java
@@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket
}
case 1:
{
- if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC))
+ if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer()))
{
obj.onAction(activeChar, false);
}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
index 876c53c093..06464d9911 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java
@@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket
return;
}
- if (Config.FORBIDDEN_NAMES.length > 1)
+ if (Config.FORBIDDEN_NAMES.length > 0)
{
for (String st : Config.FORBIDDEN_NAMES)
{
@@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
+ return;
+ }
+
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
index 06bfa3c200..01c8b0c67f 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java
@@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class RequestBlock implements IClientIncomingPacket
{
@@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket
case BLOCK:
case UNBLOCK:
{
+ // TODO: Save in database? :P
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (_type == BLOCK)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
// can't use block/unblock for locating invisible characters
if (targetId <= 0)
{
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
index ceb67b0f5f..cf79bdb24c 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java
@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable;
import com.l2jmobius.gameserver.util.Util;
@@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket
{
result = NAME_ALREADY_EXISTS;
}
+ else if (FakePlayerData.getInstance().getProperName(_name) != null)
+ {
+ result = NAME_ALREADY_EXISTS;
+ }
else if (_name.length() > 16)
{
result = INVALID_LENGTH;
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
index b0ace828dc..ee8bcd656b 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java
@@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart;
@@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance activeChar = client.getActiveChar();
- final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (activeChar == null)
{
return;
}
+
+ if (FakePlayerData.getInstance().isTalkable(_player))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(_player);
+ if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ return;
+ }
+ if (activeChar.isProcessingRequest())
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(name);
+ activeChar.sendPacket(msg);
+ return;
+ }
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL);
+ sm.addString(name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000);
+ activeChar.blockRequest();
+ return;
+ }
+
+ final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (targetChar == null)
{
activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
index f104c94161..c0042d45c5 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java
@@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Party;
@@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ if (player.getParty() == null)
+ {
+ player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED);
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY);
+ }
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
final L2PcInstance requestor = client.getActiveChar();
- final L2PcInstance target = L2World.getInstance().getPlayer(_name);
-
if (requestor == null)
{
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY);
+ sm.addString(FakePlayerData.getInstance().getProperName(_name));
+ requestor.sendPacket(sm);
+ if (!requestor.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000);
+ requestor.blockRequest();
+ }
+ else
+ {
+ requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY);
+ }
+ return;
+ }
+
+ final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (target == null)
{
requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
index 292153afd8..37c539556f 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java
@@ -17,12 +17,15 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge;
+import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class ...
@@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return;
}
+ if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName())))
+ {
+ if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0)
+ {
+ activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN);
+ }
+ else
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ msg.addString(activeChar.getTarget().getName());
+ activeChar.sendPacket(msg);
+ }
+ }
+ return;
+ }
+
final L2PcInstance target = L2World.getInstance().getPlayer(_target);
if (target == null)
{
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
index 3d5bcaeca5..9cbb114e88 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java
@@ -23,6 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.BlockList;
@@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket
}
}
+ if (FakePlayerData.getInstance().isTalkable(_receiver))
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1);
+ sm.addString(FakePlayerData.getInstance().getProperName(_receiver));
+ activeChar.sendPacket(sm);
+ return;
+ }
+
final int receiverId = CharNameTable.getInstance().getIdByName(_receiver);
if (receiverId <= 0)
{
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
index 8156905e94..1336c2bdb7 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java
@@ -17,6 +17,7 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
@@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket
}
final L2Object object = activeChar.getTarget();
-
if (!(object instanceof L2PcInstance))
{
if (object == null)
{
client.sendPacket(SystemMessageId.SELECT_TARGET);
}
+ else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName()))
+ {
+ if (activeChar.getRecomLeft() <= 0)
+ {
+ client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER);
+ return;
+ }
+
+ SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT);
+ sm.addString(FakePlayerData.getInstance().getProperName(object.getName()));
+ sm.addInt(activeChar.getRecomLeft());
+ client.sendPacket(sm);
+
+ activeChar.setRecomLeft(activeChar.getRecomLeft() - 1);
+ client.sendPacket(new UserInfo(activeChar));
+ client.sendPacket(new ExVoteSystemInfo(activeChar));
+ }
else
{
client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
index d77dc881b3..5d7e35eb43 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java
@@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.skills.AbnormalType;
@@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player, String name)
+ {
+ if (player != null)
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE);
+ sm.addString(name);
+ player.sendPacket(sm);
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(target.getName()))
+ {
+ final String name = FakePlayerData.getInstance().getProperName(target.getName());
+ boolean npcInRange = false;
+ for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150))
+ {
+ if (npc.getName().equals(name))
+ {
+ npcInRange = true;
+ }
+ }
+ if (!npcInRange)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE));
+ return;
+ }
+ if (!player.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1);
+ sm.addString(name);
+ player.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000);
+ player.blockRequest();
+ }
+ else
+ {
+ player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE);
+ }
+ return;
+ }
+
if (!target.isPlayer())
{
client.sendPacket(SystemMessageId.INVALID_TARGET);
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
index 4fa25283a7..530a6d7a01 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java
@@ -17,6 +17,8 @@
package com.l2jmobius.gameserver.network.clientpackets.friend;
import com.l2jmobius.commons.network.PacketReader;
+import com.l2jmobius.gameserver.ThreadPoolManager;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return true;
}
+ private void scheduleDeny(L2PcInstance player)
+ {
+ if (player != null)
+ {
+ player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST));
+ player.onTransactionResponse();
+ }
+ }
+
@Override
public void run(L2GameClient client)
{
@@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return;
}
+ if (FakePlayerData.getInstance().isTalkable(_name))
+ {
+ if (!activeChar.isProcessingRequest())
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000);
+ activeChar.blockRequest();
+ }
+ else
+ {
+ final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
+ sm.addString(_name);
+ activeChar.sendPacket(sm);
+ }
+ return;
+ }
+
final L2PcInstance friend = L2World.getInstance().getPlayer(_name);
// Target is not found in the game.
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
index 2170ef2e94..017541bd86 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java
@@ -22,6 +22,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
- if (receiver.getFriendList().contains(sender.getObjectId()))
+ if (receiver != null)
{
- _mask |= 0x01;
- }
- if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
- {
- _mask |= 0x02;
- }
- if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
- {
- _mask |= 0x04;
- }
- if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
- {
- _mask |= 0x08;
+ if (receiver.getFriendList().contains(sender.getObjectId()))
+ {
+ _mask |= 0x01;
+ }
+ if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
+ {
+ _mask |= 0x02;
+ }
+ if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
+ {
+ _mask |= 0x04;
+ }
+ if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
+ {
+ _mask |= 0x08;
+ }
}
// Does not shows level
@@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket
}
}
+ /**
+ * Used by fake players.
+ * @param sender
+ * @param receiver
+ * @param name
+ * @param messageType
+ * @param text
+ */
+ public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
+ {
+ _objectId = sender.getObjectId();
+ _charName = name;
+ _charLevel = sender.getLevel();
+ _textType = messageType;
+ _text = text;
+ }
+
/**
* @param objectId
* @param messageType
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
new file mode 100644
index 0000000000..d1b7900f12
--- /dev/null
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java
@@ -0,0 +1,231 @@
+/*
+ * This file is part of the L2J Mobius project.
+ *
+ * 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 .
+ */
+package com.l2jmobius.gameserver.network.serverpackets;
+
+import java.util.Set;
+
+import com.l2jmobius.commons.network.PacketWriter;
+import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
+import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
+import com.l2jmobius.gameserver.enums.Sex;
+import com.l2jmobius.gameserver.model.L2Clan;
+import com.l2jmobius.gameserver.model.actor.L2Npc;
+import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
+import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
+import com.l2jmobius.gameserver.model.zone.ZoneId;
+import com.l2jmobius.gameserver.network.OutgoingPackets;
+
+/**
+ * @author Mobius
+ */
+public class FakePlayerInfo implements IClientOutgoingPacket
+{
+ private final L2Npc _npc;
+ private final int _objId;
+ private final int _x, _y, _z, _heading;
+ private final int _mAtkSpd, _pAtkSpd;
+ private final int _runSpd, _walkSpd;
+ private final int _swimRunSpd;
+ private final int _swimWalkSpd;
+ private final int _flyRunSpd;
+ private final int _flyWalkSpd;
+ private final double _moveMultiplier;
+ private final float _attackSpeedMultiplier;
+ private final FakePlayerHolder _fpcHolder;
+ private final L2Clan _clan;
+
+ public FakePlayerInfo(L2Npc npc)
+ {
+ _npc = npc;
+ _objId = npc.getObjectId();
+ _x = npc.getX();
+ _y = npc.getY();
+ _z = npc.getZ();
+ _heading = npc.getHeading();
+ _mAtkSpd = npc.getMAtkSpd();
+ _pAtkSpd = npc.getPAtkSpd();
+ _attackSpeedMultiplier = npc.getAttackSpeedMultiplier();
+ _moveMultiplier = npc.getMovementSpeedMultiplier();
+ _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier);
+ _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier);
+ _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier);
+ _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier);
+ _flyRunSpd = npc.isFlying() ? _runSpd : 0;
+ _flyWalkSpd = npc.isFlying() ? _walkSpd : 0;
+ _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId());
+ _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId());
+ }
+
+ @Override
+ public boolean write(PacketWriter packet)
+ {
+ OutgoingPackets.CHAR_INFO.writeId(packet);
+ packet.writeD(_x);
+ packet.writeD(_y);
+ packet.writeD(_z);
+ packet.writeD(0x00); // vehicleId
+ packet.writeD(_objId);
+ packet.writeS(_npc.getName());
+
+ packet.writeH(_npc.getRace().ordinal());
+ packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00);
+ packet.writeD(_fpcHolder.getClassId());
+
+ packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER
+ packet.writeD(_fpcHolder.getEquipHead());
+ packet.writeD(_fpcHolder.getEquipRHand());
+ packet.writeD(_fpcHolder.getEquipLHand());
+ packet.writeD(_fpcHolder.getEquipGloves());
+ packet.writeD(_fpcHolder.getEquipChest());
+ packet.writeD(_fpcHolder.getEquipLegs());
+ packet.writeD(_fpcHolder.getEquipFeet());
+ packet.writeD(_fpcHolder.getEquipCloak());
+ packet.writeD(_fpcHolder.getEquipRHand()); // dual hand
+ packet.writeD(_fpcHolder.getEquipHair());
+ packet.writeD(_fpcHolder.getEquipHair2());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderAugument())
+ {
+ packet.writeQ(0x00);
+ }
+
+ packet.writeC(_fpcHolder.getArmorEnchantLevel());
+
+ for (@SuppressWarnings("unused")
+ int slot : getPaperdollOrderVisualId())
+ {
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(_npc.getScriptValue()); // getPvpFlag()
+ packet.writeD(_npc.getReputation());
+
+ packet.writeD(_mAtkSpd);
+ packet.writeD(_pAtkSpd);
+
+ packet.writeH(_runSpd);
+ packet.writeH(_walkSpd);
+ packet.writeH(_swimRunSpd);
+ packet.writeH(_swimWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeH(_flyRunSpd);
+ packet.writeH(_flyWalkSpd);
+ packet.writeF(_moveMultiplier);
+ packet.writeF(_attackSpeedMultiplier);
+
+ packet.writeF(_npc.getCollisionRadius());
+ packet.writeF(_npc.getCollisionHeight());
+
+ packet.writeD(_fpcHolder.getHair());
+ packet.writeD(_fpcHolder.getHairColor());
+ packet.writeD(_fpcHolder.getFace());
+
+ packet.writeS(_npc.getTemplate().getTitle());
+
+ if (_clan != null)
+ {
+ packet.writeD(_clan.getId());
+ packet.writeD(_clan.getCrestId());
+ packet.writeD(_clan.getAllyId());
+ packet.writeD(_clan.getAllyCrestId());
+ }
+ else
+ {
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ packet.writeD(0x00);
+ }
+
+ packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked)
+ packet.writeC(_npc.isRunning() ? 0x01 : 0x00);
+ packet.writeC(_npc.isInCombat() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00);
+
+ packet.writeC(_npc.isInvisible() ? 0x01 : 0x00);
+
+ packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount
+ packet.writeC(0x00); // getPrivateStoreType().getId()
+
+ packet.writeH(0x00); // getCubics().size()
+ // getCubics().keySet().forEach(packet::writeH);
+
+ packet.writeC(0x00);
+
+ packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0);
+ packet.writeH(_fpcHolder.getRecommends());
+ packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000
+
+ packet.writeD(_fpcHolder.getClassId());
+ packet.writeD(0x00);
+ packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel
+
+ packet.writeC(_npc.getTeam().getId());
+
+ packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00);
+ packet.writeC(_fpcHolder.getNobleLevel());
+ packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00);
+
+ packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00);
+
+ packet.writeD(_fpcHolder.getBaitLocationX());
+ packet.writeD(_fpcHolder.getBaitLocationY());
+ packet.writeD(_fpcHolder.getBaitLocationZ());
+
+ packet.writeD(_fpcHolder.getNameColor());
+
+ packet.writeD(_heading);
+
+ packet.writeC(_fpcHolder.getPledgeStatus());
+ packet.writeH(0x00); // getPledgeType()
+
+ packet.writeD(_fpcHolder.getTitleColor());
+
+ packet.writeC(0x00); // isCursedWeaponEquipped
+
+ packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0
+ packet.writeD(0x00); // getTransformationDisplayId()
+ packet.writeD(_fpcHolder.getAgathionId());
+
+ packet.writeC(0x00);
+
+ packet.writeD(0x00); // getCurrentCp()
+ packet.writeD(_npc.getMaxHp());
+ packet.writeD((int) Math.round(_npc.getCurrentHp()));
+ packet.writeD(_npc.getMaxMp());
+ packet.writeD((int) Math.round(_npc.getCurrentMp()));
+
+ packet.writeC(0x00);
+ final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects();
+ packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0));
+ for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects)
+ {
+ packet.writeH(abnormalVisualEffect.getClientId());
+ }
+ if (_npc.isInvisible())
+ {
+ packet.writeH(AbnormalVisualEffect.STEALTH.getClientId());
+ }
+ packet.writeC(0x00); // cocPlayer.getPosition()
+ packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00);
+ packet.writeC(0x00); // Used Ability Points
+ return true;
+ }
+}
diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
index 4fb1a757e6..c294edab2a 100644
--- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
+++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java
@@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket
addComponentType(NpcInfoType.TITLE_NPCSTRINGID);
}
+ if (_npc.getReputation() != 0)
+ {
+ addComponentType(NpcInfoType.REPUTATION);
+ }
+
if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible())
{
addComponentType(NpcInfoType.ABNORMALS);
@@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket
}
if (containsMask(NpcInfoType.REPUTATION))
{
- packet.writeD(0x00); // Name color
+ packet.writeD(_npc.getReputation()); // Reputation
}
if (containsMask(NpcInfoType.CLAN))
{