From 749b2775a843e9b7085d1b5e66833efb95eb51f7 Mon Sep 17 00:00:00 2001 From: MobiusDev <8391001+MobiusDevelopment@users.noreply.github.com> Date: Sun, 26 Nov 2017 02:33:09 +0000 Subject: [PATCH] Addition of fake player system. --- .../dist/game/config/AdminCommands.xml | 3 + .../dist/game/config/Custom/FakePlayers.ini | 33 ++ .../dist/game/data/FakePlayerChatData.xml | 24 ++ .../dist/game/data/FakePlayerVisualData.xml | 37 ++ .../dist/game/data/Routes.xml | 39 ++ .../ai/areas/FairySettlement/Wisp.java | 2 +- .../FakePlayers/PvpFlaggingStopTask.java | 80 ++++ .../FakePlayers/RecieveAdventurerBuffs.java | 115 ++++++ .../data/scripts/handlers/MasterHandler.java | 2 + .../actionshifthandlers/L2NpcActionShift.java | 2 +- .../AdminFakePlayers.java | 77 ++++ .../admincommandhandlers/AdminReload.java | 23 ++ .../handlers/chathandlers/ChatWhisper.java | 24 ++ .../conditions/PlayerLevelCondition.java | 1 - .../handlers/playeractions/SocialAction.java | 32 +- .../Q10766_ANewCraft/Q10766_ANewCraft.java | 11 +- .../Q10767_AWholeNewLevelOfAlchemy.java | 11 +- .../game/data/spawns/Others/FakePlayers.xml | 8 + .../data/stats/npcs/custom/fpc_combat.xml | 341 ++++++++++++++++++ .../data/stats/npcs/custom/fpc_passive.xml | 26 ++ .../dist/game/data/xsd/FakePlayerChatData.xsd | 20 + .../game/data/xsd/FakePlayerVisualData.xsd | 45 +++ .../dist/game/data/xsd/npcs.xsd | 2 + .../java/com/l2jmobius/Config.java | 24 ++ .../com/l2jmobius/gameserver/GameServer.java | 4 + .../gameserver/ai/L2AttackableAI.java | 83 ++++- .../data/xml/impl/FakePlayerData.java | 125 +++++++ .../gameserver/data/xml/impl/NpcData.java | 2 + .../gameserver/data/xml/impl/SpawnsData.java | 5 + .../gameserver/datatables/BotReportTable.java | 20 +- .../gameserver/datatables/ItemTable.java | 5 +- .../gameserver/idfactory/IdFactory.java | 1 + .../FakePlayerChatManager.java | 196 ++++++++++ .../gameserver/model/DropProtection.java | 9 +- .../l2jmobius/gameserver/model/L2Object.java | 9 + .../gameserver/model/actor/L2Attackable.java | 47 ++- .../gameserver/model/actor/L2Character.java | 48 ++- .../gameserver/model/actor/L2Npc.java | 114 +++++- .../gameserver/model/actor/L2Playable.java | 2 - .../gameserver/model/actor/L2Summon.java | 8 +- .../actor/instance/DoppelgangerInstance.java | 4 +- .../model/actor/instance/L2GuardInstance.java | 9 +- .../actor/instance/L2MonsterInstance.java | 7 +- .../model/actor/instance/L2PcInstance.java | 84 +++-- .../model/actor/instance/L2TrapInstance.java | 3 +- .../model/actor/status/PcStatus.java | 6 +- .../model/actor/templates/L2NpcTemplate.java | 24 +- .../model/events/impl/item/OnItemCreate.java | 8 +- .../model/holders/FakePlayerChatHolder.java | 60 +++ .../model/holders/FakePlayerHolder.java | 232 ++++++++++++ .../model/items/instance/L2ItemInstance.java | 10 +- .../gameserver/model/skills/Skill.java | 2 +- .../gameserver/model/skills/SkillCaster.java | 36 +- .../model/zone/type/L2WaterZone.java | 13 +- .../network/clientpackets/Action.java | 2 +- .../clientpackets/CharacterCreate.java | 9 +- .../network/clientpackets/RequestBlock.java | 20 + .../RequestCharacterNameCreatable.java | 5 + .../clientpackets/RequestDuelStart.java | 58 ++- .../clientpackets/RequestJoinParty.java | 38 +- .../clientpackets/RequestJoinPledge.java | 37 ++ .../clientpackets/RequestSendPost.java | 9 + .../network/clientpackets/RequestVoteNew.java | 19 +- .../network/clientpackets/TradeRequest.java | 45 +++ .../friend/RequestFriendInvite.java | 30 ++ .../network/serverpackets/CreatureSay.java | 49 ++- .../network/serverpackets/FakePlayerInfo.java | 231 ++++++++++++ .../network/serverpackets/NpcInfo.java | 7 +- L2J_Mobius_1.0_Ertheia/readme.txt | 1 + .../dist/game/config/AdminCommands.xml | 3 + .../dist/game/config/Custom/FakePlayers.ini | 33 ++ .../dist/game/data/FakePlayerChatData.xml | 24 ++ .../dist/game/data/FakePlayerVisualData.xml | 37 ++ .../dist/game/data/Routes.xml | 39 ++ .../ai/areas/FairySettlement/Wisp.java | 2 +- .../FakePlayers/PvpFlaggingStopTask.java | 80 ++++ .../FakePlayers/RecieveAdventurerBuffs.java | 115 ++++++ .../data/scripts/handlers/MasterHandler.java | 2 + .../actionshifthandlers/L2NpcActionShift.java | 2 +- .../AdminFakePlayers.java | 77 ++++ .../admincommandhandlers/AdminReload.java | 23 ++ .../handlers/chathandlers/ChatWhisper.java | 24 ++ .../conditions/PlayerLevelCondition.java | 1 - .../handlers/playeractions/SocialAction.java | 32 +- .../Q10766_ANewCraft/Q10766_ANewCraft.java | 11 +- .../Q10767_AWholeNewLevelOfAlchemy.java | 11 +- .../game/data/spawns/Others/FakePlayers.xml | 8 + .../data/stats/npcs/custom/fpc_combat.xml | 341 ++++++++++++++++++ .../data/stats/npcs/custom/fpc_passive.xml | 26 ++ .../dist/game/data/xsd/FakePlayerChatData.xsd | 20 + .../game/data/xsd/FakePlayerVisualData.xsd | 45 +++ .../dist/game/data/xsd/npcs.xsd | 2 + .../java/com/l2jmobius/Config.java | 24 ++ .../com/l2jmobius/gameserver/GameServer.java | 4 + .../gameserver/ai/L2AttackableAI.java | 83 ++++- .../data/xml/impl/FakePlayerData.java | 125 +++++++ .../gameserver/data/xml/impl/NpcData.java | 2 + .../gameserver/data/xml/impl/SpawnsData.java | 5 + .../gameserver/datatables/BotReportTable.java | 20 +- .../gameserver/datatables/ItemTable.java | 5 +- .../gameserver/idfactory/IdFactory.java | 1 + .../FakePlayerChatManager.java | 196 ++++++++++ .../gameserver/model/DropProtection.java | 9 +- .../l2jmobius/gameserver/model/L2Object.java | 9 + .../gameserver/model/actor/L2Attackable.java | 47 ++- .../gameserver/model/actor/L2Character.java | 48 ++- .../gameserver/model/actor/L2Npc.java | 155 ++++++-- .../gameserver/model/actor/L2Playable.java | 2 - .../gameserver/model/actor/L2Summon.java | 8 +- .../actor/instance/DoppelgangerInstance.java | 4 +- .../model/actor/instance/L2GuardInstance.java | 9 +- .../actor/instance/L2MonsterInstance.java | 7 +- .../model/actor/instance/L2PcInstance.java | 84 +++-- .../model/actor/instance/L2TrapInstance.java | 3 +- .../model/actor/status/PcStatus.java | 6 +- .../model/actor/templates/L2NpcTemplate.java | 24 +- .../model/events/impl/item/OnItemCreate.java | 8 +- .../model/holders/FakePlayerChatHolder.java | 60 +++ .../model/holders/FakePlayerHolder.java | 232 ++++++++++++ .../model/items/instance/L2ItemInstance.java | 10 +- .../gameserver/model/skills/Skill.java | 2 +- .../gameserver/model/skills/SkillCaster.java | 36 +- .../model/zone/type/L2WaterZone.java | 13 +- .../network/clientpackets/Action.java | 2 +- .../clientpackets/CharacterCreate.java | 9 +- .../network/clientpackets/RequestBlock.java | 20 + .../RequestCharacterNameCreatable.java | 5 + .../clientpackets/RequestDuelStart.java | 58 ++- .../clientpackets/RequestJoinParty.java | 38 +- .../clientpackets/RequestJoinPledge.java | 37 ++ .../clientpackets/RequestSendPost.java | 9 + .../network/clientpackets/RequestVoteNew.java | 19 +- .../network/clientpackets/TradeRequest.java | 45 +++ .../friend/RequestFriendInvite.java | 30 ++ .../network/serverpackets/CreatureSay.java | 49 ++- .../network/serverpackets/FakePlayerInfo.java | 231 ++++++++++++ .../network/serverpackets/NpcInfo.java | 7 +- L2J_Mobius_2.5_Underground/readme.txt | 1 + .../dist/game/config/AdminCommands.xml | 3 + .../dist/game/config/Custom/FakePlayers.ini | 33 ++ .../dist/game/data/FakePlayerChatData.xml | 24 ++ .../dist/game/data/FakePlayerVisualData.xml | 37 ++ .../dist/game/data/Routes.xml | 40 ++ .../ai/areas/FairySettlement/Wisp.java | 2 +- .../FakePlayers/PvpFlaggingStopTask.java | 80 ++++ .../FakePlayers/RecieveAdventurerBuffs.java | 115 ++++++ .../data/scripts/handlers/MasterHandler.java | 2 + .../actionshifthandlers/L2NpcActionShift.java | 2 +- .../AdminFakePlayers.java | 77 ++++ .../admincommandhandlers/AdminReload.java | 23 ++ .../handlers/chathandlers/ChatWhisper.java | 24 ++ .../conditions/PlayerLevelCondition.java | 1 - .../handlers/playeractions/SocialAction.java | 32 +- .../Q10766_ANewCraft/Q10766_ANewCraft.java | 11 +- .../Q10767_AWholeNewLevelOfAlchemy.java | 11 +- .../game/data/spawns/Others/FakePlayers.xml | 8 + .../data/stats/npcs/custom/fpc_combat.xml | 341 ++++++++++++++++++ .../data/stats/npcs/custom/fpc_passive.xml | 26 ++ .../dist/game/data/xsd/FakePlayerChatData.xsd | 20 + .../game/data/xsd/FakePlayerVisualData.xsd | 45 +++ .../dist/game/data/xsd/npcs.xsd | 2 + .../java/com/l2jmobius/Config.java | 24 ++ .../com/l2jmobius/gameserver/GameServer.java | 4 + .../gameserver/ai/L2AttackableAI.java | 83 ++++- .../data/xml/impl/FakePlayerData.java | 125 +++++++ .../gameserver/data/xml/impl/NpcData.java | 2 + .../gameserver/data/xml/impl/SpawnsData.java | 5 + .../gameserver/datatables/BotReportTable.java | 20 +- .../gameserver/datatables/ItemTable.java | 5 +- .../gameserver/idfactory/IdFactory.java | 1 + .../FakePlayerChatManager.java | 196 ++++++++++ .../gameserver/model/DropProtection.java | 9 +- .../l2jmobius/gameserver/model/L2Object.java | 9 + .../gameserver/model/actor/L2Attackable.java | 47 ++- .../gameserver/model/actor/L2Character.java | 48 ++- .../gameserver/model/actor/L2Npc.java | 155 ++++++-- .../gameserver/model/actor/L2Playable.java | 2 - .../gameserver/model/actor/L2Summon.java | 8 +- .../actor/instance/DoppelgangerInstance.java | 4 +- .../model/actor/instance/L2GuardInstance.java | 9 +- .../actor/instance/L2MonsterInstance.java | 7 +- .../model/actor/instance/L2PcInstance.java | 84 +++-- .../model/actor/instance/L2TrapInstance.java | 3 +- .../model/actor/status/PcStatus.java | 6 +- .../model/actor/templates/L2NpcTemplate.java | 24 +- .../model/events/impl/item/OnItemCreate.java | 8 +- .../model/holders/FakePlayerChatHolder.java | 60 +++ .../model/holders/FakePlayerHolder.java | 232 ++++++++++++ .../model/items/instance/L2ItemInstance.java | 10 +- .../gameserver/model/skills/Skill.java | 2 +- .../gameserver/model/skills/SkillCaster.java | 36 +- .../model/zone/type/L2WaterZone.java | 13 +- .../network/clientpackets/Action.java | 2 +- .../clientpackets/CharacterCreate.java | 9 +- .../network/clientpackets/RequestBlock.java | 20 + .../RequestCharacterNameCreatable.java | 5 + .../clientpackets/RequestDuelStart.java | 58 ++- .../clientpackets/RequestJoinParty.java | 38 +- .../clientpackets/RequestJoinPledge.java | 37 ++ .../clientpackets/RequestSendPost.java | 9 + .../network/clientpackets/RequestVoteNew.java | 19 +- .../network/clientpackets/TradeRequest.java | 45 +++ .../friend/RequestFriendInvite.java | 30 ++ .../network/serverpackets/CreatureSay.java | 49 ++- .../network/serverpackets/FakePlayerInfo.java | 231 ++++++++++++ .../network/serverpackets/NpcInfo.java | 7 +- L2J_Mobius_3.0_Helios/readme.txt | 1 + .../dist/game/config/AdminCommands.xml | 3 + .../dist/game/config/Custom/FakePlayers.ini | 33 ++ .../dist/game/data/FakePlayerChatData.xml | 24 ++ .../dist/game/data/FakePlayerVisualData.xml | 37 ++ .../dist/game/data/Routes.xml | 41 +++ .../ai/areas/FairySettlement/Wisp.java | 2 +- .../FakePlayers/PvpFlaggingStopTask.java | 80 ++++ .../FakePlayers/RecieveAdventurerBuffs.java | 115 ++++++ .../data/scripts/handlers/MasterHandler.java | 2 + .../actionshifthandlers/L2NpcActionShift.java | 2 +- .../AdminFakePlayers.java | 77 ++++ .../admincommandhandlers/AdminReload.java | 23 ++ .../handlers/chathandlers/ChatWhisper.java | 24 ++ .../conditions/PlayerLevelCondition.java | 1 - .../handlers/playeractions/SocialAction.java | 32 +- .../Q10766_ANewCraft/Q10766_ANewCraft.java | 11 +- .../Q10767_AWholeNewLevelOfAlchemy.java | 11 +- .../game/data/spawns/Others/FakePlayers.xml | 8 + .../data/stats/npcs/custom/fpc_combat.xml | 341 ++++++++++++++++++ .../data/stats/npcs/custom/fpc_passive.xml | 26 ++ .../dist/game/data/xsd/FakePlayerChatData.xsd | 20 + .../game/data/xsd/FakePlayerVisualData.xsd | 45 +++ .../dist/game/data/xsd/npcs.xsd | 2 + .../java/com/l2jmobius/Config.java | 24 ++ .../com/l2jmobius/gameserver/GameServer.java | 4 + .../gameserver/ai/L2AttackableAI.java | 83 ++++- .../data/xml/impl/FakePlayerData.java | 125 +++++++ .../gameserver/data/xml/impl/NpcData.java | 2 + .../gameserver/data/xml/impl/SpawnsData.java | 5 + .../gameserver/datatables/BotReportTable.java | 20 +- .../gameserver/datatables/ItemTable.java | 5 +- .../gameserver/idfactory/IdFactory.java | 1 + .../FakePlayerChatManager.java | 196 ++++++++++ .../gameserver/model/DropProtection.java | 9 +- .../l2jmobius/gameserver/model/L2Object.java | 9 + .../gameserver/model/actor/L2Attackable.java | 47 ++- .../gameserver/model/actor/L2Character.java | 48 ++- .../gameserver/model/actor/L2Npc.java | 155 ++++++-- .../gameserver/model/actor/L2Playable.java | 2 - .../gameserver/model/actor/L2Summon.java | 8 +- .../actor/instance/DoppelgangerInstance.java | 4 +- .../model/actor/instance/L2GuardInstance.java | 9 +- .../actor/instance/L2MonsterInstance.java | 7 +- .../model/actor/instance/L2PcInstance.java | 84 +++-- .../model/actor/instance/L2TrapInstance.java | 3 +- .../model/actor/status/PcStatus.java | 6 +- .../model/actor/templates/L2NpcTemplate.java | 24 +- .../model/events/impl/item/OnItemCreate.java | 8 +- .../model/holders/FakePlayerChatHolder.java | 60 +++ .../model/holders/FakePlayerHolder.java | 232 ++++++++++++ .../model/items/instance/L2ItemInstance.java | 10 +- .../gameserver/model/skills/Skill.java | 2 +- .../gameserver/model/skills/SkillCaster.java | 36 +- .../model/zone/type/L2WaterZone.java | 13 +- .../network/clientpackets/Action.java | 2 +- .../clientpackets/CharacterCreate.java | 9 +- .../network/clientpackets/RequestBlock.java | 20 + .../RequestCharacterNameCreatable.java | 5 + .../clientpackets/RequestDuelStart.java | 58 ++- .../clientpackets/RequestJoinParty.java | 38 +- .../clientpackets/RequestJoinPledge.java | 37 ++ .../clientpackets/RequestSendPost.java | 9 + .../network/clientpackets/RequestVoteNew.java | 19 +- .../network/clientpackets/TradeRequest.java | 45 +++ .../friend/RequestFriendInvite.java | 30 ++ .../network/serverpackets/CreatureSay.java | 49 ++- .../network/serverpackets/FakePlayerInfo.java | 232 ++++++++++++ .../network/serverpackets/NpcInfo.java | 7 +- L2J_Mobius_4.0_GrandCrusade/readme.txt | 1 + .../dist/game/config/AdminCommands.xml | 3 + .../dist/game/config/Custom/FakePlayers.ini | 33 ++ .../dist/game/data/FakePlayerChatData.xml | 24 ++ .../dist/game/data/FakePlayerVisualData.xml | 9 + .../dist/game/data/Routes.xml | 33 ++ .../FakePlayers/PvpFlaggingStopTask.java | 80 ++++ .../data/scripts/handlers/MasterHandler.java | 2 + .../actionshifthandlers/L2NpcActionShift.java | 2 +- .../AdminFakePlayers.java | 77 ++++ .../admincommandhandlers/AdminReload.java | 23 ++ .../handlers/chathandlers/ChatWhisper.java | 24 ++ .../conditions/PlayerLevelCondition.java | 1 - .../handlers/playeractions/SocialAction.java | 32 +- .../game/data/spawns/Others/FakePlayers.xml | 8 + .../data/stats/npcs/custom/fpc_passive.xml | 26 ++ .../dist/game/data/xsd/FakePlayerChatData.xsd | 20 + .../game/data/xsd/FakePlayerVisualData.xsd | 45 +++ .../dist/game/data/xsd/npcs.xsd | 2 + .../java/com/l2jmobius/Config.java | 24 ++ .../com/l2jmobius/gameserver/GameServer.java | 4 + .../gameserver/ai/L2AttackableAI.java | 83 ++++- .../data/xml/impl/FakePlayerData.java | 125 +++++++ .../gameserver/data/xml/impl/NpcData.java | 2 + .../gameserver/data/xml/impl/SpawnsData.java | 5 + .../gameserver/datatables/BotReportTable.java | 20 +- .../gameserver/datatables/ItemTable.java | 5 +- .../gameserver/idfactory/IdFactory.java | 1 + .../FakePlayerChatManager.java | 196 ++++++++++ .../gameserver/model/DropProtection.java | 9 +- .../l2jmobius/gameserver/model/L2Object.java | 9 + .../gameserver/model/actor/L2Attackable.java | 47 ++- .../gameserver/model/actor/L2Character.java | 48 ++- .../gameserver/model/actor/L2Npc.java | 155 ++++++-- .../gameserver/model/actor/L2Playable.java | 2 - .../gameserver/model/actor/L2Summon.java | 8 +- .../actor/instance/DoppelgangerInstance.java | 4 +- .../model/actor/instance/L2GuardInstance.java | 9 +- .../actor/instance/L2MonsterInstance.java | 7 +- .../model/actor/instance/L2PcInstance.java | 84 +++-- .../model/actor/instance/L2TrapInstance.java | 3 +- .../model/actor/status/PcStatus.java | 6 +- .../model/actor/templates/L2NpcTemplate.java | 22 +- .../model/events/impl/item/OnItemCreate.java | 8 +- .../model/holders/FakePlayerChatHolder.java | 60 +++ .../model/holders/FakePlayerHolder.java | 232 ++++++++++++ .../model/items/instance/L2ItemInstance.java | 10 +- .../gameserver/model/skills/Skill.java | 2 +- .../gameserver/model/skills/SkillCaster.java | 36 +- .../model/zone/type/L2WaterZone.java | 13 +- .../network/clientpackets/Action.java | 2 +- .../clientpackets/CharacterCreate.java | 9 +- .../network/clientpackets/RequestBlock.java | 20 + .../RequestCharacterNameCreatable.java | 5 + .../clientpackets/RequestDuelStart.java | 58 ++- .../clientpackets/RequestJoinParty.java | 38 +- .../clientpackets/RequestJoinPledge.java | 37 ++ .../clientpackets/RequestSendPost.java | 9 + .../network/clientpackets/RequestVoteNew.java | 19 +- .../network/clientpackets/TradeRequest.java | 45 +++ .../friend/RequestFriendInvite.java | 30 ++ .../network/serverpackets/CreatureSay.java | 49 ++- .../network/serverpackets/FakePlayerInfo.java | 231 ++++++++++++ .../network/serverpackets/NpcInfo.java | 7 +- 339 files changed, 12524 insertions(+), 717 deletions(-) create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd create mode 100644 L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd create mode 100644 L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java create mode 100644 L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java create mode 100644 L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java create mode 100644 L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java create mode 100644 L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd create mode 100644 L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd create mode 100644 L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java create mode 100644 L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java create mode 100644 L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java create mode 100644 L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java create mode 100644 L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd create mode 100644 L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd create mode 100644 L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java create mode 100644 L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java create mode 100644 L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java create mode 100644 L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java create mode 100644 L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd create mode 100644 L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd create mode 100644 L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java create mode 100644 L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd create mode 100644 L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd create mode 100644 L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java create mode 100644 L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml b/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml index 171e08cb12..f9067f1377 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/config/AdminCommands.xml @@ -392,6 +392,9 @@ + + + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini new file mode 100644 index 0000000000..f745b0d31e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/config/Custom/FakePlayers.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------------------- +# Fake players +# --------------------------------------------------------------------------- + +# Enable fake players. +EnableFakePlayers = False + +# Enable chatting with fake players. +FakePlayerChat = True + +# Enable shots usage for fake players. +FakePlayerUseShots = True + +# Reward PvP kills by killing fake players. +FakePlayerKillsRewardPvP = True + +# Fake player kills apply karma rules. +FakePlayerUnflaggedKillsKarma = True + +# Aggressive AI fake players attack nearby monsters. +FakePlayerAggroMonsters = True + +# Aggressive AI fake players attack nearby players. +FakePlayerAggroPlayers = False + +# Aggressive AI fake players attack nearby fake players. +FakePlayerAggroFPC = False + +# Fake players can drop items when killing monsters. +FakePlayerCanDropItems = True + +# Fake players can pickup dropped items. +FakePlayerCanPickup = True diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml new file mode 100644 index 0000000000..f5da5bfc8e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerChatData.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml new file mode 100644 index 0000000000..f36096ed4a --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/FakePlayerVisualData.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml index 98e0d38815..96e8e6ed81 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/Routes.xml @@ -2402,4 +2402,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java index 6f29855cc3..d12ee2e7c4 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java @@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI final L2Character creature = event.getSeen(); final L2Npc npc = (L2Npc) event.getSeer(); - if (creature.isPlayer()) + if (creature.isPlayer() || creature.isFakePlayer()) { npc.setTarget(creature); npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill()); diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java new file mode 100644 index 0000000000..e1dde7324e --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java @@ -0,0 +1,80 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +import ai.AbstractNpcAI; + +/** + * TODO: Move it to L2Character. + * @author Mobius + */ +public class PvpFlaggingStopTask extends AbstractNpcAI +{ + private PvpFlaggingStopTask() + { + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if ((npc == null) || npc.isDead()) + { + return null; + } + + if (event.startsWith("FLAG_CHECK")) + { + final L2Object target = npc.getTarget(); + if ((target != null) && (target.isPlayable() || target.isFakePlayer())) + { + npc.setScriptValue(1); // in combat + cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null); + cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null); + startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null); + startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null); + } + } + else if (event.startsWith("FINISH_FLAG")) + { + if (npc.isScriptValue(1)) + { + npc.setScriptValue(2); // blink status + npc.broadcastInfo(); // update flag status + startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null); + } + } + else if (event.startsWith("REMOVE_FLAG")) + { + if (npc.isScriptValue(2)) + { + npc.setScriptValue(0); // not in combat + npc.broadcastInfo(); // update flag status + } + } + return super.onAdvEvent(event, npc, player); + } + + public static void main(String[] args) + { + new PvpFlaggingStopTask(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java new file mode 100644 index 0000000000..dec3449549 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java @@ -0,0 +1,115 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.CommonUtil; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.base.ClassId; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.SkillCaster; + +import ai.AbstractNpcAI; + +/** + * Town Fake Player walkers that receive buffs from Adventurer NPC. + * @author Mobius + */ +public class RecieveAdventurerBuffs extends AbstractNpcAI +{ + // NPCs + private static final int[] ADVENTURERS_GUIDE = + { + 32327, + 33950, + }; + private static final int[] FAKE_PLAYER_IDS = + { + 80000 + }; + // Skills + // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer) + private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer) + private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer) + private static final SkillHolder[] GROUP_BUFFS = + { + new SkillHolder(15642, 1), // Horn Melody (Adventurer) + new SkillHolder(15643, 1), // Drum Melody (Adventurer) + new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer) + new SkillHolder(15645, 1), // Guitar Melody (Adventurer) + new SkillHolder(15646, 1), // Harp Melody (Adventurer) + new SkillHolder(15647, 1), // Lute Melody (Adventurer) + new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer) + new SkillHolder(15652, 1), // Daring Sonata (Adventurer) + new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer) + }; + + private RecieveAdventurerBuffs() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + addSpawnId(FAKE_PLAYER_IDS); + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead()) + { + if (!npc.isMoving()) + { + for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100)) + { + if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId())) + { + for (SkillHolder holder : GROUP_BUFFS) + { + SkillCaster.triggerCast(nearby, npc, holder.getSkill()); + } + if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage()) + { + SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill()); + } + else + { + SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill()); + } + break; + } + } + } + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSpawn(L2Npc npc) + { + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new RecieveAdventurerBuffs(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java index 666585bcab..ec9218857e 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/MasterHandler.java @@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant; import handlers.admincommandhandlers.AdminEventEngine; import handlers.admincommandhandlers.AdminEvents; import handlers.admincommandhandlers.AdminExpSp; +import handlers.admincommandhandlers.AdminFakePlayers; import handlers.admincommandhandlers.AdminFightCalculator; import handlers.admincommandhandlers.AdminFortSiege; import handlers.admincommandhandlers.AdminGeodata; @@ -408,6 +409,7 @@ public class MasterHandler AdminEventEngine.class, AdminEvents.class, AdminExpSp.class, + AdminFakePlayers.class, AdminFightCalculator.class, AdminFortSiege.class, AdminGeodata.class, diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java index 6b02816d9e..d6d6a99080 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java @@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler } else if (Config.ALT_GAME_VIEWNPC) { - if (!target.isNpc()) + if (!target.isNpc() || target.isFakePlayer()) { return false; } diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java new file mode 100644 index 0000000000..99926f0df7 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java @@ -0,0 +1,77 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package handlers.admincommandhandlers; + +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.handler.IAdminCommandHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +/** + * @author Mobius + */ +public class AdminFakePlayers implements IAdminCommandHandler +{ + private static final String[] ADMIN_COMMANDS = + { + "admin_fakechat" + }; + + @Override + public boolean useAdminCommand(String command, L2PcInstance activeChar) + { + if (command.startsWith("admin_fakechat")) + { + final String[] words = command.substring(15).split(" "); + if (words.length < 3) + { + activeChar.sendMessage("Usage: //fakechat playername fpcname message"); + return false; + } + final L2PcInstance player = L2World.getInstance().getPlayer(words[0]); + if (player == null) + { + activeChar.sendMessage("Player not found."); + return false; + } + final String fpcName = FakePlayerData.getInstance().getProperName(words[1]); + if (fpcName == null) + { + activeChar.sendMessage("Fake player not found."); + return false; + } + String message = ""; + for (int i = 0; i < words.length; i++) + { + if (i < 2) + { + continue; + } + message += (words[i] + " "); + } + FakePlayerChatManager.getInstance().sendChat(player, fpcName, message); + } + return true; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 5da8e115b2..4799a7aa53 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData; import com.l2jmobius.gameserver.data.xml.impl.DoorData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData; import com.l2jmobius.gameserver.data.xml.impl.MultisellData; @@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.WalkingManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.util.Util; @@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data."); break; } + case "fakeplayers": + { + FakePlayerData.getInstance().load(); + for (L2Object obj : L2World.getInstance().getVisibleObjects()) + { + if (obj.isFakePlayer()) + { + obj.broadcastInfo(); + } + } + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data."); + break; + } + case "fakeplayerchat": + { + FakePlayerChatManager.getInstance().load(); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data."); + break; + } default: { activeChar.sendMessage(RELOAD_USAGE); diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java index 99f2e9e9d7..7db79fe31d 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java @@ -17,8 +17,10 @@ package handlers.chathandlers; import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.handler.IChatHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.PcCondOverride; @@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler return; } + if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null)) + { + if (FakePlayerData.getInstance().isTalkable(target)) + { + if (Config.FAKE_PLAYER_CHAT) + { + final String name = FakePlayerData.getInstance().getProperName(target); + activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text)); + FakePlayerChatManager.getInstance().manageChat(activeChar, name, text); + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE); + } + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE); + } + return; + } + final L2PcInstance receiver = L2World.getInstance().getPlayer(target); if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId())) diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java index 41b1f99bcf..b38f5ca16d 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java @@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition { return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel); } - } diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java index 1e34a0d148..087112cc73 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/handlers/playeractions/SocialAction.java @@ -16,9 +16,11 @@ */ package handlers.playeractions; +import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.NextAction; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.handler.IPlayerActionHandler; import com.l2jmobius.gameserver.model.ActionDataHolder; import com.l2jmobius.gameserver.model.L2Object; @@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED); + player.onTransactionResponse(); + } + } + private void useCoupleSocial(L2PcInstance player, int id) { if (player == null) @@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler } final L2Object target = player.getTarget(); - if ((target == null) || !target.isPlayer()) + if ((target == null)) + { + player.sendPacket(SystemMessageId.INVALID_TARGET); + return; + } + + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1); + sm.addString(target.getName()); + player.sendPacket(sm); + if (!player.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000); + player.blockRequest(); + } + return; + } + + if (!target.isPlayer()) { player.sendPacket(SystemMessageId.INVALID_TARGET); return; diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java index b79fe7475a..5e1b48e51b 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java @@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest @Id(WINDY_HEALING_POTION_1) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(4, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + { + qs.setCond(4, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java index 0efb5383f4..34594dbc40 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java @@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest @Id(HIGH_GRADE_LOVE_POTION) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(2, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + { + qs.setCond(2, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml new file mode 100644 index 0000000000..ea77878c2c --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/spawns/Others/FakePlayers.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml new file mode 100644 index 0000000000..8470293122 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_combat.xml @@ -0,0 +1,341 @@ + + + + + HUMAN + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + ORC + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + DWARF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + KAMAEL + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + HUMAN + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + DARK_ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml new file mode 100644 index 0000000000..589f29b215 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/stats/npcs/custom/fpc_passive.xml @@ -0,0 +1,26 @@ + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd new file mode 100644 index 0000000000..2b2c94e75b --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerChatData.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd new file mode 100644 index 0000000000..0628acefc3 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/FakePlayerVisualData.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd index 6f00944cff..ae80c3ff63 100644 --- a/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd +++ b/L2J_Mobius_1.0_Ertheia/dist/game/data/xsd/npcs.xsd @@ -201,6 +201,8 @@ + + diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java index dd62606fa2..c4ea987b4d 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/Config.java @@ -116,6 +116,7 @@ public final class Config public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini"; public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini"; public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini"; + public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini"; public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini"; public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini"; public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini"; @@ -1146,6 +1147,16 @@ public final class Config public static boolean FACTION_SPECIFIC_CHAT; public static boolean FACTION_BALANCE_ONLINE_PLAYERS; public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT; + public static boolean FAKE_PLAYERS_ENABLED; + public static boolean FAKE_PLAYER_CHAT; + public static boolean FAKE_PLAYER_USE_SHOTS; + public static boolean FAKE_PLAYER_KILL_PVP; + public static boolean FAKE_PLAYER_KILL_KARMA; + public static boolean FAKE_PLAYER_AGGRO_MONSTERS; + public static boolean FAKE_PLAYER_AGGRO_PLAYERS; + public static boolean FAKE_PLAYER_AGGRO_FPC; + public static boolean FAKE_PLAYER_CAN_DROP_ITEMS; + public static boolean FAKE_PLAYER_CAN_PICKUP; public static boolean ENABLE_FIND_PVP; public static boolean PREMIUM_SYSTEM_ENABLED; public static float PREMIUM_RATE_XP; @@ -2558,6 +2569,19 @@ public final class Config FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true); FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20); + // Load FakePlayers config file (if exists) + final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE); + FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false)); + FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false)); + FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false)); + FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false)); + FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false)); + FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false)); + FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false)); + FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false)); + FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false)); + FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false)); + // Load FindPvP config file (if exists) final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE); ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java index 8fbd70bb6f..e2d108f174 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/GameServer.java @@ -60,6 +60,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnchantSkillGroupsData; import com.l2jmobius.gameserver.data.xml.impl.EventEngineData; import com.l2jmobius.gameserver.data.xml.impl.ExperienceData; import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.HennaData; import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData; @@ -109,6 +110,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; import com.l2jmobius.gameserver.instancemanager.DBSpawnManager; import com.l2jmobius.gameserver.instancemanager.FactionManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.FortManager; import com.l2jmobius.gameserver.instancemanager.FortSiegeManager; import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; @@ -282,6 +284,8 @@ public class GameServer printSection("NPCs"); SkillLearnData.getInstance(); NpcData.getInstance(); + FakePlayerData.getInstance(); + FakePlayerChatManager.getInstance(); ExtendDropData.getInstance(); SpawnsData.getInstance(); WalkingManager.getInstance(); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 6253fa9329..1da1b21546 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.model.AggroInfo; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate; import com.l2jmobius.gameserver.model.events.returns.TerminateReturn; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.skills.SkillCaster; @@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10 if (_globalAggro >= 0) { - if (npc.isAggressive() || (npc instanceof L2GuardInstance)) + if (npc.isFakePlayer() && npc.isAggressive()) + { + final List droppedItems = npc.getFakePlayerDrops(); + if (droppedItems.isEmpty()) + { + L2Character nearestTarget = null; + double closestDistance = Double.MAX_VALUE; + for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange())) + { + if ((t == _actor) || (t == null) || t.isDead()) + { + continue; + } + if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer())) + { + final int hating = npc.getHating(t); + final double distance = npc.calculateDistance(t, false, false); + if ((hating == 0) && (closestDistance > distance)) + { + nearestTarget = t; + closestDistance = distance; + } + } + } + if (nearestTarget != null) + { + npc.addDamageHate(nearestTarget, 0, 1); + } + } + else if (!npc.isInCombat()) // must pickup items + { + final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped + final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex); + if ((droppedItem != null) && droppedItem.isSpawned()) + { + if (npc.calculateDistance(droppedItem, false, false) > 50) + { + moveTo(droppedItem); + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + droppedItem.pickupMe(npc); + if (Config.SAVE_DROPPED_ITEM) + { + ItemsOnGroundManager.getInstance().removeObject(droppedItem); + } + if (droppedItem.getItem().hasExImmediateEffect()) + { + for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills()) + { + SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false); + } + npc.broadcastInfo(); // ? check if this is necessary + } + } + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + } + npc.setRunning(); + } + } + else if (npc.isAggressive() || (npc instanceof L2GuardInstance)) { final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players. L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t -> @@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // For each L2Character check if the target is autoattackable if (isAggressiveTowards(t)) // check aggression { - if (t.isPlayable()) + if (t.isFakePlayer()) + { + if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC)) + { + final int hating = npc.getHating(t); + if (hating == 0) + { + npc.addDamageHate(t, 0, 1); + } + } + } + else if (t.isPlayable()) { final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class); if ((term != null) && term.terminate()) diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java new file mode 100644 index 0000000000..0a6ca5267a --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java @@ -0,0 +1,125 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; + +/** + * @author Mobius + */ +public class FakePlayerData implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName()); + + private final Map _fakePlayerInfos = new HashMap<>(); + private final Map _fakePlayerNames = new HashMap<>(); + private final Map _fakePlayerIds = new HashMap<>(); + private final List _talkableFakePlayerNames = new ArrayList<>(); + + protected FakePlayerData() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + _fakePlayerInfos.clear(); + _fakePlayerNames.clear(); + _fakePlayerIds.clear(); + _talkableFakePlayerNames.clear(); + parseDatapackFile("data/FakePlayerVisualData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode)); + final int npcId = set.getInt("npcId"); + final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId); + final String name = template.getName(); + if (CharNameTable.getInstance().getIdByName(name) > 0) + { + LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists."); + } + else + { + _fakePlayerIds.put(name, npcId); // name - npcId + _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name + _fakePlayerInfos.put(npcId, new FakePlayerHolder(set)); + if (template.isFakePlayerTalkable()) + { + _talkableFakePlayerNames.add(name.toLowerCase()); + } + } + })); + } + + public int getNpcIdByName(String name) + { + return _fakePlayerIds.get(name); + } + + public String getProperName(String name) + { + return _fakePlayerNames.get(name.toLowerCase()); + } + + public Boolean isTalkable(String name) + { + return _talkableFakePlayerNames.contains(name.toLowerCase()); + } + + public FakePlayerHolder getInfo(int npcId) + { + return _fakePlayerInfos.get(npcId); + } + + public static FakePlayerData getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerData _instance = new FakePlayerData(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java index 883e877bc7..f03a2395f1 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java @@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader set.set("hasSummoner", parseBoolean(attrs, "hasSummoner")); set.set("canBeSown", parseBoolean(attrs, "canBeSown")); set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty")); + set.set("fakePlayer", parseBoolean(attrs, "fakePlayer")); + set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable")); break; } case "skill_list": diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java index 2ff4c9322d..15bd310bd6 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java @@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader return; } + if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer()) + { + return; + } + for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) { if ("parameters".equalsIgnoreCase(d.getNodeName())) diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java index a145b65dba..d525c02a6a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/BotReportTable.java @@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.zone.ZoneId; @@ -210,15 +212,14 @@ public final class BotReportTable public boolean reportBot(L2PcInstance reporter) { final L2Object target = reporter.getTarget(); - if (target == null) { return false; } - final L2PcInstance bot = target.getActingPlayer(); + final L2Character bot = ((L2Character) target); - if ((bot == null) || (target.getObjectId() == reporter.getObjectId())) + if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId())) { return false; } @@ -229,7 +230,7 @@ public final class BotReportTable return false; } - if (bot.isInOlympiadMode()) + if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode()) { reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD); return false; @@ -241,7 +242,7 @@ public final class BotReportTable return false; } - if (bot.getExp() == bot.getStat().getStartingExp()) + if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp())) { reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING); return false; @@ -320,15 +321,18 @@ public final class BotReportTable } SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT); - sm.addCharName(bot); + sm.addString(bot.getName()); reporter.sendPacket(sm); sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT); - sm.addCharName(bot); + sm.addString(bot.getName()); sm.addInt(rcdRep.getPointsLeft()); reporter.sendPacket(sm); - handleReport(bot, rcd); + if (bot.isPlayer()) + { + handleReport(bot.getActingPlayer(), rcd); + } return true; } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java index 7454554076..ace19486b5 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/datatables/ItemTable.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -202,11 +203,11 @@ public class ItemTable * @param process : String Identifier of process triggering this action * @param itemId : int Item Identifier of the item to be created * @param count : int Quantity of items to be created for stackable items - * @param actor : L2PcInstance Player requesting the item creation + * @param actor : L2Character requesting the item creation * @param reference : Object Object referencing current action like NPC selling item or previous item in transformation * @return L2ItemInstance corresponding to the new item */ - public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference) + public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference) { // Create and Init the L2ItemInstance corresponding to the Item Identifier final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java index b621b4c4cb..bb0e928daf 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/idfactory/IdFactory.java @@ -217,6 +217,7 @@ public abstract class IdFactory cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); + cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); // If the clan does not exist... cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java new file mode 100644 index 0000000000..16a0da92bc --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java @@ -0,0 +1,196 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.instancemanager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2Spawn; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder; +import com.l2jmobius.gameserver.network.serverpackets.CreatureSay; + +/** + * @author Mobius + */ +public final class FakePlayerChatManager implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName()); + final List MESSAGES = new ArrayList<>(); + private static final int MIN_DELAY = 5000; + private static final int MAX_DELAY = 15000; + + protected FakePlayerChatManager() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT) + { + MESSAGES.clear(); + parseDatapackFile("data/FakePlayerChatData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode)); + MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers"))); + })); + } + + public void manageChat(L2PcInstance player, String fpcName, String message) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY)); + } + + public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay)); + } + + private void manageResponce(L2PcInstance player, String fpcName, String message) + { + if (player == null) + { + return; + } + + final String text = message.toLowerCase(); + + // tricky question + if (text.contains("can you see me")) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + if (npc.calculateDistance(player, false, false) < 3000) + { + if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible()) + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes"); + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?"); + } + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no"); + } + return; + } + } + } + + for (FakePlayerChatHolder chatHolder : MESSAGES) + { + if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL")) + { + continue; + } + + switch (chatHolder.getSearchMethod()) + { + case "EQUALS": + { + if (text.equals(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "STARTS_WITH": + { + if (text.startsWith(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "CONTAINS": + { + boolean allFound = true; + for (String word : chatHolder.getSearchText()) + { + if (!text.contains(word)) + { + allFound = false; + } + } + if (allFound) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + } + } + } + + public void sendChat(L2PcInstance player, String fpcName, String message) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message)); + } + } + } + + public static FakePlayerChatManager getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerChatManager _instance = new FakePlayerChatManager(); + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java index 1a62714f0e..50a3cc2145 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/DropProtection.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model; import java.util.concurrent.ScheduledFuture; import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; @@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; public class DropProtection implements Runnable { private volatile boolean _isProtected = false; - private L2PcInstance _owner = null; + private L2Character _owner = null; private ScheduledFuture _task = null; private static final long PROTECTED_MILLIS_TIME = 15000; @@ -46,7 +47,7 @@ public class DropProtection implements Runnable return _isProtected; } - public L2PcInstance getOwner() + public L2Character getOwner() { return _owner; } @@ -91,12 +92,12 @@ public class DropProtection implements Runnable _task = null; } - public synchronized void protect(L2PcInstance player) + public synchronized void protect(L2Character character) { unprotect(); _isProtected = true; - _owner = player; + _owner = character; if (_owner == null) { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java index 16c28a08d1..cc6e623f78 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/L2Object.java @@ -365,6 +365,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab return false; } + /** + * Verify if object is a fake player. + * @return {@code true} if object is a fake player, {@code false} otherwise + */ + public boolean isFakePlayer() + { + return false; + } + /** * Verify if object is instance of L2ServitorInstance. * @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 5af3de0701..dd23f482b8 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -70,6 +70,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.L2Item; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; @@ -279,7 +280,7 @@ public class L2Attackable extends L2Npc public synchronized boolean getMustRewardExpSP() { - return _mustGiveExpSp; + return _mustGiveExpSp && !isFakePlayer(); } /** @@ -958,6 +959,39 @@ public class L2Attackable extends L2Npc // Don't drop anything if the last attacker or owner isn't L2PcInstance if (player == null) { + // unless its a fake player and they can drop items + if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS) + { + final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer); + if (deathItems != null) + { + for (ItemHolder drop : deathItems) + { + final L2Item item = ItemTable.getInstance().getTemplate(drop.getId()); + // Check if the autoLoot mode is active + if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS)))) + { + // do nothing + } + else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect()) + { + for (SkillHolder skillHolder : item.getAllSkills()) + { + SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false); + } + mainDamageDealer.broadcastInfo(); // ? check if this is necessary + } + else + { + final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground + if (Config.FAKE_PLAYER_CAN_PICKUP) + { + mainDamageDealer.getFakePlayerDrops().add(droppedItem); + } + } + } + } + } return; } @@ -1045,7 +1079,7 @@ public class L2Attackable extends L2Npc */ public void doEventDrop(L2Character lastAttacker) { - if (lastAttacker == null) + if ((lastAttacker == null) || isFakePlayer()) { return; } @@ -1419,6 +1453,15 @@ public class L2Attackable extends L2Npc _harvestItem.set(null); _sweepItems.set(null); + // fake players + if (isFakePlayer()) + { + getFakePlayerDrops().clear(); // Clear existing fake player drops + setReputation(0); // reset reputation + setScriptValue(0); // remove pvp flag + setRunning(); // don't walk + } + // Clear mod Seeded stat _seeded = false; _seed = null; diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java index be5178c202..b098378730 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -29,6 +29,7 @@ import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -61,6 +62,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.CharEffectList; @@ -136,6 +138,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack; import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType; import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType; import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -202,6 +205,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private int _reputation = 0; + /** Map containing all skills of this character. */ private final Map _skills = new ConcurrentSkipListMap<>(); /** Map containing the skill reuse time stamps. */ @@ -270,6 +275,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe /** A map holding info about basic property mesmerizing system. */ private volatile Map _basicPropertyResists; + /** A list containing the dropped items of this fake player. */ + private final List _fakePlayerDrops = new CopyOnWriteArrayList<>(); + /** * Creates a creature. * @param template the creature template @@ -1207,6 +1215,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe broadcastPacket(attack); } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) + { + final L2Npc npc = ((L2Npc) this); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + // Notify AI with EVT_READY_TO_ACT ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk); } @@ -2317,7 +2336,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -2945,7 +2968,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -4127,7 +4154,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean isInsidePeaceZone(L2Object attacker, L2Object target) { final Instance instanceWorld = getInstanceWorld(); - if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) + if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) { return false; } @@ -5535,6 +5562,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist()); } + public int getReputation() + { + return _reputation; + } + + public void setReputation(int reputation) + { + _reputation = reputation; + } + /** * Gets the distance to target. * @param target the target @@ -5549,4 +5586,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { _cursorKeyMovement = value; } + + public List getFakePlayerDrops() + { + return _fakePlayerDrops; + } } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index 314ddd1f47..4802655840 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; +import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.handler.BypassHandler; import com.l2jmobius.gameserver.handler.IBypassHandler; import com.l2jmobius.gameserver.instancemanager.CastleManager; @@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.olympiad.Olympiad; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate; +import com.l2jmobius.gameserver.model.stats.Formulas; import com.l2jmobius.gameserver.model.variables.NpcVariables; import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.NpcStringId; @@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState; import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse; import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec import com.l2jmobius.gameserver.network.serverpackets.NpcSay; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; +import com.l2jmobius.gameserver.network.serverpackets.UserInfo; import com.l2jmobius.gameserver.taskmanager.DecayTaskManager; import com.l2jmobius.gameserver.util.Broadcast; @@ -125,6 +130,7 @@ public class L2Npc extends L2Character private boolean _isRandomAnimationEnabled = true; private boolean _isRandomWalkingEnabled = true; private boolean _isTalkable = getTemplate().isTalkable(); + private final boolean _isFakePlayer = getTemplate().isFakePlayer(); protected RandomAnimationTask _rAniTask; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -365,7 +371,11 @@ public class L2Npc extends L2Character return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo(this, player)); } @@ -902,6 +912,78 @@ public class L2Npc extends L2Character final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null; _killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0; + if (isFakePlayer() && (killer != null) && killer.isPlayable()) + { + final L2PcInstance player = killer.getActingPlayer(); + if (isScriptValue(0) && (getReputation() >= 0)) + { + if (Config.FAKE_PLAYER_KILL_KARMA) + { + player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon())); + player.setPkKills(player.getPkKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + player.checkItemRestriction(); + // pk item rewards + if (Config.REWARD_PK_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } + // announce pk + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + else if (Config.FAKE_PLAYER_KILL_PVP) + { + player.setPvpKills(player.getPvpKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + // pvp item rewards + if (Config.REWARD_PVP_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + } + // announce pvp + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + DecayTaskManager.getInstance().add(this); final L2Spawn spawn = getSpawn(); @@ -1211,7 +1293,11 @@ public class L2Npc extends L2Character activeChar.sendMessage("Added NPC: " + getName()); } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + activeChar.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { activeChar.sendPacket(new ServerObjectInfo(this, activeChar)); } @@ -1455,12 +1541,12 @@ public class L2Npc extends L2Character /** * Drops an item. - * @param player the last attacker or main damage dealer + * @param character the last attacker or main damage dealer * @param itemId the item ID * @param itemCount the item count * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount) + public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount) { L2ItemInstance item = null; for (int i = 0; i < itemCount; i++) @@ -1476,15 +1562,15 @@ public class L2Npc extends L2Character return null; } - item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this); + item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this); if (item == null) { return null; } - if (player != null) + if (character != null) { - item.getDropProtection().protect(player); + item.getDropProtection().protect(character); } item.dropMe(this, newX, newY, newZ); @@ -1509,14 +1595,14 @@ public class L2Npc extends L2Character } /** - * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)} - * @param player the last attacker or main damage dealer + * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)} + * @param character the last attacker or main damage dealer * @param item the item holder * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item) + public L2ItemInstance dropItem(L2Character character, ItemHolder item) { - return dropItem(player, item.getId(), item.getCount()); + return dropItem(character, item.getId(), item.getCount()); } @Override @@ -1580,6 +1666,12 @@ public class L2Npc extends L2Character return Config.SHOP_MIN_RANGE_FROM_NPC; } + @Override + public boolean isFakePlayer() + { + return _isFakePlayer; + } + /** * @return The player's object Id this NPC is cloning. */ diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java index 34550c3dd8..10ad419ea4 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Playable.java @@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character public abstract void doPickupItem(L2Object object); - public abstract int getReputation(); - public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove); public abstract void storeMe(); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index d58adad4db..42d728ea31 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -725,7 +725,7 @@ public abstract class L2Summon extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -743,7 +743,7 @@ public abstract class L2Summon extends L2Playable { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } @@ -905,6 +905,10 @@ public abstract class L2Summon extends L2Playable { setTarget(target); getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); + if (target.isFakePlayer()) + { + getOwner().updatePvPStatus(); + } } } } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java index a5fd31dedd..44ee919058 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java @@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java index aa4f132fce..6a94be63b5 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java @@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { - if (attacker.isMonster()) + if (attacker.isMonster() && !attacker.isFakePlayer()) { return true; } @@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); } + if (isFakePlayer() && isInCombat()) + { + interact = false; + // TODO: Fix normal targeting + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); + } + // Check if the L2PcInstance already target the L2GuardInstance if (getObjectId() != player.getTargetId()) { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java index e9a9976e87..fe55288a3a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java @@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { + if (isFakePlayer()) + { + return isInCombat() || attacker.isMonster() || (getScriptValue() > 0); + } + // Check if the L2MonsterInstance target is aggressive if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance)) { @@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable if (attacker.isMonster()) { - return false; + return attacker.isFakePlayer(); } // Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints. diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 7f5114956a..3201c86040 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -445,9 +445,6 @@ public final class L2PcInstance extends L2Playable /** The Experience of the L2PcInstance before the last Death Penalty */ private long _expBeforeDeath; - /** The Reputation of the L2PcInstance */ - private int _reputation; - /** The number of player killed during a PvP (the player killed was PvP Flagged) */ private int _pvpKills; @@ -1992,24 +1989,16 @@ public final class L2PcInstance extends L2Playable return _expBeforeDeath; } - /** - * @return the reputation of the PlayerInstance. - */ - @Override - public int getReputation() - { - return _reputation; - } - public void setInitialReputation(int reputation) { - _reputation = reputation; + super.setReputation(reputation); } /** * Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast). * @param reputation */ + @Override public void setReputation(int reputation) { // Notify to scripts. @@ -2035,7 +2024,9 @@ public final class L2PcInstance extends L2Playable } }); } - _reputation = reputation; + + super.setReputation(reputation); + sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation())); broadcastReputation(); } @@ -4655,6 +4646,10 @@ public final class L2PcInstance extends L2Playable { super.doAttack(target); setRecentFakeDeath(false); + if (target.isFakePlayer()) + { + updatePvPStatus(); + } } @Override @@ -4982,22 +4977,42 @@ public final class L2PcInstance extends L2Playable if (killer != null) { final L2PcInstance pk = killer.getActingPlayer(); - if (pk != null) + final boolean fpcKill = killer.isFakePlayer(); + if ((pk != null) || fpcKill) { - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); - - if (L2Event.isParticipant(pk)) + if (pk != null) { - pk.getEventStatus().addKill(this); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); + + if (L2Event.isParticipant(pk)) + { + pk.getEventStatus().addKill(this); + } + + // pvp/pk item rewards + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + // pvp + if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) + { + pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + // pk + if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) + { + pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } } // announce pvp/pk - if (Config.ANNOUNCE_PK_PVP && !pk.isGM()) + if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill)) { String msg = ""; if (getPvpFlag() == 0) { - msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5011,7 +5026,7 @@ public final class L2PcInstance extends L2Playable } else if (getPvpFlag() != 0) { - msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5025,20 +5040,9 @@ public final class L2PcInstance extends L2Playable } } - // pvp/pk item rewards - if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // - !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0)) { - // pvp - if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) - { - pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); - } - // pk - if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) - { - pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); - } + killer.setReputation(killer.getReputation() - 150); } } @@ -5631,6 +5635,14 @@ public final class L2PcInstance extends L2Playable return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks()); } + /** + * Used by fake players to emulate proper behavior. + */ + public void blockRequest() + { + _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND); + } + /** * Select the Warehouse to be used in next activity. * @param partner @@ -11568,7 +11580,7 @@ public final class L2PcInstance extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addPcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java index fb6b184e67..8383d1efc9 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java @@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc return null; } + @Override public int getReputation() { return _owner != null ? _owner.getReputation() : 0; @@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addCharName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); _owner.sendPacket(sm); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java index a97eab382d..26a51be541 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java @@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus } } - if (attacker.isPlayable() && (caster.getCurrentCp() > 0)) + if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0)) { if (caster.getCurrentCp() > transferDmg) { @@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus } } - if (!ignoreCP && attacker.isPlayable()) + if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer())) { if (getCurrentCp() >= value) { @@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus // Send a System Message to the L2PcInstance SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addCharName(attacker); + smsg.addString(attacker.getName()); smsg.addInt(fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java index 2d7f41e9d0..f5bee5dab6 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java @@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable private boolean _randomWalk; private boolean _randomAnimation; private boolean _flying; + private boolean _fakePlayer; + private boolean _fakePlayerTalkable; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; @@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable _randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard")); _randomAnimation = set.getBoolean("randomAnimation", true); _flying = set.getBoolean("flying", false); + _fakePlayer = set.getBoolean("fakePlayer", false); + _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true); _canMove = set.getBoolean("canMove", true); _noSleepMode = set.getBoolean("noSleepMode", false); _passableDoor = set.getBoolean("passableDoor", false); @@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable return _flying; } + public boolean isFakePlayer() + { + return _fakePlayer; + } + + public boolean isFakePlayerTalkable() + { + return _fakePlayerTalkable; + } + public boolean canMove() { return _canMove; @@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null) { @@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null) { @@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable case LUCKY_DROP: { // try chance before luck - if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck()) + if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck()) { return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax())); } @@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // chance double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER; // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE; } @@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // amount is calculated after chance returned success double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER; // premium amount - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT; } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java index df9698d3c3..6cbe42b242 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.events.impl.item; -import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.events.EventType; import com.l2jmobius.gameserver.model.events.impl.IBaseEvent; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; @@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent { private final String _process; private final L2ItemInstance _item; - private final L2PcInstance _activeChar; + private final L2Character _activeChar; private final Object _reference; - public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference) + public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference) { _process = process; _item = item; @@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent return _item; } - public L2PcInstance getActiveChar() + public L2Character getActiveChar() { return _activeChar; } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java new file mode 100644 index 0000000000..3008d340b3 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java @@ -0,0 +1,60 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Mobius + */ +public class FakePlayerChatHolder +{ + private final String _fpcName; + private final String _searchMethod; + private final List _searchText; + private final List _answers; + + public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers) + { + _fpcName = fpcName; + _searchMethod = searchMethod; + _searchText = new ArrayList<>(Arrays.asList(searchText.split(";"))); + _answers = new ArrayList<>(Arrays.asList(answers.split(";"))); + } + + public String getFpcName() + { + return _fpcName; + } + + public String getSearchMethod() + { + return _searchMethod; + } + + public List getSearchText() + { + return _searchText; + } + + public List getAnswers() + { + return _answers; + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java new file mode 100644 index 0000000000..2f8aa1fa6d --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java @@ -0,0 +1,232 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class FakePlayerHolder +{ + private final int _classId; + private final int _hair; + private final int _hairColor; + private final int _face; + private final int _nameColor; + private final int _titleColor; + private final int _equipHead; + private final int _equipRHand; + private final int _equipLHand; + private final int _equipGloves; + private final int _equipChest; + private final int _equipLegs; + private final int _equipFeet; + private final int _equipCloak; + private final int _equipHair; + private final int _equipHair2; + private final int _agathionId; + private final int _weaponEnchantLevel; + private final int _armorEnchantLevel; + private final boolean _fishing; + private final int _baitLocationX; + private final int _baitLocationY; + private final int _baitLocationZ; + private final int _recommends; + private final int _nobleLevel; + private final boolean _hero; + private final int _clanId; + private final int _pledgeStatus; + + public FakePlayerHolder(StatsSet set) + { + _classId = set.getInt("classId", 182); + + _hair = set.getInt("hair", 1); + _hairColor = set.getInt("hairColor", 1); + _face = set.getInt("face", 1); + + _nameColor = set.getInt("nameColor", 0xFFFFFF); + _titleColor = set.getInt("titleColor", 0xECF9A2); + + _equipHead = set.getInt("equipHead", 0); + _equipRHand = set.getInt("equipRHand", 0); // or dual hand + _equipLHand = set.getInt("equipLHand", 0); + _equipGloves = set.getInt("equipGloves", 0); + _equipChest = set.getInt("equipChest", 0); + _equipLegs = set.getInt("equipLegs", 0); + _equipFeet = set.getInt("equipFeet", 0); + _equipCloak = set.getInt("equipCloak", 0); + _equipHair = set.getInt("equipHair", 0); + _equipHair2 = set.getInt("equipHair2", 0); + _agathionId = set.getInt("agathionId", 0); + + _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0); + _armorEnchantLevel = set.getInt("armorEnchantLevel", 0); + + _fishing = set.getBoolean("fishing", false); + _baitLocationX = set.getInt("baitLocationX", 0); + _baitLocationY = set.getInt("baitLocationY", 0); + _baitLocationZ = set.getInt("baitLocationZ", 0); + + _recommends = set.getInt("recommends", 0); + _nobleLevel = set.getInt("nobleLevel", 0); + _hero = set.getBoolean("hero", false); + _clanId = set.getInt("clanId", 0); + _pledgeStatus = set.getInt("pledgeStatus", 0); + } + + public int getClassId() + { + return _classId; + } + + public int getHair() + { + return _hair; + } + + public int getHairColor() + { + return _hairColor; + } + + public int getFace() + { + return _face; + } + + public int getNameColor() + { + return _nameColor; + } + + public int getTitleColor() + { + return _titleColor; + } + + public int getEquipHead() + { + return _equipHead; + } + + public int getEquipRHand() + { + return _equipRHand; + } + + public int getEquipLHand() + { + return _equipLHand; + } + + public int getEquipGloves() + { + return _equipGloves; + } + + public int getEquipChest() + { + return _equipChest; + } + + public int getEquipLegs() + { + return _equipLegs; + } + + public int getEquipFeet() + { + return _equipFeet; + } + + public int getEquipCloak() + { + return _equipCloak; + } + + public int getEquipHair() + { + return _equipHair; + } + + public int getEquipHair2() + { + return _equipHair2; + } + + public int getAgathionId() + { + return _agathionId; + } + + public int getWeaponEnchantLevel() + { + return _weaponEnchantLevel; + } + + public int getArmorEnchantLevel() + { + return _armorEnchantLevel; + } + + public boolean isFishing() + { + return _fishing; + } + + public int getBaitLocationX() + { + return _baitLocationX; + } + + public int getBaitLocationY() + { + return _baitLocationY; + } + + public int getBaitLocationZ() + { + return _baitLocationZ; + } + + public int getRecommends() + { + return _recommends; + } + + public int getNobleLevel() + { + return _nobleLevel; + } + + public boolean isHero() + { + return _hero; + } + + public int getClanId() + { + return _clanId; + } + + public int getPledgeStatus() + { + return _pledgeStatus; + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index 65e361596b..190b26d291 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -277,16 +277,16 @@ public final class L2ItemInstance extends L2Object *
*
  • Do Pickup Item : PCInstance and Pet

  • *
    - * @param player Player that pick up the item + * @param character Character that pick up the item */ - public final void pickupMe(L2Character player) + public final void pickupMe(L2Character character) { assert getWorldRegion() != null; final L2WorldRegion oldregion = getWorldRegion(); // Create a server->client GetItem packet to pick up the L2ItemInstance - player.broadcastPacket(new GetItem(this, player.getObjectId())); + character.broadcastPacket(new GetItem(this, character.getObjectId())); synchronized (this) { @@ -305,10 +305,10 @@ public final class L2ItemInstance extends L2Object // Remove the L2ItemInstance from the world L2World.getInstance().removeVisibleObject(this, oldregion); - if (player.isPlayer()) + if (character.isPlayer()) { // Notify to scripts - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem()); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem()); } } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java index 98f374c294..ab8234a6e8 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable public boolean checkCondition(L2Character activeChar, L2Object object) { - if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION) + if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)) { return true; } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index b7eda58d00..13932008ff 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -159,7 +160,7 @@ public class SkillCaster implements Runnable } // You should not heal/buff monsters without pressing the ctrl button. - if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed) + if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed) { caster.sendPacket(SystemMessageId.INVALID_TARGET); return null; @@ -609,6 +610,10 @@ public class SkillCaster implements Runnable // Add hate to the attackable, and put it in the attack list. ((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint()); ((L2Character) obj).addAttackerToAttackByList(caster); + if (obj.isFakePlayer()) + { + player.updatePvPStatus(); + } } // notify target AI about the attack @@ -617,10 +622,19 @@ public class SkillCaster implements Runnable ((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster); } } - else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0)))) + else if (((skill.getEffectPoint() > 0) && obj.isMonster()) // + || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) // + || (((L2Character) obj).getReputation() < 0) // + ))) { // Supporting players or monsters result in pvpflag. - player.updatePvPStatus(); + if (!obj.isFakePlayer() // + || (obj.isFakePlayer() // + && (!((L2Npc) obj).isScriptValue(0) // + || (((L2Npc) obj).getReputation() < 0)))) + { + player.updatePvPStatus(); + } } } @@ -630,7 +644,7 @@ public class SkillCaster implements Runnable EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob); // On Skill See logic - if (npcMob.isAttackable()) + if (npcMob.isAttackable() && !npcMob.isFakePlayer()) { final L2Attackable attackable = (L2Attackable) npcMob; @@ -652,6 +666,19 @@ public class SkillCaster implements Runnable } }); } + else if (caster.isFakePlayer()) // fake player attacks player + { + if (target.isPlayable() || target.isFakePlayer()) + { + final L2Npc npc = ((L2Npc) caster); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + npc.broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + } } catch (Exception e) { @@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable return false; } } - return true; } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java index fdf0dadf55..06bea1b4cf 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java @@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.zone.L2ZoneType; import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; @@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } @@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java index 91a9ce830a..ccd2d1d13a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/Action.java @@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket } case 1: { - if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC)) + if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer())) { obj.onAction(activeChar, false); } diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java index 876c53c093..06464d9911 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java @@ -22,6 +22,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData; import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData; import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; @@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket return; } - if (Config.FORBIDDEN_NAMES.length > 1) + if (Config.FORBIDDEN_NAMES.length > 0) { for (String st : Config.FORBIDDEN_NAMES) { @@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().getProperName(_name) != null) + { + client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); + return; + } + // Last Verified: May 30, 2009 - Gracia Final if (!Util.isAlphaNumeric(_name) || !isValidName(_name)) { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java index 06bfa3c200..01c8b0c67f 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java @@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; public final class RequestBlock implements IClientIncomingPacket { @@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket case BLOCK: case UNBLOCK: { + // TODO: Save in database? :P + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (_type == BLOCK) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + return; + } + // can't use block/unblock for locating invisible characters if (targetId <= 0) { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java index ceb67b0f5f..cf79bdb24c 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable; import com.l2jmobius.gameserver.util.Util; @@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket { result = NAME_ALREADY_EXISTS; } + else if (FakePlayerData.getInstance().getProperName(_name) != null) + { + result = NAME_ALREADY_EXISTS; + } else if (_name.length() > 16) { result = INVALID_LENGTH; diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java index b0ace828dc..ee8bcd656b 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java @@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Party; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart; @@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance activeChar = client.getActiveChar(); - final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (activeChar == null) { return; } + + if (FakePlayerData.getInstance().isTalkable(_player)) + { + final String name = FakePlayerData.getInstance().getProperName(_player); + if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + if (activeChar.isProcessingRequest()) + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(name); + activeChar.sendPacket(msg); + return; + } + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL); + sm.addString(name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000); + activeChar.blockRequest(); + return; + } + + final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (targetChar == null) { activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java index f104c94161..c0042d45c5 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java @@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PartyDistributionType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Party; @@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + if (player.getParty() == null) + { + player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED); + } + else + { + player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY); + } + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance requestor = client.getActiveChar(); - final L2PcInstance target = L2World.getInstance().getPlayer(_name); - if (requestor == null) { return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + requestor.sendPacket(sm); + if (!requestor.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000); + requestor.blockRequest(); + } + else + { + requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY); + } + return; + } + + final L2PcInstance target = L2World.getInstance().getPlayer(_name); if (target == null) { requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java index 292153afd8..37c539556f 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java @@ -17,12 +17,15 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; /** * This class ... @@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket return; } + if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName()))) + { + if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0) + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN); + } + else + { + if (!activeChar.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(activeChar.getTarget().getName()); + activeChar.sendPacket(msg); + } + } + return; + } + final L2PcInstance target = L2World.getInstance().getPlayer(_target); if (target == null) { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java index 3d5bcaeca5..9cbb114e88 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java @@ -23,6 +23,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.instancemanager.MailManager; import com.l2jmobius.gameserver.model.BlockList; @@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().isTalkable(_receiver)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1); + sm.addString(FakePlayerData.getInstance().getProperName(_receiver)); + activeChar.sendPacket(sm); + return; + } + final int receiverId = CharNameTable.getInstance().getIdByName(_receiver); if (receiverId <= 0) { diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java index 8156905e94..1336c2bdb7 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java @@ -17,6 +17,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; @@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket } final L2Object object = activeChar.getTarget(); - if (!(object instanceof L2PcInstance)) { if (object == null) { client.sendPacket(SystemMessageId.SELECT_TARGET); } + else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName())) + { + if (activeChar.getRecomLeft() <= 0) + { + client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER); + return; + } + + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT); + sm.addString(FakePlayerData.getInstance().getProperName(object.getName())); + sm.addInt(activeChar.getRecomLeft()); + client.sendPacket(sm); + + activeChar.setRecomLeft(activeChar.getRecomLeft() - 1); + client.sendPacket(new UserInfo(activeChar)); + client.sendPacket(new ExVoteSystemInfo(activeChar)); + } else { client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java index d77dc881b3..5d7e35eb43 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java @@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.effects.AbstractEffect; import com.l2jmobius.gameserver.model.skills.AbnormalType; @@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final String name = FakePlayerData.getInstance().getProperName(target.getName()); + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE)); + return; + } + if (!player.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1); + sm.addString(name); + player.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000); + player.blockRequest(); + } + else + { + player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE); + } + return; + } + if (!target.isPlayer()) { client.sendPacket(SystemMessageId.INVALID_TARGET); diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java index 4fa25283a7..530a6d7a01 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java @@ -17,6 +17,8 @@ package com.l2jmobius.gameserver.network.clientpackets.friend; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST)); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (!activeChar.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST); + sm.addString(_name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + sm.addString(_name); + activeChar.sendPacket(sm); + } + return; + } + final L2PcInstance friend = L2World.getInstance().getPlayer(_name); // Target is not found in the game. diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java index 2170ef2e94..017541bd86 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java @@ -22,6 +22,7 @@ import java.util.List; import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.instancemanager.MentorManager; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.NpcStringId; import com.l2jmobius.gameserver.network.OutgoingPackets; @@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket _charLevel = sender.getLevel(); _textType = messageType; _text = text; - if (receiver.getFriendList().contains(sender.getObjectId())) + if (receiver != null) { - _mask |= 0x01; - } - if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) - { - _mask |= 0x02; - } - if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) - { - _mask |= 0x04; - } - if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) - { - _mask |= 0x08; + if (receiver.getFriendList().contains(sender.getObjectId())) + { + _mask |= 0x01; + } + if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) + { + _mask |= 0x02; + } + if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) + { + _mask |= 0x04; + } + if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) + { + _mask |= 0x08; + } } // Does not shows level @@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket } } + /** + * Used by fake players. + * @param sender + * @param receiver + * @param name + * @param messageType + * @param text + */ + public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text) + { + _objectId = sender.getObjectId(); + _charName = name; + _charLevel = sender.getLevel(); + _textType = messageType; + _text = text; + } + /** * @param objectId * @param messageType diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java new file mode 100644 index 0000000000..9ba3b311b6 --- /dev/null +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java @@ -0,0 +1,231 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.network.serverpackets; + +import java.util.Set; + +import com.l2jmobius.commons.network.PacketWriter; +import com.l2jmobius.gameserver.data.sql.impl.ClanTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.enums.Sex; +import com.l2jmobius.gameserver.model.L2Clan; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; +import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect; +import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.OutgoingPackets; + +/** + * @author Mobius + */ +public class FakePlayerInfo implements IClientOutgoingPacket +{ + private final L2Npc _npc; + private final int _objId; + private final int _x, _y, _z, _heading; + private final int _mAtkSpd, _pAtkSpd; + private final int _runSpd, _walkSpd; + private final int _swimRunSpd; + private final int _swimWalkSpd; + private final int _flyRunSpd; + private final int _flyWalkSpd; + private final double _moveMultiplier; + private final float _attackSpeedMultiplier; + private final FakePlayerHolder _fpcHolder; + private final L2Clan _clan; + + public FakePlayerInfo(L2Npc npc) + { + _npc = npc; + _objId = npc.getObjectId(); + _x = npc.getX(); + _y = npc.getY(); + _z = npc.getZ(); + _heading = npc.getHeading(); + _mAtkSpd = npc.getMAtkSpd(); + _pAtkSpd = npc.getPAtkSpd(); + _attackSpeedMultiplier = npc.getAttackSpeedMultiplier(); + _moveMultiplier = npc.getMovementSpeedMultiplier(); + _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier); + _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier); + _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier); + _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier); + _flyRunSpd = npc.isFlying() ? _runSpd : 0; + _flyWalkSpd = npc.isFlying() ? _walkSpd : 0; + _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId()); + _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId()); + } + + @Override + public boolean write(PacketWriter packet) + { + OutgoingPackets.CHAR_INFO.writeId(packet); + packet.writeD(_x); + packet.writeD(_y); + packet.writeD(_z); + packet.writeD(0x00); // vehicleId + packet.writeD(_objId); + packet.writeS(_npc.getName()); + + packet.writeH(_npc.getRace().ordinal()); + packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00); + packet.writeD(_fpcHolder.getClassId()); + + packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER + packet.writeD(_fpcHolder.getEquipHead()); + packet.writeD(_fpcHolder.getEquipRHand()); + packet.writeD(_fpcHolder.getEquipLHand()); + packet.writeD(_fpcHolder.getEquipGloves()); + packet.writeD(_fpcHolder.getEquipChest()); + packet.writeD(_fpcHolder.getEquipLegs()); + packet.writeD(_fpcHolder.getEquipFeet()); + packet.writeD(_fpcHolder.getEquipCloak()); + packet.writeD(_fpcHolder.getEquipRHand()); // dual hand + packet.writeD(_fpcHolder.getEquipHair()); + packet.writeD(_fpcHolder.getEquipHair2()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderAugument()) + { + packet.writeD(0x00); + } + + packet.writeC(_fpcHolder.getArmorEnchantLevel()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderVisualId()) + { + packet.writeD(0x00); + } + + packet.writeC(_npc.getScriptValue()); // getPvpFlag() + packet.writeD(_npc.getReputation()); + + packet.writeD(_mAtkSpd); + packet.writeD(_pAtkSpd); + + packet.writeH(_runSpd); + packet.writeH(_walkSpd); + packet.writeH(_swimRunSpd); + packet.writeH(_swimWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeF(_moveMultiplier); + packet.writeF(_attackSpeedMultiplier); + + packet.writeF(_npc.getCollisionRadius()); + packet.writeF(_npc.getCollisionHeight()); + + packet.writeD(_fpcHolder.getHair()); + packet.writeD(_fpcHolder.getHairColor()); + packet.writeD(_fpcHolder.getFace()); + + packet.writeS(_npc.getTemplate().getTitle()); + + if (_clan != null) + { + packet.writeD(_clan.getId()); + packet.writeD(_clan.getCrestId()); + packet.writeD(_clan.getAllyId()); + packet.writeD(_clan.getAllyCrestId()); + } + else + { + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + } + + packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked) + packet.writeC(_npc.isRunning() ? 0x01 : 0x00); + packet.writeC(_npc.isInCombat() ? 0x01 : 0x00); + + packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00); + + packet.writeC(_npc.isInvisible() ? 0x01 : 0x00); + + packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount + packet.writeC(0x00); // getPrivateStoreType().getId() + + packet.writeH(0x00); // getCubics().size() + // getCubics().keySet().forEach(packet::writeH); + + packet.writeC(0x00); + + packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0); + packet.writeH(_fpcHolder.getRecommends()); + packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000 + + packet.writeD(_fpcHolder.getClassId()); + packet.writeD(0x00); + packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel + + packet.writeC(_npc.getTeam().getId()); + + packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00); + packet.writeC(_fpcHolder.getNobleLevel()); + packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00); + + packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00); + + packet.writeD(_fpcHolder.getBaitLocationX()); + packet.writeD(_fpcHolder.getBaitLocationY()); + packet.writeD(_fpcHolder.getBaitLocationZ()); + + packet.writeD(_fpcHolder.getNameColor()); + + packet.writeD(_heading); + + packet.writeC(_fpcHolder.getPledgeStatus()); + packet.writeH(0x00); // getPledgeType() + + packet.writeD(_fpcHolder.getTitleColor()); + + packet.writeC(0x00); // isCursedWeaponEquipped + + packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0 + packet.writeD(0x00); // getTransformationDisplayId() + packet.writeD(_fpcHolder.getAgathionId()); + + packet.writeC(0x00); + + packet.writeD(0x00); // getCurrentCp() + packet.writeD(_npc.getMaxHp()); + packet.writeD((int) Math.round(_npc.getCurrentHp())); + packet.writeD(_npc.getMaxMp()); + packet.writeD((int) Math.round(_npc.getCurrentMp())); + + packet.writeC(0x00); + final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects(); + packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0)); + for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects) + { + packet.writeH(abnormalVisualEffect.getClientId()); + } + if (_npc.isInvisible()) + { + packet.writeH(AbnormalVisualEffect.STEALTH.getClientId()); + } + packet.writeC(0x00); // cocPlayer.getPosition() + packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00); + packet.writeC(0x00); // Used Ability Points + return true; + } +} diff --git a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index 4fb1a757e6..c294edab2a 100644 --- a/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_1.0_Ertheia/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket addComponentType(NpcInfoType.TITLE_NPCSTRINGID); } + if (_npc.getReputation() != 0) + { + addComponentType(NpcInfoType.REPUTATION); + } + if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible()) { addComponentType(NpcInfoType.ABNORMALS); @@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.REPUTATION)) { - packet.writeD(0x00); // Name color + packet.writeD(_npc.getReputation()); // Reputation } if (containsMask(NpcInfoType.CLAN)) { diff --git a/L2J_Mobius_1.0_Ertheia/readme.txt b/L2J_Mobius_1.0_Ertheia/readme.txt index a5606e61ff..324c1e9e52 100644 --- a/L2J_Mobius_1.0_Ertheia/readme.txt +++ b/L2J_Mobius_1.0_Ertheia/readme.txt @@ -82,6 +82,7 @@ Customs: -Classmaster -Community board -Faction system +-Fake players -Find PvP -NPC stat multipliers -Realtime offline trade diff --git a/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml b/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml index 171e08cb12..f9067f1377 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/config/AdminCommands.xml @@ -392,6 +392,9 @@ + + + diff --git a/L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini new file mode 100644 index 0000000000..f745b0d31e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/config/Custom/FakePlayers.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------------------- +# Fake players +# --------------------------------------------------------------------------- + +# Enable fake players. +EnableFakePlayers = False + +# Enable chatting with fake players. +FakePlayerChat = True + +# Enable shots usage for fake players. +FakePlayerUseShots = True + +# Reward PvP kills by killing fake players. +FakePlayerKillsRewardPvP = True + +# Fake player kills apply karma rules. +FakePlayerUnflaggedKillsKarma = True + +# Aggressive AI fake players attack nearby monsters. +FakePlayerAggroMonsters = True + +# Aggressive AI fake players attack nearby players. +FakePlayerAggroPlayers = False + +# Aggressive AI fake players attack nearby fake players. +FakePlayerAggroFPC = False + +# Fake players can drop items when killing monsters. +FakePlayerCanDropItems = True + +# Fake players can pickup dropped items. +FakePlayerCanPickup = True diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml new file mode 100644 index 0000000000..f5da5bfc8e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerChatData.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml new file mode 100644 index 0000000000..f36096ed4a --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/FakePlayerVisualData.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml index 98e0d38815..96e8e6ed81 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml +++ b/L2J_Mobius_2.5_Underground/dist/game/data/Routes.xml @@ -2402,4 +2402,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java index 6f29855cc3..d12ee2e7c4 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java @@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI final L2Character creature = event.getSeen(); final L2Npc npc = (L2Npc) event.getSeer(); - if (creature.isPlayer()) + if (creature.isPlayer() || creature.isFakePlayer()) { npc.setTarget(creature); npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill()); diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java new file mode 100644 index 0000000000..e1dde7324e --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java @@ -0,0 +1,80 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +import ai.AbstractNpcAI; + +/** + * TODO: Move it to L2Character. + * @author Mobius + */ +public class PvpFlaggingStopTask extends AbstractNpcAI +{ + private PvpFlaggingStopTask() + { + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if ((npc == null) || npc.isDead()) + { + return null; + } + + if (event.startsWith("FLAG_CHECK")) + { + final L2Object target = npc.getTarget(); + if ((target != null) && (target.isPlayable() || target.isFakePlayer())) + { + npc.setScriptValue(1); // in combat + cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null); + cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null); + startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null); + startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null); + } + } + else if (event.startsWith("FINISH_FLAG")) + { + if (npc.isScriptValue(1)) + { + npc.setScriptValue(2); // blink status + npc.broadcastInfo(); // update flag status + startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null); + } + } + else if (event.startsWith("REMOVE_FLAG")) + { + if (npc.isScriptValue(2)) + { + npc.setScriptValue(0); // not in combat + npc.broadcastInfo(); // update flag status + } + } + return super.onAdvEvent(event, npc, player); + } + + public static void main(String[] args) + { + new PvpFlaggingStopTask(); + } +} diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java new file mode 100644 index 0000000000..dec3449549 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java @@ -0,0 +1,115 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.CommonUtil; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.base.ClassId; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.SkillCaster; + +import ai.AbstractNpcAI; + +/** + * Town Fake Player walkers that receive buffs from Adventurer NPC. + * @author Mobius + */ +public class RecieveAdventurerBuffs extends AbstractNpcAI +{ + // NPCs + private static final int[] ADVENTURERS_GUIDE = + { + 32327, + 33950, + }; + private static final int[] FAKE_PLAYER_IDS = + { + 80000 + }; + // Skills + // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer) + private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer) + private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer) + private static final SkillHolder[] GROUP_BUFFS = + { + new SkillHolder(15642, 1), // Horn Melody (Adventurer) + new SkillHolder(15643, 1), // Drum Melody (Adventurer) + new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer) + new SkillHolder(15645, 1), // Guitar Melody (Adventurer) + new SkillHolder(15646, 1), // Harp Melody (Adventurer) + new SkillHolder(15647, 1), // Lute Melody (Adventurer) + new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer) + new SkillHolder(15652, 1), // Daring Sonata (Adventurer) + new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer) + }; + + private RecieveAdventurerBuffs() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + addSpawnId(FAKE_PLAYER_IDS); + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead()) + { + if (!npc.isMoving()) + { + for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100)) + { + if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId())) + { + for (SkillHolder holder : GROUP_BUFFS) + { + SkillCaster.triggerCast(nearby, npc, holder.getSkill()); + } + if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage()) + { + SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill()); + } + else + { + SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill()); + } + break; + } + } + } + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSpawn(L2Npc npc) + { + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new RecieveAdventurerBuffs(); + } +} diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java index 01015c4d55..fd223930e4 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/MasterHandler.java @@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant; import handlers.admincommandhandlers.AdminEventEngine; import handlers.admincommandhandlers.AdminEvents; import handlers.admincommandhandlers.AdminExpSp; +import handlers.admincommandhandlers.AdminFakePlayers; import handlers.admincommandhandlers.AdminFightCalculator; import handlers.admincommandhandlers.AdminFortSiege; import handlers.admincommandhandlers.AdminGeodata; @@ -409,6 +410,7 @@ public class MasterHandler AdminEventEngine.class, AdminEvents.class, AdminExpSp.class, + AdminFakePlayers.class, AdminFightCalculator.class, AdminFortSiege.class, AdminGeodata.class, diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java index 6b02816d9e..d6d6a99080 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java @@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler } else if (Config.ALT_GAME_VIEWNPC) { - if (!target.isNpc()) + if (!target.isNpc() || target.isFakePlayer()) { return false; } diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java new file mode 100644 index 0000000000..99926f0df7 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java @@ -0,0 +1,77 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package handlers.admincommandhandlers; + +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.handler.IAdminCommandHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +/** + * @author Mobius + */ +public class AdminFakePlayers implements IAdminCommandHandler +{ + private static final String[] ADMIN_COMMANDS = + { + "admin_fakechat" + }; + + @Override + public boolean useAdminCommand(String command, L2PcInstance activeChar) + { + if (command.startsWith("admin_fakechat")) + { + final String[] words = command.substring(15).split(" "); + if (words.length < 3) + { + activeChar.sendMessage("Usage: //fakechat playername fpcname message"); + return false; + } + final L2PcInstance player = L2World.getInstance().getPlayer(words[0]); + if (player == null) + { + activeChar.sendMessage("Player not found."); + return false; + } + final String fpcName = FakePlayerData.getInstance().getProperName(words[1]); + if (fpcName == null) + { + activeChar.sendMessage("Fake player not found."); + return false; + } + String message = ""; + for (int i = 0; i < words.length; i++) + { + if (i < 2) + { + continue; + } + message += (words[i] + " "); + } + FakePlayerChatManager.getInstance().sendChat(player, fpcName, message); + } + return true; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 5da8e115b2..4799a7aa53 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData; import com.l2jmobius.gameserver.data.xml.impl.DoorData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData; import com.l2jmobius.gameserver.data.xml.impl.MultisellData; @@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.WalkingManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.util.Util; @@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data."); break; } + case "fakeplayers": + { + FakePlayerData.getInstance().load(); + for (L2Object obj : L2World.getInstance().getVisibleObjects()) + { + if (obj.isFakePlayer()) + { + obj.broadcastInfo(); + } + } + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data."); + break; + } + case "fakeplayerchat": + { + FakePlayerChatManager.getInstance().load(); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data."); + break; + } default: { activeChar.sendMessage(RELOAD_USAGE); diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java index 99f2e9e9d7..7db79fe31d 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java @@ -17,8 +17,10 @@ package handlers.chathandlers; import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.handler.IChatHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.PcCondOverride; @@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler return; } + if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null)) + { + if (FakePlayerData.getInstance().isTalkable(target)) + { + if (Config.FAKE_PLAYER_CHAT) + { + final String name = FakePlayerData.getInstance().getProperName(target); + activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text)); + FakePlayerChatManager.getInstance().manageChat(activeChar, name, text); + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE); + } + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE); + } + return; + } + final L2PcInstance receiver = L2World.getInstance().getPlayer(target); if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId())) diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java index 41b1f99bcf..b38f5ca16d 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java @@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition { return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel); } - } diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java index 1e34a0d148..087112cc73 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/handlers/playeractions/SocialAction.java @@ -16,9 +16,11 @@ */ package handlers.playeractions; +import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.NextAction; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.handler.IPlayerActionHandler; import com.l2jmobius.gameserver.model.ActionDataHolder; import com.l2jmobius.gameserver.model.L2Object; @@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED); + player.onTransactionResponse(); + } + } + private void useCoupleSocial(L2PcInstance player, int id) { if (player == null) @@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler } final L2Object target = player.getTarget(); - if ((target == null) || !target.isPlayer()) + if ((target == null)) + { + player.sendPacket(SystemMessageId.INVALID_TARGET); + return; + } + + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1); + sm.addString(target.getName()); + player.sendPacket(sm); + if (!player.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000); + player.blockRequest(); + } + return; + } + + if (!target.isPlayer()) { player.sendPacket(SystemMessageId.INVALID_TARGET); return; diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java index b79fe7475a..5e1b48e51b 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java @@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest @Id(WINDY_HEALING_POTION_1) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(4, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + { + qs.setCond(4, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java index 0efb5383f4..34594dbc40 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java +++ b/L2J_Mobius_2.5_Underground/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java @@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest @Id(HIGH_GRADE_LOVE_POTION) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(2, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + { + qs.setCond(2, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml new file mode 100644 index 0000000000..ea77878c2c --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/spawns/Others/FakePlayers.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml new file mode 100644 index 0000000000..8470293122 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_combat.xml @@ -0,0 +1,341 @@ + + + + + HUMAN + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + ORC + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + DWARF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + KAMAEL + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + HUMAN + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + DARK_ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml new file mode 100644 index 0000000000..589f29b215 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/stats/npcs/custom/fpc_passive.xml @@ -0,0 +1,26 @@ + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd new file mode 100644 index 0000000000..2b2c94e75b --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerChatData.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd new file mode 100644 index 0000000000..0628acefc3 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/FakePlayerVisualData.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd index 6f00944cff..ae80c3ff63 100644 --- a/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd +++ b/L2J_Mobius_2.5_Underground/dist/game/data/xsd/npcs.xsd @@ -201,6 +201,8 @@ + +
    diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java index f74df8f22f..1da64a6c7e 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/Config.java @@ -116,6 +116,7 @@ public final class Config public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini"; public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini"; public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini"; + public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini"; public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini"; public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini"; public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini"; @@ -1147,6 +1148,16 @@ public final class Config public static boolean FACTION_SPECIFIC_CHAT; public static boolean FACTION_BALANCE_ONLINE_PLAYERS; public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT; + public static boolean FAKE_PLAYERS_ENABLED; + public static boolean FAKE_PLAYER_CHAT; + public static boolean FAKE_PLAYER_USE_SHOTS; + public static boolean FAKE_PLAYER_KILL_PVP; + public static boolean FAKE_PLAYER_KILL_KARMA; + public static boolean FAKE_PLAYER_AGGRO_MONSTERS; + public static boolean FAKE_PLAYER_AGGRO_PLAYERS; + public static boolean FAKE_PLAYER_AGGRO_FPC; + public static boolean FAKE_PLAYER_CAN_DROP_ITEMS; + public static boolean FAKE_PLAYER_CAN_PICKUP; public static boolean ENABLE_FIND_PVP; public static boolean PREMIUM_SYSTEM_ENABLED; public static float PREMIUM_RATE_XP; @@ -2560,6 +2571,19 @@ public final class Config FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true); FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20); + // Load FakePlayers config file (if exists) + final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE); + FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false)); + FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false)); + FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false)); + FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false)); + FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false)); + FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false)); + FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false)); + FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false)); + FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false)); + FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false)); + // Load FindPvP config file (if exists) final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE); ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java index 802ea4e498..09ca886b87 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/GameServer.java @@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData; import com.l2jmobius.gameserver.data.xml.impl.EventEngineData; import com.l2jmobius.gameserver.data.xml.impl.ExperienceData; import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.HennaData; import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData; @@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; import com.l2jmobius.gameserver.instancemanager.DBSpawnManager; import com.l2jmobius.gameserver.instancemanager.FactionManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.FortManager; import com.l2jmobius.gameserver.instancemanager.FortSiegeManager; import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; @@ -288,6 +290,8 @@ public class GameServer printSection("NPCs"); SkillLearnData.getInstance(); NpcData.getInstance(); + FakePlayerData.getInstance(); + FakePlayerChatManager.getInstance(); ExtendDropData.getInstance(); SpawnsData.getInstance(); WalkingManager.getInstance(); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 6253fa9329..1da1b21546 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.model.AggroInfo; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate; import com.l2jmobius.gameserver.model.events.returns.TerminateReturn; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.skills.SkillCaster; @@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10 if (_globalAggro >= 0) { - if (npc.isAggressive() || (npc instanceof L2GuardInstance)) + if (npc.isFakePlayer() && npc.isAggressive()) + { + final List droppedItems = npc.getFakePlayerDrops(); + if (droppedItems.isEmpty()) + { + L2Character nearestTarget = null; + double closestDistance = Double.MAX_VALUE; + for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange())) + { + if ((t == _actor) || (t == null) || t.isDead()) + { + continue; + } + if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer())) + { + final int hating = npc.getHating(t); + final double distance = npc.calculateDistance(t, false, false); + if ((hating == 0) && (closestDistance > distance)) + { + nearestTarget = t; + closestDistance = distance; + } + } + } + if (nearestTarget != null) + { + npc.addDamageHate(nearestTarget, 0, 1); + } + } + else if (!npc.isInCombat()) // must pickup items + { + final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped + final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex); + if ((droppedItem != null) && droppedItem.isSpawned()) + { + if (npc.calculateDistance(droppedItem, false, false) > 50) + { + moveTo(droppedItem); + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + droppedItem.pickupMe(npc); + if (Config.SAVE_DROPPED_ITEM) + { + ItemsOnGroundManager.getInstance().removeObject(droppedItem); + } + if (droppedItem.getItem().hasExImmediateEffect()) + { + for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills()) + { + SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false); + } + npc.broadcastInfo(); // ? check if this is necessary + } + } + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + } + npc.setRunning(); + } + } + else if (npc.isAggressive() || (npc instanceof L2GuardInstance)) { final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players. L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t -> @@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // For each L2Character check if the target is autoattackable if (isAggressiveTowards(t)) // check aggression { - if (t.isPlayable()) + if (t.isFakePlayer()) + { + if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC)) + { + final int hating = npc.getHating(t); + if (hating == 0) + { + npc.addDamageHate(t, 0, 1); + } + } + } + else if (t.isPlayable()) { final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class); if ((term != null) && term.terminate()) diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java new file mode 100644 index 0000000000..0a6ca5267a --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java @@ -0,0 +1,125 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; + +/** + * @author Mobius + */ +public class FakePlayerData implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName()); + + private final Map _fakePlayerInfos = new HashMap<>(); + private final Map _fakePlayerNames = new HashMap<>(); + private final Map _fakePlayerIds = new HashMap<>(); + private final List _talkableFakePlayerNames = new ArrayList<>(); + + protected FakePlayerData() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + _fakePlayerInfos.clear(); + _fakePlayerNames.clear(); + _fakePlayerIds.clear(); + _talkableFakePlayerNames.clear(); + parseDatapackFile("data/FakePlayerVisualData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode)); + final int npcId = set.getInt("npcId"); + final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId); + final String name = template.getName(); + if (CharNameTable.getInstance().getIdByName(name) > 0) + { + LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists."); + } + else + { + _fakePlayerIds.put(name, npcId); // name - npcId + _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name + _fakePlayerInfos.put(npcId, new FakePlayerHolder(set)); + if (template.isFakePlayerTalkable()) + { + _talkableFakePlayerNames.add(name.toLowerCase()); + } + } + })); + } + + public int getNpcIdByName(String name) + { + return _fakePlayerIds.get(name); + } + + public String getProperName(String name) + { + return _fakePlayerNames.get(name.toLowerCase()); + } + + public Boolean isTalkable(String name) + { + return _talkableFakePlayerNames.contains(name.toLowerCase()); + } + + public FakePlayerHolder getInfo(int npcId) + { + return _fakePlayerInfos.get(npcId); + } + + public static FakePlayerData getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerData _instance = new FakePlayerData(); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java index 883e877bc7..f03a2395f1 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java @@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader set.set("hasSummoner", parseBoolean(attrs, "hasSummoner")); set.set("canBeSown", parseBoolean(attrs, "canBeSown")); set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty")); + set.set("fakePlayer", parseBoolean(attrs, "fakePlayer")); + set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable")); break; } case "skill_list": diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java index 2ff4c9322d..15bd310bd6 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java @@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader return; } + if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer()) + { + return; + } + for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) { if ("parameters".equalsIgnoreCase(d.getNodeName())) diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java index a145b65dba..d525c02a6a 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/BotReportTable.java @@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.zone.ZoneId; @@ -210,15 +212,14 @@ public final class BotReportTable public boolean reportBot(L2PcInstance reporter) { final L2Object target = reporter.getTarget(); - if (target == null) { return false; } - final L2PcInstance bot = target.getActingPlayer(); + final L2Character bot = ((L2Character) target); - if ((bot == null) || (target.getObjectId() == reporter.getObjectId())) + if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId())) { return false; } @@ -229,7 +230,7 @@ public final class BotReportTable return false; } - if (bot.isInOlympiadMode()) + if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode()) { reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD); return false; @@ -241,7 +242,7 @@ public final class BotReportTable return false; } - if (bot.getExp() == bot.getStat().getStartingExp()) + if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp())) { reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING); return false; @@ -320,15 +321,18 @@ public final class BotReportTable } SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT); - sm.addCharName(bot); + sm.addString(bot.getName()); reporter.sendPacket(sm); sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT); - sm.addCharName(bot); + sm.addString(bot.getName()); sm.addInt(rcdRep.getPointsLeft()); reporter.sendPacket(sm); - handleReport(bot, rcd); + if (bot.isPlayer()) + { + handleReport(bot.getActingPlayer(), rcd); + } return true; } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java index 7454554076..ace19486b5 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/datatables/ItemTable.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -202,11 +203,11 @@ public class ItemTable * @param process : String Identifier of process triggering this action * @param itemId : int Item Identifier of the item to be created * @param count : int Quantity of items to be created for stackable items - * @param actor : L2PcInstance Player requesting the item creation + * @param actor : L2Character requesting the item creation * @param reference : Object Object referencing current action like NPC selling item or previous item in transformation * @return L2ItemInstance corresponding to the new item */ - public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference) + public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference) { // Create and Init the L2ItemInstance corresponding to the Item Identifier final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java index b621b4c4cb..bb0e928daf 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/idfactory/IdFactory.java @@ -217,6 +217,7 @@ public abstract class IdFactory cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); + cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); // If the clan does not exist... cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java new file mode 100644 index 0000000000..16a0da92bc --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java @@ -0,0 +1,196 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.instancemanager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2Spawn; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder; +import com.l2jmobius.gameserver.network.serverpackets.CreatureSay; + +/** + * @author Mobius + */ +public final class FakePlayerChatManager implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName()); + final List MESSAGES = new ArrayList<>(); + private static final int MIN_DELAY = 5000; + private static final int MAX_DELAY = 15000; + + protected FakePlayerChatManager() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT) + { + MESSAGES.clear(); + parseDatapackFile("data/FakePlayerChatData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode)); + MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers"))); + })); + } + + public void manageChat(L2PcInstance player, String fpcName, String message) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY)); + } + + public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay)); + } + + private void manageResponce(L2PcInstance player, String fpcName, String message) + { + if (player == null) + { + return; + } + + final String text = message.toLowerCase(); + + // tricky question + if (text.contains("can you see me")) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + if (npc.calculateDistance(player, false, false) < 3000) + { + if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible()) + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes"); + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?"); + } + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no"); + } + return; + } + } + } + + for (FakePlayerChatHolder chatHolder : MESSAGES) + { + if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL")) + { + continue; + } + + switch (chatHolder.getSearchMethod()) + { + case "EQUALS": + { + if (text.equals(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "STARTS_WITH": + { + if (text.startsWith(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "CONTAINS": + { + boolean allFound = true; + for (String word : chatHolder.getSearchText()) + { + if (!text.contains(word)) + { + allFound = false; + } + } + if (allFound) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + } + } + } + + public void sendChat(L2PcInstance player, String fpcName, String message) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message)); + } + } + } + + public static FakePlayerChatManager getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerChatManager _instance = new FakePlayerChatManager(); + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java index 1a62714f0e..50a3cc2145 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/DropProtection.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model; import java.util.concurrent.ScheduledFuture; import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; @@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; public class DropProtection implements Runnable { private volatile boolean _isProtected = false; - private L2PcInstance _owner = null; + private L2Character _owner = null; private ScheduledFuture _task = null; private static final long PROTECTED_MILLIS_TIME = 15000; @@ -46,7 +47,7 @@ public class DropProtection implements Runnable return _isProtected; } - public L2PcInstance getOwner() + public L2Character getOwner() { return _owner; } @@ -91,12 +92,12 @@ public class DropProtection implements Runnable _task = null; } - public synchronized void protect(L2PcInstance player) + public synchronized void protect(L2Character character) { unprotect(); _isProtected = true; - _owner = player; + _owner = character; if (_owner == null) { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java index 459660c7ca..92837e4b25 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/L2Object.java @@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab return false; } + /** + * Verify if object is a fake player. + * @return {@code true} if object is a fake player, {@code false} otherwise + */ + public boolean isFakePlayer() + { + return false; + } + /** * Verify if object is instance of L2ServitorInstance. * @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 2ecce60d39..ddc1a1b8d4 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.L2Item; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; @@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc public synchronized boolean getMustRewardExpSP() { - return _mustGiveExpSp; + return _mustGiveExpSp && !isFakePlayer(); } /** @@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc // Don't drop anything if the last attacker or owner isn't L2PcInstance if (player == null) { + // unless its a fake player and they can drop items + if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS) + { + final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer); + if (deathItems != null) + { + for (ItemHolder drop : deathItems) + { + final L2Item item = ItemTable.getInstance().getTemplate(drop.getId()); + // Check if the autoLoot mode is active + if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS)))) + { + // do nothing + } + else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect()) + { + for (SkillHolder skillHolder : item.getAllSkills()) + { + SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false); + } + mainDamageDealer.broadcastInfo(); // ? check if this is necessary + } + else + { + final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground + if (Config.FAKE_PLAYER_CAN_PICKUP) + { + mainDamageDealer.getFakePlayerDrops().add(droppedItem); + } + } + } + } + } return; } @@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc */ public void doEventDrop(L2Character lastAttacker) { - if (lastAttacker == null) + if ((lastAttacker == null) || isFakePlayer()) { return; } @@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc _harvestItem.set(null); _sweepItems.set(null); + // fake players + if (isFakePlayer()) + { + getFakePlayerDrops().clear(); // Clear existing fake player drops + setReputation(0); // reset reputation + setScriptValue(0); // remove pvp flag + setRunning(); // don't walk + } + // Clear mod Seeded stat _seeded = false; _seed = null; diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 226b8e981a..6dd50e079f 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -30,6 +30,7 @@ import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.CharEffectList; @@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack; import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType; import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType; import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private int _reputation = 0; + /** Map containing all skills of this character. */ private final Map _skills = new ConcurrentSkipListMap<>(); /** Map containing the skill reuse time stamps. */ @@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe /** A set containing the shot types currently charged. */ private Set _chargedShots = EnumSet.noneOf(ShotType.class); + /** A list containing the dropped items of this fake player. */ + private final List _fakePlayerDrops = new CopyOnWriteArrayList<>(); + /** * Creates a creature. * @param template the creature template @@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe broadcastPacket(attack); } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) + { + final L2Npc npc = ((L2Npc) this); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + // Notify AI with EVT_READY_TO_ACT ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk); } @@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean isInsidePeaceZone(L2Object attacker, L2Object target) { final Instance instanceWorld = getInstanceWorld(); - if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) + if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) { return false; } @@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist()); } + public int getReputation() + { + return _reputation; + } + + public void setReputation(int reputation) + { + _reputation = reputation; + } + /** * Gets the distance to target. * @param target the target @@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { _cursorKeyMovement = value; } + + public List getFakePlayerDrops() + { + return _fakePlayerDrops; + } } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index 5742c07807..b669e16e76 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; +import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.handler.BypassHandler; import com.l2jmobius.gameserver.handler.IBypassHandler; import com.l2jmobius.gameserver.instancemanager.CastleManager; @@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.olympiad.Olympiad; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate; +import com.l2jmobius.gameserver.model.stats.Formulas; import com.l2jmobius.gameserver.model.variables.NpcVariables; import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.NpcStringId; @@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState; import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse; import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec import com.l2jmobius.gameserver.network.serverpackets.NpcSay; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; +import com.l2jmobius.gameserver.network.serverpackets.UserInfo; import com.l2jmobius.gameserver.taskmanager.DecayTaskManager; import com.l2jmobius.gameserver.util.Broadcast; @@ -125,6 +130,7 @@ public class L2Npc extends L2Character private boolean _isRandomAnimationEnabled = true; private boolean _isRandomWalkingEnabled = true; private boolean _isTalkable = getTemplate().isTalkable(); + private final boolean _isFakePlayer = getTemplate().isFakePlayer(); protected RandomAnimationTask _rAniTask; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -364,7 +370,11 @@ public class L2Npc extends L2Character return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo(this, player)); } @@ -901,6 +911,78 @@ public class L2Npc extends L2Character final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null; _killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0; + if (isFakePlayer() && (killer != null) && killer.isPlayable()) + { + final L2PcInstance player = killer.getActingPlayer(); + if (isScriptValue(0) && (getReputation() >= 0)) + { + if (Config.FAKE_PLAYER_KILL_KARMA) + { + player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon())); + player.setPkKills(player.getPkKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + player.checkItemRestriction(); + // pk item rewards + if (Config.REWARD_PK_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } + // announce pk + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + else if (Config.FAKE_PLAYER_KILL_PVP) + { + player.setPvpKills(player.getPvpKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + // pvp item rewards + if (Config.REWARD_PVP_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + } + // announce pvp + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + DecayTaskManager.getInstance().add(this); final L2Spawn spawn = getSpawn(); @@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character activeChar.sendMessage("Added NPC: " + getName()); } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + activeChar.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { activeChar.sendPacket(new ServerObjectInfo(this, activeChar)); } @@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character @Override public void rechargeShots(boolean physical, boolean magic, boolean fish) { - if (physical && (_soulshotamount > 0)) + if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS) { - if (Rnd.get(100) > getTemplate().getSoulShotChance()) + if (physical) { - return; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic) + { + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _soulshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); - chargeShot(ShotType.SOULSHOTS); } - - if (magic && (_spiritshotamount > 0)) + else { - if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + if (physical && (_soulshotamount > 0)) { - return; + if (Rnd.get(100) > getTemplate().getSoulShotChance()) + { + return; + } + _soulshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic && (_spiritshotamount > 0)) + { + if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + { + return; + } + _spiritshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _spiritshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); - chargeShot(ShotType.SPIRITSHOTS); } } @@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character /** * Drops an item. - * @param player the last attacker or main damage dealer + * @param character the last attacker or main damage dealer * @param itemId the item ID * @param itemCount the item count * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount) + public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount) { L2ItemInstance item = null; for (int i = 0; i < itemCount; i++) @@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character return null; } - item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this); + item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this); if (item == null) { return null; } - if (player != null) + if (character != null) { - item.getDropProtection().protect(player); + item.getDropProtection().protect(character); } item.dropMe(this, newX, newY, newZ); @@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character } /** - * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)} - * @param player the last attacker or main damage dealer + * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)} + * @param character the last attacker or main damage dealer * @param item the item holder * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item) + public L2ItemInstance dropItem(L2Character character, ItemHolder item) { - return dropItem(player, item.getId(), item.getCount()); + return dropItem(character, item.getId(), item.getCount()); } @Override @@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character return Config.SHOP_MIN_RANGE_FROM_NPC; } + @Override + public boolean isFakePlayer() + { + return _isFakePlayer; + } + /** * @return The player's object Id this NPC is cloning. */ diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java index 34550c3dd8..10ad419ea4 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Playable.java @@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character public abstract void doPickupItem(L2Object object); - public abstract int getReputation(); - public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove); public abstract void storeMe(); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index dab0c5323a..80c2783883 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } @@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable { setTarget(target); getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); + if (target.isFakePlayer()) + { + getOwner().updatePvPStatus(); + } } } } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java index a5fd31dedd..44ee919058 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java @@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java index aa4f132fce..6a94be63b5 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java @@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { - if (attacker.isMonster()) + if (attacker.isMonster() && !attacker.isFakePlayer()) { return true; } @@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); } + if (isFakePlayer() && isInCombat()) + { + interact = false; + // TODO: Fix normal targeting + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); + } + // Check if the L2PcInstance already target the L2GuardInstance if (getObjectId() != player.getTargetId()) { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java index e9a9976e87..fe55288a3a 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java @@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { + if (isFakePlayer()) + { + return isInCombat() || attacker.isMonster() || (getScriptValue() > 0); + } + // Check if the L2MonsterInstance target is aggressive if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance)) { @@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable if (attacker.isMonster()) { - return false; + return attacker.isFakePlayer(); } // Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints. diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 6a4bd24efe..9429bcdb82 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -444,9 +444,6 @@ public final class L2PcInstance extends L2Playable /** The Experience of the L2PcInstance before the last Death Penalty */ private long _expBeforeDeath; - /** The Reputation of the L2PcInstance */ - private int _reputation; - /** The number of player killed during a PvP (the player killed was PvP Flagged) */ private int _pvpKills; @@ -1991,24 +1988,16 @@ public final class L2PcInstance extends L2Playable return _expBeforeDeath; } - /** - * @return the reputation of the PlayerInstance. - */ - @Override - public int getReputation() - { - return _reputation; - } - public void setInitialReputation(int reputation) { - _reputation = reputation; + super.setReputation(reputation); } /** * Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast). * @param reputation */ + @Override public void setReputation(int reputation) { // Notify to scripts. @@ -2034,7 +2023,9 @@ public final class L2PcInstance extends L2Playable } }); } - _reputation = reputation; + + super.setReputation(reputation); + sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation())); broadcastReputation(); } @@ -4654,6 +4645,10 @@ public final class L2PcInstance extends L2Playable { super.doAttack(target); setRecentFakeDeath(false); + if (target.isFakePlayer()) + { + updatePvPStatus(); + } } @Override @@ -4981,22 +4976,42 @@ public final class L2PcInstance extends L2Playable if (killer != null) { final L2PcInstance pk = killer.getActingPlayer(); - if (pk != null) + final boolean fpcKill = killer.isFakePlayer(); + if ((pk != null) || fpcKill) { - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); - - if (L2Event.isParticipant(pk)) + if (pk != null) { - pk.getEventStatus().addKill(this); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); + + if (L2Event.isParticipant(pk)) + { + pk.getEventStatus().addKill(this); + } + + // pvp/pk item rewards + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + // pvp + if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) + { + pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + // pk + if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) + { + pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } } // announce pvp/pk - if (Config.ANNOUNCE_PK_PVP && !pk.isGM()) + if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill)) { String msg = ""; if (getPvpFlag() == 0) { - msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5010,7 +5025,7 @@ public final class L2PcInstance extends L2Playable } else if (getPvpFlag() != 0) { - msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5024,20 +5039,9 @@ public final class L2PcInstance extends L2Playable } } - // pvp/pk item rewards - if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // - !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0)) { - // pvp - if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) - { - pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); - } - // pk - if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) - { - pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); - } + killer.setReputation(killer.getReputation() - 150); } } @@ -5630,6 +5634,14 @@ public final class L2PcInstance extends L2Playable return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks()); } + /** + * Used by fake players to emulate proper behavior. + */ + public void blockRequest() + { + _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND); + } + /** * Select the Warehouse to be used in next activity. * @param partner @@ -11569,7 +11581,7 @@ public final class L2PcInstance extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addPcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java index fb6b184e67..8383d1efc9 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java @@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc return null; } + @Override public int getReputation() { return _owner != null ? _owner.getReputation() : 0; @@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addCharName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); _owner.sendPacket(sm); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java index a97eab382d..26a51be541 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java @@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus } } - if (attacker.isPlayable() && (caster.getCurrentCp() > 0)) + if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0)) { if (caster.getCurrentCp() > transferDmg) { @@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus } } - if (!ignoreCP && attacker.isPlayable()) + if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer())) { if (getCurrentCp() >= value) { @@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus // Send a System Message to the L2PcInstance SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addCharName(attacker); + smsg.addString(attacker.getName()); smsg.addInt(fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java index 2d7f41e9d0..f5bee5dab6 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java @@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable private boolean _randomWalk; private boolean _randomAnimation; private boolean _flying; + private boolean _fakePlayer; + private boolean _fakePlayerTalkable; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; @@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable _randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard")); _randomAnimation = set.getBoolean("randomAnimation", true); _flying = set.getBoolean("flying", false); + _fakePlayer = set.getBoolean("fakePlayer", false); + _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true); _canMove = set.getBoolean("canMove", true); _noSleepMode = set.getBoolean("noSleepMode", false); _passableDoor = set.getBoolean("passableDoor", false); @@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable return _flying; } + public boolean isFakePlayer() + { + return _fakePlayer; + } + + public boolean isFakePlayerTalkable() + { + return _fakePlayerTalkable; + } + public boolean canMove() { return _canMove; @@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null) { @@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null) { @@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable case LUCKY_DROP: { // try chance before luck - if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck()) + if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck()) { return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax())); } @@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // chance double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER; // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE; } @@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // amount is calculated after chance returned success double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER; // premium amount - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT; } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java index df9698d3c3..6cbe42b242 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.events.impl.item; -import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.events.EventType; import com.l2jmobius.gameserver.model.events.impl.IBaseEvent; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; @@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent { private final String _process; private final L2ItemInstance _item; - private final L2PcInstance _activeChar; + private final L2Character _activeChar; private final Object _reference; - public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference) + public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference) { _process = process; _item = item; @@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent return _item; } - public L2PcInstance getActiveChar() + public L2Character getActiveChar() { return _activeChar; } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java new file mode 100644 index 0000000000..3008d340b3 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java @@ -0,0 +1,60 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Mobius + */ +public class FakePlayerChatHolder +{ + private final String _fpcName; + private final String _searchMethod; + private final List _searchText; + private final List _answers; + + public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers) + { + _fpcName = fpcName; + _searchMethod = searchMethod; + _searchText = new ArrayList<>(Arrays.asList(searchText.split(";"))); + _answers = new ArrayList<>(Arrays.asList(answers.split(";"))); + } + + public String getFpcName() + { + return _fpcName; + } + + public String getSearchMethod() + { + return _searchMethod; + } + + public List getSearchText() + { + return _searchText; + } + + public List getAnswers() + { + return _answers; + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java new file mode 100644 index 0000000000..2f8aa1fa6d --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java @@ -0,0 +1,232 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class FakePlayerHolder +{ + private final int _classId; + private final int _hair; + private final int _hairColor; + private final int _face; + private final int _nameColor; + private final int _titleColor; + private final int _equipHead; + private final int _equipRHand; + private final int _equipLHand; + private final int _equipGloves; + private final int _equipChest; + private final int _equipLegs; + private final int _equipFeet; + private final int _equipCloak; + private final int _equipHair; + private final int _equipHair2; + private final int _agathionId; + private final int _weaponEnchantLevel; + private final int _armorEnchantLevel; + private final boolean _fishing; + private final int _baitLocationX; + private final int _baitLocationY; + private final int _baitLocationZ; + private final int _recommends; + private final int _nobleLevel; + private final boolean _hero; + private final int _clanId; + private final int _pledgeStatus; + + public FakePlayerHolder(StatsSet set) + { + _classId = set.getInt("classId", 182); + + _hair = set.getInt("hair", 1); + _hairColor = set.getInt("hairColor", 1); + _face = set.getInt("face", 1); + + _nameColor = set.getInt("nameColor", 0xFFFFFF); + _titleColor = set.getInt("titleColor", 0xECF9A2); + + _equipHead = set.getInt("equipHead", 0); + _equipRHand = set.getInt("equipRHand", 0); // or dual hand + _equipLHand = set.getInt("equipLHand", 0); + _equipGloves = set.getInt("equipGloves", 0); + _equipChest = set.getInt("equipChest", 0); + _equipLegs = set.getInt("equipLegs", 0); + _equipFeet = set.getInt("equipFeet", 0); + _equipCloak = set.getInt("equipCloak", 0); + _equipHair = set.getInt("equipHair", 0); + _equipHair2 = set.getInt("equipHair2", 0); + _agathionId = set.getInt("agathionId", 0); + + _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0); + _armorEnchantLevel = set.getInt("armorEnchantLevel", 0); + + _fishing = set.getBoolean("fishing", false); + _baitLocationX = set.getInt("baitLocationX", 0); + _baitLocationY = set.getInt("baitLocationY", 0); + _baitLocationZ = set.getInt("baitLocationZ", 0); + + _recommends = set.getInt("recommends", 0); + _nobleLevel = set.getInt("nobleLevel", 0); + _hero = set.getBoolean("hero", false); + _clanId = set.getInt("clanId", 0); + _pledgeStatus = set.getInt("pledgeStatus", 0); + } + + public int getClassId() + { + return _classId; + } + + public int getHair() + { + return _hair; + } + + public int getHairColor() + { + return _hairColor; + } + + public int getFace() + { + return _face; + } + + public int getNameColor() + { + return _nameColor; + } + + public int getTitleColor() + { + return _titleColor; + } + + public int getEquipHead() + { + return _equipHead; + } + + public int getEquipRHand() + { + return _equipRHand; + } + + public int getEquipLHand() + { + return _equipLHand; + } + + public int getEquipGloves() + { + return _equipGloves; + } + + public int getEquipChest() + { + return _equipChest; + } + + public int getEquipLegs() + { + return _equipLegs; + } + + public int getEquipFeet() + { + return _equipFeet; + } + + public int getEquipCloak() + { + return _equipCloak; + } + + public int getEquipHair() + { + return _equipHair; + } + + public int getEquipHair2() + { + return _equipHair2; + } + + public int getAgathionId() + { + return _agathionId; + } + + public int getWeaponEnchantLevel() + { + return _weaponEnchantLevel; + } + + public int getArmorEnchantLevel() + { + return _armorEnchantLevel; + } + + public boolean isFishing() + { + return _fishing; + } + + public int getBaitLocationX() + { + return _baitLocationX; + } + + public int getBaitLocationY() + { + return _baitLocationY; + } + + public int getBaitLocationZ() + { + return _baitLocationZ; + } + + public int getRecommends() + { + return _recommends; + } + + public int getNobleLevel() + { + return _nobleLevel; + } + + public boolean isHero() + { + return _hero; + } + + public int getClanId() + { + return _clanId; + } + + public int getPledgeStatus() + { + return _pledgeStatus; + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index c5af087f72..551733f42a 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object *
    *
  • Do Pickup Item : PCInstance and Pet

  • *
    - * @param player Player that pick up the item + * @param character Character that pick up the item */ - public final void pickupMe(L2Character player) + public final void pickupMe(L2Character character) { assert getWorldRegion() != null; final L2WorldRegion oldregion = getWorldRegion(); // Create a server->client GetItem packet to pick up the L2ItemInstance - player.broadcastPacket(new GetItem(this, player.getObjectId())); + character.broadcastPacket(new GetItem(this, character.getObjectId())); synchronized (this) { @@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object // Remove the L2ItemInstance from the world L2World.getInstance().removeVisibleObject(this, oldregion); - if (player.isPlayer()) + if (character.isPlayer()) { // Notify to scripts - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem()); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem()); } } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java index 83f6e88b77..7505001c60 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable public boolean checkCondition(L2Character activeChar, L2Object object) { - if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION) + if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)) { return true; } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index b7eda58d00..13932008ff 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -159,7 +160,7 @@ public class SkillCaster implements Runnable } // You should not heal/buff monsters without pressing the ctrl button. - if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed) + if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed) { caster.sendPacket(SystemMessageId.INVALID_TARGET); return null; @@ -609,6 +610,10 @@ public class SkillCaster implements Runnable // Add hate to the attackable, and put it in the attack list. ((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint()); ((L2Character) obj).addAttackerToAttackByList(caster); + if (obj.isFakePlayer()) + { + player.updatePvPStatus(); + } } // notify target AI about the attack @@ -617,10 +622,19 @@ public class SkillCaster implements Runnable ((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster); } } - else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0)))) + else if (((skill.getEffectPoint() > 0) && obj.isMonster()) // + || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) // + || (((L2Character) obj).getReputation() < 0) // + ))) { // Supporting players or monsters result in pvpflag. - player.updatePvPStatus(); + if (!obj.isFakePlayer() // + || (obj.isFakePlayer() // + && (!((L2Npc) obj).isScriptValue(0) // + || (((L2Npc) obj).getReputation() < 0)))) + { + player.updatePvPStatus(); + } } } @@ -630,7 +644,7 @@ public class SkillCaster implements Runnable EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob); // On Skill See logic - if (npcMob.isAttackable()) + if (npcMob.isAttackable() && !npcMob.isFakePlayer()) { final L2Attackable attackable = (L2Attackable) npcMob; @@ -652,6 +666,19 @@ public class SkillCaster implements Runnable } }); } + else if (caster.isFakePlayer()) // fake player attacks player + { + if (target.isPlayable() || target.isFakePlayer()) + { + final L2Npc npc = ((L2Npc) caster); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + npc.broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + } } catch (Exception e) { @@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable return false; } } - return true; } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java index fdf0dadf55..06bea1b4cf 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java @@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.zone.L2ZoneType; import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; @@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } @@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java index 91a9ce830a..ccd2d1d13a 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/Action.java @@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket } case 1: { - if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC)) + if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer())) { obj.onAction(activeChar, false); } diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java index 876c53c093..06464d9911 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java @@ -22,6 +22,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData; import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData; import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; @@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket return; } - if (Config.FORBIDDEN_NAMES.length > 1) + if (Config.FORBIDDEN_NAMES.length > 0) { for (String st : Config.FORBIDDEN_NAMES) { @@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().getProperName(_name) != null) + { + client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); + return; + } + // Last Verified: May 30, 2009 - Gracia Final if (!Util.isAlphaNumeric(_name) || !isValidName(_name)) { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java index 06bfa3c200..01c8b0c67f 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java @@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; public final class RequestBlock implements IClientIncomingPacket { @@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket case BLOCK: case UNBLOCK: { + // TODO: Save in database? :P + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (_type == BLOCK) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + return; + } + // can't use block/unblock for locating invisible characters if (targetId <= 0) { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java index ceb67b0f5f..cf79bdb24c 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable; import com.l2jmobius.gameserver.util.Util; @@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket { result = NAME_ALREADY_EXISTS; } + else if (FakePlayerData.getInstance().getProperName(_name) != null) + { + result = NAME_ALREADY_EXISTS; + } else if (_name.length() > 16) { result = INVALID_LENGTH; diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java index b0ace828dc..ee8bcd656b 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java @@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Party; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart; @@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance activeChar = client.getActiveChar(); - final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (activeChar == null) { return; } + + if (FakePlayerData.getInstance().isTalkable(_player)) + { + final String name = FakePlayerData.getInstance().getProperName(_player); + if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + if (activeChar.isProcessingRequest()) + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(name); + activeChar.sendPacket(msg); + return; + } + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL); + sm.addString(name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000); + activeChar.blockRequest(); + return; + } + + final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (targetChar == null) { activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java index f104c94161..c0042d45c5 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java @@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PartyDistributionType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Party; @@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + if (player.getParty() == null) + { + player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED); + } + else + { + player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY); + } + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance requestor = client.getActiveChar(); - final L2PcInstance target = L2World.getInstance().getPlayer(_name); - if (requestor == null) { return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + requestor.sendPacket(sm); + if (!requestor.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000); + requestor.blockRequest(); + } + else + { + requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY); + } + return; + } + + final L2PcInstance target = L2World.getInstance().getPlayer(_name); if (target == null) { requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java index 292153afd8..37c539556f 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java @@ -17,12 +17,15 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; /** * This class ... @@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket return; } + if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName()))) + { + if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0) + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN); + } + else + { + if (!activeChar.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(activeChar.getTarget().getName()); + activeChar.sendPacket(msg); + } + } + return; + } + final L2PcInstance target = L2World.getInstance().getPlayer(_target); if (target == null) { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java index 3d5bcaeca5..9cbb114e88 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java @@ -23,6 +23,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.instancemanager.MailManager; import com.l2jmobius.gameserver.model.BlockList; @@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().isTalkable(_receiver)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1); + sm.addString(FakePlayerData.getInstance().getProperName(_receiver)); + activeChar.sendPacket(sm); + return; + } + final int receiverId = CharNameTable.getInstance().getIdByName(_receiver); if (receiverId <= 0) { diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java index 8156905e94..1336c2bdb7 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java @@ -17,6 +17,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; @@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket } final L2Object object = activeChar.getTarget(); - if (!(object instanceof L2PcInstance)) { if (object == null) { client.sendPacket(SystemMessageId.SELECT_TARGET); } + else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName())) + { + if (activeChar.getRecomLeft() <= 0) + { + client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER); + return; + } + + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT); + sm.addString(FakePlayerData.getInstance().getProperName(object.getName())); + sm.addInt(activeChar.getRecomLeft()); + client.sendPacket(sm); + + activeChar.setRecomLeft(activeChar.getRecomLeft() - 1); + client.sendPacket(new UserInfo(activeChar)); + client.sendPacket(new ExVoteSystemInfo(activeChar)); + } else { client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java index d77dc881b3..5d7e35eb43 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java @@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.effects.AbstractEffect; import com.l2jmobius.gameserver.model.skills.AbnormalType; @@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final String name = FakePlayerData.getInstance().getProperName(target.getName()); + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE)); + return; + } + if (!player.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1); + sm.addString(name); + player.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000); + player.blockRequest(); + } + else + { + player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE); + } + return; + } + if (!target.isPlayer()) { client.sendPacket(SystemMessageId.INVALID_TARGET); diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java index 4fa25283a7..530a6d7a01 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java @@ -17,6 +17,8 @@ package com.l2jmobius.gameserver.network.clientpackets.friend; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST)); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (!activeChar.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST); + sm.addString(_name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + sm.addString(_name); + activeChar.sendPacket(sm); + } + return; + } + final L2PcInstance friend = L2World.getInstance().getPlayer(_name); // Target is not found in the game. diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java index 2170ef2e94..017541bd86 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java @@ -22,6 +22,7 @@ import java.util.List; import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.instancemanager.MentorManager; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.NpcStringId; import com.l2jmobius.gameserver.network.OutgoingPackets; @@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket _charLevel = sender.getLevel(); _textType = messageType; _text = text; - if (receiver.getFriendList().contains(sender.getObjectId())) + if (receiver != null) { - _mask |= 0x01; - } - if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) - { - _mask |= 0x02; - } - if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) - { - _mask |= 0x04; - } - if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) - { - _mask |= 0x08; + if (receiver.getFriendList().contains(sender.getObjectId())) + { + _mask |= 0x01; + } + if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) + { + _mask |= 0x02; + } + if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) + { + _mask |= 0x04; + } + if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) + { + _mask |= 0x08; + } } // Does not shows level @@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket } } + /** + * Used by fake players. + * @param sender + * @param receiver + * @param name + * @param messageType + * @param text + */ + public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text) + { + _objectId = sender.getObjectId(); + _charName = name; + _charLevel = sender.getLevel(); + _textType = messageType; + _text = text; + } + /** * @param objectId * @param messageType diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java new file mode 100644 index 0000000000..d1b7900f12 --- /dev/null +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java @@ -0,0 +1,231 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.network.serverpackets; + +import java.util.Set; + +import com.l2jmobius.commons.network.PacketWriter; +import com.l2jmobius.gameserver.data.sql.impl.ClanTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.enums.Sex; +import com.l2jmobius.gameserver.model.L2Clan; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; +import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect; +import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.OutgoingPackets; + +/** + * @author Mobius + */ +public class FakePlayerInfo implements IClientOutgoingPacket +{ + private final L2Npc _npc; + private final int _objId; + private final int _x, _y, _z, _heading; + private final int _mAtkSpd, _pAtkSpd; + private final int _runSpd, _walkSpd; + private final int _swimRunSpd; + private final int _swimWalkSpd; + private final int _flyRunSpd; + private final int _flyWalkSpd; + private final double _moveMultiplier; + private final float _attackSpeedMultiplier; + private final FakePlayerHolder _fpcHolder; + private final L2Clan _clan; + + public FakePlayerInfo(L2Npc npc) + { + _npc = npc; + _objId = npc.getObjectId(); + _x = npc.getX(); + _y = npc.getY(); + _z = npc.getZ(); + _heading = npc.getHeading(); + _mAtkSpd = npc.getMAtkSpd(); + _pAtkSpd = npc.getPAtkSpd(); + _attackSpeedMultiplier = npc.getAttackSpeedMultiplier(); + _moveMultiplier = npc.getMovementSpeedMultiplier(); + _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier); + _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier); + _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier); + _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier); + _flyRunSpd = npc.isFlying() ? _runSpd : 0; + _flyWalkSpd = npc.isFlying() ? _walkSpd : 0; + _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId()); + _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId()); + } + + @Override + public boolean write(PacketWriter packet) + { + OutgoingPackets.CHAR_INFO.writeId(packet); + packet.writeD(_x); + packet.writeD(_y); + packet.writeD(_z); + packet.writeD(0x00); // vehicleId + packet.writeD(_objId); + packet.writeS(_npc.getName()); + + packet.writeH(_npc.getRace().ordinal()); + packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00); + packet.writeD(_fpcHolder.getClassId()); + + packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER + packet.writeD(_fpcHolder.getEquipHead()); + packet.writeD(_fpcHolder.getEquipRHand()); + packet.writeD(_fpcHolder.getEquipLHand()); + packet.writeD(_fpcHolder.getEquipGloves()); + packet.writeD(_fpcHolder.getEquipChest()); + packet.writeD(_fpcHolder.getEquipLegs()); + packet.writeD(_fpcHolder.getEquipFeet()); + packet.writeD(_fpcHolder.getEquipCloak()); + packet.writeD(_fpcHolder.getEquipRHand()); // dual hand + packet.writeD(_fpcHolder.getEquipHair()); + packet.writeD(_fpcHolder.getEquipHair2()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderAugument()) + { + packet.writeQ(0x00); + } + + packet.writeC(_fpcHolder.getArmorEnchantLevel()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderVisualId()) + { + packet.writeD(0x00); + } + + packet.writeC(_npc.getScriptValue()); // getPvpFlag() + packet.writeD(_npc.getReputation()); + + packet.writeD(_mAtkSpd); + packet.writeD(_pAtkSpd); + + packet.writeH(_runSpd); + packet.writeH(_walkSpd); + packet.writeH(_swimRunSpd); + packet.writeH(_swimWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeF(_moveMultiplier); + packet.writeF(_attackSpeedMultiplier); + + packet.writeF(_npc.getCollisionRadius()); + packet.writeF(_npc.getCollisionHeight()); + + packet.writeD(_fpcHolder.getHair()); + packet.writeD(_fpcHolder.getHairColor()); + packet.writeD(_fpcHolder.getFace()); + + packet.writeS(_npc.getTemplate().getTitle()); + + if (_clan != null) + { + packet.writeD(_clan.getId()); + packet.writeD(_clan.getCrestId()); + packet.writeD(_clan.getAllyId()); + packet.writeD(_clan.getAllyCrestId()); + } + else + { + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + } + + packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked) + packet.writeC(_npc.isRunning() ? 0x01 : 0x00); + packet.writeC(_npc.isInCombat() ? 0x01 : 0x00); + + packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00); + + packet.writeC(_npc.isInvisible() ? 0x01 : 0x00); + + packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount + packet.writeC(0x00); // getPrivateStoreType().getId() + + packet.writeH(0x00); // getCubics().size() + // getCubics().keySet().forEach(packet::writeH); + + packet.writeC(0x00); + + packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0); + packet.writeH(_fpcHolder.getRecommends()); + packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000 + + packet.writeD(_fpcHolder.getClassId()); + packet.writeD(0x00); + packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel + + packet.writeC(_npc.getTeam().getId()); + + packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00); + packet.writeC(_fpcHolder.getNobleLevel()); + packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00); + + packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00); + + packet.writeD(_fpcHolder.getBaitLocationX()); + packet.writeD(_fpcHolder.getBaitLocationY()); + packet.writeD(_fpcHolder.getBaitLocationZ()); + + packet.writeD(_fpcHolder.getNameColor()); + + packet.writeD(_heading); + + packet.writeC(_fpcHolder.getPledgeStatus()); + packet.writeH(0x00); // getPledgeType() + + packet.writeD(_fpcHolder.getTitleColor()); + + packet.writeC(0x00); // isCursedWeaponEquipped + + packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0 + packet.writeD(0x00); // getTransformationDisplayId() + packet.writeD(_fpcHolder.getAgathionId()); + + packet.writeC(0x00); + + packet.writeD(0x00); // getCurrentCp() + packet.writeD(_npc.getMaxHp()); + packet.writeD((int) Math.round(_npc.getCurrentHp())); + packet.writeD(_npc.getMaxMp()); + packet.writeD((int) Math.round(_npc.getCurrentMp())); + + packet.writeC(0x00); + final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects(); + packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0)); + for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects) + { + packet.writeH(abnormalVisualEffect.getClientId()); + } + if (_npc.isInvisible()) + { + packet.writeH(AbnormalVisualEffect.STEALTH.getClientId()); + } + packet.writeC(0x00); // cocPlayer.getPosition() + packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00); + packet.writeC(0x00); // Used Ability Points + return true; + } +} diff --git a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index 4fb1a757e6..c294edab2a 100644 --- a/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_2.5_Underground/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket addComponentType(NpcInfoType.TITLE_NPCSTRINGID); } + if (_npc.getReputation() != 0) + { + addComponentType(NpcInfoType.REPUTATION); + } + if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible()) { addComponentType(NpcInfoType.ABNORMALS); @@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.REPUTATION)) { - packet.writeD(0x00); // Name color + packet.writeD(_npc.getReputation()); // Reputation } if (containsMask(NpcInfoType.CLAN)) { diff --git a/L2J_Mobius_2.5_Underground/readme.txt b/L2J_Mobius_2.5_Underground/readme.txt index 51ce661fc2..96437b02b9 100644 --- a/L2J_Mobius_2.5_Underground/readme.txt +++ b/L2J_Mobius_2.5_Underground/readme.txt @@ -94,6 +94,7 @@ Customs: -Classmaster -Community board -Faction system +-Fake players -Find PvP -NPC stat multipliers -Realtime offline trade diff --git a/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml b/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml index 171e08cb12..f9067f1377 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/config/AdminCommands.xml @@ -392,6 +392,9 @@ + + + diff --git a/L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini new file mode 100644 index 0000000000..f745b0d31e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/config/Custom/FakePlayers.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------------------- +# Fake players +# --------------------------------------------------------------------------- + +# Enable fake players. +EnableFakePlayers = False + +# Enable chatting with fake players. +FakePlayerChat = True + +# Enable shots usage for fake players. +FakePlayerUseShots = True + +# Reward PvP kills by killing fake players. +FakePlayerKillsRewardPvP = True + +# Fake player kills apply karma rules. +FakePlayerUnflaggedKillsKarma = True + +# Aggressive AI fake players attack nearby monsters. +FakePlayerAggroMonsters = True + +# Aggressive AI fake players attack nearby players. +FakePlayerAggroPlayers = False + +# Aggressive AI fake players attack nearby fake players. +FakePlayerAggroFPC = False + +# Fake players can drop items when killing monsters. +FakePlayerCanDropItems = True + +# Fake players can pickup dropped items. +FakePlayerCanPickup = True diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml new file mode 100644 index 0000000000..f5da5bfc8e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerChatData.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml new file mode 100644 index 0000000000..f36096ed4a --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/FakePlayerVisualData.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml index 98e0d38815..e87880bdd1 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml +++ b/L2J_Mobius_3.0_Helios/dist/game/data/Routes.xml @@ -2402,4 +2402,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java index 6f29855cc3..d12ee2e7c4 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java @@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI final L2Character creature = event.getSeen(); final L2Npc npc = (L2Npc) event.getSeer(); - if (creature.isPlayer()) + if (creature.isPlayer() || creature.isFakePlayer()) { npc.setTarget(creature); npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill()); diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java new file mode 100644 index 0000000000..e1dde7324e --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java @@ -0,0 +1,80 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +import ai.AbstractNpcAI; + +/** + * TODO: Move it to L2Character. + * @author Mobius + */ +public class PvpFlaggingStopTask extends AbstractNpcAI +{ + private PvpFlaggingStopTask() + { + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if ((npc == null) || npc.isDead()) + { + return null; + } + + if (event.startsWith("FLAG_CHECK")) + { + final L2Object target = npc.getTarget(); + if ((target != null) && (target.isPlayable() || target.isFakePlayer())) + { + npc.setScriptValue(1); // in combat + cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null); + cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null); + startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null); + startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null); + } + } + else if (event.startsWith("FINISH_FLAG")) + { + if (npc.isScriptValue(1)) + { + npc.setScriptValue(2); // blink status + npc.broadcastInfo(); // update flag status + startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null); + } + } + else if (event.startsWith("REMOVE_FLAG")) + { + if (npc.isScriptValue(2)) + { + npc.setScriptValue(0); // not in combat + npc.broadcastInfo(); // update flag status + } + } + return super.onAdvEvent(event, npc, player); + } + + public static void main(String[] args) + { + new PvpFlaggingStopTask(); + } +} diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java new file mode 100644 index 0000000000..dec3449549 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java @@ -0,0 +1,115 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.CommonUtil; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.base.ClassId; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.SkillCaster; + +import ai.AbstractNpcAI; + +/** + * Town Fake Player walkers that receive buffs from Adventurer NPC. + * @author Mobius + */ +public class RecieveAdventurerBuffs extends AbstractNpcAI +{ + // NPCs + private static final int[] ADVENTURERS_GUIDE = + { + 32327, + 33950, + }; + private static final int[] FAKE_PLAYER_IDS = + { + 80000 + }; + // Skills + // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer) + private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer) + private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer) + private static final SkillHolder[] GROUP_BUFFS = + { + new SkillHolder(15642, 1), // Horn Melody (Adventurer) + new SkillHolder(15643, 1), // Drum Melody (Adventurer) + new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer) + new SkillHolder(15645, 1), // Guitar Melody (Adventurer) + new SkillHolder(15646, 1), // Harp Melody (Adventurer) + new SkillHolder(15647, 1), // Lute Melody (Adventurer) + new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer) + new SkillHolder(15652, 1), // Daring Sonata (Adventurer) + new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer) + }; + + private RecieveAdventurerBuffs() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + addSpawnId(FAKE_PLAYER_IDS); + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead()) + { + if (!npc.isMoving()) + { + for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100)) + { + if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId())) + { + for (SkillHolder holder : GROUP_BUFFS) + { + SkillCaster.triggerCast(nearby, npc, holder.getSkill()); + } + if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage()) + { + SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill()); + } + else + { + SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill()); + } + break; + } + } + } + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSpawn(L2Npc npc) + { + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new RecieveAdventurerBuffs(); + } +} diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java index 3c72228c33..3228e5fe09 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/MasterHandler.java @@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant; import handlers.admincommandhandlers.AdminEventEngine; import handlers.admincommandhandlers.AdminEvents; import handlers.admincommandhandlers.AdminExpSp; +import handlers.admincommandhandlers.AdminFakePlayers; import handlers.admincommandhandlers.AdminFightCalculator; import handlers.admincommandhandlers.AdminFortSiege; import handlers.admincommandhandlers.AdminGeodata; @@ -410,6 +411,7 @@ public class MasterHandler AdminEventEngine.class, AdminEvents.class, AdminExpSp.class, + AdminFakePlayers.class, AdminFightCalculator.class, AdminFortSiege.class, AdminGeodata.class, diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java index 6b02816d9e..d6d6a99080 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java @@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler } else if (Config.ALT_GAME_VIEWNPC) { - if (!target.isNpc()) + if (!target.isNpc() || target.isFakePlayer()) { return false; } diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java new file mode 100644 index 0000000000..99926f0df7 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java @@ -0,0 +1,77 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package handlers.admincommandhandlers; + +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.handler.IAdminCommandHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +/** + * @author Mobius + */ +public class AdminFakePlayers implements IAdminCommandHandler +{ + private static final String[] ADMIN_COMMANDS = + { + "admin_fakechat" + }; + + @Override + public boolean useAdminCommand(String command, L2PcInstance activeChar) + { + if (command.startsWith("admin_fakechat")) + { + final String[] words = command.substring(15).split(" "); + if (words.length < 3) + { + activeChar.sendMessage("Usage: //fakechat playername fpcname message"); + return false; + } + final L2PcInstance player = L2World.getInstance().getPlayer(words[0]); + if (player == null) + { + activeChar.sendMessage("Player not found."); + return false; + } + final String fpcName = FakePlayerData.getInstance().getProperName(words[1]); + if (fpcName == null) + { + activeChar.sendMessage("Fake player not found."); + return false; + } + String message = ""; + for (int i = 0; i < words.length; i++) + { + if (i < 2) + { + continue; + } + message += (words[i] + " "); + } + FakePlayerChatManager.getInstance().sendChat(player, fpcName, message); + } + return true; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 5da8e115b2..4799a7aa53 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData; import com.l2jmobius.gameserver.data.xml.impl.DoorData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData; import com.l2jmobius.gameserver.data.xml.impl.MultisellData; @@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.WalkingManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.util.Util; @@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data."); break; } + case "fakeplayers": + { + FakePlayerData.getInstance().load(); + for (L2Object obj : L2World.getInstance().getVisibleObjects()) + { + if (obj.isFakePlayer()) + { + obj.broadcastInfo(); + } + } + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data."); + break; + } + case "fakeplayerchat": + { + FakePlayerChatManager.getInstance().load(); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data."); + break; + } default: { activeChar.sendMessage(RELOAD_USAGE); diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java index 99f2e9e9d7..7db79fe31d 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java @@ -17,8 +17,10 @@ package handlers.chathandlers; import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.handler.IChatHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.PcCondOverride; @@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler return; } + if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null)) + { + if (FakePlayerData.getInstance().isTalkable(target)) + { + if (Config.FAKE_PLAYER_CHAT) + { + final String name = FakePlayerData.getInstance().getProperName(target); + activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text)); + FakePlayerChatManager.getInstance().manageChat(activeChar, name, text); + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE); + } + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE); + } + return; + } + final L2PcInstance receiver = L2World.getInstance().getPlayer(target); if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId())) diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java index 41b1f99bcf..b38f5ca16d 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java @@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition { return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel); } - } diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java index 1e34a0d148..087112cc73 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/handlers/playeractions/SocialAction.java @@ -16,9 +16,11 @@ */ package handlers.playeractions; +import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.NextAction; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.handler.IPlayerActionHandler; import com.l2jmobius.gameserver.model.ActionDataHolder; import com.l2jmobius.gameserver.model.L2Object; @@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED); + player.onTransactionResponse(); + } + } + private void useCoupleSocial(L2PcInstance player, int id) { if (player == null) @@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler } final L2Object target = player.getTarget(); - if ((target == null) || !target.isPlayer()) + if ((target == null)) + { + player.sendPacket(SystemMessageId.INVALID_TARGET); + return; + } + + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1); + sm.addString(target.getName()); + player.sendPacket(sm); + if (!player.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000); + player.blockRequest(); + } + return; + } + + if (!target.isPlayer()) { player.sendPacket(SystemMessageId.INVALID_TARGET); return; diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java index 12f33e2bbc..9dd91055b9 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java @@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest @Id(WINDY_HEALING_POTION_1) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(4, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + { + qs.setCond(4, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java index 0efb5383f4..34594dbc40 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java +++ b/L2J_Mobius_3.0_Helios/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java @@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest @Id(HIGH_GRADE_LOVE_POTION) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(2, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + { + qs.setCond(2, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml new file mode 100644 index 0000000000..ea77878c2c --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/spawns/Others/FakePlayers.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml new file mode 100644 index 0000000000..8470293122 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_combat.xml @@ -0,0 +1,341 @@ + + + + + HUMAN + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + ORC + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + DWARF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + KAMAEL + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + HUMAN + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + DARK_ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml new file mode 100644 index 0000000000..589f29b215 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/stats/npcs/custom/fpc_passive.xml @@ -0,0 +1,26 @@ + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd new file mode 100644 index 0000000000..2b2c94e75b --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerChatData.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd new file mode 100644 index 0000000000..0628acefc3 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/FakePlayerVisualData.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd index 6f00944cff..ae80c3ff63 100644 --- a/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd +++ b/L2J_Mobius_3.0_Helios/dist/game/data/xsd/npcs.xsd @@ -201,6 +201,8 @@ + +
    diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java index 0a047f9679..bf72ea7ba4 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/Config.java @@ -116,6 +116,7 @@ public final class Config public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini"; public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini"; public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini"; + public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini"; public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini"; public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini"; public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini"; @@ -1155,6 +1156,16 @@ public final class Config public static boolean FACTION_SPECIFIC_CHAT; public static boolean FACTION_BALANCE_ONLINE_PLAYERS; public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT; + public static boolean FAKE_PLAYERS_ENABLED; + public static boolean FAKE_PLAYER_CHAT; + public static boolean FAKE_PLAYER_USE_SHOTS; + public static boolean FAKE_PLAYER_KILL_PVP; + public static boolean FAKE_PLAYER_KILL_KARMA; + public static boolean FAKE_PLAYER_AGGRO_MONSTERS; + public static boolean FAKE_PLAYER_AGGRO_PLAYERS; + public static boolean FAKE_PLAYER_AGGRO_FPC; + public static boolean FAKE_PLAYER_CAN_DROP_ITEMS; + public static boolean FAKE_PLAYER_CAN_PICKUP; public static boolean ENABLE_FIND_PVP; public static boolean PREMIUM_SYSTEM_ENABLED; public static float PREMIUM_RATE_XP; @@ -2577,6 +2588,19 @@ public final class Config FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true); FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20); + // Load FakePlayers config file (if exists) + final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE); + FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false)); + FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false)); + FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false)); + FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false)); + FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false)); + FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false)); + FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false)); + FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false)); + FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false)); + FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false)); + // Load FindPvP config file (if exists) final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE); ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java index 3d1ce4387e..810ed1ae09 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/GameServer.java @@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData; import com.l2jmobius.gameserver.data.xml.impl.EventEngineData; import com.l2jmobius.gameserver.data.xml.impl.ExperienceData; import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.HennaData; import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData; @@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; import com.l2jmobius.gameserver.instancemanager.DBSpawnManager; import com.l2jmobius.gameserver.instancemanager.FactionManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.FortManager; import com.l2jmobius.gameserver.instancemanager.FortSiegeManager; import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; @@ -288,6 +290,8 @@ public class GameServer printSection("NPCs"); SkillLearnData.getInstance(); NpcData.getInstance(); + FakePlayerData.getInstance(); + FakePlayerChatManager.getInstance(); ExtendDropData.getInstance(); SpawnsData.getInstance(); WalkingManager.getInstance(); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 6253fa9329..1da1b21546 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.model.AggroInfo; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate; import com.l2jmobius.gameserver.model.events.returns.TerminateReturn; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.skills.SkillCaster; @@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10 if (_globalAggro >= 0) { - if (npc.isAggressive() || (npc instanceof L2GuardInstance)) + if (npc.isFakePlayer() && npc.isAggressive()) + { + final List droppedItems = npc.getFakePlayerDrops(); + if (droppedItems.isEmpty()) + { + L2Character nearestTarget = null; + double closestDistance = Double.MAX_VALUE; + for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange())) + { + if ((t == _actor) || (t == null) || t.isDead()) + { + continue; + } + if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer())) + { + final int hating = npc.getHating(t); + final double distance = npc.calculateDistance(t, false, false); + if ((hating == 0) && (closestDistance > distance)) + { + nearestTarget = t; + closestDistance = distance; + } + } + } + if (nearestTarget != null) + { + npc.addDamageHate(nearestTarget, 0, 1); + } + } + else if (!npc.isInCombat()) // must pickup items + { + final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped + final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex); + if ((droppedItem != null) && droppedItem.isSpawned()) + { + if (npc.calculateDistance(droppedItem, false, false) > 50) + { + moveTo(droppedItem); + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + droppedItem.pickupMe(npc); + if (Config.SAVE_DROPPED_ITEM) + { + ItemsOnGroundManager.getInstance().removeObject(droppedItem); + } + if (droppedItem.getItem().hasExImmediateEffect()) + { + for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills()) + { + SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false); + } + npc.broadcastInfo(); // ? check if this is necessary + } + } + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + } + npc.setRunning(); + } + } + else if (npc.isAggressive() || (npc instanceof L2GuardInstance)) { final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players. L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t -> @@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // For each L2Character check if the target is autoattackable if (isAggressiveTowards(t)) // check aggression { - if (t.isPlayable()) + if (t.isFakePlayer()) + { + if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC)) + { + final int hating = npc.getHating(t); + if (hating == 0) + { + npc.addDamageHate(t, 0, 1); + } + } + } + else if (t.isPlayable()) { final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class); if ((term != null) && term.terminate()) diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java new file mode 100644 index 0000000000..0a6ca5267a --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java @@ -0,0 +1,125 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; + +/** + * @author Mobius + */ +public class FakePlayerData implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName()); + + private final Map _fakePlayerInfos = new HashMap<>(); + private final Map _fakePlayerNames = new HashMap<>(); + private final Map _fakePlayerIds = new HashMap<>(); + private final List _talkableFakePlayerNames = new ArrayList<>(); + + protected FakePlayerData() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + _fakePlayerInfos.clear(); + _fakePlayerNames.clear(); + _fakePlayerIds.clear(); + _talkableFakePlayerNames.clear(); + parseDatapackFile("data/FakePlayerVisualData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode)); + final int npcId = set.getInt("npcId"); + final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId); + final String name = template.getName(); + if (CharNameTable.getInstance().getIdByName(name) > 0) + { + LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists."); + } + else + { + _fakePlayerIds.put(name, npcId); // name - npcId + _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name + _fakePlayerInfos.put(npcId, new FakePlayerHolder(set)); + if (template.isFakePlayerTalkable()) + { + _talkableFakePlayerNames.add(name.toLowerCase()); + } + } + })); + } + + public int getNpcIdByName(String name) + { + return _fakePlayerIds.get(name); + } + + public String getProperName(String name) + { + return _fakePlayerNames.get(name.toLowerCase()); + } + + public Boolean isTalkable(String name) + { + return _talkableFakePlayerNames.contains(name.toLowerCase()); + } + + public FakePlayerHolder getInfo(int npcId) + { + return _fakePlayerInfos.get(npcId); + } + + public static FakePlayerData getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerData _instance = new FakePlayerData(); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java index 883e877bc7..f03a2395f1 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java @@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader set.set("hasSummoner", parseBoolean(attrs, "hasSummoner")); set.set("canBeSown", parseBoolean(attrs, "canBeSown")); set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty")); + set.set("fakePlayer", parseBoolean(attrs, "fakePlayer")); + set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable")); break; } case "skill_list": diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java index 2ff4c9322d..15bd310bd6 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java @@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader return; } + if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer()) + { + return; + } + for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) { if ("parameters".equalsIgnoreCase(d.getNodeName())) diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java index a145b65dba..d525c02a6a 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/BotReportTable.java @@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.zone.ZoneId; @@ -210,15 +212,14 @@ public final class BotReportTable public boolean reportBot(L2PcInstance reporter) { final L2Object target = reporter.getTarget(); - if (target == null) { return false; } - final L2PcInstance bot = target.getActingPlayer(); + final L2Character bot = ((L2Character) target); - if ((bot == null) || (target.getObjectId() == reporter.getObjectId())) + if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId())) { return false; } @@ -229,7 +230,7 @@ public final class BotReportTable return false; } - if (bot.isInOlympiadMode()) + if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode()) { reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD); return false; @@ -241,7 +242,7 @@ public final class BotReportTable return false; } - if (bot.getExp() == bot.getStat().getStartingExp()) + if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp())) { reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING); return false; @@ -320,15 +321,18 @@ public final class BotReportTable } SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT); - sm.addCharName(bot); + sm.addString(bot.getName()); reporter.sendPacket(sm); sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT); - sm.addCharName(bot); + sm.addString(bot.getName()); sm.addInt(rcdRep.getPointsLeft()); reporter.sendPacket(sm); - handleReport(bot, rcd); + if (bot.isPlayer()) + { + handleReport(bot.getActingPlayer(), rcd); + } return true; } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java index 7454554076..ace19486b5 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/datatables/ItemTable.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -202,11 +203,11 @@ public class ItemTable * @param process : String Identifier of process triggering this action * @param itemId : int Item Identifier of the item to be created * @param count : int Quantity of items to be created for stackable items - * @param actor : L2PcInstance Player requesting the item creation + * @param actor : L2Character requesting the item creation * @param reference : Object Object referencing current action like NPC selling item or previous item in transformation * @return L2ItemInstance corresponding to the new item */ - public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference) + public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference) { // Create and Init the L2ItemInstance corresponding to the Item Identifier final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java index b621b4c4cb..bb0e928daf 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/idfactory/IdFactory.java @@ -217,6 +217,7 @@ public abstract class IdFactory cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); + cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); // If the clan does not exist... cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java new file mode 100644 index 0000000000..16a0da92bc --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java @@ -0,0 +1,196 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.instancemanager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2Spawn; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder; +import com.l2jmobius.gameserver.network.serverpackets.CreatureSay; + +/** + * @author Mobius + */ +public final class FakePlayerChatManager implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName()); + final List MESSAGES = new ArrayList<>(); + private static final int MIN_DELAY = 5000; + private static final int MAX_DELAY = 15000; + + protected FakePlayerChatManager() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT) + { + MESSAGES.clear(); + parseDatapackFile("data/FakePlayerChatData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode)); + MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers"))); + })); + } + + public void manageChat(L2PcInstance player, String fpcName, String message) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY)); + } + + public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay)); + } + + private void manageResponce(L2PcInstance player, String fpcName, String message) + { + if (player == null) + { + return; + } + + final String text = message.toLowerCase(); + + // tricky question + if (text.contains("can you see me")) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + if (npc.calculateDistance(player, false, false) < 3000) + { + if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible()) + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes"); + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?"); + } + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no"); + } + return; + } + } + } + + for (FakePlayerChatHolder chatHolder : MESSAGES) + { + if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL")) + { + continue; + } + + switch (chatHolder.getSearchMethod()) + { + case "EQUALS": + { + if (text.equals(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "STARTS_WITH": + { + if (text.startsWith(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "CONTAINS": + { + boolean allFound = true; + for (String word : chatHolder.getSearchText()) + { + if (!text.contains(word)) + { + allFound = false; + } + } + if (allFound) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + } + } + } + + public void sendChat(L2PcInstance player, String fpcName, String message) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message)); + } + } + } + + public static FakePlayerChatManager getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerChatManager _instance = new FakePlayerChatManager(); + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java index 1a62714f0e..50a3cc2145 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/DropProtection.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model; import java.util.concurrent.ScheduledFuture; import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; @@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; public class DropProtection implements Runnable { private volatile boolean _isProtected = false; - private L2PcInstance _owner = null; + private L2Character _owner = null; private ScheduledFuture _task = null; private static final long PROTECTED_MILLIS_TIME = 15000; @@ -46,7 +47,7 @@ public class DropProtection implements Runnable return _isProtected; } - public L2PcInstance getOwner() + public L2Character getOwner() { return _owner; } @@ -91,12 +92,12 @@ public class DropProtection implements Runnable _task = null; } - public synchronized void protect(L2PcInstance player) + public synchronized void protect(L2Character character) { unprotect(); _isProtected = true; - _owner = player; + _owner = character; if (_owner == null) { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java index 459660c7ca..92837e4b25 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/L2Object.java @@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab return false; } + /** + * Verify if object is a fake player. + * @return {@code true} if object is a fake player, {@code false} otherwise + */ + public boolean isFakePlayer() + { + return false; + } + /** * Verify if object is instance of L2ServitorInstance. * @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 2ecce60d39..ddc1a1b8d4 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.L2Item; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; @@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc public synchronized boolean getMustRewardExpSP() { - return _mustGiveExpSp; + return _mustGiveExpSp && !isFakePlayer(); } /** @@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc // Don't drop anything if the last attacker or owner isn't L2PcInstance if (player == null) { + // unless its a fake player and they can drop items + if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS) + { + final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer); + if (deathItems != null) + { + for (ItemHolder drop : deathItems) + { + final L2Item item = ItemTable.getInstance().getTemplate(drop.getId()); + // Check if the autoLoot mode is active + if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS)))) + { + // do nothing + } + else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect()) + { + for (SkillHolder skillHolder : item.getAllSkills()) + { + SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false); + } + mainDamageDealer.broadcastInfo(); // ? check if this is necessary + } + else + { + final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground + if (Config.FAKE_PLAYER_CAN_PICKUP) + { + mainDamageDealer.getFakePlayerDrops().add(droppedItem); + } + } + } + } + } return; } @@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc */ public void doEventDrop(L2Character lastAttacker) { - if (lastAttacker == null) + if ((lastAttacker == null) || isFakePlayer()) { return; } @@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc _harvestItem.set(null); _sweepItems.set(null); + // fake players + if (isFakePlayer()) + { + getFakePlayerDrops().clear(); // Clear existing fake player drops + setReputation(0); // reset reputation + setScriptValue(0); // remove pvp flag + setRunning(); // don't walk + } + // Clear mod Seeded stat _seeded = false; _seed = null; diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 226b8e981a..6dd50e079f 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -30,6 +30,7 @@ import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.CharEffectList; @@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack; import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType; import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType; import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private int _reputation = 0; + /** Map containing all skills of this character. */ private final Map _skills = new ConcurrentSkipListMap<>(); /** Map containing the skill reuse time stamps. */ @@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe /** A set containing the shot types currently charged. */ private Set _chargedShots = EnumSet.noneOf(ShotType.class); + /** A list containing the dropped items of this fake player. */ + private final List _fakePlayerDrops = new CopyOnWriteArrayList<>(); + /** * Creates a creature. * @param template the creature template @@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe broadcastPacket(attack); } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) + { + final L2Npc npc = ((L2Npc) this); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + // Notify AI with EVT_READY_TO_ACT ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk); } @@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean isInsidePeaceZone(L2Object attacker, L2Object target) { final Instance instanceWorld = getInstanceWorld(); - if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) + if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) { return false; } @@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist()); } + public int getReputation() + { + return _reputation; + } + + public void setReputation(int reputation) + { + _reputation = reputation; + } + /** * Gets the distance to target. * @param target the target @@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { _cursorKeyMovement = value; } + + public List getFakePlayerDrops() + { + return _fakePlayerDrops; + } } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index 5742c07807..b669e16e76 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; +import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.handler.BypassHandler; import com.l2jmobius.gameserver.handler.IBypassHandler; import com.l2jmobius.gameserver.instancemanager.CastleManager; @@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.olympiad.Olympiad; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate; +import com.l2jmobius.gameserver.model.stats.Formulas; import com.l2jmobius.gameserver.model.variables.NpcVariables; import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.NpcStringId; @@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState; import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse; import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec import com.l2jmobius.gameserver.network.serverpackets.NpcSay; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; +import com.l2jmobius.gameserver.network.serverpackets.UserInfo; import com.l2jmobius.gameserver.taskmanager.DecayTaskManager; import com.l2jmobius.gameserver.util.Broadcast; @@ -125,6 +130,7 @@ public class L2Npc extends L2Character private boolean _isRandomAnimationEnabled = true; private boolean _isRandomWalkingEnabled = true; private boolean _isTalkable = getTemplate().isTalkable(); + private final boolean _isFakePlayer = getTemplate().isFakePlayer(); protected RandomAnimationTask _rAniTask; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -364,7 +370,11 @@ public class L2Npc extends L2Character return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo(this, player)); } @@ -901,6 +911,78 @@ public class L2Npc extends L2Character final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null; _killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0; + if (isFakePlayer() && (killer != null) && killer.isPlayable()) + { + final L2PcInstance player = killer.getActingPlayer(); + if (isScriptValue(0) && (getReputation() >= 0)) + { + if (Config.FAKE_PLAYER_KILL_KARMA) + { + player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon())); + player.setPkKills(player.getPkKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + player.checkItemRestriction(); + // pk item rewards + if (Config.REWARD_PK_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } + // announce pk + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + else if (Config.FAKE_PLAYER_KILL_PVP) + { + player.setPvpKills(player.getPvpKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + // pvp item rewards + if (Config.REWARD_PVP_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + } + // announce pvp + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + DecayTaskManager.getInstance().add(this); final L2Spawn spawn = getSpawn(); @@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character activeChar.sendMessage("Added NPC: " + getName()); } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + activeChar.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { activeChar.sendPacket(new ServerObjectInfo(this, activeChar)); } @@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character @Override public void rechargeShots(boolean physical, boolean magic, boolean fish) { - if (physical && (_soulshotamount > 0)) + if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS) { - if (Rnd.get(100) > getTemplate().getSoulShotChance()) + if (physical) { - return; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic) + { + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _soulshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); - chargeShot(ShotType.SOULSHOTS); } - - if (magic && (_spiritshotamount > 0)) + else { - if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + if (physical && (_soulshotamount > 0)) { - return; + if (Rnd.get(100) > getTemplate().getSoulShotChance()) + { + return; + } + _soulshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic && (_spiritshotamount > 0)) + { + if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + { + return; + } + _spiritshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _spiritshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); - chargeShot(ShotType.SPIRITSHOTS); } } @@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character /** * Drops an item. - * @param player the last attacker or main damage dealer + * @param character the last attacker or main damage dealer * @param itemId the item ID * @param itemCount the item count * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount) + public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount) { L2ItemInstance item = null; for (int i = 0; i < itemCount; i++) @@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character return null; } - item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this); + item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this); if (item == null) { return null; } - if (player != null) + if (character != null) { - item.getDropProtection().protect(player); + item.getDropProtection().protect(character); } item.dropMe(this, newX, newY, newZ); @@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character } /** - * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)} - * @param player the last attacker or main damage dealer + * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)} + * @param character the last attacker or main damage dealer * @param item the item holder * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item) + public L2ItemInstance dropItem(L2Character character, ItemHolder item) { - return dropItem(player, item.getId(), item.getCount()); + return dropItem(character, item.getId(), item.getCount()); } @Override @@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character return Config.SHOP_MIN_RANGE_FROM_NPC; } + @Override + public boolean isFakePlayer() + { + return _isFakePlayer; + } + /** * @return The player's object Id this NPC is cloning. */ diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java index 34550c3dd8..10ad419ea4 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Playable.java @@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character public abstract void doPickupItem(L2Object object); - public abstract int getReputation(); - public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove); public abstract void storeMe(); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index 8427885746..87cc552765 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } @@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable { setTarget(target); getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); + if (target.isFakePlayer()) + { + getOwner().updatePvPStatus(); + } } } } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java index a5fd31dedd..44ee919058 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java @@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java index aa4f132fce..6a94be63b5 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java @@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { - if (attacker.isMonster()) + if (attacker.isMonster() && !attacker.isFakePlayer()) { return true; } @@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); } + if (isFakePlayer() && isInCombat()) + { + interact = false; + // TODO: Fix normal targeting + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); + } + // Check if the L2PcInstance already target the L2GuardInstance if (getObjectId() != player.getTargetId()) { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java index e9a9976e87..fe55288a3a 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java @@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { + if (isFakePlayer()) + { + return isInCombat() || attacker.isMonster() || (getScriptValue() > 0); + } + // Check if the L2MonsterInstance target is aggressive if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance)) { @@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable if (attacker.isMonster()) { - return false; + return attacker.isFakePlayer(); } // Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints. diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index fc00a851c3..cff16174ad 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -446,9 +446,6 @@ public final class L2PcInstance extends L2Playable /** The Experience of the L2PcInstance before the last Death Penalty */ private long _expBeforeDeath; - /** The Reputation of the L2PcInstance */ - private int _reputation; - /** The number of player killed during a PvP (the player killed was PvP Flagged) */ private int _pvpKills; @@ -1993,24 +1990,16 @@ public final class L2PcInstance extends L2Playable return _expBeforeDeath; } - /** - * @return the reputation of the PlayerInstance. - */ - @Override - public int getReputation() - { - return _reputation; - } - public void setInitialReputation(int reputation) { - _reputation = reputation; + super.setReputation(reputation); } /** * Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast). * @param reputation */ + @Override public void setReputation(int reputation) { // Notify to scripts. @@ -2036,7 +2025,9 @@ public final class L2PcInstance extends L2Playable } }); } - _reputation = reputation; + + super.setReputation(reputation); + sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation())); broadcastReputation(); } @@ -4656,6 +4647,10 @@ public final class L2PcInstance extends L2Playable { super.doAttack(target); setRecentFakeDeath(false); + if (target.isFakePlayer()) + { + updatePvPStatus(); + } } @Override @@ -4983,22 +4978,42 @@ public final class L2PcInstance extends L2Playable if (killer != null) { final L2PcInstance pk = killer.getActingPlayer(); - if (pk != null) + final boolean fpcKill = killer.isFakePlayer(); + if ((pk != null) || fpcKill) { - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); - - if (L2Event.isParticipant(pk)) + if (pk != null) { - pk.getEventStatus().addKill(this); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); + + if (L2Event.isParticipant(pk)) + { + pk.getEventStatus().addKill(this); + } + + // pvp/pk item rewards + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + // pvp + if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) + { + pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + // pk + if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) + { + pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } } // announce pvp/pk - if (Config.ANNOUNCE_PK_PVP && !pk.isGM()) + if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill)) { String msg = ""; if (getPvpFlag() == 0) { - msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5012,7 +5027,7 @@ public final class L2PcInstance extends L2Playable } else if (getPvpFlag() != 0) { - msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5026,20 +5041,9 @@ public final class L2PcInstance extends L2Playable } } - // pvp/pk item rewards - if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // - !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0)) { - // pvp - if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) - { - pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); - } - // pk - if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) - { - pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); - } + killer.setReputation(killer.getReputation() - 150); } } @@ -5632,6 +5636,14 @@ public final class L2PcInstance extends L2Playable return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks()); } + /** + * Used by fake players to emulate proper behavior. + */ + public void blockRequest() + { + _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND); + } + /** * Select the Warehouse to be used in next activity. * @param partner @@ -11579,7 +11591,7 @@ public final class L2PcInstance extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addPcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java index fb6b184e67..8383d1efc9 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java @@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc return null; } + @Override public int getReputation() { return _owner != null ? _owner.getReputation() : 0; @@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addCharName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); _owner.sendPacket(sm); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java index a97eab382d..26a51be541 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java @@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus } } - if (attacker.isPlayable() && (caster.getCurrentCp() > 0)) + if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0)) { if (caster.getCurrentCp() > transferDmg) { @@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus } } - if (!ignoreCP && attacker.isPlayable()) + if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer())) { if (getCurrentCp() >= value) { @@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus // Send a System Message to the L2PcInstance SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addCharName(attacker); + smsg.addString(attacker.getName()); smsg.addInt(fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java index 2d7f41e9d0..f5bee5dab6 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java @@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable private boolean _randomWalk; private boolean _randomAnimation; private boolean _flying; + private boolean _fakePlayer; + private boolean _fakePlayerTalkable; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; @@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable _randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard")); _randomAnimation = set.getBoolean("randomAnimation", true); _flying = set.getBoolean("flying", false); + _fakePlayer = set.getBoolean("fakePlayer", false); + _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true); _canMove = set.getBoolean("canMove", true); _noSleepMode = set.getBoolean("noSleepMode", false); _passableDoor = set.getBoolean("passableDoor", false); @@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable return _flying; } + public boolean isFakePlayer() + { + return _fakePlayer; + } + + public boolean isFakePlayerTalkable() + { + return _fakePlayerTalkable; + } + public boolean canMove() { return _canMove; @@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null) { @@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null) { @@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable case LUCKY_DROP: { // try chance before luck - if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck()) + if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck()) { return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax())); } @@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // chance double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER; // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE; } @@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // amount is calculated after chance returned success double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER; // premium amount - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT; } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java index df9698d3c3..6cbe42b242 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.events.impl.item; -import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.events.EventType; import com.l2jmobius.gameserver.model.events.impl.IBaseEvent; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; @@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent { private final String _process; private final L2ItemInstance _item; - private final L2PcInstance _activeChar; + private final L2Character _activeChar; private final Object _reference; - public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference) + public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference) { _process = process; _item = item; @@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent return _item; } - public L2PcInstance getActiveChar() + public L2Character getActiveChar() { return _activeChar; } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java new file mode 100644 index 0000000000..3008d340b3 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java @@ -0,0 +1,60 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Mobius + */ +public class FakePlayerChatHolder +{ + private final String _fpcName; + private final String _searchMethod; + private final List _searchText; + private final List _answers; + + public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers) + { + _fpcName = fpcName; + _searchMethod = searchMethod; + _searchText = new ArrayList<>(Arrays.asList(searchText.split(";"))); + _answers = new ArrayList<>(Arrays.asList(answers.split(";"))); + } + + public String getFpcName() + { + return _fpcName; + } + + public String getSearchMethod() + { + return _searchMethod; + } + + public List getSearchText() + { + return _searchText; + } + + public List getAnswers() + { + return _answers; + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java new file mode 100644 index 0000000000..2f8aa1fa6d --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java @@ -0,0 +1,232 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class FakePlayerHolder +{ + private final int _classId; + private final int _hair; + private final int _hairColor; + private final int _face; + private final int _nameColor; + private final int _titleColor; + private final int _equipHead; + private final int _equipRHand; + private final int _equipLHand; + private final int _equipGloves; + private final int _equipChest; + private final int _equipLegs; + private final int _equipFeet; + private final int _equipCloak; + private final int _equipHair; + private final int _equipHair2; + private final int _agathionId; + private final int _weaponEnchantLevel; + private final int _armorEnchantLevel; + private final boolean _fishing; + private final int _baitLocationX; + private final int _baitLocationY; + private final int _baitLocationZ; + private final int _recommends; + private final int _nobleLevel; + private final boolean _hero; + private final int _clanId; + private final int _pledgeStatus; + + public FakePlayerHolder(StatsSet set) + { + _classId = set.getInt("classId", 182); + + _hair = set.getInt("hair", 1); + _hairColor = set.getInt("hairColor", 1); + _face = set.getInt("face", 1); + + _nameColor = set.getInt("nameColor", 0xFFFFFF); + _titleColor = set.getInt("titleColor", 0xECF9A2); + + _equipHead = set.getInt("equipHead", 0); + _equipRHand = set.getInt("equipRHand", 0); // or dual hand + _equipLHand = set.getInt("equipLHand", 0); + _equipGloves = set.getInt("equipGloves", 0); + _equipChest = set.getInt("equipChest", 0); + _equipLegs = set.getInt("equipLegs", 0); + _equipFeet = set.getInt("equipFeet", 0); + _equipCloak = set.getInt("equipCloak", 0); + _equipHair = set.getInt("equipHair", 0); + _equipHair2 = set.getInt("equipHair2", 0); + _agathionId = set.getInt("agathionId", 0); + + _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0); + _armorEnchantLevel = set.getInt("armorEnchantLevel", 0); + + _fishing = set.getBoolean("fishing", false); + _baitLocationX = set.getInt("baitLocationX", 0); + _baitLocationY = set.getInt("baitLocationY", 0); + _baitLocationZ = set.getInt("baitLocationZ", 0); + + _recommends = set.getInt("recommends", 0); + _nobleLevel = set.getInt("nobleLevel", 0); + _hero = set.getBoolean("hero", false); + _clanId = set.getInt("clanId", 0); + _pledgeStatus = set.getInt("pledgeStatus", 0); + } + + public int getClassId() + { + return _classId; + } + + public int getHair() + { + return _hair; + } + + public int getHairColor() + { + return _hairColor; + } + + public int getFace() + { + return _face; + } + + public int getNameColor() + { + return _nameColor; + } + + public int getTitleColor() + { + return _titleColor; + } + + public int getEquipHead() + { + return _equipHead; + } + + public int getEquipRHand() + { + return _equipRHand; + } + + public int getEquipLHand() + { + return _equipLHand; + } + + public int getEquipGloves() + { + return _equipGloves; + } + + public int getEquipChest() + { + return _equipChest; + } + + public int getEquipLegs() + { + return _equipLegs; + } + + public int getEquipFeet() + { + return _equipFeet; + } + + public int getEquipCloak() + { + return _equipCloak; + } + + public int getEquipHair() + { + return _equipHair; + } + + public int getEquipHair2() + { + return _equipHair2; + } + + public int getAgathionId() + { + return _agathionId; + } + + public int getWeaponEnchantLevel() + { + return _weaponEnchantLevel; + } + + public int getArmorEnchantLevel() + { + return _armorEnchantLevel; + } + + public boolean isFishing() + { + return _fishing; + } + + public int getBaitLocationX() + { + return _baitLocationX; + } + + public int getBaitLocationY() + { + return _baitLocationY; + } + + public int getBaitLocationZ() + { + return _baitLocationZ; + } + + public int getRecommends() + { + return _recommends; + } + + public int getNobleLevel() + { + return _nobleLevel; + } + + public boolean isHero() + { + return _hero; + } + + public int getClanId() + { + return _clanId; + } + + public int getPledgeStatus() + { + return _pledgeStatus; + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index c5af087f72..551733f42a 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object *
    *
  • Do Pickup Item : PCInstance and Pet

  • *
    - * @param player Player that pick up the item + * @param character Character that pick up the item */ - public final void pickupMe(L2Character player) + public final void pickupMe(L2Character character) { assert getWorldRegion() != null; final L2WorldRegion oldregion = getWorldRegion(); // Create a server->client GetItem packet to pick up the L2ItemInstance - player.broadcastPacket(new GetItem(this, player.getObjectId())); + character.broadcastPacket(new GetItem(this, character.getObjectId())); synchronized (this) { @@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object // Remove the L2ItemInstance from the world L2World.getInstance().removeVisibleObject(this, oldregion); - if (player.isPlayer()) + if (character.isPlayer()) { // Notify to scripts - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem()); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem()); } } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java index 83f6e88b77..7505001c60 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable public boolean checkCondition(L2Character activeChar, L2Object object) { - if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION) + if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)) { return true; } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index b7eda58d00..13932008ff 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -159,7 +160,7 @@ public class SkillCaster implements Runnable } // You should not heal/buff monsters without pressing the ctrl button. - if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed) + if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed) { caster.sendPacket(SystemMessageId.INVALID_TARGET); return null; @@ -609,6 +610,10 @@ public class SkillCaster implements Runnable // Add hate to the attackable, and put it in the attack list. ((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint()); ((L2Character) obj).addAttackerToAttackByList(caster); + if (obj.isFakePlayer()) + { + player.updatePvPStatus(); + } } // notify target AI about the attack @@ -617,10 +622,19 @@ public class SkillCaster implements Runnable ((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster); } } - else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0)))) + else if (((skill.getEffectPoint() > 0) && obj.isMonster()) // + || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) // + || (((L2Character) obj).getReputation() < 0) // + ))) { // Supporting players or monsters result in pvpflag. - player.updatePvPStatus(); + if (!obj.isFakePlayer() // + || (obj.isFakePlayer() // + && (!((L2Npc) obj).isScriptValue(0) // + || (((L2Npc) obj).getReputation() < 0)))) + { + player.updatePvPStatus(); + } } } @@ -630,7 +644,7 @@ public class SkillCaster implements Runnable EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob); // On Skill See logic - if (npcMob.isAttackable()) + if (npcMob.isAttackable() && !npcMob.isFakePlayer()) { final L2Attackable attackable = (L2Attackable) npcMob; @@ -652,6 +666,19 @@ public class SkillCaster implements Runnable } }); } + else if (caster.isFakePlayer()) // fake player attacks player + { + if (target.isPlayable() || target.isFakePlayer()) + { + final L2Npc npc = ((L2Npc) caster); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + npc.broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + } } catch (Exception e) { @@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable return false; } } - return true; } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java index fdf0dadf55..06bea1b4cf 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java @@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.zone.L2ZoneType; import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; @@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } @@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java index 91a9ce830a..ccd2d1d13a 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/Action.java @@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket } case 1: { - if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC)) + if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer())) { obj.onAction(activeChar, false); } diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java index 876c53c093..06464d9911 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java @@ -22,6 +22,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData; import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData; import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; @@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket return; } - if (Config.FORBIDDEN_NAMES.length > 1) + if (Config.FORBIDDEN_NAMES.length > 0) { for (String st : Config.FORBIDDEN_NAMES) { @@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().getProperName(_name) != null) + { + client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); + return; + } + // Last Verified: May 30, 2009 - Gracia Final if (!Util.isAlphaNumeric(_name) || !isValidName(_name)) { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java index 06bfa3c200..01c8b0c67f 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java @@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; public final class RequestBlock implements IClientIncomingPacket { @@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket case BLOCK: case UNBLOCK: { + // TODO: Save in database? :P + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (_type == BLOCK) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + return; + } + // can't use block/unblock for locating invisible characters if (targetId <= 0) { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java index ceb67b0f5f..cf79bdb24c 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable; import com.l2jmobius.gameserver.util.Util; @@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket { result = NAME_ALREADY_EXISTS; } + else if (FakePlayerData.getInstance().getProperName(_name) != null) + { + result = NAME_ALREADY_EXISTS; + } else if (_name.length() > 16) { result = INVALID_LENGTH; diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java index b0ace828dc..ee8bcd656b 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java @@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Party; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart; @@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance activeChar = client.getActiveChar(); - final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (activeChar == null) { return; } + + if (FakePlayerData.getInstance().isTalkable(_player)) + { + final String name = FakePlayerData.getInstance().getProperName(_player); + if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + if (activeChar.isProcessingRequest()) + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(name); + activeChar.sendPacket(msg); + return; + } + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL); + sm.addString(name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000); + activeChar.blockRequest(); + return; + } + + final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (targetChar == null) { activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java index f104c94161..c0042d45c5 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java @@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PartyDistributionType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Party; @@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + if (player.getParty() == null) + { + player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED); + } + else + { + player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY); + } + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance requestor = client.getActiveChar(); - final L2PcInstance target = L2World.getInstance().getPlayer(_name); - if (requestor == null) { return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + requestor.sendPacket(sm); + if (!requestor.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000); + requestor.blockRequest(); + } + else + { + requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY); + } + return; + } + + final L2PcInstance target = L2World.getInstance().getPlayer(_name); if (target == null) { requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java index 292153afd8..37c539556f 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java @@ -17,12 +17,15 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; /** * This class ... @@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket return; } + if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName()))) + { + if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0) + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN); + } + else + { + if (!activeChar.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(activeChar.getTarget().getName()); + activeChar.sendPacket(msg); + } + } + return; + } + final L2PcInstance target = L2World.getInstance().getPlayer(_target); if (target == null) { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java index 3d5bcaeca5..9cbb114e88 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java @@ -23,6 +23,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.instancemanager.MailManager; import com.l2jmobius.gameserver.model.BlockList; @@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().isTalkable(_receiver)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1); + sm.addString(FakePlayerData.getInstance().getProperName(_receiver)); + activeChar.sendPacket(sm); + return; + } + final int receiverId = CharNameTable.getInstance().getIdByName(_receiver); if (receiverId <= 0) { diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java index 8156905e94..1336c2bdb7 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java @@ -17,6 +17,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; @@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket } final L2Object object = activeChar.getTarget(); - if (!(object instanceof L2PcInstance)) { if (object == null) { client.sendPacket(SystemMessageId.SELECT_TARGET); } + else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName())) + { + if (activeChar.getRecomLeft() <= 0) + { + client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER); + return; + } + + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT); + sm.addString(FakePlayerData.getInstance().getProperName(object.getName())); + sm.addInt(activeChar.getRecomLeft()); + client.sendPacket(sm); + + activeChar.setRecomLeft(activeChar.getRecomLeft() - 1); + client.sendPacket(new UserInfo(activeChar)); + client.sendPacket(new ExVoteSystemInfo(activeChar)); + } else { client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java index d77dc881b3..5d7e35eb43 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java @@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.effects.AbstractEffect; import com.l2jmobius.gameserver.model.skills.AbnormalType; @@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final String name = FakePlayerData.getInstance().getProperName(target.getName()); + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE)); + return; + } + if (!player.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1); + sm.addString(name); + player.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000); + player.blockRequest(); + } + else + { + player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE); + } + return; + } + if (!target.isPlayer()) { client.sendPacket(SystemMessageId.INVALID_TARGET); diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java index 4fa25283a7..530a6d7a01 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java @@ -17,6 +17,8 @@ package com.l2jmobius.gameserver.network.clientpackets.friend; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST)); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (!activeChar.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST); + sm.addString(_name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + sm.addString(_name); + activeChar.sendPacket(sm); + } + return; + } + final L2PcInstance friend = L2World.getInstance().getPlayer(_name); // Target is not found in the game. diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java index 2170ef2e94..017541bd86 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java @@ -22,6 +22,7 @@ import java.util.List; import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.instancemanager.MentorManager; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.NpcStringId; import com.l2jmobius.gameserver.network.OutgoingPackets; @@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket _charLevel = sender.getLevel(); _textType = messageType; _text = text; - if (receiver.getFriendList().contains(sender.getObjectId())) + if (receiver != null) { - _mask |= 0x01; - } - if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) - { - _mask |= 0x02; - } - if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) - { - _mask |= 0x04; - } - if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) - { - _mask |= 0x08; + if (receiver.getFriendList().contains(sender.getObjectId())) + { + _mask |= 0x01; + } + if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) + { + _mask |= 0x02; + } + if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) + { + _mask |= 0x04; + } + if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) + { + _mask |= 0x08; + } } // Does not shows level @@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket } } + /** + * Used by fake players. + * @param sender + * @param receiver + * @param name + * @param messageType + * @param text + */ + public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text) + { + _objectId = sender.getObjectId(); + _charName = name; + _charLevel = sender.getLevel(); + _textType = messageType; + _text = text; + } + /** * @param objectId * @param messageType diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java new file mode 100644 index 0000000000..d1b7900f12 --- /dev/null +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java @@ -0,0 +1,231 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.network.serverpackets; + +import java.util.Set; + +import com.l2jmobius.commons.network.PacketWriter; +import com.l2jmobius.gameserver.data.sql.impl.ClanTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.enums.Sex; +import com.l2jmobius.gameserver.model.L2Clan; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; +import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect; +import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.OutgoingPackets; + +/** + * @author Mobius + */ +public class FakePlayerInfo implements IClientOutgoingPacket +{ + private final L2Npc _npc; + private final int _objId; + private final int _x, _y, _z, _heading; + private final int _mAtkSpd, _pAtkSpd; + private final int _runSpd, _walkSpd; + private final int _swimRunSpd; + private final int _swimWalkSpd; + private final int _flyRunSpd; + private final int _flyWalkSpd; + private final double _moveMultiplier; + private final float _attackSpeedMultiplier; + private final FakePlayerHolder _fpcHolder; + private final L2Clan _clan; + + public FakePlayerInfo(L2Npc npc) + { + _npc = npc; + _objId = npc.getObjectId(); + _x = npc.getX(); + _y = npc.getY(); + _z = npc.getZ(); + _heading = npc.getHeading(); + _mAtkSpd = npc.getMAtkSpd(); + _pAtkSpd = npc.getPAtkSpd(); + _attackSpeedMultiplier = npc.getAttackSpeedMultiplier(); + _moveMultiplier = npc.getMovementSpeedMultiplier(); + _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier); + _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier); + _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier); + _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier); + _flyRunSpd = npc.isFlying() ? _runSpd : 0; + _flyWalkSpd = npc.isFlying() ? _walkSpd : 0; + _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId()); + _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId()); + } + + @Override + public boolean write(PacketWriter packet) + { + OutgoingPackets.CHAR_INFO.writeId(packet); + packet.writeD(_x); + packet.writeD(_y); + packet.writeD(_z); + packet.writeD(0x00); // vehicleId + packet.writeD(_objId); + packet.writeS(_npc.getName()); + + packet.writeH(_npc.getRace().ordinal()); + packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00); + packet.writeD(_fpcHolder.getClassId()); + + packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER + packet.writeD(_fpcHolder.getEquipHead()); + packet.writeD(_fpcHolder.getEquipRHand()); + packet.writeD(_fpcHolder.getEquipLHand()); + packet.writeD(_fpcHolder.getEquipGloves()); + packet.writeD(_fpcHolder.getEquipChest()); + packet.writeD(_fpcHolder.getEquipLegs()); + packet.writeD(_fpcHolder.getEquipFeet()); + packet.writeD(_fpcHolder.getEquipCloak()); + packet.writeD(_fpcHolder.getEquipRHand()); // dual hand + packet.writeD(_fpcHolder.getEquipHair()); + packet.writeD(_fpcHolder.getEquipHair2()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderAugument()) + { + packet.writeQ(0x00); + } + + packet.writeC(_fpcHolder.getArmorEnchantLevel()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderVisualId()) + { + packet.writeD(0x00); + } + + packet.writeC(_npc.getScriptValue()); // getPvpFlag() + packet.writeD(_npc.getReputation()); + + packet.writeD(_mAtkSpd); + packet.writeD(_pAtkSpd); + + packet.writeH(_runSpd); + packet.writeH(_walkSpd); + packet.writeH(_swimRunSpd); + packet.writeH(_swimWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeF(_moveMultiplier); + packet.writeF(_attackSpeedMultiplier); + + packet.writeF(_npc.getCollisionRadius()); + packet.writeF(_npc.getCollisionHeight()); + + packet.writeD(_fpcHolder.getHair()); + packet.writeD(_fpcHolder.getHairColor()); + packet.writeD(_fpcHolder.getFace()); + + packet.writeS(_npc.getTemplate().getTitle()); + + if (_clan != null) + { + packet.writeD(_clan.getId()); + packet.writeD(_clan.getCrestId()); + packet.writeD(_clan.getAllyId()); + packet.writeD(_clan.getAllyCrestId()); + } + else + { + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + } + + packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked) + packet.writeC(_npc.isRunning() ? 0x01 : 0x00); + packet.writeC(_npc.isInCombat() ? 0x01 : 0x00); + + packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00); + + packet.writeC(_npc.isInvisible() ? 0x01 : 0x00); + + packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount + packet.writeC(0x00); // getPrivateStoreType().getId() + + packet.writeH(0x00); // getCubics().size() + // getCubics().keySet().forEach(packet::writeH); + + packet.writeC(0x00); + + packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0); + packet.writeH(_fpcHolder.getRecommends()); + packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000 + + packet.writeD(_fpcHolder.getClassId()); + packet.writeD(0x00); + packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel + + packet.writeC(_npc.getTeam().getId()); + + packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00); + packet.writeC(_fpcHolder.getNobleLevel()); + packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00); + + packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00); + + packet.writeD(_fpcHolder.getBaitLocationX()); + packet.writeD(_fpcHolder.getBaitLocationY()); + packet.writeD(_fpcHolder.getBaitLocationZ()); + + packet.writeD(_fpcHolder.getNameColor()); + + packet.writeD(_heading); + + packet.writeC(_fpcHolder.getPledgeStatus()); + packet.writeH(0x00); // getPledgeType() + + packet.writeD(_fpcHolder.getTitleColor()); + + packet.writeC(0x00); // isCursedWeaponEquipped + + packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0 + packet.writeD(0x00); // getTransformationDisplayId() + packet.writeD(_fpcHolder.getAgathionId()); + + packet.writeC(0x00); + + packet.writeD(0x00); // getCurrentCp() + packet.writeD(_npc.getMaxHp()); + packet.writeD((int) Math.round(_npc.getCurrentHp())); + packet.writeD(_npc.getMaxMp()); + packet.writeD((int) Math.round(_npc.getCurrentMp())); + + packet.writeC(0x00); + final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects(); + packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0)); + for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects) + { + packet.writeH(abnormalVisualEffect.getClientId()); + } + if (_npc.isInvisible()) + { + packet.writeH(AbnormalVisualEffect.STEALTH.getClientId()); + } + packet.writeC(0x00); // cocPlayer.getPosition() + packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00); + packet.writeC(0x00); // Used Ability Points + return true; + } +} diff --git a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index 4fb1a757e6..c294edab2a 100644 --- a/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_3.0_Helios/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket addComponentType(NpcInfoType.TITLE_NPCSTRINGID); } + if (_npc.getReputation() != 0) + { + addComponentType(NpcInfoType.REPUTATION); + } + if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible()) { addComponentType(NpcInfoType.ABNORMALS); @@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.REPUTATION)) { - packet.writeD(0x00); // Name color + packet.writeD(_npc.getReputation()); // Reputation } if (containsMask(NpcInfoType.CLAN)) { diff --git a/L2J_Mobius_3.0_Helios/readme.txt b/L2J_Mobius_3.0_Helios/readme.txt index 613ec18d32..03c043d22c 100644 --- a/L2J_Mobius_3.0_Helios/readme.txt +++ b/L2J_Mobius_3.0_Helios/readme.txt @@ -101,6 +101,7 @@ Customs: -Classmaster -Community board -Faction system +-Fake players -Find PvP -NPC stat multipliers -Realtime offline trade diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml index 171e08cb12..f9067f1377 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/AdminCommands.xml @@ -392,6 +392,9 @@ + + + diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini new file mode 100644 index 0000000000..f745b0d31e --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/config/Custom/FakePlayers.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------------------- +# Fake players +# --------------------------------------------------------------------------- + +# Enable fake players. +EnableFakePlayers = False + +# Enable chatting with fake players. +FakePlayerChat = True + +# Enable shots usage for fake players. +FakePlayerUseShots = True + +# Reward PvP kills by killing fake players. +FakePlayerKillsRewardPvP = True + +# Fake player kills apply karma rules. +FakePlayerUnflaggedKillsKarma = True + +# Aggressive AI fake players attack nearby monsters. +FakePlayerAggroMonsters = True + +# Aggressive AI fake players attack nearby players. +FakePlayerAggroPlayers = False + +# Aggressive AI fake players attack nearby fake players. +FakePlayerAggroFPC = False + +# Fake players can drop items when killing monsters. +FakePlayerCanDropItems = True + +# Fake players can pickup dropped items. +FakePlayerCanPickup = True diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml new file mode 100644 index 0000000000..f5da5bfc8e --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerChatData.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml new file mode 100644 index 0000000000..f36096ed4a --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/FakePlayerVisualData.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml index 98e0d38815..4a7f998b00 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/Routes.xml @@ -2402,4 +2402,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java index 6f29855cc3..d12ee2e7c4 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/ai/areas/FairySettlement/Wisp.java @@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI final L2Character creature = event.getSeen(); final L2Npc npc = (L2Npc) event.getSeer(); - if (creature.isPlayer()) + if (creature.isPlayer() || creature.isFakePlayer()) { npc.setTarget(creature); npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill()); diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java new file mode 100644 index 0000000000..e1dde7324e --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java @@ -0,0 +1,80 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +import ai.AbstractNpcAI; + +/** + * TODO: Move it to L2Character. + * @author Mobius + */ +public class PvpFlaggingStopTask extends AbstractNpcAI +{ + private PvpFlaggingStopTask() + { + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if ((npc == null) || npc.isDead()) + { + return null; + } + + if (event.startsWith("FLAG_CHECK")) + { + final L2Object target = npc.getTarget(); + if ((target != null) && (target.isPlayable() || target.isFakePlayer())) + { + npc.setScriptValue(1); // in combat + cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null); + cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null); + startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null); + startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null); + } + } + else if (event.startsWith("FINISH_FLAG")) + { + if (npc.isScriptValue(1)) + { + npc.setScriptValue(2); // blink status + npc.broadcastInfo(); // update flag status + startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null); + } + } + else if (event.startsWith("REMOVE_FLAG")) + { + if (npc.isScriptValue(2)) + { + npc.setScriptValue(0); // not in combat + npc.broadcastInfo(); // update flag status + } + } + return super.onAdvEvent(event, npc, player); + } + + public static void main(String[] args) + { + new PvpFlaggingStopTask(); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java new file mode 100644 index 0000000000..dec3449549 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/custom/FakePlayers/RecieveAdventurerBuffs.java @@ -0,0 +1,115 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.CommonUtil; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.base.ClassId; +import com.l2jmobius.gameserver.model.holders.SkillHolder; +import com.l2jmobius.gameserver.model.skills.SkillCaster; + +import ai.AbstractNpcAI; + +/** + * Town Fake Player walkers that receive buffs from Adventurer NPC. + * @author Mobius + */ +public class RecieveAdventurerBuffs extends AbstractNpcAI +{ + // NPCs + private static final int[] ADVENTURERS_GUIDE = + { + 32327, + 33950, + }; + private static final int[] FAKE_PLAYER_IDS = + { + 80000 + }; + // Skills + // private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer) + private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer) + private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer) + private static final SkillHolder[] GROUP_BUFFS = + { + new SkillHolder(15642, 1), // Horn Melody (Adventurer) + new SkillHolder(15643, 1), // Drum Melody (Adventurer) + new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer) + new SkillHolder(15645, 1), // Guitar Melody (Adventurer) + new SkillHolder(15646, 1), // Harp Melody (Adventurer) + new SkillHolder(15647, 1), // Lute Melody (Adventurer) + new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer) + new SkillHolder(15652, 1), // Daring Sonata (Adventurer) + new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer) + }; + + private RecieveAdventurerBuffs() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + addSpawnId(FAKE_PLAYER_IDS); + } + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead()) + { + if (!npc.isMoving()) + { + for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100)) + { + if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId())) + { + for (SkillHolder holder : GROUP_BUFFS) + { + SkillCaster.triggerCast(nearby, npc, holder.getSkill()); + } + if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage()) + { + SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill()); + } + else + { + SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill()); + } + break; + } + } + } + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null); + } + return super.onAdvEvent(event, npc, player); + } + + @Override + public String onSpawn(L2Npc npc) + { + startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null); + return super.onSpawn(npc); + } + + public static void main(String[] args) + { + new RecieveAdventurerBuffs(); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java index 3c72228c33..3228e5fe09 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/MasterHandler.java @@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant; import handlers.admincommandhandlers.AdminEventEngine; import handlers.admincommandhandlers.AdminEvents; import handlers.admincommandhandlers.AdminExpSp; +import handlers.admincommandhandlers.AdminFakePlayers; import handlers.admincommandhandlers.AdminFightCalculator; import handlers.admincommandhandlers.AdminFortSiege; import handlers.admincommandhandlers.AdminGeodata; @@ -410,6 +411,7 @@ public class MasterHandler AdminEventEngine.class, AdminEvents.class, AdminExpSp.class, + AdminFakePlayers.class, AdminFightCalculator.class, AdminFortSiege.class, AdminGeodata.class, diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java index 6b02816d9e..d6d6a99080 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java @@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler } else if (Config.ALT_GAME_VIEWNPC) { - if (!target.isNpc()) + if (!target.isNpc() || target.isFakePlayer()) { return false; } diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java new file mode 100644 index 0000000000..99926f0df7 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java @@ -0,0 +1,77 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package handlers.admincommandhandlers; + +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.handler.IAdminCommandHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +/** + * @author Mobius + */ +public class AdminFakePlayers implements IAdminCommandHandler +{ + private static final String[] ADMIN_COMMANDS = + { + "admin_fakechat" + }; + + @Override + public boolean useAdminCommand(String command, L2PcInstance activeChar) + { + if (command.startsWith("admin_fakechat")) + { + final String[] words = command.substring(15).split(" "); + if (words.length < 3) + { + activeChar.sendMessage("Usage: //fakechat playername fpcname message"); + return false; + } + final L2PcInstance player = L2World.getInstance().getPlayer(words[0]); + if (player == null) + { + activeChar.sendMessage("Player not found."); + return false; + } + final String fpcName = FakePlayerData.getInstance().getProperName(words[1]); + if (fpcName == null) + { + activeChar.sendMessage("Fake player not found."); + return false; + } + String message = ""; + for (int i = 0; i < words.length; i++) + { + if (i < 2) + { + continue; + } + message += (words[i] + " "); + } + FakePlayerChatManager.getInstance().sendChat(player, fpcName, message); + } + return true; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index fee328deb5..f3dfff6e7d 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -31,6 +31,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData; import com.l2jmobius.gameserver.data.xml.impl.DoorData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData; import com.l2jmobius.gameserver.data.xml.impl.MultisellData; @@ -44,9 +45,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.WalkingManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.util.Util; @@ -294,6 +298,25 @@ public class AdminReload implements IAdminCommandHandler AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data."); break; } + case "fakeplayers": + { + FakePlayerData.getInstance().load(); + for (L2Object obj : L2World.getInstance().getVisibleObjects()) + { + if (obj.isFakePlayer()) + { + obj.broadcastInfo(); + } + } + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data."); + break; + } + case "fakeplayerchat": + { + FakePlayerChatManager.getInstance().load(); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data."); + break; + } default: { activeChar.sendMessage(RELOAD_USAGE); diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java index 99f2e9e9d7..7db79fe31d 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java @@ -17,8 +17,10 @@ package handlers.chathandlers; import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.handler.IChatHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.PcCondOverride; @@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler return; } + if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null)) + { + if (FakePlayerData.getInstance().isTalkable(target)) + { + if (Config.FAKE_PLAYER_CHAT) + { + final String name = FakePlayerData.getInstance().getProperName(target); + activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text)); + FakePlayerChatManager.getInstance().manageChat(activeChar, name, text); + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE); + } + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE); + } + return; + } + final L2PcInstance receiver = L2World.getInstance().getPlayer(target); if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId())) diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java index 41b1f99bcf..b38f5ca16d 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java @@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition { return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel); } - } diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java index 766844c759..2191ab4581 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/handlers/playeractions/SocialAction.java @@ -16,9 +16,11 @@ */ package handlers.playeractions; +import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.NextAction; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.handler.IPlayerActionHandler; import com.l2jmobius.gameserver.model.ActionDataHolder; import com.l2jmobius.gameserver.model.L2Object; @@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED); + player.onTransactionResponse(); + } + } + private void useCoupleSocial(L2PcInstance player, int id) { if (player == null) @@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler } final L2Object target = player.getTarget(); - if ((target == null) || !target.isPlayer()) + if ((target == null)) + { + player.sendPacket(SystemMessageId.INVALID_TARGET); + return; + } + + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1); + sm.addString(target.getName()); + player.sendPacket(sm); + if (!player.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000); + player.blockRequest(); + } + return; + } + + if (!target.isPlayer()) { player.sendPacket(SystemMessageId.INVALID_TARGET); return; diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java index 12f33e2bbc..9dd91055b9 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10766_ANewCraft/Q10766_ANewCraft.java @@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest @Id(WINDY_HEALING_POTION_1) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(4, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1)) + { + qs.setCond(4, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java index 0efb5383f4..34594dbc40 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/scripts/quests/Q10767_AWholeNewLevelOfAlchemy/Q10767_AWholeNewLevelOfAlchemy.java @@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest @Id(HIGH_GRADE_LOVE_POTION) public void onItemCreate(OnItemCreate event) { - final L2PcInstance player = event.getActiveChar(); - final QuestState qs = getQuestState(player, false); - if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + final L2PcInstance player = event.getActiveChar().getActingPlayer(); + if (player != null) { - qs.setCond(2, true); + final QuestState qs = getQuestState(player, false); + if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000)) + { + qs.setCond(2, true); + } } } } \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml new file mode 100644 index 0000000000..ea77878c2c --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/spawns/Others/FakePlayers.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml new file mode 100644 index 0000000000..8470293122 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_combat.xml @@ -0,0 +1,341 @@ + + + + + HUMAN + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + ORC + MALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + DWARF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + KAMAEL + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + HUMAN + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + + + DARK_ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + + + ELF + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + FAKE_PLAYER + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml new file mode 100644 index 0000000000..589f29b215 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/stats/npcs/custom/fpc_passive.xml @@ -0,0 +1,26 @@ + + + + + ERTHEIA + FEMALE + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd new file mode 100644 index 0000000000..2b2c94e75b --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerChatData.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd new file mode 100644 index 0000000000..0628acefc3 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/FakePlayerVisualData.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd index 6f00944cff..ae80c3ff63 100644 --- a/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd +++ b/L2J_Mobius_4.0_GrandCrusade/dist/game/data/xsd/npcs.xsd @@ -201,6 +201,8 @@ + +
    diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java index e7a921883b..841ae086c8 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/Config.java @@ -116,6 +116,7 @@ public final class Config public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini"; public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini"; public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini"; + public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini"; public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini"; public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini"; public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini"; @@ -1154,6 +1155,16 @@ public final class Config public static boolean FACTION_SPECIFIC_CHAT; public static boolean FACTION_BALANCE_ONLINE_PLAYERS; public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT; + public static boolean FAKE_PLAYERS_ENABLED; + public static boolean FAKE_PLAYER_CHAT; + public static boolean FAKE_PLAYER_USE_SHOTS; + public static boolean FAKE_PLAYER_KILL_PVP; + public static boolean FAKE_PLAYER_KILL_KARMA; + public static boolean FAKE_PLAYER_AGGRO_MONSTERS; + public static boolean FAKE_PLAYER_AGGRO_PLAYERS; + public static boolean FAKE_PLAYER_AGGRO_FPC; + public static boolean FAKE_PLAYER_CAN_DROP_ITEMS; + public static boolean FAKE_PLAYER_CAN_PICKUP; public static boolean ENABLE_FIND_PVP; public static boolean PREMIUM_SYSTEM_ENABLED; public static float PREMIUM_RATE_XP; @@ -2575,6 +2586,19 @@ public final class Config FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true); FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20); + // Load FakePlayers config file (if exists) + final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE); + FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false)); + FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false)); + FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false)); + FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false)); + FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false)); + FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false)); + FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false)); + FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false)); + FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false)); + FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false)); + // Load FindPvP config file (if exists) final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE); ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java index 8be60100d7..f90fd5cedc 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/GameServer.java @@ -61,6 +61,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData; import com.l2jmobius.gameserver.data.xml.impl.EventEngineData; import com.l2jmobius.gameserver.data.xml.impl.ExperienceData; import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.HennaData; import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData; @@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; import com.l2jmobius.gameserver.instancemanager.DBSpawnManager; import com.l2jmobius.gameserver.instancemanager.FactionManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.FortManager; import com.l2jmobius.gameserver.instancemanager.FortSiegeManager; import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; @@ -287,6 +289,8 @@ public class GameServer printSection("NPCs"); SkillLearnData.getInstance(); NpcData.getInstance(); + FakePlayerData.getInstance(); + FakePlayerChatManager.getInstance(); ExtendDropData.getInstance(); SpawnsData.getInstance(); MonsterBookData.getInstance(); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 6253fa9329..1da1b21546 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.model.AggroInfo; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate; import com.l2jmobius.gameserver.model.events.returns.TerminateReturn; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.skills.SkillCaster; @@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10 if (_globalAggro >= 0) { - if (npc.isAggressive() || (npc instanceof L2GuardInstance)) + if (npc.isFakePlayer() && npc.isAggressive()) + { + final List droppedItems = npc.getFakePlayerDrops(); + if (droppedItems.isEmpty()) + { + L2Character nearestTarget = null; + double closestDistance = Double.MAX_VALUE; + for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange())) + { + if ((t == _actor) || (t == null) || t.isDead()) + { + continue; + } + if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer())) + { + final int hating = npc.getHating(t); + final double distance = npc.calculateDistance(t, false, false); + if ((hating == 0) && (closestDistance > distance)) + { + nearestTarget = t; + closestDistance = distance; + } + } + } + if (nearestTarget != null) + { + npc.addDamageHate(nearestTarget, 0, 1); + } + } + else if (!npc.isInCombat()) // must pickup items + { + final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped + final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex); + if ((droppedItem != null) && droppedItem.isSpawned()) + { + if (npc.calculateDistance(droppedItem, false, false) > 50) + { + moveTo(droppedItem); + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + droppedItem.pickupMe(npc); + if (Config.SAVE_DROPPED_ITEM) + { + ItemsOnGroundManager.getInstance().removeObject(droppedItem); + } + if (droppedItem.getItem().hasExImmediateEffect()) + { + for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills()) + { + SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false); + } + npc.broadcastInfo(); // ? check if this is necessary + } + } + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + } + npc.setRunning(); + } + } + else if (npc.isAggressive() || (npc instanceof L2GuardInstance)) { final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players. L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t -> @@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // For each L2Character check if the target is autoattackable if (isAggressiveTowards(t)) // check aggression { - if (t.isPlayable()) + if (t.isFakePlayer()) + { + if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC)) + { + final int hating = npc.getHating(t); + if (hating == 0) + { + npc.addDamageHate(t, 0, 1); + } + } + } + else if (t.isPlayable()) { final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class); if ((term != null) && term.terminate()) diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java new file mode 100644 index 0000000000..0a6ca5267a --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java @@ -0,0 +1,125 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; + +/** + * @author Mobius + */ +public class FakePlayerData implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName()); + + private final Map _fakePlayerInfos = new HashMap<>(); + private final Map _fakePlayerNames = new HashMap<>(); + private final Map _fakePlayerIds = new HashMap<>(); + private final List _talkableFakePlayerNames = new ArrayList<>(); + + protected FakePlayerData() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + _fakePlayerInfos.clear(); + _fakePlayerNames.clear(); + _fakePlayerIds.clear(); + _talkableFakePlayerNames.clear(); + parseDatapackFile("data/FakePlayerVisualData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode)); + final int npcId = set.getInt("npcId"); + final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId); + final String name = template.getName(); + if (CharNameTable.getInstance().getIdByName(name) > 0) + { + LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists."); + } + else + { + _fakePlayerIds.put(name, npcId); // name - npcId + _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name + _fakePlayerInfos.put(npcId, new FakePlayerHolder(set)); + if (template.isFakePlayerTalkable()) + { + _talkableFakePlayerNames.add(name.toLowerCase()); + } + } + })); + } + + public int getNpcIdByName(String name) + { + return _fakePlayerIds.get(name); + } + + public String getProperName(String name) + { + return _fakePlayerNames.get(name.toLowerCase()); + } + + public Boolean isTalkable(String name) + { + return _talkableFakePlayerNames.contains(name.toLowerCase()); + } + + public FakePlayerHolder getInfo(int npcId) + { + return _fakePlayerInfos.get(npcId); + } + + public static FakePlayerData getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerData _instance = new FakePlayerData(); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java index 883e877bc7..f03a2395f1 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java @@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader set.set("hasSummoner", parseBoolean(attrs, "hasSummoner")); set.set("canBeSown", parseBoolean(attrs, "canBeSown")); set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty")); + set.set("fakePlayer", parseBoolean(attrs, "fakePlayer")); + set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable")); break; } case "skill_list": diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java index 2ff4c9322d..15bd310bd6 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java @@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader return; } + if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer()) + { + return; + } + for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) { if ("parameters".equalsIgnoreCase(d.getNodeName())) diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java index a145b65dba..d525c02a6a 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/BotReportTable.java @@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.zone.ZoneId; @@ -210,15 +212,14 @@ public final class BotReportTable public boolean reportBot(L2PcInstance reporter) { final L2Object target = reporter.getTarget(); - if (target == null) { return false; } - final L2PcInstance bot = target.getActingPlayer(); + final L2Character bot = ((L2Character) target); - if ((bot == null) || (target.getObjectId() == reporter.getObjectId())) + if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId())) { return false; } @@ -229,7 +230,7 @@ public final class BotReportTable return false; } - if (bot.isInOlympiadMode()) + if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode()) { reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD); return false; @@ -241,7 +242,7 @@ public final class BotReportTable return false; } - if (bot.getExp() == bot.getStat().getStartingExp()) + if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp())) { reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING); return false; @@ -320,15 +321,18 @@ public final class BotReportTable } SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT); - sm.addCharName(bot); + sm.addString(bot.getName()); reporter.sendPacket(sm); sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT); - sm.addCharName(bot); + sm.addString(bot.getName()); sm.addInt(rcdRep.getPointsLeft()); reporter.sendPacket(sm); - handleReport(bot, rcd); + if (bot.isPlayer()) + { + handleReport(bot.getActingPlayer(), rcd); + } return true; } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java index 7454554076..ace19486b5 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/datatables/ItemTable.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -202,11 +203,11 @@ public class ItemTable * @param process : String Identifier of process triggering this action * @param itemId : int Item Identifier of the item to be created * @param count : int Quantity of items to be created for stackable items - * @param actor : L2PcInstance Player requesting the item creation + * @param actor : L2Character requesting the item creation * @param reference : Object Object referencing current action like NPC selling item or previous item in transformation * @return L2ItemInstance corresponding to the new item */ - public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference) + public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference) { // Create and Init the L2ItemInstance corresponding to the Item Identifier final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java index b621b4c4cb..bb0e928daf 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/idfactory/IdFactory.java @@ -217,6 +217,7 @@ public abstract class IdFactory cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); + cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); // If the clan does not exist... cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java new file mode 100644 index 0000000000..16a0da92bc --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java @@ -0,0 +1,196 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.instancemanager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2Spawn; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder; +import com.l2jmobius.gameserver.network.serverpackets.CreatureSay; + +/** + * @author Mobius + */ +public final class FakePlayerChatManager implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName()); + final List MESSAGES = new ArrayList<>(); + private static final int MIN_DELAY = 5000; + private static final int MAX_DELAY = 15000; + + protected FakePlayerChatManager() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT) + { + MESSAGES.clear(); + parseDatapackFile("data/FakePlayerChatData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode)); + MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers"))); + })); + } + + public void manageChat(L2PcInstance player, String fpcName, String message) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY)); + } + + public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay)); + } + + private void manageResponce(L2PcInstance player, String fpcName, String message) + { + if (player == null) + { + return; + } + + final String text = message.toLowerCase(); + + // tricky question + if (text.contains("can you see me")) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + if (npc.calculateDistance(player, false, false) < 3000) + { + if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible()) + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes"); + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?"); + } + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no"); + } + return; + } + } + } + + for (FakePlayerChatHolder chatHolder : MESSAGES) + { + if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL")) + { + continue; + } + + switch (chatHolder.getSearchMethod()) + { + case "EQUALS": + { + if (text.equals(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "STARTS_WITH": + { + if (text.startsWith(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "CONTAINS": + { + boolean allFound = true; + for (String word : chatHolder.getSearchText()) + { + if (!text.contains(word)) + { + allFound = false; + } + } + if (allFound) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + } + } + } + + public void sendChat(L2PcInstance player, String fpcName, String message) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message)); + } + } + } + + public static FakePlayerChatManager getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerChatManager _instance = new FakePlayerChatManager(); + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java index 1a62714f0e..50a3cc2145 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/DropProtection.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model; import java.util.concurrent.ScheduledFuture; import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; @@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; public class DropProtection implements Runnable { private volatile boolean _isProtected = false; - private L2PcInstance _owner = null; + private L2Character _owner = null; private ScheduledFuture _task = null; private static final long PROTECTED_MILLIS_TIME = 15000; @@ -46,7 +47,7 @@ public class DropProtection implements Runnable return _isProtected; } - public L2PcInstance getOwner() + public L2Character getOwner() { return _owner; } @@ -91,12 +92,12 @@ public class DropProtection implements Runnable _task = null; } - public synchronized void protect(L2PcInstance player) + public synchronized void protect(L2Character character) { unprotect(); _isProtected = true; - _owner = player; + _owner = character; if (_owner == null) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java index 459660c7ca..92837e4b25 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/L2Object.java @@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab return false; } + /** + * Verify if object is a fake player. + * @return {@code true} if object is a fake player, {@code false} otherwise + */ + public boolean isFakePlayer() + { + return false; + } + /** * Verify if object is instance of L2ServitorInstance. * @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 2ecce60d39..ddc1a1b8d4 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.L2Item; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; @@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc public synchronized boolean getMustRewardExpSP() { - return _mustGiveExpSp; + return _mustGiveExpSp && !isFakePlayer(); } /** @@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc // Don't drop anything if the last attacker or owner isn't L2PcInstance if (player == null) { + // unless its a fake player and they can drop items + if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS) + { + final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer); + if (deathItems != null) + { + for (ItemHolder drop : deathItems) + { + final L2Item item = ItemTable.getInstance().getTemplate(drop.getId()); + // Check if the autoLoot mode is active + if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS)))) + { + // do nothing + } + else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect()) + { + for (SkillHolder skillHolder : item.getAllSkills()) + { + SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false); + } + mainDamageDealer.broadcastInfo(); // ? check if this is necessary + } + else + { + final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground + if (Config.FAKE_PLAYER_CAN_PICKUP) + { + mainDamageDealer.getFakePlayerDrops().add(droppedItem); + } + } + } + } + } return; } @@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc */ public void doEventDrop(L2Character lastAttacker) { - if (lastAttacker == null) + if ((lastAttacker == null) || isFakePlayer()) { return; } @@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc _harvestItem.set(null); _sweepItems.set(null); + // fake players + if (isFakePlayer()) + { + getFakePlayerDrops().clear(); // Clear existing fake player drops + setReputation(0); // reset reputation + setScriptValue(0); // remove pvp flag + setRunning(); // don't walk + } + // Clear mod Seeded stat _seeded = false; _seed = null; diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 226b8e981a..6dd50e079f 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -30,6 +30,7 @@ import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.CharEffectList; @@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack; import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType; import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType; import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private int _reputation = 0; + /** Map containing all skills of this character. */ private final Map _skills = new ConcurrentSkipListMap<>(); /** Map containing the skill reuse time stamps. */ @@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe /** A set containing the shot types currently charged. */ private Set _chargedShots = EnumSet.noneOf(ShotType.class); + /** A list containing the dropped items of this fake player. */ + private final List _fakePlayerDrops = new CopyOnWriteArrayList<>(); + /** * Creates a creature. * @param template the creature template @@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe broadcastPacket(attack); } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) + { + final L2Npc npc = ((L2Npc) this); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + // Notify AI with EVT_READY_TO_ACT ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk); } @@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean isInsidePeaceZone(L2Object attacker, L2Object target) { final Instance instanceWorld = getInstanceWorld(); - if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) + if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) { return false; } @@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist()); } + public int getReputation() + { + return _reputation; + } + + public void setReputation(int reputation) + { + _reputation = reputation; + } + /** * Gets the distance to target. * @param target the target @@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { _cursorKeyMovement = value; } + + public List getFakePlayerDrops() + { + return _fakePlayerDrops; + } } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index 5742c07807..b669e16e76 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; +import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.handler.BypassHandler; import com.l2jmobius.gameserver.handler.IBypassHandler; import com.l2jmobius.gameserver.instancemanager.CastleManager; @@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.olympiad.Olympiad; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate; +import com.l2jmobius.gameserver.model.stats.Formulas; import com.l2jmobius.gameserver.model.variables.NpcVariables; import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.NpcStringId; @@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState; import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse; import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec import com.l2jmobius.gameserver.network.serverpackets.NpcSay; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; +import com.l2jmobius.gameserver.network.serverpackets.UserInfo; import com.l2jmobius.gameserver.taskmanager.DecayTaskManager; import com.l2jmobius.gameserver.util.Broadcast; @@ -125,6 +130,7 @@ public class L2Npc extends L2Character private boolean _isRandomAnimationEnabled = true; private boolean _isRandomWalkingEnabled = true; private boolean _isTalkable = getTemplate().isTalkable(); + private final boolean _isFakePlayer = getTemplate().isFakePlayer(); protected RandomAnimationTask _rAniTask; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -364,7 +370,11 @@ public class L2Npc extends L2Character return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo(this, player)); } @@ -901,6 +911,78 @@ public class L2Npc extends L2Character final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null; _killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0; + if (isFakePlayer() && (killer != null) && killer.isPlayable()) + { + final L2PcInstance player = killer.getActingPlayer(); + if (isScriptValue(0) && (getReputation() >= 0)) + { + if (Config.FAKE_PLAYER_KILL_KARMA) + { + player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon())); + player.setPkKills(player.getPkKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + player.checkItemRestriction(); + // pk item rewards + if (Config.REWARD_PK_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } + // announce pk + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + else if (Config.FAKE_PLAYER_KILL_PVP) + { + player.setPvpKills(player.getPvpKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + // pvp item rewards + if (Config.REWARD_PVP_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + } + // announce pvp + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + DecayTaskManager.getInstance().add(this); final L2Spawn spawn = getSpawn(); @@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character activeChar.sendMessage("Added NPC: " + getName()); } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + activeChar.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { activeChar.sendPacket(new ServerObjectInfo(this, activeChar)); } @@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character @Override public void rechargeShots(boolean physical, boolean magic, boolean fish) { - if (physical && (_soulshotamount > 0)) + if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS) { - if (Rnd.get(100) > getTemplate().getSoulShotChance()) + if (physical) { - return; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9193, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic) + { + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 9195, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _soulshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); - chargeShot(ShotType.SOULSHOTS); } - - if (magic && (_spiritshotamount > 0)) + else { - if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + if (physical && (_soulshotamount > 0)) { - return; + if (Rnd.get(100) > getTemplate().getSoulShotChance()) + { + return; + } + _soulshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic && (_spiritshotamount > 0)) + { + if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + { + return; + } + _spiritshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _spiritshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); - chargeShot(ShotType.SPIRITSHOTS); } } @@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character /** * Drops an item. - * @param player the last attacker or main damage dealer + * @param character the last attacker or main damage dealer * @param itemId the item ID * @param itemCount the item count * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount) + public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount) { L2ItemInstance item = null; for (int i = 0; i < itemCount; i++) @@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character return null; } - item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this); + item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this); if (item == null) { return null; } - if (player != null) + if (character != null) { - item.getDropProtection().protect(player); + item.getDropProtection().protect(character); } item.dropMe(this, newX, newY, newZ); @@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character } /** - * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)} - * @param player the last attacker or main damage dealer + * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)} + * @param character the last attacker or main damage dealer * @param item the item holder * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item) + public L2ItemInstance dropItem(L2Character character, ItemHolder item) { - return dropItem(player, item.getId(), item.getCount()); + return dropItem(character, item.getId(), item.getCount()); } @Override @@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character return Config.SHOP_MIN_RANGE_FROM_NPC; } + @Override + public boolean isFakePlayer() + { + return _isFakePlayer; + } + /** * @return The player's object Id this NPC is cloning. */ diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java index 34550c3dd8..10ad419ea4 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Playable.java @@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character public abstract void doPickupItem(L2Object object); - public abstract int getReputation(); - public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove); public abstract void storeMe(); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index 8427885746..87cc552765 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } @@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable { setTarget(target); getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); + if (target.isFakePlayer()) + { + getOwner().updatePvPStatus(); + } } } } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java index a5fd31dedd..44ee919058 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java @@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java index aa4f132fce..6a94be63b5 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java @@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { - if (attacker.isMonster()) + if (attacker.isMonster() && !attacker.isFakePlayer()) { return true; } @@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); } + if (isFakePlayer() && isInCombat()) + { + interact = false; + // TODO: Fix normal targeting + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); + } + // Check if the L2PcInstance already target the L2GuardInstance if (getObjectId() != player.getTargetId()) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java index e9a9976e87..fe55288a3a 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java @@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { + if (isFakePlayer()) + { + return isInCombat() || attacker.isMonster() || (getScriptValue() > 0); + } + // Check if the L2MonsterInstance target is aggressive if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance)) { @@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable if (attacker.isMonster()) { - return false; + return attacker.isFakePlayer(); } // Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints. diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index c41f46c7d1..b561365375 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -450,9 +450,6 @@ public final class L2PcInstance extends L2Playable /** The Experience of the L2PcInstance before the last Death Penalty */ private long _expBeforeDeath; - /** The Reputation of the L2PcInstance */ - private int _reputation; - /** The number of player killed during a PvP (the player killed was PvP Flagged) */ private int _pvpKills; @@ -2013,24 +2010,16 @@ public final class L2PcInstance extends L2Playable return _expBeforeDeath; } - /** - * @return the reputation of the PlayerInstance. - */ - @Override - public int getReputation() - { - return _reputation; - } - public void setInitialReputation(int reputation) { - _reputation = reputation; + super.setReputation(reputation); } /** * Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast). * @param reputation */ + @Override public void setReputation(int reputation) { // Notify to scripts. @@ -2056,7 +2045,9 @@ public final class L2PcInstance extends L2Playable } }); } - _reputation = reputation; + + super.setReputation(reputation); + sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation())); broadcastReputation(); } @@ -4655,6 +4646,10 @@ public final class L2PcInstance extends L2Playable { super.doAttack(target); setRecentFakeDeath(false); + if (target.isFakePlayer()) + { + updatePvPStatus(); + } } @Override @@ -4982,22 +4977,42 @@ public final class L2PcInstance extends L2Playable if (killer != null) { final L2PcInstance pk = killer.getActingPlayer(); - if (pk != null) + final boolean fpcKill = killer.isFakePlayer(); + if ((pk != null) || fpcKill) { - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); - - if (L2Event.isParticipant(pk)) + if (pk != null) { - pk.getEventStatus().addKill(this); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); + + if (L2Event.isParticipant(pk)) + { + pk.getEventStatus().addKill(this); + } + + // pvp/pk item rewards + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + // pvp + if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) + { + pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + // pk + if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) + { + pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } } // announce pvp/pk - if (Config.ANNOUNCE_PK_PVP && !pk.isGM()) + if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill)) { String msg = ""; if (getPvpFlag() == 0) { - msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5011,7 +5026,7 @@ public final class L2PcInstance extends L2Playable } else if (getPvpFlag() != 0) { - msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -5025,20 +5040,9 @@ public final class L2PcInstance extends L2Playable } } - // pvp/pk item rewards - if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // - !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0)) { - // pvp - if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) - { - pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); - } - // pk - if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) - { - pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); - } + killer.setReputation(killer.getReputation() - 150); } } @@ -5631,6 +5635,14 @@ public final class L2PcInstance extends L2Playable return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks()); } + /** + * Used by fake players to emulate proper behavior. + */ + public void blockRequest() + { + _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND); + } + /** * Select the Warehouse to be used in next activity. * @param partner @@ -11568,7 +11580,7 @@ public final class L2PcInstance extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addPcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java index fb6b184e67..8383d1efc9 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java @@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc return null; } + @Override public int getReputation() { return _owner != null ? _owner.getReputation() : 0; @@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addCharName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); _owner.sendPacket(sm); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java index dcb3ab34da..164786d5a4 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java @@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus } } - if (attacker.isPlayable() && (caster.getCurrentCp() > 0)) + if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0)) { if (caster.getCurrentCp() > transferDmg) { @@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus } } - if (!ignoreCP && attacker.isPlayable()) + if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer())) { if (getCurrentCp() >= value) { @@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus // Send a System Message to the L2PcInstance SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addCharName(attacker); + smsg.addString(attacker.getName()); smsg.addInt(fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java index 2d7f41e9d0..f5bee5dab6 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java @@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable private boolean _randomWalk; private boolean _randomAnimation; private boolean _flying; + private boolean _fakePlayer; + private boolean _fakePlayerTalkable; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; @@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable _randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard")); _randomAnimation = set.getBoolean("randomAnimation", true); _flying = set.getBoolean("flying", false); + _fakePlayer = set.getBoolean("fakePlayer", false); + _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true); _canMove = set.getBoolean("canMove", true); _noSleepMode = set.getBoolean("noSleepMode", false); _passableDoor = set.getBoolean("passableDoor", false); @@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable return _flying; } + public boolean isFakePlayer() + { + return _fakePlayer; + } + + public boolean isFakePlayerTalkable() + { + return _fakePlayerTalkable; + } + public boolean canMove() { return _canMove; @@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null) { @@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null) { @@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable case LUCKY_DROP: { // try chance before luck - if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck()) + if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck()) { return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax())); } @@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // chance double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER; // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE; } @@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // amount is calculated after chance returned success double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER; // premium amount - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT; } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java index df9698d3c3..6cbe42b242 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.events.impl.item; -import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.events.EventType; import com.l2jmobius.gameserver.model.events.impl.IBaseEvent; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; @@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent { private final String _process; private final L2ItemInstance _item; - private final L2PcInstance _activeChar; + private final L2Character _activeChar; private final Object _reference; - public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference) + public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference) { _process = process; _item = item; @@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent return _item; } - public L2PcInstance getActiveChar() + public L2Character getActiveChar() { return _activeChar; } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java new file mode 100644 index 0000000000..3008d340b3 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java @@ -0,0 +1,60 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Mobius + */ +public class FakePlayerChatHolder +{ + private final String _fpcName; + private final String _searchMethod; + private final List _searchText; + private final List _answers; + + public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers) + { + _fpcName = fpcName; + _searchMethod = searchMethod; + _searchText = new ArrayList<>(Arrays.asList(searchText.split(";"))); + _answers = new ArrayList<>(Arrays.asList(answers.split(";"))); + } + + public String getFpcName() + { + return _fpcName; + } + + public String getSearchMethod() + { + return _searchMethod; + } + + public List getSearchText() + { + return _searchText; + } + + public List getAnswers() + { + return _answers; + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java new file mode 100644 index 0000000000..2f8aa1fa6d --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java @@ -0,0 +1,232 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class FakePlayerHolder +{ + private final int _classId; + private final int _hair; + private final int _hairColor; + private final int _face; + private final int _nameColor; + private final int _titleColor; + private final int _equipHead; + private final int _equipRHand; + private final int _equipLHand; + private final int _equipGloves; + private final int _equipChest; + private final int _equipLegs; + private final int _equipFeet; + private final int _equipCloak; + private final int _equipHair; + private final int _equipHair2; + private final int _agathionId; + private final int _weaponEnchantLevel; + private final int _armorEnchantLevel; + private final boolean _fishing; + private final int _baitLocationX; + private final int _baitLocationY; + private final int _baitLocationZ; + private final int _recommends; + private final int _nobleLevel; + private final boolean _hero; + private final int _clanId; + private final int _pledgeStatus; + + public FakePlayerHolder(StatsSet set) + { + _classId = set.getInt("classId", 182); + + _hair = set.getInt("hair", 1); + _hairColor = set.getInt("hairColor", 1); + _face = set.getInt("face", 1); + + _nameColor = set.getInt("nameColor", 0xFFFFFF); + _titleColor = set.getInt("titleColor", 0xECF9A2); + + _equipHead = set.getInt("equipHead", 0); + _equipRHand = set.getInt("equipRHand", 0); // or dual hand + _equipLHand = set.getInt("equipLHand", 0); + _equipGloves = set.getInt("equipGloves", 0); + _equipChest = set.getInt("equipChest", 0); + _equipLegs = set.getInt("equipLegs", 0); + _equipFeet = set.getInt("equipFeet", 0); + _equipCloak = set.getInt("equipCloak", 0); + _equipHair = set.getInt("equipHair", 0); + _equipHair2 = set.getInt("equipHair2", 0); + _agathionId = set.getInt("agathionId", 0); + + _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0); + _armorEnchantLevel = set.getInt("armorEnchantLevel", 0); + + _fishing = set.getBoolean("fishing", false); + _baitLocationX = set.getInt("baitLocationX", 0); + _baitLocationY = set.getInt("baitLocationY", 0); + _baitLocationZ = set.getInt("baitLocationZ", 0); + + _recommends = set.getInt("recommends", 0); + _nobleLevel = set.getInt("nobleLevel", 0); + _hero = set.getBoolean("hero", false); + _clanId = set.getInt("clanId", 0); + _pledgeStatus = set.getInt("pledgeStatus", 0); + } + + public int getClassId() + { + return _classId; + } + + public int getHair() + { + return _hair; + } + + public int getHairColor() + { + return _hairColor; + } + + public int getFace() + { + return _face; + } + + public int getNameColor() + { + return _nameColor; + } + + public int getTitleColor() + { + return _titleColor; + } + + public int getEquipHead() + { + return _equipHead; + } + + public int getEquipRHand() + { + return _equipRHand; + } + + public int getEquipLHand() + { + return _equipLHand; + } + + public int getEquipGloves() + { + return _equipGloves; + } + + public int getEquipChest() + { + return _equipChest; + } + + public int getEquipLegs() + { + return _equipLegs; + } + + public int getEquipFeet() + { + return _equipFeet; + } + + public int getEquipCloak() + { + return _equipCloak; + } + + public int getEquipHair() + { + return _equipHair; + } + + public int getEquipHair2() + { + return _equipHair2; + } + + public int getAgathionId() + { + return _agathionId; + } + + public int getWeaponEnchantLevel() + { + return _weaponEnchantLevel; + } + + public int getArmorEnchantLevel() + { + return _armorEnchantLevel; + } + + public boolean isFishing() + { + return _fishing; + } + + public int getBaitLocationX() + { + return _baitLocationX; + } + + public int getBaitLocationY() + { + return _baitLocationY; + } + + public int getBaitLocationZ() + { + return _baitLocationZ; + } + + public int getRecommends() + { + return _recommends; + } + + public int getNobleLevel() + { + return _nobleLevel; + } + + public boolean isHero() + { + return _hero; + } + + public int getClanId() + { + return _clanId; + } + + public int getPledgeStatus() + { + return _pledgeStatus; + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index fb63011022..d429fbfee8 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object *
    *
  • Do Pickup Item : PCInstance and Pet

  • *
    - * @param player Player that pick up the item + * @param character Character that pick up the item */ - public final void pickupMe(L2Character player) + public final void pickupMe(L2Character character) { assert getWorldRegion() != null; final L2WorldRegion oldregion = getWorldRegion(); // Create a server->client GetItem packet to pick up the L2ItemInstance - player.broadcastPacket(new GetItem(this, player.getObjectId())); + character.broadcastPacket(new GetItem(this, character.getObjectId())); synchronized (this) { @@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object // Remove the L2ItemInstance from the world L2World.getInstance().removeVisibleObject(this, oldregion); - if (player.isPlayer()) + if (character.isPlayer()) { // Notify to scripts - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem()); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem()); } } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java index 83f6e88b77..7505001c60 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable public boolean checkCondition(L2Character activeChar, L2Object object) { - if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION) + if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)) { return true; } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index b7eda58d00..13932008ff 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -159,7 +160,7 @@ public class SkillCaster implements Runnable } // You should not heal/buff monsters without pressing the ctrl button. - if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed) + if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed) { caster.sendPacket(SystemMessageId.INVALID_TARGET); return null; @@ -609,6 +610,10 @@ public class SkillCaster implements Runnable // Add hate to the attackable, and put it in the attack list. ((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint()); ((L2Character) obj).addAttackerToAttackByList(caster); + if (obj.isFakePlayer()) + { + player.updatePvPStatus(); + } } // notify target AI about the attack @@ -617,10 +622,19 @@ public class SkillCaster implements Runnable ((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster); } } - else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0)))) + else if (((skill.getEffectPoint() > 0) && obj.isMonster()) // + || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) // + || (((L2Character) obj).getReputation() < 0) // + ))) { // Supporting players or monsters result in pvpflag. - player.updatePvPStatus(); + if (!obj.isFakePlayer() // + || (obj.isFakePlayer() // + && (!((L2Npc) obj).isScriptValue(0) // + || (((L2Npc) obj).getReputation() < 0)))) + { + player.updatePvPStatus(); + } } } @@ -630,7 +644,7 @@ public class SkillCaster implements Runnable EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob); // On Skill See logic - if (npcMob.isAttackable()) + if (npcMob.isAttackable() && !npcMob.isFakePlayer()) { final L2Attackable attackable = (L2Attackable) npcMob; @@ -652,6 +666,19 @@ public class SkillCaster implements Runnable } }); } + else if (caster.isFakePlayer()) // fake player attacks player + { + if (target.isPlayable() || target.isFakePlayer()) + { + final L2Npc npc = ((L2Npc) caster); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + npc.broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + } } catch (Exception e) { @@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable return false; } } - return true; } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java index fdf0dadf55..06bea1b4cf 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java @@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.zone.L2ZoneType; import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; @@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } @@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java index 91a9ce830a..ccd2d1d13a 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/Action.java @@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket } case 1: { - if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC)) + if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer())) { obj.onAction(activeChar, false); } diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java index 876c53c093..06464d9911 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java @@ -22,6 +22,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData; import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData; import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; @@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket return; } - if (Config.FORBIDDEN_NAMES.length > 1) + if (Config.FORBIDDEN_NAMES.length > 0) { for (String st : Config.FORBIDDEN_NAMES) { @@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().getProperName(_name) != null) + { + client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); + return; + } + // Last Verified: May 30, 2009 - Gracia Final if (!Util.isAlphaNumeric(_name) || !isValidName(_name)) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java index 06bfa3c200..01c8b0c67f 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java @@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; public final class RequestBlock implements IClientIncomingPacket { @@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket case BLOCK: case UNBLOCK: { + // TODO: Save in database? :P + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (_type == BLOCK) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + return; + } + // can't use block/unblock for locating invisible characters if (targetId <= 0) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java index ceb67b0f5f..cf79bdb24c 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable; import com.l2jmobius.gameserver.util.Util; @@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket { result = NAME_ALREADY_EXISTS; } + else if (FakePlayerData.getInstance().getProperName(_name) != null) + { + result = NAME_ALREADY_EXISTS; + } else if (_name.length() > 16) { result = INVALID_LENGTH; diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java index b0ace828dc..ee8bcd656b 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java @@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Party; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart; @@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance activeChar = client.getActiveChar(); - final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (activeChar == null) { return; } + + if (FakePlayerData.getInstance().isTalkable(_player)) + { + final String name = FakePlayerData.getInstance().getProperName(_player); + if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + if (activeChar.isProcessingRequest()) + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(name); + activeChar.sendPacket(msg); + return; + } + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL); + sm.addString(name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000); + activeChar.blockRequest(); + return; + } + + final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (targetChar == null) { activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java index f104c94161..c0042d45c5 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java @@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PartyDistributionType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Party; @@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + if (player.getParty() == null) + { + player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED); + } + else + { + player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY); + } + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance requestor = client.getActiveChar(); - final L2PcInstance target = L2World.getInstance().getPlayer(_name); - if (requestor == null) { return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + requestor.sendPacket(sm); + if (!requestor.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000); + requestor.blockRequest(); + } + else + { + requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY); + } + return; + } + + final L2PcInstance target = L2World.getInstance().getPlayer(_name); if (target == null) { requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java index 292153afd8..37c539556f 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java @@ -17,12 +17,15 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; /** * This class ... @@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket return; } + if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName()))) + { + if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0) + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN); + } + else + { + if (!activeChar.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(activeChar.getTarget().getName()); + activeChar.sendPacket(msg); + } + } + return; + } + final L2PcInstance target = L2World.getInstance().getPlayer(_target); if (target == null) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java index 3d5bcaeca5..9cbb114e88 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java @@ -23,6 +23,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.instancemanager.MailManager; import com.l2jmobius.gameserver.model.BlockList; @@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().isTalkable(_receiver)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1); + sm.addString(FakePlayerData.getInstance().getProperName(_receiver)); + activeChar.sendPacket(sm); + return; + } + final int receiverId = CharNameTable.getInstance().getIdByName(_receiver); if (receiverId <= 0) { diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java index 8156905e94..1336c2bdb7 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java @@ -17,6 +17,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; @@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket } final L2Object object = activeChar.getTarget(); - if (!(object instanceof L2PcInstance)) { if (object == null) { client.sendPacket(SystemMessageId.SELECT_TARGET); } + else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName())) + { + if (activeChar.getRecomLeft() <= 0) + { + client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER); + return; + } + + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT); + sm.addString(FakePlayerData.getInstance().getProperName(object.getName())); + sm.addInt(activeChar.getRecomLeft()); + client.sendPacket(sm); + + activeChar.setRecomLeft(activeChar.getRecomLeft() - 1); + client.sendPacket(new UserInfo(activeChar)); + client.sendPacket(new ExVoteSystemInfo(activeChar)); + } else { client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java index d77dc881b3..5d7e35eb43 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java @@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.effects.AbstractEffect; import com.l2jmobius.gameserver.model.skills.AbnormalType; @@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final String name = FakePlayerData.getInstance().getProperName(target.getName()); + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE)); + return; + } + if (!player.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1); + sm.addString(name); + player.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000); + player.blockRequest(); + } + else + { + player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE); + } + return; + } + if (!target.isPlayer()) { client.sendPacket(SystemMessageId.INVALID_TARGET); diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java index 4fa25283a7..530a6d7a01 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java @@ -17,6 +17,8 @@ package com.l2jmobius.gameserver.network.clientpackets.friend; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST)); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (!activeChar.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST); + sm.addString(_name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + sm.addString(_name); + activeChar.sendPacket(sm); + } + return; + } + final L2PcInstance friend = L2World.getInstance().getPlayer(_name); // Target is not found in the game. diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java index 2170ef2e94..017541bd86 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java @@ -22,6 +22,7 @@ import java.util.List; import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.instancemanager.MentorManager; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.NpcStringId; import com.l2jmobius.gameserver.network.OutgoingPackets; @@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket _charLevel = sender.getLevel(); _textType = messageType; _text = text; - if (receiver.getFriendList().contains(sender.getObjectId())) + if (receiver != null) { - _mask |= 0x01; - } - if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) - { - _mask |= 0x02; - } - if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) - { - _mask |= 0x04; - } - if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) - { - _mask |= 0x08; + if (receiver.getFriendList().contains(sender.getObjectId())) + { + _mask |= 0x01; + } + if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) + { + _mask |= 0x02; + } + if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) + { + _mask |= 0x04; + } + if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) + { + _mask |= 0x08; + } } // Does not shows level @@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket } } + /** + * Used by fake players. + * @param sender + * @param receiver + * @param name + * @param messageType + * @param text + */ + public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text) + { + _objectId = sender.getObjectId(); + _charName = name; + _charLevel = sender.getLevel(); + _textType = messageType; + _text = text; + } + /** * @param objectId * @param messageType diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java new file mode 100644 index 0000000000..317d7c7312 --- /dev/null +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java @@ -0,0 +1,232 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.network.serverpackets; + +import java.util.Set; + +import com.l2jmobius.commons.network.PacketWriter; +import com.l2jmobius.gameserver.data.sql.impl.ClanTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.enums.Sex; +import com.l2jmobius.gameserver.model.L2Clan; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; +import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect; +import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.OutgoingPackets; + +/** + * @author Mobius + */ +public class FakePlayerInfo implements IClientOutgoingPacket +{ + private final L2Npc _npc; + private final int _objId; + private final int _x, _y, _z, _heading; + private final int _mAtkSpd, _pAtkSpd; + private final int _runSpd, _walkSpd; + private final int _swimRunSpd; + private final int _swimWalkSpd; + private final int _flyRunSpd; + private final int _flyWalkSpd; + private final double _moveMultiplier; + private final float _attackSpeedMultiplier; + private final FakePlayerHolder _fpcHolder; + private final L2Clan _clan; + + public FakePlayerInfo(L2Npc npc) + { + _npc = npc; + _objId = npc.getObjectId(); + _x = npc.getX(); + _y = npc.getY(); + _z = npc.getZ(); + _heading = npc.getHeading(); + _mAtkSpd = npc.getMAtkSpd(); + _pAtkSpd = npc.getPAtkSpd(); + _attackSpeedMultiplier = npc.getAttackSpeedMultiplier(); + _moveMultiplier = npc.getMovementSpeedMultiplier(); + _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier); + _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier); + _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier); + _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier); + _flyRunSpd = npc.isFlying() ? _runSpd : 0; + _flyWalkSpd = npc.isFlying() ? _walkSpd : 0; + _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId()); + _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId()); + } + + @Override + public boolean write(PacketWriter packet) + { + OutgoingPackets.CHAR_INFO.writeId(packet); + packet.writeC(0x00); // Grand Crusade + packet.writeD(_x); + packet.writeD(_y); + packet.writeD(_z); + packet.writeD(0x00); // vehicleId + packet.writeD(_objId); + packet.writeS(_npc.getName()); + + packet.writeH(_npc.getRace().ordinal()); + packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00); + packet.writeD(_fpcHolder.getClassId()); + + packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER + packet.writeD(_fpcHolder.getEquipHead()); + packet.writeD(_fpcHolder.getEquipRHand()); + packet.writeD(_fpcHolder.getEquipLHand()); + packet.writeD(_fpcHolder.getEquipGloves()); + packet.writeD(_fpcHolder.getEquipChest()); + packet.writeD(_fpcHolder.getEquipLegs()); + packet.writeD(_fpcHolder.getEquipFeet()); + packet.writeD(_fpcHolder.getEquipCloak()); + packet.writeD(_fpcHolder.getEquipRHand()); // dual hand + packet.writeD(_fpcHolder.getEquipHair()); + packet.writeD(_fpcHolder.getEquipHair2()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderAugument()) + { + packet.writeQ(0x00); + } + + packet.writeC(_fpcHolder.getArmorEnchantLevel()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderVisualId()) + { + packet.writeD(0x00); + } + + packet.writeC(_npc.getScriptValue()); // getPvpFlag() + packet.writeD(_npc.getReputation()); + + packet.writeD(_mAtkSpd); + packet.writeD(_pAtkSpd); + + packet.writeH(_runSpd); + packet.writeH(_walkSpd); + packet.writeH(_swimRunSpd); + packet.writeH(_swimWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeF(_moveMultiplier); + packet.writeF(_attackSpeedMultiplier); + + packet.writeF(_npc.getCollisionRadius()); + packet.writeF(_npc.getCollisionHeight()); + + packet.writeD(_fpcHolder.getHair()); + packet.writeD(_fpcHolder.getHairColor()); + packet.writeD(_fpcHolder.getFace()); + + packet.writeS(_npc.getTemplate().getTitle()); + + if (_clan != null) + { + packet.writeD(_clan.getId()); + packet.writeD(_clan.getCrestId()); + packet.writeD(_clan.getAllyId()); + packet.writeD(_clan.getAllyCrestId()); + } + else + { + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + } + + packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked) + packet.writeC(_npc.isRunning() ? 0x01 : 0x00); + packet.writeC(_npc.isInCombat() ? 0x01 : 0x00); + + packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00); + + packet.writeC(_npc.isInvisible() ? 0x01 : 0x00); + + packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount + packet.writeC(0x00); // getPrivateStoreType().getId() + + packet.writeH(0x00); // getCubics().size() + // getCubics().keySet().forEach(packet::writeH); + + packet.writeC(0x00); + + packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0); + packet.writeH(_fpcHolder.getRecommends()); + packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000 + + packet.writeD(_fpcHolder.getClassId()); + packet.writeD(0x00); + packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel + + packet.writeC(_npc.getTeam().getId()); + + packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00); + packet.writeC(_fpcHolder.getNobleLevel()); + packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00); + + packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00); + + packet.writeD(_fpcHolder.getBaitLocationX()); + packet.writeD(_fpcHolder.getBaitLocationY()); + packet.writeD(_fpcHolder.getBaitLocationZ()); + + packet.writeD(_fpcHolder.getNameColor()); + + packet.writeD(_heading); + + packet.writeC(_fpcHolder.getPledgeStatus()); + packet.writeH(0x00); // getPledgeType() + + packet.writeD(_fpcHolder.getTitleColor()); + + packet.writeC(0x00); // isCursedWeaponEquipped + + packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0 + packet.writeD(0x00); // getTransformationDisplayId() + packet.writeD(_fpcHolder.getAgathionId()); + + packet.writeC(0x00); + + packet.writeD(0x00); // getCurrentCp() + packet.writeD(_npc.getMaxHp()); + packet.writeD((int) Math.round(_npc.getCurrentHp())); + packet.writeD(_npc.getMaxMp()); + packet.writeD((int) Math.round(_npc.getCurrentMp())); + + packet.writeC(0x00); + final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects(); + packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0)); + for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects) + { + packet.writeH(abnormalVisualEffect.getClientId()); + } + if (_npc.isInvisible()) + { + packet.writeH(AbnormalVisualEffect.STEALTH.getClientId()); + } + packet.writeC(0x00); // cocPlayer.getPosition() + packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00); + packet.writeC(0x00); // Used Ability Points + return true; + } +} diff --git a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index 4fb1a757e6..c294edab2a 100644 --- a/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_4.0_GrandCrusade/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket addComponentType(NpcInfoType.TITLE_NPCSTRINGID); } + if (_npc.getReputation() != 0) + { + addComponentType(NpcInfoType.REPUTATION); + } + if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible()) { addComponentType(NpcInfoType.ABNORMALS); @@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.REPUTATION)) { - packet.writeD(0x00); // Name color + packet.writeD(_npc.getReputation()); // Reputation } if (containsMask(NpcInfoType.CLAN)) { diff --git a/L2J_Mobius_4.0_GrandCrusade/readme.txt b/L2J_Mobius_4.0_GrandCrusade/readme.txt index 5a1848fb6c..a90279520e 100644 --- a/L2J_Mobius_4.0_GrandCrusade/readme.txt +++ b/L2J_Mobius_4.0_GrandCrusade/readme.txt @@ -105,6 +105,7 @@ Customs: -Classmaster -Community board -Faction system +-Fake players -Find PvP -NPC stat multipliers -Realtime offline trade diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml index f538dfbbf2..d74ab987f6 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/AdminCommands.xml @@ -392,6 +392,9 @@ + + + diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini new file mode 100644 index 0000000000..f745b0d31e --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/config/Custom/FakePlayers.ini @@ -0,0 +1,33 @@ +# --------------------------------------------------------------------------- +# Fake players +# --------------------------------------------------------------------------- + +# Enable fake players. +EnableFakePlayers = False + +# Enable chatting with fake players. +FakePlayerChat = True + +# Enable shots usage for fake players. +FakePlayerUseShots = True + +# Reward PvP kills by killing fake players. +FakePlayerKillsRewardPvP = True + +# Fake player kills apply karma rules. +FakePlayerUnflaggedKillsKarma = True + +# Aggressive AI fake players attack nearby monsters. +FakePlayerAggroMonsters = True + +# Aggressive AI fake players attack nearby players. +FakePlayerAggroPlayers = False + +# Aggressive AI fake players attack nearby fake players. +FakePlayerAggroFPC = False + +# Fake players can drop items when killing monsters. +FakePlayerCanDropItems = True + +# Fake players can pickup dropped items. +FakePlayerCanPickup = True diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml new file mode 100644 index 0000000000..f5da5bfc8e --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerChatData.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml new file mode 100644 index 0000000000..446768c5a3 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/FakePlayerVisualData.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml index e452b77d1c..37f8bfae98 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/Routes.xml @@ -9,4 +9,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java new file mode 100644 index 0000000000..e1dde7324e --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/custom/FakePlayers/PvpFlaggingStopTask.java @@ -0,0 +1,80 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package custom.FakePlayers; + +import com.l2jmobius.Config; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +import ai.AbstractNpcAI; + +/** + * TODO: Move it to L2Character. + * @author Mobius + */ +public class PvpFlaggingStopTask extends AbstractNpcAI +{ + private PvpFlaggingStopTask() + { + } + + @Override + public String onAdvEvent(String event, L2Npc npc, L2PcInstance player) + { + if ((npc == null) || npc.isDead()) + { + return null; + } + + if (event.startsWith("FLAG_CHECK")) + { + final L2Object target = npc.getTarget(); + if ((target != null) && (target.isPlayable() || target.isFakePlayer())) + { + npc.setScriptValue(1); // in combat + cancelQuestTimer("FINISH_FLAG" + npc.getObjectId(), npc, null); + cancelQuestTimer("REMOVE_FLAG" + npc.getObjectId(), npc, null); + startQuestTimer("FINISH_FLAG" + npc.getObjectId(), Config.PVP_NORMAL_TIME - 20000, npc, null); + startQuestTimer("FLAG_CHECK" + npc.getObjectId(), 5000, npc, null); + } + } + else if (event.startsWith("FINISH_FLAG")) + { + if (npc.isScriptValue(1)) + { + npc.setScriptValue(2); // blink status + npc.broadcastInfo(); // update flag status + startQuestTimer("REMOVE_FLAG" + npc.getObjectId(), 20000, npc, null); + } + } + else if (event.startsWith("REMOVE_FLAG")) + { + if (npc.isScriptValue(2)) + { + npc.setScriptValue(0); // not in combat + npc.broadcastInfo(); // update flag status + } + } + return super.onAdvEvent(event, npc, player); + } + + public static void main(String[] args) + { + new PvpFlaggingStopTask(); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java index 67e0f164e4..b2e61af8eb 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/MasterHandler.java @@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant; import handlers.admincommandhandlers.AdminEventEngine; import handlers.admincommandhandlers.AdminEvents; import handlers.admincommandhandlers.AdminExpSp; +import handlers.admincommandhandlers.AdminFakePlayers; import handlers.admincommandhandlers.AdminFightCalculator; import handlers.admincommandhandlers.AdminFortSiege; import handlers.admincommandhandlers.AdminGeodata; @@ -410,6 +411,7 @@ public class MasterHandler AdminEventEngine.class, AdminEvents.class, AdminExpSp.class, + AdminFakePlayers.class, AdminFightCalculator.class, AdminFortSiege.class, AdminGeodata.class, diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java index 6b02816d9e..d6d6a99080 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/actionshifthandlers/L2NpcActionShift.java @@ -192,7 +192,7 @@ public class L2NpcActionShift implements IActionShiftHandler } else if (Config.ALT_GAME_VIEWNPC) { - if (!target.isNpc()) + if (!target.isNpc() || target.isFakePlayer()) { return false; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java new file mode 100644 index 0000000000..99926f0df7 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminFakePlayers.java @@ -0,0 +1,77 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package handlers.admincommandhandlers; + +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.handler.IAdminCommandHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; +import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; + +/** + * @author Mobius + */ +public class AdminFakePlayers implements IAdminCommandHandler +{ + private static final String[] ADMIN_COMMANDS = + { + "admin_fakechat" + }; + + @Override + public boolean useAdminCommand(String command, L2PcInstance activeChar) + { + if (command.startsWith("admin_fakechat")) + { + final String[] words = command.substring(15).split(" "); + if (words.length < 3) + { + activeChar.sendMessage("Usage: //fakechat playername fpcname message"); + return false; + } + final L2PcInstance player = L2World.getInstance().getPlayer(words[0]); + if (player == null) + { + activeChar.sendMessage("Player not found."); + return false; + } + final String fpcName = FakePlayerData.getInstance().getProperName(words[1]); + if (fpcName == null) + { + activeChar.sendMessage("Fake player not found."); + return false; + } + String message = ""; + for (int i = 0; i < words.length; i++) + { + if (i < 2) + { + continue; + } + message += (words[i] + " "); + } + FakePlayerChatManager.getInstance().sendChat(player, fpcName, message); + } + return true; + } + + @Override + public String[] getAdminCommandList() + { + return ADMIN_COMMANDS; + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index 5da8e115b2..4799a7aa53 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData; import com.l2jmobius.gameserver.data.xml.impl.DoorData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData; import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData; import com.l2jmobius.gameserver.data.xml.impl.MultisellData; @@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData; import com.l2jmobius.gameserver.datatables.ItemTable; import com.l2jmobius.gameserver.handler.IAdminCommandHandler; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.WalkingManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; +import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.scripting.ScriptEngineManager; import com.l2jmobius.gameserver.util.Util; @@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data."); break; } + case "fakeplayers": + { + FakePlayerData.getInstance().load(); + for (L2Object obj : L2World.getInstance().getVisibleObjects()) + { + if (obj.isFakePlayer()) + { + obj.broadcastInfo(); + } + } + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data."); + break; + } + case "fakeplayerchat": + { + FakePlayerChatManager.getInstance().load(); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data."); + break; + } default: { activeChar.sendMessage(RELOAD_USAGE); diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java index 99f2e9e9d7..7db79fe31d 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/chathandlers/ChatWhisper.java @@ -17,8 +17,10 @@ package handlers.chathandlers; import com.l2jmobius.Config; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.handler.IChatHandler; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.PcCondOverride; @@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler return; } + if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null)) + { + if (FakePlayerData.getInstance().isTalkable(target)) + { + if (Config.FAKE_PLAYER_CHAT) + { + final String name = FakePlayerData.getInstance().getProperName(target); + activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text)); + FakePlayerChatManager.getInstance().manageChat(activeChar, name, text); + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE); + } + } + else + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE); + } + return; + } + final L2PcInstance receiver = L2World.getInstance().getPlayer(target); if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId())) diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java index 41b1f99bcf..b38f5ca16d 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/conditions/PlayerLevelCondition.java @@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition { return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel); } - } diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java index 1e34a0d148..087112cc73 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/scripts/handlers/playeractions/SocialAction.java @@ -16,9 +16,11 @@ */ package handlers.playeractions; +import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.ai.CtrlEvent; import com.l2jmobius.gameserver.ai.CtrlIntention; import com.l2jmobius.gameserver.ai.NextAction; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.handler.IPlayerActionHandler; import com.l2jmobius.gameserver.model.ActionDataHolder; import com.l2jmobius.gameserver.model.L2Object; @@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED); + player.onTransactionResponse(); + } + } + private void useCoupleSocial(L2PcInstance player, int id) { if (player == null) @@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler } final L2Object target = player.getTarget(); - if ((target == null) || !target.isPlayer()) + if ((target == null)) + { + player.sendPacket(SystemMessageId.INVALID_TARGET); + return; + } + + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1); + sm.addString(target.getName()); + player.sendPacket(sm); + if (!player.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000); + player.blockRequest(); + } + return; + } + + if (!target.isPlayer()) { player.sendPacket(SystemMessageId.INVALID_TARGET); return; diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml new file mode 100644 index 0000000000..ea77878c2c --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/spawns/Others/FakePlayers.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml new file mode 100644 index 0000000000..bea608ac16 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/stats/npcs/custom/fpc_passive.xml @@ -0,0 +1,26 @@ + + + + + DARK_ELF + FEMALE + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd new file mode 100644 index 0000000000..2b2c94e75b --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerChatData.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd new file mode 100644 index 0000000000..0628acefc3 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/FakePlayerVisualData.xsd @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd index 6f00944cff..ae80c3ff63 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd +++ b/L2J_Mobius_Classic_2.0_Saviors/dist/game/data/xsd/npcs.xsd @@ -201,6 +201,8 @@ + +
    diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java index a1d5dff508..d110fd2fa2 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/Config.java @@ -116,6 +116,7 @@ public final class Config public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini"; public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini"; public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini"; + public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini"; public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini"; public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini"; public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini"; @@ -1087,6 +1088,16 @@ public final class Config public static boolean FACTION_SPECIFIC_CHAT; public static boolean FACTION_BALANCE_ONLINE_PLAYERS; public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT; + public static boolean FAKE_PLAYERS_ENABLED; + public static boolean FAKE_PLAYER_CHAT; + public static boolean FAKE_PLAYER_USE_SHOTS; + public static boolean FAKE_PLAYER_KILL_PVP; + public static boolean FAKE_PLAYER_KILL_KARMA; + public static boolean FAKE_PLAYER_AGGRO_MONSTERS; + public static boolean FAKE_PLAYER_AGGRO_PLAYERS; + public static boolean FAKE_PLAYER_AGGRO_FPC; + public static boolean FAKE_PLAYER_CAN_DROP_ITEMS; + public static boolean FAKE_PLAYER_CAN_PICKUP; public static boolean ENABLE_FIND_PVP; public static boolean PREMIUM_SYSTEM_ENABLED; public static float PREMIUM_RATE_XP; @@ -2451,6 +2462,19 @@ public final class Config FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true); FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20); + // Load FakePlayers config file (if exists) + final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE); + FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false)); + FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false)); + FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false)); + FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false)); + FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false)); + FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false)); + FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false)); + FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false)); + FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false)); + FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false)); + // Load FindPvP config file (if exists) final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE); ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java index 6153a97816..d439bda0f7 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/GameServer.java @@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData; import com.l2jmobius.gameserver.data.xml.impl.EventEngineData; import com.l2jmobius.gameserver.data.xml.impl.ExperienceData; import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.FishingData; import com.l2jmobius.gameserver.data.xml.impl.HennaData; import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData; @@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager; import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager; import com.l2jmobius.gameserver.instancemanager.DBSpawnManager; import com.l2jmobius.gameserver.instancemanager.FactionManager; +import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager; import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager; import com.l2jmobius.gameserver.instancemanager.GraciaSeedsManager; import com.l2jmobius.gameserver.instancemanager.GrandBossManager; @@ -286,6 +288,8 @@ public class GameServer printSection("NPCs"); SkillLearnData.getInstance(); NpcData.getInstance(); + FakePlayerData.getInstance(); + FakePlayerChatManager.getInstance(); ExtendDropData.getInstance(); SpawnsData.getInstance(); WalkingManager.getInstance(); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java index 6253fa9329..1da1b21546 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/ai/L2AttackableAI.java @@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController; import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.enums.AISkillScope; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager; import com.l2jmobius.gameserver.model.AggroInfo; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate; import com.l2jmobius.gameserver.model.events.returns.TerminateReturn; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.skills.SkillCaster; @@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10 if (_globalAggro >= 0) { - if (npc.isAggressive() || (npc instanceof L2GuardInstance)) + if (npc.isFakePlayer() && npc.isAggressive()) + { + final List droppedItems = npc.getFakePlayerDrops(); + if (droppedItems.isEmpty()) + { + L2Character nearestTarget = null; + double closestDistance = Double.MAX_VALUE; + for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange())) + { + if ((t == _actor) || (t == null) || t.isDead()) + { + continue; + } + if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) // + || (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer())) + { + final int hating = npc.getHating(t); + final double distance = npc.calculateDistance(t, false, false); + if ((hating == 0) && (closestDistance > distance)) + { + nearestTarget = t; + closestDistance = distance; + } + } + } + if (nearestTarget != null) + { + npc.addDamageHate(nearestTarget, 0, 1); + } + } + else if (!npc.isInCombat()) // must pickup items + { + final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped + final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex); + if ((droppedItem != null) && droppedItem.isSpawned()) + { + if (npc.calculateDistance(droppedItem, false, false) > 50) + { + moveTo(droppedItem); + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + droppedItem.pickupMe(npc); + if (Config.SAVE_DROPPED_ITEM) + { + ItemsOnGroundManager.getInstance().removeObject(droppedItem); + } + if (droppedItem.getItem().hasExImmediateEffect()) + { + for (SkillHolder skillHolder : droppedItem.getItem().getAllSkills()) + { + SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false); + } + npc.broadcastInfo(); // ? check if this is necessary + } + } + } + else + { + npc.getFakePlayerDrops().remove(itemIndex); + } + npc.setRunning(); + } + } + else if (npc.isAggressive() || (npc instanceof L2GuardInstance)) { final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players. L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t -> @@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable // For each L2Character check if the target is autoattackable if (isAggressiveTowards(t)) // check aggression { - if (t.isPlayable()) + if (t.isFakePlayer()) + { + if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC)) + { + final int hating = npc.getHating(t); + if (hating == 0) + { + npc.addDamageHate(t, 0, 1); + } + } + } + else if (t.isPlayable()) { final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class); if ((term != null) && term.terminate()) diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java new file mode 100644 index 0000000000..0a6ca5267a --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/FakePlayerData.java @@ -0,0 +1,125 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.data.xml.impl; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; + +/** + * @author Mobius + */ +public class FakePlayerData implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerData.class.getName()); + + private final Map _fakePlayerInfos = new HashMap<>(); + private final Map _fakePlayerNames = new HashMap<>(); + private final Map _fakePlayerIds = new HashMap<>(); + private final List _talkableFakePlayerNames = new ArrayList<>(); + + protected FakePlayerData() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED) + { + _fakePlayerInfos.clear(); + _fakePlayerNames.clear(); + _fakePlayerIds.clear(); + _talkableFakePlayerNames.clear(); + parseDatapackFile("data/FakePlayerVisualData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + _fakePlayerInfos.size() + " templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayer", fakePlayerNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerNode)); + final int npcId = set.getInt("npcId"); + final L2NpcTemplate template = NpcData.getInstance().getTemplate(npcId); + final String name = template.getName(); + if (CharNameTable.getInstance().getIdByName(name) > 0) + { + LOGGER.info(getClass().getSimpleName() + ": Could not create fake player template " + npcId + ", player name already exists."); + } + else + { + _fakePlayerIds.put(name, npcId); // name - npcId + _fakePlayerNames.put(name.toLowerCase(), name); // name to lowercase - name + _fakePlayerInfos.put(npcId, new FakePlayerHolder(set)); + if (template.isFakePlayerTalkable()) + { + _talkableFakePlayerNames.add(name.toLowerCase()); + } + } + })); + } + + public int getNpcIdByName(String name) + { + return _fakePlayerIds.get(name); + } + + public String getProperName(String name) + { + return _fakePlayerNames.get(name.toLowerCase()); + } + + public Boolean isTalkable(String name) + { + return _talkableFakePlayerNames.contains(name.toLowerCase()); + } + + public FakePlayerHolder getInfo(int npcId) + { + return _fakePlayerInfos.get(npcId); + } + + public static FakePlayerData getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerData _instance = new FakePlayerData(); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java index 7e6728d387..2caef85892 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/NpcData.java @@ -316,6 +316,8 @@ public class NpcData implements IGameXmlReader set.set("hasSummoner", parseBoolean(attrs, "hasSummoner")); set.set("canBeSown", parseBoolean(attrs, "canBeSown")); set.set("isDeathPenalty", parseBoolean(attrs, "isDeathPenalty")); + set.set("fakePlayer", parseBoolean(attrs, "fakePlayer")); + set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable")); break; } case "skill_list": diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java index 2ff4c9322d..15bd310bd6 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/data/xml/impl/SpawnsData.java @@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader return; } + if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer()) + { + return; + } + for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling()) { if ("parameters".equalsIgnoreCase(d.getNodeName())) diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java index a145b65dba..d525c02a6a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/BotReportTable.java @@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager; import com.l2jmobius.gameserver.data.xml.impl.SkillData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; +import com.l2jmobius.gameserver.model.actor.L2Character; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.zone.ZoneId; @@ -210,15 +212,14 @@ public final class BotReportTable public boolean reportBot(L2PcInstance reporter) { final L2Object target = reporter.getTarget(); - if (target == null) { return false; } - final L2PcInstance bot = target.getActingPlayer(); + final L2Character bot = ((L2Character) target); - if ((bot == null) || (target.getObjectId() == reporter.getObjectId())) + if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId())) { return false; } @@ -229,7 +230,7 @@ public final class BotReportTable return false; } - if (bot.isInOlympiadMode()) + if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode()) { reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD); return false; @@ -241,7 +242,7 @@ public final class BotReportTable return false; } - if (bot.getExp() == bot.getStat().getStartingExp()) + if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp())) { reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING); return false; @@ -320,15 +321,18 @@ public final class BotReportTable } SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT); - sm.addCharName(bot); + sm.addString(bot.getName()); reporter.sendPacket(sm); sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT); - sm.addCharName(bot); + sm.addString(bot.getName()); sm.addInt(rcdRep.getPointsLeft()); reporter.sendPacket(sm); - handleReport(bot, rcd); + if (bot.isPlayer()) + { + handleReport(bot.getActingPlayer(), rcd); + } return true; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java index 7454554076..ace19486b5 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/datatables/ItemTable.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.L2Attackable; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.events.EventDispatcher; @@ -202,11 +203,11 @@ public class ItemTable * @param process : String Identifier of process triggering this action * @param itemId : int Item Identifier of the item to be created * @param count : int Quantity of items to be created for stackable items - * @param actor : L2PcInstance Player requesting the item creation + * @param actor : L2Character requesting the item creation * @param reference : Object Object referencing current action like NPC selling item or previous item in transformation * @return L2ItemInstance corresponding to the new item */ - public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference) + public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference) { // Create and Init the L2ItemInstance corresponding to the Item Identifier final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java index b621b4c4cb..bb0e928daf 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/idfactory/IdFactory.java @@ -217,6 +217,7 @@ public abstract class IdFactory cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);"); cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);"); + cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);"); // If the clan does not exist... cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);"); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java new file mode 100644 index 0000000000..16a0da92bc --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/instancemanager/FakePlayerChatManager.java @@ -0,0 +1,196 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.instancemanager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +import org.w3c.dom.Document; + +import com.l2jmobius.Config; +import com.l2jmobius.commons.util.IGameXmlReader; +import com.l2jmobius.commons.util.Rnd; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.datatables.SpawnTable; +import com.l2jmobius.gameserver.enums.ChatType; +import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.model.L2Spawn; +import com.l2jmobius.gameserver.model.StatsSet; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder; +import com.l2jmobius.gameserver.network.serverpackets.CreatureSay; + +/** + * @author Mobius + */ +public final class FakePlayerChatManager implements IGameXmlReader +{ + private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName()); + final List MESSAGES = new ArrayList<>(); + private static final int MIN_DELAY = 5000; + private static final int MAX_DELAY = 15000; + + protected FakePlayerChatManager() + { + load(); + } + + @Override + public void load() + { + if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT) + { + MESSAGES.clear(); + parseDatapackFile("data/FakePlayerChatData.xml"); + LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates."); + } + else + { + LOGGER.info(getClass().getSimpleName() + ": Disabled."); + } + } + + @Override + public void parseDocument(Document doc, File f) + { + forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode -> + { + final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode)); + MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers"))); + })); + } + + public void manageChat(L2PcInstance player, String fpcName, String message) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY)); + } + + public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay) + { + ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay)); + } + + private void manageResponce(L2PcInstance player, String fpcName, String message) + { + if (player == null) + { + return; + } + + final String text = message.toLowerCase(); + + // tricky question + if (text.contains("can you see me")) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + if (npc.calculateDistance(player, false, false) < 3000) + { + if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible()) + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes"); + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?"); + } + } + else + { + sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no"); + } + return; + } + } + } + + for (FakePlayerChatHolder chatHolder : MESSAGES) + { + if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL")) + { + continue; + } + + switch (chatHolder.getSearchMethod()) + { + case "EQUALS": + { + if (text.equals(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "STARTS_WITH": + { + if (text.startsWith(chatHolder.getSearchText().get(0))) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + case "CONTAINS": + { + boolean allFound = true; + for (String word : chatHolder.getSearchText()) + { + if (!text.contains(word)) + { + allFound = false; + } + } + if (allFound) + { + sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size()))); + } + break; + } + } + } + } + + public void sendChat(L2PcInstance player, String fpcName, String message) + { + final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName)); + if (spawn != null) + { + final L2Npc npc = spawn.getLastSpawn(); + if (npc != null) + { + player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message)); + } + } + } + + public static FakePlayerChatManager getInstance() + { + return SingletonHolder._instance; + } + + private static class SingletonHolder + { + protected static final FakePlayerChatManager _instance = new FakePlayerChatManager(); + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java index 1a62714f0e..50a3cc2145 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/DropProtection.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model; import java.util.concurrent.ScheduledFuture; import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; @@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance; public class DropProtection implements Runnable { private volatile boolean _isProtected = false; - private L2PcInstance _owner = null; + private L2Character _owner = null; private ScheduledFuture _task = null; private static final long PROTECTED_MILLIS_TIME = 15000; @@ -46,7 +47,7 @@ public class DropProtection implements Runnable return _isProtected; } - public L2PcInstance getOwner() + public L2Character getOwner() { return _owner; } @@ -91,12 +92,12 @@ public class DropProtection implements Runnable _task = null; } - public synchronized void protect(L2PcInstance player) + public synchronized void protect(L2Character character) { unprotect(); _isProtected = true; - _owner = player; + _owner = character; if (_owner == null) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java index 459660c7ca..92837e4b25 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/L2Object.java @@ -364,6 +364,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab return false; } + /** + * Verify if object is a fake player. + * @return {@code true} if object is a fake player, {@code false} otherwise + */ + public boolean isFakePlayer() + { + return false; + } + /** * Verify if object is instance of L2ServitorInstance. * @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java index 390cee7b5a..c3f0de92ff 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Attackable.java @@ -69,6 +69,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack; import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill; import com.l2jmobius.gameserver.model.holders.ItemHolder; +import com.l2jmobius.gameserver.model.holders.SkillHolder; import com.l2jmobius.gameserver.model.items.L2Item; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.skills.Skill; @@ -275,7 +276,7 @@ public class L2Attackable extends L2Npc public synchronized boolean getMustRewardExpSP() { - return _mustGiveExpSp; + return _mustGiveExpSp && !isFakePlayer(); } /** @@ -954,6 +955,39 @@ public class L2Attackable extends L2Npc // Don't drop anything if the last attacker or owner isn't L2PcInstance if (player == null) { + // unless its a fake player and they can drop items + if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS) + { + final Collection deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer); + if (deathItems != null) + { + for (ItemHolder drop : deathItems) + { + final L2Item item = ItemTable.getInstance().getTemplate(drop.getId()); + // Check if the autoLoot mode is active + if (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS)))) + { + // do nothing + } + else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect()) + { + for (SkillHolder skillHolder : item.getAllSkills()) + { + SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false); + } + mainDamageDealer.broadcastInfo(); // ? check if this is necessary + } + else + { + final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground + if (Config.FAKE_PLAYER_CAN_PICKUP) + { + mainDamageDealer.getFakePlayerDrops().add(droppedItem); + } + } + } + } + } return; } @@ -1041,7 +1075,7 @@ public class L2Attackable extends L2Npc */ public void doEventDrop(L2Character lastAttacker) { - if (lastAttacker == null) + if ((lastAttacker == null) || isFakePlayer()) { return; } @@ -1365,6 +1399,15 @@ public class L2Attackable extends L2Npc _harvestItem.set(null); _sweepItems.set(null); + // fake players + if (isFakePlayer()) + { + getFakePlayerDrops().clear(); // Clear existing fake player drops + setReputation(0); // reset reputation + setScriptValue(0); // remove pvp flag + setRunning(); // don't walk + } + // Clear mod Seeded stat _seeded = false; _seed = null; diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java index 226b8e981a..6dd50e079f 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Character.java @@ -30,6 +30,7 @@ import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -62,6 +63,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.geoengine.GeoEngine; import com.l2jmobius.gameserver.idfactory.IdFactory; import com.l2jmobius.gameserver.instancemanager.MapRegionManager; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.instancemanager.TimersManager; import com.l2jmobius.gameserver.instancemanager.ZoneManager; import com.l2jmobius.gameserver.model.CharEffectList; @@ -137,6 +139,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack; import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType; import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType; import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket; import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -203,6 +206,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe private double _hpUpdateDecCheck = .0; private double _hpUpdateInterval = .0; + private int _reputation = 0; + /** Map containing all skills of this character. */ private final Map _skills = new ConcurrentSkipListMap<>(); /** Map containing the skill reuse time stamps. */ @@ -274,6 +279,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe /** A set containing the shot types currently charged. */ private Set _chargedShots = EnumSet.noneOf(ShotType.class); + /** A list containing the dropped items of this fake player. */ + private final List _fakePlayerDrops = new CopyOnWriteArrayList<>(); + /** * Creates a creature. * @param template the creature template @@ -1211,6 +1219,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe broadcastPacket(attack); } + if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer())) + { + final L2Npc npc = ((L2Npc) this); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + // Notify AI with EVT_READY_TO_ACT ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk); } @@ -2321,7 +2340,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -2949,7 +2972,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) this, player)); } @@ -4131,7 +4158,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe public boolean isInsidePeaceZone(L2Object attacker, L2Object target) { final Instance instanceWorld = getInstanceWorld(); - if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) + if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP())) { return false; } @@ -5539,6 +5566,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist()); } + public int getReputation() + { + return _reputation; + } + + public void setReputation(int reputation) + { + _reputation = reputation; + } + /** * Gets the distance to target. * @param target the target @@ -5586,4 +5623,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe { _cursorKeyMovement = value; } + + public List getFakePlayerDrops() + { + return _fakePlayerDrops; + } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java index dd3a438337..0a27adf635 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Npc.java @@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.enums.Race; import com.l2jmobius.gameserver.enums.ShotType; import com.l2jmobius.gameserver.enums.Team; +import com.l2jmobius.gameserver.enums.UserInfoType; import com.l2jmobius.gameserver.handler.BypassHandler; import com.l2jmobius.gameserver.handler.IBypassHandler; import com.l2jmobius.gameserver.instancemanager.CastleManager; @@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; import com.l2jmobius.gameserver.model.olympiad.Olympiad; import com.l2jmobius.gameserver.model.skills.Skill; import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate; +import com.l2jmobius.gameserver.model.stats.Formulas; import com.l2jmobius.gameserver.model.variables.NpcVariables; import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.NpcStringId; @@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ActionFailed; import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState; import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse; import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; @@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec import com.l2jmobius.gameserver.network.serverpackets.NpcSay; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; import com.l2jmobius.gameserver.network.serverpackets.SocialAction; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; +import com.l2jmobius.gameserver.network.serverpackets.UserInfo; import com.l2jmobius.gameserver.taskmanager.DecayTaskManager; import com.l2jmobius.gameserver.util.Broadcast; @@ -125,6 +130,7 @@ public class L2Npc extends L2Character private boolean _isRandomAnimationEnabled = true; private boolean _isRandomWalkingEnabled = true; private boolean _isTalkable = getTemplate().isTalkable(); + private final boolean _isFakePlayer = getTemplate().isFakePlayer(); protected RandomAnimationTask _rAniTask; private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions @@ -364,7 +370,11 @@ public class L2Npc extends L2Character return; } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo(this, player)); } @@ -901,6 +911,78 @@ public class L2Npc extends L2Character final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null; _killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0; + if (isFakePlayer() && (killer != null) && killer.isPlayable()) + { + final L2PcInstance player = killer.getActingPlayer(); + if (isScriptValue(0) && (getReputation() >= 0)) + { + if (Config.FAKE_PLAYER_KILL_KARMA) + { + player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon())); + player.setPkKills(player.getPkKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + player.checkItemRestriction(); + // pk item rewards + if (Config.REWARD_PK_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } + // announce pk + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + else if (Config.FAKE_PLAYER_KILL_PVP) + { + player.setPvpKills(player.getPvpKills() + 1); + final UserInfo ui = new UserInfo(player, false); + ui.addComponentType(UserInfoType.SOCIAL); + player.sendPacket(ui); + // pvp item rewards + if (Config.REWARD_PVP_ITEM) + { + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + } + // announce pvp + if (Config.ANNOUNCE_PK_PVP && !player.isGM()) + { + final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName()); + if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); + sm.addString(msg); + Broadcast.toAllOnlinePlayers(sm); + } + else + { + Broadcast.toAllOnlinePlayers(msg, false); + } + } + } + } + DecayTaskManager.getInstance().add(this); final L2Spawn spawn = getSpawn(); @@ -1210,7 +1292,11 @@ public class L2Npc extends L2Character activeChar.sendMessage("Added NPC: " + getName()); } - if (getRunSpeed() == 0) + if (isFakePlayer()) + { + activeChar.sendPacket(new FakePlayerInfo(this)); + } + else if (getRunSpeed() == 0) { activeChar.sendPacket(new ServerObjectInfo(this, activeChar)); } @@ -1301,26 +1387,41 @@ public class L2Npc extends L2Character @Override public void rechargeShots(boolean physical, boolean magic, boolean fish) { - if (physical && (_soulshotamount > 0)) + if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS) { - if (Rnd.get(100) > getTemplate().getSoulShotChance()) + if (physical) { - return; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic) + { + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _soulshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); - chargeShot(ShotType.SOULSHOTS); } - - if (magic && (_spiritshotamount > 0)) + else { - if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + if (physical && (_soulshotamount > 0)) { - return; + if (Rnd.get(100) > getTemplate().getSoulShotChance()) + { + return; + } + _soulshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600); + chargeShot(ShotType.SOULSHOTS); + } + if (magic && (_spiritshotamount > 0)) + { + if (Rnd.get(100) > getTemplate().getSpiritShotChance()) + { + return; + } + _spiritshotamount--; + Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); + chargeShot(ShotType.SPIRITSHOTS); } - _spiritshotamount--; - Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600); - chargeShot(ShotType.SPIRITSHOTS); } } @@ -1435,12 +1536,12 @@ public class L2Npc extends L2Character /** * Drops an item. - * @param player the last attacker or main damage dealer + * @param character the last attacker or main damage dealer * @param itemId the item ID * @param itemCount the item count * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount) + public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount) { L2ItemInstance item = null; for (int i = 0; i < itemCount; i++) @@ -1456,15 +1557,15 @@ public class L2Npc extends L2Character return null; } - item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this); + item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this); if (item == null) { return null; } - if (player != null) + if (character != null) { - item.getDropProtection().protect(player); + item.getDropProtection().protect(character); } item.dropMe(this, newX, newY, newZ); @@ -1489,14 +1590,14 @@ public class L2Npc extends L2Character } /** - * Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)} - * @param player the last attacker or main damage dealer + * Method overload for {@link L2Attackable#dropItem(L2Character, int, long)} + * @param character the last attacker or main damage dealer * @param item the item holder * @return the dropped item */ - public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item) + public L2ItemInstance dropItem(L2Character character, ItemHolder item) { - return dropItem(player, item.getId(), item.getCount()); + return dropItem(character, item.getId(), item.getCount()); } @Override @@ -1560,6 +1661,12 @@ public class L2Npc extends L2Character return Config.SHOP_MIN_RANGE_FROM_NPC; } + @Override + public boolean isFakePlayer() + { + return _isFakePlayer; + } + /** * @return The player's object Id this NPC is cloning. */ diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java index 34550c3dd8..10ad419ea4 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Playable.java @@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character public abstract void doPickupItem(L2Object object); - public abstract int getReputation(); - public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove); public abstract void storeMe(); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java index dab0c5323a..80c2783883 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/L2Summon.java @@ -723,7 +723,7 @@ public abstract class L2Summon extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -741,7 +741,7 @@ public abstract class L2Summon extends L2Playable { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } @@ -903,6 +903,10 @@ public abstract class L2Summon extends L2Playable { setTarget(target); getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target); + if (target.isFakePlayer()) + { + getOwner().updatePvPStatus(); + } } } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java index a5fd31dedd..44ee919058 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/DoppelgangerInstance.java @@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addNpcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); } @@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); sm.addNpcName(this); - sm.addCharName(attacker); + sm.addString(attacker.getName()); sm.addInt((int) damage); sendPacket(sm); } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java index aa4f132fce..6a94be63b5 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2GuardInstance.java @@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { - if (attacker.isMonster()) + if (attacker.isMonster() && !attacker.isFakePlayer()) { return true; } @@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); } + if (isFakePlayer() && isInCombat()) + { + interact = false; + // TODO: Fix normal targeting + player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this); + } + // Check if the L2PcInstance already target the L2GuardInstance if (getObjectId() != player.getTargetId()) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java index e9a9976e87..fe55288a3a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2MonsterInstance.java @@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable @Override public boolean isAutoAttackable(L2Character attacker) { + if (isFakePlayer()) + { + return isInCombat() || attacker.isMonster() || (getScriptValue() > 0); + } + // Check if the L2MonsterInstance target is aggressive if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance)) { @@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable if (attacker.isMonster()) { - return false; + return attacker.isFakePlayer(); } // Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints. diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java index 96dd03ebdc..abff3608fa 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2PcInstance.java @@ -442,9 +442,6 @@ public final class L2PcInstance extends L2Playable /** The Experience of the L2PcInstance before the last Death Penalty */ private long _expBeforeDeath; - /** The Reputation of the L2PcInstance */ - private int _reputation; - /** The number of player killed during a PvP (the player killed was PvP Flagged) */ private int _pvpKills; @@ -1968,24 +1965,16 @@ public final class L2PcInstance extends L2Playable return _expBeforeDeath; } - /** - * @return the reputation of the PlayerInstance. - */ - @Override - public int getReputation() - { - return _reputation; - } - public void setInitialReputation(int reputation) { - _reputation = reputation; + super.setReputation(reputation); } /** * Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast). * @param reputation */ + @Override public void setReputation(int reputation) { // Notify to scripts. @@ -2011,7 +2000,9 @@ public final class L2PcInstance extends L2Playable } }); } - _reputation = reputation; + + super.setReputation(reputation); + sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation())); broadcastReputation(); } @@ -4625,6 +4616,10 @@ public final class L2PcInstance extends L2Playable { super.doAttack(target); setRecentFakeDeath(false); + if (target.isFakePlayer()) + { + updatePvPStatus(); + } } @Override @@ -4952,22 +4947,42 @@ public final class L2PcInstance extends L2Playable if (killer != null) { final L2PcInstance pk = killer.getActingPlayer(); - if (pk != null) + final boolean fpcKill = killer.isFakePlayer(); + if ((pk != null) || fpcKill) { - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); - - if (L2Event.isParticipant(pk)) + if (pk != null) { - pk.getEventStatus().addKill(this); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this); + + if (L2Event.isParticipant(pk)) + { + pk.getEventStatus().addKill(this); + } + + // pvp/pk item rewards + if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // + !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + { + // pvp + if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) + { + pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); + } + // pk + if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) + { + pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); + } + } } // announce pvp/pk - if (Config.ANNOUNCE_PK_PVP && !pk.isGM()) + if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill)) { String msg = ""; if (getPvpFlag() == 0) { - msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -4981,7 +4996,7 @@ public final class L2PcInstance extends L2Playable } else if (getPvpFlag() != 0) { - msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName()); + msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName()); if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE) { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13); @@ -4995,20 +5010,9 @@ public final class L2PcInstance extends L2Playable } } - // pvp/pk item rewards - if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && // - !(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP))) + if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0)) { - // pvp - if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0)) - { - pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE); - } - // pk - if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0)) - { - pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE); - } + killer.setReputation(killer.getReputation() - 150); } } @@ -5601,6 +5605,14 @@ public final class L2PcInstance extends L2Playable return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks()); } + /** + * Used by fake players to emulate proper behavior. + */ + public void blockRequest() + { + _requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND); + } + /** * Select the Warehouse to be used in next activity. * @param partner @@ -11502,7 +11514,7 @@ public final class L2PcInstance extends L2Playable { sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addPcName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), -damage); } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java index fb6b184e67..8383d1efc9 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/instance/L2TrapInstance.java @@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc return null; } + @Override public int getReputation() { return _owner != null ? _owner.getReputation() : 0; @@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc { final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4); sm.addCharName(this); - sm.addCharName(target); + sm.addString(target.getName()); sm.addInt(damage); sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1)); _owner.sendPacket(sm); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java index a97eab382d..26a51be541 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/status/PcStatus.java @@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus } } - if (attacker.isPlayable() && (caster.getCurrentCp() > 0)) + if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0)) { if (caster.getCurrentCp() > transferDmg) { @@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus } } - if (!ignoreCP && attacker.isPlayable()) + if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer())) { if (getCurrentCp() >= value) { @@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus // Send a System Message to the L2PcInstance SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2); smsg.addString(getActiveChar().getName()); - smsg.addCharName(attacker); + smsg.addString(attacker.getName()); smsg.addInt(fullValue); getActiveChar().sendPacket(smsg); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java index 9abefd2e88..0d276af74d 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/actor/templates/L2NpcTemplate.java @@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable private boolean _randomWalk; private boolean _randomAnimation; private boolean _flying; + private boolean _fakePlayer; + private boolean _fakePlayerTalkable; private boolean _canMove; private boolean _noSleepMode; private boolean _passableDoor; @@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable _randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard")); _randomAnimation = set.getBoolean("randomAnimation", true); _flying = set.getBoolean("flying", false); + _fakePlayer = set.getBoolean("fakePlayer", false); + _fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true); _canMove = set.getBoolean("canMove", true); _noSleepMode = set.getBoolean("noSleepMode", false); _passableDoor = set.getBoolean("passableDoor", false); @@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable return _flying; } + public boolean isFakePlayer() + { + return _fakePlayer; + } + + public boolean isFakePlayerTalkable() + { + return _fakePlayerTalkable; + } + public boolean canMove() { return _canMove; @@ -758,7 +772,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null) { @@ -804,7 +818,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable } // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null) { @@ -837,7 +851,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // chance double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER; // premium chance - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE; } @@ -850,7 +864,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable // amount is calculated after chance returned success double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER; // premium amount - if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus()) + if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus()) { rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java index df9698d3c3..6cbe42b242 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/events/impl/item/OnItemCreate.java @@ -16,7 +16,7 @@ */ package com.l2jmobius.gameserver.model.events.impl.item; -import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.actor.L2Character; import com.l2jmobius.gameserver.model.events.EventType; import com.l2jmobius.gameserver.model.events.impl.IBaseEvent; import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance; @@ -28,10 +28,10 @@ public class OnItemCreate implements IBaseEvent { private final String _process; private final L2ItemInstance _item; - private final L2PcInstance _activeChar; + private final L2Character _activeChar; private final Object _reference; - public OnItemCreate(String process, L2ItemInstance item, L2PcInstance actor, Object reference) + public OnItemCreate(String process, L2ItemInstance item, L2Character actor, Object reference) { _process = process; _item = item; @@ -49,7 +49,7 @@ public class OnItemCreate implements IBaseEvent return _item; } - public L2PcInstance getActiveChar() + public L2Character getActiveChar() { return _activeChar; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java new file mode 100644 index 0000000000..3008d340b3 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerChatHolder.java @@ -0,0 +1,60 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author Mobius + */ +public class FakePlayerChatHolder +{ + private final String _fpcName; + private final String _searchMethod; + private final List _searchText; + private final List _answers; + + public FakePlayerChatHolder(String fpcName, String searchMethod, String searchText, String answers) + { + _fpcName = fpcName; + _searchMethod = searchMethod; + _searchText = new ArrayList<>(Arrays.asList(searchText.split(";"))); + _answers = new ArrayList<>(Arrays.asList(answers.split(";"))); + } + + public String getFpcName() + { + return _fpcName; + } + + public String getSearchMethod() + { + return _searchMethod; + } + + public List getSearchText() + { + return _searchText; + } + + public List getAnswers() + { + return _answers; + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java new file mode 100644 index 0000000000..2f8aa1fa6d --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/holders/FakePlayerHolder.java @@ -0,0 +1,232 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.model.holders; + +import com.l2jmobius.gameserver.model.StatsSet; + +/** + * @author Mobius + */ +public class FakePlayerHolder +{ + private final int _classId; + private final int _hair; + private final int _hairColor; + private final int _face; + private final int _nameColor; + private final int _titleColor; + private final int _equipHead; + private final int _equipRHand; + private final int _equipLHand; + private final int _equipGloves; + private final int _equipChest; + private final int _equipLegs; + private final int _equipFeet; + private final int _equipCloak; + private final int _equipHair; + private final int _equipHair2; + private final int _agathionId; + private final int _weaponEnchantLevel; + private final int _armorEnchantLevel; + private final boolean _fishing; + private final int _baitLocationX; + private final int _baitLocationY; + private final int _baitLocationZ; + private final int _recommends; + private final int _nobleLevel; + private final boolean _hero; + private final int _clanId; + private final int _pledgeStatus; + + public FakePlayerHolder(StatsSet set) + { + _classId = set.getInt("classId", 182); + + _hair = set.getInt("hair", 1); + _hairColor = set.getInt("hairColor", 1); + _face = set.getInt("face", 1); + + _nameColor = set.getInt("nameColor", 0xFFFFFF); + _titleColor = set.getInt("titleColor", 0xECF9A2); + + _equipHead = set.getInt("equipHead", 0); + _equipRHand = set.getInt("equipRHand", 0); // or dual hand + _equipLHand = set.getInt("equipLHand", 0); + _equipGloves = set.getInt("equipGloves", 0); + _equipChest = set.getInt("equipChest", 0); + _equipLegs = set.getInt("equipLegs", 0); + _equipFeet = set.getInt("equipFeet", 0); + _equipCloak = set.getInt("equipCloak", 0); + _equipHair = set.getInt("equipHair", 0); + _equipHair2 = set.getInt("equipHair2", 0); + _agathionId = set.getInt("agathionId", 0); + + _weaponEnchantLevel = set.getInt("weaponEnchantLevel", 0); + _armorEnchantLevel = set.getInt("armorEnchantLevel", 0); + + _fishing = set.getBoolean("fishing", false); + _baitLocationX = set.getInt("baitLocationX", 0); + _baitLocationY = set.getInt("baitLocationY", 0); + _baitLocationZ = set.getInt("baitLocationZ", 0); + + _recommends = set.getInt("recommends", 0); + _nobleLevel = set.getInt("nobleLevel", 0); + _hero = set.getBoolean("hero", false); + _clanId = set.getInt("clanId", 0); + _pledgeStatus = set.getInt("pledgeStatus", 0); + } + + public int getClassId() + { + return _classId; + } + + public int getHair() + { + return _hair; + } + + public int getHairColor() + { + return _hairColor; + } + + public int getFace() + { + return _face; + } + + public int getNameColor() + { + return _nameColor; + } + + public int getTitleColor() + { + return _titleColor; + } + + public int getEquipHead() + { + return _equipHead; + } + + public int getEquipRHand() + { + return _equipRHand; + } + + public int getEquipLHand() + { + return _equipLHand; + } + + public int getEquipGloves() + { + return _equipGloves; + } + + public int getEquipChest() + { + return _equipChest; + } + + public int getEquipLegs() + { + return _equipLegs; + } + + public int getEquipFeet() + { + return _equipFeet; + } + + public int getEquipCloak() + { + return _equipCloak; + } + + public int getEquipHair() + { + return _equipHair; + } + + public int getEquipHair2() + { + return _equipHair2; + } + + public int getAgathionId() + { + return _agathionId; + } + + public int getWeaponEnchantLevel() + { + return _weaponEnchantLevel; + } + + public int getArmorEnchantLevel() + { + return _armorEnchantLevel; + } + + public boolean isFishing() + { + return _fishing; + } + + public int getBaitLocationX() + { + return _baitLocationX; + } + + public int getBaitLocationY() + { + return _baitLocationY; + } + + public int getBaitLocationZ() + { + return _baitLocationZ; + } + + public int getRecommends() + { + return _recommends; + } + + public int getNobleLevel() + { + return _nobleLevel; + } + + public boolean isHero() + { + return _hero; + } + + public int getClanId() + { + return _clanId; + } + + public int getPledgeStatus() + { + return _pledgeStatus; + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java index c5af087f72..551733f42a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/items/instance/L2ItemInstance.java @@ -281,16 +281,16 @@ public final class L2ItemInstance extends L2Object *
    *
  • Do Pickup Item : PCInstance and Pet

  • *
    - * @param player Player that pick up the item + * @param character Character that pick up the item */ - public final void pickupMe(L2Character player) + public final void pickupMe(L2Character character) { assert getWorldRegion() != null; final L2WorldRegion oldregion = getWorldRegion(); // Create a server->client GetItem packet to pick up the L2ItemInstance - player.broadcastPacket(new GetItem(this, player.getObjectId())); + character.broadcastPacket(new GetItem(this, character.getObjectId())); synchronized (this) { @@ -309,10 +309,10 @@ public final class L2ItemInstance extends L2Object // Remove the L2ItemInstance from the world L2World.getInstance().removeVisibleObject(this, oldregion); - if (player.isPlayer()) + if (character.isPlayer()) { // Notify to scripts - EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem()); + EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem()); } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java index 83f6e88b77..7505001c60 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/Skill.java @@ -1076,7 +1076,7 @@ public final class Skill implements IIdentifiable public boolean checkCondition(L2Character activeChar, L2Object object) { - if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION) + if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)) { return true; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java index b7eda58d00..13932008ff 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/skills/SkillCaster.java @@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType; import com.l2jmobius.gameserver.enums.NextActionType; import com.l2jmobius.gameserver.enums.StatusUpdateType; import com.l2jmobius.gameserver.geoengine.GeoEngine; +import com.l2jmobius.gameserver.instancemanager.QuestManager; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; @@ -159,7 +160,7 @@ public class SkillCaster implements Runnable } // You should not heal/buff monsters without pressing the ctrl button. - if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed) + if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed) { caster.sendPacket(SystemMessageId.INVALID_TARGET); return null; @@ -609,6 +610,10 @@ public class SkillCaster implements Runnable // Add hate to the attackable, and put it in the attack list. ((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint()); ((L2Character) obj).addAttackerToAttackByList(caster); + if (obj.isFakePlayer()) + { + player.updatePvPStatus(); + } } // notify target AI about the attack @@ -617,10 +622,19 @@ public class SkillCaster implements Runnable ((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster); } } - else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0)))) + else if (((skill.getEffectPoint() > 0) && obj.isMonster()) // + || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) // + || (((L2Character) obj).getReputation() < 0) // + ))) { // Supporting players or monsters result in pvpflag. - player.updatePvPStatus(); + if (!obj.isFakePlayer() // + || (obj.isFakePlayer() // + && (!((L2Npc) obj).isScriptValue(0) // + || (((L2Npc) obj).getReputation() < 0)))) + { + player.updatePvPStatus(); + } } } @@ -630,7 +644,7 @@ public class SkillCaster implements Runnable EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob); // On Skill See logic - if (npcMob.isAttackable()) + if (npcMob.isAttackable() && !npcMob.isFakePlayer()) { final L2Attackable attackable = (L2Attackable) npcMob; @@ -652,6 +666,19 @@ public class SkillCaster implements Runnable } }); } + else if (caster.isFakePlayer()) // fake player attacks player + { + if (target.isPlayable() || target.isFakePlayer()) + { + final L2Npc npc = ((L2Npc) caster); + if (!npc.isScriptValue(1)) + { + npc.setScriptValue(1); // in combat + npc.broadcastInfo(); // update flag status + QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null); + } + } + } } catch (Exception e) { @@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable return false; } } - return true; } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java index fdf0dadf55..06bea1b4cf 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/model/zone/type/L2WaterZone.java @@ -22,6 +22,7 @@ import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.zone.L2ZoneType; import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo; import com.l2jmobius.gameserver.network.serverpackets.NpcInfo; import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo; @@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } @@ -80,7 +85,11 @@ public class L2WaterZone extends L2ZoneType { L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player -> { - if (character.getRunSpeed() == 0) + if (character.isFakePlayer()) + { + player.sendPacket(new FakePlayerInfo((L2Npc) character)); + } + else if (character.getRunSpeed() == 0) { player.sendPacket(new ServerObjectInfo((L2Npc) character, player)); } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java index 91a9ce830a..ccd2d1d13a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/Action.java @@ -143,7 +143,7 @@ public final class Action implements IClientIncomingPacket } case 1: { - if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC)) + if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer())) { obj.onAction(activeChar, false); } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java index 876c53c093..06464d9911 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/CharacterCreate.java @@ -22,6 +22,7 @@ import java.util.logging.Logger; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData; import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData; import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData; @@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket return; } - if (Config.FORBIDDEN_NAMES.length > 1) + if (Config.FORBIDDEN_NAMES.length > 0) { for (String st : Config.FORBIDDEN_NAMES) { @@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().getProperName(_name) != null) + { + client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME)); + return; + } + // Last Verified: May 30, 2009 - Gracia Final if (!Util.isAlphaNumeric(_name) || !isValidName(_name)) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java index 06bfa3c200..01c8b0c67f 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestBlock.java @@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; public final class RequestBlock implements IClientIncomingPacket { @@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket case BLOCK: case UNBLOCK: { + // TODO: Save in database? :P + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (_type == BLOCK) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + activeChar.sendPacket(sm); + } + return; + } + // can't use block/unblock for locating invisible characters if (targetId <= 0) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java index ceb67b0f5f..cf79bdb24c 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestCharacterNameCreatable.java @@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable; import com.l2jmobius.gameserver.util.Util; @@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket { result = NAME_ALREADY_EXISTS; } + else if (FakePlayerData.getInstance().getProperName(_name) != null) + { + result = NAME_ALREADY_EXISTS; + } else if (_name.length() > 16) { result = INVALID_LENGTH; diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java index b0ace828dc..ee8bcd656b 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestDuelStart.java @@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Party; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; +import com.l2jmobius.gameserver.model.zone.ZoneId; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart; @@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance activeChar = client.getActiveChar(); - final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (activeChar == null) { return; } + + if (FakePlayerData.getInstance().isTalkable(_player)) + { + final String name = FakePlayerData.getInstance().getProperName(_player); + if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE); + sm.addString(name); + activeChar.sendPacket(sm); + return; + } + if (activeChar.isProcessingRequest()) + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(name); + activeChar.sendPacket(msg); + return; + } + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL); + sm.addString(name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000); + activeChar.blockRequest(); + return; + } + + final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player); if (targetChar == null) { activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java index f104c94161..c0042d45c5 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinParty.java @@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PartyDistributionType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Party; @@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + if (player.getParty() == null) + { + player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED); + } + else + { + player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY); + } + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { final L2PcInstance requestor = client.getActiveChar(); - final L2PcInstance target = L2World.getInstance().getPlayer(_name); - if (requestor == null) { return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY); + sm.addString(FakePlayerData.getInstance().getProperName(_name)); + requestor.sendPacket(sm); + if (!requestor.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000); + requestor.blockRequest(); + } + else + { + requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY); + } + return; + } + + final L2PcInstance target = L2World.getInstance().getPlayer(_name); if (target == null) { requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java index 292153afd8..37c539556f 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestJoinPledge.java @@ -17,12 +17,15 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Clan; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; import com.l2jmobius.gameserver.network.SystemMessageId; import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge; +import com.l2jmobius.gameserver.network.serverpackets.SystemMessage; /** * This class ... @@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket return; } + if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName()))) + { + if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0) + { + activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN); + } + else + { + if (!activeChar.isProcessingRequest()) + { + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + msg.addString(activeChar.getTarget().getName()); + activeChar.sendPacket(msg); + } + } + return; + } + final L2PcInstance target = L2World.getInstance().getPlayer(_target); if (target == null) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java index 3d5bcaeca5..9cbb114e88 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestSendPost.java @@ -23,6 +23,7 @@ import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; import com.l2jmobius.gameserver.data.sql.impl.CharNameTable; import com.l2jmobius.gameserver.data.xml.impl.AdminData; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.instancemanager.MailManager; import com.l2jmobius.gameserver.model.BlockList; @@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket } } + if (FakePlayerData.getInstance().isTalkable(_receiver)) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1); + sm.addString(FakePlayerData.getInstance().getProperName(_receiver)); + activeChar.sendPacket(sm); + return; + } + final int receiverId = CharNameTable.getInstance().getIdByName(_receiver); if (receiverId <= 0) { diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java index 8156905e94..1336c2bdb7 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/RequestVoteNew.java @@ -17,6 +17,7 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.L2GameClient; @@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket } final L2Object object = activeChar.getTarget(); - if (!(object instanceof L2PcInstance)) { if (object == null) { client.sendPacket(SystemMessageId.SELECT_TARGET); } + else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName())) + { + if (activeChar.getRecomLeft() <= 0) + { + client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER); + return; + } + + SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT); + sm.addString(FakePlayerData.getInstance().getProperName(object.getName())); + sm.addInt(activeChar.getRecomLeft()); + client.sendPacket(sm); + + activeChar.setRecomLeft(activeChar.getRecomLeft() - 1); + client.sendPacket(new UserInfo(activeChar)); + client.sendPacket(new ExVoteSystemInfo(activeChar)); + } else { client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java index d77dc881b3..5d7e35eb43 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/TradeRequest.java @@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets; import com.l2jmobius.Config; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.datatables.BotReportTable; import com.l2jmobius.gameserver.enums.PrivateStoreType; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2Object; import com.l2jmobius.gameserver.model.L2World; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.model.effects.AbstractEffect; import com.l2jmobius.gameserver.model.skills.AbnormalType; @@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player, String name) + { + if (player != null) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE); + sm.addString(name); + player.sendPacket(sm); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(target.getName())) + { + final String name = FakePlayerData.getInstance().getProperName(target.getName()); + boolean npcInRange = false; + for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150)) + { + if (npc.getName().equals(name)) + { + npcInRange = true; + } + } + if (!npcInRange) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE)); + return; + } + if (!player.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1); + sm.addString(name); + player.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000); + player.blockRequest(); + } + else + { + player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE); + } + return; + } + if (!target.isPlayer()) { client.sendPacket(SystemMessageId.INVALID_TARGET); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java index 4fa25283a7..530a6d7a01 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/clientpackets/friend/RequestFriendInvite.java @@ -17,6 +17,8 @@ package com.l2jmobius.gameserver.network.clientpackets.friend; import com.l2jmobius.commons.network.PacketReader; +import com.l2jmobius.gameserver.ThreadPoolManager; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; import com.l2jmobius.gameserver.model.BlockList; import com.l2jmobius.gameserver.model.L2World; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; @@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket return true; } + private void scheduleDeny(L2PcInstance player) + { + if (player != null) + { + player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST)); + player.onTransactionResponse(); + } + } + @Override public void run(L2GameClient client) { @@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket return; } + if (FakePlayerData.getInstance().isTalkable(_name)) + { + if (!activeChar.isProcessingRequest()) + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST); + sm.addString(_name); + activeChar.sendPacket(sm); + ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000); + activeChar.blockRequest(); + } + else + { + final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER); + sm.addString(_name); + activeChar.sendPacket(sm); + } + return; + } + final L2PcInstance friend = L2World.getInstance().getPlayer(_name); // Target is not found in the game. diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java index 2170ef2e94..017541bd86 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/CreatureSay.java @@ -22,6 +22,7 @@ import java.util.List; import com.l2jmobius.commons.network.PacketWriter; import com.l2jmobius.gameserver.enums.ChatType; import com.l2jmobius.gameserver.instancemanager.MentorManager; +import com.l2jmobius.gameserver.model.actor.L2Npc; import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance; import com.l2jmobius.gameserver.network.NpcStringId; import com.l2jmobius.gameserver.network.OutgoingPackets; @@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket _charLevel = sender.getLevel(); _textType = messageType; _text = text; - if (receiver.getFriendList().contains(sender.getObjectId())) + if (receiver != null) { - _mask |= 0x01; - } - if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) - { - _mask |= 0x02; - } - if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) - { - _mask |= 0x04; - } - if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) - { - _mask |= 0x08; + if (receiver.getFriendList().contains(sender.getObjectId())) + { + _mask |= 0x01; + } + if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId())) + { + _mask |= 0x02; + } + if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null)) + { + _mask |= 0x04; + } + if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId())) + { + _mask |= 0x08; + } } // Does not shows level @@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket } } + /** + * Used by fake players. + * @param sender + * @param receiver + * @param name + * @param messageType + * @param text + */ + public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text) + { + _objectId = sender.getObjectId(); + _charName = name; + _charLevel = sender.getLevel(); + _textType = messageType; + _text = text; + } + /** * @param objectId * @param messageType diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java new file mode 100644 index 0000000000..d1b7900f12 --- /dev/null +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/FakePlayerInfo.java @@ -0,0 +1,231 @@ +/* + * This file is part of the L2J Mobius project. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jmobius.gameserver.network.serverpackets; + +import java.util.Set; + +import com.l2jmobius.commons.network.PacketWriter; +import com.l2jmobius.gameserver.data.sql.impl.ClanTable; +import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData; +import com.l2jmobius.gameserver.enums.Sex; +import com.l2jmobius.gameserver.model.L2Clan; +import com.l2jmobius.gameserver.model.actor.L2Npc; +import com.l2jmobius.gameserver.model.holders.FakePlayerHolder; +import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect; +import com.l2jmobius.gameserver.model.zone.ZoneId; +import com.l2jmobius.gameserver.network.OutgoingPackets; + +/** + * @author Mobius + */ +public class FakePlayerInfo implements IClientOutgoingPacket +{ + private final L2Npc _npc; + private final int _objId; + private final int _x, _y, _z, _heading; + private final int _mAtkSpd, _pAtkSpd; + private final int _runSpd, _walkSpd; + private final int _swimRunSpd; + private final int _swimWalkSpd; + private final int _flyRunSpd; + private final int _flyWalkSpd; + private final double _moveMultiplier; + private final float _attackSpeedMultiplier; + private final FakePlayerHolder _fpcHolder; + private final L2Clan _clan; + + public FakePlayerInfo(L2Npc npc) + { + _npc = npc; + _objId = npc.getObjectId(); + _x = npc.getX(); + _y = npc.getY(); + _z = npc.getZ(); + _heading = npc.getHeading(); + _mAtkSpd = npc.getMAtkSpd(); + _pAtkSpd = npc.getPAtkSpd(); + _attackSpeedMultiplier = npc.getAttackSpeedMultiplier(); + _moveMultiplier = npc.getMovementSpeedMultiplier(); + _runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier); + _walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier); + _swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier); + _swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier); + _flyRunSpd = npc.isFlying() ? _runSpd : 0; + _flyWalkSpd = npc.isFlying() ? _walkSpd : 0; + _fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId()); + _clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId()); + } + + @Override + public boolean write(PacketWriter packet) + { + OutgoingPackets.CHAR_INFO.writeId(packet); + packet.writeD(_x); + packet.writeD(_y); + packet.writeD(_z); + packet.writeD(0x00); // vehicleId + packet.writeD(_objId); + packet.writeS(_npc.getName()); + + packet.writeH(_npc.getRace().ordinal()); + packet.writeC(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00); + packet.writeD(_fpcHolder.getClassId()); + + packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER + packet.writeD(_fpcHolder.getEquipHead()); + packet.writeD(_fpcHolder.getEquipRHand()); + packet.writeD(_fpcHolder.getEquipLHand()); + packet.writeD(_fpcHolder.getEquipGloves()); + packet.writeD(_fpcHolder.getEquipChest()); + packet.writeD(_fpcHolder.getEquipLegs()); + packet.writeD(_fpcHolder.getEquipFeet()); + packet.writeD(_fpcHolder.getEquipCloak()); + packet.writeD(_fpcHolder.getEquipRHand()); // dual hand + packet.writeD(_fpcHolder.getEquipHair()); + packet.writeD(_fpcHolder.getEquipHair2()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderAugument()) + { + packet.writeQ(0x00); + } + + packet.writeC(_fpcHolder.getArmorEnchantLevel()); + + for (@SuppressWarnings("unused") + int slot : getPaperdollOrderVisualId()) + { + packet.writeD(0x00); + } + + packet.writeC(_npc.getScriptValue()); // getPvpFlag() + packet.writeD(_npc.getReputation()); + + packet.writeD(_mAtkSpd); + packet.writeD(_pAtkSpd); + + packet.writeH(_runSpd); + packet.writeH(_walkSpd); + packet.writeH(_swimRunSpd); + packet.writeH(_swimWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeH(_flyRunSpd); + packet.writeH(_flyWalkSpd); + packet.writeF(_moveMultiplier); + packet.writeF(_attackSpeedMultiplier); + + packet.writeF(_npc.getCollisionRadius()); + packet.writeF(_npc.getCollisionHeight()); + + packet.writeD(_fpcHolder.getHair()); + packet.writeD(_fpcHolder.getHairColor()); + packet.writeD(_fpcHolder.getFace()); + + packet.writeS(_npc.getTemplate().getTitle()); + + if (_clan != null) + { + packet.writeD(_clan.getId()); + packet.writeD(_clan.getCrestId()); + packet.writeD(_clan.getAllyId()); + packet.writeD(_clan.getAllyCrestId()); + } + else + { + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + packet.writeD(0x00); + } + + packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked) + packet.writeC(_npc.isRunning() ? 0x01 : 0x00); + packet.writeC(_npc.isInCombat() ? 0x01 : 0x00); + + packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00); + + packet.writeC(_npc.isInvisible() ? 0x01 : 0x00); + + packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount + packet.writeC(0x00); // getPrivateStoreType().getId() + + packet.writeH(0x00); // getCubics().size() + // getCubics().keySet().forEach(packet::writeH); + + packet.writeC(0x00); + + packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0); + packet.writeH(_fpcHolder.getRecommends()); + packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000 + + packet.writeD(_fpcHolder.getClassId()); + packet.writeD(0x00); + packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel + + packet.writeC(_npc.getTeam().getId()); + + packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00); + packet.writeC(_fpcHolder.getNobleLevel()); + packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00); + + packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00); + + packet.writeD(_fpcHolder.getBaitLocationX()); + packet.writeD(_fpcHolder.getBaitLocationY()); + packet.writeD(_fpcHolder.getBaitLocationZ()); + + packet.writeD(_fpcHolder.getNameColor()); + + packet.writeD(_heading); + + packet.writeC(_fpcHolder.getPledgeStatus()); + packet.writeH(0x00); // getPledgeType() + + packet.writeD(_fpcHolder.getTitleColor()); + + packet.writeC(0x00); // isCursedWeaponEquipped + + packet.writeD(0x00); // getAppearance().getVisibleClanId() > 0 ? getClan().getReputationScore() : 0 + packet.writeD(0x00); // getTransformationDisplayId() + packet.writeD(_fpcHolder.getAgathionId()); + + packet.writeC(0x00); + + packet.writeD(0x00); // getCurrentCp() + packet.writeD(_npc.getMaxHp()); + packet.writeD((int) Math.round(_npc.getCurrentHp())); + packet.writeD(_npc.getMaxMp()); + packet.writeD((int) Math.round(_npc.getCurrentMp())); + + packet.writeC(0x00); + final Set abnormalVisualEffects = _npc.getEffectList().getCurrentAbnormalVisualEffects(); + packet.writeD(abnormalVisualEffects.size() + (_npc.isInvisible() ? 1 : 0)); + for (AbnormalVisualEffect abnormalVisualEffect : abnormalVisualEffects) + { + packet.writeH(abnormalVisualEffect.getClientId()); + } + if (_npc.isInvisible()) + { + packet.writeH(AbnormalVisualEffect.STEALTH.getClientId()); + } + packet.writeC(0x00); // cocPlayer.getPosition() + packet.writeC((_fpcHolder.getHair() > 0) || (_fpcHolder.getEquipHair2() > 0) ? 0x01 : 0x00); + packet.writeC(0x00); // Used Ability Points + return true; + } +} diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java index 4fb1a757e6..c294edab2a 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/com/l2jmobius/gameserver/network/serverpackets/NpcInfo.java @@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket addComponentType(NpcInfoType.TITLE_NPCSTRINGID); } + if (_npc.getReputation() != 0) + { + addComponentType(NpcInfoType.REPUTATION); + } + if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible()) { addComponentType(NpcInfoType.ABNORMALS); @@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket } if (containsMask(NpcInfoType.REPUTATION)) { - packet.writeD(0x00); // Name color + packet.writeD(_npc.getReputation()); // Reputation } if (containsMask(NpcInfoType.CLAN)) {