· last year · Oct 30, 2023, 04:45 PM
1### Eclipse Workspace Patch 1.0
2#P L2J_Mobius_C6_Interlude
3diff --git dist/db_installer/sql/game/character_autofarm.sql dist/db_installer/sql/game/character_autofarm.sql
4new file mode 100644
5index 0000000..35128de
6--- /dev/null
7+++ dist/db_installer/sql/game/character_autofarm.sql
8@@ -0,0 +1,37 @@
9+/*
10+Navicat MySQL Data Transfer
11+
12+Source Server : localhost
13+Source Server Version : 50740
14+Source Host : localhost:3306
15+Source Database : 1faris
16+
17+Target Server Type : MYSQL
18+Target Server Version : 50740
19+File Encoding : 65001
20+
21+Date: 2023-10-15 07:01:50
22+*/
23+
24+SET FOREIGN_KEY_CHECKS=0;
25+
26+-- ----------------------------
27+-- Table structure for character_autofarm
28+-- ----------------------------
29+DROP TABLE IF EXISTS `character_autofarm`;
30+CREATE TABLE `character_autofarm` (
31+ `char_id` int(10) unsigned NOT NULL,
32+ `char_name` varchar(35) COLLATE utf8_unicode_ci NOT NULL,
33+ `auto_farm` tinyint(1) unsigned NOT NULL DEFAULT '0',
34+ `radius` int(10) unsigned NOT NULL DEFAULT '1200',
35+ `short_cut` int(10) unsigned NOT NULL DEFAULT '9',
36+ `heal_percent` int(10) unsigned NOT NULL DEFAULT '30',
37+ `buff_protection` tinyint(1) unsigned NOT NULL DEFAULT '0',
38+ `anti_ks_protection` tinyint(1) unsigned NOT NULL DEFAULT '0',
39+ `summon_attack` tinyint(1) unsigned NOT NULL DEFAULT '0',
40+ `summon_skill_percent` int(10) unsigned NOT NULL DEFAULT '0',
41+ `hp_potion_percent` int(10) unsigned NOT NULL DEFAULT '60',
42+ `mp_potion_percent` int(10) unsigned NOT NULL DEFAULT '60',
43+ PRIMARY KEY (`char_id`),
44+ KEY `char_name` (`char_name`)
45+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
46diff --git dist/game/data/html/mods/menu/AutoFarm.htm dist/game/data/html/mods/menu/AutoFarm.htm
47new file mode 100644
48index 0000000..19711f7
49--- /dev/null
50+++ dist/game/data/html/mods/menu/AutoFarm.htm
51@@ -0,0 +1,126 @@
52+<html><title>Auto Hunting</title>
53+
54+<table width=280>
55+<tr>
56+<td width=5></td>
57+<td width=20 align="center"><img src="L2UI_CH3.herotower_deco" width=256 height=32></td>
58+</tr>
59+</table>
60+
61+<table width=265>
62+<tr>
63+<td width=120 align="right"><font color="LEVEL">Auto Farm State:</font> %autofarm%</td>
64+<td width=20 align="left"><button width=75 height=19 back="buttons_bs.bs_64x27_1" fore="buttons_bs.bs_64x27_2" action="bypass voiced_enableAutoFarm" value="%button%"></td>
65+</tr>
66+</table>
67+
68+<br1>
69+
70+<table width=265>
71+<tr>
72+<td width=5></td>
73+<td width=100 valign="top" align="center"><font color="e6dcbe">Target Range:</font> </td>
74+<td width=20 align=center><button action="bypass voiced_radiusAutoFarm dec_radius" width=16 height=16 back=L2UI_CH3.prev1_down fore=L2UI_CH3.prev1></td>
75+<td width=40 align=center><font color=CC9933>%radius%</font></td>
76+<td width=20 align=center><button action="bypass voiced_radiusAutoFarm inc_radius" width=16 height=16 back=L2UI_CH3.next1_down fore=L2UI_CH3.next1></td>
77+</tr>
78+<tr>
79+<td width=5></td>
80+<td width=100 valign="top" align="center"><font color="e6dcbe">Heal Percent: </font></td>
81+<td width=20 align=center><button action="bypass voiced_healAutoFarm dec_heal" width=16 height=16 back=L2UI_CH3.prev1_down fore=L2UI_CH3.prev1></td>
82+<td width=40 align=center><font color=CC9933>%heal%</font></td>
83+<td width=20 align=center><button action="bypass voiced_healAutoFarm inc_heal" width=16 height=16 back=L2UI_CH3.next1_down fore=L2UI_CH3.next1></td>
84+</tr>
85+<tr>
86+<td width=5></td>
87+<td width=100 valign="top" align="center"><font color="e6dcbe">Shortcut Page: </font></td>
88+<td width=20 align=center><button action="bypass voiced_pageAutoFarm dec_page" width=16 height=16 back=L2UI_CH3.prev1_down fore=L2UI_CH3.prev1></td>
89+<td width=40 align=center><font color=CC9933>%page%</font></td>
90+<td width=20 align=center><button action="bypass voiced_pageAutoFarm inc_page" width=16 height=16 back=L2UI_CH3.next1_down fore=L2UI_CH3.next1></td>
91+</tr>
92+<tr>
93+<td width=5></td>
94+<td width=100 valign="top" align="center"><font color="e6dcbe">Mana Potion Percent: </font></td>
95+<td width=20 align=center><button action="bypass voiced_mpAutoFarm dec_mp_pot" width=16 height=16 back=L2UI_CH3.prev1_down fore=L2UI_CH3.prev1></td>
96+<td width=40 align=center><font color=CC9933>%mpPotion%</font></td>
97+<td width=20 align=center><button action="bypass voiced_mpAutoFarm inc_mp_pot" width=16 height=16 back=L2UI_CH3.next1_down fore=L2UI_CH3.next1></td>
98+</tr>
99+<tr>
100+<td width=5></td>
101+<td width=100 valign="top" align="center"><font color="e6dcbe">Healing Potion Percent: </font></td>
102+<td width=20 align=center><button action="bypass voiced_hpAutoFarm dec_hp_pot" width=16 height=16 back=L2UI_CH3.prev1_down fore=L2UI_CH3.prev1></td>
103+<td width=40 align=center><font color=CC9933>%hpPotion%</font></td>
104+<td width=20 align=center><button action="bypass voiced_hpAutoFarm inc_hp_pot" width=16 height=16 back=L2UI_CH3.next1_down fore=L2UI_CH3.next1></td>
105+</tr>
106+<tr>
107+<td width=5></td>
108+<td width=100 valign="top" align="center"><font color="e6dcbe">Summon Skill Chance: </font></td>
109+<td width=20 align=center><button action="bypass voiced_summonSkillAutoFarm dec_summonSkill" width=16 height=16 back=L2UI_CH3.prev1_down fore=L2UI_CH3.prev1></td>
110+<td width=40 align=center><font color=CC9933>%summonSkill%</font></td>
111+<td width=20 align=center><button action="bypass voiced_summonSkillAutoFarm inc_summonSkill" width=16 height=16 back=L2UI_CH3.next1_down fore=L2UI_CH3.next1></td>
112+</tr>
113+</table>
114+
115+<table width=300>
116+<tr>
117+<td width=20 align=left><font color="e6dcbe">Enable Summon attack support</font></td>
118+<td width=30></td>
119+<td width=5 align=left><button action="bypass voiced_enableSummonAttack" %summonAtk% width="16" height="16"></td>
120+</tr>
121+<tr>
122+<td width=50 align=left><font color="e6dcbe">Manner Mode, Anti-KS protection</font></td>
123+<td width=20></td>
124+<td width=10 align=left><button action="bypass voiced_enableAntiKs" %antiKs% width="16" height="16"></td>
125+</tr>
126+<tr>
127+<td width=50 align=left><font color="e6dcbe">Disable Auto Farm after losing all buffs</font></td>
128+<td width=20></td>
129+<td width=10 align=left><button action="bypass voiced_enableBuffProtect" %noBuff% width="16" height="16"></td>
130+</tr>
131+</table>
132+
133+<br1>
134+<center>
135+<table>
136+<tr>
137+ <td width=250><font color="LEVEL">Avoid specific monsters adding them to the blacklist</font></td>
138+</tr>
139+</table>
140+
141+<table>
142+<tr>
143+ <td><button value="Blacklist Target" action="bypass voiced_ignoreMonster" width=90 height=14 back="buttons_bs.bs_64x15_1" fore="buttons_bs.bs_64x15_2"></td>
144+ <td><button value="Unblacklist Target" action="bypass voiced_activeMonster" width=90 height=14 back="buttons_bs.bs_64x15_1" fore="buttons_bs.bs_64x15_2"></td>
145+</tr>
146+</table>
147+</center>
148+
149+<img src="L2UI.SquareGray" width=310 height=1>
150+<table bgcolor="000000" width=330>
151+<tr>
152+<td></td>
153+<td><font color="LEVEL">Rules:</font></td>
154+<td height=20><font color="e6dcbe">-</font> <font color="F42B00">'Attack'</font> <font color="e6dcbe">Shortcuts: </font><font color="F42B00">F1, F2, F3 & F4</font></td>
155+</tr>
156+<tr>
157+<td></td>
158+<td></td>
159+<td height=20><font color="e6dcbe">-</font> <font color="70F011">'Chance'</font> <font color="e6dcbe">Shortcuts: </font><font color="70F011">F5, F6, F7 & F8</font></td>
160+</tr>
161+<tr>
162+<td></td>
163+<td></td>
164+<td height=20><font color="e6dcbe">-</font> <font color="09E1FA">'Low Life'</font> <font color="e6dcbe">Shortcuts: </font><font color="09E1FA">F9, F10, F11 & F12</font></td>
165+</tr>
166+</table>
167+<img src="L2UI.SquareGray" width=310 height=1>
168+<br1>
169+
170+<table width=350>
171+<tr>
172+<td width=5></td>
173+<td width=20 align="center"><a action="bypass voiced_menu">Back</a></td>
174+</tr>
175+</table>
176+
177+</body></html>
178\ No newline at end of file
179diff --git java/Base/AutoFarm/AutofarmConstants.java java/Base/AutoFarm/AutofarmConstants.java
180new file mode 100644
181index 0000000..70e4aef
182--- /dev/null
183+++ java/Base/AutoFarm/AutofarmConstants.java
184@@ -0,0 +1,11 @@
185+package Base.AutoFarm;
186+
187+import java.util.Arrays;
188+import java.util.List;
189+
190+public class AutofarmConstants
191+{
192+ public final static List<Integer> attackSlots = Arrays.asList(0, 1, 2, 3);
193+ public final static List<Integer> chanceSlots = Arrays.asList(4, 5, 6, 7);
194+ public final static List<Integer> lowLifeSlots = Arrays.asList(8, 9, 10, 11);
195+}
196\ No newline at end of file
197diff --git java/Base/AutoFarm/AutofarmPlayerRoutine.java java/Base/AutoFarm/AutofarmPlayerRoutine.java
198new file mode 100644
199index 0000000..6f3a1ae
200--- /dev/null
201+++ java/Base/AutoFarm/AutofarmPlayerRoutine.java
202@@ -0,0 +1,581 @@
203+package Base.AutoFarm;
204+
205+import java.util.ArrayList;
206+import java.util.Arrays;
207+import java.util.Collections;
208+import java.util.List;
209+import java.util.concurrent.ScheduledFuture;
210+import java.util.function.Function;
211+import java.util.stream.Collectors;
212+
213+import org.l2jmobius.commons.threads.ThreadPool;
214+import org.l2jmobius.commons.util.Rnd;
215+import org.l2jmobius.gameserver.ai.CtrlIntention;
216+import org.l2jmobius.gameserver.geoengine.GeoEngine;
217+import org.l2jmobius.gameserver.handler.IItemHandler;
218+import org.l2jmobius.gameserver.handler.ItemHandler;
219+import org.l2jmobius.gameserver.handler.voicedcommandhandlers.VoicedAutoFarm;
220+import org.l2jmobius.gameserver.model.ShortCut;
221+import org.l2jmobius.gameserver.model.Skill;
222+import org.l2jmobius.gameserver.model.WorldObject;
223+import org.l2jmobius.gameserver.model.WorldRegion;
224+import org.l2jmobius.gameserver.model.actor.Creature;
225+import org.l2jmobius.gameserver.model.actor.Player;
226+import org.l2jmobius.gameserver.model.actor.Summon;
227+import org.l2jmobius.gameserver.model.actor.instance.Chest;
228+import org.l2jmobius.gameserver.model.actor.instance.Monster;
229+import org.l2jmobius.gameserver.model.actor.instance.Pet;
230+import org.l2jmobius.gameserver.model.item.instance.Item;
231+import org.l2jmobius.gameserver.model.skill.SkillType;
232+import org.l2jmobius.gameserver.network.SystemMessageId;
233+import org.l2jmobius.gameserver.network.serverpackets.ActionFailed;
234+import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
235+import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
236+import org.l2jmobius.gameserver.util.Util;
237+
238+public class AutofarmPlayerRoutine
239+{
240+ private final Player player;
241+ private ScheduledFuture<?> _task;
242+ private Creature committedTarget = null;
243+
244+ public AutofarmPlayerRoutine(Player player)
245+ {
246+ this.player = player;
247+ }
248+
249+ public void start()
250+ {
251+ if (_task == null)
252+ {
253+ _task = ThreadPool.scheduleAtFixedRate(() -> executeRoutine(), 450, 450);
254+
255+ player.sendPacket(new ExShowScreenMessage("Auto Farming Actived...", 5 * 1000));
256+ player.sendPacket(new SystemMessage(SystemMessageId.AUTO_FARM_ACTIVATED));
257+
258+ }
259+ }
260+
261+ public void stop()
262+ {
263+ if (_task != null)
264+ {
265+ _task.cancel(false);
266+ _task = null;
267+
268+ player.sendPacket(new ExShowScreenMessage("Auto Farming Deactivated...", 5 * 1000));
269+ player.sendPacket(new SystemMessage(SystemMessageId.AUTO_FARM_DESACTIVATED));
270+
271+ }
272+ }
273+
274+ public void executeRoutine()
275+ {
276+ if (player.isNoBuffProtected() && (player.getAllEffects().size() <= 8))
277+ {
278+ player.sendMessage("You don't have buffs to use autofarm.");
279+ player.broadcastUserInfo();
280+ stop();
281+ player.setAutoFarm(false);
282+ VoicedAutoFarm.showAutoFarm(player);
283+ return;
284+ }
285+
286+ calculatePotions();
287+ checkSpoil();
288+ targetEligibleCreature();
289+ if (player.isMageClass())
290+ {
291+ useAppropriateSpell();
292+ }
293+ else if (shotcutsContainAttack())
294+ {
295+ attack();
296+ }
297+ else
298+ {
299+ useAppropriateSpell();
300+ }
301+ checkSpoil();
302+ useAppropriateSpell();
303+ }
304+
305+ private void attack()
306+ {
307+ Boolean shortcutsContainAttack = shotcutsContainAttack();
308+
309+ if (shortcutsContainAttack)
310+ {
311+ physicalAttack();
312+ }
313+ }
314+
315+ private void useAppropriateSpell()
316+ {
317+ Skill chanceSkill = nextAvailableSkill(getChanceSpells(), AutofarmSpellType.Chance);
318+
319+ if (chanceSkill != null)
320+ {
321+ useMagicSkill(chanceSkill, false);
322+ return;
323+ }
324+
325+ Skill lowLifeSkill = nextAvailableSkill(getLowLifeSpells(), AutofarmSpellType.LowLife);
326+
327+ if (lowLifeSkill != null)
328+ {
329+ useMagicSkill(lowLifeSkill, true);
330+ return;
331+ }
332+
333+ Skill attackSkill = nextAvailableSkill(getAttackSpells(), AutofarmSpellType.Attack);
334+
335+ if (attackSkill != null)
336+ {
337+ useMagicSkill(attackSkill, false);
338+ return;
339+ }
340+ }
341+
342+ public Skill nextAvailableSkill(List<Integer> skillIds, AutofarmSpellType spellType)
343+ {
344+ for (Integer skillId : skillIds)
345+ {
346+ Skill skill = player.getSkill(skillId);
347+
348+ if (skill == null)
349+ {
350+ continue;
351+ }
352+
353+ if ((skill.getSkillType() == SkillType.SIGNET) || (skill.getSkillType() == SkillType.SIGNET_CASTTIME))
354+ {
355+ continue;
356+ }
357+
358+ if (isSpoil(skillId))
359+ {
360+ if (monsterIsAlreadySpoiled())
361+ {
362+ continue;
363+ }
364+ return skill;
365+ }
366+
367+ if ((spellType == AutofarmSpellType.Chance) && (getMonsterTarget() != null))
368+ {
369+ if (getMonsterTarget().getFirstEffect(skillId) == null)
370+ {
371+ return skill;
372+ }
373+ continue;
374+ }
375+
376+ if ((spellType == AutofarmSpellType.LowLife) && (getHpPercentage() > player.getHealPercent()))
377+ {
378+ break;
379+ }
380+
381+ return skill;
382+ }
383+
384+ return null;
385+ }
386+
387+ private void checkSpoil()
388+ {
389+ if (canBeSweepedByMe() && getMonsterTarget().isDead())
390+ {
391+ Skill sweeper = player.getSkill(42);
392+ if (sweeper == null)
393+ {
394+ return;
395+ }
396+
397+ useMagicSkill(sweeper, false);
398+ }
399+ }
400+
401+ private Double getHpPercentage()
402+ {
403+ return (player.getCurrentHp() * 100.0f) / player.getMaxHp();
404+ }
405+
406+ private Double percentageMpIsLessThan()
407+ {
408+ return (player.getCurrentMp() * 100.0f) / player.getMaxMp();
409+ }
410+
411+ private Double percentageHpIsLessThan()
412+ {
413+ return (player.getCurrentHp() * 100.0f) / player.getMaxHp();
414+ }
415+
416+ private List<Integer> getAttackSpells()
417+ {
418+ return getSpellsInSlots(AutofarmConstants.attackSlots);
419+ }
420+
421+ private List<Integer> getSpellsInSlots(List<Integer> attackSlots)
422+ {
423+ return Arrays.stream(player.getAllShortCuts2()).filter(shortcut -> (shortcut.getPage() == player.getPage()) && (shortcut.getType() == ShortCut.TYPE_SKILL) && attackSlots.contains(shortcut.getSlot())).map(ShortCut::getId).collect(Collectors.toList());
424+ }
425+
426+ private List<Integer> getChanceSpells()
427+ {
428+ return getSpellsInSlots(AutofarmConstants.chanceSlots);
429+ }
430+
431+ private List<Integer> getLowLifeSpells()
432+ {
433+ return getSpellsInSlots(AutofarmConstants.lowLifeSlots);
434+ }
435+
436+ private boolean shotcutsContainAttack()
437+ {
438+ return Arrays.stream(player.getAllShortCuts2()).anyMatch(shortcut -> (shortcut.getPage() == player.getPage()) && (shortcut.getType() == ShortCut.TYPE_ACTION) && ((shortcut.getId() == 2) || (player.isSummonAttack() && (shortcut.getId() == 22))));
439+ }
440+
441+ private boolean monsterIsAlreadySpoiled()
442+ {
443+ return (getMonsterTarget() != null) && (getMonsterTarget().getSpoiledBy() != 0);
444+ }
445+
446+ private static boolean isSpoil(Integer skillId)
447+ {
448+ return (skillId == 254) || (skillId == 302);
449+ }
450+
451+ private boolean canBeSweepedByMe()
452+ {
453+ return (getMonsterTarget() != null) && getMonsterTarget().isDead() && (getMonsterTarget().getSpoiledBy() == player.getObjectId());
454+ }
455+
456+ private void castSpellWithAppropriateTarget(Skill skill, Boolean forceOnSelf)
457+ {
458+ if (forceOnSelf)
459+ {
460+ WorldObject oldTarget = player.getTarget();
461+ player.setTarget(player);
462+ player.useMagic(skill, false, false);
463+ player.setTarget(oldTarget);
464+ return;
465+ }
466+
467+ player.useMagic(skill, false, false);
468+ }
469+
470+ private void physicalAttack()
471+ {
472+ if (!(player.getTarget() instanceof Monster))
473+ {
474+ return;
475+ }
476+
477+ Monster target = (Monster) player.getTarget();
478+
479+ if (!player.isMageClass())
480+ {
481+ if (target.isAutoAttackable(player) && GeoEngine.getInstance().canSeeTarget(player, target))
482+ {
483+ if (GeoEngine.getInstance().canSeeTarget(player, target))
484+ {
485+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
486+ player.onActionRequest();
487+
488+ if (player.isSummonAttack() && (player.getPet() != null))
489+ {
490+ // Siege Golem's
491+ if (((player.getPet().getNpcId() >= 14702) && (player.getPet().getNpcId() <= 14798)) || ((player.getPet().getNpcId() >= 14839) && (player.getPet().getNpcId() <= 14869)))
492+ {
493+ return;
494+ }
495+
496+ Summon activeSummon = player.getPet();
497+ activeSummon.setTarget(target);
498+ activeSummon.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
499+
500+ int[] summonAttackSkills =
501+ {
502+ 4261,
503+ 4068,
504+ 4137,
505+ 4260,
506+ 4708,
507+ 4709,
508+ 4710,
509+ 4712,
510+ 5135,
511+ 5138,
512+ 5141,
513+ 5442,
514+ 5444,
515+ 6095,
516+ 6096,
517+ 6041,
518+ 6044
519+ };
520+ if (Rnd.get(100) < player.getSummonSkillPercent())
521+ {
522+ for (int skillId : summonAttackSkills)
523+ {
524+ useMagicSkillBySummon(skillId, target);
525+ }
526+ }
527+ }
528+ }
529+ }
530+ else
531+ {
532+ if (target.isAutoAttackable(player) && GeoEngine.getInstance().canSeeTarget(player, target))
533+ {
534+ if (GeoEngine.getInstance().canSeeTarget(player, target))
535+ {
536+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, target);
537+ }
538+ }
539+ }
540+ }
541+ else
542+ {
543+ if (player.isSummonAttack() && (player.getPet() != null))
544+ {
545+ // Siege Golem's
546+ if (((player.getPet().getNpcId() >= 14702) && (player.getPet().getNpcId() <= 14798)) || ((player.getPet().getNpcId() >= 14839) && (player.getPet().getNpcId() <= 14869)))
547+ {
548+ return;
549+ }
550+
551+ Summon activeSummon = player.getPet();
552+ activeSummon.setTarget(target);
553+ activeSummon.getAI().setIntention(CtrlIntention.AI_INTENTION_ATTACK, target);
554+
555+ int[] summonAttackSkills =
556+ {
557+ 4261,
558+ 4068,
559+ 4137,
560+ 4260,
561+ 4708,
562+ 4709,
563+ 4710,
564+ 4712,
565+ 5135,
566+ 5138,
567+ 5141,
568+ 5442,
569+ 5444,
570+ 6095,
571+ 6096,
572+ 6041,
573+ 6044
574+ };
575+ if (Rnd.get(100) < player.getSummonSkillPercent())
576+ {
577+ for (int skillId : summonAttackSkills)
578+ {
579+ useMagicSkillBySummon(skillId, target);
580+ }
581+ }
582+ }
583+ }
584+ }
585+
586+ public void targetEligibleCreature()
587+ {
588+ if (player.getTarget() == null)
589+ {
590+ selectNewTarget();
591+ return;
592+ }
593+
594+ if (committedTarget != null)
595+ {
596+ if (!committedTarget.isDead() && GeoEngine.getInstance().canSeeTarget(player, committedTarget))
597+ {
598+ attack();
599+ return;
600+ }
601+ else if (!GeoEngine.getInstance().canSeeTarget(player, committedTarget))
602+ {
603+ committedTarget = null;
604+ selectNewTarget();
605+ return;
606+ }
607+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_FOLLOW, committedTarget);
608+ committedTarget = null;
609+ player.setTarget(null);
610+ }
611+
612+ if (committedTarget instanceof Summon)
613+ {
614+ return;
615+ }
616+
617+ List<Monster> targets = getKnownMonstersInRadius(player, player.getRadius(), creature -> GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), creature.getX(), creature.getY(), creature.getZ(), 0) && !player.ignoredMonsterContain(creature.getNpcId()) && !creature.isMinion() && !creature.isRaid() && !creature.isDead() && !(creature instanceof Chest) && !(player.isAntiKsProtected() && (creature.getTarget() != null) && (creature.getTarget() != player) && (creature.getTarget() != player.getPet())));
618+
619+ if (targets.isEmpty())
620+ {
621+ return;
622+ }
623+
624+ Monster closestTarget = targets.stream().min((o1, o2) -> Integer.compare((int) Math.sqrt(player.getDistanceSq(o1)), (int) Math.sqrt(player.getDistanceSq(o2)))).get();
625+
626+ committedTarget = closestTarget;
627+ player.setTarget(closestTarget);
628+ }
629+
630+ private void selectNewTarget()
631+ {
632+ List<Monster> targets = getKnownMonstersInRadius(player, player.getRadius(), creature -> GeoEngine.getInstance().canMoveToTarget(player.getX(), player.getY(), player.getZ(), creature.getX(), creature.getY(), creature.getZ(), 0) && !player.ignoredMonsterContain(creature.getNpcId()) && !creature.isMinion() && !creature.isRaid() && !creature.isDead() && !(creature instanceof Chest) && !(player.isAntiKsProtected() && (creature.getTarget() != null) && (creature.getTarget() != player) && (creature.getTarget() != player.getPet())));
633+
634+ if (targets.isEmpty())
635+ {
636+ return;
637+ }
638+
639+ Monster closestTarget = targets.stream().min((o1, o2) -> Integer.compare((int) Math.sqrt(player.getDistanceSq(o1)), (int) Math.sqrt(player.getDistanceSq(o2)))).get();
640+
641+ committedTarget = closestTarget;
642+ player.setTarget(closestTarget);
643+ }
644+
645+ public final static List<Monster> getKnownMonstersInRadius(Player player, int radius, Function<Monster, Boolean> condition)
646+ {
647+ final WorldRegion region = player.getWorldRegion();
648+ if (region == null)
649+ {
650+ return Collections.emptyList();
651+ }
652+
653+ final List<Monster> result = new ArrayList<>();
654+
655+ for (WorldRegion reg : region.getSurroundingRegions())
656+ {
657+ for (WorldObject obj : reg.getVisibleObjects())
658+ {
659+ if (!(obj instanceof Monster) || !Util.checkIfInRange(radius, player, obj, true) || !condition.apply((Monster) obj))
660+ {
661+ continue;
662+ }
663+
664+ result.add((Monster) obj);
665+ }
666+ }
667+
668+ return result;
669+ }
670+
671+ public Monster getMonsterTarget()
672+ {
673+ if (!(player.getTarget() instanceof Monster))
674+ {
675+ return null;
676+ }
677+
678+ return (Monster) player.getTarget();
679+ }
680+
681+ private void useMagicSkill(Skill skill, Boolean forceOnSelf)
682+ {
683+ if ((skill.getSkillType() == SkillType.RECALL) && (player.getKarma() > 0))
684+ {
685+ player.sendPacket(ActionFailed.STATIC_PACKET);
686+ return;
687+ }
688+
689+ if (skill.isToggle() && player.isMounted())
690+ {
691+ player.sendPacket(ActionFailed.STATIC_PACKET);
692+ return;
693+ }
694+
695+ if (player.isOutOfControl())
696+ {
697+ player.sendPacket(ActionFailed.STATIC_PACKET);
698+ return;
699+ }
700+
701+ if (player.isAttackingNow())
702+ {
703+ player.getAI().setIntention(CtrlIntention.AI_INTENTION_CAST);
704+ }
705+ else
706+ {
707+ castSpellWithAppropriateTarget(skill, forceOnSelf);
708+ }
709+ }
710+
711+ private boolean useMagicSkillBySummon(int skillId, WorldObject target)
712+ {
713+ // No owner, or owner in shop mode.
714+ if ((player == null) || player.isInStoreMode())
715+ {
716+ return false;
717+ }
718+
719+ final Summon activeSummon = player.getPet();
720+ if (activeSummon == null)
721+ {
722+ return false;
723+ }
724+
725+ // Pet which is 20 levels higher than owner.
726+ if ((activeSummon instanceof Pet) && ((activeSummon.getLevel() - player.getLevel()) > 20))
727+ {
728+ // player.sendPacket(SystemMessageId.PET_TOO_HIGH_TO_CONTROL);
729+ return false;
730+ }
731+
732+ // Out of control pet.
733+ if (activeSummon.isOutOfControl())
734+ {
735+ // player.sendPacket(SystemMessageId.PET_REFUSING_ORDER);
736+ return false;
737+ }
738+
739+ // Verify if the launched skill is mastered by the summon.
740+ final Skill skill = activeSummon.getSkill(skillId);
741+ if (skill == null)
742+ {
743+ return false;
744+ }
745+
746+ // Can't launch offensive skills on owner.
747+ if (skill.isOffensive() && (player == target))
748+ {
749+ return false;
750+ }
751+
752+ activeSummon.setTarget(target);
753+ return activeSummon.useMagic(skill, false, false);
754+ }
755+
756+ private void calculatePotions()
757+ {
758+ if (percentageHpIsLessThan() < player.getHpPotionPercentage())
759+ {
760+ forceUseItem(1539);
761+ }
762+
763+ if (percentageMpIsLessThan() < player.getMpPotionPercentage())
764+ {
765+ forceUseItem(728);
766+ }
767+ }
768+
769+ private void forceUseItem(int itemId)
770+ {
771+ final Item potion = player.getInventory().getItemByItemId(itemId);
772+ if (potion == null)
773+ {
774+ return;
775+ }
776+
777+ final IItemHandler handler = ItemHandler.getInstance().getItemHandler(potion.getItemId());
778+ if (handler != null)
779+ {
780+ handler.useItem(player, potion);
781+ }
782+ }
783+}
784\ No newline at end of file
785diff --git java/Base/AutoFarm/AutofarmSpell.java java/Base/AutoFarm/AutofarmSpell.java
786new file mode 100644
787index 0000000..beefc8d
788--- /dev/null
789+++ java/Base/AutoFarm/AutofarmSpell.java
790@@ -0,0 +1,20 @@
791+package Base.AutoFarm;
792+
793+public class AutofarmSpell {
794+ private final Integer _skillId;
795+ private final AutofarmSpellType _spellType;
796+
797+ public AutofarmSpell(Integer skillId, AutofarmSpellType spellType){
798+
799+ _skillId = skillId;
800+ _spellType = spellType;
801+ }
802+
803+ public Integer getSkillId() {
804+ return _skillId;
805+ }
806+
807+ public AutofarmSpellType getSpellType() {
808+ return _spellType;
809+ }
810+}
811\ No newline at end of file
812diff --git java/Base/AutoFarm/AutofarmSpellType.java java/Base/AutoFarm/AutofarmSpellType.java
813new file mode 100644
814index 0000000..2ec3039
815--- /dev/null
816+++ java/Base/AutoFarm/AutofarmSpellType.java
817@@ -0,0 +1,8 @@
818+package Base.AutoFarm;
819+
820+public enum AutofarmSpellType
821+{
822+ Attack,
823+ Chance,
824+ LowLife
825+}
826\ No newline at end of file
827diff --git java/org/l2jmobius/gameserver/handler/VoicedCommandHandler.java java/org/l2jmobius/gameserver/handler/VoicedCommandHandler.java
828index 466e2a6..b25580e 100644
829--- java/org/l2jmobius/gameserver/handler/VoicedCommandHandler.java
830+++ java/org/l2jmobius/gameserver/handler/VoicedCommandHandler.java
831@@ -30,6 +30,7 @@
832 import org.l2jmobius.gameserver.handler.voicedcommandhandlers.Online;
833 import org.l2jmobius.gameserver.handler.voicedcommandhandlers.StatsCmd;
834 import org.l2jmobius.gameserver.handler.voicedcommandhandlers.VoiceCommand;
835+import org.l2jmobius.gameserver.handler.voicedcommandhandlers.VoicedAutoFarm;
836 import org.l2jmobius.gameserver.handler.voicedcommandhandlers.Wedding;
837
838 public class VoicedCommandHandler
839@@ -43,6 +44,7 @@
840 _datatable = new HashMap<>();
841
842 registerVoicedCommandHandler(new VoiceCommand());
843+ registerVoicedCommandHandler(new VoicedAutoFarm());
844
845 if (Config.ENABLE_AUTO_PLAY)
846 {
847diff --git java/org/l2jmobius/gameserver/handler/voicedcommandhandlers/VoicedAutoFarm.java java/org/l2jmobius/gameserver/handler/voicedcommandhandlers/VoicedAutoFarm.java
848new file mode 100644
849index 0000000..6501c48
850--- /dev/null
851+++ java/org/l2jmobius/gameserver/handler/voicedcommandhandlers/VoicedAutoFarm.java
852@@ -0,0 +1,332 @@
853+package org.l2jmobius.gameserver.handler.voicedcommandhandlers;
854+
855+import java.util.StringTokenizer;
856+
857+import org.l2jmobius.commons.util.StringUtil;
858+import org.l2jmobius.gameserver.handler.IVoicedCommandHandler;
859+import org.l2jmobius.gameserver.model.WorldObject;
860+import org.l2jmobius.gameserver.model.actor.Player;
861+import org.l2jmobius.gameserver.model.actor.instance.Monster;
862+import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
863+
864+import Base.AutoFarm.AutofarmPlayerRoutine;
865+
866+public class VoicedAutoFarm implements IVoicedCommandHandler
867+{
868+ private final String[] VOICED_COMMANDS =
869+ {
870+ "autofarm",
871+ "enableAutoFarm",
872+ "radiusAutoFarm",
873+ "pageAutoFarm",
874+ "enableBuffProtect",
875+ "healAutoFarm",
876+ "hpAutoFarm",
877+ "mpAutoFarm",
878+ "enableAntiKs",
879+ "enableSummonAttack",
880+ "summonSkillAutoFarm",
881+ "ignoreMonster",
882+ "activeMonster"
883+ };
884+
885+ @Override
886+ public boolean useVoicedCommand(final String command, final Player activeChar, final String args)
887+ {
888+ final AutofarmPlayerRoutine bot = activeChar.getBot();
889+
890+ if (command.startsWith("autofarm"))
891+ {
892+ showAutoFarm(activeChar);
893+ }
894+
895+ if (command.startsWith("radiusAutoFarm"))
896+ {
897+ StringTokenizer st = new StringTokenizer(command, " ");
898+ st.nextToken();
899+ try
900+ {
901+ String param = st.nextToken();
902+
903+ if (param.startsWith("inc_radius"))
904+ {
905+ activeChar.setRadius(activeChar.getRadius() + 200);
906+ showAutoFarm(activeChar);
907+ }
908+ else if (param.startsWith("dec_radius"))
909+ {
910+ activeChar.setRadius(activeChar.getRadius() - 200);
911+ showAutoFarm(activeChar);
912+ }
913+ activeChar.saveAutoFarmSettings();
914+ }
915+ catch (Exception e)
916+ {
917+ e.printStackTrace();
918+ }
919+ }
920+
921+ if (command.startsWith("pageAutoFarm"))
922+ {
923+ StringTokenizer st = new StringTokenizer(command, " ");
924+ st.nextToken();
925+ try
926+ {
927+ String param = st.nextToken();
928+
929+ if (param.startsWith("inc_page"))
930+ {
931+ activeChar.setPage(activeChar.getPage() + 1);
932+ showAutoFarm(activeChar);
933+ }
934+ else if (param.startsWith("dec_page"))
935+ {
936+ activeChar.setPage(activeChar.getPage() - 1);
937+ showAutoFarm(activeChar);
938+ }
939+ activeChar.saveAutoFarmSettings();
940+ }
941+ catch (Exception e)
942+ {
943+ e.printStackTrace();
944+ }
945+ }
946+
947+ if (command.startsWith("healAutoFarm"))
948+ {
949+ StringTokenizer st = new StringTokenizer(command, " ");
950+ st.nextToken();
951+ try
952+ {
953+ String param = st.nextToken();
954+
955+ if (param.startsWith("inc_heal"))
956+ {
957+ activeChar.setHealPercent(activeChar.getHealPercent() + 10);
958+ showAutoFarm(activeChar);
959+ }
960+ else if (param.startsWith("dec_heal"))
961+ {
962+ activeChar.setHealPercent(activeChar.getHealPercent() - 10);
963+ showAutoFarm(activeChar);
964+ }
965+ activeChar.saveAutoFarmSettings();
966+ }
967+ catch (Exception e)
968+ {
969+ e.printStackTrace();
970+ }
971+ }
972+
973+ if (command.startsWith("hpAutoFarm"))
974+ {
975+ StringTokenizer st = new StringTokenizer(command, " ");
976+ st.nextToken();
977+ try
978+ {
979+ String param = st.nextToken();
980+
981+ if (param.contains("inc_hp_pot"))
982+ {
983+ activeChar.setHpPotionPercentage(activeChar.getHpPotionPercentage() + 5);
984+ showAutoFarm(activeChar);
985+ }
986+ else if (param.contains("dec_hp_pot"))
987+ {
988+ activeChar.setHpPotionPercentage(activeChar.getHpPotionPercentage() - 5);
989+ showAutoFarm(activeChar);
990+ }
991+ activeChar.saveAutoFarmSettings();
992+ }
993+ catch (Exception e)
994+ {
995+ e.printStackTrace();
996+ }
997+ }
998+
999+ if (command.startsWith("mpAutoFarm"))
1000+ {
1001+ StringTokenizer st = new StringTokenizer(command, " ");
1002+ st.nextToken();
1003+ try
1004+ {
1005+ String param = st.nextToken();
1006+
1007+ if (param.contains("inc_mp_pot"))
1008+ {
1009+ activeChar.setMpPotionPercentage(activeChar.getMpPotionPercentage() + 5);
1010+ showAutoFarm(activeChar);
1011+ }
1012+ else if (param.contains("dec_mp_pot"))
1013+ {
1014+ activeChar.setMpPotionPercentage(activeChar.getMpPotionPercentage() - 5);
1015+ showAutoFarm(activeChar);
1016+ }
1017+ activeChar.saveAutoFarmSettings();
1018+ }
1019+ catch (Exception e)
1020+ {
1021+ e.printStackTrace();
1022+ }
1023+ }
1024+
1025+ if (command.startsWith("enableAutoFarm"))
1026+ {
1027+ if (activeChar.isAutoFarm())
1028+ {
1029+ bot.stop();
1030+ activeChar.setAutoFarm(false);
1031+ activeChar.broadcastUserInfo();
1032+ activeChar.broadcastCharInfo();
1033+ }
1034+ else
1035+ {
1036+ bot.start();
1037+ activeChar.setAutoFarm(true);
1038+ activeChar.broadcastUserInfo();
1039+ activeChar.broadcastCharInfo();
1040+ }
1041+
1042+ showAutoFarm(activeChar);
1043+ }
1044+
1045+ if (command.startsWith("enableBuffProtect"))
1046+ {
1047+ activeChar.setNoBuffProtection(!activeChar.isNoBuffProtected());
1048+ showAutoFarm(activeChar);
1049+ activeChar.saveAutoFarmSettings();
1050+ }
1051+
1052+ if (command.startsWith("enableAntiKs"))
1053+ {
1054+ activeChar.setAntiKsProtection(!activeChar.isAntiKsProtected());
1055+
1056+ if (activeChar.isAntiKsProtected())
1057+ {
1058+ // activeChar.sendPacket(new SystemMessage(SystemMessageId.ACTIVATE_RESPECT_HUNT));
1059+ // activeChar.sendPacket(new ExShowScreenMessage("Respct Hunt On" , 3*1000, SMPOS.TOP_CENTER, false));
1060+ }
1061+ else
1062+ {
1063+ // activeChar.sendPacket(new SystemMessage(SystemMessageId.DESACTIVATE_RESPECT_HUNT));
1064+ // activeChar.sendPacket(new ExShowScreenMessage("Respct Hunt Off" , 3*1000, SMPOS.TOP_CENTER, false));
1065+ }
1066+
1067+ activeChar.saveAutoFarmSettings();
1068+ showAutoFarm(activeChar);
1069+ }
1070+
1071+ if (command.startsWith("enableSummonAttack"))
1072+ {
1073+ activeChar.setSummonAttack(!activeChar.isSummonAttack());
1074+ if (activeChar.isSummonAttack())
1075+ {
1076+ // activeChar.sendPacket(new SystemMessage(SystemMessageId.ACTIVATE_SUMMON_ACTACK));
1077+ // activeChar.sendPacket(new ExShowScreenMessage("Auto Farm Summon Attack On" , 3*1000, SMPOS.TOP_CENTER, false));
1078+ }
1079+ else
1080+ {
1081+ // activeChar.sendPacket(new SystemMessage(SystemMessageId.DESACTIVATE_SUMMON_ACTACK));
1082+ // activeChar.sendPacket(new ExShowScreenMessage("Auto Farm Summon Attack Off" , 3*1000, SMPOS.TOP_CENTER, false));
1083+ }
1084+ activeChar.saveAutoFarmSettings();
1085+ showAutoFarm(activeChar);
1086+ }
1087+
1088+ if (command.startsWith("summonSkillAutoFarm"))
1089+ {
1090+ StringTokenizer st = new StringTokenizer(command, " ");
1091+ st.nextToken();
1092+ try
1093+ {
1094+ String param = st.nextToken();
1095+
1096+ if (param.startsWith("inc_summonSkill"))
1097+ {
1098+ activeChar.setSummonSkillPercent(activeChar.getSummonSkillPercent() + 10);
1099+ showAutoFarm(activeChar);
1100+ }
1101+ else if (param.startsWith("dec_summonSkill"))
1102+ {
1103+ activeChar.setSummonSkillPercent(activeChar.getSummonSkillPercent() - 10);
1104+ showAutoFarm(activeChar);
1105+ }
1106+ activeChar.saveAutoFarmSettings();
1107+ }
1108+ catch (Exception e)
1109+ {
1110+ e.printStackTrace();
1111+ }
1112+ }
1113+
1114+ if (command.startsWith("ignoreMonster"))
1115+ {
1116+ int monsterId = 0;
1117+ WorldObject target = activeChar.getTarget();
1118+ if (target instanceof Monster)
1119+ {
1120+ monsterId = ((Monster) target).getNpcId();
1121+ }
1122+
1123+ if (target == null)
1124+ {
1125+ activeChar.sendMessage("You dont have a target");
1126+ return false;
1127+ }
1128+
1129+ activeChar.sendMessage(target.getName() + " has been added to the ignore list.");
1130+ activeChar.ignoredMonster(monsterId);
1131+ }
1132+
1133+ if (command.startsWith("activeMonster"))
1134+ {
1135+ int monsterId = 0;
1136+ WorldObject target = activeChar.getTarget();
1137+ if (target instanceof Monster)
1138+ {
1139+ monsterId = ((Monster) target).getNpcId();
1140+ }
1141+
1142+ if (target == null)
1143+ {
1144+ activeChar.sendMessage("You dont have a target");
1145+ return false;
1146+ }
1147+
1148+ activeChar.sendMessage(target.getName() + " has been removed from the ignore list.");
1149+ activeChar.activeMonster(monsterId);
1150+ }
1151+
1152+ return false;
1153+ }
1154+
1155+ private static final String ACTIVED = "<font color=00FF00>STARTED</font>";
1156+ private static final String DESATIVED = "<font color=FF0000>STOPPED</font>";
1157+ private static final String STOP = "STOP";
1158+ private static final String START = "START";
1159+
1160+ public static void showAutoFarm(Player activeChar)
1161+ {
1162+ NpcHtmlMessage html = new NpcHtmlMessage(0);
1163+ html.setFile("data/html/mods/menu/AutoFarm.htm");
1164+ html.replace("%player%", activeChar.getName());
1165+ html.replace("%page%", StringUtil.formatNumber(activeChar.getPage() + 1));
1166+ html.replace("%heal%", StringUtil.formatNumber(activeChar.getHealPercent()));
1167+ html.replace("%radius%", StringUtil.formatNumber(activeChar.getRadius()));
1168+ html.replace("%summonSkill%", StringUtil.formatNumber(activeChar.getSummonSkillPercent()));
1169+ html.replace("%hpPotion%", StringUtil.formatNumber(activeChar.getHpPotionPercentage()));
1170+ html.replace("%mpPotion%", StringUtil.formatNumber(activeChar.getMpPotionPercentage()));
1171+ html.replace("%noBuff%", activeChar.isNoBuffProtected() ? "back=L2UI.CheckBox_checked fore=L2UI.CheckBox_checked" : "back=L2UI.CheckBox fore=L2UI.CheckBox");
1172+ html.replace("%summonAtk%", activeChar.isSummonAttack() ? "back=L2UI.CheckBox_checked fore=L2UI.CheckBox_checked" : "back=L2UI.CheckBox fore=L2UI.CheckBox");
1173+ html.replace("%antiKs%", activeChar.isAntiKsProtected() ? "back=L2UI.CheckBox_checked fore=L2UI.CheckBox_checked" : "back=L2UI.CheckBox fore=L2UI.CheckBox");
1174+ html.replace("%autofarm%", activeChar.isAutoFarm() ? ACTIVED : DESATIVED);
1175+ html.replace("%button%", activeChar.isAutoFarm() ? STOP : START);
1176+ activeChar.sendPacket(html);
1177+ }
1178+
1179+ @Override
1180+ public String[] getVoicedCommandList()
1181+ {
1182+ return VOICED_COMMANDS;
1183+ }
1184+}
1185\ No newline at end of file
1186diff --git java/org/l2jmobius/gameserver/model/ShortCuts.java java/org/l2jmobius/gameserver/model/ShortCuts.java
1187index 99279ba..2b0fb56 100644
1188--- java/org/l2jmobius/gameserver/model/ShortCuts.java
1189+++ java/org/l2jmobius/gameserver/model/ShortCuts.java
1190@@ -51,6 +51,11 @@
1191 return _shortCuts.values();
1192 }
1193
1194+ public ShortCut[] getAllShortCuts2()
1195+ {
1196+ return _shortCuts.values().toArray(new ShortCut[_shortCuts.values().size()]);
1197+ }
1198+
1199 public ShortCut getShortCut(int slot, int page)
1200 {
1201 final ShortCut sc = _shortCuts.get(slot + (page * 12));
1202diff --git java/org/l2jmobius/gameserver/model/actor/Creature.java java/org/l2jmobius/gameserver/model/actor/Creature.java
1203index e6fc06d..4fcd802 100644
1204--- java/org/l2jmobius/gameserver/model/actor/Creature.java
1205+++ java/org/l2jmobius/gameserver/model/actor/Creature.java
1206@@ -2224,6 +2224,15 @@
1207 }
1208
1209 /**
1210+ * @param skillId The identifier of the L2Skill to check the knowledge
1211+ * @return True if the skill is known by the Creature.
1212+ */
1213+ public Skill getSkill(int skillId)
1214+ {
1215+ return getSkills().get(skillId);
1216+ }
1217+
1218+ /**
1219 * Set the Creature flying mode to True.
1220 * @param mode the new checks if is flying
1221 */
1222@@ -9414,6 +9423,32 @@
1223 }
1224
1225 /**
1226+ * Return the squared distance between the current position of the Creature and the given object.
1227+ * @param object WorldObject
1228+ * @return the squared distance
1229+ */
1230+ public final double getDistanceSq(WorldObject object)
1231+ {
1232+ return getDistanceSq(object.getX(), object.getY(), object.getZ());
1233+ }
1234+
1235+ /**
1236+ * Return the squared distance between the current position of the Creature and the given x, y, z.
1237+ * @param x X position of the target
1238+ * @param y Y position of the target
1239+ * @param z Z position of the target
1240+ * @return the squared distance
1241+ */
1242+ public final double getDistanceSq(int x, int y, int z)
1243+ {
1244+ double dx = x - getX();
1245+ double dy = y - getY();
1246+ double dz = z - getZ();
1247+
1248+ return ((dx * dx) + (dy * dy) + (dz * dz));
1249+ }
1250+
1251+ /**
1252 * Gets the _triggered skills.
1253 * @return the _triggeredSkills
1254 */
1255diff --git java/org/l2jmobius/gameserver/model/actor/Player.java java/org/l2jmobius/gameserver/model/actor/Player.java
1256index ce1f47c..41f6412 100644
1257--- java/org/l2jmobius/gameserver/model/actor/Player.java
1258+++ java/org/l2jmobius/gameserver/model/actor/Player.java
1259@@ -19,6 +19,7 @@
1260 import java.sql.Connection;
1261 import java.sql.PreparedStatement;
1262 import java.sql.ResultSet;
1263+import java.sql.SQLException;
1264 import java.util.ArrayList;
1265 import java.util.Calendar;
1266 import java.util.Collection;
1267@@ -240,8 +241,11 @@
1268 import org.l2jmobius.gameserver.taskmanager.PlayerAutoSaveTaskManager;
1269 import org.l2jmobius.gameserver.taskmanager.PvpFlagTaskManager;
1270 import org.l2jmobius.gameserver.util.Broadcast;
1271+import org.l2jmobius.gameserver.util.MathUtil;
1272 import org.l2jmobius.gameserver.util.Util;
1273
1274+import Base.AutoFarm.AutofarmPlayerRoutine;
1275+
1276 /**
1277 * This class represents all player characters in the world.<br>
1278 * There is always a client-thread connected to this (except if a player-store is activated upon logout).
1279@@ -1510,6 +1514,14 @@
1280 }
1281
1282 /**
1283+ * @return A table containing all L2ShortCut of the Player.
1284+ */
1285+ public ShortCut[] getAllShortCuts2()
1286+ {
1287+ return _shortCuts.getAllShortCuts2();
1288+ }
1289+
1290+ /**
1291 * Return the ShortCut of the Player corresponding to the position (page-slot).
1292 * @param slot The slot in wich the shortCuts is equiped
1293 * @param page The page of shortCuts containing the slot
1294@@ -13093,6 +13105,8 @@
1295 getVariables().setIntegerList(PlayerVariables.AUTO_USE_SETTINGS, settings);
1296 }
1297
1298+ _bot.stop();
1299+
1300 // Check if the Player is in observer mode to set its position to its position before entering in observer mode
1301 if (inObserverMode())
1302 {
1303@@ -15649,4 +15663,233 @@
1304 {
1305 return true;
1306 }
1307+
1308+ // ------------
1309+ // Autofarm
1310+ // ------------
1311+
1312+ private boolean _autoFarm;
1313+
1314+ public void setAutoFarm(boolean comm)
1315+ {
1316+ _autoFarm = comm;
1317+ }
1318+
1319+ public boolean isAutoFarm()
1320+ {
1321+ return _autoFarm;
1322+ }
1323+
1324+ private int autoFarmRadius = 1200;
1325+
1326+ public void setRadius(int value)
1327+ {
1328+ autoFarmRadius = MathUtil.limit(value, 200, 3000);
1329+ }
1330+
1331+ public int getRadius()
1332+ {
1333+ return autoFarmRadius;
1334+ }
1335+
1336+ private int autoFarmShortCut = 9;
1337+
1338+ public void setPage(int value)
1339+ {
1340+ autoFarmShortCut = MathUtil.limit(value, 0, 9);
1341+ }
1342+
1343+ public int getPage()
1344+ {
1345+ return autoFarmShortCut;
1346+ }
1347+
1348+ private int autoFarmHealPercente = 30;
1349+
1350+ public void setHealPercent(int value)
1351+ {
1352+ autoFarmHealPercente = MathUtil.limit(value, 20, 90);
1353+ }
1354+
1355+ public int getHealPercent()
1356+ {
1357+ return autoFarmHealPercente;
1358+ }
1359+
1360+ private boolean autoFarmBuffProtection = false;
1361+
1362+ public void setNoBuffProtection(boolean val)
1363+ {
1364+ autoFarmBuffProtection = val;
1365+ }
1366+
1367+ public boolean isNoBuffProtected()
1368+ {
1369+ return autoFarmBuffProtection;
1370+ }
1371+
1372+ private boolean autoAntiKsProtection = false;
1373+
1374+ public void setAntiKsProtection(boolean val)
1375+ {
1376+ autoAntiKsProtection = val;
1377+ }
1378+
1379+ public boolean isAntiKsProtected()
1380+ {
1381+ return autoAntiKsProtection;
1382+ }
1383+
1384+ private boolean autoFarmSummonAttack = false;
1385+
1386+ public void setSummonAttack(boolean val)
1387+ {
1388+ autoFarmSummonAttack = val;
1389+ }
1390+
1391+ public boolean isSummonAttack()
1392+ {
1393+ return autoFarmSummonAttack;
1394+ }
1395+
1396+ private int autoFarmSummonSkillPercente = 0;
1397+
1398+ public void setSummonSkillPercent(int value)
1399+ {
1400+ autoFarmSummonSkillPercente = MathUtil.limit(value, 0, 90);
1401+ }
1402+
1403+ public int getSummonSkillPercent()
1404+ {
1405+ return autoFarmSummonSkillPercente;
1406+ }
1407+
1408+ private int hpPotionPercent = 60;
1409+ private int mpPotionPercent = 60;
1410+
1411+ public void setHpPotionPercentage(int value)
1412+ {
1413+ hpPotionPercent = MathUtil.limit(value, 0, 100);
1414+ }
1415+
1416+ public int getHpPotionPercentage()
1417+ {
1418+ return hpPotionPercent;
1419+ }
1420+
1421+ public void setMpPotionPercentage(int value)
1422+ {
1423+ mpPotionPercent = MathUtil.limit(value, 0, 100);
1424+ }
1425+
1426+ public int getMpPotionPercentage()
1427+ {
1428+ return mpPotionPercent;
1429+ }
1430+
1431+ private final List<Integer> _ignoredMonster = new ArrayList<>();
1432+
1433+ public void ignoredMonster(Integer npcId)
1434+ {
1435+ _ignoredMonster.add(npcId);
1436+ }
1437+
1438+ public void activeMonster(Integer npcId)
1439+ {
1440+ if (_ignoredMonster.contains(npcId))
1441+ {
1442+ _ignoredMonster.remove(npcId);
1443+ }
1444+ }
1445+
1446+ public boolean ignoredMonsterContain(int npcId)
1447+ {
1448+ return _ignoredMonster.contains(npcId);
1449+ }
1450+
1451+ private AutofarmPlayerRoutine _bot = new AutofarmPlayerRoutine(this);
1452+
1453+ public AutofarmPlayerRoutine getBot()
1454+ {
1455+ if (_bot == null)
1456+ {
1457+ _bot = new AutofarmPlayerRoutine(this);
1458+ }
1459+
1460+ return _bot;
1461+ }
1462+
1463+ public void saveAutoFarmSettings()
1464+ {
1465+ try (Connection con = DatabaseFactory.getConnection())
1466+ {
1467+ String updateSql = "REPLACE INTO character_autofarm (char_id, char_name, radius, short_cut, heal_percent, buff_protection, anti_ks_protection, summon_attack, summon_skill_percent, hp_potion_percent, mp_potion_percent) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
1468+ try (PreparedStatement updateStatement = con.prepareStatement(updateSql))
1469+ {
1470+ updateStatement.setInt(1, getObjectId()); // char_id
1471+ updateStatement.setString(2, getName()); // char_name
1472+
1473+ updateStatement.setInt(3, autoFarmRadius);
1474+ updateStatement.setInt(4, autoFarmShortCut);
1475+ updateStatement.setInt(5, autoFarmHealPercente);
1476+ updateStatement.setBoolean(6, autoFarmBuffProtection);
1477+ updateStatement.setBoolean(7, autoAntiKsProtection);
1478+ updateStatement.setBoolean(8, autoFarmSummonAttack);
1479+ updateStatement.setInt(9, autoFarmSummonSkillPercente);
1480+ updateStatement.setInt(10, hpPotionPercent);
1481+ updateStatement.setInt(11, mpPotionPercent);
1482+ updateStatement.executeUpdate();
1483+ }
1484+ }
1485+ catch (SQLException e)
1486+ {
1487+ e.printStackTrace();
1488+ }
1489+ }
1490+
1491+ public void loadAutoFarmSettings()
1492+ {
1493+ try (Connection con = DatabaseFactory.getConnection())
1494+ {
1495+ String selectSql = "SELECT * FROM character_autofarm WHERE char_id = ?";
1496+ try (PreparedStatement selectStatement = con.prepareStatement(selectSql))
1497+ {
1498+ selectStatement.setInt(1, getObjectId()); // char_id
1499+ try (ResultSet resultSet = selectStatement.executeQuery())
1500+ {
1501+ if (resultSet.next())
1502+ {
1503+
1504+ autoFarmRadius = resultSet.getInt("radius");
1505+ autoFarmShortCut = resultSet.getInt("short_cut");
1506+ autoFarmHealPercente = resultSet.getInt("heal_percent");
1507+ autoFarmBuffProtection = resultSet.getBoolean("buff_protection");
1508+ autoAntiKsProtection = resultSet.getBoolean("anti_ks_protection");
1509+ autoFarmSummonAttack = resultSet.getBoolean("summon_attack");
1510+ autoFarmSummonSkillPercente = resultSet.getInt("summon_skill_percent");
1511+ hpPotionPercent = resultSet.getInt("hp_potion_percent");
1512+ mpPotionPercent = resultSet.getInt("mp_potion_percent");
1513+ }
1514+ else
1515+ {
1516+
1517+ autoFarmRadius = 1200;
1518+ autoFarmShortCut = 9;
1519+ autoFarmHealPercente = 30;
1520+ autoFarmBuffProtection = false;
1521+ autoAntiKsProtection = false;
1522+ autoFarmSummonAttack = false;
1523+ autoFarmSummonSkillPercente = 0;
1524+ hpPotionPercent = 60;
1525+ mpPotionPercent = 60;
1526+ }
1527+ }
1528+ }
1529+ }
1530+ catch (SQLException e)
1531+ {
1532+ e.printStackTrace();
1533+ }
1534+ }
1535+
1536 }
1537\ No newline at end of file
1538diff --git java/org/l2jmobius/gameserver/network/SystemMessageId.java java/org/l2jmobius/gameserver/network/SystemMessageId.java
1539index faeaa6a..ec95ef5 100644
1540--- java/org/l2jmobius/gameserver/network/SystemMessageId.java
1541+++ java/org/l2jmobius/gameserver/network/SystemMessageId.java
1542@@ -6280,6 +6280,20 @@
1543 @ClientString(id = 2153, message = "You are currently logged into 10 of your accounts and can no longer access your other accounts.")
1544 public static SystemMessageId YOU_ARE_CURRENTLY_LOGGED_INTO_10_OF_YOUR_ACCOUNTS_AND_CAN_NO_LONGER_ACCESS_YOUR_OTHER_ACCOUNTS;
1545
1546+ @ClientString(id = 2156, message = "Because of your Fatigue level, this is not allowed.")
1547+ public static SystemMessageId ACTIVATE_SUMMON_ACTACK;
1548+
1549+ @ClientString(id = 2157, message = "Because of your Fatigue level, this is not allowed.")
1550+ public static SystemMessageId DESACTIVATE_SUMMON_ACTACK;
1551+ @ClientString(id = 2158, message = "Because of your Fatigue level, this is not allowed.")
1552+ public static SystemMessageId ACTIVATE_RESPECT_HUNT;
1553+ @ClientString(id = 2159, message = "Because of your Fatigue level, this is not allowed.")
1554+ public static SystemMessageId DESACTIVATE_RESPECT_HUNT;
1555+ @ClientString(id = 2155, message = "Because of your Fatigue level, this is not allowed.")
1556+ public static SystemMessageId AUTO_FARM_DESACTIVATED;
1557+ @ClientString(id = 2160, message = "Because of your Fatigue level, this is not allowed.")
1558+ public static SystemMessageId AUTO_FARM_ACTIVATED;
1559+
1560 static
1561 {
1562 buildFastLookupTable();
1563diff --git java/org/l2jmobius/gameserver/network/clientpackets/EnterWorld.java java/org/l2jmobius/gameserver/network/clientpackets/EnterWorld.java
1564index fb7f499..7e69579 100644
1565--- java/org/l2jmobius/gameserver/network/clientpackets/EnterWorld.java
1566+++ java/org/l2jmobius/gameserver/network/clientpackets/EnterWorld.java
1567@@ -324,6 +324,19 @@
1568
1569 PetitionManager.getInstance().checkPetitionMessages(player);
1570
1571+ player.loadAutoFarmSettings();
1572+
1573+ if (player.isSummonAttack())
1574+ {
1575+ player.sendPacket(new SystemMessage(SystemMessageId.ACTIVATE_SUMMON_ACTACK));
1576+
1577+ }
1578+
1579+ if (player.isAntiKsProtected())
1580+ {
1581+ player.sendPacket(new SystemMessage(SystemMessageId.ACTIVATE_RESPECT_HUNT));
1582+ }
1583+
1584 if ((player.getClanId() != 0) && (player.getClan() != null))
1585 {
1586 player.sendPacket(new PledgeShowMemberListAll(player.getClan(), player));
1587diff --git java/org/l2jmobius/gameserver/network/clientpackets/RequestBypassToServer.java java/org/l2jmobius/gameserver/network/clientpackets/RequestBypassToServer.java
1588index dcfe0f4..431c5cf 100644
1589--- java/org/l2jmobius/gameserver/network/clientpackets/RequestBypassToServer.java
1590+++ java/org/l2jmobius/gameserver/network/clientpackets/RequestBypassToServer.java
1591@@ -16,6 +16,8 @@
1592 */
1593 package org.l2jmobius.gameserver.network.clientpackets;
1594
1595+import java.util.StringTokenizer;
1596+
1597 import org.l2jmobius.Config;
1598 import org.l2jmobius.commons.network.ReadablePacket;
1599 import org.l2jmobius.commons.util.CommonUtil;
1600@@ -37,10 +39,15 @@
1601 import org.l2jmobius.gameserver.model.olympiad.Olympiad;
1602 import org.l2jmobius.gameserver.network.GameClient;
1603 import org.l2jmobius.gameserver.network.PacketLogger;
1604+import org.l2jmobius.gameserver.network.SystemMessageId;
1605 import org.l2jmobius.gameserver.network.serverpackets.ActionFailed;
1606+import org.l2jmobius.gameserver.network.serverpackets.ExShowScreenMessage;
1607 import org.l2jmobius.gameserver.network.serverpackets.NpcHtmlMessage;
1608+import org.l2jmobius.gameserver.network.serverpackets.SystemMessage;
1609 import org.l2jmobius.gameserver.util.GMAudit;
1610
1611+import Base.AutoFarm.AutofarmPlayerRoutine;
1612+
1613 public class RequestBypassToServer implements ClientPacket
1614 {
1615 // S
1616@@ -61,6 +68,8 @@
1617 return;
1618 }
1619
1620+ final AutofarmPlayerRoutine bot = player.getBot();
1621+
1622 if (!client.getFloodProtectors().canUseServerBypass())
1623 {
1624 return;
1625@@ -107,6 +116,123 @@
1626 ach.useAdminCommand(_command, player);
1627 player.sendPacket(ActionFailed.STATIC_PACKET);
1628 }
1629+
1630+ else if (_command.startsWith("_autofarm"))
1631+ {
1632+ if (player.isAutoFarm())
1633+ {
1634+ bot.stop();
1635+ player.setAutoFarm(false);
1636+ player.broadcastUserInfo();
1637+ player.broadcastCharInfo();
1638+ }
1639+ else
1640+ {
1641+ bot.start();
1642+ player.setAutoFarm(true);
1643+ player.broadcastUserInfo();
1644+ player.broadcastCharInfo();
1645+ }
1646+
1647+ }
1648+
1649+ if (_command.startsWith("_pageAutoFarm"))
1650+ {
1651+ StringTokenizer st = new StringTokenizer(_command, " ");
1652+ st.nextToken();
1653+ try
1654+ {
1655+ String param = st.nextToken();
1656+
1657+ if (param.startsWith("inc_page") || param.startsWith("dec_page"))
1658+ {
1659+ int newPage;
1660+
1661+ if (param.startsWith("inc_page"))
1662+ {
1663+ newPage = player.getPage() + 1;
1664+ }
1665+ else
1666+ {
1667+ newPage = player.getPage() - 1;
1668+ }
1669+
1670+ if ((newPage >= 0) && (newPage <= 9))
1671+ {
1672+ String[] pageStrings =
1673+ {
1674+ "F1",
1675+ "F2",
1676+ "F3",
1677+ "F4",
1678+ "F5",
1679+ "F6",
1680+ "F7",
1681+ "F8",
1682+ "F9",
1683+ "F10"
1684+ };
1685+
1686+ player.setPage(newPage);
1687+ player.sendPacket(new ExShowScreenMessage("Auto Farm Skill Bar " + pageStrings[newPage], 3 * 1000));
1688+ player.saveAutoFarmSettings();
1689+
1690+ }
1691+
1692+ }
1693+
1694+ }
1695+ catch (Exception e)
1696+ {
1697+ e.printStackTrace();
1698+ }
1699+ }
1700+
1701+ if (_command.startsWith("_enableBuffProtect"))
1702+ {
1703+ player.setNoBuffProtection(!player.isNoBuffProtected());
1704+ if (player.isNoBuffProtected())
1705+ {
1706+ player.sendPacket(new ExShowScreenMessage("Auto Farm Buff Protect On", 3 * 1000));
1707+ }
1708+ else
1709+ {
1710+ player.sendPacket(new ExShowScreenMessage("Auto Farm Buff Protect Off", 3 * 1000));
1711+ }
1712+ player.saveAutoFarmSettings();
1713+ }
1714+ if (_command.startsWith("_enableSummonAttack"))
1715+ {
1716+ player.setSummonAttack(!player.isSummonAttack());
1717+ if (player.isSummonAttack())
1718+ {
1719+ player.sendPacket(new SystemMessage(SystemMessageId.ACTIVATE_SUMMON_ACTACK));
1720+ player.sendPacket(new ExShowScreenMessage("Auto Farm Summon Attack On", 3 * 1000));
1721+ }
1722+ else
1723+ {
1724+ player.sendPacket(new SystemMessage(SystemMessageId.DESACTIVATE_SUMMON_ACTACK));
1725+ player.sendPacket(new ExShowScreenMessage("Auto Farm Summon Attack Off", 3 * 1000));
1726+ }
1727+ player.saveAutoFarmSettings();
1728+ }
1729+
1730+ else if (_command.startsWith("voiced_"))
1731+ {
1732+ String command = _command.split(" ")[0];
1733+
1734+ IVoicedCommandHandler ach = VoicedCommandHandler.getInstance().getVoicedCommandHandler(_command.substring(7));
1735+
1736+ if (ach == null)
1737+ {
1738+ player.sendMessage("The command " + command.substring(7) + " does not exist!");
1739+ PacketLogger.warning("No handler registered for command '" + _command + "'");
1740+ return;
1741+ }
1742+
1743+ ach.useVoicedCommand(_command.substring(7), player, null);
1744+ }
1745+
1746 else if (_command.equals("come_here") && player.isGM())
1747 {
1748 final WorldObject obj = player.getTarget();
1749diff --git java/org/l2jmobius/gameserver/network/serverpackets/Die.java java/org/l2jmobius/gameserver/network/serverpackets/Die.java
1750index ee75ca2..84358ae 100644
1751--- java/org/l2jmobius/gameserver/network/serverpackets/Die.java
1752+++ java/org/l2jmobius/gameserver/network/serverpackets/Die.java
1753@@ -27,6 +27,8 @@
1754 import org.l2jmobius.gameserver.model.siege.SiegeClan;
1755 import org.l2jmobius.gameserver.network.ServerPackets;
1756
1757+import Base.AutoFarm.AutofarmPlayerRoutine;
1758+
1759 public class Die extends ServerPacket
1760 {
1761 private final int _objectId;
1762@@ -43,9 +45,17 @@
1763 if (creature instanceof Player)
1764 {
1765 final Player player = creature.getActingPlayer();
1766+ final AutofarmPlayerRoutine bot = player.getBot();
1767 _allowFixedRes = player.getAccessLevel().allowFixedRes();
1768 _clan = player.getClan();
1769 _canTeleport = !player.isPendingRevive();
1770+
1771+ if (player.isAutoFarm())
1772+ {
1773+ bot.stop();
1774+ player.setAutoFarm(false);
1775+ }
1776+
1777 }
1778 _objectId = creature.getObjectId();
1779 _fake = !creature.isDead();
1780