From da00345aec775bb2a58ef8b9757b89d21e938044 Mon Sep 17 00:00:00 2001 From: ronancpl Date: Fri, 5 May 2017 00:55:36 -0300 Subject: [PATCH] KerningPQ + some boosts on PQ/event scripting Added cleaner mechanics for dealing with PQs and events (bonus Exp when clearing a stage, for instance). Reimplemented KerningPQ. --- mychanges_ptbr.txt | 17 +- nbproject/private/private.xml | 30 +- scripts/event/0_EXAMPLE.js | 2 +- scripts/event/BossRushPQ.js | 64 +- scripts/event/Ellin.js | 129 ++-- scripts/event/KerningPQ.js | 263 ++++---- scripts/event/PiratePQ.js | 143 ++--- scripts/npc/world0/1012112.js | 6 +- scripts/npc/world0/1012114.js | 4 +- scripts/npc/world0/1061012.js | 4 +- scripts/npc/world0/2013002.js | 2 +- scripts/npc/world0/2030008.js | 6 +- scripts/npc/world0/2030013_old.js | 6 +- scripts/npc/world0/2032002.js | 2 +- scripts/npc/world0/2040034.js | 6 +- scripts/npc/world0/2083000.js | 6 +- scripts/npc/world0/2094000.js | 6 +- scripts/npc/world0/2094002.js | 39 +- scripts/npc/world0/2133000.js | 6 +- scripts/npc/world0/2141001.js | 2 +- scripts/npc/world0/22000.js | 2 +- scripts/npc/world0/9000037.js | 24 +- scripts/npc/world0/9020000.js | 158 ++--- scripts/npc/world0/9020001.js | 568 ++++++++---------- scripts/npc/world0/9020002.js | 12 +- scripts/npc/world0/9040010.js | 2 +- scripts/npc/world0/9103001.js | 7 +- scripts/npc/world0/9201048.js | 9 +- scripts/portal/kpq4.js | 2 +- scripts/portal/party6_out.js | 3 +- sql/db_drops.sql | 2 + src/client/MapleCharacter.java | 67 ++- src/constants/ServerConstants.java | 1 + .../channel/handlers/KeymapChangeHandler.java | 14 +- .../handlers/PartyOperationHandler.java | 8 +- .../handlers/PlayerLoggedinHandler.java | 4 +- .../channel/handlers/QuestActionHandler.java | 12 +- src/scripting/AbstractPlayerInteraction.java | 16 +- src/scripting/event/EventInstanceManager.java | 504 +++++++++++----- src/scripting/event/EventManager.java | 38 +- src/scripting/npc/NPCConversationManager.java | 2 +- src/server/quest/MapleQuest.java | 84 ++- .../requirements/IntervalRequirement.java | 3 + .../requirements/MapleQuestRequirement.java | 4 +- src/tools/MaplePacketCreator.java | 1 + 45 files changed, 1260 insertions(+), 1030 deletions(-) diff --git a/mychanges_ptbr.txt b/mychanges_ptbr.txt index 1af2afc65a..dc5f631842 100644 --- a/mychanges_ptbr.txt +++ b/mychanges_ptbr.txt @@ -185,4 +185,19 @@ Corre 29 Abril 2017, Novos métodos para uso especializado em eventos caracteristicos de PQ. -Aprimoração da Boss Rush PQ: novo sistema de recompensas. \ No newline at end of file +Aprimoração da Boss Rush PQ: novo sistema de recompensas. + +01 Maio 2017, +Correção de bugs menores na BRPQ. +Refatoração de código pertinente aos Cash USEs para Pet. +Animação para Pets ao consumirem pet food. + +02 Maio 2017, +Reestruturação e refatoração de código para PQs (funções específicas para uso em PQs). +Reimplementação da Kerning PQ. + +03 Maio 2017, +Para quests que podem ser repetidas, adição de mensagem mencionando o tempo restante para recomeçá-la. + +04 - 05 Maio 2017, +Finalização da reimplementação da Kerning PQ, com adição de novos mecanismos esperados em eventos/PQs. \ No newline at end of file diff --git a/nbproject/private/private.xml b/nbproject/private/private.xml index 80f9ea6b6a..9b65b85a48 100644 --- a/nbproject/private/private.xml +++ b/nbproject/private/private.xml @@ -3,30 +3,14 @@ - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/command/Commands.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MonsterBook.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/raid_stage.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/AbstractPlayerInteraction.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/1022101.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/1012103.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/tools/MaplePacketCreator.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/9000038.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/raid_rest.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleDisease.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/kpq3.js + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/kpq4.js + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/kpq1.js + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/9020001.js file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventInstanceManager.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/BossRushPQ.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/QuestActionHandler.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/npc/NPCConversationManager.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/world0/9000037.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/maps/MapleMap.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/raidout.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/PiratePQ.js - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleClient.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventManager.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/quest/MapleQuest.java - file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/server/quest/requirements/MonsterBookCountRequirement.java + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/kpq2.js + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/KerningPQ.js + file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/portal/kpq0.js diff --git a/scripts/event/0_EXAMPLE.js b/scripts/event/0_EXAMPLE.js index 7a92c046e0..5d8de9a5d4 100644 --- a/scripts/event/0_EXAMPLE.js +++ b/scripts/event/0_EXAMPLE.js @@ -66,7 +66,7 @@ function disbandParty(eim, player) { } function clearPQ(eim) { - // Happens when the function EventInstanceManager.finishPQ() is invoked by NPC/Reactor script + // Happens when the function EventInstanceManager.clearPQ() is invoked by NPC/Reactor script } function removePlayer(eim, player) { diff --git a/scripts/event/BossRushPQ.js b/scripts/event/BossRushPQ.js index 87ff3c9d59..f75a1e35f4 100644 --- a/scripts/event/BossRushPQ.js +++ b/scripts/event/BossRushPQ.js @@ -69,9 +69,10 @@ function getEligibleParty(party) { //selects, from the given party, the tea function setup(level, leaderid) { em.setProperty("state", "1"); em.setProperty("leader", "true"); + var eim = em.newInstance("BossRush" + leaderid); - - em.setProperty("level", level); + eim.setProperty("level", level); + eim.startEventTimer(45 * 60000); //45 mins setEventRewards(eim); return eim; @@ -93,8 +94,7 @@ function playerExit(eim, player) { function changedMap(eim, player, mapid) { if (mapid < 970030001 || mapid > 970042711) { - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() <= minPlayers) { + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { eim.unregisterPlayer(player); end(eim); } @@ -106,8 +106,7 @@ function changedMap(eim, player, mapid) { function playerDead(eim, player) {} function playerRevive(eim, player) { // player presses ok on the death pop up. - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() <= minPlayers) { + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { eim.unregisterPlayer(player); end(eim); } @@ -117,16 +116,14 @@ function playerRevive(eim, player) { // player presses ok on the death pop up. function playerDisconnected(eim, player) { - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() <= minPlayers) + if (eim.isEventTeamLackingNow(true, minPlayers, player)) end(eim); else playerExit(eim, player); } function leftParty(eim, player) { - var party = eim.getPlayers(); - if (party.size() <= minPlayers) + if (eim.isEventTeamLackingNow(false, minPlayers, player)) end(eim); else playerExit(eim, player); @@ -137,35 +134,33 @@ function disbandParty(eim) { } function monsterValue(eim, mobId) { - return 1; + return 1; } function end(eim) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerExit(eim, party.get(i)); - } - eim.dispose(); + var party = eim.getPlayers(); + for (var i = 0; i < party.size(); i++) { + playerExit(eim, party.get(i)); + } + eim.dispose(); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. } -function playerClear(eim, player, toMap) { - eim.unregisterPlayer(player); -} - -function complete(eim, toMap) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerClear(eim, party.get(i), toMap); - } - eim.dispose(); -} - -function clearPQ(eim, toMap) { - complete(eim, toMap); +function clearPQ(eim) { + eim.stopEventTimer(); + eim.setEventCleared(); // from now on event just finishes when ALL players gets out of the range defined inside changedMap function. + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. } function giveRandomEventReward(eim, player) { - eim.giveEventReward(player); + eim.giveEventReward(player); +} + +function reopenEvent() { + em.setProperty("state", "0"); + em.setProperty("leader", "true"); } function monsterKilled(mob, eim) {} @@ -174,9 +169,4 @@ function allMonstersDead(eim) {} function cancelSchedule() {} -function dispose(eim) { - em.cancelSchedule(); - - em.setProperty("state", "0"); - em.setProperty("leader", "true"); -} +function dispose(eim) {} diff --git a/scripts/event/Ellin.js b/scripts/event/Ellin.js index 8da6fbe6b6..5ebb88eeb7 100644 --- a/scripts/event/Ellin.js +++ b/scripts/event/Ellin.js @@ -1,6 +1,6 @@ var isPq = true; -var minPlayers = 4, maxPlayers = 6; -var minLevel = 44, maxLevel = 55; +var minPlayers = 1, maxPlayers = 6; +var minLevel = 1, maxLevel = 200; var entryMap = 930000000; var exitMap = 930000800; var recruitMap = 300030100; @@ -35,8 +35,10 @@ function getEligibleParty(party) { //selects, from the given party, the tea function setup(level, leaderid) { em.setProperty("state", "1"); em.setProperty("leader", "true"); + var eim = em.newInstance("Ellin" + leaderid); - + eim.setProperty("level", level); + eim.setInstanceMap(930000000).resetPQ(level); eim.setInstanceMap(930000100).resetPQ(level); eim.setInstanceMap(930000200).resetPQ(level); @@ -55,109 +57,89 @@ function setup(level, leaderid) { function respawnStg2(eim) { if(!eim.getMapInstance(930000200).getAllPlayer().isEmpty()) eim.getMapInstance(930000200).instanceMapRespawn(); - em.schedule("respawnStg2", eim, 4 * 1000); + eim.schedule("respawnStg2", 4 * 1000); } function changedMap(eim, player, mapid) { - if (mapid < 930000000 || mapid > 930000800) { - eim.unregisterPlayer(player); - if(eim.getPlayers().isEmpty()) end(eim); - } + if (mapid < 930000000 || mapid > 930000800) { + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); + } } function playerEntry(eim, player) { - var map = eim.getMapInstance(entryMap); - player.changeMap(map, map.getPortal(0)); + var map = eim.getMapInstance(entryMap); + player.changeMap(map, map.getPortal(0)); } function scheduledTimeout(eim) { - end(eim); + end(eim); } -function removePlayer(eim, player) { - eim.unregisterPlayer(player); - player.changeMap(exitMap, 0); +function playerExit(eim, player) { + eim.unregisterPlayer(player); + player.changeMap(exitMap, 0); } function playerDead(eim, player) {} function playerRevive(eim, player) { // player presses ok on the death pop up. - if (eim.isLeader(player) || party.size() <= minPlayers) { // Check for party leader - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - playerExit(eim, party.get(i)); - eim.dispose(); - } else - playerExit(eim, player); + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); } function playerDisconnected(eim, player) { - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() < minPlayers) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - if (party.get(i).equals(player)) - removePlayer(eim, player); - else - playerExit(eim, party.get(i)); - eim.dispose(); - } else - removePlayer(eim, player); + if (eim.isEventTeamLackingNow(true, minPlayers, player)) + end(eim); + else + playerExit(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); + if (eim.isEventTeamLackingNow(false, minPlayers, player)) + end(eim); + else + playerExit(eim, player); } function disbandParty(eim) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerExit(eim, party.get(i)); - } - eim.dispose(); -} - -function playerExit(eim, player) { - eim.unregisterPlayer(player); - player.changeMap(exitMap, 0); + end(eim); } function monsterValue(eim, mobId) { - return 1; + return 1; } function end(eim) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerExit(eim, party.get(i)); - } - eim.dispose(); + var party = eim.getPlayers(); + for (var i = 0; i < party.size(); i++) { + playerExit(eim, party.get(i)); + } + eim.dispose(); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. } -function playerClear(eim, player, toMap) { - eim.unregisterPlayer(player); - - if(toMap != null) player.changeMap(toMap); - else player.changeMap(clearMap, 0); +function clearPQ(eim) { + eim.stopEventTimer(); + eim.setEventCleared(); + eim.warpEventTeam(toMap); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. } -function complete(eim, toMap) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerClear(eim, party.get(i), toMap); - } - eim.dispose(); -} - -function clearPQ(eim, toMap) { - complete(eim, toMap); +function reopenEvent() { + em.setProperty("state", "0"); + em.setProperty("leader", "true"); } function monsterKilled(mob, eim) {} @@ -166,9 +148,4 @@ function allMonstersDead(eim) {} function cancelSchedule() {} -function dispose(eim) { - em.cancelSchedule(); - - em.setProperty("state", "0"); - em.setProperty("leader", "true"); -} +function dispose(eim) {} diff --git a/scripts/event/KerningPQ.js b/scripts/event/KerningPQ.js index 322c98ad0e..bdff3cdbe0 100644 --- a/scripts/event/KerningPQ.js +++ b/scripts/event/KerningPQ.js @@ -1,140 +1,153 @@ -/* - * This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer +var isPq = true; +var minPlayers = 1, maxPlayers = 6; +var minLevel = 1, maxLevel = 200; +var entryMap = 103000800; +var exitMap = 103000890; +var recruitMap = 103000000; +var clearMap = 103000805; - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License 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 . - */ - -/* -INSERT monsterdrops (monsterid,itemid,chance) VALUES (9300001,4001007,5); -INSERT monsterdrops (monsterid,itemid,chance) VALUES (9300000,4001008,1); -INSERT monsterdrops (monsterid,itemid,chance) VALUES (9300002,4001008,1); -INSERT monsterdrops (monsterid,itemid,chance) VALUES (9300003,4001008,1); -*/ - -importPackage(Packages.world); -var exitMap; -var minPlayers = 3; - -function init() { // Initial loading. - exitMap = em.getChannelServer().getMapFactory().getMap(103000890); - em.setProperty("KPQOpen", "true"); // allows entrance. - em.setProperty("shuffleReactors", "true"); - instanceId = 1; +function init() { + em.setProperty("state", "0"); + em.setProperty("leader", "true"); } +function setEventRewards(eim) { + var itemSet, itemQty, evLevel, expStages; - -function monsterValue(eim, mobId) { // Killed monster. - return 1; // returns an amount to add onto kill count. + evLevel = 1; //Rewards at clear PQ + itemSet = [2040505, 2040514, 2040502, 2040002, 2040602, 2040402, 2040802, 1032009, 1032004, 1032005, 1032006, 1032007, 1032010, 1032002, 1002026, 1002089, 1002090, 2000003, 2000001, 2000002, 2000006, 2022003, 2022000, 2000004, 4003000, 4010000, 4010001, 4010002, 4010003, 4010004, 4010005, 4010006, 4010007, 4020000, 4020001, 4020002, 4020003, 4020004, 4020005, 4020006, 4020007, 4020008]; + itemQty = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 80, 80, 80, 50, 5, 15, 15, 30, 15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3]; + eim.setEventRewards(evLevel, itemSet, itemQty); + + expStages = [100, 200, 400, 800, 1500]; //bonus exp given on CLEAR stage signal + eim.setEventClearStageExp(expStages); } -function setup() { // Invoked from "EventManager.startInstance()" - var eim = em.newInstance("KerningPQ"); // adds a new instance and returns EventInstanceManager. - var eventTime = 30 * (1000 * 60); // 30 mins. - var firstPortal = eim.getMapInstance(103000800).getPortal("next00"); - respawn(eim); - firstPortal.setScriptName("kpq0"); - em.schedule("timeOut", eim, eventTime); // invokes "timeOut" in how ever many seconds. - eim.startEventTimer(eventTime); // Sends a clock packet and tags a timer to the players. - return eim; // returns the new instance. +function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event + var eligible = []; + var hasLeader = false; + + if(party.size() > 0) { + var partyList = party.toArray(); + + for(var i = 0; i < party.size(); i++) { + var ch = partyList[i]; + + if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) { + if(ch.isLeader()) hasLeader = true; + eligible.push(ch); + } + } + } + + if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = []; + return eligible; } -function playerEntry(eim, player) { // this gets looped for every player in the party. - var map = eim.getMapInstance(103000800); - player.changeMap(map, map.getPortal(0)); // We're now in KPQ :D +function setup(level, leaderid) { + em.setProperty("state", "1"); + em.setProperty("leader", "true"); + + var eim = em.newInstance("Kerning" + leaderid); + eim.setProperty("level", level); + + respawnStg1(eim); + eim.startEventTimer(30 * 60000); //30 mins + setEventRewards(eim); + return eim; } -function playerDead(eim, player) { +function respawnStg1(eim) { + eim.getMapInstance(103000800).instanceMapRespawn(); + eim.schedule("respawnStg1", 10 * 1000); } -function playerRevive(eim, player) { // player presses ok on the death pop up. - if (eim.isLeader(player) || party.size() <= minPlayers) { // Check for party leader - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - playerExit(eim, party.get(i)); - eim.dispose(); - } else - playerExit(eim, player); +function playerEntry(eim, player) { + var map = eim.getMapInstance(entryMap); + player.changeMap(map, map.getPortal(0)); } - -function respawn(eim) { - var map = eim.getMapInstance(103000800); - var map2 = eim.getMapInstance(103000805); - if (map.getSummonState()) { //Map spawns are set to true by default - map.instanceMapRespawn(); - } - if(map2.getSummonState()) { - map2.instanceMapRespawn(); - } - eim.schedule("respawn", 10000); -} - - - -function playerDisconnected(eim, player) { - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() < minPlayers) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - if (party.get(i).equals(player)) - removePlayer(eim, player); - else - playerExit(eim, party.get(i)); - eim.dispose(); - } else - removePlayer(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) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerExit(eim, party.get(i)); - } - eim.dispose(); +function scheduledTimeout(eim) { + end(eim); } function playerExit(eim, player) { - eim.unregisterPlayer(player); - player.changeMap(exitMap, exitMap.getPortal(0)); + eim.unregisterPlayer(player); + player.changeMap(exitMap, 0); } -function removePlayer(eim, player) { - eim.unregisterPlayer(player); - player.getMap().removePlayer(player); - player.setMap(exitMap); +function changedMap(eim, player, mapid) { + if (mapid < 103000800 || mapid > 103000805) { + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); + } +} + +function playerDead(eim, player) {} + +function playerRevive(eim, player) { // player presses ok on the death pop up. + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); +} + +function playerDisconnected(eim, player) { + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); +} + +function leftParty(eim, player) { + if (eim.isEventTeamLackingNow(false, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); +} + +function disbandParty(eim) { + end(eim); +} + +function monsterValue(eim, mobId) { + return 1; +} + +function end(eim) { + var party = eim.getPlayers(); + for (var i = 0; i < party.size(); i++) { + playerExit(eim, party.get(i)); + } + eim.dispose(); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. +} + +function giveRandomEventReward(eim, player) { + eim.giveEventReward(player); } function clearPQ(eim) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - playerExit(eim, party.get(i)); - eim.dispose(); + eim.stopEventTimer(); + eim.setEventCleared(); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. +} + +function reopenEvent() { + em.setProperty("state", "0"); + em.setProperty("leader", "true"); } function monsterKilled(mob, eim) {} @@ -143,22 +156,4 @@ function allMonstersDead(eim) {} function cancelSchedule() {} -function dispose(eim) { - em.cancelSchedule(); - em.schedule("OpenKPQ", 10000); // 10 seconds ? -} - -function OpenKPQ() { - em.setProperty("KPQOpen", "true"); -} - -function timeOut(eim) { - if (eim != null) { - if (eim.getPlayerCount() > 0) { - var pIter = eim.getPlayers().iterator(); - while (pIter.hasNext()) - playerExit(eim, pIter.next()); - } - eim.dispose(); - } -} \ No newline at end of file +function dispose(eim) {} diff --git a/scripts/event/PiratePQ.js b/scripts/event/PiratePQ.js index 2f8c31abf6..ed6ea91350 100644 --- a/scripts/event/PiratePQ.js +++ b/scripts/event/PiratePQ.js @@ -1,6 +1,6 @@ var isPq = true; -var minPlayers = 3, maxPlayers = 6; -var minLevel = 55, maxLevel = 100; +var minPlayers = 1, maxPlayers = 6; +var minLevel = 1, maxLevel = 200; var entryMap = 925100000; var exitMap = 925100700; var recruitMap = 251010404; @@ -35,7 +35,10 @@ function getEligibleParty(party) { //selects, from the given party, the tea function setup(level, leaderid) { em.setProperty("state", "1"); em.setProperty("leader", "true"); + var eim = em.newInstance("Pirate" + leaderid); + eim.setProperty("level", level); + em.setProperty("stage2", "0"); em.setProperty("stage2a", "0"); em.setProperty("stage3a", "0"); @@ -43,7 +46,7 @@ function setup(level, leaderid) { em.setProperty("stage3b", "0"); em.setProperty("stage4", "0"); em.setProperty("stage5", "0"); - em.setProperty("level", level); + em.setProperty("openedChests", "0"); eim.setInstanceMap(925100000).resetPQ(level); eim.setInstanceMap(925100000).shuffleReactors(); @@ -125,111 +128,91 @@ function setup(level, leaderid) { return eim; } +function respawnStg4(eim) { + eim.getMapInstance(925100400).instanceMapRespawn(); + eim.schedule("respawnStg4", 10 * 1000); +} + function playerEntry(eim, player) { - var map = eim.getMapInstance(entryMap); - player.changeMap(map, map.getPortal(0)); + var map = eim.getMapInstance(entryMap); + player.changeMap(map, map.getPortal(0)); } function scheduledTimeout(eim) { - end(eim); + end(eim); } -function removePlayer(eim, player) { - eim.unregisterPlayer(player); - player.changeMap(exitMap, 0); +function playerExit(eim, player) { + eim.unregisterPlayer(player); + player.changeMap(exitMap, 0); } function changedMap(eim, player, mapid) { - if (mapid < 925100000 || mapid > 925100500) { - eim.unregisterPlayer(player); - - if (eim.disposeIfPlayerBelow(minPlayers, exitMap)) { - em.setProperty("state", "0"); - em.setProperty("leader", "true"); - } - } + if (mapid < 925100000 || mapid > 925100500) { + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); + } } function playerDead(eim, player) {} function playerRevive(eim, player) { // player presses ok on the death pop up. - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() <= minPlayers) { // Check for party leader - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - playerExit(eim, party.get(i)); - eim.dispose(); - } else - playerExit(eim, player); + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); } function playerDisconnected(eim, player) { - var party = eim.getPlayers(); - if (eim.isLeader(player) || party.size() < minPlayers) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) - if (party.get(i).equals(player)) - removePlayer(eim, player); - else - playerExit(eim, party.get(i)); - eim.dispose(); - } else - removePlayer(eim, player); + if (eim.isEventTeamLackingNow(true, minPlayers, player)) + end(eim); + else + playerExit(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); + if (eim.isEventTeamLackingNow(false, minPlayers, player)) + end(eim); + else + playerExit(eim, player); } function disbandParty(eim) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerExit(eim, party.get(i)); - } - eim.dispose(); -} - -function playerExit(eim, player) { - eim.unregisterPlayer(player); - player.changeMap(exitMap, 0); + end(eim); } function monsterValue(eim, mobId) { - return 1; + return 1; } function end(eim) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerExit(eim, party.get(i)); - } - eim.dispose(); + var party = eim.getPlayers(); + for (var i = 0; i < party.size(); i++) { + playerExit(eim, party.get(i)); + } + eim.dispose(); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. } -function playerClear(eim, player, toMap) { - eim.unregisterPlayer(player); - - if(toMap != null) player.changeMap(toMap); - else player.changeMap(clearMap, 0); +function clearPQ(eim) { + eim.stopEventTimer(); + eim.setEventCleared(); + eim.warpEventTeam(toMap); + + em.schedule("reopenEvent", 10 * 1000); // leaders have 10 seconds cooldown to reach recruit map and retry for a new PQ. } -function complete(eim, toMap) { - var party = eim.getPlayers(); - for (var i = 0; i < party.size(); i++) { - playerClear(eim, party.get(i), toMap); - } - eim.dispose(); -} - -function clearPQ(eim, toMap) { - complete(eim, toMap); +function reopenEvent() { + em.setProperty("state", "0"); + em.setProperty("leader", "true"); } function monsterKilled(mob, eim) {} @@ -238,14 +221,4 @@ function allMonstersDead(eim) {} function cancelSchedule() {} -function respawnStg4(eim) { - eim.getMapInstance(925100400).instanceMapRespawn(); - em.schedule("respawnStg4", eim, 10 * 1000); -} - -function dispose(eim) { - em.cancelSchedule(); - - em.setProperty("state", "0"); - em.setProperty("leader", "true"); -} +function dispose(eim) {} diff --git a/scripts/npc/world0/1012112.js b/scripts/npc/world0/1012112.js index 6bf2eb2a8a..688791cd55 100644 --- a/scripts/npc/world0/1012112.js +++ b/scripts/npc/world0/1012112.js @@ -94,7 +94,11 @@ function action(mode, type, selection) { if (prop == null || prop.equals("0")) { //Start the PQ cm.removeHPQItems(); em.setProperty("latestLeader", cm.getPlayer().getName()); - em.startInstance(cm.getParty(), cm.getPlayer().getMap()); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } } else { cm.sendOk("Someone is already attempting the PQ. Please wait for them to finish, or find another channel."); cm.dispose(); diff --git a/scripts/npc/world0/1012114.js b/scripts/npc/world0/1012114.js index 71b962c230..8122e85737 100644 --- a/scripts/npc/world0/1012114.js +++ b/scripts/npc/world0/1012114.js @@ -37,7 +37,7 @@ function action(mode, type, selection) { status++; if (status == 51) { var eim = cm.getEventManager("HenesysPQ").getInstance("HenesysPQ_" + cm.getParty().getLeader().getName()); - eim.finishPQ(); + eim.clearPQ(); cm.dispose(); return; } @@ -89,7 +89,7 @@ function action(mode, type, selection) { cm.sendNextPrev("When the flowers of primrose blooms, the full moon will rise, and that's when the Moon Bunnies will appear and start pounding the mill. Your task is to fight off the monsters to make sure that Moon Bunny can concentrate on making the best rice cake possible."); } else if (chosen == 1) { var eim = cm.getEventManager("HenesysPQ").getInstance("HenesysPQ_" + cm.getParty().getLeader().getName()); - eim.finishPQ(); + eim.clearPQ(); cm.dispose(); } } else if (status == 4) { diff --git a/scripts/npc/world0/1061012.js b/scripts/npc/world0/1061012.js index 7161167a13..85749950f0 100644 --- a/scripts/npc/world0/1061012.js +++ b/scripts/npc/world0/1061012.js @@ -22,7 +22,9 @@ function start() { } else if (em.getProperty("started").equals("true")) { cm.sendOk("Someone else is already attempting to defeat the Jr.Balrog in another world." ); } else { - em.startInstance(cm.getParty(), cm.getMap()); + if(!em.startInstance(cm.getParty(), cm.getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + } } } } diff --git a/scripts/npc/world0/2013002.js b/scripts/npc/world0/2013002.js index a0c59a0ccc..2386140397 100644 --- a/scripts/npc/world0/2013002.js +++ b/scripts/npc/world0/2013002.js @@ -44,7 +44,7 @@ function action(mode, type, selection) { cm.sendNext("Thank you for not only restoring the statue, but rescuing me, Minerva, from the entrapment. May the blessing of the goddess be with you till the end..."); else if (status == 1) { var eim = cm.getPlayer().getEventInstance(); - eim.finishPQ(); + eim.clearPQ(); cm.dispose(); } } else if (cm.getPlayer().getMapId() == 920011300) { diff --git a/scripts/npc/world0/2030008.js b/scripts/npc/world0/2030008.js index 5d8cff520d..f6dc6f670c 100644 --- a/scripts/npc/world0/2030008.js +++ b/scripts/npc/world0/2030008.js @@ -117,7 +117,11 @@ function action(mode, type, selection) { if (em == null) { cm.sendOk("This trial is currently under construction."); } else { - em.startInstance(cm.getParty(), cm.getPlayer().getMap()); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } party = cm.getPlayer().getEventInstance().getPlayers(); cm.removeFromParty(4001015, party); cm.removeFromParty(4001018, party); diff --git a/scripts/npc/world0/2030013_old.js b/scripts/npc/world0/2030013_old.js index e4333baa77..358c846eae 100644 --- a/scripts/npc/world0/2030013_old.js +++ b/scripts/npc/world0/2030013_old.js @@ -79,7 +79,11 @@ function action(mode, type, selection) { cm.sendOk("You may not use that password."); else { // start Zakum Battle var eim = em.newInstance("Zakum" + passwd); - em.startInstance(eim,cm.getPlayer().getName()); + if(!em.startInstance(eim,cm.getPlayer().getName())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } eim.registerPlayer(cm.getPlayer()); } } diff --git a/scripts/npc/world0/2032002.js b/scripts/npc/world0/2032002.js index f0a0c5be5c..79e79e605a 100644 --- a/scripts/npc/world0/2032002.js +++ b/scripts/npc/world0/2032002.js @@ -82,7 +82,7 @@ function action(mode, type, selection) { cm.givePartyExp(20000, party); } else cm.givePartyExp(12000, party); - eim.finishPQ(); + eim.clearPQ(); cm.dispose(); } else if (selectedType == 2) { diff --git a/scripts/npc/world0/2040034.js b/scripts/npc/world0/2040034.js index 5bc11803b9..ae76e2fb4f 100644 --- a/scripts/npc/world0/2040034.js +++ b/scripts/npc/world0/2040034.js @@ -74,7 +74,11 @@ function action(mode, type, selection) { } else { var prop = em.getProperty("LPQOpen"); if (prop == null || prop.equals("true")) { - em.startInstance(cm.getParty(), cm.getPlayer().getMap()); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } cm.removeAll(4001022); cm.removeAll(4001023); cm.dispose(); diff --git a/scripts/npc/world0/2083000.js b/scripts/npc/world0/2083000.js index c9fe3b6fb1..0747a6a2af 100644 --- a/scripts/npc/world0/2083000.js +++ b/scripts/npc/world0/2083000.js @@ -85,7 +85,11 @@ function action(mode, type, selection) { } else { // Begin the PQ. - em.startInstance(cm.getParty(),cm.getPlayer().getMap()); + if(!em.startInstance(cm.getParty(),cm.getPlayer().getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } //force the two scripts on portals in the map //eim = cm.getPlayer().getEventInstance(); var map = eim.getMapInstance(240050100); diff --git a/scripts/npc/world0/2094000.js b/scripts/npc/world0/2094000.js index 52aca93851..ae9f2881da 100644 --- a/scripts/npc/world0/2094000.js +++ b/scripts/npc/world0/2094000.js @@ -50,7 +50,11 @@ function action(mode, type, selection) { if(eli.size() > 0) { var prop = em.getProperty("state"); if (prop != null && prop.equals("0")) { - em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } cm.dispose(); } else { cm.sendOk("Another party has already entered the #rParty Quest#k in this channel. Please try another channel, or wait for the current party to finish."); diff --git a/scripts/npc/world0/2094002.js b/scripts/npc/world0/2094002.js index 20e86f82ae..093c1cfcba 100644 --- a/scripts/npc/world0/2094002.js +++ b/scripts/npc/world0/2094002.js @@ -20,28 +20,32 @@ function action(mode, type, selection) { cm.dispose(); return; } - var em = cm.getEventManager("PiratePQ"); - if (em == null) { - cm.sendNext("The event isn't started..."); - cm.dispose(); - return; - } - level = em.getProperty("level"); if (!cm.isLeader()) { cm.sendNext("I wish for your leader to talk to me."); cm.dispose(); return; } + + var eim = cm.getEventInstance(); + if (eim == null) { + cm.warp(251010404,0); + cm.sendNext("How are you even here without being registered on an event?"); + cm.dispose(); + return; + } + + level = eim.getProperty("level"); + switch(cm.getPlayer().getMapId()) { case 925100000: cm.sendNext("We are heading into the Pirate Ship now! To get in, we must destroy all the monsters guarding it."); cm.dispose(); break; case 925100100: - var emp = em.getProperty("stage2"); + var emp = eim.getProperty("stage2"); if (emp == null) { - em.setProperty("stage2", "0"); + eim.setProperty("stage2", "0"); emp = "0"; } if (emp.equals("0")) { @@ -49,7 +53,7 @@ function action(mode, type, selection) { cm.sendNext("Excellent! Now hunt me 20 Rising Medals."); cm.gainItem(4001120,-20); cm.getMap().killAllMonsters(); - em.setProperty("stage2", "1"); + eim.setProperty("stage2", "1"); } else { cm.sendNext("We are heading into the Pirate Ship now! To get in, we must qualify ourselves as noble pirates. Hunt me 20 Rookie Medals."); if(cm.countMonster() < 1) cm.getPlayer().getMap().spawnAllMonsterIdFromMapSpawnList(9300114, level, true); @@ -59,7 +63,7 @@ function action(mode, type, selection) { cm.sendNext("Excellent! Now hunt me 20 Veteran Medals."); cm.gainItem(4001121,-20); cm.getMap().killAllMonsters(); - em.setProperty("stage2", "2"); + eim.setProperty("stage2", "2"); } else { cm.sendNext("We are heading into the Pirate Ship now! To get in, we must qualify ourselves as noble pirates. Hunt me 20 Rising Medals."); if(cm.countMonster() < 1) cm.getPlayer().getMap().spawnAllMonsterIdFromMapSpawnList(9300115, level, true); @@ -69,7 +73,7 @@ function action(mode, type, selection) { cm.sendNext("Excellent! Now let us go."); cm.gainItem(4001122,-20); cm.getMap().killAllMonsters(); - em.setProperty("stage2", "3"); + eim.setProperty("stage2", "3"); } else { cm.sendNext("We are heading into the Pirate Ship now! To get in, we must qualify ourselves as noble pirates. Hunt me 20 Veteran Medals."); if(cm.countMonster() < 1) cm.getPlayer().getMap().spawnAllMonsterIdFromMapSpawnList(9300116, level, true); @@ -87,9 +91,9 @@ function action(mode, type, selection) { case 925100201: if (cm.getMap().getMonsters().size() == 0) { cm.sendNext("Excellent."); - if (em.getProperty("stage2a") == "0") { + if (eim.getProperty("stage2a") == "0") { cm.getMap().setReactorState(); - em.setProperty("stage2a", "1"); + eim.setProperty("stage2a", "1"); } } else { cm.sendNext("These bellflowers are in hiding. We must liberate them."); @@ -99,9 +103,9 @@ function action(mode, type, selection) { case 925100301: if (cm.getMap().getMonsters().size() == 0) { cm.sendNext("Excellent."); - if (em.getProperty("stage3a").equals("0")) { + if (eim.getProperty("stage3a").equals("0")) { cm.getMap().setReactorState(); - em.setProperty("stage3a", "1"); + eim.setProperty("stage3a", "1"); } } else { cm.sendNext("These bellflowers are in hiding. We must liberate them."); @@ -119,7 +123,8 @@ function action(mode, type, selection) { break; case 925100500: if (cm.getMap().getMonsters().size() == 0) { - cm.clearPQ(925100600); + cm.getEventInstance().clearPQ(); + cm.getEventInstance().warpEventTeam(925100600); } else { cm.sendNext("Defeat all monsters! Even Lord Pirate's minions!"); } diff --git a/scripts/npc/world0/2133000.js b/scripts/npc/world0/2133000.js index 6741f6bb3f..8d6fb23f76 100644 --- a/scripts/npc/world0/2133000.js +++ b/scripts/npc/world0/2133000.js @@ -50,7 +50,11 @@ function action(mode, type, selection) { if(eli.size() > 0) { var prop = em.getProperty("state"); if (prop != null && prop.equals("0")) { - em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } cm.dispose(); } else { cm.sendOk("Another party has already entered the #rParty Quest#k in this channel. Please try another channel, or wait for the current party to finish."); diff --git a/scripts/npc/world0/2141001.js b/scripts/npc/world0/2141001.js index d33ca2fb6a..d752de99f8 100644 --- a/scripts/npc/world0/2141001.js +++ b/scripts/npc/world0/2141001.js @@ -189,7 +189,7 @@ function action(mode, type, selection) { cm.sendOk("Due to an unknown error, the request for squad has been denied."); cm.dispose(); } - } else if (selection == 3) { // get insode + } else if (selection == 3) { // get inside if (cm.getSquad("PinkBean") != null) { var dd = cm.getEventManager("PinkBeanBattle"); dd.startInstance(cm.getSquad("PinkBean"), cm.getMap(), 160104); diff --git a/scripts/npc/world0/22000.js b/scripts/npc/world0/22000.js index 2c6e3b3225..a135c3b54e 100644 --- a/scripts/npc/world0/22000.js +++ b/scripts/npc/world0/22000.js @@ -64,7 +64,7 @@ function action(mode, type, selection) { } else if (status == 3) { if (cm.haveItem(4031801)) cm.gainItem(4031801, -1); - cm.warp(2010000); + cm.warp(104000000); cm.dispose(); } } \ No newline at end of file diff --git a/scripts/npc/world0/9000037.js b/scripts/npc/world0/9000037.js index 846f517409..24517e8a35 100644 --- a/scripts/npc/world0/9000037.js +++ b/scripts/npc/world0/9000037.js @@ -41,18 +41,16 @@ function action(mode, type, selection) { if (status == 0) { if(state == 3) { + if(cm.getEventInstance().getProperty("clear") == null) { + cm.getEventInstance().clearPQ(); + cm.getEventInstance().setProperty("clear", "true"); + } + if(cm.isLeader()) { - if(cm.getPlayer().getEventInstance().getPlayerCount() > 1) { - cm.sendOk("Now, tell your party I will be warping everyone out and rewarding them as they talk to me. The leader goes last."); - cm.dispose(); - return; - } - else { - cm.sendOk("Your party completed such an astounding feat coming this far, #byou have defeated all the bosses#k, congratulations! Now I will be handing your reward as you are being transported out..."); - } - } + cm.sendOk("Your party completed such an astounding feat coming this far, #byou have defeated all the bosses#k, congratulations! Now I will be handing your reward as you are being transported out..."); + } else { - cm.sendOk("For #bdefeating all bosses#k in this event, congratulations! Now you will receive a prize that matches your performance here as I warp you out."); + cm.sendOk("For #bdefeating all bosses#k in this event, congratulations! You will now receive a prize that matches your performance here as I warp you out."); } } else if(state == 2) { @@ -114,7 +112,11 @@ function action(mode, type, selection) { if(eli.size() > 0) { var prop = em.getProperty("state"); if (prop != null && prop.equals("0")) { - em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } cm.dispose(); } else { cm.sendOk("Another party has already entered the #rParty Quest#k in this channel. Please try another channel, or wait for the current party to finish."); diff --git a/scripts/npc/world0/9020000.js b/scripts/npc/world0/9020000.js index dc2044a2cd..b4c517463d 100644 --- a/scripts/npc/world0/9020000.js +++ b/scripts/npc/world0/9020000.js @@ -1,89 +1,91 @@ -/* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License 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 . +/** + * @author: Ronan + * @npc: Lakelis + * @map: 103000000 - Kerning City + * @func: Kerning PQ */ -/** --- Odin JavaScript -------------------------------------------------------------------------------- - Lakelis - Victoria Road: Kerning City (103000000) --- By --------------------------------------------------------------------------------------------- - Stereo --- Version Info ----------------------------------------------------------------------------------- - 1.0 - First Version by Stereo ---------------------------------------------------------------------------------------------------- -**/ - -var status; -var minLevel = 21; -var maxLevel = 255; -var minPlayers = 1; -var maxPlayers = 6; +var status = 0; +var minLevel = 1; +var maxLevel = 200; +var minPartySize = 1; +var maxPartySize = 6; +var state; function start() { - status = -1; - action(1, 0, 0); + status = -1; + state = (cm.getMapId() >= 103000800 && cm.getMapId() <= 103000805) ? 1 : 0; + action(1, 0, 0); } function action(mode, type, selection) { - if (mode == 1) - status++; - else { - cm.dispose(); - return; - } - if (status == 0) { - if (cm.getParty() == null) { // No Party - cm.sendOk("How about you and your party members collectively beating a quest? Here you'll find obstacles and problems where you won't be able to beat it without great teamwork. If you want to try it, please tell the #bleader of your party#k to talk to me."); - cm.dispose(); - } else if (!cm.isLeader()) { // Not Party Leader - cm.sendOk("If you want to try the quest, please tell the #bleader of your party#k to talk to me."); - cm.dispose(); + if (mode == -1) { + cm.dispose(); } else { - var party = cm.getParty().getMembers(); - var inMap = cm.partyMembersInMap(); - var levelValid = 0; - for (var i = 0; i < party.size(); i++) { - if (party.get(i).getLevel() >= minLevel && party.get(i).getLevel() <= maxLevel) - levelValid++; - } - if (inMap < minPlayers || inMap > maxPlayers) { - cm.sendOk("Your party is not a party of "+minPlayers+". Please make sure all your members are present and qualified to participate in this quest."); - cm.dispose(); - } else if (levelValid != inMap) { - cm.sendOk("Please make sure all your members are present and qualified to participate in this quest. This PQ requires players ranging from level "+minLevel+" to level "+maxLevel+". I see #b" + levelValid + "#k members are in the right level range. If this seems wrong, #blog out and log back in,#k or reform the party."); - cm.dispose(); - } else { - var em = cm.getEventManager("KerningPQ"); - if (em == null) { - cm.sendOk("This PQ is currently unavailable."); - } else if (em.getProperty("KPQOpen").equals("true")) { - // Begin the PQ. - em.startInstance(cm.getParty(), cm.getPlayer().getMap()); - party = cm.getParty(); - cm.removePartyItems(4001008); - cm.removePartyItems(4001007); - em.setProperty("KPQOpen" , "false"); - } else { - cm.sendNext("There is already another party inside. Please wait !"); + if (mode == 0 && status == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + + if (status == 0) { + if(state == 1) { + cm.sendYesNo("Do you wish to abandon this area?"); + } + else { + cm.sendSimple("#b#k\r\n\r\nHow about you and your party members collectively beating a quest? Here you'll find obstacles and problems where you won't be able to beat it without great teamwork. If you want to try it, please tell the #bleader of your party#k to talk to me.#b\r\n#L0#I want to participate in the party quest.\r\n#L1#I want to find party members.\r\n#L2#I would like to hear more details."); + } + } else if (status == 1) { + if(state == 1) { + cm.warp(103000000); + cm.dispose(); + } + else { + if (selection == 0) { + if (cm.getParty() == null) { + cm.sendOk("You can participate in the party quest only if you are in a party."); + cm.dispose(); + } else if(!cm.isLeader()) { + cm.sendOk("Your party leader must talk to me to start this party quest."); + cm.dispose(); + } else { + var em = cm.getEventManager("KerningPQ"); + if(em == null) { + cm.sendOk("The Kerning PQ has encountered an error."); + cm.dispose(); + } + + var eli = em.getEligibleParty(cm.getParty()); + if(eli.size() > 0) { + var prop = em.getProperty("state"); + if (prop != null && prop.equals("0")) { + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap(), 1)) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } + cm.dispose(); + } else { + cm.sendOk("Another party has already entered the #rParty Quest#k in this channel. Please try another channel, or wait for the current party to finish."); + cm.dispose(); + } + } + else { + cm.sendOk("You cannot start this party quest yet, because either your party is not in the range size, some of your party members are not eligible to attempt it or they are not in this map. If you're having trouble finding party members, try Party Search."); + cm.dispose(); + } + } + } else if (selection == 1) { + cm.sendOk("Try using a Super Megaphone or asking your buddies or guild to join!"); + cm.dispose(); + } else { + cm.sendOk("#b#k\r\nYour party must pass through many obstacles and puzzles while traversing the sub-objectives of this Party Quest. Coordinate with your team in order to further advance and defeat the final boss and collect the dropped item in order to access the rewards and bonus stage."); + cm.dispose(); + } + } } - cm.dispose(); - } } - } } \ No newline at end of file diff --git a/scripts/npc/world0/9020001.js b/scripts/npc/world0/9020001.js index b7892692a7..7dc4335f59 100644 --- a/scripts/npc/world0/9020001.js +++ b/scripts/npc/world0/9020001.js @@ -1,4 +1,4 @@ -/*/* +/* This file is part of the OdinMS Maple Story Server Copyright (C) 2008 Patrick Huy Matthias Butz @@ -21,31 +21,25 @@ */ /** --- Odin JavaScript -------------------------------------------------------------------------------- - Cloto - Hidden Street : 1st Accompaniment --- By --------------------------------------------------------------------------------------------- - Stereo --- Version Info ----------------------------------------------------------------------------------- - 1.1 - Second Version by Moogra - 1.0 - First Version by Stereo ---------------------------------------------------------------------------------------------------- -**/ + * @author: Stereo, Moogra, Ronan + * @npc: Cloto + * @map: 1st Accompaniment - KPQ + * @func: Kerning PQ +*/ importPackage(Packages.tools); importPackage(java.awt); -var status; -var curMap; -var questions = Array("Here's the question. Collect the same number of coupons as the minimum level required to make the first job advancement as warrior.", +var stage1Questions = Array( + "Here's the question. Collect the same number of coupons as the minimum level required to make the first job advancement as warrior.", "Here's the question. Collect the same number of coupons as the minimum amount of STR needed to make the first job advancement as a warrior.", "Here's the question. Collect the same number of coupons as the minimum amount of INT needed to make the first job advancement as a magician.", "Here's the question. Collect the same number of coupons as the minimum amount of DEX needed to make the first job advancement as a bowman.", "Here's the question. Collect the same number of coupons as the minimum amount of DEX needed to make the first job advancement as a thief.", "Here's the question. Collect the same number of coupons as the minimum level required to advance to 2nd job.", - "Here's the question. Collect the same number of coupons as the minimum level required to make the first job advancement as a magician."); -var qanswers = Array(10, 35, 20, 25, 25, 30, 8); -var party; -var preamble; // we dont even need this mother fucker ! -- + "Here's the question. Collect the same number of coupons as the minimum level required to make the first job advancement as a magician."); +var stage1Answers = Array(10, 35, 20, 25, 25, 30, 8); + var stage2Rects = Array(new Rectangle(-755,-132,4,218),new Rectangle(-721,-340,4,166),new Rectangle(-586,-326,4,150),new Rectangle(-483,-181,4,222)); var stage3Rects = Array(new Rectangle(608,-180,140,50),new Rectangle(791,-117,140,45), new Rectangle(958,-180,140,50),new Rectangle(876,-238,140,45), @@ -53,329 +47,251 @@ var stage3Rects = Array(new Rectangle(608,-180,140,50),new Rectangle(791,-117,14 var stage4Rects = Array(new Rectangle(910,-236,35,5),new Rectangle(877,-184,35,5), new Rectangle(946,-184,35,5),new Rectangle(845,-132,35,5), new Rectangle(910,-132,35,5),new Rectangle(981,-132,35,5)); -var stage2combos = Array(Array(0,1,1,1),Array(1,0,1,1),Array(1,1,0,1),Array(1,1,1,0)); -var stage3combos = Array(Array(0,0,1,1,1),Array(0,1,0,1,1),Array(0,1,1,0,1), + +var stage2Combos = Array(Array(0,1,1,1),Array(1,0,1,1),Array(1,1,0,1),Array(1,1,1,0)); +var stage3Combos = Array(Array(0,0,1,1,1),Array(0,1,0,1,1),Array(0,1,1,0,1), Array(0,1,1,1,0),Array(1,0,0,1,1),Array(1,0,1,0,1), Array(1,0,1,1,0),Array(1,1,0,0,1),Array(1,1,0,1,0), Array(1,1,1,0,0)); -var stage4combos = Array(Array(0,0,0,1,1,1),Array(0,0,1,0,1,1),Array(0,0,1,1,0,1), +var stage4Combos = Array(Array(0,0,0,1,1,1),Array(0,0,1,0,1,1),Array(0,0,1,1,0,1), Array(0,0,1,1,1,0),Array(0,1,0,0,1,1),Array(0,1,0,1,0,1), Array(0,1,0,1,1,0),Array(0,1,1,0,0,1),Array(0,1,1,0,1,0), Array(0,1,1,1,0,0),Array(1,0,0,0,1,1),Array(1,0,0,1,0,1), Array(1,0,0,1,1,0),Array(1,0,1,0,0,1),Array(1,0,1,0,1,0), Array(1,0,1,1,0,0),Array(1,1,0,0,0,1),Array(1,1,0,0,1,0), - Array(1,1,0,1,0,0),Array(1,1,1,0,0,0)); -var eye = 9300002; -var necki = 9300000; -var slime = 9300003; -var monsterIds = Array(eye, eye, eye, necki, necki, necki, necki, necki, necki, slime); -var prizeIdScroll = Array(2040502, 2040505,// Overall DEX and DEF - 2040802,// Gloves for DEX - 2040002, 2040402, 2040602);// Helmet, Topwear and Bottomwear for DEF -var prizeIdUse = Array(2000001, 2000002, 2000003, 2000006,// Orange, White and Blue Potions and Mana Elixir - 2000004, 2022000, 2022003);// Elixir, Pure Water and Unagi -var prizeQtyUse = Array(80, 80, 80, 50, 5, 15, 15); -var prizeIdEquip = Array(1032004, 1032005, 1032009,// Level 20-25 Earrings - 1032006, 1032007, 1032010,// Level 30 Earrings - 1032002,// Level 35 Earring - 1002026, 1002089, 1002090);// Bamboo Hats -var prizeIdEtc = Array(4010000, 4010001, 4010002, 4010003,// Mineral Ores - 4010004, 4010005, 4010006,// Mineral Ores - 4020000, 4020001, 4020002, 4020003,// Jewel Ores - 4020004, 4020005, 4020006,// Jewel Ores - 4020007, 4020008, 4003000); // Diamond and Black Crystal Ores and Screws -var prizeQtyEtc = Array(15, 15, 15, 15, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 3, 3, 30); -//500, 1000, 2000, 4000, 7500 = default + Array(1,1,0,1,0,0),Array(1,1,1,0,0,0)); + +function clearStage(stage, eim, curMap) { + eim.setProperty(stage + "stageclear", "true"); + eim.showClearEffect(true); + + eim.linkToNextStage(stage, "kpq", curMap); //opens the portal to the next map +} + +function rectangleStages(eim, property, areaCombos, areaRects) { + var c = eim.getProperty(property); + if(c == null) { + c = Math.floor(Math.random() * areaCombos.length); + eim.setProperty(property, c.toString()); + } + else c = parseInt(c); + + // get player placement + var players = eim.getPlayers(); + var playerPlacement = new Array(0, 0, 0, 0, 0, 0); + + for(var i = 0; i < eim.getPlayerCount(); i++) { + for(var j = 0; j < areaRects.length; j++) { + if(areaRects[j].contains(players.get(i).getPosition())) { + playerPlacement[j] += 1; + break; + } + } + } + + var curCombo = areaCombos[c]; + var accept = true; + for(var j = 0; j < curCombo.length; j++) { + if(curCombo[j] != playerPlacement[j]) { + accept = false; + break; + } + } + + return accept; +} + +var status = -1; +var eim; + function start() { - status = -1; - curMap = cm.getPlayer().getMapId() - 103000799; - action(1, 0, 0); + action(1, 0, 0); } function action(mode, type, selection) { - if (mode == 1) { - status++; - } else if (type == 0 && mode == 0) - status--; - else { - cm.dispose(); - return; - } - if (curMap == 1) { // First Stage. - if (isLeader()) { - var eim = cm.getPlayer().getEventInstance(); - party = eim.getPlayers(); - preamble = eim.getProperty("leader1stpreamble"); - if (preamble == null) { - cm.sendNext("Hello. Welcome to the first stage. Look around and you'll see Ligators wandering around. When you defeat them, they will cough up a #bcoupon#k. Every member of the party other than the leader should talk to me, geta question, and gather up the same number of #bcoupons#k as the answer to the question I'll give to them.\r\nIf you gather up the right amount of #bcoupons#k, I'll give the #bpass#k to that player. Once all the party members other than the leader gather up the #bpasses#k and give them to the leader, the leader will hand over the #bpasses#k to me, clearing the stage in the process. The faster you take care of the stages, the more stages you'll be able to challenge. So I suggest you take care of things quickly and swiftly. Well then, best of luck to you."); - eim.setProperty("leader1stpreamble","done"); - cm.dispose(); - } else { - var complete = eim.getProperty(curMap + "stageclear"); - if (complete != null) { - cm.sendNext("Please hurry on to the next stage, the portal opened!"); - cm.dispose(); - } else { - var numpasses = party.size() - 1; // All the players in the party need to get a pass besides the leader. - var strpasses = "#b" + numpasses + " passes#k"; - if (!cm.haveItem(4001008, numpasses)) { - cm.sendNext("I'm sorry, but you are short on the number of passes. You need to give me the right number of passes; it should be the number of members of your party minus the leader, " + strpasses + " to clear the stage. Tell your party members to solve the questions, gather up the passes, and give them to you."); - cm.dispose(); - } else { - cm.sendNext("You gathered up " + strpasses + "! Congratulations on clearing the stage! I'll make the portal that sends you to the next stage. There's a time limit on getting there, so please hurry. Best of luck to you all!"); - clear(1, eim, cm); - cm.givePartyExp("KerningPQ1st"); - cm.gainItem(4001008, -numpasses); - cm.dispose(); - // TODO: Make the shiny thing flash - } - } - } - } else { // Not leader - var eim = cm.getPlayer().getEventInstance(); - pstring = "member1stpreamble" + cm.getPlayer().getId(); - preamble = eim.getProperty(pstring); - if (status == 0) { - if (preamble == null) { - var qstring = "member1st" + cm.getPlayer().getId(); - var question = eim.getProperty(qstring); - if (question == null) { - // Select a random question to ask the player. - var questionNum = Math.floor(Math.random() * questions.length); - eim.setProperty(qstring, questionNum); - } - cm.sendNext("Here, you need to collect #bcoupons#k by defeating the same number of Ligators as the answer to the questions asked individually."); - } else { // Otherwise, check for stage completed - var complete = eim.getProperty(curMap + "stageclear"); - if (complete != null) { // Strage completed - cm.sendNext("Please hurry on to the next stage, the portal is open!"); - cm.dispose(); - } else { - // Reply to player correct/incorrect response to the question they have been asked - var qstring = "member1st" + cm.getPlayer().getId(); - var qcompletestr = "member1stcom" + cm.getPlayer().getId(); - var numcoupons = qanswers[parseInt(eim.getProperty(qstring))]; - var qcorr = cm.itemQuantity(4001007); - if(eim.getProperty(qcompletestr) != null) { - cm.sendNext("Thanks for bringing me the coupons. Please hand the pass to your party leader to continue."); - cm.dispose(); - } else if (numcoupons == qcorr) { - cm.sendNext("That's the right answer! For that you have just received a #bpass#k. Please hand it to the leader of the party."); - cm.gainItem(4001007, -numcoupons); - cm.gainItem(4001008, 1); - eim.setProperty(qcompletestr, "done"); - cm.dispose(); - } else - cm.sendNext("I'm sorry, but that is not the right answer! Please have the correct number of coupons in your inventory."); - } - } - } else if (status == 1) { - if (preamble == null) { - var qstring = "member1st" + cm.getPlayer().getId(); - var question = parseInt(eim.getProperty(qstring)); - cm.sendNextPrev(questions[question]); - } else { - var qstring = "member1st" + cm.getPlayer().getId(); - var question = parseInt(eim.getProperty(qstring)); - cm.sendNextPrev(questions[question]); - cm.dispose(); - } - } else if (status == 2) { // Preamble completed - eim.setProperty(pstring,"done"); + eim = cm.getEventInstance(); + + if (mode == -1) { cm.dispose(); - } - } // End first map scripts - }else if (2 <= curMap && 4 >= curMap) { - new Rectanglestages(cm); - }else if (curMap == 5) { // Final stage - var eim = cm.getPlayer().getEventInstance(); - if (eim.getProperty("5stageclear") == null) { //If no - if (isLeader()) { // Leader - if (cm.haveItem(4001008, 10)) { - // Clear stage - cm.sendNext("Here's the portal that leads you to the last, bonus stage. It's a stage that allows you to defeat regular monsters a little easier. You'll be given a set amount of time to hunt as much as possible, but you can always leave the stage in the middle of it through the NPC. Again, congratulations on clearing all the stages. Take care..."); - party = eim.getPlayers(); - cm.gainItem(4001008, -10); - clear(5, eim, cm); - cm.givePartyExp("KerningPQFinal"); - cm.dispose(); - } else { // Not done yet - cm.sendNext("Hello. Welcome to the 5th and final stage. Walk around the map and you'll be able to find some Boss monsters. Defeat all of them, gather up #bthe passes#k, and please get them to me. Once you earn your pass, the leader of your party will collect them, and then get them to me once the #bpasses#k are gathered up. The monsters may be familiar to you, but they may be much stronger than you think, so please be careful. Good luck!\r\nAs a result of complaints, it is now mandatory to kill all the Slimes! Do it!"); - } - cm.dispose(); - } else { // Members - cm.sendNext("Welcome to the 5th and final stage. Walk around the map and you will be able to find some Boss monsters. Defeat them all, gather up the #bpasses#k, and give them to your leader. Once you are done, return to me to collect your reward."); - cm.dispose(); - } - } else { // Give rewards and warp to bonus - if (status == 0) { - cm.sendNext("Incredible! You cleared all the stages to get to this point. Here's a small prize for your job well done. Before you accept it, however, please make sure your use and etc. inventories have empty slots available.\r\n#bYou will not receive a prize if you have no free slots!#k"); - } else if (status == 1) { - getPrize(eim,cm); - cm.dispose(); - } - } - } else { // No map found - cm.sendNext("Invalid map, this means the stage is incomplete."); - cm.dispose(); - } -} - -function clear(stage, eim, cm) { - eim.setProperty(stage + "stageclear", "true"); - var map = eim.getMapInstance(cm.getPlayer().getMapId()); - map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/clear")); - map.broadcastMessage(MaplePacketCreator.playSound("Party1/Clear")); - map.broadcastMessage(MaplePacketCreator.environmentChange("gate", 2)); - var mf = eim.getMapFactory(); - map = mf.getMap(103000800 + stage); - var nextStage = eim.getMapInstance(103000800 + stage); - var portal = nextStage.getPortal("next00"); - if (portal != null) { - portal.setScriptName("kpq" + stage); - } -} - -function failstage(eim, cm) { - var map = eim.getMapInstance(cm.getPlayer().getMapId()); - map.broadcastMessage(MaplePacketCreator.playSound("Party1/Failed")); - map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/wrong_kor")); -} - -function Rectanglestages (cm) { - var eim = cm.getPlayer().getEventInstance(); - var nthtext; - var nthobj; - var nthverb; - var nthpos; - var curArray; - var curCombo; - var objset; - if (curMap == 2) { - nthtext = "2nd"; - nthobj = "ropes"; - nthverb = "hang"; - nthpos = "hang on the ropes too low"; - curArray = stage2Rects; - curCombo = stage2combos; - objset = [0,0,0,0]; - } else if (curMap == 3) { - nthtext = "3rd"; - nthobj = "platforms"; - nthverb = "stand"; - nthpos = "stand too close to the edges"; - curArray = stage3Rects; - curCombo = stage3combos; - objset = [0,0,0,0,0]; - } else if (curMap == 4) { - nthtext = "4th"; - nthobj = "barrels"; - nthverb = "stand"; - nthpos = "stand too close to the edges"; - curArray = stage4Rects; - curCombo = stage4combos; - objset = [0,0,0,0,0,0]; - } - if (isLeader()) { // Check if player is leader - if (status == 0) { - party = eim.getPlayers(); - preamble = eim.getProperty("leader" + nthtext + "preamble"); - if (preamble == null) { // first time talking. - cm.sendNext("Hi. Welcome to the " + nthtext + " stage. Next to me, you'll see a number of " + nthobj + ". Out of these " + nthobj + ", #b3 are connected to the portal that sends you to the next stage#k. All you need to do is have #b3 party members find the correct " + nthobj + " and " + nthverb + " on them.#k\r\nBUT, it doesn't count as an answer if you " + nthpos + "; please be near the middle of the " + nthobj + " to be counted as a correct answer. Also, only 3 members of your party are allowed on the " + nthobj + ". Once they are " + nthverb + "ing on them, the leader of the party must #bdouble-click me to check and see if the answer's correct or not#k. Now, find the right " + nthobj + " to " + nthverb + " on!"); - eim.setProperty("leader" + nthtext + "preamble","done"); - var sequenceNum = Math.floor(Math.random() * curCombo.length); - eim.setProperty("stage" + nthtext + "combo", sequenceNum.toString()); - cm.dispose(); - } else { - if(cm.getPlayer().getMap().getCharacters().size() != eim.getPlayerCount()) { - cm.sendOk("Please make sure all of your party members are here before you continue."); - cm.dispose(); - return; - } - var complete = eim.getProperty(curMap + "stageclear"); - if (complete != null) { - cm.sendNext("Please hurry on to the next stage, the portal opened!"); - cm.dispose(); - } else { // Check for people on ropes and their positions - var playersOnCombo = 0; - for (var i = 0; i < party.size(); i++) { - for (var y = 0; y < curArray.length; y++) { - if (curArray[y].contains(party.get(i).getPosition())) { - playersOnCombo++; - objset[y] = 1; - break; - } - } - } - if (playersOnCombo == 3) { - var combo = curCombo[parseInt(eim.getProperty("stage" + nthtext + "combo"))]; - var correctCombo = true; - for (i = 0; i < objset.length && correctCombo; i++) - if (combo[i] != objset[i]) - correctCombo = false; - if (correctCombo) { - clear(curMap, eim, cm); - cm.givePartyExp("KerningPQ" + nthtext); - cm.dispose(); - } else { // Wrong - failstage(eim, cm); - cm.dispose(); - } - } else { - cm.sendNext("It looks like you haven't found the 3 " + nthobj + " just yet. Please think of a different combination of " + nthobj + ". Only 3 are allowed to " + nthverb + " on " + nthobj + ", and if you " + nthpos + " it may not count as an answer, so please keep that in mind. Keep going!"); - cm.dispose(); - } - } - } } else { - var complete = eim.getProperty(curMap + "stageclear"); - if (complete != null) { - var target = eim.getMapInstance(103000800 + curMap); - var targetPortal = target.getPortal("st00"); - cm.getPlayer().changeMap(target, targetPortal); - } - cm.dispose(); - } - } else { // Not leader - var complete = eim.getProperty(curMap.toString() + "stageclear"); - if (complete != null) { - cm.sendNext("Please hurry on to the next stage, the portal opened!"); - } else { - cm.sendNext("Please have the party leader talk to me."); - } - cm.dispose(); - } -} + if (mode == 0 && status == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + + if(status == 0) { + var curMap = cm.getMapId(); + var stage = curMap - 103000800 + 1; + if(eim.getProperty(stage.toString() + "stageclear") != null) { + if(stage < 5) { + cm.sendNext("Please hurry on to the next stage, the portal opened!"); + cm.dispose(); + } + else { + cm.sendNext("Incredible! You cleared all the stages to get to this point. Here's a small prize for your job well done. Before you accept it, however, please make sure your use and etc. inventories have empty slots available."); + } + } + else if(curMap == 103000800) { // stage 1 + if(cm.isLeader()) { + var numpasses = eim.getPlayerCount() - 1; // minus leader -function isLeader(){ - if(cm.getParty() == null) - return false; - else - return cm.isLeader(); -} + if(cm.hasItem(4001008, numpasses)) { + cm.sendNext("You gathered up " + numpasses + " passes! Congratulations on clearing the stage! I'll make the portal that sends you to the next stage. There's a time limit on getting there, so please hurry. Best of luck to you all!"); + clearStage(stage, eim, curMap); + eim.gridClear(); + cm.gainItem(4001008, -numpasses); + } + else { + cm.sendNext("I'm sorry, but you are short on the number of passes. You need to give me the right number of passes; it should be the number of members of your party minus the leader, in this case the total of " + numpasses + " to clear the stage. Tell your party members to solve the questions, gather up the passes, and give them to you."); + } + } + else { + var data = eim.gridCheck(cm.getPlayer()); -function getPrize(eim,cm) { - var itemSetSel = Math.random(); - var itemSet; - var itemSetQty; - var hasQty = false; - if (itemSetSel < 0.3) - itemSet = prizeIdScroll; - else if (itemSetSel < 0.6) - itemSet = prizeIdEquip; - else if (itemSetSel < 0.9) { - itemSet = prizeIdUse; - itemSetQty = prizeQtyUse; - hasQty = true; - } else { - itemSet = prizeIdEtc; - itemSetQty = prizeQtyEtc; - hasQty = true; - } - var sel = Math.floor(Math.random()*itemSet.length); - var qty = 1; - if (hasQty) - qty = itemSetQty[sel]; - cm.gainItem(itemSet[sel], qty, true, true); - cm.getPlayer().changeMap(eim.getMapInstance(103000805)); + if(data == 0) { + cm.sendNext("Thanks for bringing me the coupons. Please hand the pass to your party leader to continue."); + } else if(data == -1) { + data = Math.floor(Math.random() * stage1Questions.length) + 1; //data will be counted from 1 + eim.gridInsert(cm.getPlayer(), data); + + var question = stage1Questions[data - 1]; + cm.sendNext(question); + } else { + var answer = stage1Answers[data - 1]; + + if(cm.itemQuantity(4001007) == answer) { + cm.sendNext("That's the right answer! For that you have just received a #bpass#k. Please hand it to the leader of the party."); + cm.gainItem(4001007, -answer); + cm.gainItem(4001008, 1); + eim.gridInsert(cm.getPlayer(), 0); + } + else { + cm.sendNext("I'm sorry, but that is not the right answer! Please have the correct number of coupons in your inventory."); + } + } + } + + cm.dispose(); + } else if(curMap == 103000801) { // stage 2 + var stgProperty = "stg2Property"; + var stgCombos = stage2Combos; + var stgAreas = stage2Rects; + + var nthtext = "2nd", nthobj = "ropes", nthverb = "hang", nthpos = "hang on the ropes too low"; + var nextStgId = 103000802; + + if(!eim.isLeader(cm.getPlayer())) { + cm.sendOk("Follow the instructions given by your party leader to proceed through this stage."); + } + else if(eim.getProperty(stgProperty) == null) { + cm.sendNext("Hi. Welcome to the " + nthtext + " stage. Next to me, you'll see a number of " + nthobj + ". Out of these " + nthobj + ", #b3 are connected to the portal that sends you to the next stage#k. All you need to do is have #b3 party members find the correct " + nthobj + " and " + nthverb + " on them.#k\r\nBUT, it doesn't count as an answer if you " + nthpos + "; please be near the middle of the " + nthobj + " to be counted as a correct answer. Also, only 3 members of your party are allowed on the " + nthobj + ". Once they are " + nthverb + "ing on them, the leader of the party must #bdouble-click me to check and see if the answer's correct or not#k. Now, find the right " + nthobj + " to " + nthverb + " on!"); + var c = Math.floor(Math.random() * stgCombos.length); + eim.setProperty(stgProperty, c.toString()); + } + else { + var accept = rectangleStages(eim, stgProperty, stgCombos, stgAreas); + + if(accept) { + clearStage(stage, eim, curMap); + cm.sendNext("Please hurry on to the next stage, the portal opened!"); + } + else { + eim.showWrongEffect(); + cm.sendNext("It looks like you haven't found the 3 " + nthobj + " just yet. Please think of a different combination of " + nthobj + ". Only 3 are allowed to " + nthverb + " on " + nthobj + ", and if you " + nthpos + " it may not count as an answer, so please keep that in mind. Keep going!"); + } + } + + cm.dispose(); + } else if(curMap == 103000802) { + var stgProperty = "stg3Property"; + var stgCombos = stage3Combos; + var stgAreas = stage3Rects; + + var nthtext = "3rd", nthobj = "platforms", nthverb = "stand", nthpos = "stand too close to the edges"; + var nextStgId = 103000803; + + if(!eim.isLeader(cm.getPlayer())) { + cm.sendOk("Follow the instructions given by your party leader to proceed through this stage."); + } + else if(eim.getProperty(stgProperty) == null) { + cm.sendNext("Hi. Welcome to the " + nthtext + " stage. Next to me, you'll see a number of " + nthobj + ". Out of these " + nthobj + ", #b3 are connected to the portal that sends you to the next stage#k. All you need to do is have #b3 party members find the correct " + nthobj + " and " + nthverb + " on them.#k\r\nBUT, it doesn't count as an answer if you " + nthpos + "; please be near the middle of the " + nthobj + " to be counted as a correct answer. Also, only 3 members of your party are allowed on the " + nthobj + ". Once they are " + nthverb + "ing on them, the leader of the party must #bdouble-click me to check and see if the answer's correct or not#k. Now, find the right " + nthobj + " to " + nthverb + " on!"); + var c = Math.floor(Math.random() * stgCombos.length); + eim.setProperty(stgProperty, c.toString()); + } + else { + var accept = rectangleStages(eim, stgProperty, stgCombos, stgAreas); + + if(accept) { + clearStage(stage, eim, curMap); + cm.sendNext("Please hurry on to the next stage, the portal opened!"); + } + else { + eim.showWrongEffect(); + cm.sendNext("It looks like you haven't found the 3 " + nthobj + " just yet. Please think of a different combination of " + nthobj + ". Only 3 are allowed to " + nthverb + " on " + nthobj + ", and if you " + nthpos + " it may not count as an answer, so please keep that in mind. Keep going!"); + } + } + + cm.dispose(); + } else if(curMap == 103000803) { + var stgProperty = "stg4Property"; + var stgCombos = stage4Combos; + var stgAreas = stage4Rects; + + var nthtext = "4th", nthobj = "barrels", nthverb = "stand", nthpos = "stand too close to the edges"; + var nextStgId = 103000804; + + if(!eim.isLeader(cm.getPlayer())) { + cm.sendOk("Follow the instructions given by your party leader to proceed through this stage."); + } + else if(eim.getProperty(stgProperty) == null) { + cm.sendNext("Hi. Welcome to the " + nthtext + " stage. Next to me, you'll see a number of " + nthobj + ". Out of these " + nthobj + ", #b3 are connected to the portal that sends you to the next stage#k. All you need to do is have #b3 party members find the correct " + nthobj + " and " + nthverb + " on them.#k\r\nBUT, it doesn't count as an answer if you " + nthpos + "; please be near the middle of the " + nthobj + " to be counted as a correct answer. Also, only 3 members of your party are allowed on the " + nthobj + ". Once they are " + nthverb + "ing on them, the leader of the party must #bdouble-click me to check and see if the answer's correct or not#k. Now, find the right " + nthobj + " to " + nthverb + " on!"); + var c = Math.floor(Math.random() * stgCombos.length); + eim.setProperty(stgProperty, c.toString()); + } + else { + var accept = rectangleStages(eim, stgProperty, stgCombos, stgAreas); + + if(accept) { + clearStage(stage, eim, curMap); + cm.sendNext("Please hurry on to the next stage, the portal opened!"); + } + else { + eim.showWrongEffect(); + cm.sendNext("It looks like you haven't found the 3 " + nthobj + " just yet. Please think of a different combination of " + nthobj + ". Only 3 are allowed to " + nthverb + " on " + nthobj + ", and if you " + nthpos + " it may not count as an answer, so please keep that in mind. Keep going!"); + } + } + + cm.dispose(); + } else if(curMap == 103000804) { + if (eim.isLeader(cm.getPlayer())) { + if (cm.haveItem(4001008, 10)) { + cm.sendNext("Here's the portal that leads you to the last, bonus stage. It's a stage that allows you to defeat regular monsters a little easier. You'll be given a set amount of time to hunt as much as possible, but you can always leave the stage in the middle of it through the NPC. Again, congratulations on clearing all the stages. Let your party talk to me to receive their prizes as they are allowed to pass to the bonus stage. Take care..."); + cm.gainItem(4001008, -10); + + clearStage(stage, eim, curMap); + eim.clearPQ(); + } else { + cm.sendNext("Hello. Welcome to the 5th and final stage. Walk around the map and you'll be able to find some Boss monsters. Defeat all of them, gather up #bthe passes#k, and please get them to me. Once you earn your pass, the leader of your party will collect them, and then get them to me once the #bpasses#k are gathered up. The monsters may be familiar to you, but they may be much stronger than you think, so please be careful. Good luck!"); + } + } else { + cm.sendNext("Welcome to the 5th and final stage. Walk around the map and you will be able to find some Boss monsters. Defeat them all, gather up the #bpasses#k, and #bgive them to your leader#k. Once you are done, return to me to collect your reward."); + } + + cm.dispose(); + } + } + else if (status == 1) { + if(!eim.giveEventReward(cm.getPlayer())) { + cm.sendNext("Please make room on your inventory first!"); + } else { + cm.warp(103000805, "st00"); + } + + cm.dispose(); + } + } } \ No newline at end of file diff --git a/scripts/npc/world0/9020002.js b/scripts/npc/world0/9020002.js index c2e787e0ba..fbbc28076d 100644 --- a/scripts/npc/world0/9020002.js +++ b/scripts/npc/world0/9020002.js @@ -46,7 +46,7 @@ function action(mode, type, selection){ var mapId = cm.getPlayer().getMapId(); if (mapId == 103000890) { if (status == 0) { - cm.sendNext("See you next time."); + cm.sendNext("To return back to the city, follow this way."); } else { cm.getPlayer().changeMap(103000000, cm.getClient().getChannelServer().getMapFactory().getMap(103000000).getRandomSpawnpoint()); cm.removeAll(4001007); @@ -61,15 +61,7 @@ function action(mode, type, selection){ } cm.sendYesNo(outText); } else if (mode == 1) { - var eim = cm.getPlayer().getEventInstance(); // Remove them from the PQ! - if (eim == null) - cm.warp(103000890, "st00"); // Warp player - else if (cm.isLeader()) { - //cm.getEventManager("KerningPQ").setProperty("KPQOpen" , "true"); - eim.disbandParty(); - } - else - eim.leftParty(cm.getPlayer()); + cm.warp(103000890, "st00"); // Warp player cm.dispose(); } } diff --git a/scripts/npc/world0/9040010.js b/scripts/npc/world0/9040010.js index 5a3ca5c663..46432c5e76 100644 --- a/scripts/npc/world0/9040010.js +++ b/scripts/npc/world0/9040010.js @@ -34,7 +34,7 @@ function start() { points = 100; cm.getGuild().gainGP(points); } - eim.finishPQ(); + eim.clearPQ(); } else { cm.sendOk("This is your final challenge. Defeat the evil lurking within the Rubian and return it to me. That is all."); diff --git a/scripts/npc/world0/9103001.js b/scripts/npc/world0/9103001.js index 06abdade82..3fd9fc5e86 100644 --- a/scripts/npc/world0/9103001.js +++ b/scripts/npc/world0/9103001.js @@ -72,8 +72,11 @@ function action(mode, type, selection) { } else if (!open){ cm.sendOk("The PQ is #rclosed#k for now."); } else { - //cm.sendOk("You may enter");//ENTER PQ - em.startInstance(cm.getParty(), cm.getPlayer().getMap()); + if(!em.startInstance(cm.getParty(), cm.getPlayer().getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } var party = cm.getPlayer().getEventInstance().getPlayers(); cm.removeFromParty(4001106, party); } diff --git a/scripts/npc/world0/9201048.js b/scripts/npc/world0/9201048.js index 70652ae6e1..e78524b640 100644 --- a/scripts/npc/world0/9201048.js +++ b/scripts/npc/world0/9201048.js @@ -59,8 +59,13 @@ function start() { var em = cm.getEventManager("AmoriaPQ"); if (em == null) cm.dispose(); - else - em.startInstance(cm.getParty(),cm.getPlayer().getMap()); + else { + if(!em.startInstance(cm.getParty(),cm.getPlayer().getMap())) { + cm.sendOk("A party in your name is already registered in this event."); + cm.dispose(); + return; + } + } cm.dispose(); } else { diff --git a/scripts/portal/kpq4.js b/scripts/portal/kpq4.js index ce063c40c0..efbf215bb2 100644 --- a/scripts/portal/kpq4.js +++ b/scripts/portal/kpq4.js @@ -26,7 +26,7 @@ Kerning PQ: 4th stage to final stage portal function enter(pi) { var eim = pi.getPlayer().getEventInstance(); var target = eim.getMapInstance(103000805); - if (eim.getProperty("4stageclear") != null) { + if (eim.getProperty("5stageclear") != null) { pi.getPlayer().changeMap(target, target.getPortal("st00")); return true; } diff --git a/scripts/portal/party6_out.js b/scripts/portal/party6_out.js index d5f7228a5b..b47179ae61 100644 --- a/scripts/portal/party6_out.js +++ b/scripts/portal/party6_out.js @@ -1,7 +1,8 @@ function enter(pi) { if ((pi.getMap().getMonsters().size() == 0 || pi.getMap().getMonsterById(9300183) != null) && (pi.getMap().getReactorByName("") == null || pi.getMap().getReactorByName("").getState() == 1)) { if(pi.isLeader()) { - pi.clearPQ(930000800); + pi.getEventInstance().clearPQ(); + pi.getEventInstance().warpEventTeam(930000800); return true; } else { diff --git a/sql/db_drops.sql b/sql/db_drops.sql index 7878a833ae..8f3ee6e205 100644 --- a/sql/db_drops.sql +++ b/sql/db_drops.sql @@ -19106,6 +19106,8 @@ UPDATE reactordrops SET questid=6002 WHERE itemid=4031508; UPDATE reactordrops SET questid=9351 WHERE itemid=4031258; UPDATE reactordrops SET questid=3083 WHERE itemid >= 4031274 AND itemid <= 4031278; + UPDATE reactordrops SET questid=1008 WHERE itemid=4031161; + UPDATE reactordrops SET questid=1008 WHERE itemid=4031162; INSERT INTO `reactordrops` (`reactorid`, `itemid`, `chance`, `questid`) VALUES (9102000, 4031157, 1, 2074), diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index cda4becb92..1f944870a8 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -151,9 +151,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { private static final int[] EXP_RATE_GAIN = {1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144}; //fibonacci :3 private static final String LEVEL_200 = "[Congrats] %s has reached Level 200! Congratulate %s on such an amazing achievement!"; + + // MapleStory default keyset private static final int[] DEFAULT_KEY = {18, 65, 2, 23, 3, 4, 5, 6, 16, 17, 19, 25, 26, 27, 31, 34, 35, 37, 38, 40, 43, 44, 45, 46, 50, 56, 59, 60, 61, 62, 63, 64, 57, 48, 29, 7, 24, 33, 41, 39}; private static final int[] DEFAULT_TYPE = {4, 6, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 4, 4, 5, 6, 6, 6, 6, 6, 6, 5, 4, 5, 4, 4, 4, 4, 4}; private static final int[] DEFAULT_ACTION = {0, 106, 10, 1, 12, 13, 18, 24, 8, 5, 4, 19, 14, 15, 2, 17, 11, 3, 20, 16, 9, 50, 51, 6, 7, 53, 100, 101, 102, 103, 104, 105, 54, 22, 52, 21, 25, 26, 23, 27}; + + // MapleSolaxiaV2 custom keyset + private static final int[] CUSTOM_KEY = {2, 3, 4, 5, 31, 56, 59, 32, 42, 6, 17, 29, 30, 41, 50, 60, 61, 62, 63, 64, 65, 16, 7, 8}; + private static final int[] CUSTOM_TYPE = {4, 4, 4, 4, 5, 5, 6, 5, 5, 4, 4, 4, 5, 4, 4, 6, 6, 6, 6, 6, 6, 4, 4, 4}; + private static final int[] CUSTOM_ACTION = {1, 0, 3, 2, 53, 54, 100, 52, 51, 19, 5, 9, 50, 7, 22, 101, 102, 103, 104, 105, 106, 8, 17, 26}; + private static final String[] BLOCKED_NAMES = {"admin", "owner", "moderator", "intern", "donor", "administrator", "help", "helper", "alert", "notice", "maplestory", "Solaxia", "fuck", "wizet", "fucking", "negro", "fuk", "fuc", "penis", "pussy", "asshole", "gay", "nigger", "homo", "suck", "cum", "shit", "shitty", "condom", "security", "official", "rape", "nigga", "sex", "tit", "boner", "orgy", "clit", "asshole", "fatass", "bitch", "support", "gamemaster", "cock", "gaay", "gm", "operate", "master", "sysop", "party", "GameMaster", "community", "message", "event", "test", "meso", "Scania", "renewal", "yata", "AsiaSoft", "henesys"}; @@ -354,9 +362,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { ret.getInventory(MapleInventoryType.USE).setSlotLimit(24); ret.getInventory(MapleInventoryType.SETUP).setSlotLimit(24); ret.getInventory(MapleInventoryType.ETC).setSlotLimit(24); - for (int i = 0; i < DEFAULT_KEY.length; i++) { - ret.keymap.put(DEFAULT_KEY[i], new MapleKeyBinding(DEFAULT_TYPE[i], DEFAULT_ACTION[i])); + + // Select a keybinding method + int[] selectedKey; + int[] selectedType; + int[] selectedAction; + + if(ServerConstants.USE_CUSTOM_KEYSET) { + selectedKey = CUSTOM_KEY; + selectedType = CUSTOM_TYPE; + selectedAction = CUSTOM_ACTION; } + else { + selectedKey = DEFAULT_KEY; + selectedType = DEFAULT_TYPE; + selectedAction = DEFAULT_ACTION; + } + + for (int i = 0; i < selectedKey.length; i++) { + ret.keymap.put(selectedKey[i], new MapleKeyBinding(selectedType[i], selectedAction[i])); + } + + //to fix the map 0 lol for (int i = 0; i < 5; i++) { ret.trockmaps.add(999999999); @@ -1206,6 +1233,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { newWarpMap = -1; changeMap(temp); } + + // if this event map has a gate already opened, render it + if(getEventInstance() != null) { + getEventInstance().recoverOpenedGate(this, map.getId()); + } } public void changePage(int page) { @@ -1714,6 +1746,10 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { this.addFame(delta); this.updateSingleStat(MapleStat.FAME, this.fame); } + + public void gainMeso(int gain) { + gainMeso(gain, true, false, true); + } public void gainMeso(int gain, boolean show) { gainMeso(gain, show, false, false); @@ -3475,7 +3511,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { int lastQuestProcessed = 0; try { for (MapleQuestStatus q : quests.values()) { - lastQuestProcessed = q.getQuest().getId(); + lastQuestProcessed = q.getQuest().getId(); if (q.getStatus() == MapleQuestStatus.Status.COMPLETED || q.getQuest().canComplete(this, null)) { continue; } @@ -4037,12 +4073,28 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { return false; } + // Select a keybinding method + int[] selectedKey; + int[] selectedType; + int[] selectedAction; + + if(ServerConstants.USE_CUSTOM_KEYSET) { + selectedKey = CUSTOM_KEY; + selectedType = CUSTOM_TYPE; + selectedAction = CUSTOM_ACTION; + } + else { + selectedKey = DEFAULT_KEY; + selectedType = DEFAULT_TYPE; + selectedAction = DEFAULT_ACTION; + } + ps = con.prepareStatement("INSERT INTO keymap (characterid, `key`, `type`, `action`) VALUES (?, ?, ?, ?)"); ps.setInt(1, id); - for (int i = 0; i < DEFAULT_KEY.length; i++) { - ps.setInt(2, DEFAULT_KEY[i]); - ps.setInt(3, DEFAULT_TYPE[i]); - ps.setInt(4, DEFAULT_ACTION[i]); + for (int i = 0; i < selectedKey.length; i++) { + ps.setInt(2, selectedKey[i]); + ps.setInt(3, selectedType[i]); + ps.setInt(4, selectedAction[i]); ps.execute(); } ps.close(); @@ -4203,6 +4255,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { ps.addBatch(); } ps.executeBatch(); + deleteWhereCharacterId(con, "DELETE FROM skillmacros WHERE characterid = ?"); ps = con.prepareStatement("INSERT INTO skillmacros (characterid, skill1, skill2, skill3, name, shout, position) VALUES (?, ?, ?, ?, ?, ?, ?)"); ps.setInt(1, getId()); diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java index 01e675e0fe..b891cb041c 100644 --- a/src/constants/ServerConstants.java +++ b/src/constants/ServerConstants.java @@ -24,6 +24,7 @@ public class ServerConstants { public static boolean JAVA_8; public static boolean SHUTDOWNHOOK; //Gameplay Configurations + public static final boolean USE_CUSTOM_KEYSET = true; public static final boolean USE_MAXRANGE = true; //will send and receive packets from all events of a map, rather than those of only view range. public static final boolean USE_DEBUG = true; //will enable some text prints and new commands in the client oriented for debugging. public static final boolean USE_MTS = false; diff --git a/src/net/server/channel/handlers/KeymapChangeHandler.java b/src/net/server/channel/handlers/KeymapChangeHandler.java index b0da962abf..70f17a67ad 100644 --- a/src/net/server/channel/handlers/KeymapChangeHandler.java +++ b/src/net/server/channel/handlers/KeymapChangeHandler.java @@ -35,28 +35,30 @@ import tools.data.input.SeekableLittleEndianAccessor; public final class KeymapChangeHandler extends AbstractMaplePacketHandler { @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - if (slea.available() >= 8) { + if (slea.available() >= 8) { int mode = slea.readInt(); if(mode == 0) { int numChanges = slea.readInt(); for (int i = 0; i < numChanges; i++) { int key = slea.readInt(); int type = slea.readByte(); - int action = slea.readInt(); + int action = slea.readInt(); + Skill skill = SkillFactory.getSkill(action); boolean isBanndedSkill = false; if (skill != null) { - isBanndedSkill = GameConstants.bannedBindSkills(skill.getId()); + isBanndedSkill = GameConstants.bannedBindSkills(skill.getId()); if (isBanndedSkill || (!c.getPlayer().isGM() && GameConstants.isGMSkills(skill.getId())) || (!GameConstants.isInJobTree(skill.getId(), c.getPlayer().getJob().getId()) && !c.getPlayer().isGM())) { //for those skills are are "technically" in the beginner tab, like bamboo rain in Dojo or skills you find in PYPQ AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit keymapping."); FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " tried to use skill " + skill.getId() + "\r\n"); c.disconnect(true, false); return; } - if (c.getPlayer().getSkillLevel(skill) < 1) { - continue; - } + /* if (c.getPlayer().getSkillLevel(skill) < 1) { HOW WOULD A SKILL EVEN BE AVAILABLE TO KEYBINDING + continue; IF THERE IS NOT EVEN A SINGLE POINT USED INTO IT?? + } */ //Nice to know some skills have the same ids as items, heh. } + c.getPlayer().changeKeybinding(key, new MapleKeyBinding(type, action)); } } else if(mode == 1) { // Auto HP Potion diff --git a/src/net/server/channel/handlers/PartyOperationHandler.java b/src/net/server/channel/handlers/PartyOperationHandler.java index adcaf7c315..d7984df99e 100644 --- a/src/net/server/channel/handlers/PartyOperationHandler.java +++ b/src/net/server/channel/handlers/PartyOperationHandler.java @@ -99,10 +99,10 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { String name = slea.readMapleAsciiString(); MapleCharacter invited = world.getPlayerStorage().getCharacterByName(name); if (invited != null) { - if(invited.getLevel() < 10) { //min requirement is level 10 - c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements.")); - return; - } + if(invited.getLevel() < 10) { //min requirement is level 10 + c.announce(MaplePacketCreator.serverNotice(5, "The player you have invited does not meet the requirements.")); + return; + } if (invited.getParty() == null) { if (player.getParty() == null) { partyplayer = new MaplePartyCharacter(player); diff --git a/src/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/net/server/channel/handlers/PlayerLoggedinHandler.java index 8ac3a5b802..c2ed617358 100644 --- a/src/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -245,8 +245,8 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { player.checkBerserk(); player.expirationTask(); //player.setRates(); - if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) { - player.createDragon(); + if (GameConstants.hasSPTable(player.getJob()) && player.getJob().getId() != 2001) { + player.createDragon(); } if (newcomer){ /* diff --git a/src/net/server/channel/handlers/QuestActionHandler.java b/src/net/server/channel/handlers/QuestActionHandler.java index 4a2d65b2b6..dedb7ec7a8 100644 --- a/src/net/server/channel/handlers/QuestActionHandler.java +++ b/src/net/server/channel/handlers/QuestActionHandler.java @@ -59,18 +59,18 @@ public final class QuestActionHandler extends AbstractMaplePacketHandler { } else if (action == 4) { // scripted start quest int npc = slea.readInt(); slea.readInt(); - if(quest.canStart(player, npc)) { - QuestScriptManager.getInstance().start(c, questid, npc); - } + if(quest.canStart(player, npc)) { + QuestScriptManager.getInstance().start(c, questid, npc); + } } else if (action == 5) { // scripted end quests //System.out.println(slea.toString()); int npc = slea.readInt(); slea.readInt(); if(quest.canComplete(player, npc)) { - QuestScriptManager.getInstance().end(c, questid, npc); - player.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); //show effect when completion - player.getMap().broadcastMessage(player, MaplePacketCreator.showForeignEffect(player.getId(), 9));//show effect around players I guess + QuestScriptManager.getInstance().end(c, questid, npc); + player.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); //show effect when completion + player.getMap().broadcastMessage(player, MaplePacketCreator.showForeignEffect(player.getId(), 9));//show effect around players I guess } } } diff --git a/src/scripting/AbstractPlayerInteraction.java b/src/scripting/AbstractPlayerInteraction.java index 4fc4911238..1309c596e3 100644 --- a/src/scripting/AbstractPlayerInteraction.java +++ b/src/scripting/AbstractPlayerInteraction.java @@ -32,6 +32,7 @@ import net.server.channel.Channel; import net.server.guild.MapleGuild; import net.server.world.MapleParty; import net.server.world.MaplePartyCharacter; +import scripting.event.EventInstanceManager; import scripting.event.EventManager; import scripting.npc.NPCScriptManager; import server.MapleInventoryManipulator; @@ -157,24 +158,19 @@ public class AbstractPlayerInteraction { return getClient().getEventManager(event); } - public void clearPQ(int toMap) { - clearPQ(getWarpMap(toMap)); - } + public EventInstanceManager getEventInstance() { + return getPlayer().getEventInstance(); + } - public void clearPQ(MapleMap toMap) { - if(getPlayer().getEventInstance() != null) - getPlayer().getEventInstance().getEm().clearPQ(getPlayer().getEventInstance(), toMap); - } - public MapleInventory getInventory(MapleInventoryType type) { return getPlayer().getInventory(type); } - public boolean hasItem(int itemid){ + public boolean hasItem(int itemid) { return haveItem(itemid, 1); } - public boolean hasItem(int itemid, int quantity){ + public boolean hasItem(int itemid, int quantity) { return haveItem(itemid, quantity); } diff --git a/src/scripting/event/EventInstanceManager.java b/src/scripting/event/EventInstanceManager.java index 5067918ec4..da74b73e63 100644 --- a/src/scripting/event/EventInstanceManager.java +++ b/src/scripting/event/EventInstanceManager.java @@ -25,10 +25,12 @@ import java.io.File; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.HashMap; import java.util.Map; +import java.util.HashSet; +import java.util.Set; import java.util.Properties; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; @@ -39,6 +41,7 @@ import javax.script.ScriptException; import net.server.world.MapleParty; import net.server.world.MaplePartyCharacter; import provider.MapleDataProviderFactory; +import server.MaplePortal; import server.TimerManager; import server.expeditions.MapleExpedition; import server.life.MapleMonster; @@ -52,6 +55,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.logging.Level; import java.util.logging.Logger; import scripting.AbstractPlayerInteraction; +import tools.MaplePacketCreator; /** * @@ -75,12 +79,23 @@ public class EventInstanceManager { private final WriteLock wL = mutex.writeLock(); private ScheduledFuture event_schedule = null; private boolean disposed = false; + private boolean eventCleared = false; // multi-leveled PQ rewards! private Map> collectionSet = new HashMap<>(ServerConstants.MAX_EVENT_LEVELS); private Map> collectionQty = new HashMap<>(ServerConstants.MAX_EVENT_LEVELS); private Map collectionExp = new HashMap<>(ServerConstants.MAX_EVENT_LEVELS); + // Exp/Meso rewards by CLEAR on a stage + private List onMapClearExp = new ArrayList<>(); + private List onMapClearMeso = new ArrayList<>(); + + // registers player status on an event (null on this Map structure equals to 0) + private Map playerGrid = new HashMap<>(); + + // registers all opened gates on the event. Will help late characters to encounter next stages gates already opened + private Set openedGates = new HashSet<>(); + public EventInstanceManager(EventManager em, String name) { this.em = em; this.name = name; @@ -97,6 +112,8 @@ public class EventInstanceManager { } public void giveEventPlayersExp(int gain, int mapId) { + if(gain == 0) return; + rL.lock(); try { if(mapId == -1) { @@ -113,6 +130,30 @@ public class EventInstanceManager { rL.unlock(); } } + + public void giveEventPlayersMeso(int gain) { + giveEventPlayersMeso(gain, -1); + } + + public void giveEventPlayersMeso(int gain, int mapId) { + if(gain == 0) return; + + rL.lock(); + try { + if(mapId == -1) { + for(MapleCharacter mc: chars) { + mc.gainMeso(gain * mc.getMesoRate()); + } + } + else { + for(MapleCharacter mc: chars) { + if(mc.getMapId() == mapId) mc.gainMeso(gain * mc.getMesoRate()); + } + } + } finally { + rL.unlock(); + } + } public void registerPlayer(MapleCharacter chr) { if (chr == null || !chr.isLoggedin()){ @@ -186,12 +227,19 @@ public class EventInstanceManager { } } - public void cancelEventTimer() { - if(event_schedule != null) event_schedule.cancel(false); + public void stopEventTimer() { + if(event_schedule != null) { + event_schedule.cancel(false); + event_schedule = null; + } dismissEventTimer(); } private void dismissEventTimer() { + for(MapleCharacter chr: getPlayers()) { + chr.getClient().getSession().write(MaplePacketCreator.removeClock()); + } + event_schedule = null; eventTime = 0; timeStarted = 0; @@ -220,9 +268,10 @@ public class EventInstanceManager { public void unregisterPlayer(MapleCharacter chr) { wL.lock(); try { - chars.remove(chr); + chars.remove(chr); + gridRemove(chr); } finally { - wL.unlock(); + wL.unlock(); } chr.setEventInstance(null); @@ -231,20 +280,20 @@ public class EventInstanceManager { public int getPlayerCount() { rL.lock(); try { - return chars.size(); + return chars.size(); } finally { - rL.unlock(); + rL.unlock(); } } public List getPlayers() { rL.lock(); try { - return new ArrayList<>(chars); + return new ArrayList<>(chars); } finally { - rL.unlock(); + rL.unlock(); } } @@ -340,37 +389,40 @@ public class EventInstanceManager { public int getKillCount(MapleCharacter chr) { Integer kc = killCount.get(chr); - if (kc == null) { - return 0; - } else { - return kc; - } + return (kc == null) ? 0 : kc; } + + public void cancelSchedule() { + if(event_schedule != null) { + event_schedule.cancel(false); + event_schedule = null; + } + } public void dispose() { - try { - em.getIv().invokeFunction("dispose", this); - } catch (ScriptException | NoSuchMethodException ex) { - ex.printStackTrace(); - } + try { + em.getIv().invokeFunction("dispose", this); + } catch (ScriptException | NoSuchMethodException ex) { + ex.printStackTrace(); + } - wL.lock(); - try { - chars.clear(); - } finally { - wL.unlock(); - } - - if(event_schedule != null) event_schedule.cancel(false); + wL.lock(); + try { + chars.clear(); + } finally { + wL.unlock(); + } + + cancelSchedule(); - mobs.clear(); - killCount.clear(); - mapFactory = null; - if (expedition != null) { - em.getChannelServer().getExpeditions().remove(expedition); - } - em.disposeInstance(name); - em = null; + mobs.clear(); + killCount.clear(); + mapFactory = null; + if (expedition != null) { + em.getChannelServer().getExpeditions().remove(expedition); + } + em.disposeInstance(name); + em = null; } public MapleMapFactory getMapFactory() { @@ -381,6 +433,8 @@ public class EventInstanceManager { TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { + if(em == null) return; + try { em.getIv().invokeFunction(methodName, EventInstanceManager.this); } catch (ScriptException | NoSuchMethodException ex) { @@ -431,8 +485,8 @@ public class EventInstanceManager { return props.getProperty(key); } - public Properties getProperties(){ - return props; + public Properties getProperties() { + return props; } public void leftParty(MapleCharacter chr) { @@ -451,7 +505,7 @@ public class EventInstanceManager { } } - public void finishPQ() { + public void clearPQ() { try { em.getIv().invokeFunction("clearPQ", this); } catch (ScriptException | NoSuchMethodException ex) { @@ -472,149 +526,315 @@ public class EventInstanceManager { } public final MapleMap setInstanceMap(final int mapid) { //gets instance map from the channelserv - if (disposed) { + if (disposed) { + return this.getMapFactory().getMap(mapid); + } + mapIds.add(mapid); + isInstanced.add(false); return this.getMapFactory().getMap(mapid); - } - mapIds.add(mapid); - isInstanced.add(false); - return this.getMapFactory().getMap(mapid); } public final boolean disposeIfPlayerBelow(final byte size, final int towarp) { - if (disposed) { - return true; - } - MapleMap map = null; - if (towarp > 0) { - map = this.getMapFactory().getMap(towarp); - } - - rL.lock(); - try { - if (chars != null && chars.size() < size) { - for (MapleCharacter chr : chars) { - if (chr == null) { - continue; - } - unregisterPlayer(chr); - if (towarp > 0) { - chr.changeMap(map, map.getPortal(0)); - } - } - dispose(); - return true; + if (disposed) { + return true; } - } catch (Exception ex) { - ex.printStackTrace(); - } finally { - rL.unlock(); - } - return false; + MapleMap map = null; + if (towarp > 0) { + map = this.getMapFactory().getMap(towarp); + } + + rL.lock(); + try { + if (chars != null && chars.size() < size) { + for (MapleCharacter chr : chars) { + if (chr == null) { + continue; + } + + unregisterPlayer(chr); + if (towarp > 0) { + chr.changeMap(map, map.getPortal(0)); + } + } + + dispose(); + return true; + } + } catch (Exception ex) { + ex.printStackTrace(); + } finally { + rL.unlock(); + } + return false; } private List convertToIntegerArray(List list) { - List intList = new ArrayList<>(); - for(Double d: list) intList.add(d.intValue()); - - return intList; + List intList = new ArrayList<>(); + for(Double d: list) intList.add(d.intValue()); + + return intList; + } + + public void setEventClearStageExp(List gain) { + onMapClearExp.clear(); + onMapClearExp.addAll(convertToIntegerArray(gain)); + } + + public void setEventClearStageMeso(List gain) { + onMapClearMeso.clear(); + onMapClearMeso.addAll(convertToIntegerArray(gain)); + } + + public Integer getClearStageExp(int stage) { //stage counts from ONE. + if(stage > onMapClearExp.size()) return 0; + return onMapClearExp.get(stage - 1); + } + + public Integer getClearStageMeso(int stage) { //stage counts from ONE. + if(stage > onMapClearMeso.size()) return 0; + return onMapClearMeso.get(stage - 1); + } + + public List getClearStageBonus(int stage) { + List list = new ArrayList<>(); + list.add(getClearStageExp(stage)); + list.add(getClearStageMeso(stage)); + + return list; } public final void setEventRewards(List rwds, List qtys, int expGiven) { - setEventRewards(1, rwds, qtys, expGiven); + setEventRewards(1, rwds, qtys, expGiven); } public final void setEventRewards(List rwds, List qtys) { - setEventRewards(1, rwds, qtys); + setEventRewards(1, rwds, qtys); } public final void setEventRewards(int eventLevel, List rwds, List qtys) { - setEventRewards(eventLevel, rwds, qtys, 0); + setEventRewards(eventLevel, rwds, qtys, 0); } public final void setEventRewards(int eventLevel, List rwds, List qtys, int expGiven) { - // fixed EXP will be rewarded at the same time the random item is given - - if(eventLevel <= 0 || eventLevel > ServerConstants.MAX_EVENT_LEVELS) return; - eventLevel--; //event level starts from 1 - - List rewardIds = convertToIntegerArray(rwds); - List rewardQtys = convertToIntegerArray(qtys); - - //rewardsSet and rewardsQty hold temporary values - collectionSet.put(eventLevel, rewardIds); - collectionQty.put(eventLevel, rewardQtys); - collectionExp.put(eventLevel, expGiven); + // fixed EXP will be rewarded at the same time the random item is given + + if(eventLevel <= 0 || eventLevel > ServerConstants.MAX_EVENT_LEVELS) return; + eventLevel--; //event level starts from 1 + + List rewardIds = convertToIntegerArray(rwds); + List rewardQtys = convertToIntegerArray(qtys); + + //rewardsSet and rewardsQty hold temporary values + wL.lock(); + try { + collectionSet.put(eventLevel, rewardIds); + collectionQty.put(eventLevel, rewardQtys); + collectionExp.put(eventLevel, expGiven); + } finally { + wL.unlock(); + } } private byte getRewardListRequirements(int level) { - if(level >= collectionSet.size()) return 0; - - byte rewardTypes = 0; - List list = collectionSet.get(level); - - for (Integer itemId : list) { - rewardTypes |= (1 << ItemConstants.getInventoryType(itemId).getType()); - } - - return rewardTypes; + if(level >= collectionSet.size()) return 0; + + byte rewardTypes = 0; + List list = collectionSet.get(level); + + for (Integer itemId : list) { + rewardTypes |= (1 << ItemConstants.getInventoryType(itemId).getType()); + } + + return rewardTypes; } private boolean hasRewardSlot(MapleCharacter player, int eventLevel) { - byte listReq = getRewardListRequirements(eventLevel); //gets all types of items present in the event reward list - - //iterating over all valid inventory types - for(byte type = 1; type <= 5; type++) { - if((listReq >> type) % 2 == 1 && !player.hasEmptySlot(type)) - return false; - } - - return true; + byte listReq = getRewardListRequirements(eventLevel); //gets all types of items present in the event reward list + + //iterating over all valid inventory types + for(byte type = 1; type <= 5; type++) { + if((listReq >> type) % 2 == 1 && !player.hasEmptySlot(type)) + return false; + } + + return true; } public final boolean giveEventReward(MapleCharacter player) { - return giveEventReward(player, 1); + return giveEventReward(player, 1); } //gives out EXP & a random item in a similar fashion of when clearing KPQ, LPQ, etc. public final boolean giveEventReward(MapleCharacter player, int eventLevel) { - eventLevel--; //event level starts counting from 1 - if(eventLevel >= collectionSet.size()) return true; - - List rewardsSet = collectionSet.get(eventLevel); - List rewardsQty = collectionQty.get(eventLevel); - - Integer rewardExp = collectionExp.get(eventLevel); - if(rewardExp == null) rewardExp = 0; - - if(rewardsSet == null || rewardsSet.isEmpty()) { - if(rewardExp > 0) player.gainExp(rewardExp); - return true; - } - - if(!hasRewardSlot(player, eventLevel)) return false; + rL.lock(); + try { + eventLevel--; //event level starts counting from 1 + if(eventLevel >= collectionSet.size()) return true; - AbstractPlayerInteraction api = new AbstractPlayerInteraction(player.getClient()); - int rnd = (int)Math.floor(Math.random() * rewardsSet.size()); - - api.gainItem(rewardsSet.get(rnd), rewardsQty.get(rnd).shortValue()); - if(rewardExp > 0) player.gainExp(rewardExp); - return true; + List rewardsSet = collectionSet.get(eventLevel); + List rewardsQty = collectionQty.get(eventLevel); + + Integer rewardExp = collectionExp.get(eventLevel); + if(rewardExp == null) rewardExp = 0; + + if(rewardsSet == null || rewardsSet.isEmpty()) { + if(rewardExp > 0) player.gainExp(rewardExp); + return true; + } + + if(!hasRewardSlot(player, eventLevel)) return false; + + AbstractPlayerInteraction api = new AbstractPlayerInteraction(player.getClient()); + int rnd = (int)Math.floor(Math.random() * rewardsSet.size()); + + api.gainItem(rewardsSet.get(rnd), rewardsQty.get(rnd).shortValue()); + if(rewardExp > 0) player.gainExp(rewardExp); + return true; + } finally { + rL.unlock(); + } + } + + public final void setEventCleared() { + eventCleared = true; + } + + public final boolean isEventTeamLackingNow(boolean testLeader, int minPlayers, MapleCharacter quitter) { + if(eventCleared && getPlayerCount() > 1) return false; + + if(!eventCleared && testLeader && getLeader().getId() == quitter.getId()) return true; + if(getPlayerCount() <= minPlayers) return true; + + return false; } public final boolean isEventTeamTogether() { - if(chars.size() <= 1) return true; - - int mapId = chars.get(0).getMapId(); - for(int i = 1; i < chars.size(); i++) { - if(chars.get(i).getMapId() != mapId) return false; - } - - return true; + rL.lock(); + try { + if(chars.size() <= 1) return true; + + int mapId = chars.get(0).getMapId(); + for(int i = 1; i < chars.size(); i++) { + if(chars.get(i).getMapId() != mapId) return false; + } + + return true; + } finally { + rL.unlock(); + } } public final void warpEventTeam(int warpTo) { - for (MapleCharacter chr : chars) { - chr.changeMap(warpTo); - } + rL.lock(); + try { + for (MapleCharacter chr : chars) { + chr.changeMap(warpTo); + } + } finally { + rL.unlock(); + } + } + + public final MapleCharacter getLeader() { + rL.lock(); + try { + for (MapleCharacter chr : chars) { + if(chr.isPartyLeader()) return chr; + } + + return null; + } finally { + rL.unlock(); + } + } + + public final void showWrongEffect() { + MapleMap map = getMapInstance(getLeader().getMapId()); + map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/wrong_kor")); + map.broadcastMessage(MaplePacketCreator.playSound("Party1/Failed")); + } + + public final void showClearEffect() { + showClearEffect(false); + } + + public final void showClearEffect(boolean hasGate) { + MapleMap map = getMapInstance(getLeader().getMapId()); + map.broadcastMessage(MaplePacketCreator.showEffect("quest/party/clear")); + map.broadcastMessage(MaplePacketCreator.playSound("Party1/Clear")); + if(hasGate) { + map.broadcastMessage(MaplePacketCreator.environmentChange("gate", 2)); + wL.lock(); + try { + openedGates.add(map.getId()); + } finally { + wL.unlock(); + } + } + } + + public final void recoverOpenedGate(MapleCharacter chr, int thisMapId) { + rL.lock(); + try { + if(openedGates.contains(thisMapId)) { + chr.announce(MaplePacketCreator.environmentChange("gate", 2)); + } + } finally { + rL.unlock(); + } + } + + public final void linkToNextStage(int thisStage, String eventFamily, int thisMapId) { + List list = getClearStageBonus(thisStage); // will give bonus exp & mesos to everyone in the event + giveEventPlayersExp(list.get(0)); + giveEventPlayersMeso(list.get(1)); + + thisStage--; //stages counts from ONE, scripts from ZERO + + MapleMap nextStage = getMapInstance(thisMapId); + MaplePortal portal = nextStage.getPortal("next00"); + if (portal != null) { + portal.setScriptName(eventFamily + thisStage); + } + } + + // registers a player status in an event + public final void gridInsert(MapleCharacter chr, int newStatus) { + wL.lock(); + try { + playerGrid.put(chr.getId(), newStatus); + } finally { + wL.unlock(); + } + } + + // unregisters a player status in an event + public final void gridRemove(MapleCharacter chr) { + wL.lock(); + try { + playerGrid.remove(chr.getId()); + } finally { + wL.unlock(); + } + } + + // checks a player status + public final int gridCheck(MapleCharacter chr) { + rL.lock(); + try { + Integer i = playerGrid.get(chr.getId()); + return (i != null) ? i : -1; + } finally { + rL.unlock(); + } + } + + public final void gridClear() { + wL.lock(); + try { + playerGrid.clear(); + } finally { + wL.unlock(); + } } } diff --git a/src/scripting/event/EventManager.java b/src/scripting/event/EventManager.java index 44cefb7ea8..9c571e61b8 100644 --- a/src/scripting/event/EventManager.java +++ b/src/scripting/event/EventManager.java @@ -154,56 +154,76 @@ public class EventManager { } //Expedition method: starts an expedition - public void startInstance(MapleExpedition exped) { + public boolean startInstance(MapleExpedition exped) { try { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null)); + if(eim == null) return false; + eim.registerExpedition(exped); exped.start(); } catch (ScriptException | NoSuchMethodException ex) { Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex); } + + return true; } //Regular method: player - public void startInstance(MapleCharacter chr) { + public boolean startInstance(MapleCharacter chr) { try { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null)); + if(eim == null) return false; + eim.registerPlayer(chr); } catch (ScriptException | NoSuchMethodException ex) { Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex); } + + return true; } //PQ method: starts a PQ - public void startInstance(MapleParty party, MapleMap map) { + public boolean startInstance(MapleParty party, MapleMap map) { try { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null)); + if(eim == null) return false; + eim.registerParty(party, map); party.setEligibleMembers(null); } catch (ScriptException | NoSuchMethodException ex) { Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex); } + + return true; } //PQ method: starts a PQ with a difficulty level, requires function setup(difficulty, leaderid) instead of setup() - public void startInstance(MapleParty party, MapleMap map, int difficulty) { + public boolean startInstance(MapleParty party, MapleMap map, int difficulty) { try { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, party.getLeader().getId())); + if(eim == null) return false; + eim.registerParty(party, map); party.setEligibleMembers(null); } catch (ScriptException | NoSuchMethodException ex) { Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex); } + + return true; } //non-PQ method for starting instance - public void startInstance(EventInstanceManager eim, String leader) { + public boolean startInstance(EventInstanceManager eim, String leader) { try { + if(eim == null) return false; + iv.invokeFunction("setup", eim); eim.setProperty("leader", leader); } catch (ScriptException | NoSuchMethodException ex) { Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex); } + + return true; } public List getEligibleParty(MapleParty party) { @@ -225,6 +245,14 @@ public class EventManager { return(new ArrayList<>()); } + public void clearPQ(EventInstanceManager eim) { + try { + iv.invokeFunction("clearPQ", eim); + } catch (ScriptException | NoSuchMethodException ex) { + Logger.getLogger(EventManager.class.getName()).log(Level.SEVERE, null, ex); + } + } + public void clearPQ(EventInstanceManager eim, MapleMap toMap) { try { iv.invokeFunction("clearPQ", eim, toMap); diff --git a/src/scripting/npc/NPCConversationManager.java b/src/scripting/npc/NPCConversationManager.java index 7cd14e1e58..b627ab138f 100644 --- a/src/scripting/npc/NPCConversationManager.java +++ b/src/scripting/npc/NPCConversationManager.java @@ -227,7 +227,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction { if (gain > 0 && ServerConstants.USE_AUTOBAN == true) { FilePrinter.printError(FilePrinter.EXPLOITS + c.getPlayer().getName() + ".txt", c.getPlayer().getName() + " gained " + gain + " mesos from NPC " + npc + "\r\n"); } - getPlayer().gainMeso(gain, true, false, true); + getPlayer().gainMeso(gain); } public void gainExp(int gain) { diff --git a/src/server/quest/MapleQuest.java b/src/server/quest/MapleQuest.java index f369f78674..7fa1e2021d 100644 --- a/src/server/quest/MapleQuest.java +++ b/src/server/quest/MapleQuest.java @@ -90,8 +90,8 @@ public class MapleQuest { MapleQuestRequirement req = this.getRequirement(type, startReq); - if(req == null) - continue; + if(req == null) + continue; if (type.equals(MapleQuestRequirementType.MOB)) { for (MapleData mob : startReq.getChildren()) { @@ -161,15 +161,46 @@ public class MapleQuest { public static MapleQuest getInstance(int id) { MapleQuest ret = quests.get(id); if (ret == null) { - questInfo = questData.getData("QuestInfo.img"); - questReq = questData.getData("Check.img"); - questAct = questData.getData("Act.img"); + questInfo = questData.getData("QuestInfo.img"); + questReq = questData.getData("Check.img"); + questAct = questData.getData("Act.img"); ret = new MapleQuest(id); quests.put(id, ret); } return ret; } + + private String getIntervalTimeLeft(MapleCharacter c, IntervalRequirement r) { + StringBuilder str = new StringBuilder(); + + long futureTime = c.getQuest(MapleQuest.getInstance(getId())).getCompletionTime() + r.getInterval(); + long leftTime = futureTime - System.currentTimeMillis(); + + byte mode = 0; + if(leftTime / (60*1000) > 0) { + mode++; //counts minutes + + if(leftTime / (60*60*1000) > 0) + mode++; //counts hours + } + + switch(mode) { + case 2: + int hours = (int) ((leftTime / (1000*60*60))); + str.append(hours + " hours, "); + + case 1: + int minutes = (int) ((leftTime / (1000*60)) % 60); + str.append(minutes + " minutes, "); + + default: + int seconds = (int) (leftTime / 1000) % 60 ; + str.append(seconds + " seconds"); + } + + return str.toString(); + } public boolean canStart(MapleCharacter c, int npcid) { if (c.getQuest(this).getStatus() != Status.NOT_STARTED && !(c.getQuest(this).getStatus() == Status.COMPLETED && repeatable)) { @@ -177,6 +208,9 @@ public class MapleQuest { } for (MapleQuestRequirement r : startReqs.values()) { if (!r.check(c, npcid)) { + if(r.getType().getType() == MapleQuestRequirementType.INTERVAL.getType()) { + c.message("This quest will become available again in approximately " + getIntervalTimeLeft(c, (IntervalRequirement)r) + "."); + } return false; } } @@ -198,9 +232,9 @@ public class MapleQuest { public void start(MapleCharacter c, int npc) { if (autoStart || canStart(c, npc)) { for (MapleQuestAction a : startActs.values()) { - if (!a.check(c, null)) { // would null be good ? - return; - } + if (!a.check(c, null)) { // would null be good ? + return; + } a.run(c, null); } forceStart(c, npc); @@ -212,20 +246,20 @@ public class MapleQuest { } public void complete(MapleCharacter c, int npc, Integer selection) { - if (autoPreComplete || canComplete(c, npc)) { - for (MapleQuestAction a : completeActs.values()) { - if (!a.check(c, selection)) { - return; - } - } - forceComplete(c, npc); - for (MapleQuestAction a : completeActs.values()) { - a.run(c, selection); - } - - c.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); // Quest completion - c.getMap().broadcastMessage(c, MaplePacketCreator.showForeignEffect(c.getId(), 9), false); //use 9 instead of 12 for both - } + if (autoPreComplete || canComplete(c, npc)) { + for (MapleQuestAction a : completeActs.values()) { + if (!a.check(c, selection)) { + return; + } + } + forceComplete(c, npc); + for (MapleQuestAction a : completeActs.values()) { + a.run(c, selection); + } + + c.getClient().getSession().write(MaplePacketCreator.showSpecialEffect(9)); // Quest completion + c.getMap().broadcastMessage(c, MaplePacketCreator.showForeignEffect(c.getId(), 9), false); //use 9 instead of 12 for both + } } public void reset(MapleCharacter c) { @@ -314,9 +348,9 @@ public class MapleQuest { return ret; } - public int getTimeLimit() { - return timeLimit; - } + public int getTimeLimit() { + return timeLimit; + } public static void clearCache(int quest) { if(quests.containsKey(quest)){ diff --git a/src/server/quest/requirements/IntervalRequirement.java b/src/server/quest/requirements/IntervalRequirement.java index f37037690c..76d0645a25 100644 --- a/src/server/quest/requirements/IntervalRequirement.java +++ b/src/server/quest/requirements/IntervalRequirement.java @@ -42,6 +42,9 @@ public class IntervalRequirement extends MapleQuestRequirement { questID = quest.getId(); } + public int getInterval() { + return interval; + } @Override public void processData(MapleData data) { diff --git a/src/server/quest/requirements/MapleQuestRequirement.java b/src/server/quest/requirements/MapleQuestRequirement.java index 1e052498a2..908544ad89 100644 --- a/src/server/quest/requirements/MapleQuestRequirement.java +++ b/src/server/quest/requirements/MapleQuestRequirement.java @@ -51,6 +51,6 @@ public abstract class MapleQuestRequirement { public abstract void processData(MapleData data); public MapleQuestRequirementType getType() { - return type; - } + return type; + } } \ No newline at end of file diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index 53f12a7d9d..b8c6f19fba 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -2508,6 +2508,7 @@ public class MaplePacketCreator { * @param progress * @return */ + public static byte[] updateQuestInfo(short quest, int npc) { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.UPDATE_QUEST_INFO.getValue());