Reactor Loot + Obstacles damage mob + Static calls from scripts
Revised starting AP, now working out with flags. To supply the 9AP shortage of 4/4/4/4, two options: one giving out 9 AP from the start, other giving 4/5 AP when changing jobs (1st, 2nd). This change would also work with the autoassign for beginners flag. Refactored several quest scripts, that would be glitching the player when doing quest start/complete and disposing under the same script status. Cleared some cases with the quest reward system where it would call out a "full inventory" even though new inventory slots could get discovered when doing the quest loot transaction. Fixed an issue with player stores being deployed overlapping in a few scenarios. Fixed reduced EXP gain from kills when triggering skill Mortal Blow. Added "open Duey" functionality when clicking "O" in the incoming package notification. Fixed packages without messages (a quirk from quick delivery) not accounting visually as a "quick" one. Fixed certain mounts (non-item skill mounts, such as Yeti or Spaceship) not showing up properly to other players when changing maps. Added handler for mob damage by environment objects (OrbisPQ jail storage area). Added a placeholder on mob's stolen items to prevent more steals to be placed as soon as the Steal mechanism is triggered. Patched boss logs not removing recent entries from the DB tables (the reset method is actually supposed to clear every entry). Revised a possible memory leak scenario happening due to an exception thrown midway monster kill method. Improved reactor drops, now placing loots visible for the acting player centered (similar as to how mob loots work). Refactored several issues in scripts, related to accessing static Java methods through an object, that would start appearing after transitioning to Java 8.
This commit is contained in:
@@ -168,6 +168,7 @@ import server.maps.MapleMapItem;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import org.apache.mina.util.ConcurrentHashSet;
|
||||
import scripting.quest.QuestActionManager;
|
||||
import server.maps.FieldLimit;
|
||||
|
||||
public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
@@ -305,6 +306,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private List<Integer> viptrockmaps = new ArrayList<>();
|
||||
private Map<String, MapleEvents> events = new LinkedHashMap<>();
|
||||
private PartyQuest partyQuest = null;
|
||||
private List<Pair<DelayedQuestUpdate, Object[]>> npcUpdateQuests = new LinkedList<>();
|
||||
private MapleDragon dragon = null;
|
||||
private MapleRing marriageRing;
|
||||
private int marriageItemid = -1;
|
||||
@@ -1173,7 +1175,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
if (this.isCygnus()) {
|
||||
gainAp(7, true);
|
||||
} else {
|
||||
gainAp(5, true);
|
||||
if (ServerConstants.USE_STARTING_AP_4 || newJob.getId() % 10 >= 1) {
|
||||
gainAp(5, true);
|
||||
}
|
||||
}
|
||||
} else { // thanks Periwinks for noticing an AP shortage from lower levels
|
||||
if (ServerConstants.USE_STARTING_AP_4 && newJob.getId() % 1000 >= 1) {
|
||||
gainAp(4, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3877,10 +3885,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
List<Pair<MapleBuffStat, MapleBuffStatValueHolder>> toCancel = deregisterBuffStats(buffstats);
|
||||
if (effect.isMonsterRiding()) {
|
||||
if (effect.getSourceId() != Corsair.BATTLE_SHIP) {
|
||||
this.getClient().getWorldServer().unregisterMountHunger(this);
|
||||
this.getMount().setActive(false);
|
||||
}
|
||||
this.getClient().getWorldServer().unregisterMountHunger(this);
|
||||
this.getMount().setActive(false);
|
||||
}
|
||||
|
||||
if (!overwrite) {
|
||||
@@ -6168,7 +6174,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
spGain += (expectedSp - curSp);
|
||||
}
|
||||
|
||||
return getSpGain(spGain, curSp, job);
|
||||
return getSpGain(spGain, curSp, newJob);
|
||||
}
|
||||
|
||||
private int getUsedSp(MapleJob job) {
|
||||
@@ -7391,7 +7397,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
continue;
|
||||
}
|
||||
if (q.progress(id)) {
|
||||
client.announce(MaplePacketCreator.updateQuest(q, false));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7400,8 +7406,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
}
|
||||
|
||||
public void mount(int id, int skillid) {
|
||||
public MapleMount mount(int id, int skillid) {
|
||||
maplemount = new MapleMount(this, id, skillid);
|
||||
return maplemount;
|
||||
}
|
||||
|
||||
private void playerDead() {
|
||||
@@ -9632,9 +9639,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
quests.put(q.getId(), qs);
|
||||
}
|
||||
|
||||
announce(MaplePacketCreator.updateQuest(qs, false));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, false);
|
||||
if (qs.getQuest().getInfoNumber() > 0) {
|
||||
announce(MaplePacketCreator.updateQuest(qs, true));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, qs, true);
|
||||
}
|
||||
announce(MaplePacketCreator.updateQuestInfo((short) qs.getQuest().getId(), qs.getNpc()));
|
||||
}
|
||||
@@ -9657,14 +9664,61 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
}
|
||||
|
||||
public enum DelayedQuestUpdate { // quest updates allow player actions during NPC talk...
|
||||
UPDATE, FORFEIT, COMPLETE
|
||||
}
|
||||
|
||||
private void announceUpdateQuestInternal(Pair<DelayedQuestUpdate, Object[]> questUpdate) {
|
||||
Object[] objs = questUpdate.getRight();
|
||||
|
||||
switch (questUpdate.getLeft()) {
|
||||
case UPDATE:
|
||||
announce(MaplePacketCreator.updateQuest((MapleQuestStatus) objs[0], (Boolean) objs[1]));
|
||||
break;
|
||||
|
||||
case FORFEIT:
|
||||
announce(MaplePacketCreator.forfeitQuest((Short) objs[0]));
|
||||
break;
|
||||
|
||||
case COMPLETE:
|
||||
announce(MaplePacketCreator.completeQuest((Short) objs[0], (Long) objs[1]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void announceUpdateQuest(DelayedQuestUpdate questUpdateType, Object... params) {
|
||||
Pair<DelayedQuestUpdate, Object[]> p = new Pair<>(questUpdateType, params);
|
||||
MapleClient c = this.getClient();
|
||||
if (c.getQM() != null || c.getCM() != null) {
|
||||
synchronized (npcUpdateQuests) {
|
||||
npcUpdateQuests.add(p);
|
||||
}
|
||||
} else {
|
||||
announceUpdateQuestInternal(p);
|
||||
}
|
||||
}
|
||||
|
||||
public void flushDelayedUpdateQuests() {
|
||||
List<Pair<DelayedQuestUpdate, Object[]>> qmQuestUpdateList;
|
||||
|
||||
synchronized (npcUpdateQuests) {
|
||||
qmQuestUpdateList = new ArrayList<>(npcUpdateQuests);
|
||||
npcUpdateQuests.clear();
|
||||
}
|
||||
|
||||
for (Pair<DelayedQuestUpdate, Object[]> q : qmQuestUpdateList) {
|
||||
announceUpdateQuestInternal(q);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateQuest(MapleQuestStatus quest) {
|
||||
synchronized (quests) {
|
||||
quests.put(quest.getQuestID(), quest);
|
||||
}
|
||||
if (quest.getStatus().equals(MapleQuestStatus.Status.STARTED)) {
|
||||
announce(MaplePacketCreator.updateQuest(quest, false));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, false);
|
||||
if (quest.getQuest().getInfoNumber() > 0) {
|
||||
announce(MaplePacketCreator.updateQuest(quest, true));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, true);
|
||||
}
|
||||
announce(MaplePacketCreator.updateQuestInfo((short) quest.getQuest().getId(), quest.getNpc()));
|
||||
} else if (quest.getStatus().equals(MapleQuestStatus.Status.COMPLETED)) {
|
||||
@@ -9675,11 +9729,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
quest.setCompleted(quest.getCompleted() + 1); // count quest completed Jayd's idea
|
||||
|
||||
announce(MaplePacketCreator.completeQuest(questid, quest.getCompletionTime()));
|
||||
announceUpdateQuest(DelayedQuestUpdate.COMPLETE, questid, quest.getCompletionTime());
|
||||
} else if (quest.getStatus().equals(MapleQuestStatus.Status.NOT_STARTED)) {
|
||||
announce(MaplePacketCreator.updateQuest(quest, false));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, false);
|
||||
if (quest.getQuest().getInfoNumber() > 0) {
|
||||
announce(MaplePacketCreator.updateQuest(quest, true));
|
||||
announceUpdateQuest(DelayedQuestUpdate.UPDATE, quest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import client.MapleJob;
|
||||
import client.Skill;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.ServerConstants;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
@@ -39,7 +40,7 @@ public class CharacterFactoryRecipe {
|
||||
private int level, map, top, bottom, shoes, weapon;
|
||||
private int str = 4, dex = 4, int_ = 4, luk = 4;
|
||||
private int maxHp = 50, maxMp = 5;
|
||||
private int ap = 9, sp = 0;
|
||||
private int ap = 0, sp = 0;
|
||||
private int meso = 0;
|
||||
private List<Pair<Skill, Integer>> skills = new LinkedList<>();
|
||||
|
||||
@@ -54,6 +55,15 @@ public class CharacterFactoryRecipe {
|
||||
this.bottom = bottom;
|
||||
this.shoes = shoes;
|
||||
this.weapon = weapon;
|
||||
|
||||
if (!ServerConstants.USE_STARTING_AP_4) {
|
||||
if (ServerConstants.USE_AUTOASSIGN_STARTERS_AP) {
|
||||
str = 12;
|
||||
dex = 5;
|
||||
} else {
|
||||
ap = 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setStr(int v) {
|
||||
|
||||
@@ -60,6 +60,7 @@ import tools.Pair;
|
||||
public class DueyProcessor {
|
||||
|
||||
public enum Actions {
|
||||
TOSERVER_RECV_ITEM(0x00),
|
||||
TOSERVER_SEND_ITEM(0x02),
|
||||
TOSERVER_CLAIM_PACKAGE(0x04),
|
||||
TOSERVER_REMOVE_PACKAGE(0x05),
|
||||
@@ -113,15 +114,6 @@ public class DueyProcessor {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Timestamp getCurrentDate(boolean quick) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
if (!quick) {
|
||||
cal.add(Calendar.DATE, 1);
|
||||
}
|
||||
|
||||
return new Timestamp(cal.getTime().getTime());
|
||||
}
|
||||
|
||||
private static void showDueyNotification(MapleClient c, MapleCharacter player) {
|
||||
Connection con = null;
|
||||
PreparedStatement ps = null;
|
||||
@@ -204,7 +196,7 @@ public class DueyProcessor {
|
||||
|
||||
dueypack.setSender(rs.getString("SenderName"));
|
||||
dueypack.setMesos(rs.getInt("Mesos"));
|
||||
dueypack.setSentTime(rs.getTimestamp("TimeStamp"));
|
||||
dueypack.setSentTime(rs.getTimestamp("TimeStamp"), rs.getBoolean("Type"));
|
||||
dueypack.setMessage(rs.getString("Message"));
|
||||
|
||||
return dueypack;
|
||||
@@ -250,7 +242,7 @@ public class DueyProcessor {
|
||||
ps.setInt(1, toCid);
|
||||
ps.setString(2, sender);
|
||||
ps.setInt(3, mesos);
|
||||
ps.setTimestamp(4, getCurrentDate(quick));
|
||||
ps.setTimestamp(4, new Timestamp(System.currentTimeMillis()));
|
||||
ps.setString(5, message);
|
||||
ps.setInt(6, quick ? 1 : 0);
|
||||
|
||||
@@ -515,7 +507,11 @@ public class DueyProcessor {
|
||||
}
|
||||
c.getPlayer().setNpcCooldown(timeNow);
|
||||
|
||||
c.announce(MaplePacketCreator.sendDuey(quickDelivery ? 0x1A : 0x8, loadPackages(c.getPlayer())));
|
||||
if (quickDelivery) {
|
||||
c.announce(MaplePacketCreator.sendDuey(0x1A, null));
|
||||
} else {
|
||||
c.announce(MaplePacketCreator.sendDuey(0x8, loadPackages(c.getPlayer())));
|
||||
}
|
||||
} finally {
|
||||
c.releaseClient();
|
||||
}
|
||||
@@ -523,7 +519,7 @@ public class DueyProcessor {
|
||||
}
|
||||
|
||||
public static void dueyCreatePackage(Item item, int mesos, String sender, int recipientCid) {
|
||||
int packageId = createPackage(mesos, "", sender, recipientCid, false);
|
||||
int packageId = createPackage(mesos, null, sender, recipientCid, false);
|
||||
if (packageId != -1) {
|
||||
insertPackageItem(packageId, item);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,16 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import client.MapleJob;
|
||||
import constants.skills.Aran;
|
||||
import java.io.File;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataDirectoryEntry;
|
||||
import provider.MapleDataFileEntry;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
import provider.MapleDataTool;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.FieldLimit;
|
||||
import server.quest.MapleQuest;
|
||||
@@ -38,6 +45,8 @@ public class GameConstants {
|
||||
public static final MapleDisease[] CPQ_DISEASES = {MapleDisease.SLOW, MapleDisease.SEDUCE, MapleDisease.STUN, MapleDisease.POISON,
|
||||
MapleDisease.SEAL, MapleDisease.DARKNESS, MapleDisease.WEAKEN, MapleDisease.CURSE};
|
||||
|
||||
public static final int MAX_FIELD_MOB_DAMAGE = getMaxObstacleMobDamageFromWz() * 2;
|
||||
|
||||
public static int getPlayerBonusDropRate(int slot) {
|
||||
return(DROP_RATE_GAIN[slot]);
|
||||
}
|
||||
@@ -672,4 +681,32 @@ public class GameConstants {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getMaxObstacleMobDamageFromWz() {
|
||||
MapleDataProvider mapSource = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Map.wz"));
|
||||
int maxMobDmg = 0;
|
||||
|
||||
MapleDataDirectoryEntry root = mapSource.getRoot();
|
||||
for (MapleDataDirectoryEntry objData : root.getSubdirectories()) {
|
||||
if (!objData.getName().contentEquals("Obj")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (MapleDataFileEntry obj : objData.getFiles()) {
|
||||
for (MapleData l0 : mapSource.getData(objData.getName() + "/" + obj.getName()).getChildren()) {
|
||||
for (MapleData l1 : l0.getChildren()) {
|
||||
for (MapleData l2 : l1.getChildren()) {
|
||||
int objDmg = MapleDataTool.getIntConvert("s1/mobdamage", l2, 0);
|
||||
if (maxMobDmg < objDmg) {
|
||||
maxMobDmg = objDmg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxMobDmg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ public class ServerConstants {
|
||||
public static final boolean USE_PARTY_FOR_STARTERS = true; //Players level 10 or below can create/invite other players on the given level range.
|
||||
public static final boolean USE_AUTOASSIGN_STARTERS_AP = false; //Beginners level 10 or below have their AP autoassigned (they can't choose to levelup a stat). Set true ONLY if the localhost doesn't support AP assigning for beginners level 10 or below.
|
||||
public static final boolean USE_AUTOASSIGN_SECONDARY_CAP = true;//Prevents AP autoassign from spending on secondary stats after the player class' cap (defined on the autoassign handler) has been reached.
|
||||
public static final boolean USE_STARTING_AP_4 = true; //Use early-GMS 4/4/4/4 starting stats. To overcome AP shortage, this gives 4AP/5AP at 1st/2nd job advancements.
|
||||
public static final boolean USE_AUTOBAN = false; //Commands the server to detect infractors automatically.
|
||||
public static final boolean USE_AUTOBAN_LOG = true; //Log autoban related messages. Still logs even with USE_AUTOBAN disabled.
|
||||
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
|
||||
|
||||
@@ -245,6 +245,7 @@ public final class PacketProcessor {
|
||||
registerHandler(RecvOpcode.PLAYER_MAP_TRANSFER, new PlayerMapTransitionHandler());
|
||||
registerHandler(RecvOpcode.USE_MAPLELIFE, new UseMapleLifeHandler());
|
||||
registerHandler(RecvOpcode.USE_CATCH_ITEM, new UseCatchItemHandler());
|
||||
registerHandler(RecvOpcode.FIELD_DAMAGE_MOB, new FieldDamageMobHandler());
|
||||
registerHandler(RecvOpcode.MOB_DAMAGE_MOB_FRIENDLY, new MobDamageMobFriendlyHandler());
|
||||
registerHandler(RecvOpcode.PARTY_SEARCH_REGISTER, new PartySearchRegisterHandler());
|
||||
registerHandler(RecvOpcode.PARTY_SEARCH_START, new PartySearchStartHandler());
|
||||
|
||||
@@ -170,6 +170,7 @@ public enum RecvOpcode {
|
||||
MOVE_DRAGON(0xB5),
|
||||
MOVE_LIFE(0xBC),
|
||||
AUTO_AGGRO(0xBD),
|
||||
FIELD_DAMAGE_MOB(0xBF),
|
||||
MOB_DAMAGE_MOB_FRIENDLY(0xC0),
|
||||
MONSTER_BOMB(0xC1),
|
||||
MOB_DAMAGE_MOB(0xC2),
|
||||
|
||||
@@ -1868,12 +1868,12 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
resetServerWorlds();
|
||||
|
||||
ThreadManager.getInstance().stop();
|
||||
TimerManager.getInstance().purge();
|
||||
TimerManager.getInstance().stop();
|
||||
|
||||
|
||||
resetServerWorlds();
|
||||
|
||||
System.out.println("Worlds + Channels are offline.");
|
||||
acceptor.unbind();
|
||||
acceptor = null;
|
||||
|
||||
@@ -321,8 +321,9 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
Skill steal = SkillFactory.getSkill(Bandit.STEAL);
|
||||
if (monster.getStolen().size() < 1) { // One steal per mob <3
|
||||
if (steal.getEffect(player.getSkillLevel(steal)).makeChanceResult()) {
|
||||
MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
|
||||
monster.addStolen(0);
|
||||
|
||||
MapleMonsterInformationProvider mi = MapleMonsterInformationProvider.getInstance();
|
||||
List<Integer> dropPool = mi.retrieveDropPool(monster.getId());
|
||||
if(!dropPool.isEmpty()) {
|
||||
Integer rndPool = (int) Math.floor(Math.random() * dropPool.get(dropPool.size() - 1));
|
||||
@@ -441,11 +442,13 @@ public abstract class AbstractDealDamageHandler extends AbstractMaplePacketHandl
|
||||
} else {
|
||||
mortalBlow = SkillFactory.getSkill(Sniper.MORTAL_BLOW);
|
||||
}
|
||||
if (player.getSkillLevel(mortalBlow) > 0) {
|
||||
MapleStatEffect mortal = mortalBlow.getEffect(player.getSkillLevel(mortalBlow));
|
||||
|
||||
int skillLevel = player.getSkillLevel(mortalBlow);
|
||||
if (skillLevel > 0) {
|
||||
MapleStatEffect mortal = mortalBlow.getEffect(skillLevel);
|
||||
if (monster.getHp() <= (monster.getStats().getHp() * mortal.getX()) / 100) {
|
||||
if (Randomizer.rand(1, 100) <= mortal.getY()) {
|
||||
monster.getMap().killMonster(monster, player, true);
|
||||
map.damageMonster(player, monster, Integer.MAX_VALUE); // thanks Conrad for noticing reduced EXP gain from skill kill
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,12 +40,10 @@ public class CashShopSurpriseHandler extends AbstractMaplePacketHandler {
|
||||
Pair<Item, Item> cssResult = cs.openCashShopSurprise();
|
||||
|
||||
if(cssResult != null) {
|
||||
//Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight();
|
||||
//c.announce(MaplePacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getSN(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true));
|
||||
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA4));
|
||||
Item cssItem = cssResult.getLeft(), cssBox = cssResult.getRight();
|
||||
c.announce(MaplePacketCreator.onCashGachaponOpenSuccess(c.getAccID(), cssBox.getSN(), cssBox.getQuantity(), cssItem, cssItem.getItemId(), cssItem.getQuantity(), true));
|
||||
} else {
|
||||
//c.announce(MaplePacketCreator.onCashItemGachaponOpenFailed());
|
||||
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0x00));
|
||||
c.announce(MaplePacketCreator.onCashItemGachaponOpenFailed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,16 +37,18 @@ public final class DueyHandler extends AbstractMaplePacketHandler {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
byte operation = slea.readByte();
|
||||
if (operation == DueyProcessor.Actions.TOSERVER_SEND_ITEM.getCode()) {
|
||||
if (operation == DueyProcessor.Actions.TOSERVER_RECV_ITEM.getCode()) { // on click 'O' Button, thanks inhyuk
|
||||
DueyProcessor.dueySendTalk(c, false);
|
||||
} else if (operation == DueyProcessor.Actions.TOSERVER_SEND_ITEM.getCode()) {
|
||||
byte inventId = slea.readByte();
|
||||
short itemPos = slea.readShort();
|
||||
short amount = slea.readShort();
|
||||
int mesos = slea.readInt();
|
||||
String recipient = slea.readMapleAsciiString();
|
||||
boolean quick = slea.readByte() != 0;
|
||||
String message = quick ? slea.readMapleAsciiString() : "";
|
||||
String message = quick ? slea.readMapleAsciiString() : null;
|
||||
|
||||
DueyProcessor.dueySendItem(c, inventId, itemPos, amount, mesos, message, recipient, quick);
|
||||
} else if (operation == DueyProcessor.Actions.TOSERVER_REMOVE_PACKAGE.getCode()) {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
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.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import constants.GameConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.life.MapleMonster;
|
||||
import server.life.MapleMonsterInformationProvider;
|
||||
import server.maps.MapleMap;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public class FieldDamageMobHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
int mobOid = slea.readInt(); // packet structure found thanks to Darter (Rajan)
|
||||
int dmg = slea.readInt();
|
||||
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
MapleMap map = chr.getMap();
|
||||
|
||||
if (map.getEnvironment().isEmpty()) { // no environment objects activated to actually hit the mob
|
||||
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use an obstacle on mapid " + map.getId() + " to attack.");
|
||||
return;
|
||||
}
|
||||
|
||||
MapleMonster mob = map.getMonsterByOid(mobOid);
|
||||
if (mob != null) {
|
||||
if (dmg < 0 || dmg > GameConstants.MAX_FIELD_MOB_DAMAGE) {
|
||||
FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use an obstacle on mapid " + map.getId() + " to attack " + MapleMonsterInformationProvider.getInstance().getMobNameFromId(mob.getId()) + " with damage " + dmg);
|
||||
return;
|
||||
}
|
||||
|
||||
map.broadcastMessage(chr, MaplePacketCreator.damageMonster(mobOid, dmg), true);
|
||||
map.damageMonster(chr, mob, dmg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,10 +25,9 @@ import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.autoban.AutobanFactory;
|
||||
import client.autoban.AutobanManager;
|
||||
import constants.GameConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import net.server.Server;
|
||||
import server.maps.MapleMapFactory;
|
||||
import server.maps.MapleMap;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
@@ -47,7 +46,8 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
abm.setTimestamp(8, timestamp, 28); // thanks Vcoc & Thora for pointing out d/c happening here
|
||||
if ((abm.getLastSpam(0) + 1500) > timestamp) AutobanFactory.FAST_HP_HEALING.addPoint(abm, "Fast hp healing");
|
||||
|
||||
int abHeal = (int)(77 * MapleMapFactory.getMapRecoveryRate(chr.getMapId()) * 1.5); // thanks Ari for noticing players not getting healed in sauna in certain cases
|
||||
MapleMap map = chr.getMap();
|
||||
int abHeal = (int)(77 * map.getRecovery() * 1.5); // thanks Ari for noticing players not getting healed in sauna in certain cases
|
||||
if (healHP > abHeal) {
|
||||
AutobanFactory.HIGH_HP_HEALING.autoban(chr, "Healing: " + healHP + "; Max is " + abHeal + ".");
|
||||
return;
|
||||
@@ -60,7 +60,10 @@ public final class HealOvertimeHandler extends AbstractMaplePacketHandler {
|
||||
short healMP = slea.readShort();
|
||||
if (healMP != 0 && healMP < 1000) {
|
||||
abm.setTimestamp(9, timestamp, 28);
|
||||
if ((abm.getLastSpam(1) + 1500) > timestamp) AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
|
||||
if ((abm.getLastSpam(1) + 1500) > timestamp) {
|
||||
AutobanFactory.FAST_MP_HEALING.addPoint(abm, "Fast mp healing");
|
||||
return; // thanks resinate for noticing mp being gained even after detection
|
||||
}
|
||||
chr.addMP(healMP);
|
||||
abm.spam(1, timestamp);
|
||||
}
|
||||
|
||||
@@ -27,8 +27,12 @@ import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import client.MapleClient;
|
||||
import constants.GameConstants;
|
||||
import java.awt.Point;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.MaplePortal;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import server.maps.MaplePlayerShop;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -40,7 +44,34 @@ public final class HiredMerchantRequest extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
if (chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT)).isEmpty() && (GameConstants.isFreeMarketRoom(chr.getMapId()))) {
|
||||
|
||||
try {
|
||||
for (MapleMapObject mmo : chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT, MapleMapObjectType.PLAYER))) {
|
||||
if (mmo instanceof MapleCharacter) {
|
||||
MapleCharacter mc = (MapleCharacter) mmo;
|
||||
|
||||
MaplePlayerShop shop = mc.getPlayerShop();
|
||||
if (shop != null && shop.isOwner(mc)) {
|
||||
chr.announce(MaplePacketCreator.getMiniRoomError(13));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
chr.announce(MaplePacketCreator.getMiniRoomError(13));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Point cpos = chr.getPosition();
|
||||
MaplePortal portal = chr.getMap().findClosestTeleportPortal(cpos);
|
||||
if (portal != null && portal.getPosition().distance(cpos) < 120.0) {
|
||||
chr.announce(MaplePacketCreator.getMiniRoomError(10));
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (GameConstants.isFreeMarketRoom(chr.getMapId())) {
|
||||
if (!chr.hasMerchant()) {
|
||||
try {
|
||||
if (ItemFactory.MERCHANT.loadItems(chr.getId(), false).isEmpty() && chr.getMerchantMeso() == 0) {
|
||||
|
||||
@@ -30,6 +30,10 @@ import tools.data.output.MaplePacketLittleEndianWriter;
|
||||
public final class NPCAnimationHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
if (c.getPlayer().isChangingMaps()) { // possible cause of error 38 in some map transition scenarios, thanks Arnah
|
||||
return;
|
||||
}
|
||||
|
||||
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
int length = (int) slea.available();
|
||||
if (length == 6) { // NPC Talk
|
||||
|
||||
@@ -34,11 +34,13 @@ import constants.ServerConstants;
|
||||
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MaplePortal;
|
||||
import server.MapleTrade;
|
||||
import constants.GameConstants;
|
||||
import server.maps.FieldLimit;
|
||||
import server.maps.MapleHiredMerchant;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import server.maps.MapleMiniGame;
|
||||
import server.maps.MapleMiniGame.MiniGameType;
|
||||
import server.maps.MaplePlayerShop;
|
||||
@@ -49,6 +51,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -237,13 +240,9 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Point cpos = chr.getPosition();
|
||||
if (chr.getMap().findClosestWarpPortal(cpos).getPosition().distance(cpos) < 120.0) {
|
||||
chr.getClient().announce(MaplePacketCreator.getMiniRoomError(10));
|
||||
return;
|
||||
}
|
||||
} catch (NullPointerException npe) {}
|
||||
if (!canPlaceStore(chr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String desc = slea.readMapleAsciiString();
|
||||
slea.skip(3);
|
||||
@@ -362,6 +361,10 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
c.announce(MaplePacketCreator.hiredMerchantOwnerMaintenanceLeave());
|
||||
}
|
||||
|
||||
if (!canPlaceStore(chr)) { // thanks Ari for noticing player shops overlapping on opening time
|
||||
return;
|
||||
}
|
||||
|
||||
MaplePlayerShop shop = chr.getPlayerShop();
|
||||
MapleHiredMerchant merchant = chr.getHiredMerchant();
|
||||
@@ -797,4 +800,37 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean canPlaceStore(MapleCharacter chr) {
|
||||
try {
|
||||
for (MapleMapObject mmo : chr.getMap().getMapObjectsInRange(chr.getPosition(), 23000, Arrays.asList(MapleMapObjectType.HIRED_MERCHANT, MapleMapObjectType.PLAYER))) {
|
||||
if (mmo instanceof MapleCharacter) {
|
||||
MapleCharacter mc = (MapleCharacter) mmo;
|
||||
if (mc.getId() == chr.getId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MaplePlayerShop shop = mc.getPlayerShop();
|
||||
if (shop != null && shop.isOwner(mc)) {
|
||||
chr.announce(MaplePacketCreator.getMiniRoomError(13));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
chr.announce(MaplePacketCreator.getMiniRoomError(13));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Point cpos = chr.getPosition();
|
||||
MaplePortal portal = chr.getMap().findClosestTeleportPortal(cpos);
|
||||
if (portal != null && portal.getPosition().distance(cpos) < 120.0) {
|
||||
chr.announce(MaplePacketCreator.getMiniRoomError(10));
|
||||
return false;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package net.server.channel.handlers;
|
||||
|
||||
import client.MapleCharacter.DelayedQuestUpdate;
|
||||
import client.MapleClient;
|
||||
import client.MapleQuestStatus;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.quest.MapleQuest;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
/**
|
||||
@@ -25,7 +25,7 @@ public class RaiseUIStateHandler extends AbstractMaplePacketHandler {
|
||||
quest.forceStart(c.getPlayer(), 22000);
|
||||
c.getPlayer().updateQuestInfo(quest.getId(), "0");
|
||||
} else if (mqs.getStatus() == MapleQuestStatus.Status.STARTED) {
|
||||
c.announce(MaplePacketCreator.updateQuest(mqs, false));
|
||||
c.getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, mqs, false);
|
||||
} else {
|
||||
//c.announce(MaplePacketCreator.updateQuestInfo(mqs.getQuestID(), 22000, "0"));
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package net.server.worker;
|
||||
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import server.maps.MapleMapManager;
|
||||
|
||||
/**
|
||||
* @author Resinate
|
||||
@@ -11,8 +13,14 @@ public class RespawnWorker implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Channel ch : Server.getInstance().getAllChannels()) {
|
||||
if (!ch.getPlayerStorage().getAllCharacters().isEmpty()) {
|
||||
ch.getMapFactory().updateMaps();
|
||||
PlayerStorage ps = ch.getPlayerStorage();
|
||||
if (ps != null) {
|
||||
if (!ps.getAllCharacters().isEmpty()) {
|
||||
MapleMapManager mapManager = ch.getMapFactory();
|
||||
if (mapManager != null) {
|
||||
mapManager.updateMaps();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ import server.partyquest.Pyramid;
|
||||
import server.quest.MapleQuest;
|
||||
import tools.MaplePacketCreator;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleCharacter.DelayedQuestUpdate;
|
||||
import client.MapleClient;
|
||||
import client.MapleQuestStatus;
|
||||
import client.SkillFactory;
|
||||
@@ -468,12 +469,12 @@ public class AbstractPlayerInteraction {
|
||||
|
||||
public void resetAllQuestProgress(int qid) {
|
||||
getPlayer().getQuest(MapleQuest.getInstance(qid)).resetAllProgress();
|
||||
getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false));
|
||||
getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, getPlayer().getQuest(MapleQuest.getInstance(qid)), false);
|
||||
}
|
||||
|
||||
public void resetQuestProgress(int qid, int pid) {
|
||||
getPlayer().getQuest(MapleQuest.getInstance(qid)).resetProgress(pid);
|
||||
getClient().announce(MaplePacketCreator.updateQuest(getPlayer().getQuest(MapleQuest.getInstance(qid)), false));
|
||||
getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, getPlayer().getQuest(MapleQuest.getInstance(qid)), false);
|
||||
}
|
||||
|
||||
public boolean forceStartQuest(int id) {
|
||||
|
||||
@@ -70,7 +70,7 @@ public abstract class AbstractScriptManager {
|
||||
NashornScriptEngine engine = c.getScriptEngine(cachePath);
|
||||
|
||||
if (engine == null) {
|
||||
engine = getScriptEngine(cachePath);
|
||||
engine = getScriptEngine(path);
|
||||
c.setScriptEngine(path, engine);
|
||||
}
|
||||
|
||||
|
||||
@@ -347,6 +347,12 @@ public class EventManager {
|
||||
private boolean startLobbyInstance(int lobbyId) {
|
||||
lobbyLock.lock();
|
||||
try {
|
||||
if (lobbyId < 0) {
|
||||
lobbyId = 0;
|
||||
} else if (lobbyId >= maxLobbys) {
|
||||
lobbyId = maxLobbys - 1;
|
||||
}
|
||||
|
||||
if(!openedLobbys.get(lobbyId)) {
|
||||
openedLobbys.set(lobbyId, true);
|
||||
return true;
|
||||
|
||||
@@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package scripting.map;
|
||||
|
||||
import client.MapleCharacter.DelayedQuestUpdate;
|
||||
import client.MapleClient;
|
||||
import client.MapleQuestStatus;
|
||||
import scripting.AbstractPlayerInteraction;
|
||||
@@ -99,7 +100,7 @@ public class MapScriptMethods extends AbstractPlayerInteraction {
|
||||
}
|
||||
String status = Integer.toString(q.getMedalProgress());
|
||||
String infoex = quest.getInfoEx();
|
||||
getPlayer().announce(MaplePacketCreator.updateQuest(q, true));
|
||||
getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, true);
|
||||
StringBuilder smp = new StringBuilder();
|
||||
StringBuilder etm = new StringBuilder();
|
||||
if (status.equals(infoex)) {
|
||||
@@ -127,7 +128,7 @@ public class MapScriptMethods extends AbstractPlayerInteraction {
|
||||
return;
|
||||
}
|
||||
String status = Integer.toString(q.getMedalProgress());
|
||||
getPlayer().announce(MaplePacketCreator.updateQuest(q, true));
|
||||
getPlayer().announceUpdateQuest(DelayedQuestUpdate.UPDATE, q, true);
|
||||
getPlayer().announce(MaplePacketCreator.earnTitleMessage(status + "/5 Completed"));
|
||||
getPlayer().announce(MaplePacketCreator.earnTitleMessage("The One Who's Touched the Sky title in progress."));
|
||||
if (Integer.toString(q.getMedalProgress()).equals(quest.getInfoEx())) {
|
||||
|
||||
@@ -200,6 +200,8 @@ public class NPCScriptManager extends AbstractScriptManager {
|
||||
} else {
|
||||
resetContext(scriptFolder + "/" + cm.getNpc() + ".js", c);
|
||||
}
|
||||
|
||||
c.getPlayer().flushDelayedUpdateQuests();
|
||||
}
|
||||
|
||||
public void dispose(MapleClient c) {
|
||||
|
||||
@@ -163,6 +163,7 @@ public class QuestScriptManager extends AbstractScriptManager {
|
||||
scripts.remove(c);
|
||||
c.getPlayer().setNpcCooldown(System.currentTimeMillis());
|
||||
resetContext("quest/" + qm.getQuest() + ".js", c);
|
||||
c.getPlayer().flushDelayedUpdateQuests();
|
||||
}
|
||||
|
||||
public void dispose(MapleClient c) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.awt.Point;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.logging.Level;
|
||||
@@ -57,24 +58,70 @@ import tools.MaplePacketCreator;
|
||||
*/
|
||||
public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
private MapleReactor reactor;
|
||||
private MapleClient client;
|
||||
private Invocable iv;
|
||||
private ScheduledFuture<?> sprayTask = null;
|
||||
|
||||
public ReactorActionManager(MapleClient c, MapleReactor reactor, Invocable iv) {
|
||||
super(c);
|
||||
this.reactor = reactor;
|
||||
this.client = c;
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public void hitReactor() {
|
||||
reactor.hitReactor(client);
|
||||
reactor.hitReactor(c);
|
||||
}
|
||||
|
||||
public void destroyNpc(int npcId) {
|
||||
reactor.getMap().destroyNPC(npcId);
|
||||
}
|
||||
|
||||
private static void sortDropEntries(List<ReactorDropEntry> from, List<ReactorDropEntry> item, List<ReactorDropEntry> visibleQuest, List<ReactorDropEntry> otherQuest, MapleCharacter chr) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
for(ReactorDropEntry mde : from) {
|
||||
if(!ii.isQuestItem(mde.itemId)) {
|
||||
item.add(mde);
|
||||
} else {
|
||||
if(chr.needQuestItem(mde.questid, mde.itemId)) {
|
||||
visibleQuest.add(mde);
|
||||
} else {
|
||||
otherQuest.add(mde);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<ReactorDropEntry> assembleReactorDropEntries(MapleCharacter chr, List<ReactorDropEntry> items) {
|
||||
final List<ReactorDropEntry> dropEntry = new ArrayList<>();
|
||||
final List<ReactorDropEntry> visibleQuestEntry = new ArrayList<>();
|
||||
final List<ReactorDropEntry> otherQuestEntry = new ArrayList<>();
|
||||
sortDropEntries(items, dropEntry, visibleQuestEntry, otherQuestEntry, chr);
|
||||
|
||||
Collections.shuffle(dropEntry);
|
||||
Collections.shuffle(visibleQuestEntry);
|
||||
Collections.shuffle(otherQuestEntry);
|
||||
|
||||
items.clear();
|
||||
items.addAll(dropEntry);
|
||||
items.addAll(visibleQuestEntry);
|
||||
items.addAll(otherQuestEntry);
|
||||
|
||||
List<ReactorDropEntry> items1 = new ArrayList<>(items.size());
|
||||
List<ReactorDropEntry> items2 = new ArrayList<>(items.size() / 2);
|
||||
|
||||
for (int i = 0; i < items.size(); i++) {
|
||||
if (i % 2 == 0) {
|
||||
items1.add(items.get(i));
|
||||
} else {
|
||||
items2.add(items.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
Collections.reverse(items1);
|
||||
items1.addAll(items2);
|
||||
|
||||
return items1;
|
||||
}
|
||||
|
||||
public void sprayItems() {
|
||||
sprayItems(false, 0, 0, 0, 0);
|
||||
@@ -109,10 +156,10 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
}
|
||||
|
||||
public void dropItems(boolean delayed, int posX, int posY, boolean meso, int mesoChance, final int minMeso, final int maxMeso, int minItems) {
|
||||
if(c.getPlayer() == null) return;
|
||||
|
||||
List<ReactorDropEntry> items = generateDropList(getDropChances(), c.getPlayer().getDropRate(), meso, mesoChance, minItems);
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
if(chr == null) return;
|
||||
|
||||
List<ReactorDropEntry> items = assembleReactorDropEntries(chr, generateDropList(getDropChances(), chr.getDropRate(), meso, mesoChance, minItems));
|
||||
if(items.size() % 2 == 0) posX -= 12;
|
||||
final Point dropPos = new Point(posX, posY);
|
||||
|
||||
@@ -127,8 +174,8 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
if (d.itemId == 0) {
|
||||
int range = maxMeso - minMeso;
|
||||
int displayDrop = (int) (Math.random() * range) + minMeso;
|
||||
int mesoDrop = (displayDrop * client.getWorldServer().getMesoRate());
|
||||
reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, client.getPlayer(), false, (byte) 2);
|
||||
int mesoDrop = (displayDrop * c.getWorldServer().getMesoRate());
|
||||
reactor.getMap().spawnMesoDrop(mesoDrop, reactor.getMap().calcDropPos(dropPos, reactor.getPosition()), reactor, c.getPlayer(), false, (byte) 2);
|
||||
} else {
|
||||
Item drop;
|
||||
|
||||
@@ -142,10 +189,9 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final MapleCharacter chr = client.getPlayer();
|
||||
final MapleReactor r = reactor;
|
||||
final List<ReactorDropEntry> dropItems = items;
|
||||
final int worldMesoRate = client.getWorldServer().getMesoRate();
|
||||
final int worldMesoRate = c.getWorldServer().getMesoRate();
|
||||
|
||||
dropPos.x -= (12 * items.size());
|
||||
|
||||
@@ -178,7 +224,7 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
|
||||
dropPos.x += 25;
|
||||
}
|
||||
}, 100);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,37 +233,21 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
}
|
||||
|
||||
private List<ReactorDropEntry> generateDropList(List<ReactorDropEntry> drops, int dropRate, boolean meso, int mesoChance, int minItems) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
|
||||
List<ReactorDropEntry> items = new ArrayList<>();
|
||||
List<ReactorDropEntry> questItems = new ArrayList<>();
|
||||
int numItems = 0;
|
||||
|
||||
if (meso && Math.random() < (1 / (double) mesoChance)) {
|
||||
items.add(new ReactorDropEntry(0, mesoChance, -1));
|
||||
}
|
||||
|
||||
for(ReactorDropEntry mde : drops) {
|
||||
if (Math.random() < (dropRate / (double) mde.chance)) {
|
||||
if(!ii.isQuestItem(mde.itemId)) {
|
||||
items.add(mde);
|
||||
} else {
|
||||
questItems.add(mde);
|
||||
}
|
||||
|
||||
numItems++;
|
||||
items.add(mde);
|
||||
}
|
||||
}
|
||||
|
||||
while (numItems < minItems) {
|
||||
while (items.size() < minItems) {
|
||||
items.add(new ReactorDropEntry(0, mesoChance, -1));
|
||||
numItems++;
|
||||
}
|
||||
|
||||
java.util.Collections.shuffle(items);
|
||||
java.util.Collections.shuffle(questItems);
|
||||
|
||||
items.addAll(questItems);
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -226,7 +256,7 @@ public class ReactorActionManager extends AbstractPlayerInteraction {
|
||||
}
|
||||
|
||||
public void createMapMonitor(int mapId, String portal) {
|
||||
new MapMonitor(client.getChannelServer().getMapFactory().getMap(mapId), portal);
|
||||
new MapMonitor(c.getChannelServer().getMapFactory().getMap(mapId), portal);
|
||||
}
|
||||
|
||||
public void spawnMonster(int id, int qty) {
|
||||
|
||||
@@ -157,7 +157,7 @@ public class CashShop {
|
||||
private static final Map<Integer, CashItem> items = new HashMap<>();
|
||||
private static final Map<Integer, List<Integer>> packages = new HashMap<>();
|
||||
private static final List<SpecialCashItem> specialcashitems = new ArrayList<>();
|
||||
private static final List<Integer> randomitemids = new ArrayList<>();
|
||||
private static final List<Integer> randomitemsns = new ArrayList<>();
|
||||
|
||||
static {
|
||||
MapleDataProvider etc = MapleDataProviderFactory.getDataProvider(new File("wz/Etc.wz"));
|
||||
@@ -184,7 +184,7 @@ public class CashShop {
|
||||
|
||||
for(Entry<Integer, CashItem> e : items.entrySet()) {
|
||||
if(e.getValue().isOnSale()) {
|
||||
randomitemids.add(e.getKey());
|
||||
randomitemsns.add(e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,10 +212,10 @@ public class CashShop {
|
||||
}
|
||||
|
||||
public static CashItem getRandomCashItem() {
|
||||
if(randomitemids.isEmpty()) return null;
|
||||
if(randomitemsns.isEmpty()) return null;
|
||||
|
||||
int rnd = (int)(Math.random() * randomitemids.size());
|
||||
return items.get(randomitemids.get(rnd));
|
||||
int rnd = (int)(Math.random() * randomitemsns.size());
|
||||
return items.get(randomitemsns.get(rnd));
|
||||
}
|
||||
|
||||
public static CashItem getItem(int sn) {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class DueyPackage {
|
||||
private String sender = null;
|
||||
private Item item = null;
|
||||
private int mesos = 0;
|
||||
private String message = "";
|
||||
private String message = null;
|
||||
private Calendar timestamp;
|
||||
private int packageId = 0;
|
||||
|
||||
@@ -96,13 +96,15 @@ public class DueyPackage {
|
||||
}
|
||||
}
|
||||
|
||||
public void setSentTime(Timestamp ts) {
|
||||
public void setSentTime(Timestamp ts, boolean quick) {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeInMillis(ts.getTime());
|
||||
cal.set(Calendar.HOUR, 0);
|
||||
cal.set(Calendar.MINUTE, 0);
|
||||
cal.set(Calendar.SECOND, 0);
|
||||
cal.set(Calendar.MILLISECOND, 0);
|
||||
|
||||
if (quick) {
|
||||
if (System.currentTimeMillis() - ts.getTime() < 24 * 60 * 60 * 1000) { // thanks inhyuk for noticing quick delivery packages unavailable to retrieve from the get-go
|
||||
cal.add(Calendar.DATE, -1);
|
||||
}
|
||||
}
|
||||
|
||||
this.timestamp = cal;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.awt.Point;
|
||||
import client.MapleClient;
|
||||
|
||||
public interface MaplePortal {
|
||||
public final int TELEPORT_PORTAL = 1;
|
||||
public final int MAP_PORTAL = 2;
|
||||
public final int DOOR_PORTAL = 6;
|
||||
public static boolean OPEN = true;
|
||||
|
||||
@@ -1288,6 +1288,7 @@ public class MapleStatEffect {
|
||||
if (mount != null) {
|
||||
ridingMountId = mount.getItemId();
|
||||
}
|
||||
|
||||
if (sourceid == Corsair.BATTLE_SHIP) {
|
||||
ridingMountId = 1932000;
|
||||
} else if (sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP) {
|
||||
@@ -1300,28 +1301,12 @@ public class MapleStatEffect {
|
||||
ridingMountId = 1932005;
|
||||
} else if (sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.BALROG_MOUNT) {
|
||||
ridingMountId = 1932010;
|
||||
} else {
|
||||
if (applyto.getMount() == null) {
|
||||
applyto.mount(ridingMountId, sourceid);
|
||||
}
|
||||
|
||||
applyto.getClient().getWorldServer().registerMountHunger(applyto);
|
||||
}
|
||||
if (sourceid == Corsair.BATTLE_SHIP) {
|
||||
givemount = new MapleMount(applyto, 1932000, sourceid);
|
||||
} else if (sourceid == Beginner.SPACESHIP || sourceid == Noblesse.SPACESHIP) {
|
||||
givemount = new MapleMount(applyto, 1932000 + applyto.getSkillLevel(sourceid), sourceid);
|
||||
} else if (sourceid == Beginner.YETI_MOUNT1 || sourceid == Noblesse.YETI_MOUNT1 || sourceid == Legend.YETI_MOUNT1) {
|
||||
givemount = new MapleMount(applyto, 1932003, sourceid);
|
||||
} else if (sourceid == Beginner.YETI_MOUNT2 || sourceid == Noblesse.YETI_MOUNT2 || sourceid == Legend.YETI_MOUNT2) {
|
||||
givemount = new MapleMount(applyto, 1932004, sourceid);
|
||||
} else if (sourceid == Beginner.WITCH_BROOMSTICK || sourceid == Noblesse.WITCH_BROOMSTICK || sourceid == Legend.WITCH_BROOMSTICK) {
|
||||
givemount = new MapleMount(applyto, 1932005, sourceid);
|
||||
} else if (sourceid == Beginner.BALROG_MOUNT || sourceid == Noblesse.BALROG_MOUNT || sourceid == Legend.BALROG_MOUNT) {
|
||||
givemount = new MapleMount(applyto, 1932010, sourceid);
|
||||
} else {
|
||||
givemount = applyto.getMount();
|
||||
}
|
||||
|
||||
// thanks inhyuk for noticing some skill mounts not acting properly for other players when changing maps
|
||||
givemount = applyto.mount(ridingMountId, sourceid);
|
||||
applyto.getClient().getWorldServer().registerMountHunger(applyto);
|
||||
|
||||
localDuration = sourceid;
|
||||
localsourceid = ridingMountId;
|
||||
localstatups = Collections.singletonList(new Pair<>(MapleBuffStat.MONSTER_RIDING, 0));
|
||||
|
||||
@@ -65,12 +65,9 @@ public class MapleExpeditionBossLog {
|
||||
private static List<Pair<Timestamp, BossLogEntry>> getBossLogResetTimestamps(Calendar timeNow, boolean week) {
|
||||
List<Pair<Timestamp, BossLogEntry>> resetTimestamps = new LinkedList<>();
|
||||
|
||||
Timestamp ts = new Timestamp(timeNow.getTime().getTime()); // reset all table entries actually, thanks Conrad
|
||||
for (BossLogEntry b : BossLogEntry.values()) {
|
||||
if (b.week == week) {
|
||||
Calendar c = (Calendar) timeNow.clone();
|
||||
c.roll(Calendar.DAY_OF_MONTH, -1 * (week ? 7 : 1) * b.timeLength);
|
||||
Timestamp ts = new Timestamp(c.getTime().getTime());
|
||||
|
||||
resetTimestamps.add(new Pair<>(ts, b));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private Set<Integer> usedAttacks = new HashSet<>();
|
||||
private Set<Integer> calledMobOids = null;
|
||||
private WeakReference<MapleMonster> callerMob = new WeakReference<>(null);
|
||||
private List<Integer> stolenItems = new ArrayList<>();
|
||||
private List<Integer> stolenItems = new ArrayList<>(5);
|
||||
private int team;
|
||||
private int parentMobOid = 0;
|
||||
private final HashMap<Integer, AtomicLong> takenDamage = new HashMap<>();
|
||||
|
||||
@@ -152,7 +152,7 @@ public class MapleMonsterInformationProvider {
|
||||
|
||||
int rnd = Randomizer.rand(mde.Minimum, mde.Maximum);
|
||||
for (int i = 0; i < rnd - 1; i++) {
|
||||
extra.add(mde); // this passes copies of the equips' MDE with min/max quantity > 1, but idc it'll be unused anyways
|
||||
extra.add(mde); // this passes copies of the equips' MDE with min/max quantity > 1, but idc on equips they are unused anyways
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ public class MapleMap {
|
||||
private int timeLimit;
|
||||
private long mapTimer;
|
||||
private int decHP = 0;
|
||||
private float recovery = 1.0f;
|
||||
private int protectItem = 0;
|
||||
private boolean town;
|
||||
private MapleOxQuiz ox;
|
||||
@@ -1408,81 +1409,85 @@ public class MapleMap {
|
||||
}
|
||||
} else {
|
||||
if (removeKilledMonsterObject(monster)) {
|
||||
if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) {
|
||||
AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher.");
|
||||
}
|
||||
|
||||
/*if (chr.getQuest(MapleQuest.getInstance(29400)).getStatus().equals(MapleQuestStatus.Status.STARTED)) {
|
||||
if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) {
|
||||
//FIX MEDAL SHET
|
||||
} else if (monster.getStats().getLevel() >= chr.getLevel()) {
|
||||
}
|
||||
}*/
|
||||
|
||||
if (monster.getCP() > 0 && chr.getMap().isCPQMap()) {
|
||||
chr.gainCP(monster.getCP());
|
||||
}
|
||||
|
||||
int buff = monster.getBuffToGive();
|
||||
if (buff > -1) {
|
||||
MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance();
|
||||
for (MapleMapObject mmo : this.getPlayers()) {
|
||||
MapleCharacter character = (MapleCharacter) mmo;
|
||||
if (character.isAlive()) {
|
||||
MapleStatEffect statEffect = mii.getItemEffect(buff);
|
||||
character.getClient().announce(MaplePacketCreator.showOwnBuffEffect(buff, 1));
|
||||
broadcastMessage(character, MaplePacketCreator.showBuffeffect(character.getId(), buff, 1), false);
|
||||
statEffect.applyTo(character);
|
||||
}
|
||||
try {
|
||||
if (monster.getStats().getLevel() >= chr.getLevel() + 30 && !chr.isGM()) {
|
||||
AutobanFactory.GENERAL.alert(chr, " for killing a " + monster.getName() + " which is over 30 levels higher.");
|
||||
}
|
||||
}
|
||||
|
||||
if (monster.getId() >= 8800003 && monster.getId() <= 8800010) {
|
||||
boolean makeZakReal = true;
|
||||
Collection<MapleMapObject> objects = getMapObjects();
|
||||
for (MapleMapObject object : objects) {
|
||||
MapleMonster mons = getMonsterByOid(object.getObjectId());
|
||||
if (mons != null) {
|
||||
if (mons.getId() >= 8800003 && mons.getId() <= 8800010) {
|
||||
makeZakReal = false;
|
||||
break;
|
||||
|
||||
/*if (chr.getQuest(MapleQuest.getInstance(29400)).getStatus().equals(MapleQuestStatus.Status.STARTED)) {
|
||||
if (chr.getLevel() >= 120 && monster.getStats().getLevel() >= 120) {
|
||||
//FIX MEDAL SHET
|
||||
} else if (monster.getStats().getLevel() >= chr.getLevel()) {
|
||||
}
|
||||
}*/
|
||||
|
||||
if (monster.getCP() > 0 && chr.getMap().isCPQMap()) {
|
||||
chr.gainCP(monster.getCP());
|
||||
}
|
||||
|
||||
int buff = monster.getBuffToGive();
|
||||
if (buff > -1) {
|
||||
MapleItemInformationProvider mii = MapleItemInformationProvider.getInstance();
|
||||
for (MapleMapObject mmo : this.getPlayers()) {
|
||||
MapleCharacter character = (MapleCharacter) mmo;
|
||||
if (character.isAlive()) {
|
||||
MapleStatEffect statEffect = mii.getItemEffect(buff);
|
||||
character.getClient().announce(MaplePacketCreator.showOwnBuffEffect(buff, 1));
|
||||
broadcastMessage(character, MaplePacketCreator.showBuffeffect(character.getId(), buff, 1), false);
|
||||
statEffect.applyTo(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (makeZakReal) {
|
||||
MapleMap map = chr.getMap();
|
||||
|
||||
if (monster.getId() >= 8800003 && monster.getId() <= 8800010) {
|
||||
boolean makeZakReal = true;
|
||||
Collection<MapleMapObject> objects = getMapObjects();
|
||||
for (MapleMapObject object : objects) {
|
||||
MapleMonster mons = map.getMonsterByOid(object.getObjectId());
|
||||
MapleMonster mons = getMonsterByOid(object.getObjectId());
|
||||
if (mons != null) {
|
||||
if (mons.getId() == 8800000) {
|
||||
makeMonsterReal(mons);
|
||||
mons.aggroUpdateController();
|
||||
if (mons.getId() >= 8800003 && mons.getId() <= 8800010) {
|
||||
makeZakReal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (makeZakReal) {
|
||||
MapleMap map = chr.getMap();
|
||||
|
||||
MapleCharacter dropOwner = monster.killBy(chr);
|
||||
if (withDrops && !monster.dropsDisabled()) {
|
||||
if (dropOwner == null) {
|
||||
dropOwner = chr;
|
||||
}
|
||||
dropFromMonster(dropOwner, monster, false);
|
||||
}
|
||||
|
||||
if (monster.hasBossHPBar()) {
|
||||
for(MapleCharacter mc : this.getAllPlayers()) {
|
||||
if(mc.getTargetHpBarHash() == monster.hashCode()) {
|
||||
mc.resetPlayerAggro();
|
||||
for (MapleMapObject object : objects) {
|
||||
MapleMonster mons = map.getMonsterByOid(object.getObjectId());
|
||||
if (mons != null) {
|
||||
if (mons.getId() == 8800000) {
|
||||
makeMonsterReal(mons);
|
||||
mons.aggroUpdateController();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monster.dispatchMonsterKilled(true);
|
||||
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
|
||||
MapleCharacter dropOwner = monster.killBy(chr);
|
||||
if (withDrops && !monster.dropsDisabled()) {
|
||||
if (dropOwner == null) {
|
||||
dropOwner = chr;
|
||||
}
|
||||
dropFromMonster(dropOwner, monster, false);
|
||||
}
|
||||
|
||||
if (monster.hasBossHPBar()) {
|
||||
for(MapleCharacter mc : this.getAllPlayers()) {
|
||||
if(mc.getTargetHpBarHash() == monster.hashCode()) {
|
||||
mc.resetPlayerAggro();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally { // thanks resinate for pointing out a memory leak possibly from an exception thrown
|
||||
monster.dispatchMonsterKilled(true);
|
||||
broadcastMessage(MaplePacketCreator.killMonster(monster.getObjectId(), animation), monster.getPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2707,12 +2712,12 @@ public class MapleMap {
|
||||
return portal != null ? portal : getPortal(0);
|
||||
}
|
||||
|
||||
public MaplePortal findClosestWarpPortal(Point from) {
|
||||
public MaplePortal findClosestTeleportPortal(Point from) {
|
||||
MaplePortal closest = null;
|
||||
double shortestDistance = Double.POSITIVE_INFINITY;
|
||||
for (MaplePortal portal : portals.values()) {
|
||||
double distance = portal.getPosition().distanceSq(from);
|
||||
if (portal.getType() == MaplePortal.MAP_PORTAL && distance < shortestDistance && portal.getTargetMapId() == 999999999) {
|
||||
if (portal.getType() == MaplePortal.TELEPORT_PORTAL && distance < shortestDistance && portal.getTargetMapId() != 999999999) {
|
||||
closest = portal;
|
||||
shortestDistance = distance;
|
||||
}
|
||||
@@ -3777,6 +3782,14 @@ public class MapleMap {
|
||||
public void setHPDecProtect(int delta) {
|
||||
this.protectItem = delta;
|
||||
}
|
||||
|
||||
public float getRecovery() {
|
||||
return recovery;
|
||||
}
|
||||
|
||||
public void setRecovery(float recRate) {
|
||||
recovery = recRate;
|
||||
}
|
||||
|
||||
private int hasBoat() {
|
||||
return !boat ? 0 : (docked ? 1 : 2);
|
||||
|
||||
@@ -31,7 +31,6 @@ import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import provider.MapleData;
|
||||
import provider.MapleDataProvider;
|
||||
import provider.MapleDataProviderFactory;
|
||||
@@ -49,8 +48,6 @@ import tools.StringUtil;
|
||||
|
||||
public class MapleMapFactory {
|
||||
|
||||
private static Map<Integer, Float> mapRecoveryRateCache = new HashMap<>();
|
||||
|
||||
private static MapleData nameData;
|
||||
private static MapleDataProvider mapSource;
|
||||
|
||||
@@ -336,11 +333,10 @@ public class MapleMapFactory {
|
||||
map.setTimeLimit(MapleDataTool.getIntConvert("timeLimit", infoData, -1));
|
||||
map.setFieldType(MapleDataTool.getIntConvert("fieldType", infoData, 0));
|
||||
map.setMobCapacity(MapleDataTool.getIntConvert("fixedMobCapacity", infoData, 500));//Is there a map that contains more than 500 mobs?
|
||||
|
||||
|
||||
MapleData recData = infoData.getChildByPath("recovery");
|
||||
if (recData != null) {
|
||||
float recoveryRate = MapleDataTool.getFloat(recData);
|
||||
mapRecoveryRateCache.put(mapid, recoveryRate);
|
||||
map.setRecovery(MapleDataTool.getFloat(recData));
|
||||
}
|
||||
|
||||
HashMap<Integer, Integer> backTypes = new HashMap<>();
|
||||
@@ -438,9 +434,5 @@ public class MapleMapFactory {
|
||||
builder.append("/").append(mapid);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static float getMapRecoveryRate(int mapid) {
|
||||
Float recRate = mapRecoveryRateCache.get(mapid);
|
||||
return recRate != null ? recRate : 1.0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -139,7 +139,4 @@ public class MapleMapManager {
|
||||
this.event = null;
|
||||
}
|
||||
|
||||
public static float getMapRecoveryRate(int mapid) {
|
||||
return MapleMapFactory.getMapRecoveryRate(mapid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleCharacter.DelayedQuestUpdate;
|
||||
import client.MapleQuestStatus;
|
||||
import client.MapleQuestStatus.Status;
|
||||
import constants.ServerConstants;
|
||||
@@ -337,7 +338,7 @@ public class MapleQuest {
|
||||
if(pid >= 8200000 && pid <= 8200012) {
|
||||
String pr = StringUtil.getLeftPaddedStr(Integer.toString(setProg), '0', 3);
|
||||
newStatus.setProgress(pid, pr);
|
||||
c.announce(MaplePacketCreator.updateQuest(newStatus, false));
|
||||
c.announceUpdateQuest(DelayedQuestUpdate.UPDATE, newStatus, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ public class ItemAction extends MapleQuestAction {
|
||||
if (!canGetItem(iEntry, chr)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(iEntry.getProp() != null) {
|
||||
if(iEntry.getProp() == -1) {
|
||||
if(extSelection != extNum++)
|
||||
@@ -181,11 +182,11 @@ public class ItemAction extends MapleQuestAction {
|
||||
}
|
||||
|
||||
} else {
|
||||
if(item.getCount() > 0) {
|
||||
// Make sure they can hold the item.
|
||||
Item toItem = new Item(item.getId(), (short) 0, (short) item.getCount());
|
||||
gainList.add(new Pair<>(toItem, type));
|
||||
} else {
|
||||
// Make sure they can hold the item.
|
||||
Item toItem = new Item(item.getId(), (short) 0, (short) item.getCount());
|
||||
gainList.add(new Pair<>(toItem, type));
|
||||
|
||||
if(item.getCount() < 0) {
|
||||
// Make sure they actually have the item.
|
||||
int quantity = item.getCount() * -1;
|
||||
|
||||
@@ -229,12 +230,34 @@ public class ItemAction extends MapleQuestAction {
|
||||
gainList.add(selected);
|
||||
}
|
||||
|
||||
if (!MapleInventory.checkSpots(chr, gainList, allSlotUsed, false)) {
|
||||
if (!canHold(chr, gainList)) {
|
||||
chr.dropMessage(1, "Please check if you have enough space in your inventory.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean canHold(MapleCharacter chr, List<Pair<Item, MapleInventoryType>> gainList) {
|
||||
List<Integer> toAddItemids = new LinkedList<>();
|
||||
List<Integer> toAddQuantity = new LinkedList<>();
|
||||
List<Integer> toRemoveItemids = new LinkedList<>();
|
||||
List<Integer> toRemoveQuantity = new LinkedList<>();
|
||||
|
||||
for (Pair<Item, MapleInventoryType> item : gainList) {
|
||||
Item it = item.getLeft();
|
||||
|
||||
if (it.getQuantity() > 0) {
|
||||
toAddItemids.add(it.getItemId());
|
||||
toAddQuantity.add((int) it.getQuantity());
|
||||
} else {
|
||||
toRemoveItemids.add(it.getItemId());
|
||||
toRemoveQuantity.add(-1 * ((int) it.getQuantity()));
|
||||
}
|
||||
}
|
||||
|
||||
// thanks onechord for noticing quests unnecessarily giving out "full inventory" from quests that also takes items from players
|
||||
return chr.getClient().getAbstractPlayerInteraction().canHoldAllAfterRemoving(toAddItemids, toAddQuantity, toRemoveItemids, toRemoveQuantity);
|
||||
}
|
||||
|
||||
private boolean canGetItem(ItemData item, MapleCharacter chr) {
|
||||
if (item.getGender() != 2 && item.getGender() != chr.getGender()) {
|
||||
|
||||
@@ -1916,17 +1916,12 @@ public class MaplePacketCreator {
|
||||
|
||||
Integer bv = chr.getBuffedValue(MapleBuffStat.MONSTER_RIDING);
|
||||
if (bv != null) {
|
||||
if(bv.equals(Corsair.BATTLE_SHIP)) {
|
||||
mplew.writeInt(1932000);
|
||||
mplew.writeInt(Corsair.BATTLE_SHIP);
|
||||
MapleMount mount = chr.getMount();
|
||||
if (mount != null) {
|
||||
mplew.writeInt(mount.getItemId());
|
||||
mplew.writeInt(mount.getSkillId());
|
||||
} else {
|
||||
final Item mount = chr.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -18);
|
||||
if(mount != null) {
|
||||
mplew.writeInt(mount.getItemId());
|
||||
mplew.writeInt(1004);
|
||||
} else {
|
||||
mplew.writeLong(0);
|
||||
}
|
||||
mplew.writeLong(0);
|
||||
}
|
||||
} else {
|
||||
mplew.writeLong(0);
|
||||
@@ -6975,14 +6970,14 @@ public class MaplePacketCreator {
|
||||
public static byte[] onCashItemGachaponOpenFailed(){
|
||||
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT.getValue());
|
||||
mplew.write(189);
|
||||
mplew.write(0xE4);
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
public static byte[] onCashGachaponOpenSuccess(int accountid, long sn, int remainingBoxes, Item item, int itemid, int nSelectedItemCount, boolean bJackpot){
|
||||
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.CASHSHOP_CASH_ITEM_GACHAPON_RESULT.getValue());
|
||||
mplew.write(190);
|
||||
mplew.write(0xE5); // subopcode thanks to Ubaware
|
||||
mplew.writeLong(sn);// sn of the box used
|
||||
mplew.writeInt(remainingBoxes);
|
||||
addCashItemInformation(mplew, item, accountid);
|
||||
@@ -7253,15 +7248,15 @@ public class MaplePacketCreator {
|
||||
mplew.writeLong(getTime(dp.sentTimeInMilliseconds()));
|
||||
|
||||
String msg = dp.getMessage();
|
||||
if (!msg.isEmpty()) {
|
||||
mplew.writeInt(1);
|
||||
mplew.writeAsciiString(msg);
|
||||
for (int i = msg.length(); i < 200; i++) {
|
||||
mplew.write(0);
|
||||
}
|
||||
if (msg != null) {
|
||||
mplew.writeInt(1);
|
||||
mplew.writeAsciiString(msg);
|
||||
for (int i = msg.length(); i < 200; i++) {
|
||||
mplew.write(0);
|
||||
}
|
||||
} else {
|
||||
mplew.writeInt(0);
|
||||
mplew.skip(200);
|
||||
mplew.writeInt(0);
|
||||
mplew.skip(200);
|
||||
}
|
||||
|
||||
mplew.write(0);
|
||||
|
||||
Reference in New Issue
Block a user