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:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user