Addition of fake player system.

This commit is contained in:
MobiusDev 2017-11-26 02:33:09 +00:00
parent fffb78c071
commit 749b2775a8
339 changed files with 12524 additions and 717 deletions

View File

@ -392,6 +392,9 @@
<!-- ADMIN MESSAGES -->
<admin command="admin_msg" accessLevel="100" />
<!-- ADMIN FAKE PLAYERS -->
<admin command="admin_fakechat" accessLevel="100" />
<!-- ADMIN MOB GROUP -->
<admin command="admin_mobmenu" accessLevel="100" />
<admin command="admin_mobgroup_list" 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,37 @@
<?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 -->
<!--
####################################### Hero Weapons #####################################################
Bow(37874) Crossbow(37875) Dagger(37868) Dual Blunt Weapon(37881) Dual Dagger(37880) Dual Sword(37879)
Fist(37872) OneHand Blunt(37871) OneHand Magic Blunt(37877) One Hand Magic Sword(37876) One Hand Sword(37869)
Spear(37873) Two-handed Magic Blunt Weapon(37878) Two-handed Sword(37870) Shield(37870) Sigil(37223)
#############################################################################################################
-->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/FakePlayerVisualData.xsd">
<!-- Non-Combat -->
<fakePlayer npcId="80000" classId="188" hair="1" hairColor="1" face="0" equipRHand="17294" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="40200" />
<!-- Combat -->
<!-- Sigel Phoenix Knight -->
<fakePlayer npcId="81001" classId="148" hair="0" hairColor="0" face="0" equipRHand="37869" equipLHand="37212" equipHead="37209" equipGloves="37210" equipChest="37207" equipLegs="37208" equipFeet="37211" equipCloak="30310" />
<!-- Tyrr Titan -->
<fakePlayer npcId="81002" classId="154" hair="0" hairColor="0" face="0" equipRHand="37870" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="30311" />
<!-- Othell Fortune Seeker -->
<fakePlayer npcId="81003" classId="161" hair="0" hairColor="0" face="0" equipRHand="37880" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="30312" />
<!-- Yul Trickster -->
<fakePlayer npcId="81004" classId="165" hair="0" hairColor="0" face="0" equipRHand="37875" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="30313" />
<!-- Feoh Archmage -->
<fakePlayer npcId="81005" classId="166" hair="0" hairColor="0" face="0" equipRHand="37878" equipHead="37220" equipGloves="37221" equipChest="37218" equipLegs="37219" equipFeet="37222" equipCloak="30314" />
<!-- Iss Spectral Dancer -->
<fakePlayer npcId="81006" classId="173" hair="0" hairColor="0" face="0" equipRHand="37879" equipHead="37209" equipGloves="37210" equipChest="37207" equipLegs="37208" equipFeet="37211" equipCloak="30316" />
<!-- Aeore Eva's Saint -->
<fakePlayer npcId="81007" classId="180" hair="0" hairColor="0" face="0" equipRHand="37876" equipLHand="37223" equipHead="37220" equipGloves="37221" equipChest="37218" equipLegs="37219" equipFeet="37222" equipCloak="30317" />
<!-- Eviscerator -->
<fakePlayer npcId="81008" classId="188" hair="0" hairColor="0" face="0" equipRHand="37872" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="40200" />
<!-- Sayha's Seer -->
<fakePlayer npcId="81009" classId="189" hair="0" hairColor="0" face="0" equipRHand="37878" equipHead="37220" equipGloves="37221" equipChest="37218" equipLegs="37219" equipFeet="37222" equipCloak="40201" />
</list>

View File

@ -2402,4 +2402,43 @@
<point X="42630" Y="-48231" Z="-792" delay="0" run="true" />
<point X="45069" Y="-48034" Z="-792" delay="0" run="true" />
</route>
<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="83575" Y="147722" Z="-3405" delay="32" run="true" /> <!-- Buffer -->
<point X="82117" Y="147642" Z="-3469" delay="0" run="true" />
<point X="82152" Y="147580" Z="-3469" delay="36" run="true" /> <!-- Olympiad Statue-->
<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="83216" Y="146672" Z="-3465" delay="28" run="true" /> <!-- Warehouse -->
<point X="83211" Y="146724" Z="-3467" 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="80375" Y="145484" Z="-3535" delay="28" run="true" /> <!-- Pochi -->
<point X="80283" Y="145826" Z="-3533" delay="0" run="true" />
<point X="79952" Y="145840" Z="-3496" 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="81068" Y="145845" Z="-3533" delay="36" run="true" /> <!-- Pet Manager -->
<point X="81061" Y="145563" Z="-3533" delay="0" run="true" />
<point X="81563" Y="145532" Z="-3533" delay="3" run="true" />
<point X="81692" Y="147231" Z="-3533" delay="32" run="true" /> <!-- Kiki -->
<point X="81370" Y="147213" Z="-3533" delay="64" run="true" /> <!-- Plani -->
<point X="81517" Y="147231" Z="-3533" delay="1" run="true" />
<point X="81542" Y="147570" Z="-3469" delay="0" run="true" />
<point X="81109" Y="147770" Z="-3469" delay="99" run="true" /> <!-- Moe -->
<point X="81108" Y="149415" Z="-3469" delay="99" run="true" /> <!-- Auction House -->
<point X="81413" Y="149700" Z="-3469" delay="52" run="true" /> <!-- Clan Hall Managers -->
<point X="81718" Y="149626" Z="-3469" delay="60" run="true" /> <!-- Beauty Shop -->
<point X="82815" Y="148840" Z="-3469" delay="3" run="true" />
<point X="83307" Y="148431" Z="-3405" delay="21" run="true" /> <!-- Training Camp Manager -->
</route>
</routes>

View File

@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI
final L2Character creature = event.getSeen();
final L2Npc npc = (L2Npc) event.getSeer();
if (creature.isPlayer())
if (creature.isPlayer() || creature.isFakePlayer())
{
npc.setTarget(creature);
npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill());

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

@ -0,0 +1,115 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package custom.FakePlayers;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
import ai.AbstractNpcAI;
/**
* Town Fake Player walkers that receive buffs from Adventurer NPC.
* @author Mobius
*/
public class RecieveAdventurerBuffs extends AbstractNpcAI
{
// NPCs
private static final int[] ADVENTURERS_GUIDE =
{
32327,
33950,
};
private static final int[] FAKE_PLAYER_IDS =
{
80000
};
// Skills
// private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
private static final SkillHolder[] GROUP_BUFFS =
{
new SkillHolder(15642, 1), // Horn Melody (Adventurer)
new SkillHolder(15643, 1), // Drum Melody (Adventurer)
new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
new SkillHolder(15646, 1), // Harp Melody (Adventurer)
new SkillHolder(15647, 1), // Lute Melody (Adventurer)
new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
};
private RecieveAdventurerBuffs()
{
if (Config.FAKE_PLAYERS_ENABLED)
{
addSpawnId(FAKE_PLAYER_IDS);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead())
{
if (!npc.isMoving())
{
for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100))
{
if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId()))
{
for (SkillHolder holder : GROUP_BUFFS)
{
SkillCaster.triggerCast(nearby, npc, holder.getSkill());
}
if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage())
{
SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill());
}
else
{
SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill());
}
break;
}
}
}
startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpawn(L2Npc npc)
{
startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RecieveAdventurerBuffs();
}
}

View File

@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@ -408,6 +409,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,

View File

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

View File

@ -0,0 +1,77 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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);
}
return true;
}
@Override
public String[] getAdminCommandList()
{
return ADMIN_COMMANDS;
}
}

View File

@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
case "fakeplayers":
{
FakePlayerData.getInstance().load();
for (L2Object obj : L2World.getInstance().getVisibleObjects())
{
if (obj.isFakePlayer())
{
obj.broadcastInfo();
}
}
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
break;
}
case "fakeplayerchat":
{
FakePlayerChatManager.getInstance().load();
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
break;
}
default:
{
activeChar.sendMessage(RELOAD_USAGE);

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;
@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
{
if (FakePlayerData.getInstance().isTalkable(target))
{
if (Config.FAKE_PLAYER_CHAT)
{
final String name = FakePlayerData.getInstance().getProperName(target);
activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
}
else
{
activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
}
}
else
{
activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
}
return;
}
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))

View File

@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
}

View File

@ -16,9 +16,11 @@
*/
package handlers.playeractions;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
private void scheduleDeny(L2PcInstance player)
{
if (player != null)
{
player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
player.onTransactionResponse();
}
}
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
if ((target == null) || !target.isPlayer())
if ((target == null))
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
}
if (FakePlayerData.getInstance().isTalkable(target.getName()))
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
sm.addString(target.getName());
player.sendPacket(sm);
if (!player.isProcessingRequest())
{
ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
player.blockRequest();
}
return;
}
if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;

View File

@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest
@Id(WINDY_HEALING_POTION_1)
public void onItemCreate(OnItemCreate event)
{
final L2PcInstance player = event.getActiveChar();
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
final L2PcInstance player = event.getActiveChar().getActingPlayer();
if (player != null)
{
qs.setCond(4, true);
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
{
qs.setCond(4, true);
}
}
}
}

View File

@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest
@Id(HIGH_GRADE_LOVE_POTION)
public void onItemCreate(OnItemCreate event)
{
final L2PcInstance player = event.getActiveChar();
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
final L2PcInstance player = event.getActiveChar().getActingPlayer();
if (player != null)
{
qs.setCond(2, true);
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
{
qs.setCond(2, true);
}
}
}
}

View File

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

View File

@ -0,0 +1,341 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/npcs.xsd">
<!-- Sigel Phoenix Knight -->
<npc id="81001" level="94" type="L2Monster" name="Siegfield" title="Sigel Phoenix Knight" >
<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" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="9" />
<height normal="23" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10009" level="6" />
<skill name="Skill02_ID" id="10010" level="6" />
<skill name="Skill03_ID" id="10011" level="4" />
<skill name="Skill04_ID" id="10012" level="4" />
</parameters>
<skill_list>
<skill id="10009" level="6" /> <!-- Last Judgment -->
<skill id="10010" level="6" /> <!-- Justice Punishment -->
<skill id="10011" level="4" /> <!-- Shield Impact -->
<skill id="10012" level="4" /> <!-- Shield Wave -->
</skill_list>
</npc>
<!-- Tyrr Titan -->
<npc id="81002" level="94" type="L2Monster" name="Tyrrion" title="Tyrr Titan" >
<race>ORC</race>
<sex>MALE</sex>
<stats str="88" int="37" dex="50" wit="38" con="87" men="41">
<vitals hp="19416" hpRegen="10.8" mp="3727" mpRegen="3.0" />
<attack physical="11025" magical="1247" random="30" critical="92" accuracy="168" attackSpeed="540" type="SWORD" range="40" distance="80" width="120" />
<defence physical="3429" magical="2046" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="70" />
<run ground="130" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7" />
<height normal="27" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10267" level="4" />
<skill name="Skill02_ID" id="1760" level="5" />
</parameters>
<skill_list>
<skill id="10267" level="4" /> <!-- Hurricane Rush -->
<skill id="1760" level="5" /> <!-- Armor Destruction -->
</skill_list>
</npc>
<!-- Othell Fortune Seeker -->
<npc id="81003" level="94" type="L2Monster" name="Othelo" title="Othell Fortune Seeker" >
<race>DWARF</race>
<sex>FEMALE</sex>
<stats str="87" int="39" dex="53" wit="37" con="85" men="40">
<vitals hp="17018" hpRegen="10.8" mp="3693" mpRegen="3.0" />
<attack physical="4807" magical="1281" random="30" critical="230" accuracy="165" attackSpeed="943" type="SWORD" range="40" distance="80" width="120" />
<defence physical="2889" magical="2035" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="80" />
<run ground="131" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="5" />
<height normal="19" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10508" level="6" />
<skill name="Skill02_ID" id="10509" level="6" />
<skill name="Skill03_ID" id="10510" level="5" />
</parameters>
<skill_list>
<skill id="10508" level="6" /> <!-- Blood Stab -->
<skill id="10509" level="6" /> <!-- Heart Breaker -->
<skill id="10510" level="5" /> <!-- Chain Blow -->
</skill_list>
</npc>
<!-- Yul Trickster -->
<npc id="81004" level="94" type="L2Monster" name="Yully" title="Yul Trickster" >
<race>KAMAEL</race>
<sex>FEMALE</sex>
<stats str="88" int="43" dex="57" wit="36" con="80" men="37">
<vitals hp="15285" hpRegen="10.8" mp="4596" mpRegen="3.0" />
<attack physical="9754" magical="1375" random="30" critical="185" accuracy="167" attackSpeed="483" reuseDelay="1500" type="BOW" range="500" distance="80" width="120" />
<defence physical="2885" magical="2318" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="87" />
<run ground="140" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="ARCHER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7" />
<height normal="22.6" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10760" level="6" />
<skill name="Skill02_ID" id="10762" level="5" />
<skill name="Skill03_ID" id="10763" level="6" />
</parameters>
<skill_list>
<skill id="10760" level="6" /> <!-- Tornado Shot -->
<skill id="10762" level="5" /> <!-- Quick Shot -->
<skill id="10763" level="6" /> <!-- Pin Point -->
</skill_list>
</npc>
<!-- Feoh Archmage -->
<npc id="81005" level="94" type="L2Monster" name="Feoth" title="Feoh Archmage" >
<race>HUMAN</race>
<sex>FEMALE</sex>
<stats str="38" int="79" dex="27" wit="78" con="41" men="78">
<vitals hp="14435" hpRegen="10.8" mp="9103" mpRegen="3.0" />
<attack physical="1257" magical="10320" random="30" critical="61" accuracy="158" attackSpeed="336" type="BLUNT" range="40" distance="500" width="120" />
<defence physical="3132" magical="2635" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="78" />
<run ground="124" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="MAGE" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="8" />
<height normal="23.5" />
</collision>
<parameters>
<skill name="Skill01_ID" id="11011" level="6" />
<skill name="Skill02_ID" id="11017" level="6" />
<skill name="Skill03_ID" id="11024" level="5" />
<skill name="Skill04_ID" id="11047" level="4" />
</parameters>
<skill_list>
<skill id="11011" level="6" /> <!-- Elemental Spike -->
<skill id="11017" level="6" /> <!-- Elemental Crash -->
<skill id="11024" level="5" /> <!-- Volcanic Destruction -->
<skill id="11047" level="4" /> <!-- Ruin -->
</skill_list>
</npc>
<!-- Iss Spectral Dancer -->
<npc id="81006" level="94" type="L2Monster" name="Isda" title="Iss Spectral Dancer" >
<race>DARK_ELF</race>
<sex>FEMALE</sex>
<stats str="92" int="42" dex="56" wit="39" con="77" men="35">
<vitals hp="15499" hpRegen="10.8" mp="4038" mpRegen="3.0" />
<attack physical="8777" magical="1451" random="30" critical="95" accuracy="162" attackSpeed="582" type="SWORD" range="40" distance="80" width="120" />
<defence physical="3429" magical="2026" />
<attribute>
<defence fire="250" 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" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="BALANCED" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7" />
<height normal="23.5" />
</collision>
<parameters>
<skill name="Skill01_ID" id="11508" level="4" />
<skill name="Skill02_ID" id="11509" level="6" />
<skill name="Skill02_ID" id="11510" level="5" />
</parameters>
<skill_list>
<skill id="11508" level="4" /> <!-- Assault Rush -->
<skill id="11509" level="6" /> <!-- Crippling Attack -->
<skill id="11510" level="5" /> <!-- Shadow Blade -->
</skill_list>
</npc>
<!-- Aeore Eva's Saint -->
<npc id="81007" level="94" type="L2Monster" name="Aorta" title="Aeore Eva's Saint" >
<race>ELF</race>
<sex>FEMALE</sex>
<stats str="36" int="74" dex="32" wit="84" con="38" men="77">
<vitals hp="13651" hpRegen="10.8" mp="11193" mpRegen="3.0" />
<attack physical="1008" magical="7469" random="30" critical="63" accuracy="161" attackSpeed="400" type="SWORD" range="40" distance="80" width="120" />
<defence physical="2406" magical="2627" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="85" />
<run ground="129" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="HEALER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7.5" />
<height normal="23" />
</collision>
<parameters>
<skill name="Skill01_ID" id="11766" level="6" />
<skill name="Skill02_ID" id="11814" level="6" />
</parameters>
<skill_list>
<skill id="11766" level="6" /> <!-- Dark Blast -->
<skill id="11814" level="6" /> <!-- Dark Force -->
</skill_list>
</npc>
<!-- Eviscerator -->
<npc id="81008" level="94" type="L2Monster" name="Breezer" title="Eviscerator" >
<race>ERTHEIA</race>
<sex>FEMALE</sex>
<stats str="89" int="40" dex="52" 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="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="88" />
<run ground="141" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="6.5" />
<height normal="19.2" />
</collision>
<parameters>
<skill name="Skill01_ID" id="30500" level="18" />
<skill name="Skill02_ID" id="30504" level="6" />
</parameters>
<skill_list>
<skill id="30500" level="18" /> <!-- Lateral Hit -->
<skill id="30504" level="6" /> <!-- Gravity Hit -->
</skill_list>
</npc>
<!-- Sayha's Seer -->
<npc id="81009" level="94" type="L2Monster" name="Hoppy" title="Sayha's Seer" >
<race>ERTHEIA</race>
<sex>FEMALE</sex>
<stats str="37" int="79" dex="27" wit="76" con="42" men="80">
<vitals hp="18857" hpRegen="10.8" mp="3863" mpRegen="3.0" />
<attack physical="1242" magical="4784" random="30" critical="61" accuracy="177" attackSpeed="162" type="BLUNT" range="40" distance="80" width="120" />
<defence physical="3388" magical="2450" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="88" />
<run ground="141" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="BALANCED" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="6.5" />
<height normal="19.2" />
</collision>
<parameters>
<skill name="Skill01_ID" id="30001" level="22" /> <!-- Hydro Attack -->
<skill name="Skill02_ID" id="30019" level="5" /> <!-- Sayha's Word -->
</parameters>
<skill_list>
<skill id="30001" level="22" /> <!-- Hydro Attack -->
<skill id="30019" level="5" /> <!-- Sayha's Word -->
</skill_list>
</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">
<!-- Eviscerator -->
<npc id="80000" level="94" type="L2Npc" name="Evi" >
<race>ERTHEIA</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="88" />
<run ground="141" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" undying="true" attackable="false" />
<collision>
<radius normal="6.5" />
<height normal="19.2" />
</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

@ -201,6 +201,8 @@
<xs:attribute name="hasSummoner" type="xs:boolean" />
<xs:attribute name="canBeSown" type="xs:boolean" />
<xs:attribute name="isDeathPenalty" type="xs:boolean" />
<xs:attribute name="fakePlayer" type="xs:boolean" />
<xs:attribute name="fakePlayerTalkable" type="xs:boolean" />
</xs:complexType>
</xs:element>
<xs:element name="skill_list" minOccurs="0" maxOccurs="1">

View File

@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@ -1146,6 +1147,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
public static boolean FAKE_PLAYERS_ENABLED;
public static boolean FAKE_PLAYER_CHAT;
public static boolean FAKE_PLAYER_USE_SHOTS;
public static boolean FAKE_PLAYER_KILL_PVP;
public static boolean FAKE_PLAYER_KILL_KARMA;
public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
public static boolean FAKE_PLAYER_AGGRO_FPC;
public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@ -2558,6 +2569,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
// Load FakePlayers config file (if exists)
final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);

View File

@ -60,6 +60,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnchantSkillGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@ -109,6 +110,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
@ -282,6 +284,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
FakePlayerData.getInstance();
FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
WalkingManager.getInstance();

View File

@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
if (npc.isAggressive() || (npc instanceof L2GuardInstance))
if (npc.isFakePlayer() && npc.isAggressive())
{
final List<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().getAllSkills())
{
SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
}
npc.broadcastInfo(); // ? check if this is necessary
}
}
}
else
{
npc.getFakePlayerDrops().remove(itemIndex);
}
npc.setRunning();
}
}
else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
if (t.isPlayable())
if (t.isFakePlayer())
{
if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
{
final int hating = npc.getHating(t);
if (hating == 0)
{
npc.addDamageHate(t, 0, 1);
}
}
}
else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())

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

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

View File

@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
{
return;
}
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))

View File

@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
if (target == null)
{
return false;
}
final L2PcInstance bot = target.getActingPlayer();
final L2Character bot = ((L2Character) target);
if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
if (bot.isInOlympiadMode())
if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
if (bot.getExp() == bot.getStat().getStartingExp())
if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
sm.addCharName(bot);
sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
sm.addCharName(bot);
sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
handleReport(bot, rcd);
if (bot.isPlayer())
{
handleReport(bot.getActingPlayer(), rcd);
}
return true;
}

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;
@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
* @param actor : L2PcInstance Player requesting the item creation
* @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);

View File

@ -217,6 +217,7 @@ public abstract class IdFactory
cleanCount += stmt.executeUpdate("DELETE FROM character_offline_trade_items WHERE character_offline_trade_items.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_tpbookmark WHERE character_tpbookmark.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM character_variables WHERE character_variables.charId NOT IN (SELECT charId FROM characters);");
cleanCount += stmt.executeUpdate("DELETE FROM bot_reported_char_data WHERE bot_reported_char_data.botId NOT IN (SELECT charId FROM characters);");
// If the clan does not exist...
cleanCount += stmt.executeUpdate("DELETE FROM clan_privs WHERE clan_privs.clan_id NOT IN (SELECT clan_id FROM clan_data);");

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.util.IGameXmlReader;
import com.l2jmobius.commons.util.Rnd;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.SpawnTable;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.model.L2Spawn;
import com.l2jmobius.gameserver.model.StatsSet;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.holders.FakePlayerChatHolder;
import com.l2jmobius.gameserver.network.serverpackets.CreatureSay;
/**
* @author Mobius
*/
public final class FakePlayerChatManager implements IGameXmlReader
{
private static Logger LOGGER = Logger.getLogger(FakePlayerChatManager.class.getName());
final List<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)
{
ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(MIN_DELAY, MAX_DELAY));
}
public void manageChat(L2PcInstance player, String fpcName, String message, int minDelay, int maxDelay)
{
ThreadPoolManager.schedule(() -> manageResponce(player, fpcName, message), Rnd.get(minDelay, maxDelay));
}
private void manageResponce(L2PcInstance player, String fpcName, String message)
{
if (player == null)
{
return;
}
final String text = message.toLowerCase();
// tricky question
if (text.contains("can you see me"))
{
final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
if (spawn != null)
{
final L2Npc npc = spawn.getLastSpawn();
if (npc != null)
{
if (npc.calculateDistance(player, false, false) < 3000)
{
if (GeoEngine.getInstance().canSeeTarget(npc, player) && !player.isInvisible())
{
sendChat(player, fpcName, Rnd.nextBoolean() ? "i am not blind" : Rnd.nextBoolean() ? "of course i can" : "yes");
}
else
{
sendChat(player, fpcName, Rnd.nextBoolean() ? "i know you are around" : Rnd.nextBoolean() ? "not at the moment :P" : "no, where are you?");
}
}
else
{
sendChat(player, fpcName, Rnd.nextBoolean() ? "nope, can't see you" : Rnd.nextBoolean() ? "nope" : "no");
}
return;
}
}
}
for (FakePlayerChatHolder chatHolder : MESSAGES)
{
if (!chatHolder.getFpcName().equals(fpcName) && !chatHolder.getFpcName().equals("ALL"))
{
continue;
}
switch (chatHolder.getSearchMethod())
{
case "EQUALS":
{
if (text.equals(chatHolder.getSearchText().get(0)))
{
sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
}
break;
}
case "STARTS_WITH":
{
if (text.startsWith(chatHolder.getSearchText().get(0)))
{
sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
}
break;
}
case "CONTAINS":
{
boolean allFound = true;
for (String word : chatHolder.getSearchText())
{
if (!text.contains(word))
{
allFound = false;
}
}
if (allFound)
{
sendChat(player, fpcName, chatHolder.getAnswers().get(Rnd.get(chatHolder.getAnswers().size())));
}
break;
}
}
}
}
public void sendChat(L2PcInstance player, String fpcName, String message)
{
final L2Spawn spawn = SpawnTable.getInstance().getAnySpawn(FakePlayerData.getInstance().getNpcIdByName(fpcName));
if (spawn != null)
{
final L2Npc npc = spawn.getLastSpawn();
if (npc != null)
{
player.sendPacket(new CreatureSay(npc, player, fpcName, ChatType.WHISPER, message));
}
}
}
public static FakePlayerChatManager getInstance()
{
return SingletonHolder._instance;
}
private static class SingletonHolder
{
protected static final FakePlayerChatManager _instance = new FakePlayerChatManager();
}
}

View File

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

View File

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

View File

@ -70,6 +70,7 @@ import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAggr
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableAttack;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableKill;
import com.l2jmobius.gameserver.model.holders.ItemHolder;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.L2Item;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
@ -279,7 +280,7 @@ public class L2Attackable extends L2Npc
public synchronized boolean getMustRewardExpSP()
{
return _mustGiveExpSp;
return _mustGiveExpSp && !isFakePlayer();
}
/**
@ -958,6 +959,39 @@ public class L2Attackable extends L2Npc
// Don't drop anything if the last attacker or owner isn't L2PcInstance
if (player == null)
{
// unless its a fake player and they can drop items
if (mainDamageDealer.isFakePlayer() && Config.FAKE_PLAYER_CAN_DROP_ITEMS)
{
final Collection<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 (isFlying() || (!item.hasExImmediateEffect() && ((!isRaid() && Config.AUTO_LOOT) || (isRaid() && Config.AUTO_LOOT_RAIDS))))
{
// do nothing
}
else if (Config.AUTO_LOOT_HERBS && item.hasExImmediateEffect())
{
for (SkillHolder skillHolder : item.getAllSkills())
{
SkillCaster.triggerCast(mainDamageDealer, null, skillHolder.getSkill(), null, false);
}
mainDamageDealer.broadcastInfo(); // ? check if this is necessary
}
else
{
final L2ItemInstance droppedItem = dropItem(mainDamageDealer, drop); // drop the item on the ground
if (Config.FAKE_PLAYER_CAN_PICKUP)
{
mainDamageDealer.getFakePlayerDrops().add(droppedItem);
}
}
}
}
}
return;
}
@ -1045,7 +1079,7 @@ public class L2Attackable extends L2Npc
*/
public void doEventDrop(L2Character lastAttacker)
{
if (lastAttacker == null)
if ((lastAttacker == null) || isFakePlayer())
{
return;
}
@ -1419,6 +1453,15 @@ public class L2Attackable extends L2Npc
_harvestItem.set(null);
_sweepItems.set(null);
// fake players
if (isFakePlayer())
{
getFakePlayerDrops().clear(); // Clear existing fake player drops
setReputation(0); // reset reputation
setScriptValue(0); // remove pvp flag
setRunning(); // don't walk
}
// Clear mod Seeded stat
_seeded = false;
_seed = null;

View File

@ -29,6 +29,7 @@ import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@ -61,6 +62,7 @@ import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.idfactory.IdFactory;
import com.l2jmobius.gameserver.instancemanager.MapRegionManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.TimersManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.CharEffectList;
@ -136,6 +138,7 @@ import com.l2jmobius.gameserver.network.serverpackets.Attack;
import com.l2jmobius.gameserver.network.serverpackets.ChangeMoveType;
import com.l2jmobius.gameserver.network.serverpackets.ChangeWaitType;
import com.l2jmobius.gameserver.network.serverpackets.ExTeleportToLocationActivate;
import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.IClientOutgoingPacket;
import com.l2jmobius.gameserver.network.serverpackets.MoveToLocation;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@ -202,6 +205,8 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
private double _hpUpdateDecCheck = .0;
private double _hpUpdateInterval = .0;
private int _reputation = 0;
/** Map containing all skills of this character. */
private final Map<Integer, Skill> _skills = new ConcurrentSkipListMap<>();
/** Map containing the skill reuse time stamps. */
@ -270,6 +275,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
/** A map holding info about basic property mesmerizing system. */
private volatile Map<BasicProperty, BasicPropertyResist> _basicPropertyResists;
/** 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
@ -1207,6 +1215,17 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
broadcastPacket(attack);
}
if (isFakePlayer() && (target.isPlayable() || target.isFakePlayer()))
{
final L2Npc npc = ((L2Npc) this);
if (!npc.isScriptValue(1))
{
npc.setScriptValue(1); // in combat
broadcastInfo(); // update flag status
QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
}
}
// Notify AI with EVT_READY_TO_ACT
ThreadPoolManager.schedule(new NotifyAITask(this, CtrlEvent.EVT_READY_TO_ACT), timeAtk);
}
@ -2317,7 +2336,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((L2Npc) this));
}
else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@ -2945,7 +2968,11 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return;
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo((L2Npc) this));
}
else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo((L2Npc) this, player));
}
@ -4127,7 +4154,7 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
public boolean isInsidePeaceZone(L2Object attacker, L2Object target)
{
final Instance instanceWorld = getInstanceWorld();
if ((target == null) || !(target.isPlayable() && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
if ((target == null) || !((target.isPlayable() || target.isFakePlayer()) && attacker.isPlayable()) || ((instanceWorld != null) && instanceWorld.isPvP()))
{
return false;
}
@ -5535,6 +5562,16 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
return _basicPropertyResists.computeIfAbsent(basicProperty, k -> new BasicPropertyResist());
}
public int getReputation()
{
return _reputation;
}
public void setReputation(int reputation)
{
_reputation = reputation;
}
/**
* Gets the distance to target.
* @param target the target
@ -5549,4 +5586,9 @@ public abstract class L2Character extends L2Object implements ISkillsHolder, IDe
{
_cursorKeyMovement = value;
}
public List<L2ItemInstance> getFakePlayerDrops()
{
return _fakePlayerDrops;
}
}

View File

@ -35,6 +35,7 @@ import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.enums.Race;
import com.l2jmobius.gameserver.enums.ShotType;
import com.l2jmobius.gameserver.enums.Team;
import com.l2jmobius.gameserver.enums.UserInfoType;
import com.l2jmobius.gameserver.handler.BypassHandler;
import com.l2jmobius.gameserver.handler.IBypassHandler;
import com.l2jmobius.gameserver.instancemanager.CastleManager;
@ -79,6 +80,7 @@ import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.olympiad.Olympiad;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.spawns.NpcSpawnTemplate;
import com.l2jmobius.gameserver.model.stats.Formulas;
import com.l2jmobius.gameserver.model.variables.NpcVariables;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.NpcStringId;
@ -86,6 +88,7 @@ import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ActionFailed;
import com.l2jmobius.gameserver.network.serverpackets.ExChangeNpcState;
import com.l2jmobius.gameserver.network.serverpackets.ExShowChannelingEffect;
import com.l2jmobius.gameserver.network.serverpackets.FakePlayerInfo;
import com.l2jmobius.gameserver.network.serverpackets.MagicSkillUse;
import com.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
import com.l2jmobius.gameserver.network.serverpackets.NpcInfo;
@ -93,6 +96,8 @@ import com.l2jmobius.gameserver.network.serverpackets.NpcInfoAbnormalVisualEffec
import com.l2jmobius.gameserver.network.serverpackets.NpcSay;
import com.l2jmobius.gameserver.network.serverpackets.ServerObjectInfo;
import com.l2jmobius.gameserver.network.serverpackets.SocialAction;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
import com.l2jmobius.gameserver.network.serverpackets.UserInfo;
import com.l2jmobius.gameserver.taskmanager.DecayTaskManager;
import com.l2jmobius.gameserver.util.Broadcast;
@ -125,6 +130,7 @@ public class L2Npc extends L2Character
private boolean _isRandomAnimationEnabled = true;
private boolean _isRandomWalkingEnabled = true;
private boolean _isTalkable = getTemplate().isTalkable();
private final boolean _isFakePlayer = getTemplate().isFakePlayer();
protected RandomAnimationTask _rAniTask;
private int _currentLHandId; // normally this shouldn't change from the template, but there exist exceptions
@ -365,7 +371,11 @@ public class L2Npc extends L2Character
return;
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
player.sendPacket(new FakePlayerInfo(this));
}
else if (getRunSpeed() == 0)
{
player.sendPacket(new ServerObjectInfo(this, player));
}
@ -902,6 +912,78 @@ public class L2Npc extends L2Character
final L2Weapon weapon = (killer != null) ? killer.getActiveWeaponItem() : null;
_killingBlowWeaponId = (weapon != null) ? weapon.getId() : 0;
if (isFakePlayer() && (killer != null) && killer.isPlayable())
{
final L2PcInstance player = killer.getActingPlayer();
if (isScriptValue(0) && (getReputation() >= 0))
{
if (Config.FAKE_PLAYER_KILL_KARMA)
{
player.setReputation(player.getReputation() - Formulas.calculateKarmaGain(player.getPkKills(), killer.isSummon()));
player.setPkKills(player.getPkKills() + 1);
final UserInfo ui = new UserInfo(player, false);
ui.addComponentType(UserInfoType.SOCIAL);
player.sendPacket(ui);
player.checkItemRestriction();
// pk item rewards
if (Config.REWARD_PK_ITEM)
{
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
player.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
}
}
// announce pk
if (Config.ANNOUNCE_PK_PVP && !player.isGM())
{
final String msg = Config.ANNOUNCE_PK_MSG.replace("$killer", player.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
sm.addString(msg);
Broadcast.toAllOnlinePlayers(sm);
}
else
{
Broadcast.toAllOnlinePlayers(msg, false);
}
}
}
}
else if (Config.FAKE_PLAYER_KILL_PVP)
{
player.setPvpKills(player.getPvpKills() + 1);
final UserInfo ui = new UserInfo(player, false);
ui.addComponentType(UserInfoType.SOCIAL);
player.sendPacket(ui);
// pvp item rewards
if (Config.REWARD_PVP_ITEM)
{
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
player.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
}
}
// announce pvp
if (Config.ANNOUNCE_PK_PVP && !player.isGM())
{
final String msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", player.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
sm.addString(msg);
Broadcast.toAllOnlinePlayers(sm);
}
else
{
Broadcast.toAllOnlinePlayers(msg, false);
}
}
}
}
DecayTaskManager.getInstance().add(this);
final L2Spawn spawn = getSpawn();
@ -1211,7 +1293,11 @@ public class L2Npc extends L2Character
activeChar.sendMessage("Added NPC: " + getName());
}
if (getRunSpeed() == 0)
if (isFakePlayer())
{
activeChar.sendPacket(new FakePlayerInfo(this));
}
else if (getRunSpeed() == 0)
{
activeChar.sendPacket(new ServerObjectInfo(this, activeChar));
}
@ -1455,12 +1541,12 @@ public class L2Npc extends L2Character
/**
* Drops an item.
* @param player the last attacker or main damage dealer
* @param character the last attacker or main damage dealer
* @param itemId the item ID
* @param itemCount the item count
* @return the dropped item
*/
public L2ItemInstance dropItem(L2PcInstance player, int itemId, long itemCount)
public L2ItemInstance dropItem(L2Character character, int itemId, long itemCount)
{
L2ItemInstance item = null;
for (int i = 0; i < itemCount; i++)
@ -1476,15 +1562,15 @@ public class L2Npc extends L2Character
return null;
}
item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, player, this);
item = ItemTable.getInstance().createItem("Loot", itemId, itemCount, character, this);
if (item == null)
{
return null;
}
if (player != null)
if (character != null)
{
item.getDropProtection().protect(player);
item.getDropProtection().protect(character);
}
item.dropMe(this, newX, newY, newZ);
@ -1509,14 +1595,14 @@ public class L2Npc extends L2Character
}
/**
* Method overload for {@link L2Attackable#dropItem(L2PcInstance, int, long)}
* @param player the last attacker or main damage dealer
* Method overload for {@link L2Attackable#dropItem(L2Character, int, long)}
* @param character the last attacker or main damage dealer
* @param item the item holder
* @return the dropped item
*/
public L2ItemInstance dropItem(L2PcInstance player, ItemHolder item)
public L2ItemInstance dropItem(L2Character character, ItemHolder item)
{
return dropItem(player, item.getId(), item.getCount());
return dropItem(character, item.getId(), item.getCount());
}
@Override
@ -1580,6 +1666,12 @@ public class L2Npc extends L2Character
return Config.SHOP_MIN_RANGE_FROM_NPC;
}
@Override
public boolean isFakePlayer()
{
return _isFakePlayer;
}
/**
* @return The player's object Id this NPC is cloning.
*/

View File

@ -304,8 +304,6 @@ public abstract class L2Playable extends L2Character
public abstract void doPickupItem(L2Object object);
public abstract int getReputation();
public abstract boolean useMagic(Skill skill, L2ItemInstance item, boolean forceUse, boolean dontMove);
public abstract void storeMe();

View File

@ -725,7 +725,7 @@ public abstract class L2Summon extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
sm.addCharName(target);
sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@ -743,7 +743,7 @@ public abstract class L2Summon extends L2Playable
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
sm.addCharName(attacker);
sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}
@ -905,6 +905,10 @@ public abstract class L2Summon extends L2Playable
{
setTarget(target);
getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
if (target.isFakePlayer())
{
getOwner().updatePvPStatus();
}
}
}
}

View File

@ -147,7 +147,7 @@ public class DoppelgangerInstance extends L2Npc
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addNpcName(this);
sm.addCharName(target);
sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
}
@ -165,7 +165,7 @@ public class DoppelgangerInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
sm.addNpcName(this);
sm.addCharName(attacker);
sm.addString(attacker.getName());
sm.addInt((int) damage);
sendPacket(sm);
}

View File

@ -57,7 +57,7 @@ public class L2GuardInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
if (attacker.isMonster())
if (attacker.isMonster() && !attacker.isFakePlayer())
{
return true;
}
@ -154,6 +154,13 @@ public class L2GuardInstance extends L2Attackable
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
if (isFakePlayer() && isInCombat())
{
interact = false;
// TODO: Fix normal targeting
player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, this);
}
// Check if the L2PcInstance already target the L2GuardInstance
if (getObjectId() != player.getTargetId())
{

View File

@ -69,6 +69,11 @@ public class L2MonsterInstance extends L2Attackable
@Override
public boolean isAutoAttackable(L2Character attacker)
{
if (isFakePlayer())
{
return isInCombat() || attacker.isMonster() || (getScriptValue() > 0);
}
// Check if the L2MonsterInstance target is aggressive
if (Config.GUARD_ATTACK_AGGRO_MOB && isAggressive() && (attacker instanceof L2GuardInstance))
{
@ -77,7 +82,7 @@ public class L2MonsterInstance extends L2Attackable
if (attacker.isMonster())
{
return false;
return attacker.isFakePlayer();
}
// Anything considers monsters friendly except Players, Attackables (Guards, Friendly NPC), Traps and EffectPoints.

View File

@ -445,9 +445,6 @@ public final class L2PcInstance extends L2Playable
/** The Experience of the L2PcInstance before the last Death Penalty */
private long _expBeforeDeath;
/** The Reputation of the L2PcInstance */
private int _reputation;
/** The number of player killed during a PvP (the player killed was PvP Flagged) */
private int _pvpKills;
@ -1992,24 +1989,16 @@ public final class L2PcInstance extends L2Playable
return _expBeforeDeath;
}
/**
* @return the reputation of the PlayerInstance.
*/
@Override
public int getReputation()
{
return _reputation;
}
public void setInitialReputation(int reputation)
{
_reputation = reputation;
super.setReputation(reputation);
}
/**
* Set the reputation of the PlayerInstance and send a Server->Client packet StatusUpdate (broadcast).
* @param reputation
*/
@Override
public void setReputation(int reputation)
{
// Notify to scripts.
@ -2035,7 +2024,9 @@ public final class L2PcInstance extends L2Playable
}
});
}
_reputation = reputation;
super.setReputation(reputation);
sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_REPUTATION_HAS_BEEN_CHANGED_TO_S1).addInt(getReputation()));
broadcastReputation();
}
@ -4655,6 +4646,10 @@ public final class L2PcInstance extends L2Playable
{
super.doAttack(target);
setRecentFakeDeath(false);
if (target.isFakePlayer())
{
updatePvPStatus();
}
}
@Override
@ -4982,22 +4977,42 @@ public final class L2PcInstance extends L2Playable
if (killer != null)
{
final L2PcInstance pk = killer.getActingPlayer();
if (pk != null)
final boolean fpcKill = killer.isFakePlayer();
if ((pk != null) || fpcKill)
{
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
if (L2Event.isParticipant(pk))
if (pk != null)
{
pk.getEventStatus().addKill(this);
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerPvPKill(pk, this), this);
if (L2Event.isParticipant(pk))
{
pk.getEventStatus().addKill(this);
}
// pvp/pk item rewards
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
{
// pvp
if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
{
pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
}
// pk
if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
{
pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
}
}
}
// announce pvp/pk
if (Config.ANNOUNCE_PK_PVP && !pk.isGM())
if (Config.ANNOUNCE_PK_PVP && (((pk != null) && !pk.isGM()) || fpcKill))
{
String msg = "";
if (getPvpFlag() == 0)
{
msg = Config.ANNOUNCE_PK_MSG.replace("$killer", pk.getName()).replace("$target", getName());
msg = Config.ANNOUNCE_PK_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@ -5011,7 +5026,7 @@ public final class L2PcInstance extends L2Playable
}
else if (getPvpFlag() != 0)
{
msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", pk.getName()).replace("$target", getName());
msg = Config.ANNOUNCE_PVP_MSG.replace("$killer", killer.getName()).replace("$target", getName());
if (Config.ANNOUNCE_PK_PVP_NORMAL_MESSAGE)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S13);
@ -5025,20 +5040,9 @@ public final class L2PcInstance extends L2Playable
}
}
// pvp/pk item rewards
if (!(Config.DISABLE_REWARDS_IN_INSTANCES && (getInstanceId() != 0)) && //
!(Config.DISABLE_REWARDS_IN_PVP_ZONES && isInsideZone(ZoneId.PVP)))
if (fpcKill && Config.FAKE_PLAYER_KILL_KARMA && (getPvpFlag() == 0) && (getReputation() >= 0))
{
// pvp
if (Config.REWARD_PVP_ITEM && (getPvpFlag() != 0))
{
pk.addItem("PvP Item Reward", Config.REWARD_PVP_ITEM_ID, Config.REWARD_PVP_ITEM_AMOUNT, this, Config.REWARD_PVP_ITEM_MESSAGE);
}
// pk
if (Config.REWARD_PK_ITEM && (getPvpFlag() == 0))
{
pk.addItem("PK Item Reward", Config.REWARD_PK_ITEM_ID, Config.REWARD_PK_ITEM_AMOUNT, this, Config.REWARD_PK_ITEM_MESSAGE);
}
killer.setReputation(killer.getReputation() - 150);
}
}
@ -5631,6 +5635,14 @@ public final class L2PcInstance extends L2Playable
return (getActiveRequester() != null) || (_activeTradeList != null) || (_requestExpireTime > GameTimeController.getInstance().getGameTicks());
}
/**
* Used by fake players to emulate proper behavior.
*/
public void blockRequest()
{
_requestExpireTime = GameTimeController.getInstance().getGameTicks() + (REQUEST_TIMEOUT * GameTimeController.TICKS_PER_SECOND);
}
/**
* Select the Warehouse to be used in next activity.
* @param partner
@ -11568,7 +11580,7 @@ public final class L2PcInstance extends L2Playable
{
sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addPcName(this);
sm.addCharName(target);
sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), -damage);
}

View File

@ -178,6 +178,7 @@ public final class L2TrapInstance extends L2Npc
return null;
}
@Override
public int getReputation()
{
return _owner != null ? _owner.getReputation() : 0;
@ -265,7 +266,7 @@ public final class L2TrapInstance extends L2Npc
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_INFLICTED_S3_DAMAGE_ON_C2_S4);
sm.addCharName(this);
sm.addCharName(target);
sm.addString(target.getName());
sm.addInt(damage);
sm.addPopup(target.getObjectId(), getObjectId(), (damage * -1));
_owner.sendPacket(sm);

View File

@ -214,7 +214,7 @@ public class PcStatus extends PlayableStatus
}
}
if (attacker.isPlayable() && (caster.getCurrentCp() > 0))
if ((attacker.isPlayable() || attacker.isFakePlayer()) && (caster.getCurrentCp() > 0))
{
if (caster.getCurrentCp() > transferDmg)
{
@ -236,7 +236,7 @@ public class PcStatus extends PlayableStatus
}
}
if (!ignoreCP && attacker.isPlayable())
if (!ignoreCP && (attacker.isPlayable() || attacker.isFakePlayer()))
{
if (getCurrentCp() >= value)
{
@ -255,7 +255,7 @@ public class PcStatus extends PlayableStatus
// Send a System Message to the L2PcInstance
SystemMessage smsg = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_RECEIVED_S3_DAMAGE_FROM_C2);
smsg.addString(getActiveChar().getName());
smsg.addCharName(attacker);
smsg.addString(attacker.getName());
smsg.addInt(fullValue);
getActiveChar().sendPacket(smsg);

View File

@ -78,6 +78,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
private boolean _randomWalk;
private boolean _randomAnimation;
private boolean _flying;
private boolean _fakePlayer;
private boolean _fakePlayerTalkable;
private boolean _canMove;
private boolean _noSleepMode;
private boolean _passableDoor;
@ -157,6 +159,8 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
_randomWalk = set.getBoolean("randomWalk", !_type.equals("L2Guard"));
_randomAnimation = set.getBoolean("randomAnimation", true);
_flying = set.getBoolean("flying", false);
_fakePlayer = set.getBoolean("fakePlayer", false);
_fakePlayerTalkable = set.getBoolean("fakePlayerTalkable", true);
_canMove = set.getBoolean("canMove", true);
_noSleepMode = set.getBoolean("noSleepMode", false);
_passableDoor = set.getBoolean("passableDoor", false);
@ -390,6 +394,16 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
return _flying;
}
public boolean isFakePlayer()
{
return _fakePlayer;
}
public boolean isFakePlayerTalkable()
{
return _fakePlayerTalkable;
}
public boolean canMove()
{
return _canMove;
@ -757,7 +771,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_CHANCE_BY_ID.get(dropItem.getItemId()) != null)
{
@ -803,7 +817,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
}
// premium chance
if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
if (Config.PREMIUM_RATE_DROP_AMOUNT_BY_ID.get(dropItem.getItemId()) != null)
{
@ -834,7 +848,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
case LUCKY_DROP:
{
// try chance before luck
if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && killer.getActingPlayer().tryLuck())
if (((Rnd.nextDouble() * 100) < dropItem.getChance()) && (killer.getActingPlayer() != null) && killer.getActingPlayer().tryLuck())
{
return new ItemHolder(dropItem.getItemId(), Rnd.get(dropItem.getMin(), dropItem.getMax()));
}
@ -845,7 +859,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// chance
double rateChance = Config.RATE_SPOIL_DROP_CHANCE_MULTIPLIER;
// premium chance
if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateChance *= Config.PREMIUM_RATE_SPOIL_CHANCE;
}
@ -858,7 +872,7 @@ public final class L2NpcTemplate extends L2CharTemplate implements IIdentifiable
// amount is calculated after chance returned success
double rateAmount = Config.RATE_SPOIL_DROP_AMOUNT_MULTIPLIER;
// premium amount
if (Config.PREMIUM_SYSTEM_ENABLED && killer.getActingPlayer().hasPremiumStatus())
if (Config.PREMIUM_SYSTEM_ENABLED && (killer.getActingPlayer() != null) && killer.getActingPlayer().hasPremiumStatus())
{
rateAmount *= Config.PREMIUM_RATE_SPOIL_AMOUNT;
}

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

@ -277,16 +277,16 @@ public final class L2ItemInstance extends L2Object
* <BR>
* <li>Do Pickup Item : PCInstance and Pet</li><BR>
* <BR>
* @param player Player that pick up the item
* @param character Character that pick up the item
*/
public final void pickupMe(L2Character player)
public final void pickupMe(L2Character character)
{
assert getWorldRegion() != null;
final L2WorldRegion oldregion = getWorldRegion();
// Create a server->client GetItem packet to pick up the L2ItemInstance
player.broadcastPacket(new GetItem(this, player.getObjectId()));
character.broadcastPacket(new GetItem(this, character.getObjectId()));
synchronized (this)
{
@ -305,10 +305,10 @@ public final class L2ItemInstance extends L2Object
// Remove the L2ItemInstance from the world
L2World.getInstance().removeVisibleObject(this, oldregion);
if (player.isPlayer())
if (character.isPlayer())
{
// Notify to scripts
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(player.getActingPlayer(), this), getItem());
EventDispatcher.getInstance().notifyEventAsync(new OnPlayerItemPickup(character.getActingPlayer(), this), getItem());
}
}

View File

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

View File

@ -38,6 +38,7 @@ import com.l2jmobius.gameserver.enums.ItemSkillType;
import com.l2jmobius.gameserver.enums.NextActionType;
import com.l2jmobius.gameserver.enums.StatusUpdateType;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@ -159,7 +160,7 @@ public class SkillCaster implements Runnable
}
// You should not heal/buff monsters without pressing the ctrl button.
if (caster.isPlayer() && target.isMonster() && (skill.getEffectPoint() > 0) && !ctrlPressed)
if (caster.isPlayer() && (target.isMonster() && !target.isFakePlayer()) && (skill.getEffectPoint() > 0) && !ctrlPressed)
{
caster.sendPacket(SystemMessageId.INVALID_TARGET);
return null;
@ -609,6 +610,10 @@ public class SkillCaster implements Runnable
// Add hate to the attackable, and put it in the attack list.
((L2Attackable) obj).addDamageHate(caster, 0, -skill.getEffectPoint());
((L2Character) obj).addAttackerToAttackByList(caster);
if (obj.isFakePlayer())
{
player.updatePvPStatus();
}
}
// notify target AI about the attack
@ -617,10 +622,19 @@ public class SkillCaster implements Runnable
((L2Character) obj).getAI().notifyEvent(CtrlEvent.EVT_ATTACKED, caster);
}
}
else if (((skill.getEffectPoint() > 0) && obj.isMonster()) || (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) || (obj.getActingPlayer().getReputation() < 0))))
else if (((skill.getEffectPoint() > 0) && obj.isMonster()) //
|| (obj.isPlayable() && ((obj.getActingPlayer().getPvpFlag() > 0) //
|| (((L2Character) obj).getReputation() < 0) //
)))
{
// Supporting players or monsters result in pvpflag.
player.updatePvPStatus();
if (!obj.isFakePlayer() //
|| (obj.isFakePlayer() //
&& (!((L2Npc) obj).isScriptValue(0) //
|| (((L2Npc) obj).getReputation() < 0))))
{
player.updatePvPStatus();
}
}
}
@ -630,7 +644,7 @@ public class SkillCaster implements Runnable
EventDispatcher.getInstance().notifyEventAsync(new OnNpcSkillSee(npcMob, player, skill, caster.isSummon(), targets.toArray(new L2Object[0])), npcMob);
// On Skill See logic
if (npcMob.isAttackable())
if (npcMob.isAttackable() && !npcMob.isFakePlayer())
{
final L2Attackable attackable = (L2Attackable) npcMob;
@ -652,6 +666,19 @@ public class SkillCaster implements Runnable
}
});
}
else if (caster.isFakePlayer()) // fake player attacks player
{
if (target.isPlayable() || target.isFakePlayer())
{
final L2Npc npc = ((L2Npc) caster);
if (!npc.isScriptValue(1))
{
npc.setScriptValue(1); // in combat
npc.broadcastInfo(); // update flag status
QuestManager.getInstance().getQuest("PvpFlaggingStopTask").notifyEvent("FLAG_CHECK" + npc.getObjectId(), npc, null);
}
}
}
}
catch (Exception e)
{
@ -1022,7 +1049,6 @@ public class SkillCaster implements Runnable
return false;
}
}
return true;
}

View File

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

View File

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

View File

@ -22,6 +22,7 @@ import java.util.logging.Logger;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.InitialEquipmentData;
import com.l2jmobius.gameserver.data.xml.impl.InitialShortcutData;
import com.l2jmobius.gameserver.data.xml.impl.PlayerTemplateData;
@ -100,7 +101,7 @@ public final class CharacterCreate implements IClientIncomingPacket
return;
}
if (Config.FORBIDDEN_NAMES.length > 1)
if (Config.FORBIDDEN_NAMES.length > 0)
{
for (String st : Config.FORBIDDEN_NAMES)
{
@ -112,6 +113,12 @@ public final class CharacterCreate implements IClientIncomingPacket
}
}
if (FakePlayerData.getInstance().getProperName(_name) != null)
{
client.sendPacket(new CharCreateFail(CharCreateFail.REASON_INCORRECT_NAME));
return;
}
// Last Verified: May 30, 2009 - Gracia Final
if (!Util.isAlphaNumeric(_name) || !isValidName(_name))
{

View File

@ -18,10 +18,12 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
public final class RequestBlock implements IClientIncomingPacket
{
@ -62,6 +64,24 @@ public final class RequestBlock implements IClientIncomingPacket
case BLOCK:
case UNBLOCK:
{
// TODO: Save in database? :P
if (FakePlayerData.getInstance().isTalkable(_name))
{
if (_type == BLOCK)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_ADDED_TO_YOUR_IGNORE_LIST);
sm.addString(FakePlayerData.getInstance().getProperName(_name));
activeChar.sendPacket(sm);
}
else
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_HAS_BEEN_REMOVED_FROM_YOUR_IGNORE_LIST);
sm.addString(FakePlayerData.getInstance().getProperName(_name));
activeChar.sendPacket(sm);
}
return;
}
// can't use block/unblock for locating invisible characters
if (targetId <= 0)
{

View File

@ -19,6 +19,7 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.serverpackets.ExIsCharNameCreatable;
import com.l2jmobius.gameserver.util.Util;
@ -57,6 +58,10 @@ public class RequestCharacterNameCreatable implements IClientIncomingPacket
{
result = NAME_ALREADY_EXISTS;
}
else if (FakePlayerData.getInstance().getProperName(_name) != null)
{
result = NAME_ALREADY_EXISTS;
}
else if (_name.length() > 16)
{
result = INVALID_LENGTH;

View File

@ -18,9 +18,13 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Party;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.zone.ZoneId;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.ExDuelAskStart;
@ -43,15 +47,67 @@ public final class RequestDuelStart implements IClientIncomingPacket
return true;
}
private void scheduleDeny(L2PcInstance player, String name)
{
if (player != null)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DECLINED_YOUR_CHALLENGE_TO_A_DUEL);
sm.addString(name);
player.sendPacket(sm);
player.onTransactionResponse();
}
}
@Override
public void run(L2GameClient client)
{
final L2PcInstance activeChar = client.getActiveChar();
final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (activeChar == null)
{
return;
}
if (FakePlayerData.getInstance().isTalkable(_player))
{
final String name = FakePlayerData.getInstance().getProperName(_player);
if (activeChar.isInsideZone(ZoneId.PVP) || activeChar.isInsideZone(ZoneId.PEACE) || activeChar.isInsideZone(ZoneId.SIEGE))
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_CANNOT_MAKE_A_CHALLENGE_TO_A_DUEL_BECAUSE_C1_IS_CURRENTLY_IN_A_DUEL_PROHIBITED_AREA_PEACEFUL_ZONE_BATTLE_ZONE_NEAR_WATER_RESTART_PROHIBITED_AREA);
sm.addString(name);
activeChar.sendPacket(sm);
return;
}
boolean npcInRange = false;
for (L2Npc npc : L2World.getInstance().getVisibleObjects(activeChar, L2Npc.class, 250))
{
if (npc.getName().equals(name))
{
npcInRange = true;
}
}
if (!npcInRange)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_TOO_FAR_AWAY_TO_RECEIVE_A_DUEL_CHALLENGE);
sm.addString(name);
activeChar.sendPacket(sm);
return;
}
if (activeChar.isProcessingRequest())
{
final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
msg.addString(name);
activeChar.sendPacket(msg);
return;
}
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_CHALLENGED_TO_A_DUEL);
sm.addString(name);
activeChar.sendPacket(sm);
ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, name), 10000);
activeChar.blockRequest();
return;
}
final L2PcInstance targetChar = L2World.getInstance().getPlayer(_player);
if (targetChar == null)
{
activeChar.sendPacket(SystemMessageId.THERE_IS_NO_OPPONENT_TO_RECEIVE_YOUR_CHALLENGE_FOR_A_DUEL);

View File

@ -18,6 +18,8 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PartyDistributionType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Party;
@ -48,17 +50,49 @@ public final class RequestJoinParty implements IClientIncomingPacket
return true;
}
private void scheduleDeny(L2PcInstance player)
{
if (player != null)
{
if (player.getParty() == null)
{
player.sendPacket(SystemMessageId.THE_PARTY_HAS_DISPERSED);
}
else
{
player.sendPacket(SystemMessageId.THE_PLAYER_DECLINED_TO_JOIN_YOUR_PARTY);
}
player.onTransactionResponse();
}
}
@Override
public void run(L2GameClient client)
{
final L2PcInstance requestor = client.getActiveChar();
final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (requestor == null)
{
return;
}
if (FakePlayerData.getInstance().isTalkable(_name))
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BEEN_INVITED_TO_THE_PARTY);
sm.addString(FakePlayerData.getInstance().getProperName(_name));
requestor.sendPacket(sm);
if (!requestor.isProcessingRequest())
{
ThreadPoolManager.schedule(() -> scheduleDeny(requestor), 10000);
requestor.blockRequest();
}
else
{
requestor.sendPacket(SystemMessageId.WAITING_FOR_ANOTHER_REPLY);
}
return;
}
final L2PcInstance target = L2World.getInstance().getPlayer(_name);
if (target == null)
{
requestor.sendPacket(SystemMessageId.YOU_MUST_FIRST_SELECT_A_USER_TO_INVITE_TO_YOUR_PARTY);

View File

@ -17,12 +17,15 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
import com.l2jmobius.gameserver.network.SystemMessageId;
import com.l2jmobius.gameserver.network.serverpackets.AskJoinPledge;
import com.l2jmobius.gameserver.network.serverpackets.SystemMessage;
/**
* This class ...
@ -41,6 +44,17 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return true;
}
private void scheduleDeny(L2PcInstance player, String name)
{
if (player != null)
{
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_DID_NOT_RESPOND_INVITATION_TO_THE_CLAN_HAS_BEEN_CANCELLED);
sm.addString(name);
player.sendPacket(sm);
player.onTransactionResponse();
}
}
@Override
public void run(L2GameClient client)
{
@ -56,6 +70,29 @@ public final class RequestJoinPledge implements IClientIncomingPacket
return;
}
if ((activeChar.getTarget() != null) && (FakePlayerData.getInstance().isTalkable(activeChar.getTarget().getName())))
{
if (FakePlayerData.getInstance().getInfo(activeChar.getTarget().getId()).getClanId() > 0)
{
activeChar.sendPacket(SystemMessageId.THAT_PLAYER_ALREADY_BELONGS_TO_ANOTHER_CLAN);
}
else
{
if (!activeChar.isProcessingRequest())
{
ThreadPoolManager.schedule(() -> scheduleDeny(activeChar, activeChar.getTarget().getName()), 10000);
activeChar.blockRequest();
}
else
{
final SystemMessage msg = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
msg.addString(activeChar.getTarget().getName());
activeChar.sendPacket(msg);
}
}
return;
}
final L2PcInstance target = L2World.getInstance().getPlayer(_target);
if (target == null)
{

View File

@ -23,6 +23,7 @@ import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.sql.impl.CharNameTable;
import com.l2jmobius.gameserver.data.xml.impl.AdminData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.instancemanager.MailManager;
import com.l2jmobius.gameserver.model.BlockList;
@ -195,6 +196,14 @@ public final class RequestSendPost implements IClientIncomingPacket
}
}
if (FakePlayerData.getInstance().isTalkable(_receiver))
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_BLOCKED_YOU_YOU_CANNOT_SEND_MAIL_TO_C1);
sm.addString(FakePlayerData.getInstance().getProperName(_receiver));
activeChar.sendPacket(sm);
return;
}
final int receiverId = CharNameTable.getInstance().getIdByName(_receiver);
if (receiverId <= 0)
{

View File

@ -17,6 +17,7 @@
package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.L2GameClient;
@ -46,13 +47,29 @@ public final class RequestVoteNew implements IClientIncomingPacket
}
final L2Object object = activeChar.getTarget();
if (!(object instanceof L2PcInstance))
{
if (object == null)
{
client.sendPacket(SystemMessageId.SELECT_TARGET);
}
else if (object.isFakePlayer() && FakePlayerData.getInstance().isTalkable(object.getName()))
{
if (activeChar.getRecomLeft() <= 0)
{
client.sendPacket(SystemMessageId.YOU_ARE_OUT_OF_RECOMMENDATIONS_TRY_AGAIN_LATER);
return;
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_RECOMMENDED_C1_YOU_HAVE_S2_RECOMMENDATIONS_LEFT);
sm.addString(FakePlayerData.getInstance().getProperName(object.getName()));
sm.addInt(activeChar.getRecomLeft());
client.sendPacket(sm);
activeChar.setRecomLeft(activeChar.getRecomLeft() - 1);
client.sendPacket(new UserInfo(activeChar));
client.sendPacket(new ExVoteSystemInfo(activeChar));
}
else
{
client.sendPacket(SystemMessageId.THAT_IS_AN_INCORRECT_TARGET);

View File

@ -18,11 +18,14 @@ package com.l2jmobius.gameserver.network.clientpackets;
import com.l2jmobius.Config;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.datatables.BotReportTable;
import com.l2jmobius.gameserver.enums.PrivateStoreType;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.effects.AbstractEffect;
import com.l2jmobius.gameserver.model.skills.AbnormalType;
@ -47,6 +50,17 @@ public final class TradeRequest implements IClientIncomingPacket
return true;
}
private void scheduleDeny(L2PcInstance player, String name)
{
if (player != null)
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_HAS_DENIED_YOUR_REQUEST_TO_TRADE);
sm.addString(name);
player.sendPacket(sm);
player.onTransactionResponse();
}
}
@Override
public void run(L2GameClient client)
{
@ -94,6 +108,37 @@ public final class TradeRequest implements IClientIncomingPacket
return;
}
if (FakePlayerData.getInstance().isTalkable(target.getName()))
{
final String name = FakePlayerData.getInstance().getProperName(target.getName());
boolean npcInRange = false;
for (L2Npc npc : L2World.getInstance().getVisibleObjects(player, L2Npc.class, 150))
{
if (npc.getName().equals(name))
{
npcInRange = true;
}
}
if (!npcInRange)
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOUR_TARGET_IS_OUT_OF_RANGE));
return;
}
if (!player.isProcessingRequest())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_TRADE_WITH_C1);
sm.addString(name);
player.sendPacket(sm);
ThreadPoolManager.schedule(() -> scheduleDeny(player, name), 10000);
player.blockRequest();
}
else
{
player.sendPacket(SystemMessageId.YOU_ARE_ALREADY_TRADING_WITH_SOMEONE);
}
return;
}
if (!target.isPlayer())
{
client.sendPacket(SystemMessageId.INVALID_TARGET);

View File

@ -17,6 +17,8 @@
package com.l2jmobius.gameserver.network.clientpackets.friend;
import com.l2jmobius.commons.network.PacketReader;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.BlockList;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
@ -38,6 +40,15 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return true;
}
private void scheduleDeny(L2PcInstance player)
{
if (player != null)
{
player.sendPacket(SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_FAILED_TO_ADD_A_FRIEND_TO_YOUR_FRIENDS_LIST));
player.onTransactionResponse();
}
}
@Override
public void run(L2GameClient client)
{
@ -47,6 +58,25 @@ public final class RequestFriendInvite implements IClientIncomingPacket
return;
}
if (FakePlayerData.getInstance().isTalkable(_name))
{
if (!activeChar.isProcessingRequest())
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_VE_REQUESTED_C1_TO_BE_ON_YOUR_FRIENDS_LIST);
sm.addString(_name);
activeChar.sendPacket(sm);
ThreadPoolManager.schedule(() -> scheduleDeny(activeChar), 10000);
activeChar.blockRequest();
}
else
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_IS_ON_ANOTHER_TASK_PLEASE_TRY_AGAIN_LATER);
sm.addString(_name);
activeChar.sendPacket(sm);
}
return;
}
final L2PcInstance friend = L2World.getInstance().getPlayer(_name);
// Target is not found in the game.

View File

@ -22,6 +22,7 @@ import java.util.List;
import com.l2jmobius.commons.network.PacketWriter;
import com.l2jmobius.gameserver.enums.ChatType;
import com.l2jmobius.gameserver.instancemanager.MentorManager;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.network.NpcStringId;
import com.l2jmobius.gameserver.network.OutgoingPackets;
@ -53,21 +54,24 @@ public final class CreatureSay implements IClientOutgoingPacket
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
if (receiver.getFriendList().contains(sender.getObjectId()))
if (receiver != null)
{
_mask |= 0x01;
}
if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
{
_mask |= 0x02;
}
if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
{
_mask |= 0x04;
}
if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
{
_mask |= 0x08;
if (receiver.getFriendList().contains(sender.getObjectId()))
{
_mask |= 0x01;
}
if ((receiver.getClanId() > 0) && (receiver.getClanId() == sender.getClanId()))
{
_mask |= 0x02;
}
if ((MentorManager.getInstance().getMentee(receiver.getObjectId(), sender.getObjectId()) != null) || (MentorManager.getInstance().getMentee(sender.getObjectId(), receiver.getObjectId()) != null))
{
_mask |= 0x04;
}
if ((receiver.getAllyId() > 0) && (receiver.getAllyId() == sender.getAllyId()))
{
_mask |= 0x08;
}
}
// Does not shows level
@ -77,6 +81,23 @@ public final class CreatureSay implements IClientOutgoingPacket
}
}
/**
* Used by fake players.
* @param sender
* @param receiver
* @param name
* @param messageType
* @param text
*/
public CreatureSay(L2Npc sender, L2PcInstance receiver, String name, ChatType messageType, String text)
{
_objectId = sender.getObjectId();
_charName = name;
_charLevel = sender.getLevel();
_textType = messageType;
_text = text;
}
/**
* @param objectId
* @param messageType

View File

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

View File

@ -149,6 +149,11 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
addComponentType(NpcInfoType.TITLE_NPCSTRINGID);
}
if (_npc.getReputation() != 0)
{
addComponentType(NpcInfoType.REPUTATION);
}
if (!_abnormalVisualEffects.isEmpty() || npc.isInvisible())
{
addComponentType(NpcInfoType.ABNORMALS);
@ -402,7 +407,7 @@ public class NpcInfo extends AbstractMaskPacket<NpcInfoType>
}
if (containsMask(NpcInfoType.REPUTATION))
{
packet.writeD(0x00); // Name color
packet.writeD(_npc.getReputation()); // Reputation
}
if (containsMask(NpcInfoType.CLAN))
{

View File

@ -82,6 +82,7 @@ Customs:
-Classmaster
-Community board
-Faction system
-Fake players
-Find PvP
-NPC stat multipliers
-Realtime offline trade

View File

@ -392,6 +392,9 @@
<!-- ADMIN MESSAGES -->
<admin command="admin_msg" accessLevel="100" />
<!-- ADMIN FAKE PLAYERS -->
<admin command="admin_fakechat" accessLevel="100" />
<!-- ADMIN MOB GROUP -->
<admin command="admin_mobmenu" accessLevel="100" />
<admin command="admin_mobgroup_list" 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,37 @@
<?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 -->
<!--
####################################### Hero Weapons #####################################################
Bow(37874) Crossbow(37875) Dagger(37868) Dual Blunt Weapon(37881) Dual Dagger(37880) Dual Sword(37879)
Fist(37872) OneHand Blunt(37871) OneHand Magic Blunt(37877) One Hand Magic Sword(37876) One Hand Sword(37869)
Spear(37873) Two-handed Magic Blunt Weapon(37878) Two-handed Sword(37870) Shield(37870) Sigil(37223)
#############################################################################################################
-->
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="xsd/FakePlayerVisualData.xsd">
<!-- Non-Combat -->
<fakePlayer npcId="80000" classId="188" hair="1" hairColor="1" face="0" equipRHand="17294" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="40200" />
<!-- Combat -->
<!-- Sigel Phoenix Knight -->
<fakePlayer npcId="81001" classId="148" hair="0" hairColor="0" face="0" equipRHand="37869" equipLHand="37212" equipHead="37209" equipGloves="37210" equipChest="37207" equipLegs="37208" equipFeet="37211" equipCloak="30310" />
<!-- Tyrr Titan -->
<fakePlayer npcId="81002" classId="154" hair="0" hairColor="0" face="0" equipRHand="37870" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="30311" />
<!-- Othell Fortune Seeker -->
<fakePlayer npcId="81003" classId="161" hair="0" hairColor="0" face="0" equipRHand="37880" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="30312" />
<!-- Yul Trickster -->
<fakePlayer npcId="81004" classId="165" hair="0" hairColor="0" face="0" equipRHand="37875" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="30313" />
<!-- Feoh Archmage -->
<fakePlayer npcId="81005" classId="166" hair="0" hairColor="0" face="0" equipRHand="37878" equipHead="37220" equipGloves="37221" equipChest="37218" equipLegs="37219" equipFeet="37222" equipCloak="30314" />
<!-- Iss Spectral Dancer -->
<fakePlayer npcId="81006" classId="173" hair="0" hairColor="0" face="0" equipRHand="37879" equipHead="37209" equipGloves="37210" equipChest="37207" equipLegs="37208" equipFeet="37211" equipCloak="30316" />
<!-- Aeore Eva's Saint -->
<fakePlayer npcId="81007" classId="180" hair="0" hairColor="0" face="0" equipRHand="37876" equipLHand="37223" equipHead="37220" equipGloves="37221" equipChest="37218" equipLegs="37219" equipFeet="37222" equipCloak="30317" />
<!-- Eviscerator -->
<fakePlayer npcId="81008" classId="188" hair="0" hairColor="0" face="0" equipRHand="37872" equipHead="37215" equipGloves="37216" equipChest="37213" equipLegs="37214" equipFeet="37217" equipCloak="40200" />
<!-- Sayha's Seer -->
<fakePlayer npcId="81009" classId="189" hair="0" hairColor="0" face="0" equipRHand="37878" equipHead="37220" equipGloves="37221" equipChest="37218" equipLegs="37219" equipFeet="37222" equipCloak="40201" />
</list>

View File

@ -2402,4 +2402,43 @@
<point X="42630" Y="-48231" Z="-792" delay="0" run="true" />
<point X="45069" Y="-48034" Z="-792" delay="0" run="true" />
</route>
<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="83575" Y="147722" Z="-3405" delay="32" run="true" /> <!-- Buffer -->
<point X="82117" Y="147642" Z="-3469" delay="0" run="true" />
<point X="82152" Y="147580" Z="-3469" delay="36" run="true" /> <!-- Olympiad Statue-->
<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="83216" Y="146672" Z="-3465" delay="28" run="true" /> <!-- Warehouse -->
<point X="83211" Y="146724" Z="-3467" 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="80375" Y="145484" Z="-3535" delay="28" run="true" /> <!-- Pochi -->
<point X="80283" Y="145826" Z="-3533" delay="0" run="true" />
<point X="79952" Y="145840" Z="-3496" 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="81068" Y="145845" Z="-3533" delay="36" run="true" /> <!-- Pet Manager -->
<point X="81061" Y="145563" Z="-3533" delay="0" run="true" />
<point X="81563" Y="145532" Z="-3533" delay="3" run="true" />
<point X="81692" Y="147231" Z="-3533" delay="32" run="true" /> <!-- Kiki -->
<point X="81370" Y="147213" Z="-3533" delay="64" run="true" /> <!-- Plani -->
<point X="81517" Y="147231" Z="-3533" delay="1" run="true" />
<point X="81542" Y="147570" Z="-3469" delay="0" run="true" />
<point X="81109" Y="147770" Z="-3469" delay="99" run="true" /> <!-- Moe -->
<point X="81108" Y="149415" Z="-3469" delay="99" run="true" /> <!-- Auction House -->
<point X="81413" Y="149700" Z="-3469" delay="52" run="true" /> <!-- Clan Hall Managers -->
<point X="81718" Y="149626" Z="-3469" delay="60" run="true" /> <!-- Beauty Shop -->
<point X="82815" Y="148840" Z="-3469" delay="3" run="true" />
<point X="83307" Y="148431" Z="-3405" delay="21" run="true" /> <!-- Training Camp Manager -->
</route>
</routes>

View File

@ -88,7 +88,7 @@ public final class Wisp extends AbstractNpcAI
final L2Character creature = event.getSeen();
final L2Npc npc = (L2Npc) event.getSeer();
if (creature.isPlayer())
if (creature.isPlayer() || creature.isFakePlayer())
{
npc.setTarget(creature);
npc.doCast(npc.getId() == WISP ? WISP_HEAL.getSkill() : LARGE_WISP_HEAL.getSkill());

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

@ -0,0 +1,115 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package custom.FakePlayers;
import com.l2jmobius.Config;
import com.l2jmobius.commons.util.CommonUtil;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.base.ClassId;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
import ai.AbstractNpcAI;
/**
* Town Fake Player walkers that receive buffs from Adventurer NPC.
* @author Mobius
*/
public class RecieveAdventurerBuffs extends AbstractNpcAI
{
// NPCs
private static final int[] ADVENTURERS_GUIDE =
{
32327,
33950,
};
private static final int[] FAKE_PLAYER_IDS =
{
80000
};
// Skills
// private static final SkillHolder KNIGHT = new SkillHolder(15648, 1); // Knight's Harmony (Adventurer)
private static final SkillHolder WARRIOR = new SkillHolder(15649, 1); // Warrior's Harmony (Adventurer)
private static final SkillHolder WIZARD = new SkillHolder(15650, 1); // Wizard's Harmony (Adventurer)
private static final SkillHolder[] GROUP_BUFFS =
{
new SkillHolder(15642, 1), // Horn Melody (Adventurer)
new SkillHolder(15643, 1), // Drum Melody (Adventurer)
new SkillHolder(15644, 1), // Pipe Organ Melody (Adventurer)
new SkillHolder(15645, 1), // Guitar Melody (Adventurer)
new SkillHolder(15646, 1), // Harp Melody (Adventurer)
new SkillHolder(15647, 1), // Lute Melody (Adventurer)
new SkillHolder(15651, 1), // Prevailing Sonata (Adventurer)
new SkillHolder(15652, 1), // Daring Sonata (Adventurer)
new SkillHolder(15653, 1), // Refreshing Sonata (Adventurer)
};
private RecieveAdventurerBuffs()
{
if (Config.FAKE_PLAYERS_ENABLED)
{
addSpawnId(FAKE_PLAYER_IDS);
}
}
@Override
public String onAdvEvent(String event, L2Npc npc, L2PcInstance player)
{
if (event.startsWith("AUTOBUFF") && (npc != null) && !npc.isDead())
{
if (!npc.isMoving())
{
for (L2Npc nearby : L2World.getInstance().getVisibleObjects(npc, L2Npc.class, 100))
{
if (CommonUtil.contains(ADVENTURERS_GUIDE, nearby.getId()))
{
for (SkillHolder holder : GROUP_BUFFS)
{
SkillCaster.triggerCast(nearby, npc, holder.getSkill());
}
if (ClassId.getClassId(FakePlayerData.getInstance().getInfo(npc.getId()).getClassId()).isMage())
{
SkillCaster.triggerCast(nearby, npc, WIZARD.getSkill());
}
else
{
SkillCaster.triggerCast(nearby, npc, WARRIOR.getSkill());
}
break;
}
}
}
startQuestTimer("AUTOBUFF" + npc.getObjectId(), 30000, npc, null);
}
return super.onAdvEvent(event, npc, player);
}
@Override
public String onSpawn(L2Npc npc)
{
startQuestTimer("AUTOBUFF" + npc.getObjectId(), 1000, npc, null);
return super.onSpawn(npc);
}
public static void main(String[] args)
{
new RecieveAdventurerBuffs();
}
}

View File

@ -79,6 +79,7 @@ import handlers.admincommandhandlers.AdminEnchant;
import handlers.admincommandhandlers.AdminEventEngine;
import handlers.admincommandhandlers.AdminEvents;
import handlers.admincommandhandlers.AdminExpSp;
import handlers.admincommandhandlers.AdminFakePlayers;
import handlers.admincommandhandlers.AdminFightCalculator;
import handlers.admincommandhandlers.AdminFortSiege;
import handlers.admincommandhandlers.AdminGeodata;
@ -409,6 +410,7 @@ public class MasterHandler
AdminEventEngine.class,
AdminEvents.class,
AdminExpSp.class,
AdminFakePlayers.class,
AdminFightCalculator.class,
AdminFortSiege.class,
AdminGeodata.class,

View File

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

View File

@ -0,0 +1,77 @@
/*
* This file is part of the L2J Mobius project.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <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);
}
return true;
}
@Override
public String[] getAdminCommandList()
{
return ADMIN_COMMANDS;
}
}

View File

@ -32,6 +32,7 @@ import com.l2jmobius.gameserver.data.xml.impl.BuyListData;
import com.l2jmobius.gameserver.data.xml.impl.DoorData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemData;
import com.l2jmobius.gameserver.data.xml.impl.EnchantItemGroupsData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.ItemCrystalizationData;
import com.l2jmobius.gameserver.data.xml.impl.MultisellData;
@ -45,9 +46,12 @@ import com.l2jmobius.gameserver.data.xml.impl.TransformData;
import com.l2jmobius.gameserver.datatables.ItemTable;
import com.l2jmobius.gameserver.handler.IAdminCommandHandler;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.QuestManager;
import com.l2jmobius.gameserver.instancemanager.WalkingManager;
import com.l2jmobius.gameserver.instancemanager.ZoneManager;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.scripting.ScriptEngineManager;
import com.l2jmobius.gameserver.util.Util;
@ -301,6 +305,25 @@ public class AdminReload implements IAdminCommandHandler
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fishing data.");
break;
}
case "fakeplayers":
{
FakePlayerData.getInstance().load();
for (L2Object obj : L2World.getInstance().getVisibleObjects())
{
if (obj.isFakePlayer())
{
obj.broadcastInfo();
}
}
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player data.");
break;
}
case "fakeplayerchat":
{
FakePlayerChatManager.getInstance().load();
AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Fake Player Chat data.");
break;
}
default:
{
activeChar.sendMessage(RELOAD_USAGE);

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;
@ -59,6 +61,28 @@ public final class ChatWhisper implements IChatHandler
return;
}
if (Config.FAKE_PLAYERS_ENABLED && (FakePlayerData.getInstance().getProperName(target) != null))
{
if (FakePlayerData.getInstance().isTalkable(target))
{
if (Config.FAKE_PLAYER_CHAT)
{
final String name = FakePlayerData.getInstance().getProperName(target);
activeChar.sendPacket(new CreatureSay(activeChar, null, "->" + name, type, text));
FakePlayerChatManager.getInstance().manageChat(activeChar, name, text);
}
else
{
activeChar.sendPacket(SystemMessageId.THAT_PERSON_IS_IN_MESSAGE_REFUSAL_MODE);
}
}
else
{
activeChar.sendPacket(SystemMessageId.THAT_PLAYER_IS_NOT_ONLINE);
}
return;
}
final L2PcInstance receiver = L2World.getInstance().getPlayer(target);
if ((receiver != null) && !receiver.isSilenceMode(activeChar.getObjectId()))

View File

@ -40,5 +40,4 @@ public class PlayerLevelCondition implements ICondition
{
return creature.isPlayer() && (creature.getLevel() >= _minLevel) && (creature.getLevel() < _maxLevel);
}
}

View File

@ -16,9 +16,11 @@
*/
package handlers.playeractions;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.ai.CtrlEvent;
import com.l2jmobius.gameserver.ai.CtrlIntention;
import com.l2jmobius.gameserver.ai.NextAction;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.handler.IPlayerActionHandler;
import com.l2jmobius.gameserver.model.ActionDataHolder;
import com.l2jmobius.gameserver.model.L2Object;
@ -97,6 +99,15 @@ public final class SocialAction implements IPlayerActionHandler
return true;
}
private void scheduleDeny(L2PcInstance player)
{
if (player != null)
{
player.sendPacket(SystemMessageId.THE_COUPLE_ACTION_WAS_DENIED);
player.onTransactionResponse();
}
}
private void useCoupleSocial(L2PcInstance player, int id)
{
if (player == null)
@ -105,7 +116,26 @@ public final class SocialAction implements IPlayerActionHandler
}
final L2Object target = player.getTarget();
if ((target == null) || !target.isPlayer())
if ((target == null))
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;
}
if (FakePlayerData.getInstance().isTalkable(target.getName()))
{
final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_REQUESTED_A_COUPLE_ACTION_WITH_C1);
sm.addString(target.getName());
player.sendPacket(sm);
if (!player.isProcessingRequest())
{
ThreadPoolManager.schedule(() -> scheduleDeny(player), 10000);
player.blockRequest();
}
return;
}
if (!target.isPlayer())
{
player.sendPacket(SystemMessageId.INVALID_TARGET);
return;

View File

@ -216,11 +216,14 @@ public class Q10766_ANewCraft extends Quest
@Id(WINDY_HEALING_POTION_1)
public void onItemCreate(OnItemCreate event)
{
final L2PcInstance player = event.getActiveChar();
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
final L2PcInstance player = event.getActiveChar().getActingPlayer();
if (player != null)
{
qs.setCond(4, true);
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(3)) && (getQuestItemsCount(qs.getPlayer(), AIR_STONE) >= 1) && (getQuestItemsCount(qs.getPlayer(), WINDY_HEALING_POTION_1) >= 1))
{
qs.setCond(4, true);
}
}
}
}

View File

@ -141,11 +141,14 @@ public class Q10767_AWholeNewLevelOfAlchemy extends Quest
@Id(HIGH_GRADE_LOVE_POTION)
public void onItemCreate(OnItemCreate event)
{
final L2PcInstance player = event.getActiveChar();
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
final L2PcInstance player = event.getActiveChar().getActingPlayer();
if (player != null)
{
qs.setCond(2, true);
final QuestState qs = getQuestState(player, false);
if ((qs != null) && (qs.isCond(1)) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), SUPERIOR_WINDY_QUIK_HEALING_POTION) >= 1000) && (getQuestItemsCount(qs.getPlayer(), HIGH_GRADE_LOVE_POTION) >= 1000))
{
qs.setCond(2, true);
}
}
}
}

View File

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

View File

@ -0,0 +1,341 @@
<?xml version="1.0" encoding="UTF-8"?>
<list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../xsd/npcs.xsd">
<!-- Sigel Phoenix Knight -->
<npc id="81001" level="94" type="L2Monster" name="Siegfield" title="Sigel Phoenix Knight" >
<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" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="9" />
<height normal="23" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10009" level="6" />
<skill name="Skill02_ID" id="10010" level="6" />
<skill name="Skill03_ID" id="10011" level="4" />
<skill name="Skill04_ID" id="10012" level="4" />
</parameters>
<skill_list>
<skill id="10009" level="6" /> <!-- Last Judgment -->
<skill id="10010" level="6" /> <!-- Justice Punishment -->
<skill id="10011" level="4" /> <!-- Shield Impact -->
<skill id="10012" level="4" /> <!-- Shield Wave -->
</skill_list>
</npc>
<!-- Tyrr Titan -->
<npc id="81002" level="94" type="L2Monster" name="Tyrrion" title="Tyrr Titan" >
<race>ORC</race>
<sex>MALE</sex>
<stats str="88" int="37" dex="50" wit="38" con="87" men="41">
<vitals hp="19416" hpRegen="10.8" mp="3727" mpRegen="3.0" />
<attack physical="11025" magical="1247" random="30" critical="92" accuracy="168" attackSpeed="540" type="SWORD" range="40" distance="80" width="120" />
<defence physical="3429" magical="2046" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="70" />
<run ground="130" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7" />
<height normal="27" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10267" level="4" />
<skill name="Skill02_ID" id="1760" level="5" />
</parameters>
<skill_list>
<skill id="10267" level="4" /> <!-- Hurricane Rush -->
<skill id="1760" level="5" /> <!-- Armor Destruction -->
</skill_list>
</npc>
<!-- Othell Fortune Seeker -->
<npc id="81003" level="94" type="L2Monster" name="Othelo" title="Othell Fortune Seeker" >
<race>DWARF</race>
<sex>FEMALE</sex>
<stats str="87" int="39" dex="53" wit="37" con="85" men="40">
<vitals hp="17018" hpRegen="10.8" mp="3693" mpRegen="3.0" />
<attack physical="4807" magical="1281" random="30" critical="230" accuracy="165" attackSpeed="943" type="SWORD" range="40" distance="80" width="120" />
<defence physical="2889" magical="2035" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="80" />
<run ground="131" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="5" />
<height normal="19" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10508" level="6" />
<skill name="Skill02_ID" id="10509" level="6" />
<skill name="Skill03_ID" id="10510" level="5" />
</parameters>
<skill_list>
<skill id="10508" level="6" /> <!-- Blood Stab -->
<skill id="10509" level="6" /> <!-- Heart Breaker -->
<skill id="10510" level="5" /> <!-- Chain Blow -->
</skill_list>
</npc>
<!-- Yul Trickster -->
<npc id="81004" level="94" type="L2Monster" name="Yully" title="Yul Trickster" >
<race>KAMAEL</race>
<sex>FEMALE</sex>
<stats str="88" int="43" dex="57" wit="36" con="80" men="37">
<vitals hp="15285" hpRegen="10.8" mp="4596" mpRegen="3.0" />
<attack physical="9754" magical="1375" random="30" critical="185" accuracy="167" attackSpeed="483" reuseDelay="1500" type="BOW" range="500" distance="80" width="120" />
<defence physical="2885" magical="2318" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="87" />
<run ground="140" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="ARCHER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7" />
<height normal="22.6" />
</collision>
<parameters>
<skill name="Skill01_ID" id="10760" level="6" />
<skill name="Skill02_ID" id="10762" level="5" />
<skill name="Skill03_ID" id="10763" level="6" />
</parameters>
<skill_list>
<skill id="10760" level="6" /> <!-- Tornado Shot -->
<skill id="10762" level="5" /> <!-- Quick Shot -->
<skill id="10763" level="6" /> <!-- Pin Point -->
</skill_list>
</npc>
<!-- Feoh Archmage -->
<npc id="81005" level="94" type="L2Monster" name="Feoth" title="Feoh Archmage" >
<race>HUMAN</race>
<sex>FEMALE</sex>
<stats str="38" int="79" dex="27" wit="78" con="41" men="78">
<vitals hp="14435" hpRegen="10.8" mp="9103" mpRegen="3.0" />
<attack physical="1257" magical="10320" random="30" critical="61" accuracy="158" attackSpeed="336" type="BLUNT" range="40" distance="500" width="120" />
<defence physical="3132" magical="2635" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="78" />
<run ground="124" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="MAGE" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="8" />
<height normal="23.5" />
</collision>
<parameters>
<skill name="Skill01_ID" id="11011" level="6" />
<skill name="Skill02_ID" id="11017" level="6" />
<skill name="Skill03_ID" id="11024" level="5" />
<skill name="Skill04_ID" id="11047" level="4" />
</parameters>
<skill_list>
<skill id="11011" level="6" /> <!-- Elemental Spike -->
<skill id="11017" level="6" /> <!-- Elemental Crash -->
<skill id="11024" level="5" /> <!-- Volcanic Destruction -->
<skill id="11047" level="4" /> <!-- Ruin -->
</skill_list>
</npc>
<!-- Iss Spectral Dancer -->
<npc id="81006" level="94" type="L2Monster" name="Isda" title="Iss Spectral Dancer" >
<race>DARK_ELF</race>
<sex>FEMALE</sex>
<stats str="92" int="42" dex="56" wit="39" con="77" men="35">
<vitals hp="15499" hpRegen="10.8" mp="4038" mpRegen="3.0" />
<attack physical="8777" magical="1451" random="30" critical="95" accuracy="162" attackSpeed="582" type="SWORD" range="40" distance="80" width="120" />
<defence physical="3429" magical="2026" />
<attribute>
<defence fire="250" 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" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="BALANCED" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7" />
<height normal="23.5" />
</collision>
<parameters>
<skill name="Skill01_ID" id="11508" level="4" />
<skill name="Skill02_ID" id="11509" level="6" />
<skill name="Skill02_ID" id="11510" level="5" />
</parameters>
<skill_list>
<skill id="11508" level="4" /> <!-- Assault Rush -->
<skill id="11509" level="6" /> <!-- Crippling Attack -->
<skill id="11510" level="5" /> <!-- Shadow Blade -->
</skill_list>
</npc>
<!-- Aeore Eva's Saint -->
<npc id="81007" level="94" type="L2Monster" name="Aorta" title="Aeore Eva's Saint" >
<race>ELF</race>
<sex>FEMALE</sex>
<stats str="36" int="74" dex="32" wit="84" con="38" men="77">
<vitals hp="13651" hpRegen="10.8" mp="11193" mpRegen="3.0" />
<attack physical="1008" magical="7469" random="30" critical="63" accuracy="161" attackSpeed="400" type="SWORD" range="40" distance="80" width="120" />
<defence physical="2406" magical="2627" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="85" />
<run ground="129" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="HEALER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="7.5" />
<height normal="23" />
</collision>
<parameters>
<skill name="Skill01_ID" id="11766" level="6" />
<skill name="Skill02_ID" id="11814" level="6" />
</parameters>
<skill_list>
<skill id="11766" level="6" /> <!-- Dark Blast -->
<skill id="11814" level="6" /> <!-- Dark Force -->
</skill_list>
</npc>
<!-- Eviscerator -->
<npc id="81008" level="94" type="L2Monster" name="Breezer" title="Eviscerator" >
<race>ERTHEIA</race>
<sex>FEMALE</sex>
<stats str="89" int="40" dex="52" 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="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="88" />
<run ground="141" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="FIGHTER" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="6.5" />
<height normal="19.2" />
</collision>
<parameters>
<skill name="Skill01_ID" id="30500" level="18" />
<skill name="Skill02_ID" id="30504" level="6" />
</parameters>
<skill_list>
<skill id="30500" level="18" /> <!-- Lateral Hit -->
<skill id="30504" level="6" /> <!-- Gravity Hit -->
</skill_list>
</npc>
<!-- Sayha's Seer -->
<npc id="81009" level="94" type="L2Monster" name="Hoppy" title="Sayha's Seer" >
<race>ERTHEIA</race>
<sex>FEMALE</sex>
<stats str="37" int="79" dex="27" wit="76" con="42" men="80">
<vitals hp="18857" hpRegen="10.8" mp="3863" mpRegen="3.0" />
<attack physical="1242" magical="4784" random="30" critical="61" accuracy="177" attackSpeed="162" type="BLUNT" range="40" distance="80" width="120" />
<defence physical="3388" magical="2450" />
<attribute>
<defence fire="250" water="250" wind="250" earth="250" holy="250" dark="250" />
<attack type="WATER" value="330" />
</attribute>
<speed>
<walk ground="88" />
<run ground="141" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" attackable="true" />
<ai type="BALANCED" clanHelpRange="1000" aggroRange="1000" isAggressive="true" > <!-- FIGHTER, ARCHER, BALANCED, MAGE, HEALER -->
<clan_list>
<clan>FAKE_PLAYER</clan>
</clan_list>
</ai>
<collision>
<radius normal="6.5" />
<height normal="19.2" />
</collision>
<parameters>
<skill name="Skill01_ID" id="30001" level="22" /> <!-- Hydro Attack -->
<skill name="Skill02_ID" id="30019" level="5" /> <!-- Sayha's Word -->
</parameters>
<skill_list>
<skill id="30001" level="22" /> <!-- Hydro Attack -->
<skill id="30019" level="5" /> <!-- Sayha's Word -->
</skill_list>
</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">
<!-- Eviscerator -->
<npc id="80000" level="94" type="L2Npc" name="Evi" >
<race>ERTHEIA</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="88" />
<run ground="141" />
</speed>
</stats>
<status fakePlayer="true" talkable="false" randomAnimation="false" randomWalk="false" undying="true" attackable="false" />
<collision>
<radius normal="6.5" />
<height normal="19.2" />
</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

@ -201,6 +201,8 @@
<xs:attribute name="hasSummoner" type="xs:boolean" />
<xs:attribute name="canBeSown" type="xs:boolean" />
<xs:attribute name="isDeathPenalty" type="xs:boolean" />
<xs:attribute name="fakePlayer" type="xs:boolean" />
<xs:attribute name="fakePlayerTalkable" type="xs:boolean" />
</xs:complexType>
</xs:element>
<xs:element name="skill_list" minOccurs="0" maxOccurs="1">

View File

@ -116,6 +116,7 @@ public final class Config
public static final String CUSTOM_DEBUG_VOICE_COMMAND_CONFIG_FILE = "./config/Custom/DebugVoiceCommand.ini";
public static final String CUSTOM_DUALBOX_CHECK_CONFIG_FILE = "./config/Custom/DualboxCheck.ini";
public static final String CUSTOM_FACTION_SYSTEM_CONFIG_FILE = "./config/Custom/FactionSystem.ini";
public static final String CUSTOM_FAKE_PLAYERS_CONFIG_FILE = "./config/Custom/FakePlayers.ini";
public static final String CUSTOM_FIND_PVP_CONFIG_FILE = "./config/Custom/FindPvP.ini";
public static final String CUSTOM_MULTILANGUAL_SUPPORT_CONFIG_FILE = "./config/Custom/MultilingualSupport.ini";
public static final String CUSTOM_NPC_STAT_MULTIPIERS_CONFIG_FILE = "./config/Custom/NpcStatMultipliers.ini";
@ -1147,6 +1148,16 @@ public final class Config
public static boolean FACTION_SPECIFIC_CHAT;
public static boolean FACTION_BALANCE_ONLINE_PLAYERS;
public static int FACTION_BALANCE_PLAYER_EXCEED_LIMIT;
public static boolean FAKE_PLAYERS_ENABLED;
public static boolean FAKE_PLAYER_CHAT;
public static boolean FAKE_PLAYER_USE_SHOTS;
public static boolean FAKE_PLAYER_KILL_PVP;
public static boolean FAKE_PLAYER_KILL_KARMA;
public static boolean FAKE_PLAYER_AGGRO_MONSTERS;
public static boolean FAKE_PLAYER_AGGRO_PLAYERS;
public static boolean FAKE_PLAYER_AGGRO_FPC;
public static boolean FAKE_PLAYER_CAN_DROP_ITEMS;
public static boolean FAKE_PLAYER_CAN_PICKUP;
public static boolean ENABLE_FIND_PVP;
public static boolean PREMIUM_SYSTEM_ENABLED;
public static float PREMIUM_RATE_XP;
@ -2560,6 +2571,19 @@ public final class Config
FACTION_BALANCE_ONLINE_PLAYERS = FactionSystem.getBoolean("BalanceOnlinePlayers", true);
FACTION_BALANCE_PLAYER_EXCEED_LIMIT = FactionSystem.getInt("BalancePlayerExceedLimit", 20);
// Load FakePlayers config file (if exists)
final PropertiesParser FakePlayers = new PropertiesParser(CUSTOM_FAKE_PLAYERS_CONFIG_FILE);
FAKE_PLAYERS_ENABLED = Boolean.valueOf(FakePlayers.getBoolean("EnableFakePlayers", false));
FAKE_PLAYER_CHAT = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerChat", false));
FAKE_PLAYER_USE_SHOTS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUseShots", false));
FAKE_PLAYER_KILL_PVP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerKillsRewardPvP", false));
FAKE_PLAYER_KILL_KARMA = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerUnflaggedKillsKarma", false));
FAKE_PLAYER_AGGRO_MONSTERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroMonsters", false));
FAKE_PLAYER_AGGRO_PLAYERS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroPlayers", false));
FAKE_PLAYER_AGGRO_FPC = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerAggroFPC", false));
FAKE_PLAYER_CAN_DROP_ITEMS = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanDropItems", false));
FAKE_PLAYER_CAN_PICKUP = Boolean.valueOf(FakePlayers.getBoolean("FakePlayerCanPickup", false));
// Load FindPvP config file (if exists)
final PropertiesParser FindPvP = new PropertiesParser(CUSTOM_FIND_PVP_CONFIG_FILE);
ENABLE_FIND_PVP = FindPvP.getBoolean("EnableFindPvP", false);

View File

@ -62,6 +62,7 @@ import com.l2jmobius.gameserver.data.xml.impl.EnsoulData;
import com.l2jmobius.gameserver.data.xml.impl.EventEngineData;
import com.l2jmobius.gameserver.data.xml.impl.ExperienceData;
import com.l2jmobius.gameserver.data.xml.impl.ExtendDropData;
import com.l2jmobius.gameserver.data.xml.impl.FakePlayerData;
import com.l2jmobius.gameserver.data.xml.impl.FishingData;
import com.l2jmobius.gameserver.data.xml.impl.HennaData;
import com.l2jmobius.gameserver.data.xml.impl.HitConditionBonusData;
@ -112,6 +113,7 @@ import com.l2jmobius.gameserver.instancemanager.CommissionManager;
import com.l2jmobius.gameserver.instancemanager.CursedWeaponsManager;
import com.l2jmobius.gameserver.instancemanager.DBSpawnManager;
import com.l2jmobius.gameserver.instancemanager.FactionManager;
import com.l2jmobius.gameserver.instancemanager.FakePlayerChatManager;
import com.l2jmobius.gameserver.instancemanager.FortManager;
import com.l2jmobius.gameserver.instancemanager.FortSiegeManager;
import com.l2jmobius.gameserver.instancemanager.GlobalVariablesManager;
@ -288,6 +290,8 @@ public class GameServer
printSection("NPCs");
SkillLearnData.getInstance();
NpcData.getInstance();
FakePlayerData.getInstance();
FakePlayerChatManager.getInstance();
ExtendDropData.getInstance();
SpawnsData.getInstance();
WalkingManager.getInstance();

View File

@ -34,6 +34,7 @@ import com.l2jmobius.gameserver.GameTimeController;
import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.enums.AISkillScope;
import com.l2jmobius.gameserver.geoengine.GeoEngine;
import com.l2jmobius.gameserver.instancemanager.ItemsOnGroundManager;
import com.l2jmobius.gameserver.model.AggroInfo;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.L2World;
@ -53,6 +54,7 @@ import com.l2jmobius.gameserver.model.events.EventDispatcher;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableFactionCall;
import com.l2jmobius.gameserver.model.events.impl.character.npc.OnAttackableHate;
import com.l2jmobius.gameserver.model.events.returns.TerminateReturn;
import com.l2jmobius.gameserver.model.holders.SkillHolder;
import com.l2jmobius.gameserver.model.items.instance.L2ItemInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.skills.SkillCaster;
@ -356,7 +358,73 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// A L2Attackable isn't aggressive during 10s after its spawn because _globalAggro is set to -10
if (_globalAggro >= 0)
{
if (npc.isAggressive() || (npc instanceof L2GuardInstance))
if (npc.isFakePlayer() && npc.isAggressive())
{
final List<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().getAllSkills())
{
SkillCaster.triggerCast(npc, null, skillHolder.getSkill(), null, false);
}
npc.broadcastInfo(); // ? check if this is necessary
}
}
}
else
{
npc.getFakePlayerDrops().remove(itemIndex);
}
npc.setRunning();
}
}
else if (npc.isAggressive() || (npc instanceof L2GuardInstance))
{
final int range = npc instanceof L2GuardInstance ? 500 : npc.getAggroRange(); // TODO Make sure how guards behave towards players.
L2World.getInstance().forEachVisibleObjectInRange(npc, L2Character.class, range, t ->
@ -364,7 +432,18 @@ public class L2AttackableAI extends L2CharacterAI implements Runnable
// For each L2Character check if the target is autoattackable
if (isAggressiveTowards(t)) // check aggression
{
if (t.isPlayable())
if (t.isFakePlayer())
{
if (!npc.isFakePlayer() || (npc.isFakePlayer() && Config.FAKE_PLAYER_AGGRO_FPC))
{
final int hating = npc.getHating(t);
if (hating == 0)
{
npc.addDamageHate(t, 0, 1);
}
}
}
else if (t.isPlayable())
{
final TerminateReturn term = EventDispatcher.getInstance().notifyEvent(new OnAttackableHate(getActiveChar(), t.getActingPlayer(), t.isSummon()), getActiveChar(), TerminateReturn.class);
if ((term != null) && term.terminate())

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

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

View File

@ -250,6 +250,11 @@ public class SpawnsData implements IGameXmlReader
return;
}
if (!Config.FAKE_PLAYERS_ENABLED && template.isFakePlayer())
{
return;
}
for (Node d = n.getFirstChild(); d != null; d = d.getNextSibling())
{
if ("parameters".equalsIgnoreCase(d.getNodeName()))

View File

@ -41,6 +41,8 @@ import com.l2jmobius.gameserver.ThreadPoolManager;
import com.l2jmobius.gameserver.data.xml.impl.SkillData;
import com.l2jmobius.gameserver.model.L2Clan;
import com.l2jmobius.gameserver.model.L2Object;
import com.l2jmobius.gameserver.model.actor.L2Character;
import com.l2jmobius.gameserver.model.actor.L2Npc;
import com.l2jmobius.gameserver.model.actor.instance.L2PcInstance;
import com.l2jmobius.gameserver.model.skills.Skill;
import com.l2jmobius.gameserver.model.zone.ZoneId;
@ -210,15 +212,14 @@ public final class BotReportTable
public boolean reportBot(L2PcInstance reporter)
{
final L2Object target = reporter.getTarget();
if (target == null)
{
return false;
}
final L2PcInstance bot = target.getActingPlayer();
final L2Character bot = ((L2Character) target);
if ((bot == null) || (target.getObjectId() == reporter.getObjectId()))
if ((!bot.isPlayer() && !bot.isFakePlayer()) || (bot.isFakePlayer() && !((L2Npc) bot).getTemplate().isFakePlayerTalkable()) || (target.getObjectId() == reporter.getObjectId()))
{
return false;
}
@ -229,7 +230,7 @@ public final class BotReportTable
return false;
}
if (bot.isInOlympiadMode())
if (bot.isPlayer() && bot.getActingPlayer().isInOlympiadMode())
{
reporter.sendPacket(SystemMessageId.THIS_CHARACTER_CANNOT_MAKE_A_REPORT_YOU_CANNOT_MAKE_A_REPORT_WHILE_LOCATED_INSIDE_A_PEACE_ZONE_OR_A_BATTLEGROUND_WHILE_YOU_ARE_AN_OPPOSING_CLAN_MEMBER_DURING_A_CLAN_WAR_OR_WHILE_PARTICIPATING_IN_THE_OLYMPIAD);
return false;
@ -241,7 +242,7 @@ public final class BotReportTable
return false;
}
if (bot.getExp() == bot.getStat().getStartingExp())
if (bot.isPlayer() && (bot.getActingPlayer().getExp() == bot.getActingPlayer().getStat().getStartingExp()))
{
reporter.sendPacket(SystemMessageId.YOU_CANNOT_REPORT_A_CHARACTER_WHO_HAS_NOT_ACQUIRED_ANY_XP_AFTER_CONNECTING);
return false;
@ -320,15 +321,18 @@ public final class BotReportTable
}
SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.C1_WAS_REPORTED_AS_A_BOT);
sm.addCharName(bot);
sm.addString(bot.getName());
reporter.sendPacket(sm);
sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_HAVE_USED_A_REPORT_POINT_ON_C1_YOU_HAVE_S2_POINTS_REMAINING_ON_THIS_ACCOUNT);
sm.addCharName(bot);
sm.addString(bot.getName());
sm.addInt(rcdRep.getPointsLeft());
reporter.sendPacket(sm);
handleReport(bot, rcd);
if (bot.isPlayer())
{
handleReport(bot.getActingPlayer(), rcd);
}
return true;
}

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;
@ -202,11 +203,11 @@ public class ItemTable
* @param process : String Identifier of process triggering this action
* @param itemId : int Item Identifier of the item to be created
* @param count : int Quantity of items to be created for stackable items
* @param actor : L2PcInstance Player requesting the item creation
* @param actor : L2Character requesting the item creation
* @param reference : Object Object referencing current action like NPC selling item or previous item in transformation
* @return L2ItemInstance corresponding to the new item
*/
public L2ItemInstance createItem(String process, int itemId, long count, L2PcInstance actor, Object reference)
public L2ItemInstance createItem(String process, int itemId, long count, L2Character actor, Object reference)
{
// Create and Init the L2ItemInstance corresponding to the Item Identifier
final L2ItemInstance item = new L2ItemInstance(IdFactory.getInstance().getNextId(), itemId);

Some files were not shown because too many files have changed in this diff Show More