Fake players for HighFive.

This commit is contained in:
MobiusDev
2018-04-13 14:03:39 +00:00
parent be8e28e974
commit 0807932e6d
54 changed files with 1886 additions and 152 deletions

View File

@@ -375,7 +375,10 @@
<admin command="admin_unban_menu" accessLevel="30" />
<!-- ADMIN MESSAGES -->
<admin command="admin_msg" accessLevel="30" />
<admin command="admin_msg" accessLevel="100" />
<!-- ADMIN FAKE PLAYERS -->
<admin command="admin_fakechat" accessLevel="100" />
<!-- ADMIN MOB GROUP -->
<admin command="admin_mobmenu" accessLevel="100" />

View File

@@ -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

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Use lowercase for searchText and answers. -->
<!-- You can use specific fpcName or ALL to use with all fpcs. -->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/FakePlayerChatData.xsd">
<fakePlayerChat fpcName="ALL" searchMethod="EQUALS" searchText="hi" answers="hello;hi;hi there;hello there" />
<fakePlayerChat fpcName="ALL" searchMethod="EQUALS" searchText="hey" answers="hey hey;hey;hey there" />
<fakePlayerChat fpcName="ALL" searchMethod="EQUALS" searchText="hello" answers="hello;hi;hi there;hello there" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="here?" answers="yes;busy;i look for something" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="whats up?" answers="good;busy;i look for something" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="what?" answers="something :P;something for me" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="why?" answers="because;i don't know;what?" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="really" answers="really;yes;of course" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="thanks" answers=":);:D;:*" />
<fakePlayerChat fpcName="Evi" searchMethod="EQUALS" searchText="thank you" answers=":);:D;:*" />
<fakePlayerChat fpcName="Evi" searchMethod="STARTS_WITH" searchText="how are you" answers="fine;good;busy" />
<fakePlayerChat fpcName="Evi" searchMethod="STARTS_WITH" searchText="do you know" answers="nope;no sorry;nope, i don't" />
<fakePlayerChat fpcName="Evi" searchMethod="STARTS_WITH" searchText="where can i" answers="i don't know;no clue;ask someone else :P" />
<fakePlayerChat fpcName="Evi" searchMethod="STARTS_WITH" searchText="can i ask you" answers="yes;what?;tell me" />
<fakePlayerChat fpcName="Evi" searchMethod="CONTAINS" searchText="server;ha;problem" answers="it's good;i don't know;i don't think so..." />
<fakePlayerChat fpcName="Evi" searchMethod="CONTAINS" searchText="server;ha;bug" answers="it's good;i don't know;i don't think so..." />
<fakePlayerChat fpcName="Evi" searchMethod="CONTAINS" searchText="is th;server;good" answers="it's good :D;i like it :P;yes it is :)" />
<fakePlayerChat fpcName="Evi" searchMethod="CONTAINS" searchText="where;you;go;?" answers="i look for something;checking stuff;looking for curius people :P" />
<fakePlayerChat fpcName="Evi" searchMethod="CONTAINS" searchText="are;you;kidding" answers="^^;:D;:P" />
</list>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Values that can be set:
int classId, int hair, int hairColor, int face, int nameColor, int titleColor, int equipRHand, int equipLHand, int equipHead,
int equipGloves, int equipChest, int equipLegs, int equipFeet, int equipCloak, int equipHair, int equipHair2, int agathionId,
int weaponEnchantLevel, int armorEnchantLevel, boolean fishing, int baitLocationX, int baitLocationY, int baitLocationZ,
int recommends, int nobleLevel, boolean hero, int clanId, int pledgeStatus -->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/FakePlayerVisualData.xsd">
<!-- Non-Combat -->
<fakePlayer npcId="80000" classId="107" hair="1" hairColor="0" face="0" equipRHand="5706" equipHead="2419" equipGloves="5774" equipChest="2383" equipFeet="5786" />
<!-- Combat -->
<!-- Duelist -->
<fakePlayer npcId="81001" classId="88" hair="0" hairColor="0" face="0" equipRHand="5706" equipHead="2419" equipGloves="5774" equipChest="2383" equipFeet="5786" />
</list>

View File

@@ -9,15 +9,37 @@
<!-- npcStringId = to use String IDs from client NpcString-e.dat -->
<!-- string = to use any custom text, example: string="Hello World" -->
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/Routes.xsd">
<!-- Just test route - Giran town square -->
<route name="test_route" repeat="true" repeatStyle="cycle">
<point X="80863" Y="148339" Z="-3469" delay="0" run="true" />
<point X="80904" Y="147653" Z="-3469" delay="0" run="true" />
<point X="83205" Y="147646" Z="-3469" delay="0" run="true" />
<point X="82189" Y="148347" Z="-3467" delay="0" run="true" />
<point X="81862" Y="148266" Z="-3467" delay="0" run="true" />
<point X="81918" Y="148352" Z="-3467" delay="0" run="true" />
<point X="81937" Y="149173" Z="-3469" delay="0" run="true" />
<route name="FPC_Giran_Evi" repeat="true" repeatStyle="cycle">
<target id="80000" spawnX="83485" spawnY="147998" spawnZ="-3407" />
<point X="83485" Y="147998" Z="-3407" delay="10" run="true" /> <!-- Gatekeeper -->
<point X="82853" Y="148022" Z="-3470" delay="0" run="true" />
<point X="82117" Y="147642" Z="-3469" delay="0" run="true" />
<point X="82084" Y="147569" Z="-3469" delay="12" run="true" /> <!-- Olympiad Manager -->
<point X="81532" Y="147578" Z="-3469" delay="0" run="true" />
<point X="81593" Y="146626" Z="-3533" delay="3" run="true" />
<point X="81932" Y="146566" Z="-3533" delay="0" run="true" />
<point X="82651" Y="146714" Z="-3466" delay="20" run="true" /> <!-- Dimesional Merchant -->
<point X="82807" Y="146649" Z="-3465" delay="0" run="true" />
<point X="83192" Y="146680" Z="-3464" delay="28" run="true" /> <!-- Warehouse -->
<point X="83198" Y="146731" Z="-3469" delay="88" run="true" /> <!-- Warehouse 2 -->
<point X="81659" Y="146555" Z="-3533" delay="3" run="true" />
<point X="81283" Y="145519" Z="-3533" delay="0" run="true" />
<point X="80201" Y="145826" Z="-3524" delay="0" run="true" />
<point X="79968" Y="145826" Z="-3497" delay="0" run="true" />
<point X="79781" Y="145546" Z="-3496" delay="0" run="true" />
<point X="79736" Y="145518" Z="-3495" delay="0" run="true" />
<point X="79663" Y="145529" Z="-3496" delay="40" run="true" /> <!-- Galladucci -->
<point X="79661" Y="145429" Z="-3495" delay="80" run="true" /> <!-- Alexandria -->
<point X="79999" Y="145152" Z="-3496" delay="0" run="true" />
<point X="80393" Y="145136" Z="-3533" delay="0" run="true" />
<point X="81061" Y="145563" Z="-3533" delay="0" run="true" />
<point X="81563" Y="145532" Z="-3533" delay="3" run="true" />
<point X="81517" Y="147231" Z="-3533" delay="0" run="true" />
<point X="81542" Y="147570" Z="-3469" delay="0" run="true" />
<point X="81139" Y="148567" Z="-3469" delay="0" run="true" />
<point X="81413" Y="149700" Z="-3469" delay="52" run="true" /> <!-- Clan Hall Managers -->
<point X="82815" Y="148840" Z="-3469" delay="3" run="true" />
<point X="83318" Y="148422" Z="-3406" delay="0" run="true" />
</route>
<!-- Hellbound Town routes for Patrols -->
<route name="castletownguard01" repeat="true" repeatStyle="random">

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -74,6 +74,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGamePoints;
@@ -369,6 +370,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGamePoints.class,

View File

@@ -129,10 +129,14 @@ public class L2NpcAction implements IActionHandler
npc.showChatWindow(activeChar);
}
}
if ((Config.PLAYER_MOVEMENT_BLOCK_TIME > 0) && !activeChar.isGM())
if (Config.PLAYER_MOVEMENT_BLOCK_TIME > 0)
{
activeChar.updateNotMoveUntil();
}
if (npc.isFakePlayer() && GeoEngine.getInstance().canSeeTarget(activeChar, npc))
{
activeChar.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, npc);
}
}
}
}

View File

@@ -191,7 +191,7 @@ public class L2NpcActionShift implements IActionShiftHandler
}
else if (Config.ALT_GAME_VIEWNPC)
{
if (!target.isNpc())
if (!target.isNpc() || target.isFakePlayer())
{
return false;
}

View File

@@ -0,0 +1,78 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package handlers.admincommandhandlers;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
/**
* @author Mobius
*/
public class AdminFakePlayers implements IAdminCommandHandler
{
private static final String[] ADMIN_COMMANDS =
{
"admin_fakechat"
};
@Override
public boolean useAdminCommand(String command, L2PcInstance activeChar)
{
if (command.startsWith("admin_fakechat"))
{
final String[] words = command.substring(15).split(" ");
if (words.length < 3)
{
activeChar.sendMessage("Usage: //fakechat playername fpcname message");
return false;
}
final L2PcInstance player = L2World.getInstance().getPlayer(words[0]);
if (player == null)
{
activeChar.sendMessage("Player not found.");
return false;
}
final String fpcName = FakePlayerData.getInstance().getProperName(words[1]);
if (fpcName == null)
{
activeChar.sendMessage("Fake player not found.");
return false;
}
String message = "";
for (int i = 0; i < words.length; i++)
{
if (i < 2)
{
continue;
}
message += (words[i] + " ");
}
FakePlayerChatManager.getInstance().sendChat(player, fpcName, message);
activeChar.sendMessage("Your message has been sent.");
}
return true;
}
@Override
public String[] getAdminCommandList()
{
return ADMIN_COMMANDS;
}
}

View File

@@ -30,6 +30,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
import com.l2jmobius.gameserver.data.xml.impl.PrimeShopData;
@@ -38,9 +39,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@@ -247,11 +251,31 @@ public class AdminReload implements IAdminCommandHandler
break;
}
case "itemmall":
case "primeshop":
{
PrimeShopData.getInstance().load();
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded item mall data.");
break;
}
case "fakeplayers":
{
FakePlayerData.getInstance().load();
for (L2Object obj : L2World.getInstance().getVisibleObjects())
{
if (obj.isFakePlayer())
{
obj.broadcastInfo();
}
}
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
break;
}
case "fakeplayerchat":
{
FakePlayerChatManager.getInstance().load();
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
break;
}
default:
{
activeChar.sendMessage(RELOAD_USAGE);

View File

@@ -23,6 +23,7 @@ import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.SevenSigns;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.data.xml.impl.NpcData;
@@ -413,6 +414,12 @@ public class AdminSpawn implements IAdminCommandHandler
template = NpcData.getInstance().getTemplateByName(monsterId.replace('_', ' '));
}
if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
{
activeChar.sendPacket(SystemMessageId.YOUR_TARGET_CANNOT_BE_FOUND);
return;
}
try
{
final L2Spawn spawn = new L2Spawn(template);

View File

@@ -17,8 +17,10 @@
package handlers.chathandlers;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.handler.IChatHandler;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.PcCondOverride;
@@ -58,6 +60,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
{
if (FakePlayerData.getInstance().isTalkable(target))
{
if (Config.FAKE_PLAYER_CHAT)
{
final String name = FakePlayerData.getInstance().getProperName(target);
activeChar.sendPacket(new CreatureSay(activeChar.getObjectId(), type, "->" + name, text));
FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
}
else
{
activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
}
}
else
{
activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
}
return;
}
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<list enabled="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../xsd/spawns.xsd">
<spawn name="FakePlayers">
<npc id="80000" x="83485" y="147998" z="-3407" heading="23509" respawnDelay="60" /> <!-- Evi -->
</spawn>
</list>

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/npcs.xsd">
<!-- Duelist -->
<npc id="81001" level="85" type="L2Monster" name="Gladus" title="Duelist" >
<race>HUMAN</race>
<sex>MALE</sex>
<stats str="88" int="39" dex="55" wit="39" con="82" men="38">
<vitals hp="22228" hpRegen="10.8" mp="3681" mpRegen="3.0" />
<attack physical="4425" magical="1284" random="30" critical="94" accuracy="206" attackSpeed="517" type="SWORD" range="40" distance="80" width="120" />
<defence physical="3613" magical="2307" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="82" />
<run ground="132" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clanList>
<clan>FAKE_PLAYER</clan>
</clanList>
</ai>
<collision>
<radius normal="9" />
<height normal="23" />
</collision>
<parameters>
<skill name="Skill01_ID" id="261" level="22" />
<skill name="Skill02_ID" id="1" level="37" />
<skill name="Skill03_ID" id="6" level="37" />
<skill name="Skill04_ID" id="8" level="8" />
</parameters>
<skillList>
<skill id="261" level="22" /> <!-- Triple Sonic Slash -->
<skill id="1" level="37" /> <!-- Triple Slash -->
<skill id="6" level="37" /> <!-- Sonic Blaster -->
<skill id="8" level="8" /> <!-- Sonic Focus -->
</skillList>
</npc>
</list>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/npcs.xsd">
<!-- Spectral Dancer -->
<npc id="80000" level="78" type="L2Npc" name="Evi" >
<race>DARK_ELF</race>
<sex>FEMALE</sex>
<stats str="103" int="40" dex="53" wit="37" con="84" men="39">
<vitals hp="18857" hpRegen="10.8" mp="3863" mpRegen="3.0" />
<attack physical="10198" magical="1305" random="30" critical="132" accuracy="177" attackSpeed="588" type="FIST" range="40" distance="80" width="120" />
<defence physical="3388" magical="2450" />
<attribute>
<defence fire="200" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="85" />
<run ground="139" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" undying="true" attackable="false" />
<collision>
<radius normal="7.5" />
<height normal="24" />
</collision>
</npc>
</list>

View File

@@ -0,0 +1,20 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="fakePlayerChat" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="fpcName" use="required" />
<xs:attribute type="xs:string" name="searchMethod" use="required" />
<xs:attribute type="xs:string" name="searchText" use="required" />
<xs:attribute type="xs:string" name="answers" use="required" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,45 @@
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="list">
<xs:complexType>
<xs:sequence>
<xs:element name="fakePlayer" maxOccurs="unbounded" minOccurs="0">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:int" name="npcId"/>
<xs:attribute type="xs:short" name="classId"/>
<xs:attribute type="xs:byte" name="hair"/>
<xs:attribute type="xs:byte" name="hairColor"/>
<xs:attribute type="xs:byte" name="face"/>
<xs:attribute type="xs:string" name="nameColor"/>
<xs:attribute type="xs:string" name="titleColor"/>
<xs:attribute type="xs:int" name="equipHead"/>
<xs:attribute type="xs:int" name="equipLHand"/>
<xs:attribute type="xs:int" name="equipRHand"/>
<xs:attribute type="xs:int" name="equipGloves"/>
<xs:attribute type="xs:int" name="equipChest"/>
<xs:attribute type="xs:int" name="equipLegs"/>
<xs:attribute type="xs:int" name="equipFeet"/>
<xs:attribute type="xs:int" name="equipCloak"/>
<xs:attribute type="xs:int" name="equipHair"/>
<xs:attribute type="xs:int" name="equipHair2"/>
<xs:attribute type="xs:int" name="agathionId"/>
<xs:attribute type="xs:byte" name="weaponEnchantLevel"/>
<xs:attribute type="xs:byte" name="armorEnchantLevel"/>
<xs:attribute type="xs:boolean" name="fishing"/>
<xs:attribute type="xs:int" name="baitLocationX"/>
<xs:attribute type="xs:int" name="baitLocationY"/>
<xs:attribute type="xs:int" name="baitLocationZ"/>
<xs:attribute type="xs:byte" name="recommends"/>
<xs:attribute type="xs:byte" name="nobleLevel"/>
<xs:attribute type="xs:boolean" name="hero"/>
<xs:attribute type="xs:long" name="clanId"/>
<xs:attribute type="xs:byte" name="pledgeStatus"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -285,5 +285,7 @@
<xs:attribute name="passableDoor" type="xs:boolean" />
<xs:attribute name="hasSummoner" type="xs:boolean" />
<xs:attribute name="canBeSown" type="xs:boolean" />
<xs:attribute name="fakePlayer" type="xs:boolean" />
<xs:attribute name="fakePlayerTalkable" type="xs:boolean" />
</xs:complexType>
</xs:schema>

View File

@@ -112,8 +112,10 @@ public final class Config
public static final String CUSTOM_COMMUNITY_BOARD_CONFIG_FILE = "./config/Custom/CommunityBoard.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_HELLBOUND_STATUS_CONFIG_FILE = "./config/Custom/HellboundStatus.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
public static final String CUSTOM_OFFLINE_TRADE_CONFIG_FILE = "./config/Custom/OfflineTrade.ini";
public static final String CUSTOM_PASSWORD_CHANGE_CONFIG_FILE = "./config/Custom/PasswordChange.ini";
@@ -131,7 +133,6 @@ public final class Config
public static final String CUSTOM_VOTE_REWARD_CONFIG_FILE = "./config/Custom/VoteReward.ini";
public static final String CUSTOM_WAREHOUSE_SORTING_CONFIG_FILE = "./config/Custom/WarehouseSorting.ini";
public static final String CUSTOM_WEDDING_CONFIG_FILE = "./config/Custom/Wedding.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_WALKER_BOT_PROTECTION_CONFIG_FILE = "./config/Custom/WalkerBotProtection.ini";
// --------------------------------------------------
@@ -1280,6 +1281,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
public static boolean FAKE_PLAYERS_ENABLED;
public static boolean FAKE_PLAYER_CHAT;
public static boolean FAKE_PLAYER_USE_SHOTS;
public static boolean FAKE_PLAYER_KILL_PVP;
public static boolean FAKE_PLAYER_KILL_KARMA;
public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
public static boolean FAKE_PLAYER_AGGRO_FPC;
public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@@ -2379,6 +2390,11 @@ public final class Config
KARMA_LIST_NONDROPPABLE_ITEMS[i] = Integer.parseInt(karma[i]);
}
ANTIFEED_ENABLE = PVPSettings.getBoolean("AntiFeedEnable", false);
ANTIFEED_DUALBOX = PVPSettings.getBoolean("AntiFeedDualbox", true);
ANTIFEED_DISCONNECTED_AS_DUALBOX = PVPSettings.getBoolean("AntiFeedDisconnectedAsDualbox", true);
ANTIFEED_INTERVAL = PVPSettings.getInt("AntiFeedInterval", 120) * 1000;
// sorting so binarySearch can be used later
Arrays.sort(KARMA_LIST_NONDROPPABLE_PET_ITEMS);
Arrays.sort(KARMA_LIST_NONDROPPABLE_ITEMS);
@@ -2386,11 +2402,6 @@ public final class Config
PVP_NORMAL_TIME = PVPSettings.getInt("PvPVsNormalTime", 120000);
PVP_PVP_TIME = PVPSettings.getInt("PvPVsPvPTime", 60000);
ANTIFEED_ENABLE = PVPSettings.getBoolean("AntiFeedEnable", false);
ANTIFEED_DUALBOX = PVPSettings.getBoolean("AntiFeedDualbox", true);
ANTIFEED_DISCONNECTED_AS_DUALBOX = PVPSettings.getBoolean("AntiFeedDisconnectedAsDualbox", true);
ANTIFEED_INTERVAL = PVPSettings.getInt("AntiFeedInterval", 120) * 1000;
// Load Olympiad config file (if exists)
final PropertiesParser Olympiad = new PropertiesParser(OLYMPIAD_CONFIG_FILE);
@@ -2766,6 +2777,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
// Load FakePlayers config file (if exists)
final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
@@ -2776,6 +2800,43 @@ public final class Config
HELLBOUND_STATUS = HellboundStatus.getBoolean("HellboundStatus", false);
// Load MultilingualSupport config file (if exists)
final PropertiesParser MultilingualSupport = new PropertiesParser(CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE);
MULTILANG_DEFAULT = MultilingualSupport.getString("MultiLangDefault", "en");
MULTILANG_ENABLE = MultilingualSupport.getBoolean("MultiLangEnable", false);
String[] allowed = MultilingualSupport.getString("MultiLangAllowed", MULTILANG_DEFAULT).split(";");
MULTILANG_ALLOWED = new ArrayList<>(allowed.length);
for (String lang : allowed)
{
MULTILANG_ALLOWED.add(lang);
}
if (!MULTILANG_ALLOWED.contains(MULTILANG_DEFAULT))
{
LOGGER.warning("MultiLang[Config.load()]: default language: " + MULTILANG_DEFAULT + " is not in allowed list !");
}
MULTILANG_VOICED_ALLOW = MultilingualSupport.getBoolean("MultiLangVoiceCommand", true);
MULTILANG_SM_ENABLE = MultilingualSupport.getBoolean("MultiLangSystemMessageEnable", false);
allowed = MultilingualSupport.getString("MultiLangSystemMessageAllowed", "").split(";");
MULTILANG_SM_ALLOWED = new ArrayList<>(allowed.length);
for (String lang : allowed)
{
if (!lang.isEmpty())
{
MULTILANG_SM_ALLOWED.add(lang);
}
}
MULTILANG_NS_ENABLE = MultilingualSupport.getBoolean("MultiLangNpcStringEnable", false);
allowed = MultilingualSupport.getString("MultiLangNpcStringAllowed", "").split(";");
MULTILANG_NS_ALLOWED = new ArrayList<>(allowed.length);
for (String lang : allowed)
{
if (!lang.isEmpty())
{
MULTILANG_NS_ALLOWED.add(lang);
}
}
// Load OfflineTrade config file (if exists)
final PropertiesParser OfflineTrade = new PropertiesParser(CUSTOM_OFFLINE_TRADE_CONFIG_FILE);
@@ -2861,7 +2922,7 @@ public final class Config
}
}
// Load CustomSettings config file (if exists)
// Load PrivateStoreRange config file (if exists)
final PropertiesParser PrivateStoreRange = new PropertiesParser(CUSTOM_PRIVATE_STORE_RANGE_CONFIG_FILE);
SHOP_MIN_RANGE_FROM_PLAYER = PrivateStoreRange.getInt("ShopMinRangeFromPlayer", 50);
@@ -3184,45 +3245,6 @@ public final class Config
WEDDING_FORMALWEAR = Wedding.getBoolean("WeddingFormalWear", true);
WEDDING_DIVORCE_COSTS = Wedding.getInt("WeddingDivorceCosts", 20);
// Load MultilingualSupport config file (if exists)
final PropertiesParser MultilingualSupport = new PropertiesParser(CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE);
MULTILANG_DEFAULT = MultilingualSupport.getString("MultiLangDefault", "en");
MULTILANG_ENABLE = MultilingualSupport.getBoolean("MultiLangEnable", false);
String[] allowed = MultilingualSupport.getString("MultiLangAllowed", MULTILANG_DEFAULT).split(";");
MULTILANG_ALLOWED = new ArrayList<>(allowed.length);
for (String lang : allowed)
{
MULTILANG_ALLOWED.add(lang);
}
if (!MULTILANG_ALLOWED.contains(MULTILANG_DEFAULT))
{
LOGGER.warning("MultiLang[Config.load()]: default language: " + MULTILANG_DEFAULT + " is not in allowed list !");
}
MULTILANG_VOICED_ALLOW = MultilingualSupport.getBoolean("MultiLangVoiceCommand", true);
MULTILANG_SM_ENABLE = MultilingualSupport.getBoolean("MultiLangSystemMessageEnable", false);
allowed = MultilingualSupport.getString("MultiLangSystemMessageAllowed", "").split(";");
MULTILANG_SM_ALLOWED = new ArrayList<>(allowed.length);
for (String lang : allowed)
{
if (!lang.isEmpty())
{
MULTILANG_SM_ALLOWED.add(lang);
}
}
MULTILANG_NS_ENABLE = MultilingualSupport.getBoolean("MultiLangNpcStringEnable", false);
allowed = MultilingualSupport.getString("MultiLangNpcStringAllowed", "").split(";");
MULTILANG_NS_ALLOWED = new ArrayList<>(allowed.length);
for (String lang : allowed)
{
if (!lang.isEmpty())
{
MULTILANG_NS_ALLOWED.add(lang);
}
}
// Load VoteReward config file (if exists)
final PropertiesParser VoteReward = new PropertiesParser(CUSTOM_VOTE_REWARD_CONFIG_FILE);

View File

@@ -53,6 +53,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnchantItemHPBonusData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemOptionsData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantSkillGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishData;
import com.l2jmobius.gameserver.data.xml.impl.FishingMonstersData;
import com.l2jmobius.gameserver.data.xml.impl.FishingRodsData;
@@ -100,6 +101,7 @@ import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DayNightSpawnManager;
import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FishingChampionshipManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
@@ -269,6 +271,8 @@ public class GameServer
DoorData.getInstance();
SkillLearnData.getInstance();
NpcData.getInstance();
FakePlayerData.getInstance();
FakePlayerChatManager.getInstance();
WalkingManager.getInstance();
StaticObjectData.getInstance();
ItemAuctionManager.getInstance();

View File

@@ -30,6 +30,7 @@ import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.interfaces.ILocational;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.AutoAttackStart;
@@ -627,6 +628,11 @@ public abstract class AbstractAI implements Ctrl
}
}
public void moveTo(ILocational loc)
{
moveTo(loc.getX(), loc.getY(), loc.getZ());
}
/**
* Move the actor to Location (x,y,z) server side AND client side by sending Server->Client packet CharMoveToLocation <I>(broadcast)</I>.<br>
* <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT>

View File

@@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.enums.AIType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.DimensionalRiftManager;
import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.Location;
@@ -56,6 +57,8 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.AbnormalVisualEffect;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.targets.L2TargetType;
@@ -489,6 +492,74 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
return;
}
if (npc.isFakePlayer() && npc.isAggressive())
{
final List<L2ItemInstance> droppedItems = npc.getFakePlayerDrops();
if (droppedItems.isEmpty())
{
L2Character nearestTarget = null;
double closestDistance = Double.MAX_VALUE;
for (L2Character t : L2World.getInstance().getVisibleObjects(npc, L2Character.class, npc.getAggroRange()))
{
if ((t == _actor) || (t == null) || t.isDead())
{
continue;
}
if ((Config.FAKE_PLAYER_AGGRO_FPC && t.isFakePlayer()) //
|| (Config.FAKE_PLAYER_AGGRO_MONSTERS && t.isMonster() && !t.isFakePlayer()) //
|| (Config.FAKE_PLAYER_AGGRO_PLAYERS && t.isPlayer()))
{
final int hating = npc.getHating(t);
final double distance = npc.calculateDistance(t, false, false);
if ((hating == 0) && (closestDistance > distance))
{
nearestTarget = t;
closestDistance = distance;
}
}
}
if (nearestTarget != null)
{
npc.addDamageHate(nearestTarget, 0, 1);
}
}
else if (!npc.isInCombat()) // must pickup items
{
final int itemIndex = npc.getFakePlayerDrops().size() - 1; // last item dropped - can also use 0 for first item dropped
final L2ItemInstance droppedItem = npc.getFakePlayerDrops().get(itemIndex);
if ((droppedItem != null) && droppedItem.isSpawned())
{
if (npc.calculateDistance(droppedItem, false, false) > 50)
{
moveTo(droppedItem);
}
else
{
npc.getFakePlayerDrops().remove(itemIndex);
droppedItem.pickupMe(npc);
if (Config.SAVE_DROPPED_ITEM)
{
ItemsOnGroundManager.getInstance().removeObject(droppedItem);
}
if (droppedItem.getItem().hasExImmediateEffect())
{
for (SkillHolder skillHolder : droppedItem.getItem().getSkills())
{
npc.doSimultaneousCast(skillHolder.getSkill());
}
npc.broadcastInfo(); // ? check if this is necessary
}
}
}
else
{
npc.getFakePlayerDrops().remove(itemIndex);
}
npc.setRunning();
}
return;
}
/*
* Check to see if this is a festival mob spawn. If it is, then check to see if the aggro trigger is a festival participant...if so, move to attack it.
*/
@@ -505,6 +576,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (autoAttackCondition(target)) // check aggression
{
if (target.isFakePlayer())
{
if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
{
final int hating = npc.getHating(target);
if (hating == 0)
{
npc.addDamageHate(target, 0, 1);
}
}
return;
}
if (target.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), target.getActingPlayer(), target.isSummon()), getActiveChar(), TerminateReturn.class);
@@ -752,7 +835,10 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// Set the AI Intention to AI_INTENTION_ACTIVE
setIntention(AI_INTENTION_ACTIVE);
npc.setWalking();
if (!_actor.isFakePlayer())
{
npc.setWalking();
}
return;
}

View File

@@ -42,7 +42,6 @@ import com.l2jmobius.gameserver.model.Location;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.instance.L2DoorInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.templates.L2NpcTemplate;
@@ -859,7 +858,7 @@ public class L2CharacterAI extends AbstractAI
// Kill the actor client side by sending Server->Client packet AutoAttackStop, StopMove/StopRotation, Die (broadcast)
clientNotifyDead();
if (!(_actor instanceof L2Playable))
if (!_actor.isPlayable() && !_actor.isFakePlayer())
{
_actor.setWalking();
}

View File

@@ -81,7 +81,7 @@ public abstract class L2PlayableAI extends L2CharacterAI
@Override
protected void onIntentionCast(Skill skill, L2Object target)
{
if ((target.isPlayable()) && skill.isBad())
if ((target != null) && (target.isPlayable()) && skill.isBad())
{
if (target.getActingPlayer().isProtectionBlessingAffected() && ((_actor.getActingPlayer().getLevel() - target.getActingPlayer().getLevel()) >= 10) && (_actor.getActingPlayer().getKarma() > 0) && !target.isInsideZone(ZoneId.PVP))
{

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<Integer, FakePlayerHolder> _fakePlayerInfos = new HashMap<>();
private final Map<String, String> _fakePlayerNames = new HashMap<>();
private final Map<String, Integer> _fakePlayerIds = new HashMap<>();
private final List<String> _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();
}
}

View File

@@ -335,6 +335,8 @@ public class NpcData implements IGameXmlReader
set.set("passableDoor", parseBoolean(attrs, "passableDoor"));
set.set("hasSummoner", parseBoolean(attrs, "hasSummoner"));
set.set("canBeSown", parseBoolean(attrs, "canBeSown"));
set.set("fakePlayer", parseBoolean(attrs, "fakePlayer"));
set.set("fakePlayerTalkable", parseBoolean(attrs, "fakePlayerTalkable"));
break;
}
case "skilllist":

View File

@@ -41,6 +41,8 @@ import com.l2jmobius.commons.database.DatabaseFactory;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@@ -215,9 +217,9 @@ public final class BotReportTable
return false;
}
final L2PcInstance bot = target.getActingPlayer();
final L2Character bot = ((L2Character) target);
if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@@ -228,7 +230,7 @@ public final class BotReportTable
return false;
}
if (bot.isInOlympiadMode())
if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEFIELD_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@@ -240,7 +242,7 @@ public final class BotReportTable
return false;
}
if (bot.getExp() == bot.getStat().getStartingExp())
if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_EXP_AFTER_CONNECTING);
return false;
@@ -327,7 +329,10 @@ public final class BotReportTable
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
handleReport(bot, rcd);
if (bot.isPlayer())
{
handleReport(bot.getActingPlayer(), rcd);
}
return true;
}

View File

@@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2EventMonsterInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.events.EventDispatcher;
@@ -200,11 +201,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
* @param actor : L2PcInstance Player requesting the item creation
* @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);

View File

@@ -89,6 +89,11 @@ public final class SpawnTable implements IGameXmlReader
return false;
}
if (!Config.FAKE_PLAYERS_ENABLED && npcTemplate.isFakePlayer())
{
return false;
}
return true;
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.instancemanager;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import org.w3c.dom.Document;
import com.l2jmobius.Config;
import com.l2jmobius.commons.concurrent.ThreadPool;
import com.l2jmobius.commons.util.IGameXmlReader;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.SpawnTable;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
/**
* @author Mobius
*/
public final class FakePlayerChatManager implements IGameXmlReader
{
private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
final List<FakePlayerChatHolder> MESSAGES = new ArrayList<>();
private static final int MIN_DELAY = 5000;
private static final int MAX_DELAY = 15000;
protected FakePlayerChatManager()
{
load();
}
@Override
public void load()
{
if (Config.FAKE_PLAYERS_ENABLED && Config.FAKE_PLAYER_CHAT)
{
MESSAGES.clear();
parseDatapackFile("data/FakePlayerChatData.xml");
LOGGER.info(getClass().getSimpleName() + ": Loaded " + MESSAGES.size() + " chat templates.");
}
else
{
LOGGER.info(getClass().getSimpleName() + ": Disabled.");
}
}
@Override
public void parseDocument(Document doc, File f)
{
forEach(doc, "list", listNode -> forEach(listNode, "fakePlayerChat", fakePlayerChatNode ->
{
final StatsSet set = new StatsSet(parseAttributes(fakePlayerChatNode));
MESSAGES.add(new FakePlayerChatHolder(set.getString("fpcName"), set.getString("searchMethod"), set.getString("searchText"), set.getString("answers")));
}));
}
public void manageChat(L2PcInstance player, String fpcName, String message)
{
ThreadPool.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
}
public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
{
ThreadPool.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
}
private void manageResponce(L2PcInstance player, String fpcName, String message)
{
if (player == null)
{
return;
}
final String text = message.toLowerCase();
// tricky question
if (text.contains("can you see me"))
{
final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
if (spawn != null)
{
final L2Npc npc = spawn.getLastSpawn();
if (npc != null)
{
if (npc.calculateDistance(player, false, false) < 3000)
{
if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
{
sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
}
else
{
sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
}
}
else
{
sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
}
return;
}
}
}
for (FakePlayerChatHolder chatHolder : MESSAGES)
{
if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
{
continue;
}
switch (chatHolder.getSearchMethod())
{
case "EQUALS":
{
if (text.equals(chatHolder.getSearchText().get(0)))
{
sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
}
break;
}
case "STARTS_WITH":
{
if (text.startsWith(chatHolder.getSearchText().get(0)))
{
sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
}
break;
}
case "CONTAINS":
{
boolean allFound = true;
for (String word : chatHolder.getSearchText())
{
if (!text.contains(word))
{
allFound = false;
}
}
if (allFound)
{
sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
}
break;
}
}
}
}
public void sendChat(L2PcInstance player, String fpcName, String message)
{
final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
if (spawn != null)
{
final L2Npc npc = spawn.getLastSpawn();
if (npc != null)
{
player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
}
}
}
public static FakePlayerChatManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
}
}

View File

@@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.model;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.commons.concurrent.ThreadPool;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
@@ -28,7 +29,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PetInstance;
public class DropProtection implements Runnable
{
private volatile boolean _isProtected = false;
private L2PcInstance _owner = null;
private L2Character _owner = null;
private ScheduledFuture<?> _task = null;
private static final long PROTECTED_MILLIS_TIME = 15000;
@@ -46,7 +47,7 @@ public class DropProtection implements Runnable
return _isProtected;
}
public L2PcInstance getOwner()
public L2Character getOwner()
{
return _owner;
}
@@ -72,12 +73,12 @@ public class DropProtection implements Runnable
_task = null;
}
public synchronized void protect(L2PcInstance player)
public synchronized void protect(L2Character character)
{
unprotect();
_isProtected = true;
_owner = player;
_owner = character;
if (_owner == null)
{

View File

@@ -366,6 +366,15 @@ public abstract class L2Object extends ListenersContainer implements IIdentifiab
return false;
}
/**
* Verify if object is a fake player.
* @return {@code true} if object is a fake player, {@code false} otherwise
*/
public boolean isFakePlayer()
{
return false;
}
/**
* Verify if object is instance of L2ServitorInstance.
* @return {@code true} if object is instance of L2ServitorInstance, {@code false} otherwise

View File

@@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAtt
import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.attackable.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@@ -294,7 +295,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
return _mustGiveExpSp;
return _mustGiveExpSp && !isFakePlayer();
}
/**
@@ -653,6 +654,12 @@ public class L2Attackable extends L2Npc
return;
}
// Check if fake players should aggro each other.
if (isFakePlayer() && !Config.FAKE_PLAYER_AGGRO_FPC && attacker.isFakePlayer())
{
return;
}
// Get the AggroInfo of the attacker L2Character from the _aggroList of the L2Attackable
final AggroInfo ai = _aggroList.computeIfAbsent(attacker, AggroInfo::new);
ai.addDamage(damage);
@@ -723,7 +730,10 @@ public class L2Attackable extends L2Npc
((L2AttackableAI) getAI()).setGlobalAggro(-25);
clearAggroList();
getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
setWalking();
if (!isFakePlayer())
{
setWalking();
}
}
return;
}
@@ -741,7 +751,10 @@ public class L2Attackable extends L2Npc
((L2AttackableAI) getAI()).setGlobalAggro(-25);
clearAggroList();
getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE);
setWalking();
if (!isFakePlayer())
{
setWalking();
}
}
}
@@ -936,6 +949,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
// unless its a fake player and they can drop items
if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
{
final Collection<ItemHolder> deathItems = npcTemplate.calculateDrops(DropType.DROP, this, mainDamageDealer);
if (deathItems != null)
{
for (ItemHolder drop : deathItems)
{
final L2Item item = ItemTable.getInstance().getTemplate(drop.getId());
// Check if the autoLoot mode is active
if (Config.AUTO_LOOT_ITEM_IDS.contains(item.getId()) || isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
{
// do nothing
}
else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
{
for (SkillHolder skillHolder : item.getSkills())
{
doSimultaneousCast(skillHolder.getSkill());
}
mainDamageDealer.broadcastInfo(); // ? check if this is necessary
}
else
{
final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
if (Config.FAKE_PLAYER_CAN_PICKUP)
{
mainDamageDealer.getFakePlayerDrops().add(droppedItem);
}
}
}
}
}
return;
}
@@ -1023,7 +1069,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
if (lastAttacker == null)
if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@@ -1385,12 +1431,29 @@ public class L2Attackable extends L2Npc
public void onSpawn()
{
super.onSpawn();
// Clear mob spoil, seed
setSpoilerObjectId(0);
// Clear all aggro char from list
clearAggroList();
// Clear Harvester reward
_harvestItem.set(null);
// fake players
if (isFakePlayer())
{
getFakePlayerDrops().clear(); // Clear existing fake player drops
setKarma(0); // reset karma
setScriptValue(0); // remove pvp flag
setRunning(); // don't walk
}
else
{
setWalking();
}
// Clear mod Seeded stat
_seeded = false;
_seed = null;

View File

@@ -26,6 +26,7 @@ import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
@@ -54,6 +55,7 @@ import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.InstanceManager;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TerritoryWarManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
@@ -136,6 +138,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExRotation;
import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.FlyToLocation.FlyType;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillCanceled;
@@ -207,6 +210,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
private int _karma = 0;
/** Table of Calculators containing all used calculator */
private Calculator[] _calculators;
/** Map containing all skills of this character. */
@@ -273,6 +278,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private final Map<Integer, Integer> _knownRelations = new ConcurrentHashMap<>();
/** A list containing the dropped items of this fake player. */
private final List<L2ItemInstance> _fakePlayerDrops = new CopyOnWriteArrayList<>();
/**
* Creates a creature.
* @param template the creature template
@@ -1033,6 +1041,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
}
}
if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
{
final L2Npc npc = ((L2Npc) this);
if (!npc.isScriptValue(1))
{
npc.setScriptValue(1); // in combat
broadcastInfo(); // update flag status
QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
}
}
// Flag the attacker if it's a L2PcInstance outside a PvP area
final L2PcInstance player = getActingPlayer();
if (player != null)
@@ -2818,7 +2837,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((L2Npc) this));
}
else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -3645,7 +3668,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((L2Npc) this));
}
else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@@ -4664,6 +4691,12 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
// Check if fake players should aggro each other.
if (isFakePlayer() && !Config.FAKE_PLAYER_AGGRO_FPC && target.isFakePlayer())
{
return;
}
if ((isNpc() && target.isAlikeDead()) || target.isDead() || (!isInSurroundingRegion(target) && !isDoor()))
{
// getAI().setIntention(CtrlIntention.AI_INTENTION_ACTIVE, null);
@@ -4976,11 +5009,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
if (target == null)
{
return false;
}
if (!(target.isPlayable() && attacker.isPlayable()))
if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()))
{
return false;
}
@@ -5749,6 +5778,10 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
}
}
}
if (target.isFakePlayer())
{
player.updatePvPStatus();
}
}
// Mobs in range 1000 see spell
@@ -5803,6 +5836,20 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
creature.getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, this);
}
}
if (isFakePlayer()) // fake player attacks player
{
if (target.isPlayable() || target.isFakePlayer())
{
final L2Npc npc = ((L2Npc) this);
if (!npc.isScriptValue(1))
{
npc.setScriptValue(1); // in combat
npc.broadcastInfo(); // update flag status
QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
}
}
}
}
}
}
@@ -6800,6 +6847,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _knownRelations;
}
public int getKarma()
{
return _karma;
}
public void setKarma(int karma)
{
_karma = karma;
}
public int getMinShopDistance()
{
return 0;
@@ -6809,4 +6866,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
public List<L2ItemInstance> getFakePlayerDrops()
{
return _fakePlayerDrops;
}
}

View File

@@ -83,18 +83,22 @@ import com.l2jmobius.gameserver.model.items.L2Weapon;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.model.zone.type.L2TownZone;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AbstractNpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@@ -132,6 +136,7 @@ public class L2Npc extends L2Character
/** Support for random animation switching */
private boolean _isRandomAnimationEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask = null;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@@ -321,7 +326,7 @@ public class L2Npc extends L2Character
*/
public boolean hasRandomAnimation()
{
return ((Config.MAX_NPC_ANIMATION > 0) && _isRandomAnimationEnabled && !getAiType().equals(AIType.CORPSE));
return ((Config.MAX_NPC_ANIMATION > 0) && isRandomAnimationEnabled() && !getAiType().equals(AIType.CORPSE));
}
/**
@@ -338,7 +343,7 @@ public class L2Npc extends L2Character
*/
public boolean isRandomAnimationEnabled()
{
return _isRandomAnimationEnabled;
return !isFakePlayer() && _isRandomAnimationEnabled;
}
@Override
@@ -440,7 +445,11 @@ public class L2Npc extends L2Character
return;
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo(this));
}
else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@@ -1239,6 +1248,74 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
if (isFakePlayer() && (killer != null) && killer.isPlayable())
{
final L2PcInstance player = killer.getActingPlayer();
if (isScriptValue(0) && (getKarma() < 0))
{
if (Config.FAKE_PLAYER_KILL_KARMA)
{
player.setKarma(player.getKarma() + Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
player.setPkKills(player.getPkKills() + 1);
player.broadcastUserInfo();
player.checkItemRestriction();
// pk item rewards
if (Config.REWARD_PK_ITEM)
{
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
}
}
// announce pk
if (Config.ANNOUNCE_PK_PVP && !player.isGM())
{
final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_3);
sm.addString(msg);
Broadcast.toAllOnlinePlayers(sm);
}
else
{
Broadcast.toAllOnlinePlayers(msg, false);
}
}
}
}
else if (Config.FAKE_PLAYER_KILL_PVP)
{
player.setPvpKills(player.getPvpKills() + 1);
player.broadcastUserInfo();
// pvp item rewards
if (Config.REWARD_PVP_ITEM)
{
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
}
}
// announce pvp
if (Config.ANNOUNCE_PK_PVP && !player.isGM())
{
final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_3);
sm.addString(msg);
Broadcast.toAllOnlinePlayers(sm);
}
else
{
Broadcast.toAllOnlinePlayers(msg, false);
}
}
}
}
DecayTaskManager.getInstance().add(this);
return true;
}
@@ -1456,7 +1533,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
activeChar.sendPacket(new FakePlayerInfo(this));
}
else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@@ -1595,7 +1676,20 @@ public class L2Npc extends L2Character
@Override
public void rechargeShots(boolean physical, boolean magic)
{
if ((_soulshotamount > 0) || (_spiritshotamount > 0))
if (isFakePlayer() && Config.FAKE_PLAYER_USE_SHOTS)
{
if (physical)
{
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2154, 1, 0, 0), 600);
setChargedShot(ShotType.SOULSHOTS, true);
}
if (magic)
{
Broadcast.toSelfAndKnownPlayersInRadius(this, new MagicSkillUse(this, this, 2061, 1, 0, 0), 600);
setChargedShot(ShotType.SPIRITSHOTS, true);
}
}
else if ((_soulshotamount > 0) || (_spiritshotamount > 0))
{
if (physical)
{
@@ -1757,12 +1851,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
* @param player the last attacker or main damage dealer
* @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@@ -1778,15 +1872,15 @@ public class L2Npc extends L2Character
return null;
}
item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
if (player != null)
if (character != null)
{
item.getDropProtection().protect(player);
item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@@ -1811,14 +1905,14 @@ public class L2Npc extends L2Character
}
/**
* Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
* @param player the last attacker or main damage dealer
* Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
* @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
return dropItem(player, item.getId(), item.getCount());
return dropItem(character, item.getId(), item.getCount());
}
@Override
@@ -1876,6 +1970,12 @@ public class L2Npc extends L2Character
return _killingBlowWeaponId;
}
@Override
public boolean isFakePlayer()
{
return _isFakePlayer;
}
/**
* Adds a summoned NPC.
* @param npc the summoned NPC

View File

@@ -319,8 +319,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
public abstract int getKarma();
public abstract byte getPvpFlag();
public abstract boolean useMagic(Skill skill, boolean forceUse, boolean dontMove);

View File

@@ -951,6 +951,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
if (target.isFakePlayer())
{
getOwner().updatePvPStatus();
}
}
}
}

View File

@@ -44,13 +44,10 @@ public class L2GuardInstance extends L2Attackable
setInstanceType(InstanceType.L2GuardInstance);
}
/**
* Return True if hte attacker is a L2MonsterInstance.
*/
@Override
public boolean isAutoAttackable(L2Character attacker)
{
if (attacker.isMonster())
if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@@ -148,6 +145,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
if (isFakePlayer() && isInCombat())
{
interact = false;
// TODO: Fix normal targeting
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{

View File

@@ -18,6 +18,7 @@ package com.l2jmobius.gameserver.model.actor.instance;
import java.util.concurrent.ScheduledFuture;
import com.l2jmobius.Config;
import com.l2jmobius.gameserver.enums.InstanceType;
import com.l2jmobius.gameserver.model.actor.L2Attackable;
import com.l2jmobius.gameserver.model.actor.L2Character;
@@ -60,6 +61,28 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
if (isFakePlayer())
{
return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
}
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
return true;
}
if (attacker.isMonster())
{
return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.
if (!attacker.isPlayable() && !attacker.isAttackable() && !(attacker instanceof L2TrapInstance) && !(attacker instanceof L2EffectPointInstance))
{
return false;
}
return super.isAutoAttackable(attacker) && !isEventMob();
}

View File

@@ -443,9 +443,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
/** The Karma of the L2PcInstance (if higher than 0, the name of the L2PcInstance appears in red) */
private int _karma;
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@@ -1923,19 +1920,11 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
/**
* Return the Karma of the L2PcInstance.
*/
@Override
public int getKarma()
{
return _karma;
}
/**
* Set the Karma of the L2PcInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param karma
*/
@Override
public void setKarma(int karma)
{
// Notify to scripts.
@@ -1945,7 +1934,7 @@ public final class L2PcInstance extends L2Playable
{
karma = 0;
}
if ((_karma == 0) && (karma > 0))
if ((getKarma() == 0) && (karma > 0))
{
L2World.getInstance().forEachVisibleObject(this, L2GuardInstance.class, object ->
{
@@ -1955,13 +1944,13 @@ public final class L2PcInstance extends L2Playable
}
});
}
else if ((_karma > 0) && (karma == 0))
else if ((getKarma() > 0) && (karma == 0))
{
// Send a Server->Client StatusUpdate packet with Karma and PvP Flag to the L2PcInstance and all L2PcInstance to inform (broadcast)
setKarmaFlag(0);
}
_karma = karma;
super.setKarma(karma);
broadcastKarma();
}
@@ -4520,6 +4509,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
if (target.isFakePlayer())
{
updatePvPStatus();
}
}
@Override
@@ -5041,40 +5034,44 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
if (pk != null)
final boolean fpcKill = killer.isFakePlayer();
if ((pk != null) || fpcKill)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
TvTEvent.onKill(killer, this);
if (L2Event.isParticipant(pk))
if (pk != null)
{
pk.getEventStatus().getKills().add(this);
}
// pvp/pk item rewards
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
// pvp
if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
TvTEvent.onKill(killer, this);
if (L2Event.isParticipant(pk))
{
pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
pk.getEventStatus().getKills().add(this);
}
// pk
if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
// pvp/pk item rewards
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
// pvp
if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
{
pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
}
// pk
if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
{
pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
}
}
}
// announce pvp/pk
if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1);
@@ -5088,7 +5085,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1);
@@ -5102,6 +5099,11 @@ public final class L2PcInstance extends L2Playable
}
}
if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getKarma() <= 0))
{
killer.setKarma(killer.getKarma() + 150);
killer.broadcastInfo();
}
}
broadcastStatusUpdate();

View File

@@ -247,6 +247,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
@Override
public int getKarma()
{
return _owner != null ? _owner.getKarma() : 0;

View File

@@ -22,7 +22,6 @@ import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.DuelManager;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Playable;
import com.l2jmobius.gameserver.model.actor.L2Summon;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.actor.stat.PcStat;
@@ -189,7 +188,7 @@ public class PcStatus extends PlayableStatus
}
}
if ((attacker instanceof L2Playable) && (caster.getCurrentCp() > 0))
if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@@ -211,7 +210,7 @@ public class PcStatus extends PlayableStatus
}
}
if (!ignoreCP && (attacker instanceof L2Playable))
if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{

View File

@@ -74,6 +74,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _undying;
private boolean _showName;
private boolean _flying;
private boolean _fakePlayer;
private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@@ -143,6 +145,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_undying = set.getBoolean("undying", true);
_showName = set.getBoolean("showName", true);
_flying = set.getBoolean("flying", false);
_fakePlayer = set.getBoolean("fakePlayer", false);
_fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@@ -368,6 +372,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
public boolean isFakePlayer()
{
return _fakePlayer;
}
public boolean isFakePlayerTalkable()
{
return _fakePlayerTalkable;
}
public boolean canMove()
{
return _canMove;

View File

@@ -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;
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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<String> _searchText;
private final List<String> _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<String> getSearchText()
{
return _searchText;
}
public List<String> getAnswers()
{
return _answers;
}
}

View File

@@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -1001,7 +1001,7 @@ public final class Skill implements IIdentifiable
public boolean checkCondition(L2Character activeChar, L2Object object, boolean itemOrWeapon)
{
if (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION)
if (activeChar.isFakePlayer() || (activeChar.canOverrideCond(PcCondOverride.SKILL_CONDITIONS) && !Config.GM_SKILL_RESTRICTION))
{
return true;
}

View File

@@ -23,6 +23,7 @@ import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.L2ZoneType;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.serverpackets.AbstractNpcInfo;
import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
public class L2WaterZone extends L2ZoneType
@@ -54,7 +55,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
if (character.getRunSpeed() == 0)
if (character.isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((L2Npc) character));
}
else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}
@@ -85,7 +90,11 @@ public class L2WaterZone extends L2ZoneType
{
L2World.getInstance().forEachVisibleObject(character, L2PcInstance.class, player ->
{
if (character.getRunSpeed() == 0)
if (character.isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((L2Npc) character));
}
else if (character.getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) character, player));
}

View File

@@ -141,7 +141,7 @@ public final class Action implements IClientIncomingPacket
}
case 1:
{
if (!activeChar.isGM() && !(obj.isNpc() && Config.ALT_GAME_VIEWNPC))
if (!activeChar.isGM() && (!(obj.isNpc() && Config.ALT_GAME_VIEWNPC) || obj.isFakePlayer()))
{
obj.onAction(activeChar, false);
}

View File

@@ -27,6 +27,7 @@ import java.util.regex.PatternSyntaxException;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@@ -109,6 +110,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
if (FakePlayerData.getInstance().getProperName(_name) != null)
{
client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
return;
}
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{

View File

@@ -21,6 +21,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@@ -36,6 +37,22 @@ public final class CreatureSay implements IClientOutgoingPacket
private int _npcString = -1;
private List<String> _parameters;
/**
* Used by fake players.
* @param sender
* @param receiver
* @param name
* @param messageType
* @param text
*/
public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
{
_objectId = sender.getObjectId();
_textType = messageType;
_charName = name;
_text = text;
}
/**
* @param objectId
* @param messageType

View File

@@ -0,0 +1,220 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.l2jmobius.gameserver.network.serverpackets;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.data.sql.impl.ClanTable;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.Sex;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.holders.FakePlayerHolder;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
/**
* @author Mobius
*/
public class FakePlayerInfo implements IClientOutgoingPacket
{
private final L2Npc _npc;
private final int _objId;
private final int _x, _y, _z, _heading;
private final int _mAtkSpd, _pAtkSpd;
private final int _runSpd, _walkSpd;
private final int _swimRunSpd;
private final int _swimWalkSpd;
private final int _flyRunSpd;
private final int _flyWalkSpd;
private final double _moveMultiplier;
private final float _attackSpeedMultiplier;
private final FakePlayerHolder _fpcHolder;
private final L2Clan _clan;
public FakePlayerInfo(L2Npc npc)
{
_npc = npc;
_objId = npc.getObjectId();
_x = npc.getX();
_y = npc.getY();
_z = npc.getZ();
_heading = npc.getHeading();
_mAtkSpd = npc.getMAtkSpd();
_pAtkSpd = (int) npc.getPAtkSpd();
_attackSpeedMultiplier = npc.getAttackSpeedMultiplier();
_moveMultiplier = npc.getMovementSpeedMultiplier();
_runSpd = (int) Math.round(npc.getRunSpeed() / _moveMultiplier);
_walkSpd = (int) Math.round(npc.getWalkSpeed() / _moveMultiplier);
_swimRunSpd = (int) Math.round(npc.getSwimRunSpeed() / _moveMultiplier);
_swimWalkSpd = (int) Math.round(npc.getSwimWalkSpeed() / _moveMultiplier);
_flyRunSpd = npc.isFlying() ? _runSpd : 0;
_flyWalkSpd = npc.isFlying() ? _walkSpd : 0;
_fpcHolder = FakePlayerData.getInstance().getInfo(npc.getId());
_clan = ClanTable.getInstance().getClan(_fpcHolder.getClanId());
}
@Override
public boolean write(PacketWriter packet)
{
OutgoingPackets.CHAR_INFO.writeId(packet);
packet.writeD(_x);
packet.writeD(_y);
packet.writeD(_z);
packet.writeD(0x00); // vehicleId
packet.writeD(_objId);
packet.writeS(_npc.getName());
packet.writeD(_npc.getRace().ordinal());
packet.writeD(_npc.getTemplate().getSex() == Sex.FEMALE ? 0x01 : 0x00);
packet.writeD(_fpcHolder.getClassId());
packet.writeD(0x00); // Inventory.PAPERDOLL_UNDER
packet.writeD(_fpcHolder.getEquipHead());
packet.writeD(_fpcHolder.getEquipRHand());
packet.writeD(_fpcHolder.getEquipLHand());
packet.writeD(_fpcHolder.getEquipGloves());
packet.writeD(_fpcHolder.getEquipChest());
packet.writeD(_fpcHolder.getEquipLegs());
packet.writeD(_fpcHolder.getEquipFeet());
packet.writeD(_fpcHolder.getEquipCloak());
packet.writeD(_fpcHolder.getEquipRHand()); // dual hand
packet.writeD(_fpcHolder.getEquipHair());
packet.writeD(_fpcHolder.getEquipHair2());
packet.writeD(0x00); // Inventory.PAPERDOLL_RBRACELET
packet.writeD(0x00); // Inventory.PAPERDOLL_LBRACELET
packet.writeD(0x00); // Inventory.PAPERDOLL_DECO1
packet.writeD(0x00); // Inventory.PAPERDOLL_DECO2
packet.writeD(0x00); // Inventory.PAPERDOLL_DECO3
packet.writeD(0x00); // Inventory.PAPERDOLL_DECO4
packet.writeD(0x00); // Inventory.PAPERDOLL_DECO5
packet.writeD(0x00); // Inventory.PAPERDOLL_DECO6
packet.writeD(0x00); // Inventory.PAPERDOLL_BELT
for (int i = 0; i < 21; i++)
{
packet.writeD(0x00);
}
packet.writeD(0x00); // getTalismanSlots
packet.writeD(0x01); // canEquipCloak
packet.writeD(_npc.getScriptValue()); // getPvpFlag()
packet.writeD(_npc.getKarma());
packet.writeD(_mAtkSpd);
packet.writeD(_pAtkSpd);
packet.writeD(0x00); // ?
packet.writeD(_runSpd);
packet.writeD(_walkSpd);
packet.writeD(_swimRunSpd);
packet.writeD(_swimWalkSpd);
packet.writeD(_flyRunSpd);
packet.writeD(_flyWalkSpd);
packet.writeD(_flyRunSpd);
packet.writeD(_flyWalkSpd);
packet.writeF(_moveMultiplier);
packet.writeF(_attackSpeedMultiplier);
packet.writeF(_npc.getCollisionRadius());
packet.writeF(_npc.getCollisionHeight());
packet.writeD(_fpcHolder.getHair());
packet.writeD(_fpcHolder.getHairColor());
packet.writeD(_fpcHolder.getFace());
packet.writeS(_npc.getTemplate().getTitle());
if (_clan != null)
{
packet.writeD(_clan.getId());
packet.writeD(_clan.getCrestId());
packet.writeD(_clan.getAllyId());
packet.writeD(_clan.getAllyCrestId());
}
else
{
packet.writeD(0x00);
packet.writeD(0x00);
packet.writeD(0x00);
packet.writeD(0x00);
}
packet.writeC(0x01); // isSitting() ? 0x00 : 0x01 (at some initial tests it worked)
packet.writeC(_npc.isRunning() ? 0x01 : 0x00);
packet.writeC(_npc.isInCombat() ? 0x01 : 0x00);
packet.writeC(_npc.isAlikeDead() ? 0x01 : 0x00);
packet.writeC(_npc.isInvisible() ? 0x01 : 0x00);
packet.writeC(0x00); // 1-on Strider, 2-on Wyvern, 3-on Great Wolf, 0-no mount
packet.writeC(0x00); // getPrivateStoreType().getId()
packet.writeH(0x00); // getCubics().size()
// getCubics().keySet().forEach(packet::writeH);
packet.writeC(0x00); // isInPartyMatchRoom
packet.writeD(_npc.getAbnormalVisualEffects());
packet.writeC(_npc.isInsideZone(ZoneId.WATER) ? 1 : 0);
packet.writeH(_fpcHolder.getRecommends()); // Blue value for name (0 = white, 255 = pure blue)
packet.writeD(0x00); // getMountNpcId() == 0 ? 0 : getMountNpcId() + 1000000
packet.writeD(_fpcHolder.getClassId());
packet.writeD(0x00); // ?
packet.writeC(_fpcHolder.getWeaponEnchantLevel()); // isMounted() ? 0 : _enchantLevel
packet.writeC(_npc.getTeam().getId());
packet.writeD(_clan != null ? _clan.getCrestLargeId() : 0x00);
packet.writeC(_fpcHolder.getNobleLevel());
packet.writeC(_fpcHolder.isHero() ? 0x01 : 0x00);
packet.writeC(_fpcHolder.isFishing() ? 0x01 : 0x00);
packet.writeD(_fpcHolder.getBaitLocationX());
packet.writeD(_fpcHolder.getBaitLocationY());
packet.writeD(_fpcHolder.getBaitLocationZ());
packet.writeD(_fpcHolder.getNameColor());
packet.writeD(_heading);
packet.writeD(_fpcHolder.getPledgeStatus());
packet.writeD(0x00); // getPledgeType()
packet.writeD(_fpcHolder.getTitleColor());
packet.writeD(0x00); // isCursedWeaponEquipped
packet.writeD(0x00); // getClanId() > 0 ? getClan().getReputationScore() : 0
// T1
packet.writeD(0x00); // getTransformationDisplayId()
packet.writeD(_fpcHolder.getAgathionId());
// T2
packet.writeD(0x01);
// T2.3
packet.writeD(_npc.getAbnormalVisualEffectSpecial());
return true;
}
}

View File

@@ -34,3 +34,4 @@ What is done
-Sell buffs command
-Dropped knownlists
-Faction System (Good vs Evil)
-Fake players