WK charges fix + Job level cap + MapleQuestItemFetcher

Fixed WK charges not overriding one another and some concurrency issues within MapleMap and EventInstanceManager.
New feature: job level cap, limits EXP gain until job advancement is done.
New tool: MapleQuestItemFetcher, searches through the server files for missing quest items and reports the results.
This commit is contained in:
ronancpl
2017-11-07 10:44:00 -02:00
parent 1fead59c57
commit 624aca375e
164 changed files with 26482 additions and 35341 deletions

View File

@@ -1,4 +1,4 @@
#Fri, 03 Nov 2017 14:56:01 -0200 #Mon, 06 Nov 2017 23:43:28 -0200
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2= C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=

BIN
dist/MapleSolaxia.jar vendored

Binary file not shown.

View File

@@ -641,4 +641,13 @@ Corrigido buff Wind Walk n
03 Novembro 2017, 03 Novembro 2017,
Modificado custom questline: recompensa deixa de ser PAC com chaos scrolls p/ map chair skill com itens de Maple. Modificado custom questline: recompensa deixa de ser PAC com chaos scrolls p/ map chair skill com itens de Maple.
Adicionado quest de Horus' Eye. Adicionado quest de Horus' Eye.
Consertado Wind Walk agora atuando corretamente, não uma outra versão de Dark Sight.
04 Novembro 2017,
Corrigido WK Charge skills não sobrescrevendo uma à outra ao ativar as skills.
Implementado nova ferramenta: MapleQuestItemFetcher. Ela vasculha a DB e os XMLs em busca de informações perdidas quanto aos itens de quest.
05 Novembro 2017,
Adicionado sistema de level cap para jobs correntes.
Revisto acesso concorrente sobre o componente EM da classe EIM.

View File

@@ -35,7 +35,6 @@ ToDo / Missing features list:
--------------------------- ---------------------------
** Skills ** ** Skills **
- Some pirate skills incomplete or not implemented yet.
--------------------------- ---------------------------

View File

@@ -2,6 +2,8 @@
<project-private xmlns="http://www.netbeans.org/ns/project-private/1"> <project-private xmlns="http://www.netbeans.org/ns/project-private/1">
<editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/> <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/2" lastBookmarkId="2"/>
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2"> <open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group/> <group>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/maps/MapleMap.java</file>
</group>
</open-files> </open-files>
</project-private> </project-private>

View File

@@ -27,7 +27,6 @@ importPackage(Packages.tools);
var entryMap = 922000010; var entryMap = 922000010;
var exitMap = 221024400; var exitMap = 221024400;
var eventTime = 10; //10 minutes var eventTime = 10; //10 minutes
var eim;
function init() { function init() {
em.setProperty("noEntry","false"); em.setProperty("noEntry","false");

View File

@@ -1,7 +1,6 @@
var minPlayers = 1; var minPlayers = 1;
var timeLimit = 10; //10 minutes var timeLimit = 1; //10 minutes
var eventTimer = 1000 * 60 * timeLimit; var eventTimer = 1000 * 60 * timeLimit;
var entryMap = 910510001;
var exitMap = 105070300; var exitMap = 105070300;
var eventMap = 910510000; var eventMap = 910510000;
@@ -18,12 +17,7 @@ function setup(difficulty, lobbyId){
function afterSetup(eim){} function afterSetup(eim){}
function respawn(eim){ function respawn(eim){}
var map = eim.getMapInstance(entryMap);
map.allowSummonState(true);
map.instanceMapRespawn();
eim.schedule("respawn", 10000);
}
function playerEntry(eim, player){ function playerEntry(eim, player){
var cave = eim.getMapInstance(eventMap); var cave = eim.getMapInstance(eventMap);
@@ -43,7 +37,7 @@ function playerRevive(eim, player){
player.setHp(50); player.setHp(50);
player.setStance(0); player.setStance(0);
eim.unregisterPlayer(player); eim.unregisterPlayer(player);
player.changeMap(entryMap); player.changeMap(exitMap);
return false; return false;
} }
@@ -65,19 +59,7 @@ function monsterValue(eim, mobId){
return -1; return -1;
} }
function leftParty(eim, player){ function leftParty(eim, player){}
var party = eim.getPlayers();
if(party.size() < minPlayers){
for(var i = 0; i < party.size(); i++){
playerExit(eim, party.get(i));
}
eim.dispose();
}
else{
playerExit(eim, player);
}
}
function disbandParty(eim){} function disbandParty(eim){}
@@ -85,11 +67,11 @@ function playerUnregistered(eim, player){}
function playerExit(eim, player){ function playerExit(eim, player){
eim.unregisterPlayer(player); eim.unregisterPlayer(player);
player.changeMap(entryMap, 2); player.changeMap(exitMap);
} }
function moveMap(eim, player){ function changedMap(eim, player){
if(player.getMap().getId() == exitMap || player.getMap().getId() == entryMap){ if(player.getMap().getId() < eventMap || player.getMap().getId() > next){
removePlayer(eim, player); removePlayer(eim, player);
eim.stopEventTimer(); eim.stopEventTimer();
eim.setEventCleared(); eim.setEventCleared();
@@ -100,7 +82,7 @@ function moveMap(eim, player){
function removePlayer(eim, player){ function removePlayer(eim, player){
eim.unregisterPlayer(player); eim.unregisterPlayer(player);
player.getMap().removePlayer(player); player.getMap().removePlayer(player);
player.setMap(entryMap); player.setMap(exitMap);
} }
function cancelSchedule(){} function cancelSchedule(){}

View File

@@ -0,0 +1,11 @@
importPackage(Packages.server.life);
function start(ms){
var mobId = 9300344;
var player = ms.getPlayer();
var map = player.getMap();
if(map.countMonster(mobId) == 0) {
map.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(mobId), new java.awt.Point(680, 258));
}
}

33
scripts/npc/1063016.js Normal file
View File

@@ -0,0 +1,33 @@
/* Strange Looking Statue
Puppeteer's Secret Passage (910510100)
Puppeteer JQ.
*/
var status;
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.sendYesNo("Will you exit this trial?");
} else {
cm.warp(105040201, 2);
cm.dispose();
}
}
}

38
scripts/npc/1063017.js Normal file
View File

@@ -0,0 +1,38 @@
/* Monstrous Looking Statue
Puppeteer's Secret Passage (910510100)
Puppeteer JQ.
*/
var status;
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.sendYesNo("Ahead awaits the Master himself. Are you ready to face him?");
} else {
if(cm.getClient().getChannelServer().getMapFactory().getMap(925020010).getCharacters().size() > 0) {
cm.sendOk("Someone is already challenging the Master. Try again later.");
} else {
cm.warp(910510202, 0);
}
cm.dispose();
}
}
}

View File

@@ -15,8 +15,6 @@ function action(mode, type, selection){
else else
status++; status++;
if(status == 0){ if(status == 0){
cm.sendNext("What the... you don't belong here!"); cm.sendNext("What the... you don't belong here!");
} }

View File

@@ -5,7 +5,16 @@
var status = -1; var status = -1;
function start() {
action(1, 0, 0);
}
function action(mode, type, selection) { function action(mode, type, selection) {
if(mode == -1 || mode == 0 && type > 0) {
cm.dispose();
return;
}
if (mode == 1) { if (mode == 1) {
status++; status++;
} else { } else {
@@ -16,8 +25,8 @@ function action(mode, type, selection) {
} else if (status == 1) { } else if (status == 1) {
cm.sendNextPrev("#b(The Black Wings? Huh? Who are they? And how is all this related to the Black Mage? Hm, maybe you should report this info to Tru.)#k", 3); cm.sendNextPrev("#b(The Black Wings? Huh? Who are they? And how is all this related to the Black Mage? Hm, maybe you should report this info to Tru.)#k", 3);
} else if (status == 2) { } else if (status == 2) {
cm.startQuest(21760); cm.startQuest(21760);
cm.warp(105040200, 3);//104000004 cm.warp(105040200, 3);//104000004
cm.dispose(); cm.dispose();
} }
} }

View File

@@ -79,9 +79,9 @@ function action(mode, type, selection) {
cm.sendNext("Haha! Who are you trying to impress with a heart like that?\r\nGo back home where you belong!"); cm.sendNext("Haha! Who are you trying to impress with a heart like that?\r\nGo back home where you belong!");
} else { } else {
if(cm.getClient().getChannelServer().getMapFactory().getMap(925020010).getCharacters().size() > 0) { if(cm.getClient().getChannelServer().getMapFactory().getMap(925020010).getCharacters().size() > 0) {
cm.sendOk("Someone is already in Dojo"); cm.sendOk("Someone is already in Dojo.");
cm.dispose(); cm.dispose();
return; return;
} }
cm.warp(925020010, 0); cm.warp(925020010, 0);
cm.getPlayer().setFinishedDojoTutorial(); cm.getPlayer().setFinishedDojoTutorial();

View File

@@ -22,11 +22,10 @@ function action(mode, type, selection){
} }
else if(status == 1){ else if(status == 1){
if(cm.getText() == "Francis is a genius Puppeteer!"){ if(cm.getText() == "Francis is a genius Puppeteer!"){
if(cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) == 0)
if(cm.isQuestCompleted(20730) || !cm.isQuestStarted(20730) || (cm.isQuestStarted(20730) && cm.getQuestProgress(20730, 9300285) > 0))
cm.warp(910510000, 1);
else if(cm.isQuestStarted(20730))
cm.warp(910510001, 1); cm.warp(910510001, 1);
else
cm.playerMessage(5, "Although you said the right answer, some mysterious forces is blocking the way in.");
cm.dispose(); cm.dispose();
} }

View File

@@ -0,0 +1,12 @@
function enter(pi) {
if(pi.isQuestCompleted(20730) || pi.isQuestCompleted(21731)) { // puppeteer defeated, newfound secret path
pi.warp(105070300,3);
return true;
} else if(pi.isQuestStarted(21731)) {
pi.warp(910510100,0);
return true;
} else {
pi.message("An ominous power prevents you from passing here.");
return false;
}
}

View File

@@ -1,4 +1,9 @@
function enter(pi) { function enter(pi) {
if(pi.isQuestCompleted(20730) || pi.isQuestCompleted(21731)) { // puppeteer defeated, newfound secret path
pi.warp(105040201,2);
return true;
}
pi.openNpc(1063011, "PupeteerPassword"); pi.openNpc(1063011, "PupeteerPassword");
return false; return false;
} }

View File

@@ -110,7 +110,7 @@ public enum MapleBuffStat {
// needs Soul Stone // needs Soul Stone
//end incorrect buffstats //end incorrect buffstats
//WIND_WALK(0x400000000L, true), WIND_WALK(0x400000000L, true),
ARAN_COMBO(0x1000000000L, true), ARAN_COMBO(0x1000000000L, true),
COMBO_DRAIN(0x2000000000L, true), COMBO_DRAIN(0x2000000000L, true),
COMBO_BARRIER(0x4000000000L, true), COMBO_BARRIER(0x4000000000L, true),

View File

@@ -2984,10 +2984,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
private List<Pair<MapleBuffStat, MapleBuffStatValueHolder>> cancelEffectInternal(MapleStatEffect effect, boolean overwrite, long startTime, Set<MapleBuffStat> removedStats) { private List<Pair<MapleBuffStat, MapleBuffStatValueHolder>> cancelEffectInternal(MapleStatEffect effect, boolean overwrite, long startTime, Set<MapleBuffStat> removedStats) {
Map<MapleBuffStat, MapleBuffStatValueHolder> buffstats; Map<MapleBuffStat, MapleBuffStatValueHolder> buffstats = null;
MapleBuffStat ombs;
if (!overwrite) { // is removing the source effect, meaning every effect from this srcid is being purged if (!overwrite) { // is removing the source effect, meaning every effect from this srcid is being purged
buffstats = extractCurrentBuffStats(effect); buffstats = extractCurrentBuffStats(effect);
} else { // is dropping ALL current statups that uses same stats as the given effect } else if ((ombs = getSingletonStatupFromEffect(effect)) != null) { // removing all effects of a buff having non-shareable buff stat.
MapleBuffStatValueHolder mbsvh = effects.get(ombs);
if(mbsvh != null) {
buffstats = extractCurrentBuffStats(mbsvh.effect);
}
}
if (buffstats == null) { // all else, is dropping ALL current statups that uses same stats as the given effect
buffstats = extractLeastRelevantStatEffectsIfFull(effect); buffstats = extractLeastRelevantStatEffectsIfFull(effect);
} }
@@ -3178,7 +3186,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return extractedStatBuffs; return extractedStatBuffs;
} }
private boolean isSingletonStatup(MapleBuffStat mbs) { private static MapleBuffStat getSingletonStatupFromEffect(MapleStatEffect mse) {
for(Pair<MapleBuffStat, Integer> mbs : mse.getStatups()) {
if(isSingletonStatup(mbs.getLeft())) {
return mbs.getLeft();
}
}
return null;
}
private static boolean isSingletonStatup(MapleBuffStat mbs) {
switch(mbs) { //HPREC and MPREC are supposed to be singleton switch(mbs) { //HPREC and MPREC are supposed to be singleton
case COUPON_EXP1: case COUPON_EXP1:
case COUPON_EXP2: case COUPON_EXP2:
@@ -3890,9 +3908,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
return maxhp; return maxhp;
} }
public int getMaxLevel() { public int getMaxClassLevel() {
return isCygnus() ? 120 : 200; return isCygnus() ? 120 : 200;
} }
public int getMaxLevel() {
if(!ServerConstants.USE_ENFORCE_JOB_LEVEL_RANGE || isGmJob()) {
return getMaxClassLevel();
}
return GameConstants.getJobMaxLevel(job);
}
public int getMaxMp() { public int getMaxMp() {
return maxmp; return maxmp;
@@ -4691,12 +4717,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
public void increaseGuildCapacity() { //hopefully nothing is null public void increaseGuildCapacity() { //hopefully nothing is null
if (getMeso() < getGuild().getIncreaseGuildCost(getGuild().getCapacity())) { if (getMeso() < MapleGuild.getIncreaseGuildCost(getGuild().getCapacity())) {
dropMessage(1, "You don't have enough mesos."); dropMessage(1, "You don't have enough mesos.");
return; return;
} }
Server.getInstance().increaseGuildCapacity(guildid); Server.getInstance().increaseGuildCapacity(guildid);
gainMeso(-getGuild().getIncreaseGuildCost(getGuild().getCapacity()), true, false, false); gainMeso(-MapleGuild.getIncreaseGuildCost(getGuild().getCapacity()), true, false, false);
} }
public boolean isActiveBuffedValue(int skillid) { public boolean isActiveBuffedValue(int skillid) {
@@ -4741,13 +4767,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
public boolean isCygnus() { public boolean isCygnus() {
return getJobType() == 1; return getJobType() == 1;
} }
public boolean isGmJob() {
int jn = job.getJobNiche();
return jn >= 8 && jn <= 9;
}
public boolean isAran() { public boolean isAran() {
return getJob().getId() >= 2000 && getJob().getId() <= 2112; return job.getId() >= 2000 && job.getId() <= 2112;
} }
public boolean isBeginnerJob() { public boolean isBeginnerJob() {
return (getJob().getId() == 0 || getJob().getId() == 1000 || getJob().getId() == 2000); return (job.getId() == 0 || job.getId() == 1000 || job.getId() == 2000);
} }
public boolean isGM() { public boolean isGM() {
@@ -4852,9 +4883,9 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject {
} }
} }
level++; level++;
if (level >= getMaxLevel()) { if (level >= getMaxClassLevel()) {
exp.set(0); exp.set(0);
level = getMaxLevel(); //To prevent levels past 200 level = getMaxClassLevel(); //To prevent levels past the maximum
} }
maxhp = Math.min(30000, maxhp); maxhp = Math.min(30000, maxhp);

View File

@@ -57,7 +57,7 @@ public enum MapleJob {
THUNDERBREAKER1(1500), THUNDERBREAKER2(1510), THUNDERBREAKER3(1511), THUNDERBREAKER4(1512), THUNDERBREAKER1(1500), THUNDERBREAKER2(1510), THUNDERBREAKER3(1511), THUNDERBREAKER4(1512),
LEGEND(2000), EVAN(2001), LEGEND(2000), EVAN(2001),
ARAN1(2100),ARAN2(2110), ARAN3(2111), ARAN4(2112), ARAN1(2100), ARAN2(2110), ARAN3(2111), ARAN4(2112),
EVAN1(2200), EVAN2(2210), EVAN3(2211), EVAN4(2212), EVAN5(2213), EVAN6(2214), EVAN1(2200), EVAN2(2210), EVAN3(2211), EVAN4(2212), EVAN5(2213), EVAN6(2214),
EVAN7(2215), EVAN8(2216), EVAN9(2217), EVAN10(2218); EVAN7(2215), EVAN8(2216), EVAN9(2217), EVAN10(2218);

View File

@@ -1174,7 +1174,7 @@ public class Commands {
} }
player.loseExp(player.getExp(), false, false); player.loseExp(player.getExp(), false, false);
player.setLevel(Math.min(Integer.parseInt(sub[1]), player.getMaxLevel()) - 1); player.setLevel(Math.min(Integer.parseInt(sub[1]), player.getMaxClassLevel()) - 1);
player.resetPlayerRates(); player.resetPlayerRates();
if(ServerConstants.USE_ADD_RATES_BY_LEVEL == true) player.setPlayerRates(); if(ServerConstants.USE_ADD_RATES_BY_LEVEL == true) player.setPlayerRates();
@@ -1189,7 +1189,7 @@ public class Commands {
break; break;
} }
while (player.getLevel() < Math.min(255, Integer.parseInt(sub[1]))) { while (player.getLevel() < Math.min(player.getMaxClassLevel(), Integer.parseInt(sub[1]))) {
player.levelUp(false); player.levelUp(false);
} }
break; break;

View File

@@ -63,7 +63,7 @@ public class MonsterStatusEffect {
if (cancelTask != null) { if (cancelTask != null) {
cancelTask.cancel(false); cancelTask.cancel(false);
} }
cancelTask = null; cancelTask = null;
} }
public ScheduledFuture<?> getCancelTask() { public ScheduledFuture<?> getCancelTask() {

View File

@@ -62,7 +62,29 @@ public class GameConstants {
330000, 340000, 350000, 360000, 370000, 380000, 390000, 400000, 410000, 420000, 430000, 440000, 450000, 460000, 470000, 480000, 490000, 500000, 510000, 520000, 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}; 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;
} 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
}
}
}
public static int getHiddenSkill(final int skill) { public static int getHiddenSkill(final int skill) {
switch (skill) { switch (skill) {
case Aran.HIDDEN_FULL_DOUBLE: case Aran.HIDDEN_FULL_DOUBLE:
@@ -82,7 +104,6 @@ public class GameConstants {
return 0; return 0;
} }
public static boolean isAranSkills(final int skill) { public static boolean isAranSkills(final int skill) {
return Aran.FULL_SWING == skill || Aran.OVER_SWING == skill || Aran.COMBO_TEMPEST == skill || Aran.COMBO_FENRIR == skill || Aran.COMBO_DRAIN == skill return Aran.FULL_SWING == skill || Aran.OVER_SWING == skill || Aran.COMBO_TEMPEST == skill || Aran.COMBO_FENRIR == skill || Aran.COMBO_DRAIN == skill
|| Aran.HIDDEN_FULL_DOUBLE == skill || Aran.HIDDEN_FULL_TRIPLE == skill || Aran.HIDDEN_OVER_DOUBLE == skill || Aran.HIDDEN_OVER_TRIPLE == skill || Aran.HIDDEN_FULL_DOUBLE == skill || Aran.HIDDEN_FULL_TRIPLE == skill || Aran.HIDDEN_OVER_DOUBLE == skill || Aran.HIDDEN_OVER_TRIPLE == skill

View File

@@ -17,9 +17,11 @@ public class ServerConstants {
//Login Configuration //Login Configuration
public static final int CHANNEL_LOAD = 100; //Max players per channel. public static final int CHANNEL_LOAD = 100; //Max players per channel.
public static final long RESPAWN_INTERVAL = 10 * 1000; //10 seconds, 10000.
public static final long PURGING_INTERVAL = 5 * 60 * 1000; public static final long PURGING_INTERVAL = 5 * 60 * 1000;
public static final long RANKING_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000. public static final long RANKING_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
public static final long COUPON_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000. public static final long COUPON_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000.
public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character needs this feature ENABLED. public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character needs this feature ENABLED.
public static final boolean ENABLE_PIN = false; //Pick true/false to enable or disable Pin. public static final boolean ENABLE_PIN = false; //Pick true/false to enable or disable Pin.
@@ -50,6 +52,8 @@ public class ServerConstants {
public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour). public static final boolean USE_AUTOSAVE = true; //Enables server autosaving feature (saves characters to DB each 1 hour).
public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments. public static final boolean USE_SERVER_AUTOASSIGNER = true; //Server-builtin autoassigner, uses algorithm based on distributing AP accordingly with required secondary stat on equipments.
public static final boolean USE_REFRESH_RANK_MOVE = true; public static final boolean USE_REFRESH_RANK_MOVE = true;
public static final boolean USE_ENFORCE_MOB_LEVEL_RANGE = true; //Players N levels below the killed mob will gain no experience from defeating it.
public static final boolean USE_ENFORCE_JOB_LEVEL_RANGE = false;//Caps the player level on the minimum required to advance their current jobs.
public static final boolean USE_ENFORCE_OWL_SUGGESTIONS = false;//Forces the Owl of Minerva to always display the defined item array on GameConstants.OWL_DATA instead of those featured by the players. public static final boolean USE_ENFORCE_OWL_SUGGESTIONS = false;//Forces the Owl of Minerva to always display the defined item array on GameConstants.OWL_DATA instead of those featured by the players.
public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues) public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues)
public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster) public static final boolean USE_ENFORCE_MDOOR_POSITION = true; //Forces mystic door to be spawned near spawnpoints. (since things bugs out other way, and this helps players to locate the door faster)
@@ -57,7 +61,6 @@ public class ServerConstants {
public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped. public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped.
public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll. public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll.
public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats. public static final boolean USE_BUFF_MOST_SIGNIFICANT = true; //When applying buffs, the player will stick with the highest stat boost among the listed, rather than overwriting stats.
public static final boolean USE_UNDERLEVELED_EXP_BLOCK = true; //Players N levels below the killed mob will gain no experience from defeating it.
//Server Rates And Experience //Server Rates And Experience
public static final int EXP_RATE = 10; public static final int EXP_RATE = 10;
@@ -72,7 +75,7 @@ public class ServerConstants {
public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff. public static final int PARTY_EXPERIENCE_MOD = 1; //Change for event stuff.
//Miscellaneous Configuration //Miscellaneous Configuration
public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 5; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_UNDERLEVELED_EXP_BLOCK" is enabled. public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 5; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled.
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires. public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner. public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system. public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
@@ -81,7 +84,7 @@ public class ServerConstants {
//Dangling Items Configuration //Dangling Items Configuration
public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes. public static final int ITEM_EXPIRE_TIME = 3 * 60 * 1000; //Time before items start disappearing. Recommended to be set up to 3 minutes.
public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling item objects on the map item history. public static final int ITEM_MONITOR_TIME = 5 * 60 * 1000; //Interval between item monitoring tasks on maps, which checks for dangling (null) item objects on the map item history.
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map. public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
//Some Gameplay Enhancing Configurations //Some Gameplay Enhancing Configurations

View File

@@ -108,7 +108,7 @@ public final class Channel {
IoBuffer.setUseDirectBuffer(false); IoBuffer.setUseDirectBuffer(false);
IoBuffer.setAllocator(new SimpleBufferAllocator()); IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor(); acceptor = new NioSocketAcceptor();
TimerManager.getInstance().register(new respawnMaps(), 10000); TimerManager.getInstance().register(new respawnMaps(), ServerConstants.RESPAWN_INTERVAL);
acceptor.setHandler(new MapleServerHandler(world, channel)); acceptor.setHandler(new MapleServerHandler(world, channel));
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30); acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory())); acceptor.getFilterChain().addLast("codec", (IoFilter) new ProtocolCodecFilter(new MapleCodecFactory()));

View File

@@ -45,11 +45,6 @@ public final class CancelBuffHandler extends AbstractMaplePacketHandler implemen
int sourceid = slea.readInt(); int sourceid = slea.readInt();
switch (sourceid) { switch (sourceid) {
case NightWalker.DARK_SIGHT: // wind walk as a dark sight...
c.getPlayer().cancelEffect(SkillFactory.getSkill(NightWalker.DARK_SIGHT).getEffect(1), false, -1);
c.getPlayer().cancelEffect(SkillFactory.getSkill(WindArcher.WIND_WALK).getEffect(1), false, -1);
break;
case FPArchMage.BIG_BANG: case FPArchMage.BIG_BANG:
case ILArchMage.BIG_BANG: case ILArchMage.BIG_BANG:
case Bishop.BIG_BANG: case Bishop.BIG_BANG:

View File

@@ -178,10 +178,14 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
} }
} }
} }
if ((player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 || player.getSkillLevel(SkillFactory.getSkill(Rogue.DARK_SIGHT)) > 0) && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null) {// && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004 if ((player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || player.getSkillLevel(SkillFactory.getSkill(Rogue.DARK_SIGHT)) > 0) && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null) {// && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004
player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT); player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT);
player.cancelBuffStats(MapleBuffStat.DARKSIGHT); player.cancelBuffStats(MapleBuffStat.DARKSIGHT);
} else if(player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 && player.getBuffedValue(MapleBuffStat.WIND_WALK) != null) {
player.cancelEffectFromBuffStat(MapleBuffStat.WIND_WALK);
player.cancelBuffStats(MapleBuffStat.WIND_WALK);
} }
applyAttack(attack, player, attackCount); applyAttack(attack, player, attackCount);
} }
} }

View File

@@ -211,10 +211,15 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
} }
} }
} }
if ((player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 || player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0) && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && attack.numAttacked > 0 && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004) {
if (player.getSkillLevel(SkillFactory.getSkill(NightWalker.VANISH)) > 0 && player.getBuffedValue(MapleBuffStat.DARKSIGHT) != null && attack.numAttacked > 0 && player.getBuffSource(MapleBuffStat.DARKSIGHT) != 9101004) {
player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT); player.cancelEffectFromBuffStat(MapleBuffStat.DARKSIGHT);
player.cancelBuffStats(MapleBuffStat.DARKSIGHT); player.cancelBuffStats(MapleBuffStat.DARKSIGHT);
} else if(player.getSkillLevel(SkillFactory.getSkill(WindArcher.WIND_WALK)) > 0 && player.getBuffedValue(MapleBuffStat.WIND_WALK) != null && attack.numAttacked > 0) {
player.cancelEffectFromBuffStat(MapleBuffStat.WIND_WALK);
player.cancelBuffStats(MapleBuffStat.WIND_WALK);
} }
applyAttack(attack, player, bulletCount); applyAttack(attack, player, bulletCount);
} }
} }

View File

@@ -131,7 +131,12 @@ public class EventInstanceManager {
} }
public EventManager getEm() { public EventManager getEm() {
return em; sL.lock();
try {
return em;
} finally {
sL.unlock();
}
} }
public int getEventPlayersJobs() { public int getEventPlayersJobs() {
@@ -623,7 +628,10 @@ public class EventInstanceManager {
} }
} }
public void dispose() { public synchronized void dispose() {
if(disposed) return;
disposed = true;
try { try {
sL.lock(); sL.lock();
try { try {
@@ -652,8 +660,14 @@ public class EventInstanceManager {
killCount.clear(); killCount.clear();
disposeExpedition(); disposeExpedition();
if(!eventCleared) em.disposeInstance(name);
em = null; sL.lock();
try {
if(!eventCleared) em.disposeInstance(name);
em = null;
} finally {
sL.unlock();
}
} }
public MapleMapFactory getMapFactory() { public MapleMapFactory getMapFactory() {
@@ -664,12 +678,11 @@ public class EventInstanceManager {
TimerManager.getInstance().schedule(new Runnable() { TimerManager.getInstance().schedule(new Runnable() {
@Override @Override
public void run() { public void run() {
if(em == null) return;
try { try {
sL.lock(); sL.lock();
try { try {
em.getIv().invokeFunction(methodName, EventInstanceManager.this); if(em == null) return;
em.getIv().invokeFunction(methodName, EventInstanceManager.this);
} finally { } finally {
sL.unlock(); sL.unlock();
} }
@@ -685,10 +698,18 @@ public class EventInstanceManager {
} }
public void saveWinner(MapleCharacter chr) { public void saveWinner(MapleCharacter chr) {
String emName;
sL.lock();
try {
emName = em.getName();
} finally {
sL.unlock();
}
try { try {
Connection con = DatabaseConnection.getConnection(); Connection con = DatabaseConnection.getConnection();
try (PreparedStatement ps = con.prepareStatement("INSERT INTO eventstats (event, instance, characterid, channel) VALUES (?, ?, ?, ?)")) { try (PreparedStatement ps = con.prepareStatement("INSERT INTO eventstats (event, instance, characterid, channel) VALUES (?, ?, ?, ?)")) {
ps.setString(1, em.getName()); ps.setString(1, emName);
ps.setString(2, getName()); ps.setString(2, getName());
ps.setInt(3, chr.getId()); ps.setInt(3, chr.getId());
ps.setInt(4, chr.getClient().getChannel()); ps.setInt(4, chr.getClient().getChannel());
@@ -706,9 +727,14 @@ public class EventInstanceManager {
map.setEventInstance(this); map.setEventInstance(this);
if (!mapFactory.isMapLoaded(mapId)) { if (!mapFactory.isMapLoaded(mapId)) {
if (em.getProperty("shuffleReactors") != null && em.getProperty("shuffleReactors").equals("true")) { sL.lock();
map.shuffleReactors(); try {
} if (em.getProperty("shuffleReactors") != null && em.getProperty("shuffleReactors").equals("true")) {
map.shuffleReactors();
}
} finally {
sL.unlock();
}
} }
return map; return map;
} }
@@ -1035,8 +1061,14 @@ public class EventInstanceManager {
private void disposeExpedition() { private void disposeExpedition() {
if (expedition != null) { if (expedition != null) {
expedition.dispose(eventCleared); expedition.dispose(eventCleared);
em.getChannelServer().getExpeditions().remove(expedition);
sL.lock();
try {
em.getChannelServer().getExpeditions().remove(expedition);
} finally {
sL.unlock();
}
expedition = null; expedition = null;
} }
@@ -1044,7 +1076,14 @@ public class EventInstanceManager {
public final void setEventCleared() { public final void setEventCleared() {
eventCleared = true; eventCleared = true;
em.disposeInstance(name);
sL.lock();
try {
em.disposeInstance(name);
} finally {
sL.unlock();
}
disposeExpedition(); disposeExpedition();
} }

View File

@@ -1129,7 +1129,6 @@ public class MapleItemInformationProvider {
return isQuestItemCache.get(itemId); return isQuestItemCache.get(itemId);
} }
MapleData data = getItemData(itemId); MapleData data = getItemData(itemId);
System.out.println(data);
boolean questItem = MapleDataTool.getIntConvert("info/quest", data, 0) == 1; boolean questItem = MapleDataTool.getIntConvert("info/quest", data, 0) == 1;
isQuestItemCache.put(itemId, questItem); isQuestItemCache.put(itemId, questItem);
return questItem; return questItem;

View File

@@ -455,9 +455,10 @@ public class MapleStatEffect {
case Marksman.SHARP_EYES: case Marksman.SHARP_EYES:
statups.add(new Pair<>(MapleBuffStat.SHARP_EYES, Integer.valueOf(ret.x << 8 | ret.y))); statups.add(new Pair<>(MapleBuffStat.SHARP_EYES, Integer.valueOf(ret.x << 8 | ret.y)));
break; break;
// THIEF
case Rogue.DARK_SIGHT:
case WindArcher.WIND_WALK: case WindArcher.WIND_WALK:
statups.add(new Pair<>(MapleBuffStat.WIND_WALK, Integer.valueOf(x)));
break;
case Rogue.DARK_SIGHT:
case NightWalker.DARK_SIGHT: case NightWalker.DARK_SIGHT:
statups.add(new Pair<>(MapleBuffStat.DARKSIGHT, Integer.valueOf(x))); statups.add(new Pair<>(MapleBuffStat.DARKSIGHT, Integer.valueOf(x)));
break; break;
@@ -1099,6 +1100,9 @@ public class MapleStatEffect {
} else if (isDs()) { } else if (isDs()) {
List<Pair<MapleBuffStat, Integer>> dsstat = Collections.singletonList(new Pair<>(MapleBuffStat.DARKSIGHT, 0)); List<Pair<MapleBuffStat, Integer>> dsstat = Collections.singletonList(new Pair<>(MapleBuffStat.DARKSIGHT, 0));
mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat);
} else if (isWw()) {
List<Pair<MapleBuffStat, Integer>> dsstat = Collections.singletonList(new Pair<>(MapleBuffStat.WIND_WALK, 0));
mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), dsstat);
} else if (isCombo()) { } else if (isCombo()) {
mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), statups); mbuff = MaplePacketCreator.giveForeignBuff(applyto.getId(), statups);
} else if (isMonsterRiding()) { } else if (isMonsterRiding()) {
@@ -1353,7 +1357,11 @@ public class MapleStatEffect {
} }
private boolean isDs() { private boolean isDs() {
return skill && (sourceid == Rogue.DARK_SIGHT || sourceid == WindArcher.WIND_WALK || sourceid == NightWalker.DARK_SIGHT); return skill && (sourceid == Rogue.DARK_SIGHT || sourceid == NightWalker.DARK_SIGHT);
}
private boolean isWw() {
return skill && (sourceid == WindArcher.WIND_WALK);
} }
private boolean isCombo() { private boolean isCombo() {

View File

@@ -287,7 +287,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
} }
int partyLevel = 0; int partyLevel = 0;
int leechMinLevel = (ServerConstants.USE_UNDERLEVELED_EXP_BLOCK) ? getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN : 0; //NO EXP WILL BE GIVEN for those who are underleveled! int leechMinLevel = (ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE) ? getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN : 0; //NO EXP WILL BE GIVEN for those who are underleveled!
int leechCount = 0; int leechCount = 0;
for (MapleCharacter mc : members) { for (MapleCharacter mc : members) {
@@ -347,7 +347,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0); long pXP = (long)xp + (partyExp.containsKey(pID) ? partyExp.get(pID) : 0);
partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE)); partyExp.put(pID, (int)Math.min(pXP, Integer.MAX_VALUE));
} else { } else {
if(!ServerConstants.USE_UNDERLEVELED_EXP_BLOCK || mc.getLevel() >= getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN) { if(!ServerConstants.USE_ENFORCE_MOB_LEVEL_RANGE || mc.getLevel() >= getLevel() - ServerConstants.MIN_UNDERLEVEL_TO_EXP_GAIN) {
//NO EXP WILL BE GIVEN for those who are underleveled! //NO EXP WILL BE GIVEN for those who are underleveled!
giveExpToCharacter(mc, xp, isKiller, 1); giveExpToCharacter(mc, xp, isKiller, 1);
} else { } else {
@@ -1021,8 +1021,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
} }
final MapleMonster mons = this; final MapleMonster mons = this;
TimerManager tMan = TimerManager.getInstance(); TimerManager.getInstance().schedule(
tMan.schedule(
new Runnable() { new Runnable() {
@Override @Override

View File

@@ -602,6 +602,8 @@ public class MapleMap {
private void startItemMonitor() { private void startItemMonitor() {
chrWLock.lock(); chrWLock.lock();
try { try {
if(itemMonitor != null) return;
itemMonitor = TimerManager.getInstance().register(new Runnable() { itemMonitor = TimerManager.getInstance().register(new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -1093,14 +1095,13 @@ public class MapleMap {
public void destroyReactor(int oid) { public void destroyReactor(int oid) {
final MapleReactor reactor = getReactorByOid(oid); final MapleReactor reactor = getReactorByOid(oid);
TimerManager tMan = TimerManager.getInstance();
broadcastMessage(MaplePacketCreator.destroyReactor(reactor)); broadcastMessage(MaplePacketCreator.destroyReactor(reactor));
reactor.cancelReactorTimeout(); reactor.cancelReactorTimeout();
reactor.setAlive(false); reactor.setAlive(false);
removeMapObject(reactor); removeMapObject(reactor);
if (reactor.getDelay() > 0) { if (reactor.getDelay() > 0) {
tMan.schedule(new Runnable() { TimerManager.getInstance().schedule(new Runnable() {
@Override @Override
public void run() { public void run() {
respawnReactor(reactor); respawnReactor(reactor);
@@ -1879,9 +1880,12 @@ public class MapleMap {
} }
public void addPlayer(final MapleCharacter chr) { public void addPlayer(final MapleCharacter chr) {
int chrSize;
chrWLock.lock(); chrWLock.lock();
try { try {
characters.add(chr); characters.add(chr);
chrSize = characters.size();
addPartyMemberInternal(chr); addPartyMemberInternal(chr);
} finally { } finally {
chrWLock.unlock(); chrWLock.unlock();
@@ -1889,7 +1893,7 @@ public class MapleMap {
chr.setMapId(mapid); chr.setMapId(mapid);
itemMonitorTimeout = 1; itemMonitorTimeout = 1;
if (getCharacters().size() <= 1) { if (chrSize == 1) {
if(!hasItemMonitor()) startItemMonitor(); if(!hasItemMonitor()) startItemMonitor();
if (onFirstUserEnter.length() != 0 && !chr.hasEntered(onFirstUserEnter, mapid) && MapScriptManager.getInstance().scriptExists(onFirstUserEnter, true)) { if (onFirstUserEnter.length() != 0 && !chr.hasEntered(onFirstUserEnter, mapid) && MapScriptManager.getInstance().scriptExists(onFirstUserEnter, true)) {

View File

@@ -40,9 +40,10 @@ import tools.Pair;
/** /**
* *
* @author RonanLana * @author RonanLana
*
* This application traces arrow drop data on the underlying DB (that must be * This application traces arrow drop data on the underlying DB (that must be
* defined on the DatabaseConnection file of this project) and generates a SQL * defined on the DatabaseConnection file of this project) and generates a SQL file
* file that proposes updated arrow quantitty on drop entries for the drop_data table. * that proposes updated arrow quantitty on drop entries for the drop_data table.
* *
* The arrow quantity range is calculated accordingly with the target mob stats, such * The arrow quantity range is calculated accordingly with the target mob stats, such
* as level and if it's a boss or not. * as level and if it's a boss or not.

View File

@@ -3,4 +3,4 @@ do.depend=false
do.jar=true do.jar=true
javac.debug=true javac.debug=true
javadoc.preview=true javadoc.preview=true
user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties

Some files were not shown because too many files have changed in this diff Show More