Using Java ThreadPool + Mob Skills & Event Instance patch + Eqp Merge
Server source now uses Java ThreadPool, recycling used thread resources for next uses. Added Grenade visual effect for other players. Implemented an attempt towards unsynced mob behavior, where reportedly players were able to pin same mob in different sections of the map. Solved several deadlock issues, mostly regarding character synchronized methods, event instance scripts and player/item vision-unvision. Solved an issue where mobs would not cast some skills of it's skillset. Frequent behavior on low-leveled mobs. Fixed a bug on 2nd Maker quest where players could complete it by merely disassembling an equipment. New custom mechanic: equipment merge. Similarly to the Bazaar NPC, every equipment after the selected one is used up, and a fraction of their stat amounts are used as stat gains on the currently equipped items. If restrictions are enabled, players must be high-leveled and Maker lv3 to use it. Skill Storm Break no longer uses up arrows. Added a server flag to allow access for all Aran job skills from the beginning. Implemented Battleship and Super Transformation questline scripts. Fixed a desynchronization within pet position and cash inventory position, that could potentially lead to some inventory issues until relogin. Improved timestamp handling in some handler classes. Spam detection is entirely a server-side matter, hence removed usage of client-sided timestamp content. Refactored some pet response packets, improving some of their behaviors. Fixed some quest issues: Maker lv1 and Omega Sector meteorite one.
This commit is contained in:
@@ -102,7 +102,7 @@ public class PlayerStorage {
|
||||
for(MapleCharacter mc : chrList) {
|
||||
MapleClient client = mc.getClient();
|
||||
if(client != null) {
|
||||
client.disconnect(true, false);
|
||||
client.forceDisconnect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -85,8 +85,10 @@ import client.newyear.NewYearCardRecord;
|
||||
import constants.ItemConstants;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.util.TimeZone;
|
||||
import server.CashShop.CashItemFactory;
|
||||
import server.MapleSkillbookInformationProvider;
|
||||
import server.ThreadManager;
|
||||
import server.TimerManager;
|
||||
import server.life.MaplePlayerNPCFactory;
|
||||
import server.quest.MapleQuest;
|
||||
@@ -147,6 +149,10 @@ public class Server {
|
||||
private boolean online = false;
|
||||
public static long uptime = System.currentTimeMillis();
|
||||
|
||||
public int getCurrentTimestamp() {
|
||||
return (int) (Server.getInstance().getCurrentTime() - Server.uptime);
|
||||
}
|
||||
|
||||
public long getCurrentTime() { // returns a slightly delayed time value, under frequency of UPDATE_INTERVAL
|
||||
return serverCurrentTime;
|
||||
}
|
||||
@@ -825,6 +831,33 @@ public class Server {
|
||||
return rankSystem;
|
||||
}
|
||||
|
||||
private static void clearUnreferencedPetIds() {
|
||||
PreparedStatement ps = null;
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DatabaseConnection.getConnection();
|
||||
|
||||
ps = con.prepareStatement("UPDATE inventoryitems SET petid = -1, expiration = 0 WHERE petid != -1 AND petid NOT IN (SELECT petid FROM pets)");
|
||||
ps.executeUpdate();
|
||||
|
||||
ps.close();
|
||||
con.close();
|
||||
} catch(SQLException ex) {
|
||||
ex.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if(ps != null && !ps.isClosed()) {
|
||||
ps.close();
|
||||
}
|
||||
if(con != null && !con.isClosed()) {
|
||||
con.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void init() {
|
||||
Properties p = loadWorldINI();
|
||||
if(p == null) {
|
||||
@@ -832,11 +865,12 @@ public class Server {
|
||||
}
|
||||
|
||||
System.out.println("HeavenMS v" + ServerConstants.VERSION + " starting up.\r\n");
|
||||
|
||||
|
||||
if(ServerConstants.SHUTDOWNHOOK)
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(shutdown(false)));
|
||||
|
||||
TimeZone.setDefault(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
|
||||
Connection c = null;
|
||||
try {
|
||||
c = DatabaseConnection.getConnection();
|
||||
@@ -856,6 +890,7 @@ public class Server {
|
||||
sqle.printStackTrace();
|
||||
}
|
||||
|
||||
clearUnreferencedPetIds();
|
||||
MapleCashidGenerator.loadExistentCashIdsFromDb();
|
||||
|
||||
IoBuffer.setUseDirectBuffer(false);
|
||||
@@ -863,6 +898,7 @@ public class Server {
|
||||
acceptor = new NioSocketAcceptor();
|
||||
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));
|
||||
|
||||
ThreadManager.getInstance().start();
|
||||
TimerManager tMan = TimerManager.getInstance();
|
||||
tMan.start();
|
||||
tMan.register(tMan.purge(), ServerConstants.PURGING_INTERVAL);//Purging ftw...
|
||||
@@ -1716,6 +1752,7 @@ public class Server {
|
||||
|
||||
resetServerWorlds();
|
||||
|
||||
ThreadManager.getInstance().stop();
|
||||
TimerManager.getInstance().purge();
|
||||
TimerManager.getInstance().stop();
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ public class ThreadTracker {
|
||||
StackTraceElement[] ste = threads.get(l).getStackTrace();
|
||||
if(ste.length > 0) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
FilePrinter.print(FilePrinter.DEADLOCK_LOCKS, printThreadLog(tt, df));
|
||||
@@ -195,7 +195,7 @@ public class ThreadTracker {
|
||||
}
|
||||
} else { // print status
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
FilePrinter.printError(FilePrinter.DEADLOCK_STATE, printThreadTrackerState(dateFormat.format(new Date())));
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_STATE, "[" + dateFormat.format(new Date()) + "] Presenting current lock path for lockid " + lockId.name() + ".\r\n" + printLockStatus(lockId) + "\r\n-------------------------------\r\n");
|
||||
|
||||
@@ -62,7 +62,7 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
|
||||
@@ -64,7 +64,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
|
||||
@@ -60,7 +60,7 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement
|
||||
if(ServerConstants.USE_THREAD_TRACKER) {
|
||||
if(deadlockedState != null) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
|
||||
//FilePrinter.printError(FilePrinter.DEADLOCK_ERROR, "[CRITICAL] " + dateFormat.format(new Date()) + " Deadlock occurred when trying to use the '" + id.name() + "' lock resources:\r\n" + printStackTrace(deadlockedState) + "\r\n\r\n");
|
||||
ThreadTracker.getInstance().accessThreadTracker(true, true, id, hashcode);
|
||||
|
||||
@@ -41,7 +41,7 @@ public class EmptyReadLock implements MonitoredReadLock {
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
|
||||
@@ -41,7 +41,7 @@ public class EmptyReentrantLock implements MonitoredReentrantLock {
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
|
||||
@@ -41,7 +41,7 @@ public class EmptyWriteLock implements MonitoredWriteLock {
|
||||
|
||||
private static String printThreadStack(StackTraceElement[] list) {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
|
||||
dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE));
|
||||
dateFormat.setTimeZone(TimeZone.getDefault());
|
||||
String df = dateFormat.format(new Date());
|
||||
|
||||
String s = "\r\n" + df + "\r\n";
|
||||
|
||||
@@ -259,8 +259,9 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
else if(attack.skill == Shadower.BOOMERANG_STEP)
|
||||
distanceToDetect += 60000;
|
||||
|
||||
if(distance > distanceToDetect) {
|
||||
if (distance > distanceToDetect) {
|
||||
AutobanFactory.DISTANCE_HACK.alert(player, "Distance Sq to monster: " + distance + " SID: " + attack.skill + " MID: " + monster.getId());
|
||||
monster.refreshMobPosition();
|
||||
}
|
||||
|
||||
int totDamageToOneMonster = 0;
|
||||
@@ -338,7 +339,7 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
}
|
||||
}
|
||||
|
||||
if (job == 2111 || job == 2112) {
|
||||
if (player.isAran()) {
|
||||
if (player.getBuffedValue(MapleBuffStat.WK_CHARGE) != null) {
|
||||
Skill snowCharge = SkillFactory.getSkill(Aran.SNOW_CHARGE);
|
||||
if (totDamageToOneMonster > 0) {
|
||||
|
||||
@@ -26,6 +26,7 @@ import net.AbstractMaplePacketHandler;
|
||||
import server.life.MapleMonster;
|
||||
import server.maps.MapleMap;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleCharacter;
|
||||
|
||||
public final class AutoAggroHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@@ -38,18 +39,26 @@ public final class AutoAggroHandler extends AbstractMaplePacketHandler {
|
||||
int oid = slea.readInt();
|
||||
|
||||
MapleMonster monster = map.getMonsterByOid(oid);
|
||||
if (monster != null && monster.getController() != null) {
|
||||
if (!monster.isControllerHasAggro()) {
|
||||
if (map.getCharacterById(monster.getController().getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
if (monster != null) {
|
||||
MapleCharacter currentController = monster.getController();
|
||||
monster.lockMonster();
|
||||
try {
|
||||
if (currentController != null) {
|
||||
if (!monster.isControllerHasAggro()) {
|
||||
if (map.getCharacterById(currentController.getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
} else {
|
||||
monster.switchController(currentController, true);
|
||||
}
|
||||
} else if (map.getCharacterById(currentController.getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
}
|
||||
} else {
|
||||
monster.switchController(monster.getController(), true);
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
}
|
||||
} else if (map.getCharacterById(monster.getController().getId()) == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
} else if (monster != null && monster.getController() == null) {
|
||||
monster.switchController(c.getPlayer(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import net.AbstractMaplePacketHandler;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleClient;
|
||||
import client.autoban.AutobanFactory;
|
||||
import net.server.Server;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -35,7 +36,8 @@ public final class ChangeChannelHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
int channel = slea.readByte() + 1;
|
||||
c.getPlayer().getAutobanManager().setTimestamp(6, slea.readInt(), 2);
|
||||
slea.readInt();
|
||||
c.getPlayer().getAutobanManager().setTimestamp(6, Server.getInstance().getCurrentTimestamp(), 3);
|
||||
if(c.getChannel() == channel) {
|
||||
AutobanFactory.GENERAL.alert(c.getPlayer(), "CCing to same channel.");
|
||||
c.disconnect(false, false);
|
||||
|
||||
57
src/net/server/channel/handlers/GrenadeEffectHandler.java
Normal file
57
src/net/server/channel/handlers/GrenadeEffectHandler.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server
|
||||
Copyleft (L) 2016 - 2018 RonanLana
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation version 3 as published by
|
||||
the Free Software Foundation. You may not use, modify or distribute
|
||||
this program under any other version of the GNU Affero General Public
|
||||
License.
|
||||
|
||||
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 Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import constants.skills.Gunslinger;
|
||||
import constants.skills.NightWalker;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import java.awt.Point;
|
||||
import tools.FilePrinter;
|
||||
|
||||
/*
|
||||
* @author GabrielSin
|
||||
*/
|
||||
public class GrenadeEffectHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
Point position = new Point(slea.readInt(), slea.readInt());
|
||||
int keyDown = slea.readInt();
|
||||
int skillId = slea.readInt();
|
||||
|
||||
switch (skillId) {
|
||||
case NightWalker.POISON_BOMB:
|
||||
case Gunslinger.GRENADE:
|
||||
int skillLevel = chr.getSkillLevel(skillId);
|
||||
if (skillLevel > 0) {
|
||||
chr.getMap().broadcastMessage(chr, MaplePacketCreator.throwGrenade(chr.getId(), position, keyDown, skillId, skillLevel), position);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
FilePrinter.printError(FilePrinter.UNHANDLED_EVENT, "The skill id: " + skillId + " is not coded in " + this.getClass().getName() + ".");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,12 +38,12 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
if(!chr.isLoggedinWorld()) return;
|
||||
|
||||
AutobanManager abm = chr.getAutobanManager();
|
||||
int timestamp = (int) (Server.getInstance().getCurrentTime() - Server.uptime);
|
||||
int timestamp = Server.getInstance().getCurrentTimestamp();
|
||||
slea.skip(8);
|
||||
|
||||
short healHP = slea.readShort();
|
||||
if (healHP != 0) {
|
||||
abm.setTimestamp(8, timestamp, 3); // thanks Vcoc for pointing out d/c happening here
|
||||
abm.setTimestamp(8, timestamp, 4); // thanks Vcoc for pointing out d/c happening here
|
||||
if ((abm.getLastSpam(0) + 1500) > timestamp) AutobanFactory.FAST_HP_HEALING.addPoint(abm, "Fast hp healing");
|
||||
|
||||
int abHeal = 120 + (int)(20 * MapleMapFactory.getMapRecoveryRate(chr.getMapId())); // Sleepywood sauna and showa spa...
|
||||
@@ -58,7 +58,7 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
short healMP = slea.readShort();
|
||||
if (healMP != 0 && healMP < 1000) {
|
||||
abm.setTimestamp(9, timestamp, 3);
|
||||
abm.setTimestamp(9, timestamp, 4);
|
||||
if ((abm.getLastSpam(1) + 1500) > timestamp) AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
|
||||
chr.addMP(healMP);
|
||||
abm.spam(1, timestamp);
|
||||
|
||||
@@ -31,6 +31,7 @@ import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import net.server.Server;
|
||||
import server.MapleItemInformationProvider;
|
||||
|
||||
public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
|
||||
@@ -38,7 +39,8 @@ public final class InventoryMergeHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(2, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
chr.getAutobanManager().setTimestamp(2, Server.getInstance().getCurrentTimestamp(), 4);
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
@@ -24,7 +24,6 @@ package net.server.channel.handlers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
@@ -35,7 +34,9 @@ import client.inventory.Equip;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.ModifyInventory;
|
||||
import constants.ServerConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import net.server.Server;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -187,7 +188,8 @@ public final class InventorySortHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(3, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
chr.getAutobanManager().setTimestamp(3, Server.getInstance().getCurrentTimestamp(), 4);
|
||||
|
||||
if(!ServerConstants.USE_ITEM_SORT) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
|
||||
@@ -61,7 +61,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
}
|
||||
|
||||
MapleMonster monster = (MapleMonster) mmo;
|
||||
List<MapleCharacter> banishPlayers = new LinkedList<>();
|
||||
List<MapleCharacter> banishPlayers = null;
|
||||
|
||||
byte pNibbles = slea.readByte();
|
||||
byte rawActivity = slea.readByte();
|
||||
@@ -70,7 +70,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
short pOption = slea.readShort();
|
||||
slea.skip(8);
|
||||
|
||||
if (rawActivity >= 0) {
|
||||
if (rawActivity >= 0) {
|
||||
rawActivity = (byte) (rawActivity & 0xFF >> 1);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
boolean isSkill = inRangeInclusive(rawActivity, 21, 25);
|
||||
|
||||
byte attackId = (byte) (isAttack ? rawActivity - 12 : -1);
|
||||
boolean nextMovementCouldBeSkill = (pNibbles & 0x0F) != 0;
|
||||
isSkill |= (pNibbles != 0);
|
||||
|
||||
boolean nextMovementCouldBeSkill = true;
|
||||
boolean pUnk = (pNibbles & 0xF0) != 0;
|
||||
|
||||
boolean currentController = (monster.getController() == player);
|
||||
@@ -86,6 +88,7 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
MobSkill toUse = null;
|
||||
int useSkillId = 0, useSkillLevel = 0;
|
||||
|
||||
int rnd = 0;
|
||||
if (isSkill) {
|
||||
int noSkills = monster.getNoSkills();
|
||||
if (noSkills > 0) {
|
||||
@@ -95,21 +98,21 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
useSkillId = skillToUse.getLeft();
|
||||
useSkillLevel = skillToUse.getRight();
|
||||
toUse = MobSkillFactory.getMobSkill(useSkillId, useSkillLevel);
|
||||
} else {
|
||||
|
||||
rnd = rndSkill;
|
||||
nextMovementCouldBeSkill = false;
|
||||
}
|
||||
} else {
|
||||
nextMovementCouldBeSkill = false;
|
||||
}
|
||||
|
||||
int mobMp;
|
||||
if (toUse != null && toUse.getHP() >= (int) (((float) monster.getHp() / monster.getMaxHp()) * 100) && monster.canUseSkill(toUse)) {
|
||||
mobMp = monster.getMp();
|
||||
|
||||
|
||||
int animationTime = MapleMonsterInformationProvider.getInstance().getMobSkillAnimationTime(toUse);
|
||||
if(animationTime > 0) {
|
||||
toUse.applyDelayedEffect(player, monster, true, banishPlayers, animationTime);
|
||||
if(animationTime > 0 && toUse.getSkillId() != 129) {
|
||||
toUse.applyDelayedEffect(player, monster, true, animationTime);
|
||||
} else {
|
||||
banishPlayers = new LinkedList<>();
|
||||
toUse.applyEffect(player, monster, true, banishPlayers);
|
||||
}
|
||||
} else {
|
||||
@@ -138,36 +141,45 @@ public final class MoveLifeHandler extends AbstractMovementPacketHandler {
|
||||
short start_y = slea.readShort(); // hmm...
|
||||
Point startPos = new Point(start_x, start_y - 2);
|
||||
List<LifeMovementFragment> res = parseMovement(slea);
|
||||
if (!currentController) {
|
||||
if (monster.isAttackedBy(player)) {
|
||||
monster.switchController(player, true);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (rawActivity == -1 && monster.isControllerKnowsAboutAggro() && !monster.isMobile() && !monster.isFirstAttack()) {
|
||||
monster.setControllerHasAggro(false);
|
||||
monster.setControllerKnowsAboutAggro(false);
|
||||
}
|
||||
|
||||
boolean aggro;
|
||||
monster.lockMonster();
|
||||
try {
|
||||
if (!currentController) {
|
||||
if (monster.isAttackedBy(player)) {
|
||||
monster.switchController(player, true);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else if (rawActivity == -1 && monster.isControllerKnowsAboutAggro() && !monster.isMobile() && !monster.isFirstAttack()) {
|
||||
monster.setControllerHasAggro(false);
|
||||
monster.setControllerKnowsAboutAggro(false);
|
||||
}
|
||||
|
||||
aggro = monster.isControllerHasAggro();
|
||||
if (aggro) {
|
||||
monster.setControllerKnowsAboutAggro(true);
|
||||
}
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
|
||||
boolean aggro = monster.isControllerHasAggro();
|
||||
if (toUse != null) {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro, toUse.getSkillId(), toUse.getSkillLevel()));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.moveMonsterResponse(objectid, moveid, mobMp, aggro));
|
||||
}
|
||||
|
||||
if (aggro) {
|
||||
monster.setControllerKnowsAboutAggro(true);
|
||||
}
|
||||
|
||||
if (res != null) {
|
||||
map.broadcastMessage(player, MaplePacketCreator.moveMonster(objectid, nextMovementCouldBeSkill, rawActivity, useSkillId, useSkillLevel, pOption, startPos, res), monster.getPosition());
|
||||
updatePosition(res, monster, -2);
|
||||
map.moveMonster(monster, monster.getPosition());
|
||||
}
|
||||
|
||||
for (MapleCharacter chr : banishPlayers) {
|
||||
chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
|
||||
if (banishPlayers != null) {
|
||||
for (MapleCharacter chr : banishPlayers) {
|
||||
chr.changeMapBanish(monster.getBanish().getMap(), monster.getBanish().getPortal(), monster.getBanish().getMsg());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,9 @@ public final class PetCommandHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (Randomizer.nextInt(101) <= petCommand.getProbability()) {
|
||||
pet.gainClosenessFullness(chr, petCommand.getIncrease(), 0, command);
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, false, command, false));
|
||||
} else {
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, command, false));
|
||||
chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, true, command, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
*/
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.MapleInventory;
|
||||
@@ -28,8 +29,8 @@ import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import client.autoban.AutobanManager;
|
||||
import client.inventory.Item;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import net.server.Server;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -44,7 +45,8 @@ public final class PetFoodHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
abm.spam(2);
|
||||
abm.setTimestamp(1, slea.readInt(), 3);
|
||||
slea.readInt(); // timestamp issue detected thanks to Masterrulax
|
||||
abm.setTimestamp(1, Server.getInstance().getCurrentTimestamp(), 3);
|
||||
if (chr.getNoPets() == 0) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
|
||||
@@ -163,7 +163,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean soulArrow = chr.getBuffedValue(MapleBuffStat.SOULARROW) != null;
|
||||
boolean shadowClaw = chr.getBuffedValue(MapleBuffStat.SHADOW_CLAW) != null;
|
||||
if (projectile != 0) {
|
||||
@@ -179,7 +179,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
if (projectile != 0 || soulArrow || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 4111004) {
|
||||
if (projectile != 0 || soulArrow || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 4111004 || attack.skill == 13101005) {
|
||||
int visProjectile = projectile; //visible projectile sent to players
|
||||
if (ItemConstants.isThrowingStar(projectile)) {
|
||||
MapleInventory cash = chr.getInventory(MapleInventoryType.CASH);
|
||||
@@ -192,7 +192,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (soulArrow || attack.skill == 3111004 || attack.skill == 3211004 || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006) {
|
||||
} else if (soulArrow || attack.skill == 3111004 || attack.skill == 3211004 || attack.skill == 11101004 || attack.skill == 15111007 || attack.skill == 14101006 || attack.skill == 13101005) {
|
||||
visProjectile = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public final class ScriptedItemHandler extends AbstractMaplePacketHandler {
|
||||
if (item == null || item.getItemId() != itemId || item.getQuantity() < 1 || !ism.scriptExists(info.getScript())) {
|
||||
return;
|
||||
}
|
||||
ism.getItemScript(c, info.getScript());
|
||||
ism.runItemScript(c, info.getScript());
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
//NPCScriptManager.getInstance().start(c, info.getNpc(), null, null);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.MapleStat;
|
||||
import client.Skill;
|
||||
import client.SkillFactory;
|
||||
import constants.ServerConstants;
|
||||
@@ -41,14 +40,15 @@ import constants.skills.Hero;
|
||||
import constants.skills.Paladin;
|
||||
import constants.skills.Priest;
|
||||
import constants.skills.SuperGM;
|
||||
|
||||
import net.server.Server;
|
||||
|
||||
public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
chr.getAutobanManager().setTimestamp(4, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
chr.getAutobanManager().setTimestamp(4, Server.getInstance().getCurrentTimestamp(), 5);
|
||||
int skillid = slea.readInt();
|
||||
|
||||
/*
|
||||
@@ -99,9 +99,14 @@ public final class SpecialMoveHandler extends AbstractMaplePacketHandler {
|
||||
chr.getMap().broadcastMessage(chr, MaplePacketCreator.showMagnet(mobId, success), false);
|
||||
MapleMonster monster = chr.getMap().getMonsterByOid(mobId);
|
||||
if (monster != null) {
|
||||
if (!monster.isBoss()) {
|
||||
monster.switchController(chr, monster.isControllerHasAggro());
|
||||
}
|
||||
if (!monster.isBoss()) {
|
||||
monster.lockMonster();
|
||||
try {
|
||||
monster.switchController(chr, monster.isControllerHasAggro());
|
||||
} finally {
|
||||
monster.unlockMonster();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
byte direction = slea.readByte();
|
||||
|
||||
@@ -32,6 +32,8 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
* @author Generic
|
||||
*/
|
||||
public final class TouchReactorHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
int oid = slea.readInt();
|
||||
MapleReactor reactor = c.getPlayer().getMap().getReactorByOid(oid);
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.inventory.MapleInventoryType;
|
||||
import client.autoban.AutobanManager;
|
||||
import constants.ItemConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import server.life.MapleMonster;
|
||||
import tools.MaplePacketCreator;
|
||||
@@ -41,7 +42,8 @@ public final class UseCatchItemHandler extends AbstractMaplePacketHandler {
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
AutobanManager abm = chr.getAutobanManager();
|
||||
abm.setTimestamp(5, slea.readInt(), 3);
|
||||
slea.readInt();
|
||||
abm.setTimestamp(5, Server.getInstance().getCurrentTimestamp(), 4);
|
||||
slea.readShort();
|
||||
int itemId = slea.readInt();
|
||||
int monsterid = slea.readInt();
|
||||
|
||||
@@ -35,7 +35,6 @@ import constants.GameConstants;
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
|
||||
public final class UseOwlOfMinervaHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1402,7 +1402,9 @@ public class World {
|
||||
|
||||
int dpVal = dp.getValue() + 1;
|
||||
if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) {
|
||||
chr.runTirednessSchedule();
|
||||
if (!chr.runTirednessSchedule()) {
|
||||
continue;
|
||||
}
|
||||
dpVal = 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user