Skillbook announcer update + Encoded temporary mob buffs + Slot gains patch
Encoded temporary mob buffs on mob control request/spawn packets. Improved scroll generator NPC, now testing other bucket set possibilities. Fixed slot gain method recently updated leading to a temporary visual glitch (inventory would show as normal after relogin). Reviewed mobid check by name, no longer trying to generate a whole mob instance for info retrieval. Added debuff purge when applying a buyback. Reviewed skillbook announcer not informing properly storybooks, reactor or script loots. Fixed autoaggro not working properly as soon as a player enters the field. Fixed "fake" mobs disappearing as soon as its controller changes.
This commit is contained in:
@@ -144,7 +144,6 @@ import client.processor.action.PetAutopotProcessor;
|
||||
import constants.game.ExpTable;
|
||||
import constants.game.GameConstants;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import constants.skills.Aran;
|
||||
import constants.skills.Beginner;
|
||||
import constants.skills.Bishop;
|
||||
@@ -2819,7 +2818,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
dispelDebuff(MapleDisease.WEAKEN);
|
||||
dispelDebuff(MapleDisease.SLOW); // thanks Conrad for noticing ZOMBIFY isn't dispellable
|
||||
}
|
||||
|
||||
|
||||
public void purgeDebuffs() {
|
||||
dispelDebuff(MapleDisease.SEDUCE);
|
||||
dispelDebuff(MapleDisease.ZOMBIFY);
|
||||
dispelDebuff(MapleDisease.CONFUSE);
|
||||
dispelDebuffs();
|
||||
}
|
||||
|
||||
public void cancelAllDebuffs() {
|
||||
chrLock.lock();
|
||||
try {
|
||||
@@ -9420,26 +9426,27 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public boolean gainSlots(int type, int slots, boolean update) {
|
||||
boolean ret = gainSlotsInternal(type, slots, update);
|
||||
if (ret) {
|
||||
int newLimit = gainSlotsInternal(type, slots);
|
||||
if (newLimit != -1) {
|
||||
this.saveCharToDB();
|
||||
if (update) {
|
||||
client.announce(MaplePacketCreator.updateInventorySlotLimit(type, slots));
|
||||
client.announce(MaplePacketCreator.updateInventorySlotLimit(type, newLimit));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private boolean gainSlotsInternal(int type, int slots, boolean update) {
|
||||
private int gainSlotsInternal(int type, int slots) {
|
||||
inventory[type].lockInventory();
|
||||
try {
|
||||
if (canGainSlots(type, slots)) {
|
||||
slots += inventory[type].getSlotLimit();
|
||||
inventory[type].setSlotLimit(slots);
|
||||
return true;
|
||||
int newLimit = inventory[type].getSlotLimit() + slots;
|
||||
inventory[type].setSlotLimit(newLimit);
|
||||
return newLimit;
|
||||
} else {
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
} finally {
|
||||
inventory[type].unlockInventory();
|
||||
@@ -10652,6 +10659,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
client = null; // clients still triggers handlers a few times after disconnecting
|
||||
map = null;
|
||||
setListener(null);
|
||||
|
||||
// thanks Shavit for noticing a memory leak with inventories holding owner object
|
||||
for (int i = 0; i < inventory.length; i++) {
|
||||
inventory[i].dispose();
|
||||
}
|
||||
inventory = null;
|
||||
}
|
||||
}, 5 * 60 * 1000);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class DisposeCommand extends Command {
|
||||
{
|
||||
setDescription("");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
NPCScriptManager.getInstance().dispose(c);
|
||||
@@ -41,5 +41,5 @@ public class DisposeCommand extends Command {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
c.removeClickedNPC();
|
||||
c.getPlayer().message("You've been disposed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ package client.command.commands.gm0;
|
||||
|
||||
import client.MapleClient;
|
||||
import client.command.Command;
|
||||
import constants.net.ServerConstants;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
@@ -29,7 +29,6 @@ import client.MapleClient;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.life.MapleMonsterInformationProvider;
|
||||
import server.life.MonsterDropEntry;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
@@ -25,14 +25,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
|
||||
@@ -672,4 +670,8 @@ public class MapleInventory implements Iterable<Item> {
|
||||
public void unlockInventory() {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
owner = null;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,7 @@ public class BuybackProcessor {
|
||||
}
|
||||
|
||||
chr.healHpMp();
|
||||
chr.purgeDebuffs();
|
||||
chr.broadcastStance(chr.isFacingLeft() ? 5 : 4);
|
||||
|
||||
MapleMap map = chr.getMap();
|
||||
|
||||
@@ -179,6 +179,7 @@ public class ServerConfig {
|
||||
public int MOB_STATUS_MONITOR_LIFE;
|
||||
public int MOB_STATUS_AGGRO_PERSISTENCE;
|
||||
public int MOB_STATUS_AGGRO_INTERVAL;
|
||||
public boolean USE_AUTOAGGRO_NEARBY;
|
||||
|
||||
//Some Gameplay Enhancing Configurations
|
||||
//Scroll Configuration
|
||||
|
||||
@@ -12,6 +12,7 @@ public class ServerConstants {
|
||||
public static int DEBUG_VALUES[] = new int[10]; // Field designed for packet testing purposes
|
||||
|
||||
// https://github.com/openstreetmap/josm/blob/a3a6e8a6b657cf4c5b4c64ea14d6e87be6280d65/src/org/openstreetmap/josm/tools/Utils.java#L1566-L1585
|
||||
// Added by kolakcc (Familiar)
|
||||
/**
|
||||
* Returns the Java version as an int value.
|
||||
* @return the Java version as an int value (8, 9, etc.)
|
||||
|
||||
@@ -25,7 +25,6 @@ import config.YamlConfig;
|
||||
import net.server.guild.MapleGuildResponse;
|
||||
import net.server.guild.MapleGuild;
|
||||
import constants.game.GameConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import client.MapleClient;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
@@ -31,7 +31,6 @@ import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import constants.net.ServerConstants;
|
||||
import net.server.coordinator.world.MapleInviteCoordinator;
|
||||
import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
|
||||
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
|
||||
|
||||
@@ -58,13 +58,13 @@ public final class PlayerMapTransitionHandler extends AbstractMaplePacketHandler
|
||||
if (m.getController() == chr) {
|
||||
c.announce(MaplePacketCreator.stopControllingMonster(m.getObjectId()));
|
||||
m.sendDestroyData(c);
|
||||
m.aggroRedirectController();
|
||||
m.aggroRemoveController();
|
||||
} else {
|
||||
m.sendDestroyData(c);
|
||||
}
|
||||
|
||||
m.aggroSwitchController(chr, false);
|
||||
m.sendSpawnData(c);
|
||||
m.aggroSwitchController(chr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ public class MapleMatchCheckerCoordinator {
|
||||
|
||||
if (mmce != null) {
|
||||
synchronized (mmce) {
|
||||
if (!mmce.isMatchActive()) { // thanks Alex (CanIGetaPR) for noticing that exploiters could stall on match checking
|
||||
if (!mmce.isMatchActive()) { // thanks Alex (Alex-0000) for noticing that exploiters could stall on match checking
|
||||
matchEntries.remove(cid);
|
||||
mmce = null;
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,7 @@ import net.server.PlayerStorage;
|
||||
/**
|
||||
* @author Ronan
|
||||
*/
|
||||
public class CharacterAutosaverTask extends BaseTask implements Runnable { // thanks Alex (Alex09) for noticing these runnable classes are tasks, "workers" runs them
|
||||
public class CharacterAutosaverTask extends BaseTask implements Runnable { // thanks Alex09 (Alex-0000) for noticing these runnable classes are tasks, "workers" runs them
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.sql.SQLException;
|
||||
import client.MapleJob;
|
||||
import config.YamlConfig;
|
||||
import tools.DatabaseConnection;
|
||||
import constants.net.ServerConstants;
|
||||
import net.server.Server;
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,7 +60,6 @@ import client.inventory.MaplePet;
|
||||
import constants.game.GameConstants;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.string.LanguageConstants;
|
||||
import net.server.PlayerStorage;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType;
|
||||
import server.MapleMarriage;
|
||||
@@ -603,6 +602,12 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
switch (sbe) {
|
||||
case UNAVAILABLE:
|
||||
return "";
|
||||
|
||||
case REACTOR:
|
||||
return " Obtainable through #rexploring#k (loot boxes).";
|
||||
|
||||
case SCRIPT:
|
||||
return " Obtainable through #rexploring#k (field interaction).";
|
||||
|
||||
case QUEST_BOOK:
|
||||
return " Obtainable through #rquestline#k (collecting book).";
|
||||
@@ -633,7 +638,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (fieldTaken(i)) {
|
||||
if (fieldLobbied(i)) {
|
||||
msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (Level: " // "Carnival field" GMS-like improvement thanks to Jayd
|
||||
msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (Level: " // "Carnival field" GMS-like improvement thanks to Jayd (jaydenseah)
|
||||
+ cpqCalcAvgLvl(980000100 + i * 100) + " / "
|
||||
+ getPlayerCount(980000100 + i * 100) + "x"
|
||||
+ getPlayerCount(980000100 + i * 100) + ") #l\r\n";
|
||||
|
||||
@@ -49,7 +49,6 @@ import client.inventory.ItemFactory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MaplePet;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import java.util.Collections;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
|
||||
|
||||
@@ -60,7 +60,6 @@ import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.MapleWeaponType;
|
||||
import constants.net.ServerConstants;
|
||||
import constants.inventory.EquipSlot;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.skills.Assassin;
|
||||
@@ -2117,7 +2116,7 @@ public class MapleItemInformationProvider {
|
||||
ResultSet rs = ps.executeQuery();
|
||||
while(rs.next()) {
|
||||
String resultName = MapleMonsterInformationProvider.getInstance().getMobNameFromId(rs.getInt("dropperid"));
|
||||
if (resultName != null) {
|
||||
if (!resultName.isEmpty()) {
|
||||
list.add(resultName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,18 +65,11 @@ public class MapleSkillbookInformationProvider {
|
||||
SCRIPT
|
||||
}
|
||||
|
||||
private static String host = "jdbc:mysql://localhost:3306/heavenms";
|
||||
private static String driver = "com.mysql.jdbc.Driver";
|
||||
private static String username = "root";
|
||||
private static String password = "";
|
||||
|
||||
private static String rootDirectory = ".";
|
||||
|
||||
private static int skillbookMinItemid = 2280000;
|
||||
private static int skillbookMaxItemid = 2300000; // exclusively
|
||||
|
||||
private static Set<Integer> questSkills = new HashSet<>();
|
||||
|
||||
static {
|
||||
loadSkillbooks();
|
||||
}
|
||||
@@ -156,7 +149,13 @@ public class MapleSkillbookInformationProvider {
|
||||
int skillid = MapleDataTool.getInt("id", questSkillData, 0);
|
||||
if (is4thJobSkill(skillid)) {
|
||||
// negative itemids are skill rewards
|
||||
foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_REWARD);
|
||||
|
||||
int questbook = fetchQuestbook(checkData, questData.getName());
|
||||
if (questbook < 0) {
|
||||
foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_REWARD);
|
||||
} else {
|
||||
foundSkillbooks.put(-skillid, SkillBookEntry.QUEST_BOOK);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,10 +958,7 @@ public class MapleStatEffect {
|
||||
if (isDispel() && makeChanceResult()) {
|
||||
applyto.dispelDebuffs();
|
||||
} else if (isCureAllAbnormalStatus()) {
|
||||
applyto.dispelDebuff(MapleDisease.SEDUCE);
|
||||
applyto.dispelDebuff(MapleDisease.ZOMBIFY);
|
||||
applyto.dispelDebuff(MapleDisease.CONFUSE);
|
||||
applyto.dispelDebuffs();
|
||||
applyto.purgeDebuffs();
|
||||
} else if (isComboReset()) {
|
||||
applyto.setCombo((short) 0);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import client.inventory.MapleInventoryType;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
import constants.game.GameConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import net.server.coordinator.world.MapleInviteCoordinator;
|
||||
import net.server.coordinator.world.MapleInviteCoordinator.InviteResult;
|
||||
import net.server.coordinator.world.MapleInviteCoordinator.InviteType;
|
||||
|
||||
@@ -1040,23 +1040,6 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
return isBoss() && getTagColor() > 0;
|
||||
}
|
||||
|
||||
public void broadcastMonsterStatus() {
|
||||
Collection<MonsterStatusEffect> mseList = this.getStati().values();
|
||||
for (MapleCharacter chr : map.getAllPlayers()) {
|
||||
announceMonsterStatusInternal(chr.getClient(), mseList);
|
||||
}
|
||||
}
|
||||
|
||||
public void announceMonsterStatus(MapleClient client) {
|
||||
announceMonsterStatusInternal(client, this.getStati().values());
|
||||
}
|
||||
|
||||
public void announceMonsterStatusInternal(MapleClient client, Collection<MonsterStatusEffect> mseList) {
|
||||
for (MonsterStatusEffect mse : mseList) {
|
||||
client.announce(MaplePacketCreator.applyMonsterStatus(getObjectId(), mse, null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSpawnData(MapleClient client) {
|
||||
if (hp.get() <= 0) { // mustn't monsterLock this function
|
||||
@@ -1068,8 +1051,6 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
client.announce(MaplePacketCreator.spawnMonster(this, false));
|
||||
}
|
||||
|
||||
announceMonsterStatus(client);
|
||||
|
||||
if (hasBossHPBar()) {
|
||||
client.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket());
|
||||
}
|
||||
@@ -1934,7 +1915,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
* Removes controllability status from the current controller of this mob.
|
||||
*
|
||||
*/
|
||||
private Pair<MapleCharacter, Boolean> aggroRemoveController() {
|
||||
public Pair<MapleCharacter, Boolean> aggroRemoveController() {
|
||||
MapleCharacter chrController;
|
||||
boolean hadAggro;
|
||||
|
||||
@@ -1951,7 +1932,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
|
||||
if (chrController != null) { // this can/should only happen when a hidden gm attacks the monster
|
||||
chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
if (!this.isFake()) chrController.announce(MaplePacketCreator.stopControllingMonster(this.getObjectId()));
|
||||
chrController.stopControllingMonster(this);
|
||||
}
|
||||
|
||||
@@ -2123,9 +2104,12 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
MapleCharacter chrController = this.getActiveController();
|
||||
|
||||
if (chrController == null) {
|
||||
this.aggroSwitchController(player, true);
|
||||
this.aggroSwitchController(player, true);
|
||||
} else if (chrController.getId() == player.getId()) {
|
||||
this.setControllerHasAggro(true);
|
||||
if (!YamlConfig.config.server.USE_AUTOAGGRO_NEARBY) { // thanks Lichtmager for noticing autoaggro not updating the player properly
|
||||
aggroMonsterControl(player.getClient(), this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2164,9 +2148,6 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
|
||||
private static void aggroMonsterControl(MapleClient c, MapleMonster mob, boolean immediateAggro) {
|
||||
c.announce(MaplePacketCreator.controlMonster(mob, false, immediateAggro));
|
||||
|
||||
// thanks BHB for noticing puppets disrupting mobstatuses for bowmans
|
||||
mob.announceMonsterStatus(c);
|
||||
}
|
||||
|
||||
private void aggroRefreshPuppetVisibility(MapleCharacter chrController, MapleSummon puppet) {
|
||||
@@ -2185,7 +2166,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
chrController.announce(MaplePacketCreator.removeSummon(puppet, false));
|
||||
|
||||
MapleClient c = chrController.getClient();
|
||||
for (MapleMonster mob : puppetControlled) {
|
||||
for (MapleMonster mob : puppetControlled) { // thanks BHB for noticing puppets disrupting mobstatuses for bowmans
|
||||
aggroMonsterControl(c, mob, mob.isControllerKnowsAboutAggro());
|
||||
}
|
||||
chrController.announce(MaplePacketCreator.spawnSummon(puppet, false));
|
||||
|
||||
@@ -316,16 +316,10 @@ public class MapleMonsterInformationProvider {
|
||||
public String getMobNameFromId(int id) {
|
||||
String mobName = mobNameCache.get(id);
|
||||
if (mobName == null) {
|
||||
try {
|
||||
mobName = MapleLifeFactory.getMonster(id).getName();
|
||||
} catch (NullPointerException npe) {
|
||||
mobName = ""; //nonexistant mob
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.err.println("Nonexistant mob id " + id);
|
||||
mobName = ""; //nonexistant mob
|
||||
}
|
||||
|
||||
MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz"));
|
||||
MapleData mobData = dataProvider.getData("Mob.img");
|
||||
|
||||
mobName = MapleDataTool.getString(mobData.getChildByPath(id + "/name"), "");
|
||||
mobNameCache.put(id, mobName);
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.game.GameConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import net.server.Server;
|
||||
import net.server.channel.Channel;
|
||||
import net.server.world.World;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
package server.life;
|
||||
|
||||
import constants.net.ServerConstants;
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -413,18 +413,6 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
this.removeOwner(c.getPlayer());
|
||||
|
||||
try {
|
||||
MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterById(ownerId);
|
||||
if(player != null) {
|
||||
player.setHasMerchant(false);
|
||||
} else {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0 WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) {
|
||||
ps.setInt(1, ownerId);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
con.close();
|
||||
}
|
||||
|
||||
List<MaplePlayerShopItem> copyItems = getItems();
|
||||
if (check(c.getPlayer(), copyItems) && !timeout) {
|
||||
for (MaplePlayerShopItem mpsi : copyItems) {
|
||||
@@ -448,6 +436,19 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// thanks Rohenn for noticing a possible dupe scenario on closing shop
|
||||
MapleCharacter player = c.getWorldServer().getPlayerStorage().getCharacterById(ownerId);
|
||||
if(player != null) {
|
||||
player.setHasMerchant(false);
|
||||
} else {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("UPDATE characters SET HasMerchant = 0 WHERE id = ?", Statement.RETURN_GENERATED_KEYS)) {
|
||||
ps.setInt(1, ownerId);
|
||||
ps.executeUpdate();
|
||||
}
|
||||
con.close();
|
||||
}
|
||||
|
||||
if (YamlConfig.config.server.USE_ENFORCE_MERCHANT_SAVE) {
|
||||
c.getPlayer().saveCharToDB(false);
|
||||
}
|
||||
|
||||
@@ -2017,7 +2017,7 @@ public class MapleMap {
|
||||
if (getEventInstance() != null) {
|
||||
getEventInstance().registerMonster(monster);
|
||||
}
|
||||
|
||||
|
||||
spawnAndAddRangedMapObject(monster, new DelayedPacketCreation() {
|
||||
@Override
|
||||
public void sendPackets(MapleClient c) {
|
||||
@@ -2108,7 +2108,7 @@ public class MapleMap {
|
||||
c.announce(MaplePacketCreator.spawnFakeMonster(monster, 0));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
spawnedMonstersOnMap.incrementAndGet();
|
||||
addSelfDestructive(monster);
|
||||
}
|
||||
@@ -2116,7 +2116,6 @@ public class MapleMap {
|
||||
public void makeMonsterReal(final MapleMonster monster) {
|
||||
monster.setFake(false);
|
||||
broadcastMessage(MaplePacketCreator.makeMonsterReal(monster));
|
||||
monster.broadcastMonsterStatus();
|
||||
monster.aggroUpdateController();
|
||||
updateBossSpawn(monster);
|
||||
}
|
||||
@@ -3081,8 +3080,6 @@ public class MapleMap {
|
||||
for (MapleMapObject o : objects) {
|
||||
if (isNonRangedType(o.getType())) {
|
||||
o.sendSpawnData(c);
|
||||
} else if (o.getType() == MapleMapObjectType.MONSTER) {
|
||||
((MapleMonster) o).aggroUpdateController();
|
||||
} else if (o.getType() == MapleMapObjectType.SUMMON) {
|
||||
MapleSummon summon = (MapleSummon) o;
|
||||
if (summon.getOwner() == chr) {
|
||||
@@ -3110,6 +3107,10 @@ public class MapleMap {
|
||||
} else {
|
||||
o.sendSpawnData(chr.getClient());
|
||||
chr.addVisibleMapObject(o);
|
||||
|
||||
if (o.getType() == MapleMapObjectType.MONSTER) {
|
||||
((MapleMonster) o).aggroUpdateController();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1486,6 +1486,43 @@ public class MaplePacketCreator {
|
||||
mplew.write(newSpawn ? -2 : -1);
|
||||
}
|
||||
|
||||
private static void encodeTemporary(MaplePacketLittleEndianWriter mplew, Map<MonsterStatus, MonsterStatusEffect> stati) {
|
||||
int pCounter = -1, mCounter = -1;
|
||||
|
||||
writeLongEncodeTemporaryMask(mplew, stati.keySet()); // packet structure mapped thanks to Eric
|
||||
|
||||
for (Entry<MonsterStatus, MonsterStatusEffect> s : stati.entrySet()) {
|
||||
MonsterStatusEffect mse = s.getValue();
|
||||
mplew.writeShort(mse.getStati().get(s.getKey()));
|
||||
|
||||
MobSkill mobSkill = mse.getMobSkill();
|
||||
if (mobSkill != null) {
|
||||
mplew.writeShort(mobSkill.getSkillId());
|
||||
mplew.writeShort(mobSkill.getSkillLevel());
|
||||
|
||||
switch(s.getKey()) {
|
||||
case WEAPON_REFLECT:
|
||||
pCounter = mobSkill.getX();
|
||||
break;
|
||||
|
||||
case MAGIC_REFLECT:
|
||||
mCounter = mobSkill.getY();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Skill skill = mse.getSkill();
|
||||
mplew.writeInt(skill != null ? skill.getId() : 0);
|
||||
}
|
||||
|
||||
mplew.writeShort(-1); // duration
|
||||
}
|
||||
|
||||
// reflect packet structure found thanks to Arnah (Vertisy)
|
||||
if(pCounter != -1) mplew.writeInt(pCounter);// wPCounter_
|
||||
if(mCounter != -1) mplew.writeInt(mCounter);// wMCounter_
|
||||
if(pCounter != -1 || mCounter != -1) mplew.writeInt(100);// nCounterProb_
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal function to handler monster spawning and controlling.
|
||||
*
|
||||
@@ -1513,9 +1550,13 @@ public class MaplePacketCreator {
|
||||
mplew.writeInt(life.getObjectId());
|
||||
mplew.write(life.getController() == null ? 5 : 1);
|
||||
mplew.writeInt(life.getId());
|
||||
mplew.skip(15);
|
||||
mplew.write(0x88);
|
||||
mplew.skip(6);
|
||||
|
||||
if (requestController) {
|
||||
encodeTemporary(mplew, life.getStati()); // thanks shot for noticing encode temporary buffs missing
|
||||
} else {
|
||||
mplew.skip(16);
|
||||
}
|
||||
|
||||
mplew.writePos(life.getPosition());
|
||||
mplew.write(life.getStance());
|
||||
mplew.writeShort(0); //Origin FH //life.getStartFh()
|
||||
@@ -1561,9 +1602,7 @@ public class MaplePacketCreator {
|
||||
mplew.writeInt(life.getObjectId());
|
||||
mplew.write(5);
|
||||
mplew.writeInt(life.getId());
|
||||
mplew.skip(15);
|
||||
mplew.write(0x88);
|
||||
mplew.skip(6);
|
||||
encodeTemporary(mplew, life.getStati());
|
||||
mplew.writePos(life.getPosition());
|
||||
mplew.write(life.getStance());
|
||||
mplew.writeShort(0);//life.getStartFh()
|
||||
@@ -1591,9 +1630,7 @@ public class MaplePacketCreator {
|
||||
mplew.writeInt(life.getObjectId());
|
||||
mplew.write(5);
|
||||
mplew.writeInt(life.getId());
|
||||
mplew.skip(15);
|
||||
mplew.write(0x88);
|
||||
mplew.skip(6);
|
||||
encodeTemporary(mplew, life.getStati());
|
||||
mplew.writePos(life.getPosition());
|
||||
mplew.write(life.getStance());
|
||||
mplew.writeShort(0);//life.getStartFh()
|
||||
@@ -3151,6 +3188,21 @@ public class MaplePacketCreator {
|
||||
mplew.writeLong(firstmask);
|
||||
mplew.writeLong(secondmask);
|
||||
}
|
||||
|
||||
private static void writeLongEncodeTemporaryMask(final MaplePacketLittleEndianWriter mplew, Collection<MonsterStatus> stati) {
|
||||
int masks[] = new int[4];
|
||||
|
||||
for (MonsterStatus statup : stati) {
|
||||
int pos = statup.isFirst() ? 0 : 2;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
masks[pos + i] |= statup.getValue() >> 32 * i;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < masks.length; i++) {
|
||||
mplew.writeInt(masks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] cancelDebuff(long mask) {
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(19);
|
||||
@@ -4137,30 +4189,6 @@ public class MaplePacketCreator {
|
||||
mplew.writeInt(secondmask);
|
||||
}
|
||||
|
||||
public static byte[] applyMonsterStatus(int oid, Map<MonsterStatus, Integer> stats, int skill, boolean monsterSkill, int delay, MobSkill mobskill) {
|
||||
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
mplew.writeShort(SendOpcode.APPLY_MONSTER_STATUS.getValue());
|
||||
mplew.writeInt(oid);
|
||||
int mask = 0;
|
||||
for (MonsterStatus stat : stats.keySet()) {
|
||||
mask |= stat.getValue();
|
||||
}
|
||||
mplew.writeInt(mask);
|
||||
for (Integer val : stats.values()) {
|
||||
mplew.writeShort(val);
|
||||
if (monsterSkill) {
|
||||
mplew.writeShort(mobskill.getSkillId());
|
||||
mplew.writeShort(mobskill.getSkillLevel());
|
||||
} else {
|
||||
mplew.writeInt(skill);
|
||||
}
|
||||
mplew.writeShort(0); // as this looks similar to giveBuff this
|
||||
}
|
||||
mplew.writeShort(delay); // delay in ms
|
||||
mplew.write(1); // ?
|
||||
return mplew.getPacket();
|
||||
}
|
||||
|
||||
public static byte[] applyMonsterStatus(final int oid, final MonsterStatusEffect mse, final List<Integer> reflection) {
|
||||
Map<MonsterStatus, Integer> stati = mse.getStati();
|
||||
final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
|
||||
|
||||
@@ -23,7 +23,6 @@ import client.MapleCharacter;
|
||||
import config.YamlConfig;
|
||||
import constants.game.GameConstants;
|
||||
import constants.inventory.ItemConstants;
|
||||
import constants.net.ServerConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user