Guild PQ + fixed negative EXP error

Implemented Guild PQ. Fixed a problem introduced earlier where negative
EXP would be deemed as "integer overflow", provoking many game breaking
issues as result.
This commit is contained in:
ronancpl
2017-06-18 03:19:53 -03:00
parent 81f9226286
commit 42fe74955d
135 changed files with 822 additions and 564 deletions

View File

@@ -1,4 +1,4 @@
#Tue, 13 Jun 2017 20:04:33 -0300
#Sun, 18 Jun 2017 02:53:19 -0300
C\:\\Nexon\\MapleSolaxia\\MapleSolaxiaV2=

BIN
dist/MapleSolaxia.jar vendored

Binary file not shown.

View File

@@ -4,22 +4,27 @@ Ronan - Freelance Developer
Vcoc - Freelance Developer
---------------------------
Working features:
Feature list:
---------------------------
PQs/Quests:
* HPQ/KPQ/LPQ/LMPQ/OPQ/EllinPQ/PiratePQ 100%
* BalrogPQ semi-functional
* GuildPQ 100% + Guild queue and multi-lobby systems available.
* Brand-new PQ: Boss Rush PQ 100%
* BalrogPQ semi-functional
* Doll house quest 100%
* Loads of quests have been patched.
Player Social Network:
* Guild and Alliance system.
* Lobby system - Limited multiple PQ instances on same channel.
* Guild and Alliance system fully functional.
Cash:
* EXP/DROP/Cosmetic Coupons 100%
* Great deal of cash items functional.
PQ potentials:
* Lobby system - Limited multiple PQ instances on same channel.
* Guild queue system - Guilds can register themselves on a queue for GPQ.
Server potentials:
* Multi-worlds 100%

View File

@@ -292,25 +292,32 @@ Diversos ajustes finos nos comandos existentes.
Adicionados novos comandos: proitem, seteqstats, buffme, buffmap.
Vários ajustes finos em alguns comandos.
05 Junho 2016,
05 Junho 2017,
Novo NPC Skillbook announcer: Abdula.
Consertada a função que retorna se uma skill pertence ou não à árvore de habilidades do jogador.
06 Junho 2016,
06 Junho 2017,
Corrigido command empowerme.
Corrigidos exploits relacionados a algumas das skills do empowerme.
Corrigido possivel loop infinito no sistema de EXP.
07 - 10 Junho 2016,
07 - 10 Junho 2017,
Implementação da OPQ.
11 Junho 2016,
11 Junho 2017,
Correção de alguns bugs vindos com o commit da OPQ.
Incrementada a documentação referente aos métodos usados nos scripts de eventos.
12 Junho 2016,
12 Junho 2017,
Correção de falha em criação de guilds, não atribuindo corretamente o título de mestre da guild ao criador.
13 Junho 2016,
13 Junho 2017,
Mudança nas mecânicas de busca por portais ao transportar cada jogador: quando não for definido, escolhe-se um spawn point aleatoriamente.
Implementação de fila de espera para Guilds na GPQ (funciona em harmonia com o sistema de lobbys).
Implementação de fila de espera para Guilds na GPQ (funciona em harmonia com o sistema de lobbys).
14 Junho 2017,
Correção de bug envolvendo abuso de conversa com NPC logo após o sinal de dispose, ocasionando frequentemente crashes no cliente.
15 - 17 Junho 2017,
Correção de bug na função de atribuição de EXP, que não permitia receber valores negativos de EXP.
Implementação da GPQ.

View File

@@ -13,13 +13,14 @@
<open-files xmlns="http://www.netbeans.org/ns/projectui-open-files/2">
<group>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/GuildQuest.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/event/CWKPQ.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/9040000.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/AbstractPlayerInteraction.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/2040034.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/9040009.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/handlers/ChangeMapHandler.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/9040006.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/reactor/2006001.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/reactor/9208009.js</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/constants/ServerConstants.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/client/MapleCharacter.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/scripting/event/EventManager.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/src/net/server/channel/Channel.java</file>
<file>file:/C:/Nexon/MapleSolaxia/MapleSolaxiaV2/scripts/npc/9040001.js</file>
</group>
</open-files>
</project-private>

View File

@@ -10,7 +10,7 @@ var clearMap; // Upon event clearing, players may be moved to
var minMapId; // Event takes place inside these map id interval. Players found out is instantly dropped from the event.
var maxMapId;
var eventTime; // Max time alloted for the event, in minutes.
var eventTime; // Max time allotted for the event, in minutes.
var lobbyRange = [0, 0]; // Range of concurrent lobbies (min range is 0, max range is 7).

View File

@@ -96,7 +96,7 @@ function setup(level, lobbyid) {
function afterSetup(eim) {}
function respawnStg2(eim) {
if(!eim.getMapInstance(930000200).getAllPlayer().isEmpty()) eim.getMapInstance(930000200).instanceMapRespawn();
if(!eim.getMapInstance(930000200).getPlayers().isEmpty()) eim.getMapInstance(930000200).instanceMapRespawn();
eim.schedule("respawnStg2", 4 * 1000);
}

View File

@@ -30,13 +30,14 @@ var minLevel = 1, maxLevel = 200;
var entryMap = 990000000;
var exitMap = 990001100;
var recruitMap = 101030104;
var clearMap = 990001101;
var clearMap = 990001000;
var minMapId = 990000000;
var maxMapId = 990001101;
var waitTime = 3;
var waitTime = 3; // 3 minutes
var eventTime = 90; // 90 minutes
var bonusTime = 0.5; // 30 seconds
var lobbyRange = [0, 0];
@@ -119,7 +120,7 @@ function setup(level, lobbyid) {
eim.setProperty("guild", 0);
eim.setProperty("canJoin", 1);
eim.setProperty("statusStg1", -1);
eim.setProperty("canRevive", 0);
eim.getInstanceMap(990000000).resetPQ(level);
eim.getInstanceMap(990000100).resetPQ(level);
@@ -175,7 +176,9 @@ function isTeamAllJobs(eim) {
*/
function afterSetup(eim) {
eim.setProperty("guild", "" + eim.getLeader().getGuildId());
var leader = em.getChannelServer().getPlayerStorage().getCharacterById(eim.getLeaderId());
if(leader != null)
eim.setProperty("guild", "" + leader.getGuildId());
}
function respawnStages(eim) {}
@@ -189,16 +192,20 @@ function playerEntry(eim, player) {
}
function scheduledTimeout(eim) {
if(eim.getIntProperty("canJoin") == 1) {
eim.setProperty("canJoin", 0);
if(eim.checkEventTeamLacking(true, minPlayers)) {
end(eim);
} else {
eim.startEventTimer(eventTime * 60000);
}
if(eim.isEventCleared()) {
eim.warpEventTeam(990001100);
} else {
end(eim);
if(eim.getIntProperty("canJoin") == 1) {
eim.setProperty("canJoin", 0);
if(eim.checkEventTeamLacking(true, minPlayers)) {
end(eim);
} else {
eim.startEventTimer(eventTime * 60000);
}
} else {
end(eim);
}
}
}
@@ -222,15 +229,33 @@ function changedMap(eim, player, mapid) {
function changedLeader(eim, leader) {}
function playerDead(eim, player) {}
function playerDead(eim, player) {
if(player.getMapId() == 990000900) {
if(player.getMap().countAlivePlayers() == 0 && player.getMap().countMonsters() > 0) {
end(eim);
}
}
}
function playerRevive(eim, player) { // player presses ok on the death pop up.
if (eim.isEventTeamLackingNow(true, minPlayers, player) && eim.getIntProperty("canJoin") == 0) {
eim.unregisterPlayer(player);
end(eim);
if(eim.getIntProperty("canRevive") == 0) {
if (eim.isEventTeamLackingNow(true, minPlayers, player) && eim.getIntProperty("canJoin") == 0) {
eim.unregisterPlayer(player);
player.setHp(50);
player.changeMap(exitMap);
end(eim);
}
else {
eim.unregisterPlayer(player);
player.setHp(50);
player.changeMap(exitMap);
}
return false;
}
else
eim.unregisterPlayer(player);
return true;
}
function playerDisconnected(eim, player) {
@@ -267,6 +292,9 @@ function giveRandomEventReward(eim, player) {
function clearPQ(eim) {
eim.stopEventTimer();
eim.setEventCleared();
eim.warpEventTeam(clearMap);
eim.startEventTimer(bonusTime * 60000);
}
function monsterKilled(mob, eim) {}

View File

@@ -147,12 +147,12 @@ function action(mode, type, selection) {
var players = Array();
var total = 0;
for (var i = 0; i < 3; i++) {
var z = cm.getMap().getNumPlayersItemsInArea(i);
var z = cm.getMap().getNumPlayersInArea(i);
players.push(z);
total += z;
}
if (total != 3) {
cm.sendOk("There needs to be 3 players OR items on the platforms.");
cm.sendOk("There needs to be exactly 3 players on these platforms.");
} else {
var num_correct = 0;
for (var i = 0; i < 3; i++) {

View File

@@ -45,7 +45,7 @@ function action(mode, type, selection) {
var eim = cm.getEventInstance();
if(!eim.giveEventReward(cm.getPlayer())) {
cm.sendNext("It seems you don't have a free slot in either your #rEquip#k, #rUse#k or #rEtc#k inventories. Please make room and try again.");
cm.sendNext("It seems you don't have a free slot in either your #rEquip#k, #rUse#k or #rEtc#k inventories. Please make some room and try again.");
} else {
cm.warp(221024500);
}

View File

@@ -68,7 +68,7 @@ function action(mode, type, selection) {
cm.sendNext("A stimulator is a special potion that I can add into the process of creating certain items. It gives it stats as though it had dropped from a monster. However, it is possible to have no change, and it is also possible for the item to be below average. There's also a 10% chance of not getting any item when using a stimulator, so please choose wisely.")
cm.dispose();
} else if (selectedType == 1){ //warrior weapon
var selStr = "Very well, then which Warrior weapon shall recieve a dragon's power?#b";
var selStr = "Very well, then which Warrior weapon shall receive a dragon's power?#b";
var weapon = new Array ("Dragon Carbella#k - Lv. 110 One-Handed Sword#b","Dragon Axe#k - Lv. 110 One-Handed Axe#b","Dragon Mace#k - Lv. 110 One-Handed BW#b","Dragon Claymore#k - Lv. 110 Two-Handed Sword#b","Dragon Battle Axe#k - Lv. 110 Two-Handed Axe#b","Dragon Flame#k - Lv. 110 Two-Handed BW#b",
"Dragon Faltizan#k - Lv. 110 Spear#b","Dragon Chelbird#k - Lv. 110 Polearm#b");
for (var i = 0; i < weapon.length; i++){
@@ -76,28 +76,28 @@ function action(mode, type, selection) {
}
cm.sendSimple(selStr);
} else if (selectedType == 2){ //bowman weapon
var selStr = "Very well, then which Bowman weapon shall recieve a dragon's power?#b";
var selStr = "Very well, then which Bowman weapon shall receive a dragon's power?#b";
var weapon = new Array ("Dragon Shiner Bow#k - Lv. 110 Bow#b","Dragon Shiner Cross#k - Lv. 110 Crossbow#b");
for (var i = 0; i < weapon.length; i++){
selStr += "\r\n#L" + i + "# " + weapon[i] + "#l";
}
cm.sendSimple(selStr);
} else if (selectedType == 3){ //magician weapon
var selStr = "Very well, then which Magician weapon shall recieve a dragon's power?#b";
var selStr = "Very well, then which Magician weapon shall receive a dragon's power?#b";
var weapon = new Array ("Dragon Wand#k - Lv. 108 Wand#b","Dragon Staff#k - Lv. 110 Staff#b");
for (var i = 0; i < weapon.length; i++){
selStr += "\r\n#L" + i + "# " + weapon[i] + "#l";
}
cm.sendSimple(selStr);
} else if (selectedType == 4){ //thief weapon
var selStr = "Very well, then which Thief weapon shall recieve a dragon's power?#b";
var selStr = "Very well, then which Thief weapon shall receive a dragon's power?#b";
var weapon = new Array ("Dragon Kanzir#k - Lv. 110 STR Dagger#b","Dragon Kreda#k - Lv. 110 LUK Dagger#b","Dragon Green Sleve#k - Lv. 110 Claw#b");
for (var i = 0; i < weapon.length; i++){
selStr += "\r\n#L" + i + "# " + weapon[i] + "#l";
}
cm.sendSimple(selStr);
} else if (selectedType == 5){ //pirate weapon
var selStr = "Very well, then which Pirate weapon shall recieve a dragon's power?#b";
var selStr = "Very well, then which Pirate weapon shall receive a dragon's power?#b";
var weapon = new Array ("Dragon Slash Claw#k - Lv. 110 Knuckle#b","Dragonfire Revolver#k - Lv. 110 Gun#b");
for (var i = 0; i < weapon.length; i++){
selStr += "\r\n#L" + i + "# " + weapon[i] + "#l";

View File

@@ -68,7 +68,7 @@ function action(mode, type, selection) {
if(cm.getPlayer().getGuildId() > 0) {
var eim = findLobby(cm.getPlayer().getGuildId());
if(eim == null) {
cm.sendOk("You don't have a guild registered and currently on strategy time to assist on this channel.");
cm.sendOk("Your guild is not currently on strategy time on this channel. Check again if your guild is currently planning a Guild Quest or, if so, the channel they are allotted on.");
} else {
if(cm.isLeader()) {
em.getEligibleParty(cm.getParty());
@@ -83,16 +83,22 @@ function action(mode, type, selection) {
cm.dispose();
} else {
cm.sendOk("#e#b<Guild Quest: Sharenian Ruins>#k#n\r\n Team up with your guild members in an auspicious attempt to recover the Rubian from the skeleton's grasp, with teamwork overcoming many puzzles and challenges awaiting inside the Sharenian tombs. Great rewards can be obtained upon the instance completion, and Guild Points can be racked up for your Guild.");
var reqStr = "";
reqStr += "\r\n\r\n Team requirements:\r\n\r\n";
reqStr += " - 1 team member #rbelow or equal level 30#k.\r\n";
reqStr += " - 1 team member who is a #rThief with Dark Sight#k skill and #rmaxed Haste#k.\r\n";
reqStr += " - 1 team member who is a Magician with #rmaxed Teleport#k.\r\n";
reqStr += " - 1 team member who is a #rlong ranged attacker#k like Bowman, Assassin, or Gunslinger.\r\n";
reqStr += " - 1 team member with #rgood jumping skills#k like Assassin with maxed Flash Jump or Gunslinger with Wings.\r\n";
cm.sendOk("#e#b<Guild Quest: Sharenian Ruins>#k#n\r\n Team up with your guild members in an auspicious attempt to recover the Rubian from the skeleton's grasp, with teamwork overcoming many puzzles and challenges awaiting inside the Sharenian tombs. Great rewards can be obtained upon the instance completion, and Guild Points can be racked up for your Guild." + reqStr);
cm.dispose();
}
} else if (status == 2) {
if (sel == 0) {
var entry = em.addGuildToQueue(cm.getPlayer().getGuildId(), cm.getPlayer().getId());
if(entry > 0) {
if(entry == 1) {
cm.sendOk("Your guild has been registered successfully. A message will pop on your chat keeping your guild aware about the registration status. Now, #rimportant#k: as the leader of this instance, #ryou must already be present on this channel#k the right moment your guild is called for the strategy time. #bThe missubmission of this action will void#k your guild registration as a whole, and the next guild will be called immediately. Must be noted also, that if you become absent from the end of the strategy time to any point on the duration of the instance, it will render the instance interrupted, and your guild will be moved out instantly, moving again the queue.");
}
cm.sendOk("Your guild has been registered successfully. A message will pop on your chat keeping your guild aware about the registration status.\r\n\r\nNow, #rimportant#k: as the leader of this instance, #ryou must already be present on this channel#k the right moment your guild is called for the strategy time. #bThe missubmission of this action will void#k your guild registration as a whole, and the next guild will be called immediately. Must be noted also, that if you become absent from the end of the strategy time to any point on the duration of the instance, it will render the instance interrupted, and your guild will be moved out instantly, moving again the queue.");
} else if(entry == 0) {
cm.sendOk("The queue on this channel is already full. Please be patient and try again after a while, or try on another channel.");
} else {

View File

@@ -19,20 +19,48 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
@ Author : Ronan
@
@ NPC = Nuris (9040001)
@ Map = Sharenian - Returning Path
@ NPC MapId = 990001100
@ NPC Exit-MapId = 101030104
@
*/
/*
* @Author Lerk
*
* Nuris, Sharenian: Returning Path (990001100)
*
* Exit of Guild Quest
*/
var GQItems = new Array(1032033, 4001024, 4001025, 4001026, 4001027, 4001028, 4001029, 4001030, 4001031, 4001032, 4001033, 4001034, 4001035, 4001037);
var status;
function start() {
for (var i = 0; i < GQItems.length; i++)
cm.removeAll(GQItems[i]);
cm.warp(101030104);
cm.dispose();
status = -1;
action(1,0,0);
}
function action(mode, type, selection){
if (mode == 1)
status++;
else {
cm.dispose();
return;
}
if (status == 0) {
var outText = "It seems you have finished exploring Sharenian Keep, yes? Are you going to return to the recruitment map now?";
cm.sendYesNo(outText);
} else if (mode == 1) {
var eim = cm.getEventInstance();
if(eim != null && eim.isEventCleared()) {
if(!eim.giveEventReward(cm.getPlayer())) {
cm.sendNext("It seems you don't have a free slot in either your #rEquip#k, #rUse#k or #rEtc#k inventories. Please make some room first.");
} else {
cm.warp(101030104);
}
cm.dispose();
} else {
cm.warp(101030104);
cm.dispose();
}
}
}

View File

@@ -20,13 +20,20 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* @Author TheRamon
* @Author TheRamon, Ronan
*
* Sharen III's Soul, Sharenian: Sharen III's Grave (990000700)
*
* Guild Quest - end of stage 4
*/
function clearStage(stage, eim) {
eim.setProperty("stage" + stage + "clear", "true");
eim.showClearEffect(true);
eim.giveEventPlayersStageReward(stage);
}
var status = 0;
function start() {
status = -1;
@@ -41,39 +48,30 @@ function action(mode, type, selection) {
status++;
else
cm.dispose();
var eim = cm.getPlayer().getEventInstance();
if (eim.getProperty("stage4clear") != null && eim.getProperty("stage4clear").equals("true")) {
cm.sendOk("After what I thought would be an immortal sleep, I have finally found someone that will save Sharenian. I can truly rest in peace now.");
cm.dispose();
return;
}
if (status == 0) {
if (cm.getPlayer().getEventInstance().getProperty("leader").equals(cm.getPlayer().getName())) {
if (cm.getPlayer().getEventInstance().getProperty("stage4clear") != null && cm.getPlayer().getEventInstance().getProperty("stage4clear").equals("true"))
{
cm.sendOk("After what I thought would be an immortal sleep, I have finally found someone that will save Sharenian. I can truly rest in peace now.");
cm.dispose();
}
else {
var prev = cm.getPlayer().getEventInstance().setProperty("stage4clear","true",true);
if (prev == null) {
cm.sendNext("After what I thought would be an immortal sleep, I have finally found someone that will save Sharenian. This old man will now pave the way for you to finish the quest." + mode);
}
else {//if not null, was set before, and Gp already gained
cm.sendOk("After what I thought would be an immortal sleep, I have finally found someone that will save Sharenian. I can truly rest in peace now.");
cm.dispose();
}
}
if (cm.isEventLeader()) {
cm.sendNext("After what I thought would be an immortal sleep, I have finally found someone that will save Sharenian. This old man will now pave the way for you to finish the quest.");
clearStage(4, eim);
cm.getGuild().gainGP(30);
cm.getPlayer().getMap().getReactorByName("ghostgate").forceHitReactor(1);
cm.dispose();
}
else
{
if (cm.getPlayer().getEventInstance().getProperty("stage4clear") != null && cm.getPlayer().getEventInstance().getProperty("stage4clear").equals("true"))
cm.sendOk("After what I thought would be an immortal sleep, I have finally found someone that will save Sharenian. I can truly rest in peace now.");
else
cm.sendOk("I need the leader of your party to speak with me, nobody else.");
cm.sendOk("I need the leader of your party to speak with me, nobody else.");
cm.dispose();
}
}
else if (status == 1) {
cm.getGuild().gainGP(30);
cm.getPlayer().getMap().getReactorByName("ghostgate").hitReactor(cm.getClient());
cm.showEffect("quest/party/clear");
cm.playSound("Party1/Clear");
cm.dispose();
}
}
}

View File

@@ -25,10 +25,7 @@ function start() {
function action(mode, type, selection) {
if(mode == 1) {
var eim = cm.getPlayer().getEventInstance();
if(eim != null) {
eim.removePlayer(cm.getPlayer());
}
cm.warp(990001100);
}
cm.dispose();
}

View File

@@ -1,254 +1,209 @@
/* @Author Lerk
/* @Author Lerk, Ronan
*
* Guardian Statue - Sharenian: Fountain of the Wiseman (990000500)
*
* Guild Quest Stage 3
*/
importPackage(Packages.tools);
function clearStage(stage, eim) {
eim.setProperty("stage" + stage + "clear", "true");
eim.showClearEffect(true);
eim.giveEventPlayersStageReward(stage);
}
function start() {
//everything can be done in one status, so let's do it here.
if (cm.getPlayer().getMap().getReactorByName("watergate").getState() > 0){
cm.sendOk("Excellent work. You may proceed to the next stage.");
cm.dispose();
return;
}
var eim = cm.getPlayer().getEventInstance();
if (eim == null) {
cm.warp(990001100);
} else {
if (eim.getProperty("leader").equals(cm.getName())) {
if (cm.getPlayer().getMap().getReactorByName("watergate").getState() > 0){
cm.sendOk("You may proceed.");
} else {
var currentCombo = eim.getProperty("stage3combo");
if (currentCombo == null || currentCombo.equals("reset")) {
var newCombo = makeCombo();
eim.setProperty("stage3combo",newCombo);
//cm.playerMessage("Debug: " + newCombo);
eim.setProperty("stage3attempt","1");
cm.sendOk("This fountain guards the secret passage to the throne room. Offer items in the area to the vassals to proceed. The vassals shall tell you whether your offerings are accepted, and if not, which vassals are displeased. You have seven attempts. Good luck.")
} else {
var attempt = parseInt(eim.getProperty("stage3attempt"));
var combo = parseInt(currentCombo);
var guess = getGroundItems();
if (guess != null) {
if (combo == guess) {
cm.getPlayer().getMap().getReactorByName("watergate").hitReactor(cm.getClient());
cm.sendOk("You may proceed.");
cm.getPlayer().getMap().broadcastMessage(MaplePacketCreator.showEffect("quest/party/clear"));
cm.getPlayer().getMap().broadcastMessage(MaplePacketCreator.playSound("Party1/Clear"));
var prev = eim.getProperty("stage3clear");
eim.setProperty("stage3clear","true");
if (prev == null) {
cm.getPlayer().getGuild().gainGP(100);
}
} else {
if (attempt < 7) {
//cm.playerMessage("Combo : " + combo);
//cm.playerMessage("Guess : " + guess);
var parsedCombo = parsePattern(combo);
var parsedGuess = parsePattern(guess);
var results = compare(parsedCombo, parsedGuess);
var string = "";
//cm.playerMessage("Results - Correct: " + results[0] + " | Incorrect: " + results[1] + " | Unknown: " + results[2]);
if (results[0] != 0) {
if (results[0] == 1) {
string += "1 vassal is pleased with their offering.\r\n";
} else {
string += results[0] + " vassals are pleased with their offerings.\r\n";
}
}
if (results[1] != 0) {
if (results[1] == 1) {
string += "1 vassal has recieved an incorrect offering.\r\n";
} else {
string += results[1] + " vassals have recieved incorrect offerings.\r\n";
}
}
if (results[2] != 0) {
if (results[2] == 1) {
string += "1 vassal has recieved an unknown offering.\r\n";
} else {
string += results[2] + " vassals have recieved unknown offerings.\r\n";
}
}
string += "This is your ";
switch (attempt) {
case 1:
string += "1st";
break;
case 2:
string += "2nd";
break;
case 3:
string += "3rd";
break;
default:
string += attempt + "th";
break;
}
string += " attempt.";
if (cm.isEventLeader()) {
var currentCombo = eim.getProperty("stage3combo");
if (currentCombo == null || currentCombo.equals("reset")) {
var newCombo = makeCombo();
eim.setProperty("stage3combo",newCombo);
//cm.playerMessage("Debug: " + newCombo);
eim.setProperty("stage3attempt","1");
cm.sendOk("This fountain guards the secret passage to the throne room. Offer items in the area to the vassals to proceed. The vassals shall tell you whether your offerings are accepted, and if not, which vassals are displeased. You have seven attempts. Good luck.");
} else {
var attempt = parseInt(eim.getProperty("stage3attempt"));
var combo = parseInt(currentCombo);
var guess = getGroundItems();
if (guess != null) {
if (combo == guess) {
cm.getPlayer().getMap().getReactorByName("watergate").forceHitReactor(1);
clearStage(3, eim);
cm.getGuild().gainGP(25);
removeGroundItems();
cm.sendOk("Excellent work. You may proceed to the next stage.");
} else {
if (attempt < 7) {
var comboItems = [0, 0, 0, 0];
var guessItems = [0, 0, 0, 0];
var correct = 0, incorrect, unknown = 0;
for(var i = 0; i < 4; i++) {
var guessIdx = Math.floor(guess / Math.pow(10, i)) % 10;
var comboIdx = Math.floor(combo / Math.pow(10, i)) % 10;
if(guessIdx == comboIdx) correct++;
else {
(guessItems[guessIdx])++;
(comboItems[comboIdx])++;
}
}
for(var i = 0; i < 4; i++) {
var diff = guessItems[i] - comboItems[i];
if(diff > 0) unknown += diff;
}
incorrect = 4 - correct - unknown;
var string = "";
//cm.playerMessage("Results - Correct: " + results[0] + " | Incorrect: " + results[1] + " | Unknown: " + results[2]);
if (correct != 0) {
if (correct == 1) {
string += "1 vassal is pleased with their offering.\r\n";
} else {
string += correct + " vassals are pleased with their offerings.\r\n";
}
}
if (incorrect != 0) {
if (incorrect == 1) {
string += "1 vassal has received an incorrect offering.\r\n";
} else {
string += incorrect + " vassals have received incorrect offerings.\r\n";
}
}
if (unknown != 0) {
if (unknown == 1) {
string += "1 vassal has received an unknown offering.\r\n";
} else {
string += unknown + " vassals have received unknown offerings.\r\n";
}
}
string += "This is your ";
switch (attempt) {
case 1:
string += "1st";
break;
case 2:
string += "2nd";
break;
case 3:
string += "3rd";
break;
default:
string += attempt + "th";
break;
}
string += " attempt.";
//spawn one black and one myst knight
spawnMob(9300036, -350, 150, cm.getPlayer().getMap());
spawnMob(9300037, 400, 150, cm.getPlayer().getMap());
//spawn one black and one myst knight
spawnMob(9300036, -350, 150, cm.getPlayer().getMap());
spawnMob(9300037, 400, 150, cm.getPlayer().getMap());
cm.sendOk(string);
eim.setProperty("stage3attempt",attempt + 1);
} else {
//reset the combo and mass spawn monsters
eim.setProperty("stage3combo","reset");
cm.sendOk("You have failed the test. Please compose yourselves and try again later.");
cm.sendOk(string);
eim.setProperty("stage3attempt",attempt + 1);
} else {
//reset the combo and mass spawn monsters
eim.setProperty("stage3combo","reset");
cm.sendOk("You have failed the test. Please compose yourselves and try again later.");
for (var i = 0; i < 6; i++) {
//keep getting new monsters, lest we spawn the same monster five times o.o!
spawnMob(9300036, randX(), 150, cm.getPlayer().getMap());
spawnMob(9300037, randX(), 150, cm.getPlayer().getMap());
}
}
}
} else {
cm.sendOk("Please make sure your attempt is properly set in front of the vassals and talk to me again.");
}
}
}
} else {
cm.sendOk("Please have your leader speak to me.");
}
for (var i = 0; i < 6; i++) {
//keep getting new monsters, lest we spawn the same monster five times o.o!
spawnMob(9300036, randX(), 150, cm.getPlayer().getMap());
spawnMob(9300037, randX(), 150, cm.getPlayer().getMap());
}
}
eim.showWrongEffect();
}
} else {
cm.sendOk("Please make sure your attempt is properly set in front of the vassals and talk to me again.");
}
}
} else {
cm.sendOk("Please have your leader speak to me.");
}
}
cm.dispose();
}
function action(mode, type, selection) {
}
function action(mode, type, selection) {}
function makeCombo() {
var combo = 0;
for (var i = 0; i < 4; i++) {
combo += Math.floor(Math.random() * 4) * Math.pow(10, i);
combo += (Math.floor(Math.random() * 4) * Math.pow(10, i));
}
return combo;
}
//check the items on ground and convert into an applicable string; null if items aren't proper
function getGroundItems() {
var items = cm.getPlayer().getMap().getMapObjectsInRange(cm.getPlayer().getPosition(), Packages.java.lang.Double.POSITIVE_INFINITY, Packages.java.util.Arrays.asList([Packages.server.maps.MapleMapObjectType.ITEM]));
var itemInArea = new Array(-1, -1, -1, -1);
if (items.size() != 4) {
cm.getPlayer().dropMessage("There are too many items in the map. Please remove some");
return null;
}
var iter = items.iterator();
function getRawItems() {
var mapItems = cm.getPlayer().getMap().getItems();
var rawItems = new Array();
var iter = mapItems.iterator();
while (iter.hasNext()) {
var item = iter.next();
var id = item.getItem().getItemId();
if (id < 4001027 || id > 4001030) {
cm.getPlayer().dropMessage("Some items in the map are not part of the 4 items needed");
return null;
continue;
} else {
//check item location
for (var i = 0; i < 4; i++) {
if (cm.getPlayer().getMap().getArea(i).contains(item.getPosition())) {
itemInArea[i] = id - 4001027;
//cm.getPlayer().dropMessage("Item in area "+i+": " + id);
break;
}
}
rawItems.push(item);
}
}
return rawItems;
}
//check the items on ground and convert into an applicable string; null if items aren't proper
function getGroundItems() {
var itemInArea = new Array(-1, -1, -1, -1);
var rawItems = getRawItems();
if (rawItems.length != 4) return null;
for(var j = 0; j < rawItems.length; j++) {
var item = rawItems[j];
var id = item.getItem().getItemId();
//check item location
for (var i = 0; i < 4; i++) {
if (cm.getPlayer().getMap().getArea(i).contains(item.getPosition())) {
itemInArea[i] = id - 4001027;
break;
}
}
}
//guaranteed four items that are part of the stage 3 item set by this point, check to see if each area has an item
if (itemInArea[0] == -1 || itemInArea[1] == -1 || itemInArea[2] == -1 || itemInArea[3] == -1) {
cm.getPlayer().dropMessage("Please place these in correct positions: " + (itemInArea[0] == -1 ? "Statue 1, " : "") + (itemInArea[1] == -1 ? "Statue 2, " : "") + (itemInArea[2] == -1 ? "Statue 3, " : "") + (itemInArea[3] == -1 ? "Statue 4. " : ""));
/* for (var i = 0; i < 4; i++) {
cm.getPlayer().dropMessage("Item in area "+i+": " + itemInArea[i]);
}*/
if (itemInArea[0] == -1 || itemInArea[1] == -1 || itemInArea[2] == -1 || itemInArea[3] == -1)
return null;
}
return (itemInArea[0] * 1000 + itemInArea[1] * 100 + itemInArea[2] * 10 + itemInArea[3]);
return ((itemInArea[0] * 1000) + (itemInArea[1] * 100) + (itemInArea[2] * 10) + itemInArea[3]);
}
//convert an integer for answer or guess into int array for comparison
function parsePattern(pattern) {
var tempPattern = pattern;
var items = new Array(-1, -1, -1, -1);
for (var i = 0; i < 4; i++) {
items[i] = Math.floor(tempPattern / Math.pow(10, 3-i));
tempPattern = tempPattern % Math.pow(10, 3-i);
function removeGroundItems() {
var map = cm.getMap();
var rawItems = getRawItems();
for(var j = 0; j < rawItems.length; j++) {
map.makeDisappearItemFromMap(rawItems[j]);
}
return items;
}
// compare two int arrays for the puzzle
function compare(answer, guess) {
var correct = 0;
var incorrect = 0;
/*var debugAnswer = "Combo : ";
var debugGuess = "Guess : ";
for (var d = 0; d < answer.length; d++) {
debugAnswer += answer[d] + " ";
debugGuess += guess[d] + " ";
}
cm.getPlayer().dropMessage(debugAnswer);
cm.getPlayer().dropMessage(debugGuess);*/
for (var i = 0; i < answer.length; i) {
if (answer[i] == guess[i]) {
correct++;
//cm.getPlayer().dropMessage("Item match : " + answer[i]);
//pop the answer/guess at i
if (i != answer.length - 1) {
answer[i] = answer[answer.length - 1];
guess[i] = guess[guess.length - 1];
}
answer.pop();
guess.pop();
/*/debugAnswer = "Combo : ";
debugGuess = "Guess : ";
for (var d = 0; d < answer.length; d++) {
debugAnswer += answer[d] + " ";
debugGuess += guess[d] + " ";
}
cm.getPlayer().dropMessage(debugAnswer);
cm.getPlayer().dropMessage(debugGuess);*/
}
else {
i++;
}
}
//check remaining answers for "incorrect": correct item in incorrect position
var answerItems = new Array(0, 0, 0, 0);
var guessItems = new Array(0, 0, 0, 0);
for (var j = 0; j < answer.length; j++) {
var aItem = answer[j];
var gItem = guess[j]
answerItems[aItem]++;
guessItems[gItem]++;
}
/*for (var d = 0; d < answer.length; d++) {
cm.getPlayer().dropMessage("Item " + d + " in combo: " + answerItems[d] + " | in guess: " + guessItems[d]);
}*/
for (var k = 0; k < answerItems.length; k++) {
var inc = Math.min(answerItems[k], guessItems[k]);
//cm.getPlayer().dropMessage("Incorrect for item " + k + ": " + inc);
incorrect += inc;
}
return new Array(correct, incorrect, (4 - correct - incorrect));
}
//for mass spawn

View File

@@ -22,6 +22,13 @@
var status;
var stage;
function clearStage(stage, eim) {
eim.setProperty("stage" + stage + "clear", "true");
eim.showClearEffect(true);
eim.giveEventPlayersStageReward(stage);
}
function start() {
status = -1;
action (1, 0, 0);
@@ -39,79 +46,77 @@ function action(mode, type, selection) {
status++;
else
status--;
var eim = cm.getPlayer().getEventInstance();
if (eim == null) {
cm.warp(990001100);
} else {
if (eim.getProperty("leader").equals(cm.getPlayer().getName())) {
if (cm.getPlayer().getMap().getReactorByName("statuegate").getState() > 0){
cm.sendOk("Proceed.");
cm.dispose();
} else {
if (status == 0) {
if (eim.getProperty("stage1status") == null || eim.getProperty("stage1status").equals("waiting")) {
if (eim.getProperty("stage1phase") == null) {
stage = 1;
eim.setProperty("stage1phase",stage);
} else {
stage = parseInt(eim.getProperty("stage1phase"));
}
if (stage == 1) {
cm.sendOk("In this challenge, I shall show a pattern on the statues around me. When I give the word, repeat the pattern to me to proceed.");
}
else {
cm.sendOk("I shall now present a more difficult puzzle for you. Good luck.")
}
}
else if (eim.getProperty("stage1status").equals("active")) {
if(eim.getProperty("stage1clear") == "true") {
cm.sendOk("Excellent work. You may proceed to the next stage.");
cm.dispose();
return;
}
if (cm.isEventLeader()) {
if (status == 0) {
if (eim.getProperty("stage1status") == null || eim.getProperty("stage1status").equals("waiting")) {
if (eim.getProperty("stage1phase") == null) {
stage = 1;
eim.setProperty("stage1phase",stage);
} else {
stage = parseInt(eim.getProperty("stage1phase"));
if (eim.getProperty("stage1combo").equals(eim.getProperty("stage1guess"))) {
if (stage == 3) {
cm.getPlayer().getMap().getReactorByName("statuegate").hitReactor(cm.getClient());
cm.sendOk("Excellent work. Please proceed to the next stage.");
cm.showEffect("quest/party/clear");
cm.playSound("Party1/Clear");
var prev = eim.getProperty("stage1clear");
eim.setProperty("stage1clear","true");
if (prev == null) {
cm.getGuild().gainGP(15);
}
} else {
cm.sendOk("Very good. You still have more to complete, however. Talk to me again when you're ready.");
eim.setProperty("stage1phase", stage + 1);
cm.mapMessage(5, "You have completed part " + stage + " of the Gatekeeper Test.");
}
} else {
cm.sendOk("You have failed this test.");
cm.mapMessage(5, "You have failed the Gatekeeper Test.");
eim.setProperty("stage1phase","1")
}
eim.setProperty("stage1status", "waiting");
cm.dispose();
}
if (stage == 1) {
cm.sendOk("In this challenge, I shall show a pattern on the statues around me. When I give the word, repeat the pattern to me to proceed.");
}
else {
cm.sendOk("Please wait.");
cm.dispose();
cm.sendOk("I shall now present a more difficult puzzle for you. Good luck.");
}
}
else if (status == 1) {
var reactors = getReactors();
var combo = makeCombo(reactors);
cm.mapMessage(5, "Please wait while the combination is revealed.");
var delay = 5000;
for (var i = 0; i < combo.length; i++) {
cm.getPlayer().getMap().getReactorByOid(combo[i]).delayedHitReactor(cm.getClient(), delay + 3500*i);
else if (eim.getProperty("stage1status").equals("active")) {
stage = parseInt(eim.getProperty("stage1phase"));
if (eim.getProperty("stage1combo").equals(eim.getProperty("stage1guess"))) {
if (stage == 3) {
cm.getPlayer().getMap().getReactorByName("statuegate").forceHitReactor(1);
clearStage(1, eim);
cm.getGuild().gainGP(15);
cm.sendOk("Excellent work. You may proceed to the next stage.");
} else {
cm.sendOk("Very good. You still have more to complete, however. Talk to me again when you're ready.");
eim.setProperty("stage1phase", stage + 1);
cm.mapMessage(5, "You have completed part " + stage + " of the Gatekeeper Test.");
}
} else {
eim.showWrongEffect();
cm.sendOk("You have failed this test.");
cm.mapMessage(5, "You have failed the Gatekeeper Test.");
eim.setProperty("stage1phase","1");
}
eim.setProperty("stage1status", "display");
eim.setProperty("stage1combo","");
eim.setProperty("stage1status", "waiting");
cm.dispose();
}
else {
cm.sendOk("The statues are working on the pattern. Please wait.");
cm.dispose();
}
}
else if (status == 1) {
var reactors = getReactors();
var combo = makeCombo(reactors);
cm.mapMessage(5, "Please wait while the combination is revealed.");
var delay = 5000;
for (var i = 0; i < combo.length; i++) {
cm.getPlayer().getMap().getReactorByOid(combo[i]).delayedHitReactor(cm.getClient(), delay + 3500*i);
}
eim.setProperty("stage1status", "display");
eim.setProperty("stage1combo","");
cm.dispose();
}
} else {
cm.sendOk("I need the leader of your party to speak with me, nobody else.");
cm.sendOk("I need the leader of this event to speak with me, nobody else.");
cm.dispose();
}
}
@@ -122,10 +127,10 @@ function action(mode, type, selection) {
function getReactors() {
var reactors = new Array();
var iter = cm.getPlayer().getMap().getMapObjects().iterator();
var iter = cm.getPlayer().getMap().getReactors().iterator();
while (iter.hasNext()) {
var mo = iter.next();
if (mo.getType() == Packages.server.maps.MapleMapObjectType.REACTOR && !mo.getName().equals("statuegate")) {
if (!mo.getName().equals("statuegate")) {
reactors.push(mo.getObjectId());
}
}

View File

@@ -22,26 +22,32 @@
function start() {
var eim = cm.getPlayer().getEventInstance();
if (eim != null) {
if (eim.getProperty("leader").equals(cm.getPlayer().getName())) {
if (cm.isEventLeader()) {
if (cm.haveItem(4001024)) {
cm.removeAll(4001024);
var prev = eim.setProperty("bossclear","true",true);
var prev = eim.setProperty("bossclear", "true");
if (prev == null) {
var start = parseInt(eim.getProperty("entryTimestamp"));
var diff = Packages.java.lang.System.currentTimeMillis() - start;
var diff = Date.now() - start;
var points = 1000 - Math.floor(diff / (100 * 60));
if(points < 100)
points = 100;
if(points < 100) points = 100;
cm.getGuild().gainGP(points);
}
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.");
}
}
else {
cm.sendOk("This is your final challenge. Defeat the evil lurking within the Rubian and let your event leader return it to me. That is all.");
}
}
else
cm.warp(990001100);
cm.dispose();
}

View File

@@ -51,7 +51,7 @@ function action(mode, type, selection){
var eim = cm.getEventInstance();
if(!eim.giveEventReward(cm.getPlayer())) {
cm.sendNext("It seems you don't have a free slot in either your #rEquip#k, #rUse#k or #rEtc#k inventories. Please make room and try again.");
cm.sendNext("It seems you don't have a free slot in either your #rEquip#k, #rUse#k or #rEtc#k inventories. Please make some room and try again.");
} else {
cm.warp(809050017);
}

View File

@@ -70,7 +70,7 @@ function action(mode, type, selection) {
cm.sendOk("You already have a Gold Maple Leaf. Go give them to your guests before you go into the wedding.");
cm.dispose();
} else if (hasEngageRing) {
cm.sendOk("You have recieved 15 Gold Maple Leaves.");
cm.sendOk("You have received 15 Gold Maple Leaves.");
cm.gainItem(4000313,15);
cm.dispose();
} else {

View File

@@ -42,7 +42,7 @@ function start() {
break;
}
if (hasRing)
cm.sendNext("You've reached the end of the wedding. You will recieve an Onyx Chest for Bride and Groom and an Onyx Chest. Exchange them at Pila, she is at the top of Amoria.");
cm.sendNext("You've reached the end of the wedding. You will receive an Onyx Chest for Bride and Groom and an Onyx Chest. Exchange them at Pila, she is at the top of Amoria.");
else if (cm.haveItem(4000313)) {
cm.sendNext("Wow the end of the wedding already ? Good bye then.!");
status = 20;

View File

@@ -22,10 +22,13 @@
/*
Return from Sharen III's Grave - Guild Quest
@Author Lerk
@Author Ronan
*/
function enter(pi) {
pi.warp(990000600, 1);
var backPortals = [6, 8, 9, 11];
var idx = pi.getEventInstance().gridCheck(pi.getPlayer());
pi.warp(990000600, backPortals[idx]);
return true;
}

View File

@@ -28,6 +28,7 @@ Save location to return.
*/
function enter(pi) {
pi.getEventInstance().gridInsert(pi.getPlayer(), 0);
pi.warp(990000700, "st00");
return true;
}

View File

@@ -28,6 +28,7 @@ Save location to return.
*/
function enter(pi) {
pi.getEventInstance().gridInsert(pi.getPlayer(), 1);
pi.warp(990000700, "st00");
return true;
}

View File

@@ -28,6 +28,7 @@ Save location to return.
*/
function enter(pi) {
pi.getEventInstance().gridInsert(pi.getPlayer(), 3);
pi.warp(990000700, "st00");
return true;
}

View File

@@ -28,6 +28,7 @@ Save location to return.
*/
function enter(pi) {
pi.getEventInstance().gridInsert(pi.getPlayer(), 2);
pi.warp(990000700, "st00");
return true;
}

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