Quest & Command tweak + MapleCashDropFetcher + Cash drop tidyup

Solved a possible exploit on starting/completing non-scripted quests.
Added missing drop data for Aran's puppeteer questline.
Moved GM tier level of some commands.
Applied proper synchronization for BuddyList modules.
Issued commands now requires "@" heading for normal players and donators (GM level < 2) and "!" for Jr. GM and above (GM level >= 2).
Added custom feature: a message will be sent to acquaintances of a player (friends, family, guild, spouse) when they change/upgrade jobs.
Removed cash drop entries from the DB.
New tool: MapleCashDropFetcher. Reports on a text file all cash-type drop data on DB.
This commit is contained in:
ronancpl
2018-04-14 13:38:14 -03:00
parent 6d91c79f28
commit 6a63f9d95e
38 changed files with 3472 additions and 1057 deletions

View File

@@ -26,10 +26,12 @@ import java.sql.ResultSet;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import net.server.PlayerStorage;
import tools.DatabaseConnection;
import tools.MaplePacketCreator;
@@ -50,15 +52,22 @@ public class BuddyList {
}
public boolean contains(int characterId) {
return buddies.containsKey(Integer.valueOf(characterId));
synchronized(buddies) {
return buddies.containsKey(Integer.valueOf(characterId));
}
}
public boolean containsVisible(int characterId) {
BuddylistEntry ble = buddies.get(characterId);
BuddylistEntry ble;
synchronized(buddies) {
ble = buddies.get(characterId);
}
if (ble == null) {
return false;
}
return ble.isVisible();
}
public int getCapacity() {
@@ -70,42 +79,65 @@ public class BuddyList {
}
public BuddylistEntry get(int characterId) {
return buddies.get(Integer.valueOf(characterId));
synchronized(buddies) {
return buddies.get(Integer.valueOf(characterId));
}
}
public BuddylistEntry get(String characterName) {
String lowerCaseName = characterName.toLowerCase();
for (BuddylistEntry ble : buddies.values()) {
for (BuddylistEntry ble : getBuddies()) {
if (ble.getName().toLowerCase().equals(lowerCaseName)) {
return ble;
}
}
return null;
}
public void put(BuddylistEntry entry) {
buddies.put(Integer.valueOf(entry.getCharacterId()), entry);
synchronized(buddies) {
buddies.put(Integer.valueOf(entry.getCharacterId()), entry);
}
}
public void remove(int characterId) {
buddies.remove(Integer.valueOf(characterId));
synchronized(buddies) {
buddies.remove(Integer.valueOf(characterId));
}
}
public Collection<BuddylistEntry> getBuddies() {
return buddies.values();
synchronized(buddies) {
return Collections.unmodifiableCollection(buddies.values());
}
}
public boolean isFull() {
return buddies.size() >= capacity;
synchronized(buddies) {
return buddies.size() >= capacity;
}
}
public int[] getBuddyIds() {
int buddyIds[] = new int[buddies.size()];
int i = 0;
for (BuddylistEntry ble : buddies.values()) {
buddyIds[i++] = ble.getCharacterId();
synchronized(buddies) {
int buddyIds[] = new int[buddies.size()];
int i = 0;
for (BuddylistEntry ble : buddies.values()) {
buddyIds[i++] = ble.getCharacterId();
}
return buddyIds;
}
}
public void broadcast(byte[] packet, PlayerStorage pstorage) {
for(int bid : getBuddyIds()) {
MapleCharacter chr = pstorage.getCharacterById(bid);
if(chr != null && chr.isLoggedin() && !chr.isAwayFromWorld()) {
chr.announce(packet);
}
}
return buddyIds;
}
public void loadFromDb(int characterId) {

View File

@@ -199,7 +199,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
private int expRate = 1, mesoRate = 1, dropRate = 1, expCoupon = 1, mesoCoupon = 1, dropCoupon = 1;
private int omokwins, omokties, omoklosses, matchcardwins, matchcardties, matchcardlosses;
private int owlSearch;
private int married;
private long lastfametime, lastUsedCashItem, lastHealed, lastMesoDrop = -1, jailExpiration = -1;
private transient int localmaxhp, localmaxmp, localstr, localdex, localluk, localint_, magic, watk;
private boolean hidden, canDoor = true, berserk, hasMerchant, whiteChat = false;
@@ -1093,6 +1092,36 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
}
createDragon();
}
if(ServerConstants.USE_ANNOUNCE_CHANGEJOB) {
if(gmLevel > 1) {
broadcastAcquaintances(6, "[" + GameConstants.ordinal(GameConstants.getJobBranch(newJob)) + " Job] " + name + " has just become a " + newJob.name() + ".");
}
}
}
public void broadcastAcquaintances(int type, String message) {
broadcastAcquaintances(MaplePacketCreator.serverNotice(type, message));
}
public void broadcastAcquaintances(byte[] packet) {
buddylist.broadcast(packet, client.getWorldServer().getPlayerStorage());
if(family != null) {
//family.broadcast(packet, id); not yet implemented
}
MapleGuild guild = getGuild();
if(guild != null) {
guild.broadcast(packet, id);
}
/*
if(partnerid > 0) {
partner.announce(packet); not yet implemented
}
*/
announce(packet);
}
public void changeKeybinding(int key, MapleKeyBinding keybinding) {
@@ -3955,10 +3984,6 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return marriageRing;
}
public int getMarried() {
return married;
}
public int getMasterLevel(Skill skill) {
if (skills.get(skill) == null) {
return 0;

View File

@@ -351,7 +351,7 @@ public class Commands {
case "playercommands":
c.getAbstractPlayerInteraction().openNpc(9201143, "commands");
break;
case "droplimit":
int dropCount = c.getPlayer().getMap().getDroppedItemCount();
if(((float) dropCount) / ServerConstants.ITEM_LIMIT_ON_MAP < 0.75f) {
@@ -402,90 +402,14 @@ public class Commands {
}
break;
}
String output = "The #b" + gachaName + "#k Gachapon contains the following items.\r\n\r\n";
String talkStr = "The #b" + gachaName + "#k Gachapon contains the following items.\r\n\r\n";
for (int i = 0; i < 2; i++){
for (int id : gacha.getItems(i)){
output += "-" + MapleItemInformationProvider.getInstance().getName(id) + "\r\n";
talkStr += "-" + MapleItemInformationProvider.getInstance().getName(id) + "\r\n";
}
}
output += "\r\nPlease keep in mind that there are items that are in all gachapons and are not listed here.";
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
break;
case "whatdropsfrom":
if (sub.length < 2) {
player.dropMessage(5, "Please do @whatdropsfrom <monster name>");
break;
}
String monsterName = joinStringFrom(sub, 1);
output = "";
int limit = 3;
Iterator<Pair<Integer, String>> listIterator = MapleMonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
for (int i = 0; i < limit; i++) {
if(listIterator.hasNext()) {
Pair<Integer, String> data = listIterator.next();
int mobId = data.getLeft();
String mobName = data.getRight();
output += mobName + " drops the following items:\r\n\r\n";
for (MonsterDropEntry drop : MapleMonsterInformationProvider.getInstance().retrieveDrop(mobId)){
try {
String name = MapleItemInformationProvider.getInstance().getName(drop.itemId);
if (name.equals("null") || drop.chance == 0){
continue;
}
float chance = 1000000 / drop.chance / player.getDropRate();
output += "- " + name + " (1/" + (int) chance + ")\r\n";
} catch (Exception ex){
ex.printStackTrace();
continue;
}
}
output += "\r\n";
}
}
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
break;
case "whodrops":
if (sub.length < 2) {
player.dropMessage(5, "Please do @whodrops <item name>");
break;
}
String searchString = joinStringFrom(sub, 1);
output = "";
listIterator = MapleItemInformationProvider.getInstance().getItemDataByName(searchString).iterator();
if(listIterator.hasNext()) {
int count = 1;
while(listIterator.hasNext() && count <= 3) {
Pair<Integer, String> data = listIterator.next();
output += "#b" + data.getRight() + "#k is dropped by:\r\n";
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50");
ps.setInt(1, data.getLeft());
ResultSet rs = ps.executeQuery();
while(rs.next()) {
String resultName = MapleMonsterInformationProvider.getMobNameFromID(rs.getInt("dropperid"));
if (resultName != null) {
output += resultName + ", ";
}
}
rs.close();
ps.close();
con.close();
} catch (Exception e) {
player.dropMessage(6, "There was a problem retrieving the required data. Please try again.");
e.printStackTrace();
break;
}
output += "\r\n\r\n";
count++;
}
} else {
player.dropMessage(5, "The item you searched for doesn't exist.");
break;
}
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
talkStr += "\r\nPlease keep in mind that there are items that are in all gachapons and are not listed here.";
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, talkStr, "00 00", (byte) 0));
break;
case "dispose":
@@ -560,7 +484,7 @@ public class Commands {
player.dropMessage(5, tips[Randomizer.nextInt(tips.length)]);
break;
case "bug":
case "reportbug":
if (sub.length < 2) {
player.dropMessage(5, "Message too short and not sent. Please do @bug <bug>");
@@ -636,30 +560,6 @@ public class Commands {
}
break;
case "bosshp":
for(MapleMonster monster : player.getMap().getMonsters()) {
if(monster != null && monster.isBoss() && monster.getHp() > 0) {
long percent = monster.getHp() * 100L / monster.getMaxHp();
String bar = "[";
for (int i = 0; i < 100; i++){
bar += i < percent ? "|" : ".";
}
bar += "]";
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + percent + "% HP left.");
player.yellowMessage("HP: " + bar);
}
}
break;
case "mobhp":
for(MapleMonster monster : player.getMap().getMonsters()) {
if(monster != null && monster.getHp() > 0) {
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + monster.getHp() + " / " + monster.getMaxHp() + " HP.");
}
}
break;
case "ranks":
PreparedStatement ps = null;
ResultSet rs = null;
@@ -691,6 +591,47 @@ public class Commands {
}
}
break;
// stat autoassigning command credited to HeliosMS dev team
case "str":
case "int":
case "luk":
case "dex":
int amount = (sub.length > 1) ? Integer.parseInt(sub[1]) : player.getRemainingAp();
boolean str = sub[0].equalsIgnoreCase("str");
boolean Int = sub[0].equalsIgnoreCase("int");
boolean luk = sub[0].equalsIgnoreCase("luk");
boolean dex = sub[0].equalsIgnoreCase("dex");
if (amount > 0 && amount <= player.getRemainingAp() && amount <= 32763 || amount < 0 && amount >= -32763 && Math.abs(amount) + player.getRemainingAp() <= 32767) {
if (str && amount + player.getStr() <= 32767 && amount + player.getStr() >= 4) {
player.setStr(player.getStr() + amount);
player.updateSingleStat(MapleStat.STR, player.getStr());
player.setRemainingAp(player.getRemainingAp() - amount);
player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
} else if (Int && amount + player.getInt() <= 32767 && amount + player.getInt() >= 4) {
player.setInt(player.getInt() + amount);
player.updateSingleStat(MapleStat.INT, player.getInt());
player.setRemainingAp(player.getRemainingAp() - amount);
player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
} else if (luk && amount + player.getLuk() <= 32767 && amount + player.getLuk() >= 4) {
player.setLuk(player.getLuk() + amount);
player.updateSingleStat(MapleStat.LUK, player.getLuk());
player.setRemainingAp(player.getRemainingAp() - amount);
player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
} else if (dex && amount + player.getDex() <= 32767 && amount + player.getDex() >= 4) {
player.setDex(player.getDex() + amount);
player.updateSingleStat(MapleStat.DEX, player.getDex());
player.setRemainingAp(player.getRemainingAp() - amount);
player.updateSingleStat(MapleStat.AVAILABLEAP, player.getRemainingAp());
} else {
player.dropMessage("Please make sure the stat you are trying to raise is not over 32,767 or under 4.");
}
} else {
player.dropMessage("Please make sure your AP is not over 32,767 and you have enough to distribute.");
}
break;
default:
return false;
@@ -702,8 +643,113 @@ public class Commands {
public static boolean executeHeavenMsCommandLv1(Channel cserv, Server srv, MapleClient c, String[] sub) { //Donator
MapleCharacter player = c.getPlayer();
switch(sub[0]) {
switch(sub[0]) {
case "bosshp":
for(MapleMonster monster : player.getMap().getMonsters()) {
if(monster != null && monster.isBoss() && monster.getHp() > 0) {
long percent = monster.getHp() * 100L / monster.getMaxHp();
String bar = "[";
for (int i = 0; i < 100; i++){
bar += i < percent ? "|" : ".";
}
bar += "]";
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + percent + "% HP left.");
player.yellowMessage("HP: " + bar);
}
}
break;
case "mobhp":
for(MapleMonster monster : player.getMap().getMonsters()) {
if(monster != null && monster.getHp() > 0) {
player.yellowMessage(monster.getName() + " (" + monster.getId() + ") has " + monster.getHp() + " / " + monster.getMaxHp() + " HP.");
}
}
break;
case "whatdropsfrom":
if (sub.length < 2) {
player.dropMessage(5, "Please do @whatdropsfrom <monster name>");
break;
}
String monsterName = joinStringFrom(sub, 1);
String output = "";
int limit = 3;
Iterator<Pair<Integer, String>> listIterator = MapleMonsterInformationProvider.getMobsIDsFromName(monsterName).iterator();
for (int i = 0; i < limit; i++) {
if(listIterator.hasNext()) {
Pair<Integer, String> data = listIterator.next();
int mobId = data.getLeft();
String mobName = data.getRight();
output += mobName + " drops the following items:\r\n\r\n";
for (MonsterDropEntry drop : MapleMonsterInformationProvider.getInstance().retrieveDrop(mobId)){
try {
String name = MapleItemInformationProvider.getInstance().getName(drop.itemId);
if (name.equals("null") || drop.chance == 0){
continue;
}
float chance = 1000000 / drop.chance / player.getDropRate();
output += "- " + name + " (1/" + (int) chance + ")\r\n";
} catch (Exception ex){
ex.printStackTrace();
continue;
}
}
output += "\r\n";
}
}
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
break;
case "whodrops":
if (sub.length < 2) {
player.dropMessage(5, "Please do @whodrops <item name>");
break;
}
String searchString = joinStringFrom(sub, 1);
output = "";
listIterator = MapleItemInformationProvider.getInstance().getItemDataByName(searchString).iterator();
if(listIterator.hasNext()) {
int count = 1;
while(listIterator.hasNext() && count <= 3) {
Pair<Integer, String> data = listIterator.next();
output += "#b" + data.getRight() + "#k is dropped by:\r\n";
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT dropperid FROM drop_data WHERE itemid = ? LIMIT 50");
ps.setInt(1, data.getLeft());
ResultSet rs = ps.executeQuery();
while(rs.next()) {
String resultName = MapleMonsterInformationProvider.getMobNameFromID(rs.getInt("dropperid"));
if (resultName != null) {
output += resultName + ", ";
}
}
rs.close();
ps.close();
con.close();
} catch (Exception e) {
player.dropMessage(6, "There was a problem retrieving the required data. Please try again.");
e.printStackTrace();
break;
}
output += "\r\n\r\n";
count++;
}
} else {
player.dropMessage(5, "The item you searched for doesn't exist.");
break;
}
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
break;
case "buffme":
if(!player.isGM()) {
player.dropMessage(5, "You are already dead.");
break;
}
//GM Skills : Haste(Super) - Holy Symbol - Bless - Hyper Body - Echo of Hero
SkillFactory.getSkill(4101004).getEffect(SkillFactory.getSkill(4101004).getMaxLevel()).applyTo(player);
SkillFactory.getSkill(2311003).getEffect(SkillFactory.getSkill(2311003).getMaxLevel()).applyTo(player);
@@ -753,7 +799,20 @@ public class Commands {
}
player.dropMessage(5, "USE Recharged.");
break;
default:
return false;
}
return true;
}
public static boolean executeHeavenMsCommandLv2(Channel cserv, Server srv, MapleClient c, String[] sub) { //JrGM
MapleCharacter player = c.getPlayer();
MapleCharacter victim;
Skill skill;
switch(sub[0]) {
case "whereami":
player.yellowMessage("Map ID: " + player.getMap().getId());
player.yellowMessage("Players on this map:");
@@ -777,21 +836,8 @@ public class Commands {
}
}
}
break;
default:
return false;
}
return true;
}
public static boolean executeHeavenMsCommandLv2(Channel cserv, Server srv, MapleClient c, String[] sub) { //JrGM
MapleCharacter player = c.getPlayer();
MapleCharacter victim;
Skill skill;
switch(sub[0]) {
break;
case "hide":
SkillFactory.getSkill(9101004).getEffect(SkillFactory.getSkill(9101004).getMaxLevel()).applyTo(player);
break;

View File

@@ -62,26 +62,36 @@ public class GameConstants {
330000, 340000, 350000, 360000, 370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000, 490000, 500000, 510000, 520000,
530000, 550000, 570000, 590000, 610000, 630000, 650000, 670000, 690000, 710000, 730000, 750000, 770000, 790000, 810000, 830000, 850000, 870000, 890000, 910000};
public static int getJobMaxLevel(MapleJob job) {
if(job.getId() % 1000 == 0) { // beginner
return 10;
} else if(job.getId() % 100 == 0) { // 1st job
return 30;
public static int getJobBranch(MapleJob job) {
int jobid = job.getId();
if(jobid % 1000 == 0) {
return 0;
} else if(jobid % 100 == 0) {
return 1;
} else {
int jobBranch = job.getId() % 10;
switch(jobBranch) {
case 0:
return 70; // 2nd job
case 1:
return 120; // 3rd job
default:
return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200
}
return 2 + (jobid % 10);
}
}
public static int getJobMaxLevel(MapleJob job) {
int jobBranch = getJobBranch(job);
switch(jobBranch) {
case 0:
return 10; // beginner
case 1:
return 30; // 1st job
case 2:
return 70; // 2nd job
case 3:
return 120; // 3rd job
default:
return (job.getId() / 1000 == 1) ? 120 : 200; // 4th job: cygnus is 120, rest is 200
}
}
@@ -225,4 +235,17 @@ public class GameConstants {
}
return mobHpVal[level];
}
public static String ordinal(int i) {
String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
switch (i % 100) {
case 11:
case 12:
case 13:
return i + "th";
default:
return i + sufixes[i % 10];
}
}
}

View File

@@ -73,6 +73,10 @@ public class ServerConstants {
public static final boolean USE_QUEST_RATE = false; //Exp/Meso gained by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates.
public static final boolean USE_MULTIPLE_SAME_EQUIP_DROP = true;//Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
//Announcement Configuration
public static final boolean USE_ANNOUNCE_CHANGEJOB = true; //Automatic message sent to acquantainces when changing jobs.
//Server Rates And Experience
public static final int EXP_RATE = 10;
public static final int MESO_RATE = 10;
@@ -158,7 +162,7 @@ public class ServerConstants {
public static final boolean USE_DEADLY_DOJO = false; //Should bosses really use 1HP,1MP attacks in dojo?
public static final int DOJO_ENERGY_ATK = 100; //Dojo energy gain when deal attack
public static final int DOJO_ENERGY_DMG = 20; //Dojo energy gain when recv attack
//Event End Timestamp
public static final long EVENT_END_TIMESTAMP = 1428897600000L;

View File

@@ -32,6 +32,14 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
public final class GeneralChatHandler extends net.AbstractMaplePacketHandler {
private static boolean isCommandIssue(char heading, MapleCharacter chr) {
if(chr.gmLevel() > 1 && heading == '!') {
return true;
} else {
return heading == '@';
}
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
String s = slea.readMapleAsciiString();
@@ -47,7 +55,7 @@ public final class GeneralChatHandler extends net.AbstractMaplePacketHandler {
return;
}
char heading = s.charAt(0);
if (heading == '!' || heading == '@') {
if (isCommandIssue(heading, chr)) {
String[] sp = s.split(" ");
sp[0] = sp[0].toLowerCase().substring(1);

View File

@@ -44,15 +44,21 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler {
if (slea.available() >= 4) {
slea.readInt();
}
quest.start(player, npc);
if(quest.canStart(player, npc)) {
quest.start(player, npc);
}
} else if (action == 2) { // Complete Quest
int npc = slea.readInt();
slea.readInt();
if (slea.available() >= 2) {
int selection = slea.readShort();
quest.complete(player, npc, selection);
} else {
quest.complete(player, npc);
if(quest.canComplete(player, npc)) {
if (slea.available() >= 2) {
int selection = slea.readShort();
quest.complete(player, npc, selection);
} else {
quest.complete(player, npc);
}
}
} else if (action == 3) {// forfeit quest
quest.forfeit(player);

View File

@@ -34,6 +34,7 @@ import javax.script.Invocable;
import javax.script.ScriptException;
import constants.ServerConstants;
import constants.GameConstants;
import client.MapleCharacter;
import net.server.Server;
import net.server.world.World;
@@ -499,19 +500,6 @@ public class EventManager {
return(MapleLifeFactory.getMonster(mid));
}
private static String ordinal(int i) {
String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" };
switch (i % 100) {
case 11:
case 12:
case 13:
return i + "th";
default:
return i + sufixes[i % 10];
}
}
private void exportReadyGuild(Integer guildId) {
MapleGuild mg = server.getGuild(guildId);
String callout = "[Guild Quest] Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
@@ -524,7 +512,7 @@ public class EventManager {
private void exportMovedQueueToGuild(Integer guildId, int place) {
MapleGuild mg = server.getGuild(guildId);
String callout = "[Guild Quest] Your guild has been registered to attend to the Sharenian Guild Quest at channel " + this.getChannelServer().getId()
+ " and is currently on the " + ordinal(place) + " place on the waiting queue.";
+ " and is currently on the " + GameConstants.ordinal(place) + " place on the waiting queue.";
mg.dropMessage(6, callout);
}

View File

@@ -61,7 +61,7 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "Quest " + questid + " is uncoded.\r\n");
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "START Quest " + questid + " is uncoded.\r\n");
}
if (iv == null || QuestScriptManager.getInstance() == null) {
qm.dispose();
@@ -112,6 +112,7 @@ public class QuestScriptManager extends AbstractScriptManager {
qms.put(c, qm);
Invocable iv = getInvocable("quest/" + questid + ".js", c);
if (iv == null) {
FilePrinter.printError(FilePrinter.QUEST_UNCODED, "END Quest " + questid + " is uncoded.\r\n");
qm.dispose();
return;
}

View File

@@ -535,8 +535,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
}
}, getAnimationTime("die1"));
}
}
else { // is this even necessary?
} else { // is this even necessary?
System.out.println("[CRITICAL LOSS] toSpawn is null for " + this.getName());
}