diff --git a/scripts/npc/mapleTV.js b/scripts/npc/mapleTV.js
index d0cd016385..913e0dcf3a 100644
--- a/scripts/npc/mapleTV.js
+++ b/scripts/npc/mapleTV.js
@@ -24,13 +24,6 @@
var status;
function start() {
- const YamlConfig = Java.type('config.YamlConfig');
- if (YamlConfig.config.server.USE_ENABLE_CUSTOM_NPC_SCRIPT) {
- cm.dispose();
- cm.openNpc(9201088, "scroll_generator");
- return;
- }
-
status = -1;
action(1, 0, 0);
}
@@ -54,4 +47,4 @@ function action(mode, type, selection) {
cm.dispose();
}
}
-}
\ No newline at end of file
+}
diff --git a/scripts/npc/scroll_generator.js b/scripts/npc/scroll_generator.js
deleted file mode 100644
index 91acf32a0a..0000000000
--- a/scripts/npc/scroll_generator.js
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- This file is part of the HeavenMS MapleStory Server
- Copyleft (L) 2016 - 2019 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 .
-*/
-/* NPC: MapleTV / Larry
-
- Exchanger NPC:
- * Scroll generator
- *
- * @author Ronan Lana
-*/
-
-var status;
-
-var jobWeaponRestricted = [[[2043000, 2043100, 2044000, 2044100, 2043200, 2044200]], [[2043000, 2043100, 2044000, 2044100], [2043000, 2043200, 2044000, 2044200], [2044300, 2044400]], [[2043700, 2043800], [2043700, 2043800], [2043700, 2043800]], [[2044500], [2044600]], [[2044700], [2043300]], [[2044800], [2044900]]];
-var aranWeaponRestricted = [jobWeaponRestricted[1][2][1]];
-
-var tier1Scrolls = [];
-var tier2Scrolls = [2040000, 2040400, 2040500, 2040600, 2040700, 2040800, 2040900];
-var tier3Scrolls = [2048000, 2049200, 2041000, 2041100, 2041300, 2040100, 2040200, 2040300];
-
-var typeTierScrolls = [["PAD", "MAD"], ["STR", "DEX", "INT", "LUK", "ACC", "EVA", "Speed", "Jump"], ["PDD", "MDD", "MHP", "MMP"]];
-
-var sgItems = [4003004, 4003005, 4001006, 4006000, 4006001, 4030012];
-var sgToBucket = [100, 50, 37.5, 37.5, 37.5, 200];
-var mesoToBucket = 2800000;
-
-var sgAppliedItems = [0, 0, 0, 0, 0, 0];
-var sgAppliedMeso = 0;
-
-var sgBuckets = 0.0;
-var sgBookBuckets = 0.0;
-var sgItemBuckets = 0.0;
-
-function start() {
- status = -1;
- action(1, 0, 0);
-}
-
-function action(mode, type, selection) {
- if (mode == -1) {
- cm.dispose();
- } else {
- if (mode == 0 && type > 0) {
- cm.dispose();
- return;
- }
- if (mode == 1) {
- status++;
- } else {
- status--;
- }
-
- if (status == 0) {
- cm.sendNext("This is the MapleTV Scroll Generator broadcast. Place your supplies or mesos earned throughout your adventure to redeem a prize! You can place #bany amount of supplies#k, however take note that placing #rdifferent supplies#k with #rbigger shots of any of them#k will improve the reward possibilities!");
- } else if (status == 1) {
- var sendStr;
-
- //print("Book: " + sgBookBuckets + " Item: " + sgItemBuckets);
-
- if (sgItemBuckets > 0.0) {
- sendStr = "With the items you have currently placed, you have #r" + sgBuckets + "#k buckets (#r" + (sgItemBuckets < 1.0 ? sgItemBuckets.toFixed(2) : Math.floor(sgItemBuckets)) + "#k supply buckets) for claiming a prize. Place supplies:";
- } else {
- sendStr = "You have placed no supplies yet. Place supplies:";
- }
-
- var listStr = "";
- var i;
- for (i = 0; i < sgItems.length; i++) {
- listStr += "#b#L" + i + "##t" + sgItems[i] + "##k";
- if (sgAppliedItems[i] > 0) {
- listStr += " - " + sgAppliedItems[i];
- }
- listStr += "#l\r\n";
- }
-
- listStr += "#b#L" + i + "#Mesos#k";
- if (sgAppliedMeso > 0) {
- listStr += " - " + sgAppliedMeso;
- }
- listStr += "#l\r\n";
-
- cm.sendSimple(sendStr + "\r\n\r\n" + listStr + "#r#L" + (sgItems.length + 2) + "#Retrieve a prize!#l#k\r\n");
- } else if (status == 2) {
- if (selection == (sgItems.length + 2)) {
- if (sgItemBuckets < 1.0) {
- cm.sendPrev("You have set not enough supplies. Insert at least one bucket of #bsupplies#k to claim a prize.");
- } else {
- generateRandomScroll();
- cm.dispose();
- }
- } else {
- var tickSel;
- if (selection < sgItems.length) {
- tickSel = "of #b#t" + sgItems[selection] + "##k";
- curItemQty = cm.getItemQuantity(sgItems[selection]);
- } else {
- tickSel = "#bmesos#k";
- curItemQty = cm.getMeso();
- }
-
- curItemSel = selection;
- if (curItemQty > 0) {
- cm.sendGetText("How many " + tickSel + " do you want to provide? (#r" + curItemQty + "#k available)#k");
- } else {
- cm.sendPrev("You have got #rnone#k " + tickSel + " to provide for Scroll Generation. Click '#rBack#k' to return to the main interface.");
- }
- }
- } else if (status == 3) {
- var text = cm.getText();
-
- try {
- var placedQty = parseInt(text);
- if (isNaN(placedQty) || placedQty < 0) {
- throw true;
- }
-
- if (placedQty > curItemQty) {
- cm.sendPrev("You cannot insert the given amount of #r" + (curItemSel < sgItems.length ? "#t" + sgItems[curItemSel] + "#" : "mesos") + "#k (#r" + curItemQty + "#k available). Click '#rBack#k' to return to the main interface.");
- } else {
- if (curItemSel < sgItems.length) {
- sgApplyItem(curItemSel, placedQty);
- } else {
- sgApplyMeso(placedQty);
- }
-
- cm.sendPrev("Operation succeeded. Click '#rBack#k' to return to the main interface.");
- }
- } catch (err) {
- cm.sendPrev("You must enter a positive number of supplies to insert. Click '#rBack#k' to return to the main interface.");
- }
-
- status = 2;
- } else {
- cm.dispose();
- }
- }
-}
-
-function getJobTierScrolls() {
- var scrolls = [];
-
- var job = cm.getPlayer().getJob();
- var jobScrolls = jobWeaponRestricted[Math.floor(cm.getPlayer().getJobStyle().getId() / 100)];
-
- const GameConstants = Java.type('constants.game.GameConstants');
- var jobBranch = GameConstants.getJobBranch(job);
- if (jobBranch >= 2) {
- Array.prototype.push.apply(scrolls, jobScrolls[Math.floor((job.getId() / 10) % 10) - 1]);
- } else {
- for (var i = 0; i < jobScrolls.length; i++) {
- Array.prototype.push.apply(scrolls, jobScrolls[i]);
- }
- }
-
- return scrolls;
-}
-
-function getScrollTypePool(rewardTier) {
- var scrolls = [];
- switch (rewardTier) {
- case 1:
- if (cm.getPlayer().isAran()) {
- Array.prototype.push.apply(scrolls, aranWeaponRestricted);
- } else {
- Array.prototype.push.apply(scrolls, getJobTierScrolls());
- }
-
- Array.prototype.push.apply(scrolls, tier1Scrolls);
- break;
- case 2:
- Array.prototype.push.apply(scrolls, tier2Scrolls);
- break;
- default:
- Array.prototype.push.apply(scrolls, tier3Scrolls);
- }
-
- return scrolls;
-}
-
-function getScrollTier(scrollStats) {
- for (var i = 0; i < typeTierScrolls.length; i++) {
- for (var j = 0; j < typeTierScrolls[i].length; j++) {
- if (scrollStats.get(typeTierScrolls[i][j]) > 0) {
- return i + 1;
- }
- }
- }
-
- return 4;
-}
-
-function getScrollSuccessTier(scrollStats) {
- var prop = scrollStats.get("success");
-
- const YamlConfig = Java.type('config.YamlConfig');
- if (prop > 90) {
- return 3;
- } else if (prop < 50) {
- return YamlConfig.config.server.SCROLL_CHANCE_ROLLS > 2 ? 2 : 1;
- } else {
- return YamlConfig.config.server.SCROLL_CHANCE_ROLLS > 2 ? 1 : 2;
- }
-}
-
-function getAvailableScrollsPool(baseScrolls, rewardTier, successTier) {
- var scrolls = [];
- const ItemInformationProvider = Java.type('server.ItemInformationProvider');
- var ii = ItemInformationProvider.getInstance();
-
- for (var i = 0; i < baseScrolls.length; i++) {
- for (var j = 0; j < 100; j++) {
- var scrollid = baseScrolls[i] + j;
- var scrollStats = ii.getEquipStats(scrollid);
- if (scrollStats != null && ii.getScrollReqs(scrollid).isEmpty()) {
- var scrollTier = getScrollTier(scrollStats);
- if (scrollTier == rewardTier && successTier == getScrollSuccessTier(scrollStats)) {
- scrolls.push(scrollid);
- }
- }
- }
- }
-
- return scrolls;
-}
-
-// passive tier buckets...
-
-function getLevelTier(level) {
- return Math.floor((level - 1) / 15) + 1;
-}
-
-function getPlayerCardTierPower() {
- var cardset = cm.getPlayer().getMonsterBook().getCardSet();
- var countTier = [0, 0, 0, 0, 0, 0, 0, 0, 0];
-
- for (var iterator = cardset.iterator(); iterator.hasNext();) {
- var ce = iterator.next();
-
- var cardid = ce.getKey();
- var ceTier = Math.floor(cardid / 1000) % 10;
- countTier[ceTier] += ce.getValue();
-
- if (ceTier >= 8) { // is special card
- const LifeFactory = Java.type('server.life.LifeFactory');
- const ItemInformationProvider = Java.type('server.ItemInformationProvider');
- var mobLevel = LifeFactory.getMonsterLevel(ItemInformationProvider.getInstance().getCardMobId(cardid));
- var mobTier = getLevelTier(mobLevel) - 1;
-
- countTier[mobTier] += (ce.getValue() * 1.2);
- }
- }
-
- return countTier;
-}
-
-function calculateMobBookTierBuckets(tierSize, playerCards, tier) {
- if (tier < 1) {
- return 0.0;
- }
-
- tier--; // started at 1
- var tierHitRate = playerCards[tier] / (tierSize[tier] * 5);
- if (tierHitRate > 0.5) {
- tierHitRate = 0.5;
- }
-
- return tierHitRate * 4;
-}
-
-function calculateMobBookBuckets() {
- var book = cm.getPlayer().getMonsterBook();
- var bookLevelMult = 0.9 + (0.1 * book.getBookLevel());
-
- var playerLevelTier = getLevelTier(cm.getPlayer().getLevel());
- if (playerLevelTier > 8) {
- playerLevelTier = 8;
- }
-
- const MonsterBook = Java.type('client.MonsterBook');
- var tierSize = MonsterBook.getCardTierSize();
- var playerCards = getPlayerCardTierPower();
-
- var prevBuckets = calculateMobBookTierBuckets(tierSize, playerCards, playerLevelTier - 1);
- var currBuckets = calculateMobBookTierBuckets(tierSize, playerCards, playerLevelTier);
-
- return (prevBuckets + currBuckets) * bookLevelMult;
-}
-
-function recalcBuckets() {
- sgBookBuckets = calculateMobBookBuckets();
- sgItemBuckets = calculateSuppliesBuckets();
-
- var buckets = sgBookBuckets + sgItemBuckets;
- if (buckets > 6.0) {
- sgBuckets = 6;
- } else {
- sgBuckets = Math.floor(buckets);
- }
-}
-
-// variable buckets...
-
-function sgApplyItem(idx, amount) {
- if (sgAppliedItems[idx] != amount) {
- sgAppliedItems[idx] = amount;
- recalcBuckets();
- }
-}
-
-function sgApplyMeso(amount) {
- if (sgAppliedMeso != amount) {
- sgAppliedMeso = amount;
- recalcBuckets();
- }
-}
-
-function calculateSuppliesBuckets() {
- var suppliesHitRate = 0.0;
- for (var i = 0; i < sgItems.length; i++) {
- suppliesHitRate += sgAppliedItems[i] / sgToBucket[i];
- }
- suppliesHitRate *= 2;
-
- suppliesHitRate += (sgAppliedMeso / mesoToBucket);
- return suppliesHitRate;
-}
-
-function calculateScrollTiers() {
- var buckets = sgBuckets;
- var tiers = [0, 0, 0];
- while (buckets > 0) {
- var pool = [];
- for (var i = 0; i < tiers.length; i++) {
- if (tiers[i] < 2) {
- pool.push(i);
- }
- }
-
- var rnd = pool[Math.floor(Math.random() * pool.length)];
-
- tiers[rnd]++;
- buckets--;
- }
-
- // normalize tiers
- for (var i = 0; i < tiers.length; i++) {
- tiers[i] = 3 - tiers[i];
- }
-
- return tiers;
-}
-
-function getRandomScrollFromTiers(tiers) {
- var typeTier = tiers[0], subtypeTier = tiers[1], successTier = tiers[2];
- var scrollTypePool = getScrollTypePool(typeTier);
- var scrollPool = getAvailableScrollsPool(scrollTypePool, subtypeTier, successTier);
-
- if (scrollPool.length > 0) {
- return scrollPool[Math.floor(Math.random() * scrollPool.length)];
- } else {
- return -1;
- }
-}
-
-function getRandomScrollFromRightPermutations(tiers) {
- for (var i = 2; i >= 0; i--) {
- for (var j = i - 1; j >= 0; j--) {
- if (tiers[i] >= 3) {
- break;
- } else if (tiers[j] > 1) {
- tiers[i]++;
- tiers[j]--;
-
- var itemid = getRandomScrollFromTiers(tiers);
- if (itemid != -1) {
- return itemid;
- }
- }
- }
- }
-
- return -1;
-}
-
-function getRandomScroll(tiers) {
- var itemid = getRandomScrollFromTiers(tiers);
- if (itemid == -1) {
- // worst case shift-right permutations...
- itemid = getRandomScrollFromRightPermutations(tiers);
- }
-
- return itemid;
-}
-
-function performExchange(sgItemid, sgCount) {
- if (cm.getMeso() < sgAppliedMeso) {
- return false;
- }
-
- for (var i = 0; i < sgItems.length; i++) {
- var itemid = sgItems[i];
- var count = sgAppliedItems[i];
- if (count > 0 && !cm.haveItem(itemid, count)) {
- return false;
- }
- }
-
- cm.gainMeso(-sgAppliedMeso);
-
- for (var i = 0; i < sgItems.length; i++) {
- var itemid = sgItems[i];
- var count = sgAppliedItems[i];
- cm.gainItem(itemid, -count);
- }
-
- cm.gainItem(sgItemid, sgCount);
- return true;
-}
-
-function generateRandomScroll() {
- const InventoryType = Java.type('client.inventory.InventoryType');
- if (cm.getPlayer().getInventory(InventoryType.USE).getNumFreeSlot() >= 1) {
- var itemid = getRandomScroll(calculateScrollTiers());
- if (itemid != -1) {
- if (performExchange(itemid, 1)) {
- cm.sendNext("Transaction accepted! You have received a #r#t" + itemid + "##k.");
- } else {
- cm.sendOk("Oh, it looks like some items are missing... Please double-check provided items in your inventory before trying to exchange.");
- }
- } else {
- cm.sendOk("Sorry for the inconvenience, but it seems there are no scrolls on store right now... Try again later.");
- }
- } else {
- cm.sendOk("Please look out for a slot available on your USE inventory before trying for a scroll.");
- }
-}
diff --git a/src/main/java/client/MonsterBook.java b/src/main/java/client/MonsterBook.java
index cb3e882e76..3123c9eea5 100644
--- a/src/main/java/client/MonsterBook.java
+++ b/src/main/java/client/MonsterBook.java
@@ -28,8 +28,9 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
-import java.util.*;
-import java.util.Map.Entry;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -40,15 +41,6 @@ public final class MonsterBook {
private final Map cards = new LinkedHashMap<>();
private final Lock lock = new ReentrantLock();
- public Set> getCardSet() {
- lock.lock();
- try {
- return new HashSet<>(cards.entrySet());
- } finally {
- lock.unlock();
- }
- }
-
public void addCard(final Client c, final int cardid) {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), PacketCreator.showForeignCardEffect(c.getPlayer().getId()), false);
@@ -199,23 +191,4 @@ public final class MonsterBook {
ps.executeBatch();
}
}
-
- public static int[] getCardTierSize() {
- try (Connection con = DatabaseConnection.getConnection();
- PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM monstercarddata GROUP BY floor(cardid / 1000);", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
- ResultSet rs = ps.executeQuery()) {
- rs.last();
- int[] tierSizes = new int[rs.getRow()];
- rs.beforeFirst();
-
- while (rs.next()) {
- tierSizes[rs.getRow() - 1] = rs.getInt(1);
- }
-
- return tierSizes;
- } catch (SQLException e) {
- e.printStackTrace();
- return new int[0];
- }
- }
}