diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml index fdd47f3a21..50705109e1 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/AdminCommands.xml @@ -375,7 +375,10 @@ - + + + + diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/Custom/FakePlayers.ini new file mode 100644 index 0000000000..f745b0d31e --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FakePlayerChatData.xml new file mode 100644 index 0000000000..f5da5bfc8e --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FakePlayerChatData.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FakePlayerVisualData.xml new file mode 100644 index 0000000000..58125bd99b --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/FakePlayerVisualData.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/Routes.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/Routes.xml index 8299581178..01194b4a90 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/Routes.xml +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/Routes.xml @@ -9,15 +9,37 @@ - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java new file mode 100644 index 0000000000..e1dde7324e --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java index 1640a69781..1c0c72b387 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/MasterHandler.java @@ -74,6 +74,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.AdminGamePoints; @@ -369,6 +370,7 @@ public class MasterHandler AdminEventEngine.class, AdminEvents.class, AdminExpSp.class, + AdminFakePlayers.class, AdminFightCalculator.class, AdminFortSiege.class, AdminGamePoints.class, diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java index 1ab994904c..e783ea8ac1 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionhandlers/L2NpcAction.java @@ -129,10 +129,14 @@ public class L2NpcAction implements IActionHandler npc.showChatWindow(activeChar); } } - if ((Config.PLAYER_MOVEMENT_BLOCK_TIME > 0) && !activeChar.isGM()) + if (Config.PLAYER_MOVEMENT_BLOCK_TIME > 0) { activeChar.updateNotMoveUntil(); } + if (npc.isFakePlayer() && GeoEngine.getInstance().canSeeTarget(activeChar, npc)) + { + activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, npc); + } } } } diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java index eeb48ebbe8..955a10674b 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java @@ -191,7 +191,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_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java new file mode 100644 index 0000000000..cbe498c1f1 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java @@ -0,0 +1,78 @@ +/* + * 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); + activeChar.sendMessage("Your message has been sent."); + } + return true; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index e6cd78bfa6..708982d9f9 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -30,6 +30,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.MultisellData; import com.l2jmobius.gameserver.data.xml.impl.NpcData; import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData; @@ -38,9 +39,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; @@ -247,11 +251,31 @@ public class AdminReload implements IAdminCommandHandler break; } case "itemmall": + case "primeshop": { PrimeShopData.getInstance().load(); AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded item mall 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_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminSpawn.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminSpawn.java index e57df424e8..417ca8ba44 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminSpawn.java +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/admincommandhandlers/AdminSpawn.java @@ -23,6 +23,7 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import com.l2jmobius.Config; import com.l2jmobius.gameserver.SevenSigns; import com.l2jmobius.gameserver.data.xml.impl.AdminData; import com.l2jmobius.gameserver.data.xml.impl.NpcData; @@ -413,6 +414,12 @@ public class AdminSpawn implements IAdminCommandHandler template = NpcData.getInstance().getTemplateByName(monsterId.replace('_', ' ')); } + if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer()) + { + activeChar.sendPacket(SystemMessageId.YOUR_TARGET_CANNOT_BE_FOUND); + return; + } + try { final L2Spawn spawn = new L2Spawn(template); diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java index 12a4e008a7..d9094e3c33 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java +++ b/L2J_Mobius_CT_2.6_HighFive/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; @@ -58,6 +60,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.getObjectId(), type, "->" + name, 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_CT_2.6_HighFive/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/spawns/Others/FakePlayers.xml new file mode 100644 index 0000000000..e4e71e68fe --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/spawns/Others/FakePlayers.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/stats/npcs/custom/fpc_combat.xml new file mode 100644 index 0000000000..74282456bd --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/stats/npcs/custom/fpc_combat.xml @@ -0,0 +1,43 @@ + + + + + HUMAN + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/stats/npcs/custom/fpc_passive.xml new file mode 100644 index 0000000000..8fc0119fa1 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FakePlayerChatData.xsd new file mode 100644 index 0000000000..2b2c94e75b --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FakePlayerChatData.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FakePlayerVisualData.xsd new file mode 100644 index 0000000000..0628acefc3 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/FakePlayerVisualData.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/npcs.xsd index 76b02ee70f..087798e5ca 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/npcs.xsd +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/data/xsd/npcs.xsd @@ -285,5 +285,7 @@ + + \ No newline at end of file diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/Config.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/Config.java index 342f808403..f8e228ab7c 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/Config.java @@ -112,8 +112,10 @@ public final class Config public static final String CUSTOM_COMMUNITY_BOARD_CONFIG_FILE = "./config/Custom/CommunityBoard.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_HELLBOUND_STATUS_CONFIG_FILE = "./config/Custom/HellboundStatus.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"; public static final String CUSTOM_OFFLINE_TRADE_CONFIG_FILE = "./config/Custom/OfflineTrade.ini"; public static final String CUSTOM_PASSWORD_CHANGE_CONFIG_FILE = "./config/Custom/PasswordChange.ini"; @@ -131,7 +133,6 @@ public final class Config public static final String CUSTOM_VOTE_REWARD_CONFIG_FILE = "./config/Custom/VoteReward.ini"; public static final String CUSTOM_WAREHOUSE_SORTING_CONFIG_FILE = "./config/Custom/WarehouseSorting.ini"; public static final String CUSTOM_WEDDING_CONFIG_FILE = "./config/Custom/Wedding.ini"; - public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini"; public static final String CUSTOM_WALKER_BOT_PROTECTION_CONFIG_FILE = "./config/Custom/WalkerBotProtection.ini"; // -------------------------------------------------- @@ -1280,6 +1281,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; @@ -2379,6 +2390,11 @@ public final class Config KARMA_LIST_NONDROPPABLE_ITEMS[i] = Integer.parseInt(karma[i]); } + ANTIFEED_ENABLE = PVPSettings.getBoolean("AntiFeedEnable", false); + ANTIFEED_DUALBOX = PVPSettings.getBoolean("AntiFeedDualbox", true); + ANTIFEED_DISCONNECTED_AS_DUALBOX = PVPSettings.getBoolean("AntiFeedDisconnectedAsDualbox", true); + ANTIFEED_INTERVAL = PVPSettings.getInt("AntiFeedInterval", 120) * 1000; + // sorting so binarySearch can be used later Arrays.sort(KARMA_LIST_NONDROPPABLE_PET_ITEMS); Arrays.sort(KARMA_LIST_NONDROPPABLE_ITEMS); @@ -2386,11 +2402,6 @@ public final class Config PVP_NORMAL_TIME = PVPSettings.getInt("PvPVsNormalTime", 120000); PVP_PVP_TIME = PVPSettings.getInt("PvPVsPvPTime", 60000); - ANTIFEED_ENABLE = PVPSettings.getBoolean("AntiFeedEnable", false); - ANTIFEED_DUALBOX = PVPSettings.getBoolean("AntiFeedDualbox", true); - ANTIFEED_DISCONNECTED_AS_DUALBOX = PVPSettings.getBoolean("AntiFeedDisconnectedAsDualbox", true); - ANTIFEED_INTERVAL = PVPSettings.getInt("AntiFeedInterval", 120) * 1000; - // Load Olympiad config file (if exists) final PropertiesParser Olympiad = new PropertiesParser(OLYMPIAD_CONFIG_FILE); @@ -2766,6 +2777,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); @@ -2776,6 +2800,43 @@ public final class Config HELLBOUND_STATUS = HellboundStatus.getBoolean("HellboundStatus", false); + // Load MultilingualSupport config file (if exists) + final PropertiesParser MultilingualSupport = new PropertiesParser(CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE); + + MULTILANG_DEFAULT = MultilingualSupport.getString("MultiLangDefault", "en"); + MULTILANG_ENABLE = MultilingualSupport.getBoolean("MultiLangEnable", false); + String[] allowed = MultilingualSupport.getString("MultiLangAllowed", MULTILANG_DEFAULT).split(";"); + MULTILANG_ALLOWED = new ArrayList<>(allowed.length); + for (String lang : allowed) + { + MULTILANG_ALLOWED.add(lang); + } + if (!MULTILANG_ALLOWED.contains(MULTILANG_DEFAULT)) + { + LOGGER.warning("MultiLang[Config.load()]: default language: " + MULTILANG_DEFAULT + " is not in allowed list !"); + } + MULTILANG_VOICED_ALLOW = MultilingualSupport.getBoolean("MultiLangVoiceCommand", true); + MULTILANG_SM_ENABLE = MultilingualSupport.getBoolean("MultiLangSystemMessageEnable", false); + allowed = MultilingualSupport.getString("MultiLangSystemMessageAllowed", "").split(";"); + MULTILANG_SM_ALLOWED = new ArrayList<>(allowed.length); + for (String lang : allowed) + { + if (!lang.isEmpty()) + { + MULTILANG_SM_ALLOWED.add(lang); + } + } + MULTILANG_NS_ENABLE = MultilingualSupport.getBoolean("MultiLangNpcStringEnable", false); + allowed = MultilingualSupport.getString("MultiLangNpcStringAllowed", "").split(";"); + MULTILANG_NS_ALLOWED = new ArrayList<>(allowed.length); + for (String lang : allowed) + { + if (!lang.isEmpty()) + { + MULTILANG_NS_ALLOWED.add(lang); + } + } + // Load OfflineTrade config file (if exists) final PropertiesParser OfflineTrade = new PropertiesParser(CUSTOM_OFFLINE_TRADE_CONFIG_FILE); @@ -2861,7 +2922,7 @@ public final class Config } } - // Load CustomSettings config file (if exists) + // Load PrivateStoreRange config file (if exists) final PropertiesParser PrivateStoreRange = new PropertiesParser(CUSTOM_PRIVATE_STORE_RANGE_CONFIG_FILE); SHOP_MIN_RANGE_FROM_PLAYER = PrivateStoreRange.getInt("ShopMinRangeFromPlayer", 50); @@ -3184,45 +3245,6 @@ public final class Config WEDDING_FORMALWEAR = Wedding.getBoolean("WeddingFormalWear", true); WEDDING_DIVORCE_COSTS = Wedding.getInt("WeddingDivorceCosts", 20); - // Load MultilingualSupport config file (if exists) - final PropertiesParser MultilingualSupport = new PropertiesParser(CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE); - - MULTILANG_DEFAULT = MultilingualSupport.getString("MultiLangDefault", "en"); - MULTILANG_ENABLE = MultilingualSupport.getBoolean("MultiLangEnable", false); - String[] allowed = MultilingualSupport.getString("MultiLangAllowed", MULTILANG_DEFAULT).split(";"); - MULTILANG_ALLOWED = new ArrayList<>(allowed.length); - for (String lang : allowed) - { - MULTILANG_ALLOWED.add(lang); - } - - if (!MULTILANG_ALLOWED.contains(MULTILANG_DEFAULT)) - { - LOGGER.warning("MultiLang[Config.load()]: default language: " + MULTILANG_DEFAULT + " is not in allowed list !"); - } - - MULTILANG_VOICED_ALLOW = MultilingualSupport.getBoolean("MultiLangVoiceCommand", true); - MULTILANG_SM_ENABLE = MultilingualSupport.getBoolean("MultiLangSystemMessageEnable", false); - allowed = MultilingualSupport.getString("MultiLangSystemMessageAllowed", "").split(";"); - MULTILANG_SM_ALLOWED = new ArrayList<>(allowed.length); - for (String lang : allowed) - { - if (!lang.isEmpty()) - { - MULTILANG_SM_ALLOWED.add(lang); - } - } - MULTILANG_NS_ENABLE = MultilingualSupport.getBoolean("MultiLangNpcStringEnable", false); - allowed = MultilingualSupport.getString("MultiLangNpcStringAllowed", "").split(";"); - MULTILANG_NS_ALLOWED = new ArrayList<>(allowed.length); - for (String lang : allowed) - { - if (!lang.isEmpty()) - { - MULTILANG_NS_ALLOWED.add(lang); - } - } - // Load VoteReward config file (if exists) final PropertiesParser VoteReward = new PropertiesParser(CUSTOM_VOTE_REWARD_CONFIG_FILE); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java index 6ea6aef546..8dbd6c5e6d 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/GameServer.java @@ -53,6 +53,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnchantItemHPBonusData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemOptionsData; import com.l2jmobius.gameserver.data.xml.impl.EnchantSkillGroupsData; import com.l2jmobius.gameserver.data.xml.impl.ExperienceData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishData; import com.l2jmobius.gameserver.data.xml.impl.FishingMonstersData; import com.l2jmobius.gameserver.data.xml.impl.FishingRodsData; @@ -100,6 +101,7 @@ import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; import com.l2jmobius.gameserver.instancemanager.DayNightSpawnManager; import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager; import com.l2jmobius.gameserver.instancemanager.FactionManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.FishingChampionshipManager; import com.l2jmobius.gameserver.instancemanager.FortManager; import com.l2jmobius.gameserver.instancemanager.FortSiegeManager; @@ -269,6 +271,8 @@ public class GameServer DoorData.getInstance(); SkillLearnData.getInstance(); NpcData.getInstance(); + FakePlayerData.getInstance(); + FakePlayerChatManager.getInstance(); WalkingManager.getInstance(); StaticObjectData.getInstance(); ItemAuctionManager.getInstance(); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/AbstractAI.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/AbstractAI.java index 785e52a4fe..4cb98bf6c5 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/AbstractAI.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/AbstractAI.java @@ -30,6 +30,7 @@ import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.interfaces.ILocational; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.AutoAttackStart; @@ -627,6 +628,11 @@ public abstract class AbstractAI implements Ctrl } } + public void moveTo(ILocational loc) + { + moveTo(loc.getX(), loc.getY(), loc.getZ()); + } + /** * Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation (broadcast).
* Caution : Low level function, used by AI subclasses diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 53289857c1..265ff75ece 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.enums.AIType; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager; +import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.Location; @@ -56,6 +57,8 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher; import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAttackableFactionCall; import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.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.AbnormalVisualEffect; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.skills.targets.L2TargetType; @@ -489,6 +492,74 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable return; } + 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().getSkills()) + { + npc.doSimultaneousCast(skillHolder.getSkill()); + } + npc.broadcastInfo(); // ? check if this is necessary + } + } + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + } + npc.setRunning(); + } + return; + } + /* * Check to see if this is a festival mob spawn. If it is, then check to see if the aggro trigger is a festival participant...if so, move to attack it. */ @@ -505,6 +576,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // For each L2Character check if the target is autoattackable if (autoAttackCondition(target)) // check aggression { + if (target.isFakePlayer()) + { + if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC)) + { + final int hating = npc.getHating(target); + if (hating == 0) + { + npc.addDamageHate(target, 0, 1); + } + } + return; + } if (target.isPlayable()) { final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), target.getActingPlayer(), target.isSummon()), getActiveChar(), TerminateReturn.class); @@ -752,7 +835,10 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // Set the AI Intention to AI_INTENTION_ACTIVE setIntention(AI_INTENTION_ACTIVE); - npc.setWalking(); + if (!_actor.isFakePlayer()) + { + npc.setWalking(); + } return; } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java index 04e14b0410..dae3cefd2c 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2CharacterAI.java @@ -42,7 +42,6 @@ import com.l2jmobius.gameserver.model.Location; import com.l2jmobius.gameserver.model.actor.L2Attackable; import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.L2Npc; -import com.l2jmobius.gameserver.model.actor.L2Playable; import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; @@ -859,7 +858,7 @@ public class L2CharacterAI extends AbstractAI // Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die (broadcast) clientNotifyDead(); - if (!(_actor instanceof L2Playable)) + if (!_actor.isPlayable() && !_actor.isFakePlayer()) { _actor.setWalking(); } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2PlayableAI.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2PlayableAI.java index 4dff60a8a6..0b1c0f52d8 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2PlayableAI.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/ai/L2PlayableAI.java @@ -81,7 +81,7 @@ public abstract class L2PlayableAI extends L2CharacterAI @Override protected void onIntentionCast(Skill skill, L2Object target) { - if ((target.isPlayable()) && skill.isBad()) + if ((target != null) && (target.isPlayable()) && skill.isBad()) { if (target.getActingPlayer().isProtectionBlessingAffected() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getKarma() > 0) && !target.isInsideZone(ZoneId.PVP)) { diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java new file mode 100644 index 0000000000..0a6ca5267a --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java index c4300e0062..f5466146be 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java @@ -335,6 +335,8 @@ public class NpcData implements IGameXmlReader set.set("passableDoor", parseBoolean(attrs, "passableDoor")); set.set("hasSummoner", parseBoolean(attrs, "hasSummoner")); set.set("canBeSown", parseBoolean(attrs, "canBeSown")); + set.set("fakePlayer", parseBoolean(attrs, "fakePlayer")); + set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable")); break; } case "skilllist": diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/BotReportTable.java index 4a92ced237..250e16a8e1 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/BotReportTable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/BotReportTable.java @@ -41,6 +41,8 @@ import com.l2jmobius.commons.database.DatabaseFactory; 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; @@ -215,9 +217,9 @@ public final class BotReportTable 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; } @@ -228,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_BATTLEFIELD_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD); return false; @@ -240,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_EXP_AFTER_CONNECTING); return false; @@ -327,7 +329,10 @@ public final class BotReportTable sm.addInt(rcdRep.getPointsLeft()); reporter.sendPacket(sm); - handleReport(bot, rcd); + if (bot.isPlayer()) + { + handleReport(bot.getActingPlayer(), rcd); + } return true; } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/ItemTable.java index 89b3c159e1..d8d249d03f 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/ItemTable.java +++ b/L2J_Mobius_CT_2.6_HighFive/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; @@ -200,11 +201,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/SpawnTable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/SpawnTable.java index de19a98a16..51f2019abf 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/SpawnTable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/datatables/SpawnTable.java @@ -89,6 +89,11 @@ public final class SpawnTable implements IGameXmlReader return false; } + if (!Config.FAKE_PLAYERS_ENABLED && npcTemplate.isFakePlayer()) + { + return false; + } + return true; } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java new file mode 100644 index 0000000000..65b7775e2f --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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.concurrent.ThreadPool; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.commons.util.Rnd; +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) + { + ThreadPool.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY)); + } + + public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay) + { + ThreadPool.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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/DropProtection.java index e353a406d1..a6c0cd76fc 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/DropProtection.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/DropProtection.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model; import java.util.concurrent.ScheduledFuture; import com.l2jmobius.commons.concurrent.ThreadPool; +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; } @@ -72,12 +73,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2Object.java index ad2f7b26c7..1105b77ed5 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2Object.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/L2Object.java @@ -366,6 +366,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index b9d6adffcd..fc4297cf03 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAtt import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAttackableAttack; import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.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; @@ -294,7 +295,7 @@ public class L2Attackable extends L2Npc public synchronized boolean getMustRewardExpSP() { - return _mustGiveExpSp; + return _mustGiveExpSp && !isFakePlayer(); } /** @@ -653,6 +654,12 @@ public class L2Attackable extends L2Npc return; } + // Check if fake players should aggro each other. + if (isFakePlayer() && !Config.FAKE_PLAYER_AGGRO_FPC && attacker.isFakePlayer()) + { + return; + } + // Get the AggroInfo of the attacker L2Character from the _aggroList of the L2Attackable final AggroInfo ai = _aggroList.computeIfAbsent(attacker, AggroInfo::new); ai.addDamage(damage); @@ -723,7 +730,10 @@ public class L2Attackable extends L2Npc ((L2AttackableAI) getAI()).setGlobalAggro(-25); clearAggroList(); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); - setWalking(); + if (!isFakePlayer()) + { + setWalking(); + } } return; } @@ -741,7 +751,10 @@ public class L2Attackable extends L2Npc ((L2AttackableAI) getAI()).setGlobalAggro(-25); clearAggroList(); getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE); - setWalking(); + if (!isFakePlayer()) + { + setWalking(); + } } } @@ -936,6 +949,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 (Config.AUTO_LOOT_ITEM_IDS.contains(item.getId()) || 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.getSkills()) + { + doSimultaneousCast(skillHolder.getSkill()); + } + 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; } @@ -1023,7 +1069,7 @@ public class L2Attackable extends L2Npc */ public void doEventDrop(L2Character lastAttacker) { - if (lastAttacker == null) + if ((lastAttacker == null) || isFakePlayer()) { return; } @@ -1385,12 +1431,29 @@ public class L2Attackable extends L2Npc public void onSpawn() { super.onSpawn(); + // Clear mob spoil, seed setSpoilerObjectId(0); + // Clear all aggro char from list clearAggroList(); + // Clear Harvester reward _harvestItem.set(null); + + // fake players + if (isFakePlayer()) + { + getFakePlayerDrops().clear(); // Clear existing fake player drops + setKarma(0); // reset karma + setScriptValue(0); // remove pvp flag + setRunning(); // don't walk + } + else + { + setWalking(); + } + // Clear mod Seeded stat _seeded = false; _seed = null; diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 6d9020db6b..e4e0fa172c 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; @@ -54,6 +55,7 @@ import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.InstanceManager; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.TerritoryWarManager; import com.l2jmobius.gameserver.instancemanager.WalkingManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; @@ -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.ExRotation; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.FlyToLocation.FlyType; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.MagicSkillCanceled; @@ -207,6 +210,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private int _karma = 0; + /** Table of Calculators containing all used calculator */ private Calculator[] _calculators; /** Map containing all skills of this character. */ @@ -273,6 +278,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private final Map _knownRelations = new ConcurrentHashMap<>(); + /** A list containing the dropped items of this fake player. */ + private final List _fakePlayerDrops = new CopyOnWriteArrayList<>(); + /** * Creates a creature. * @param template the creature template @@ -1033,6 +1041,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } } + 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); + } + } + // Flag the attacker if it's a L2PcInstance outside a PvP area final L2PcInstance player = getActingPlayer(); if (player != null) @@ -2818,7 +2837,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)); } @@ -3645,7 +3668,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)); } @@ -4664,6 +4691,12 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } + // Check if fake players should aggro each other. + if (isFakePlayer() && !Config.FAKE_PLAYER_AGGRO_FPC && target.isFakePlayer()) + { + return; + } + if ((isNpc() && target.isAlikeDead()) || target.isDead() || (!isInSurroundingRegion(target) && !isDoor())) { // getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null); @@ -4976,11 +5009,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean isInsidePeaceZone(L2Object attacker, L2Object target) { - if (target == null) - { - return false; - } - if (!(target.isPlayable() && attacker.isPlayable())) + if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable())) { return false; } @@ -5749,6 +5778,10 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe } } } + if (target.isFakePlayer()) + { + player.updatePvPStatus(); + } } // Mobs in range 1000 see spell @@ -5803,6 +5836,20 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe creature.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, this); } } + + if (isFakePlayer()) // fake player attacks player + { + if (target.isPlayable() || target.isFakePlayer()) + { + final L2Npc npc = ((L2Npc) this); + 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); + } + } + } } } } @@ -6800,6 +6847,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return _knownRelations; } + public int getKarma() + { + return _karma; + } + + public void setKarma(int karma) + { + _karma = karma; + } + public int getMinShopDistance() { return 0; @@ -6809,4 +6866,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { _cursorKeyMovement = value; } + + public List getFakePlayerDrops() + { + return _fakePlayerDrops; + } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index 0024f1b8b0..33451b4007 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -83,18 +83,22 @@ import com.l2jmobius.gameserver.model.items.L2Weapon; 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.stats.Formulas; import com.l2jmobius.gameserver.model.variables.NpcVariables; +import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.model.zone.type.L2TownZone; import com.l2jmobius.gameserver.network.NpcStringId; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.AbstractNpcInfo; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState; +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.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.taskmanager.DecayTaskManager; import com.l2jmobius.gameserver.util.Broadcast; @@ -132,6 +136,7 @@ public class L2Npc extends L2Character /** Support for random animation switching */ private boolean _isRandomAnimationEnabled = true; private boolean _isTalkable = getTemplate().isTalkable(); + private final boolean _isFakePlayer = getTemplate().isFakePlayer(); protected RandomAnimationTask _rAniTask = null; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -321,7 +326,7 @@ public class L2Npc extends L2Character */ public boolean hasRandomAnimation() { - return ((Config.MAX_NPC_ANIMATION > 0) && _isRandomAnimationEnabled && !getAiType().equals(AIType.CORPSE)); + return ((Config.MAX_NPC_ANIMATION > 0) && isRandomAnimationEnabled() && !getAiType().equals(AIType.CORPSE)); } /** @@ -338,7 +343,7 @@ public class L2Npc extends L2Character */ public boolean isRandomAnimationEnabled() { - return _isRandomAnimationEnabled; + return !isFakePlayer() && _isRandomAnimationEnabled; } @Override @@ -440,7 +445,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)); } @@ -1239,6 +1248,74 @@ 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) && (getKarma() < 0)) + { + if (Config.FAKE_PLAYER_KILL_KARMA) + { + player.setKarma(player.getKarma() + Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon())); + player.setPkKills(player.getPkKills() + 1); + player.broadcastUserInfo(); + 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.S1_3); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + else if (Config.FAKE_PLAYER_KILL_PVP) + { + player.setPvpKills(player.getPvpKills() + 1); + player.broadcastUserInfo(); + // 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.S1_3); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + DecayTaskManager.getInstance().add(this); return true; } @@ -1456,7 +1533,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)); } @@ -1595,7 +1676,20 @@ public class L2Npc extends L2Character @Override public void rechargeShots(boolean physical, boolean magic) { - if ((_soulshotamount > 0) || (_spiritshotamount > 0)) + if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS) + { + if (physical) + { + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); + setChargedShot(ShotType.SOULSHOTS, true); + } + if (magic) + { + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); + setChargedShot(ShotType.SPIRITSHOTS, true); + } + } + else if ((_soulshotamount > 0) || (_spiritshotamount > 0)) { if (physical) { @@ -1757,12 +1851,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++) @@ -1778,15 +1872,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); @@ -1811,14 +1905,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 @@ -1876,6 +1970,12 @@ public class L2Npc extends L2Character return _killingBlowWeaponId; } + @Override + public boolean isFakePlayer() + { + return _isFakePlayer; + } + /** * Adds a summoned NPC. * @param npc the summoned NPC diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Playable.java index 739e47d458..277a354486 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Playable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Playable.java @@ -319,8 +319,6 @@ public abstract class L2Playable extends L2Character public abstract void doPickupItem(L2Object object); - public abstract int getKarma(); - public abstract byte getPvpFlag(); public abstract boolean useMagic(Skill skill, boolean forceUse, boolean dontMove); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index df4b9675b4..2871c8b12d 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -951,6 +951,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java index 8ab1f3e991..c321763a81 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java @@ -44,13 +44,10 @@ public class L2GuardInstance extends L2Attackable setInstanceType(InstanceType.L2GuardInstance); } - /** - * Return True if hte attacker is a L2MonsterInstance. - */ @Override public boolean isAutoAttackable(L2Character attacker) { - if (attacker.isMonster()) + if (attacker.isMonster() && !attacker.isFakePlayer()) { return true; } @@ -148,6 +145,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java index 8aff270e77..6b9cbd53b2 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java @@ -18,6 +18,7 @@ package com.l2jmobius.gameserver.model.actor.instance; import java.util.concurrent.ScheduledFuture; +import com.l2jmobius.Config; import com.l2jmobius.gameserver.enums.InstanceType; import com.l2jmobius.gameserver.model.actor.L2Attackable; import com.l2jmobius.gameserver.model.actor.L2Character; @@ -60,6 +61,28 @@ 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)) + { + return true; + } + + if (attacker.isMonster()) + { + return attacker.isFakePlayer(); + } + + // Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints. + if (!attacker.isPlayable() && !attacker.isAttackable() && !(attacker instanceof L2TrapInstance) && !(attacker instanceof L2EffectPointInstance)) + { + return false; + } + return super.isAutoAttackable(attacker) && !isEventMob(); } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 9a64a39de0..8b2c85dbf8 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -443,9 +443,6 @@ public final class L2PcInstance extends L2Playable /** The Experience of the L2PcInstance before the last Death Penalty */ private long _expBeforeDeath; - /** The Karma of the L2PcInstance (if higher than 0, the name of the L2PcInstance appears in red) */ - private int _karma; - /** The number of player killed during a PvP (the player killed was PvP Flagged) */ private int _pvpKills; @@ -1923,19 +1920,11 @@ public final class L2PcInstance extends L2Playable return _expBeforeDeath; } - /** - * Return the Karma of the L2PcInstance. - */ - @Override - public int getKarma() - { - return _karma; - } - /** * Set the Karma of the L2PcInstance and send a Server->Client packet StatusUpdate (broadcast). * @param karma */ + @Override public void setKarma(int karma) { // Notify to scripts. @@ -1945,7 +1934,7 @@ public final class L2PcInstance extends L2Playable { karma = 0; } - if ((_karma == 0) && (karma > 0)) + if ((getKarma() == 0) && (karma > 0)) { L2World.getInstance().forEachVisibleObject(this, L2GuardInstance.class, object -> { @@ -1955,13 +1944,13 @@ public final class L2PcInstance extends L2Playable } }); } - else if ((_karma > 0) && (karma == 0)) + else if ((getKarma() > 0) && (karma == 0)) { // Send a Server->Client StatusUpdate packet with Karma and PvP Flag to the L2PcInstance and all L2PcInstance to inform (broadcast) setKarmaFlag(0); } - _karma = karma; + super.setKarma(karma); broadcastKarma(); } @@ -4520,6 +4509,10 @@ public final class L2PcInstance extends L2Playable { super.doAttack(target); setRecentFakeDeath(false); + if (target.isFakePlayer()) + { + updatePvPStatus(); + } } @Override @@ -5041,40 +5034,44 @@ 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); - - TvTEvent.onKill(killer, this); - - if (L2Event.isParticipant(pk)) + if (pk != null) { - pk.getEventStatus().getKills().add(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)) + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); + + TvTEvent.onKill(killer, this); + + if (L2Event.isParticipant(pk)) { - pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + pk.getEventStatus().getKills().add(this); } - // pk - if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) + + // pvp/pk item rewards + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) { - pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + // 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.S1); @@ -5088,7 +5085,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.S1); @@ -5102,6 +5099,11 @@ public final class L2PcInstance extends L2Playable } } + if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getKarma() <= 0)) + { + killer.setKarma(killer.getKarma() + 150); + killer.broadcastInfo(); + } } broadcastStatusUpdate(); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java index 659bcc561d..1a54bd4551 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java @@ -247,6 +247,7 @@ public final class L2TrapInstance extends L2Npc return null; } + @Override public int getKarma() { return _owner != null ? _owner.getKarma() : 0; diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java index 1b812dade3..da01dd3feb 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java @@ -22,7 +22,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.instancemanager.DuelManager; import com.l2jmobius.gameserver.model.actor.L2Character; -import com.l2jmobius.gameserver.model.actor.L2Playable; import com.l2jmobius.gameserver.model.actor.L2Summon; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.stat.PcStat; @@ -189,7 +188,7 @@ public class PcStatus extends PlayableStatus } } - if ((attacker instanceof L2Playable) && (caster.getCurrentCp() > 0)) + if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0)) { if (caster.getCurrentCp() > transferDmg) { @@ -211,7 +210,7 @@ public class PcStatus extends PlayableStatus } } - if (!ignoreCP && (attacker instanceof L2Playable)) + if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer())) { if (getCurrentCp() >= value) { diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java index fa623bcb3a..a6c9765ba1 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java @@ -74,6 +74,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable private boolean _undying; private boolean _showName; private boolean _flying; + private boolean _fakePlayer; + private boolean _fakePlayerTalkable; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; @@ -143,6 +145,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable _undying = set.getBoolean("undying", true); _showName = set.getBoolean("showName", 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); @@ -368,6 +372,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; diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java index 7e13569138..3948414a74 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java new file mode 100644 index 0000000000..3008d340b3 --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java new file mode 100644 index 0000000000..2f8aa1fa6d --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java index 1551a7aed9..662160a192 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -1001,7 +1001,7 @@ public final class Skill implements IIdentifiable public boolean checkCondition(L2Character activeChar, L2Object object, boolean itemOrWeapon) { - 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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java index add888a7dd..9bdc81404b 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java @@ -23,6 +23,7 @@ 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.AbstractNpcInfo; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; public class L2WaterZone extends L2ZoneType @@ -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)); } @@ -85,7 +90,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/Action.java index 51ca0ec1d2..d6c701ab5d 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/Action.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/Action.java @@ -141,7 +141,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java index 3b6f7193e8..eadf7843ca 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java @@ -27,6 +27,7 @@ import java.util.regex.PatternSyntaxException; 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; @@ -109,6 +110,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_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java index 61a1718fc8..d22e2c96bf 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java @@ -21,6 +21,7 @@ import java.util.List; import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.gameserver.enums.ChatType; +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; @@ -36,6 +37,22 @@ public final class CreatureSay implements IClientOutgoingPacket private int _npcString = -1; private List _parameters; + /** + * 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(); + _textType = messageType; + _charName = name; + _text = text; + } + /** * @param objectId * @param messageType diff --git a/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java new file mode 100644 index 0000000000..457565d61b --- /dev/null +++ b/L2J_Mobius_CT_2.6_HighFive/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java @@ -0,0 +1,220 @@ +/* + * 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 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.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 = (int) 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.writeD(_npc.getRace().ordinal()); + packet.writeD(_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()); + packet.writeD(0x00); // Inventory.PAPERDOLL_RBRACELET + packet.writeD(0x00); // Inventory.PAPERDOLL_LBRACELET + packet.writeD(0x00); // Inventory.PAPERDOLL_DECO1 + packet.writeD(0x00); // Inventory.PAPERDOLL_DECO2 + packet.writeD(0x00); // Inventory.PAPERDOLL_DECO3 + packet.writeD(0x00); // Inventory.PAPERDOLL_DECO4 + packet.writeD(0x00); // Inventory.PAPERDOLL_DECO5 + packet.writeD(0x00); // Inventory.PAPERDOLL_DECO6 + packet.writeD(0x00); // Inventory.PAPERDOLL_BELT + + for (int i = 0; i < 21; i++) + { + packet.writeD(0x00); + } + + packet.writeD(0x00); // getTalismanSlots + packet.writeD(0x01); // canEquipCloak + + packet.writeD(_npc.getScriptValue()); // getPvpFlag() + packet.writeD(_npc.getKarma()); + + packet.writeD(_mAtkSpd); + packet.writeD(_pAtkSpd); + + packet.writeD(0x00); // ? + + packet.writeD(_runSpd); + packet.writeD(_walkSpd); + packet.writeD(_swimRunSpd); + packet.writeD(_swimWalkSpd); + packet.writeD(_flyRunSpd); + packet.writeD(_flyWalkSpd); + packet.writeD(_flyRunSpd); + packet.writeD(_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); // isInPartyMatchRoom + + packet.writeD(_npc.getAbnormalVisualEffects()); + + packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0); + + packet.writeH(_fpcHolder.getRecommends()); // Blue value for name (0 = white, 255 = pure blue) + 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.writeD(_fpcHolder.getPledgeStatus()); + packet.writeD(0x00); // getPledgeType() + + packet.writeD(_fpcHolder.getTitleColor()); + + packet.writeD(0x00); // isCursedWeaponEquipped + + packet.writeD(0x00); // getClanId() > 0 ? getClan().getReputationScore() : 0 + + // T1 + packet.writeD(0x00); // getTransformationDisplayId() + packet.writeD(_fpcHolder.getAgathionId()); + + // T2 + packet.writeD(0x01); + + // T2.3 + packet.writeD(_npc.getAbnormalVisualEffectSpecial()); + return true; + } +} diff --git a/L2J_Mobius_CT_2.6_HighFive/readme.txt b/L2J_Mobius_CT_2.6_HighFive/readme.txt index 044732e46e..d552d42179 100644 --- a/L2J_Mobius_CT_2.6_HighFive/readme.txt +++ b/L2J_Mobius_CT_2.6_HighFive/readme.txt @@ -34,3 +34,4 @@ What is done -Sell buffs command -Dropped knownlists -Faction System (Good vs Evil) +-Fake players