diff --git a/docs/feature_list.md b/docs/feature_list.md index c926beab92..fbc84a16c6 100644 --- a/docs/feature_list.md +++ b/docs/feature_list.md @@ -101,6 +101,7 @@ Monsters, Maps & Reactors: * Implemented Zombify disease status. * Added Boss HP Bar for dozens of bosses (needs provided custom wz). * If multiple bosses are on the same area, client will prioritize Boss HP bar of the target of the player. +* Boss HP Bar and Server Messages now toggles (server message disappears when a boss battle is detected, and returns afterwards). Idea thanks to GabrielSin. * Improved map bounding checks for item drop points, assuring most of the items dropped will be available to pickup inside the accessible map area. * Boats, elevator and other travelling mechanics fully working. * HP decreasing overtime on maps and mechanics to prevent them (consumables, equips) fully functional. @@ -132,7 +133,7 @@ Player potentials: Server potentials: * Multi-worlds. -* Dynamic World/Channel deployment. +* Dynamic World/Channel deployment. While not implemented here, new channel deployment sensitive to quantity of online players was originally resinate's idea. * Inventory auto-gather and auto-sorting feature. * Enhanced auto-pot system: pet uses as many potions as necessary to reach the desired threshold. * Enhanced buff system: smartly checks for the best available buff effects to be active on the player. diff --git a/docs/issues.txt b/docs/issues.txt index f67c136e9d..6e87a5eab8 100644 --- a/docs/issues.txt +++ b/docs/issues.txt @@ -13,6 +13,7 @@ Known issues: - Sometimes battleship may behave oddly with the enhanced buff system, making the character d/c in certain scenarios. - Dragon Roar doesn't show the stun effect to players. - Some monster status such as freeze and weapon/magic reflect doesn't behave properly in certain scenarios. Freeze seems to not work on mobs with low OID or are starters from server boot time. +- On low-end connections, things such as command summoning a player that is currently logging in (already visible to other players) may cause the player to freeze, consequently freezing the account as well since the server-side disconnection doesn't happen. --------------------------- --------------------------- @@ -21,6 +22,7 @@ Missing features list: - Change name/World transfer. - Some pirate skills doesn't work for 3rd parties. - Cache frequently used SQL data. +- Pet commands are not being propagated to 3rd parties, and the commandResponse packet function seems somewhat wonky. --------------------------- diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index 7a96d18335..c81cf81d06 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -1194,4 +1194,36 @@ Melhorado desempenho do HealOvertimeHandler por fazendo buscar informação de m Corrigido comando "maxhpmp" permitindo efetivar valores negativos ao alvo. Corrigido Duey não registrando nível e experiência de equipamentos ao enviá-los. Buff no buyback: por um curto período após respawnar o jogador não morre (mínimo 1 HP), assim permitindo um tempo mínimo de reação. -Revisado task do item monitor em MapleMap mal-protegido contra acessos concorrentes. \ No newline at end of file +Revisado task do item monitor em MapleMap mal-protegido contra acessos concorrentes. + +28 - 30 Julho 2018, +Revisado vários problemas com Mystic Doors. +Corrigido alguns acessos a nulos no Duey. +Corrigido erro com XMLDomMapleData em casos onde múltiplos processos tentam ler dados simultaneamente. +Revisado vários casos de "lock sem unlock" ocorrendo em casos onde o objeto no qual tal lock está acoplado já teve seus locks liberados. +Corrigido falta de proteção contra registro concorrente de event instances no objeto que representa o jogador. +Corrigido jogadores não sendo rapidamente removidos de um evento no momento do dispose deste evento, gerando diversas inconsistências ao trocar de mapa pra fora do evento. + +31 Julho 2018, +Corrigido vários casos de nulos na fase de login perante a nova abordagem dinâmica de canais e mundos. +Corrigido worker de playershops/hiredmerchs não ativado. +Implementado melhoria para o sistema de server messages/boss HP bar, agora com atuação mutuamente exclusiva. +Implementado mostrar novamente server messages (com boss HPbar ao fundo) para casos onde algum tempo se passou sem o cliente trocar ataques com o boss, nesse caso voltando a mensagem do server. +Revisado sistema de encerramento de locks por todo o server. Colocado locks para serem devidamente liberados minutos após a finalização das estruturas, permitindo assim um tempo extra onde processos possam usar esses locks sem gerar conflitos de acesso concorrente. + +01 Agosto 2018, +Corrigido um mapa de mushking empire levando jogador a um portal inexistente, levando o server a inserir o jogador no mapa por um portal default. +Corrigido Kage (Item Maker) precisando de cristais nível 71~80 ao invés de 81~90. +Removido possibilidade de comprar cosméticos por mesos pelos NPCs. Espera-se coupons somente disponível pelo Cash Shop. +Corrigido NPC's da JQ de Sleepywood dando itens de cash aos jogadores em casos onde eles completam a JQ sem ter a quest ativa. +Corrigido comando "fly" ainda não atuando corretamente. Com a busca de informação de GMlevel vindo mais cedo, o pacote de autenticação agora informa o cliente de seu GMlevel devidamente. +Colocado comandos de adicionar/remover canais/mundos para rodar em uma nova thread, eliminando assim o GM de ter que esperar para realizar próximas ações. +Corrigido alguns mapas com o NPC Duey sem caminhão característico ao fundo. Adicionado Duey em New Leaf City. +Corrigido quests scriptadas bypassando flags de QUEST_RATE ao gerir EXP e MESO aos jogadores. + +02 Agosto 2018, +Modificado algumas tabelas em ThreadTracker e World para usar Integer ao invés de Short/Byte, não há vantagens em usar tipos menores em Java para "otimizar uso de memória", piora o desempenho geral desta forma. + +07 Agosto 2018, +Corrigido um bug na fase de login que nao construia corretamente overview de characters sem itens equipados, lancando excecoes posteriormente. +Revisado alguns casos de borda com doors levando as mesmas a nao sumirem imediatamente em certos cenarios. \ No newline at end of file diff --git a/nbproject/private/private.properties b/nbproject/private/private.properties index 82074e7fad..cb253ffdf6 100644 --- a/nbproject/private/private.properties +++ b/nbproject/private/private.properties @@ -1,10 +1,10 @@ compile.on.save=true do.depend=false do.jar=true -file.reference.mina-core-2.0.7.jar=C:\\Nexon\\MapleSolaxia\\HeavenMS\\cores\\mina-core-2.0.7.jar -file.reference.mysql-connector-java-bin.jar=C:\\Nexon\\MapleSolaxia\\HeavenMS\\cores\\mysql-connector-java-bin.jar -file.reference.slf4j-api-1.6.6.jar=C:\\Nexon\\MapleSolaxia\\HeavenMS\\cores\\slf4j-api-1.6.6.jar -file.reference.slf4j-jdk14-1.7.5.jar=C:\\Nexon\\MapleSolaxia\\HeavenMS\\cores\\slf4j-jdk14-1.7.5.jar +file.reference.mina-core-2.0.7.jar=C:\\Nexon\\HeavenMS\\cores\\mina-core-2.0.7.jar +file.reference.mysql-connector-java-bin.jar=C:\\Nexon\\HeavenMS\\cores\\mysql-connector-java-bin.jar +file.reference.slf4j-api-1.6.6.jar=C:\\Nexon\\HeavenMS\\cores\\slf4j-api-1.6.6.jar +file.reference.slf4j-jdk14-1.7.5.jar=C:\\Nexon\\HeavenMS\\cores\\slf4j-jdk14-1.7.5.jar javac.debug=true javadoc.preview=true user.properties.file=C:\\Users\\USER\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties diff --git a/scripts/event/KingPepeAndYetis.js b/scripts/event/KingPepeAndYetis.js index cd2c2064e8..09b47fe7c5 100644 --- a/scripts/event/KingPepeAndYetis.js +++ b/scripts/event/KingPepeAndYetis.js @@ -2,29 +2,23 @@ var minPlayers = 1; var timeLimit = 20; //20 minutes var eventTimer = 1000 * 60 * timeLimit; var exitMap = 106021400; +var eventMap = 106021500; function init(){} function setup(difficulty, lobbyId){ var eim = em.newInstance("KingPepe_" +lobbyId); - eim.getInstanceMap(106021500).resetFully(); - eim.getInstanceMap(106021500).allowSummonState(false); - respawn(eim); + eim.getInstanceMap(eventMap).resetFully(); + eim.getInstanceMap(eventMap).allowSummonState(false); + eim.startEventTimer(eventTimer); return eim; } function afterSetup(eim){} -function respawn(eim){ - var map = eim.getMapInstance(exitMap); - map.allowSummonState(true); - map.instanceMapRespawn(); - eim.schedule("respawn", 10000); -} - function playerEntry(eim, player){ - var yetiMap = eim.getMapInstance(106021500); + var yetiMap = eim.getMapInstance(eventMap); player.changeMap(yetiMap, yetiMap.getPortal(1)); } @@ -37,46 +31,31 @@ function scheduledTimeout(eim){ eim.dispose(); } -function playerRevive(eim, player){ - player.setHp(50); - player.setStance(0); - eim.unregisterPlayer(player); - player.changeMap(exitMap); - return false; -} - function playerDead(eim, player){} function playerDisconnected(eim, player){ - 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(); + if (eim.isEventTeamLackingNow(true, minPlayers, player)) { + eim.unregisterPlayer(player); + end(eim); + } + else + eim.unregisterPlayer(player); } function monsterValue(eim, mobId){ return -1; } -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 end(eim) { + var party = eim.getPlayers(); + for (var i = 0; i < party.size(); i++) { + playerExit(eim, party.get(i)); + } + eim.dispose(); } +function leftParty(eim, player){} + function disbandParty(eim){} function playerUnregistered(eim, player){} @@ -86,17 +65,15 @@ function playerExit(eim, player){ player.changeMap(exitMap, 2); } -function moveMap(eim, player){ - if(player.getMap().getId() == exitMap){ - removePlayer(eim, player); - eim.dispose(); - } -} - -function removePlayer(eim, player){ - eim.unregisterPlayer(player); - player.getMap().removePlayer(player); - player.setMap(exitMap); +function changedMap(eim, chr, mapid) { + if (mapid != eventMap) { + if (eim.isEventTeamLackingNow(true, minPlayers, chr)) { + eim.unregisterPlayer(chr); + end(eim); + } + else + eim.unregisterPlayer(chr); + } } function cancelSchedule(){} diff --git a/scripts/npc/1012103.js b/scripts/npc/1012103.js index d9c2160279..5074166d7f 100644 --- a/scripts/npc/1012103.js +++ b/scripts/npc/1012103.js @@ -41,12 +41,9 @@ function action(mode, type, selection) { } else { status++; if (status == 0) - cm.sendSimple("I'm the head of this hair salon. If you have a #b#t5150001##k or a #b#t5151001##k allow me to take care of your hairdo. Please choose the one you want.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150001##t5150001##l\r\n#L2#Dye your hair: #i5151001##t5151001##l"); + cm.sendSimple("I'm the head of this hair salon. If you have a #b#t5150001##k or a #b#t5151001##k allow me to take care of your hairdo. Please choose the one you want.\r\n#L1#Haircut: #i5150001##t5150001##l\r\n#L2#Dye your hair: #i5151001##t5151001##l"); else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150001##t5150001##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151001##t5151001##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) diff --git a/scripts/npc/1012104.js b/scripts/npc/1012104.js index 95d5385b1c..10b4d18e66 100644 --- a/scripts/npc/1012104.js +++ b/scripts/npc/1012104.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm Brittany the assistant. If you have #b#t5150010##k or #b#t5151000##k by any chance, then how about letting me change your hairdo?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150010##t5150010##l\r\n#L2#Dye your hair: #i5151000##t5151000##l"); + cm.sendSimple("I'm Brittany the assistant. If you have #b#t5150010##k or #b#t5151000##k by any chance, then how about letting me change your hairdo?\r\n#L1#Haircut: #i5150010##t5150010##l\r\n#L2#Dye your hair: #i5151000##t5151000##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150010##t5150010##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151000##t5151000##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/1052004.js b/scripts/npc/1052004.js index 7d8621e654..8e314519a6 100644 --- a/scripts/npc/1052004.js +++ b/scripts/npc/1052004.js @@ -47,17 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Well, hello! Welcome to the Henesys Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152001##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L1#I would like to buy a #b#t5152001##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to the Henesys Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152001##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152001, 1); - cm.sendOk("Enjoy!"); - } else - cm.sendOk("You don't have enough mesos to buy a coupon!"); - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) diff --git a/scripts/npc/1052005.js b/scripts/npc/1052005.js index 3234dd4034..988249bc5e 100644 --- a/scripts/npc/1052005.js +++ b/scripts/npc/1052005.js @@ -47,18 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152000##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L1#I would like to buy a #b#t5152000##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152000##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152000, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) { diff --git a/scripts/npc/1052100.js b/scripts/npc/1052100.js index 0d99cb9b78..424a4282dc 100644 --- a/scripts/npc/1052100.js +++ b/scripts/npc/1052100.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hello! I'm Don Giovanni, head of the beauty salon! If you have either #b#t5150003##k or #b#t5151003##k, why don't you let me take care of the rest? Decide what you want to do with your hair...\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150003##t5150003##l\r\n#L2#Dye your hair: #i5151003##t5151003##l"); + cm.sendSimple("Hello! I'm Don Giovanni, head of the beauty salon! If you have either #b#t5150003##k or #b#t5151003##k, why don't you let me take care of the rest? Decide what you want to do with your hair...\r\n#L1#Haircut: #i5150003##t5150003##l\r\n#L2#Dye your hair: #i5151003##t5151003##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150003##t5150003##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151003##t5151003##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/1052101.js b/scripts/npc/1052101.js index d61f3510d9..553236cd7a 100644 --- a/scripts/npc/1052101.js +++ b/scripts/npc/1052101.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm Andre, Don's assistant. Everyone calls me Andre, though. If you have a #b#t5150011##k or a #b#t5151002##k, please let me change your hairdo!\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150011##t5150011##l\r\n#L2#Dye your hair: #i5151002##t5151002##l"); + cm.sendSimple("I'm Andre, Don's assistant. Everyone calls me Andre, though. If you have a #b#t5150011##k or a #b#t5151002##k, please let me change your hairdo!\r\n#L1#Haircut: #i5150011##t5150011##l\r\n#L2#Dye your hair: #i5151002##t5151002##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150011##t5150011##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151002##t5151002##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/1061006.js b/scripts/npc/1061006.js index 3e20b74f95..f6a447bd6f 100644 --- a/scripts/npc/1061006.js +++ b/scripts/npc/1061006.js @@ -27,11 +27,11 @@ var selectedMap = -1; function start() { cm.sendNext("You feel a mysterious force surrounding this statue."); - if (cm.isQuestStarted(2054)) + if (cm.isQuestStarted(2054) || cm.isQuestCompleted(2054)) zones = 3; - else if (cm.isQuestStarted(2053)) + else if (cm.isQuestStarted(2053) || cm.isQuestCompleted(2053)) zones = 2; - else if (cm.isQuestStarted(2052)) + else if (cm.isQuestStarted(2052) || cm.isQuestCompleted(2052)) zones = 1; else zones = 0; diff --git a/scripts/npc/1063000.js b/scripts/npc/1063000.js index 5b568921e2..ba1248310b 100644 --- a/scripts/npc/1063000.js +++ b/scripts/npc/1063000.js @@ -21,29 +21,29 @@ */ /* John JQ Flower pile #1 */ + +var repeatablePrizes = [[4010000, 3], [4010001, 3], [4010002, 3], [4010003, 3], [4010004, 3], [4010005, 3]]; + function start() { - var prizes = Array(1040051, 1040127, 1040128, 1040133, 1040138, 1041000, 1041001, 1041110, 1041130, 1041139, 1042015, 1042017, 1042023, 1702001, 1702025); - var chances = Array(10, 10, 10, 10, 5, 10, 10, 10, 10, 5, 8, 8, 8, 9, 7); - var totalodds = 0; - var choice = 0; - for (var i = 0; i < chances.length; i++) { - var itemGender = (Math.floor(prizes[i]/1000)%10); - if ((cm.getPlayer().getGender() != itemGender) && (itemGender != 2)) - chances[i] = 0; - } - for (var i = 0; i < chances.length; i++) - totalodds += chances[i]; - var randomPick = Math.floor(Math.random()*totalodds)+1; - for (var i = 0; i < chances.length; i++) { - randomPick -= chances[i]; - if (randomPick <= 0) { - choice = i; - randomPick = totalodds + 100; + if (cm.isQuestStarted(2052) && !cm.haveItem(4031025,10)) { + if(!cm.canHold(4031025,10)) { + cm.sendNext("Check for a available slot on your ETC inventory."); + cm.dispose(); + return; } - } - if (cm.isQuestStarted(2052)) + cm.gainItem(4031025,10); - else cm.gainItem(prizes[choice],1); + } else { + if(cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).getNumFreeSlot() < 1) { + cm.sendNext("Check for a available slot on your ETC inventory."); + cm.dispose(); + return; + } + + var itemPrize = repeatablePrizes[Math.floor((Math.random() * repeatablePrizes.length))]; + cm.gainItem(itemPrize[0], itemPrize[1]); + } + cm.warp(105040300, 0); cm.dispose(); } \ No newline at end of file diff --git a/scripts/npc/1063001.js b/scripts/npc/1063001.js index d00585af3d..2d4f3fad09 100644 --- a/scripts/npc/1063001.js +++ b/scripts/npc/1063001.js @@ -21,29 +21,29 @@ /* John JQ Flower pile #2 */ + +var repeatablePrizes = [[4020000, 4], [4020002, 4], [4020006, 4]]; + function start() { - var prizes = Array(1060034, 1060040, 1060049, 1060113, 1060121, 1061000, 1061001, 1061073, 1061089, 1061142, 1062010, 1062020, 1702140, 1702115); - var chances = Array(10, 10, 10, 10, 5, 10, 10, 10, 10, 5, 8, 8, 8, 8); - var totalodds = 0; - var choice = 0; - for (var i = 0; i < chances.length; i++) { - var itemGender = (Math.floor(prizes[i]/1000)%10); - if ((cm.getPlayer().getGender() != itemGender) && (itemGender != 2)) - chances[i] = 0; - } - for (var i = 0; i < chances.length; i++) - totalodds += chances[i]; - var randomPick = Math.floor(Math.random()*totalodds)+1; - for (var i = 0; i < chances.length; i++) { - randomPick -= chances[i]; - if (randomPick <= 0) { - choice = i; - randomPick = totalodds + 100; + if (cm.isQuestStarted(2053) && !cm.haveItem(4031026,20)) { + if(!cm.canHold(4031026,20)) { + cm.sendNext("Check for a available slot on your ETC inventory.") + cm.dispose(); + return; } - } - if (cm.isQuestStarted(2053)) + cm.gainItem(4031026,20); - else cm.gainItem(prizes[choice],1); + } else { + if(cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).getNumFreeSlot() < 1) { + cm.sendNext("Check for a available slot on your ETC inventory."); + cm.dispose(); + return; + } + + var itemPrize = repeatablePrizes[Math.floor((Math.random() * repeatablePrizes.length))]; + cm.gainItem(itemPrize[0], itemPrize[1]); + } + cm.warp(105040300, 0); cm.dispose(); } \ No newline at end of file diff --git a/scripts/npc/1063002.js b/scripts/npc/1063002.js index e568087825..4b27a9bcd1 100644 --- a/scripts/npc/1063002.js +++ b/scripts/npc/1063002.js @@ -19,31 +19,31 @@ along with this program. If not, see . */ -// John JQ Flower pile #3 +/* John JQ Flower pile #3 +*/ + +var repeatablePrizes = [[4010006, 4], [4010007, 4], [4020007, 4]]; function start() { - var prizes = Array(1050004, 1050015, 1050041, 1050044, 1050124, 1051021, 1051036, 1051075, 1051111, 1051138, 1052003, 1052006, 1052011, 1702024, 1702026); - var chances = Array(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 8, 8); - var totalodds = 0; - var choice = 0; - for (var i = 0; i < chances.length; i++) { - var itemGender = (Math.floor(prizes[i]/1000)%10); - if (cm.getPlayer().getGender() != itemGender && itemGender != 2) - chances[i] = 0; - } - for (var i = 0; i < chances.length; i++) - totalodds += chances[i]; - var randomPick = Math.floor(Math.random()*totalodds)+1; - for (var i = 0; i < chances.length; i++) { - randomPick -= chances[i]; - if (randomPick <= 0) { - choice = i; - randomPick = totalodds + 100; + if (cm.isQuestStarted(2054) && !cm.haveItem(4031028,30)) { + if(!cm.canHold(4031028,30)) { + cm.sendNext("Check for a available slot on your ETC inventory.") + cm.dispose(); + return; } - } - if (cm.isQuestStarted(2054)) + cm.gainItem(4031028,30); - else cm.gainItem(prizes[choice],1); + } else { + if(cm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.ETC).getNumFreeSlot() < 1) { + cm.sendNext("Check for a available slot on your ETC inventory."); + cm.dispose(); + return; + } + + var itemPrize = repeatablePrizes[Math.floor((Math.random() * repeatablePrizes.length))]; + cm.gainItem(itemPrize[0], itemPrize[1]); + } + cm.warp(105040300, 0); cm.dispose(); } \ No newline at end of file diff --git a/scripts/npc/2010001.js b/scripts/npc/2010001.js index defc9f6daf..6df9d45014 100644 --- a/scripts/npc/2010001.js +++ b/scripts/npc/2010001.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hello I'm Mino. If you have either a #b#t5150005##k or a #b#t5151005##k, then please let me take care of your hair. Choose what you want to do with it.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150005##t5150005##l\r\n#L2#Dye your hair: #i5151005##t5151005##l"); + cm.sendSimple("Hello I'm Mino. If you have either a #b#t5150005##k or a #b#t5151005##k, then please let me take care of your hair. Choose what you want to do with it.\r\n#L1#Haircut: #i5150005##t5150005##l\r\n#L2#Dye your hair: #i5151005##t5151005##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150005##t5150005##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151005##t5151005##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/2010002.js b/scripts/npc/2010002.js index 1f29480f00..770c47fb05 100644 --- a/scripts/npc/2010002.js +++ b/scripts/npc/2010002.js @@ -47,18 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Well well well, welcome to the Orbis Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152005##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L1#I would like to buy a #b#t5152005##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well well well, welcome to the Orbis Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152005##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152005, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) { diff --git a/scripts/npc/2012007.js b/scripts/npc/2012007.js index 2e700ce1ec..ae03bab004 100644 --- a/scripts/npc/2012007.js +++ b/scripts/npc/2012007.js @@ -31,7 +31,7 @@ var fhair = Array(31040, 31000, 31250, 31220, 31260, 31240, 31110, 31270, 31030, var hairnew = Array(); function start() { - cm.sendSimple("I'm Rinz, the assistant. Do you have #b#t5150013##k or #b#t5151004##k with you? If so, what do you think about letting me take care of your hairdo? What do you want to do with your hair?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150013##t5150013##l\r\n#L2#Dye your hair: #i5151004##t5151004##l"); + cm.sendSimple("I'm Rinz, the assistant. Do you have #b#t5150013##k or #b#t5151004##k with you? If so, what do you think about letting me take care of your hairdo? What do you want to do with your hair?\r\n#L1#Haircut: #i5150013##t5150013##l\r\n#L2#Dye your hair: #i5151004##t5151004##l"); } function action(mode, type, selection) { @@ -40,10 +40,7 @@ function action(mode, type, selection) { else { status++; if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150013##t5150013##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151004##t5151004##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) diff --git a/scripts/npc/2012008.js b/scripts/npc/2012008.js index bb6e763221..7e553d706c 100644 --- a/scripts/npc/2012008.js +++ b/scripts/npc/2012008.js @@ -27,7 +27,7 @@ var price = 1000000; var skin = Array(0, 1, 2, 3, 4); function start() { - cm.sendSimple("Well, hello! Welcome to the Orbis Skin-Care~! Would you like to have a firm, tight, healthy looking skin like mine? With #b#t5153001##k, you can let us take care of the rest and have the kind of skin you've always wanted~!\r\n#L1#I would like to buy a #b#t5153001##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to the Orbis Skin-Care~! Would you like to have a firm, tight, healthy looking skin like mine? With #b#t5153001##k, you can let us take care of the rest and have the kind of skin you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } function action(mode, type, selection) { @@ -43,15 +43,7 @@ function action(mode, type, selection) { else status--; if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5153001, 1); - cm.sendOk("Enjoy!"); - } else - cm.sendOk("You don't have enough mesos to buy a coupon!"); - cm.dispose(); - } else if (selection == 2) + if (selection == 2) cm.sendStyle("With our specialized machine, you can see the way you'll look after the treatment PRIOR to the procedure. What kind of a look are you looking for? Go ahead and choose the style of your liking~!", skin); } else if (status == 2){ diff --git a/scripts/npc/2012009.js b/scripts/npc/2012009.js index 3d15b91e6f..7de29684d2 100644 --- a/scripts/npc/2012009.js +++ b/scripts/npc/2012009.js @@ -30,7 +30,7 @@ var fface = Array(21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, var facenew = Array(); function start() { - cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152004##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L1#I would like to buy a #b#t5152004##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152004##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L2#I already have a Coupon!#l"); } function action(mode, type, selection) { @@ -39,15 +39,7 @@ function action(mode, type, selection) { } else { status++; if (status == 1) { - if (selection == 1) { - if (cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152004, 1); - cm.sendOk("Enjoy!"); - } else - cm.sendOk("You don't have enough mesos to buy a coupon!"); - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) for (var i = 0; i < mface.length; i++) @@ -59,13 +51,15 @@ function action(mode, type, selection) { } } else if (status == 2){ - cm.dispose(); if (cm.haveItem(5152004)){ cm.gainItem(5152004, -1); cm.setFace(facenew[Math.floor(Math.random() * facenew.length)]); cm.sendOk("Enjoy your new and improved face!"); - } else + } else { cm.sendOk("Hmm ... it looks like you don't have the coupon specifically for this place. Sorry to say this, but without the coupon, there's no plastic surgery for you..."); + } + + cm.dispose(); } } } diff --git a/scripts/npc/2040019.js b/scripts/npc/2040019.js index 70d52a97bb..33ff4935ed 100644 --- a/scripts/npc/2040019.js +++ b/scripts/npc/2040019.js @@ -47,18 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Well, I'm bored, so I'll help out the doctor. For a #b#t5152006##k, I will change the way you look. But don't forget, it will be random!\r\n#L1#I would like to buy a #b#t5152006##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, I'm bored, so I'll help out the doctor. For a #b#t5152006##k, I will change the way you look. But don't forget, it will be random!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152006, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) { diff --git a/scripts/npc/2041007.js b/scripts/npc/2041007.js index aa92e7e5b2..a30220a0e3 100644 --- a/scripts/npc/2041007.js +++ b/scripts/npc/2041007.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Welcome, welcome, welcome to the Ludibrium Hair Salon! Do you, by any chance, have a #b#t5150007##k or a #b#t5151007##k? If so, how about letting me take care of your hair? Please choose what you want to do with it...\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150007##t5150007##l\r\n#L2#Dye your hair: #i5151007##t5151007##l"); + cm.sendSimple("Welcome, welcome, welcome to the Ludibrium Hair Salon! Do you, by any chance, have a #b#t5150007##k or a #b#t5151007##k? If so, how about letting me take care of your hair? Please choose what you want to do with it...\r\n#L1#Haircut: #i5150007##t5150007##l\r\n#L2#Dye your hair: #i5151007##t5151007##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150007##t5150007##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151007##t5151007##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/2041009.js b/scripts/npc/2041009.js index 7ad8eb6dce..6d58b1ee0a 100644 --- a/scripts/npc/2041009.js +++ b/scripts/npc/2041009.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hi, I'm the assistant here. Don't worry, I'm plenty good enough for this. If you have #b#t5150012##k or #b#t5151006##k by any chance, then allow me to take care of the rest, alright?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150012##t5150012##l\r\n#L2#Dye your hair: #i5151006##t5151006##l"); + cm.sendSimple("Hi, I'm the assistant here. Don't worry, I'm plenty good enough for this. If you have #b#t5150012##k or #b#t5151006##k by any chance, then allow me to take care of the rest, alright?\r\n#L1#Haircut: #i5150012##t5150012##l\r\n#L2#Dye your hair: #i5151006##t5151006##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150012##t5150012##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151006##t5151006##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/2041010.js b/scripts/npc/2041010.js index f8878294a3..85c2a18ba2 100644 --- a/scripts/npc/2041010.js +++ b/scripts/npc/2041010.js @@ -47,18 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Well, hello! Welcome to the Ludibrium Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152007##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L1#I would like to buy a #b#t5152007##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to the Ludibrium Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152007##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152007, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) { diff --git a/scripts/npc/2041013.js b/scripts/npc/2041013.js index 8920e28bc2..cbbeb8e313 100644 --- a/scripts/npc/2041013.js +++ b/scripts/npc/2041013.js @@ -41,18 +41,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Oh, hello! Welcome to the Ludibrium Skin-Care! Are you interested in getting tanned and looking sexy? How about a beautiful, snow-white skin? If you have #b#t5153002##k, you can let us take care of the rest and have the kind of skin you've always dreamed of!\r\n#L1#I would like to buy a #b#t5153002##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); - } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5153002, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + cm.sendSimple("Oh, hello! Welcome to the Ludibrium Skin-Care! Are you interested in getting tanned and looking sexy? How about a beautiful, snow-white skin? If you have #b#t5153002##k, you can let us take care of the rest and have the kind of skin you've always dreamed of!\r\n#L2#I already have a Coupon!#l"); + } else if (status == 1) { + if (selection == 2) { cm.sendStyle("With our specialized machine, you can see the way you'll look after the treatment PRIOR to the procedure. What kind of a look are you looking for? Go ahead and choose the style of your liking~!", skin); } } diff --git a/scripts/npc/2090100.js b/scripts/npc/2090100.js index 25cacd56c9..b26fd89017 100644 --- a/scripts/npc/2090100.js +++ b/scripts/npc/2090100.js @@ -31,7 +31,7 @@ var fhair = Array(31040, 31250, 31310, 31220, 31300, 31680, 31160, 31030, 31230) var hairnew = Array(); function start() { - cm.sendSimple("Welcome to the Mu Lung hair shop. If you have a #b#t5150025##k, or a #b#t5151020##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150025##t5150025##l\r\n#L2#Dye your hair: #i5151020##t5151020##l"); + cm.sendSimple("Welcome to the Mu Lung hair shop. If you have a #b#t5150025##k, or a #b#t5151020##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L1#Haircut: #i5150025##t5150025##l\r\n#L2#Dye your hair: #i5151020##t5151020##l"); } function action(mode, type, selection) { @@ -47,10 +47,7 @@ function action(mode, type, selection) { else status--; if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150025##t5150025##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151020##t5151020##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/2090101.js b/scripts/npc/2090101.js index ec4afeccd6..ed794588b8 100644 --- a/scripts/npc/2090101.js +++ b/scripts/npc/2090101.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm a hair assistant in this shop. If you have #b#t5150024##k or #b#t5151019##k by any chance, then how about letting me change your hairdo?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150024##t5150024##l\r\n#L2#Dye your hair: #i5151019##t5151019##l"); + cm.sendSimple("I'm a hair assistant in this shop. If you have #b#t5150024##k or #b#t5151019##k by any chance, then how about letting me change your hairdo?\r\n#L1#Haircut: #i5150024##t5150024##l\r\n#L2#Dye your hair: #i5151019##t5151019##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150024##t5150024##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151019##t5151019##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/2090102.js b/scripts/npc/2090102.js index 4555708310..346b48ff47 100644 --- a/scripts/npc/2090102.js +++ b/scripts/npc/2090102.js @@ -44,18 +44,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Well, hello! Welcome to the Mu Lung Skin-Care! Would you like to have a firm, tight, healthy looking skin like mine? With #b#t5153006##k, you can let us take care of the rest and have the kind of skin you've always wanted~!\r\n#L1#I would like to buy a #b#t5153006##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to the Mu Lung Skin-Care! Would you like to have a firm, tight, healthy looking skin like mine? With #b#t5153006##k, you can let us take care of the rest and have the kind of skin you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5153006, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { cm.sendStyle("With our specialized machine, you can see the way you'll look after the treatment PRIOR to the procedure. What kind of a look are you looking for? Go ahead and choose the style of your liking~!", skin); } } diff --git a/scripts/npc/2090103.js b/scripts/npc/2090103.js index b6d711934c..f157b7bda0 100644 --- a/scripts/npc/2090103.js +++ b/scripts/npc/2090103.js @@ -46,12 +46,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hey, I'm Pata, and I am a cosmetic lens expert here in Mu Lung. I believe your eyes are the most important feature in your body, and with #b#t5152042##k or #b#t5152041##k, I can prescribe the right kind of cosmetic lenses for you. Now, what would you like to use?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Cosmetic Lenses: #i5152042##t5152042##l\r\n#L2#Cosmetic Lenses: #i5152041##t5152041##l"); + cm.sendSimple("Hey, I'm Pata, and I am a cosmetic lens expert here in Mu Lung. I believe your eyes are the most important feature in your body, and with #b#t5152042##k or #b#t5152041##k, I can prescribe the right kind of cosmetic lenses for you. Now, what would you like to use?\r\n#L1#Cosmetic Lenses: #i5152042##t5152042##l\r\n#L2#Cosmetic Lenses: #i5152041##t5152041##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Cosmetic Lenses for " + regprice + " mesos: #i5152042##t5152042##l\r\n#L1#Cosmetic Lenses for " + vipprice + " mesos: #i5152041##t5152041##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; if (cm.getPlayer().getGender() == 0) { var current = cm.getPlayer().getFace() diff --git a/scripts/npc/2090104.js b/scripts/npc/2090104.js index 1691678971..83a0497a93 100644 --- a/scripts/npc/2090104.js +++ b/scripts/npc/2090104.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hey, I'm Noma, and I am assiting Pata in changing faces into beautiful things here in Mu Lung. With #b#t5152027##k or #b#t5152028##k, I can change the way you look. Now, what would you like to use?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Plastic Surgery: #i5152027##t5152027##l\r\n#L2#Plastic Surgery: #i5152028##t5152028##l"); + cm.sendSimple("Hey, I'm Noma, and I am assiting Pata in changing faces into beautiful things here in Mu Lung. With #b#t5152027##k or #b#t5152028##k, I can change the way you look. Now, what would you like to use?\r\n#L1#Plastic Surgery: #i5152027##t5152027##l\r\n#L2#Plastic Surgery: #i5152028##t5152028##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Plastic Surgery for " + regprice + " mesos: #i5152027##t5152027##l\r\n#L1#Plastic Surgery for " + vipprice + " mesos: #i5152028##t5152028##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; facenew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/9000036.js b/scripts/npc/9000036.js index 4905fbcc0a..abeb0e696a 100644 --- a/scripts/npc/9000036.js +++ b/scripts/npc/9000036.js @@ -111,8 +111,8 @@ function action(mode, type, selection) { var matQtySet = [[5,5],[5,5,5],[5,5,5,5,1],[5,5],[5,5,5],[5,5,5,5,1],[1,1],[1,1],[1,1],[1,1]]; var costSet = [100000,200000,300000,125000,250000,375000,500000,500000,500000,500000, 25000, 25000, 25000, 25000]; }else if (selectedType == 2) { //eye accessory refine - var matSet = [[4001006, 4003002, 4000082, 4031203], [4000073, 4011008], [4000073, 4011008], [4000073, 4011008, 4000082], [4001006, 4003002, 4003000, 4003001]]; - var matQtySet = [[2, 2, 5, 10], [50, 2], [75, 3], [75, 3, 10], [2, 2, 10, 5]]; + var matSet = [[4001006, 4003002, 4000082, 4031203], [4001005, 4011008], [4001005, 4011008], [4001005, 4011008, 4000082], [4001006, 4003002, 4003000, 4003001]]; + var matQtySet = [[2, 2, 5, 10], [3, 2], [4, 3], [5, 3, 10], [2, 2, 10, 5]]; var costSet = [250000, 250000, 300000, 400000, 200000]; }else if (selectedType == 3) { //belt & medals refine var matSet = [[4001006, 4003005, 4003004], [7777, 7777]]; diff --git a/scripts/npc/9001108.js b/scripts/npc/9001108.js index 7595527346..b97c317956 100644 --- a/scripts/npc/9001108.js +++ b/scripts/npc/9001108.js @@ -68,7 +68,7 @@ function action(m,t,s) { cm.sendNext("Welcome! I heard what happened from Baby Moon Bunny I'm glad you came since I was Planning on requesting some help. Gaga is a friend of mine who has helped me before and often stops by to say hello. Unfortunaley, he was kidnapped by aliens."); } else { selected = 2; - cm.sendYesNo("At the Space Mine, you can find special ores called #bKrypto Crystals#k that contain the mysterious power of space. #bKrypto Crystals#l are usually emerald in color, but will turn brown if hit with the Spaceship's #bSpace Beam#k. Remember, in order to thwart this alien conspracy, #b10 Brown Krypto Crystal's and 10 Emerald Krypto Crystal's are needed. But since even #b1 Krypto Crystal#k can be of help, brign me as many as possible. Oh, and one more thing! The Space Mines are protected by the Space Mateons. They are extemely strong due to the power of the #Krypto Crystals#k, so don't try to defeat them. Simply concentrate on quickly collecting the crystals."); + cm.sendYesNo("At the Space Mine, you can find special ores called #bKrypto Crystals#k that contains the mysterious power of space. #bKrypto Crystals#l are usually emerald in color, but will turn brown if hit with the Spaceship's #bSpace Beam#k. Remember, in order to thwart this alien conspracy, #b10 Brown Krypto Crystal's and 10 Emerald Krypto Crystal's are needed. But since even #b1 Krypto Crystal#k can be of help, brign me as many as possible. Oh, and one more thing! The Space Mines are protected by the Space Mateons. They are extemely strong due to the power of the #Krypto Crystals#k, so don't try to defeat them. Simply concentrate on quickly collecting the crystals."); } } else if (status == 2) { if(selected == 1) { diff --git a/scripts/npc/9120100.js b/scripts/npc/9120100.js index 4a546624fd..53aa159e58 100644 --- a/scripts/npc/9120100.js +++ b/scripts/npc/9120100.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Welcome to the Showa hair shop. If you have a #b#t5150009##k, or a #b#t5151009##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150009##t5150009##l\r\n#L2#Dye your hair: #i5151009##t5151009##l"); + cm.sendSimple("Welcome to the Showa hair shop. If you have a #b#t5150009##k, or a #b#t5151009##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L1#Haircut: #i5150009##t5150009##l\r\n#L2#Dye your hair: #i5151009##t5151009##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150009##t5150009##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151009##t5151009##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/9120101.js b/scripts/npc/9120101.js index 3ffe1372bd..d07f5102d4 100644 --- a/scripts/npc/9120101.js +++ b/scripts/npc/9120101.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm the head of Showa hair salon. If you have a #b#t5150009##k or a #b#t5151009##k allow me to take care of your hairdo. Please choose the one you want.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150009##t5150009##l\r\n#L2#Dye your hair: #i5151009##t5151009##l"); + cm.sendSimple("I'm the head of Showa hair salon. If you have a #b#t5150009##k or a #b#t5151009##k allow me to take care of your hairdo. Please choose the one you want.\r\n#L1#Haircut: #i5150009##t5150009##l\r\n#L2#Dye your hair: #i5151009##t5151009##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150009##t5150009##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151009##t5151009##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/9200100.js b/scripts/npc/9200100.js index 6b111048f5..d97485e95c 100644 --- a/scripts/npc/9200100.js +++ b/scripts/npc/9200100.js @@ -44,12 +44,9 @@ function action(mode, type, selection) { else status--; if (status == 0) - cm.sendSimple("Hi, there~! I'm Dr. Lenu, in charge of the cosmetic lenses here at the Henesys Plastic Surgery Shop! With #b#t5152010##k or #b#t5152013##k, you can let us take care of the rest and have the kind of beautiful look you've always craved~! Remember, the first thing everyone notices about you is the eyes, and we can help you find the cosmetic lens that most fits you! Now, what would you like to use?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Cosmetic Lenses: #i5152010##t5152010##l\r\n#L2#Cosmetic Lenses: #i5152013##t5152013##l"); + cm.sendSimple("Hi, there~! I'm Dr. Lenu, in charge of the cosmetic lenses here at the Henesys Plastic Surgery Shop! With #b#t5152010##k or #b#t5152013##k, you can let us take care of the rest and have the kind of beautiful look you've always craved~! Remember, the first thing everyone notices about you is the eyes, and we can help you find the cosmetic lens that most fits you! Now, what would you like to use?\r\n#L1#Cosmetic Lenses: #i5152010##t5152010##l\r\n#L2#Cosmetic Lenses: #i5152013##t5152013##l"); else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Cosmetic Lenses for " + regprice + " mesos: #i5152010##t5152010##l\r\n#L1#Cosmetic Lenses for " + vipprice + " mesos: #i5152013##t5152013##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; if (cm.getPlayer().getGender() == 0) var current = cm.getPlayer().getFace()% 100 + 20000; diff --git a/scripts/npc/9200101.js b/scripts/npc/9200101.js index b9e0cf3082..13a3c7ae46 100644 --- a/scripts/npc/9200101.js +++ b/scripts/npc/9200101.js @@ -46,12 +46,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hello, I'm Dr. Rhomes, head of the cosmetic lens department here at the Orbis Plastic Surgery Shop.\r\nMy goal here is to add personality to everyone's eyes through the wonders of cosmetic lenses, and with #b#t5152011##k or #b#t5152014##k, I can do the same for you, too! Now, what would you like to use?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Cosmetic Lenses: #i5152011##t5152011##l\r\n#L2#Cosmetic Lenses: #i5152014##t5152014##l"); + cm.sendSimple("Hello, I'm Dr. Rhomes, head of the cosmetic lens department here at the Orbis Plastic Surgery Shop.\r\nMy goal here is to add personality to everyone's eyes through the wonders of cosmetic lenses, and with #b#t5152011##k or #b#t5152014##k, I can do the same for you, too! Now, what would you like to use?\r\n#L1#Cosmetic Lenses: #i5152011##t5152011##l\r\n#L2#Cosmetic Lenses: #i5152014##t5152014##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Cosmetic Lenses for " + regprice + " mesos: #i5152011##t5152011##l\r\n#L1#Cosmetic Lenses for " + vipprice + " mesos: #i5152014##t5152014##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; if (cm.getPlayer().getGender() == 0) { var current = cm.getPlayer().getFace() diff --git a/scripts/npc/9200102.js b/scripts/npc/9200102.js index 0c4e241d92..3c16150d1e 100644 --- a/scripts/npc/9200102.js +++ b/scripts/npc/9200102.js @@ -46,12 +46,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Um... hi, I'm Dr. Bosch, and I am a cosmetic lens expert here at the Ludibrium Plastic Surgery Shop. I believe your eyes are the most important feature in your body, and with #b#t5152012##k or #b#t5152015##k, I can prescribe the right kind of cosmetic lenses for you. Now, what would you like to use?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Cosmetic Lenses: #i5152012##t5152012##l\r\n#L2#Cosmetic Lenses: #i5152015##t5152015##l"); + cm.sendSimple("Um... hi, I'm Dr. Bosch, and I am a cosmetic lens expert here at the Ludibrium Plastic Surgery Shop. I believe your eyes are the most important feature in your body, and with #b#t5152012##k or #b#t5152015##k, I can prescribe the right kind of cosmetic lenses for you. Now, what would you like to use?\r\n#L1#Cosmetic Lenses: #i5152012##t5152012##l\r\n#L2#Cosmetic Lenses: #i5152015##t5152015##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Cosmetic Lenses for " + regprice + " mesos: #i5152012##t5152012##l\r\n#L1#Cosmetic Lenses for " + vipprice + " mesos: #i5152015##t5152015##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; if (cm.getPlayer().getGender() == 0) { var current = cm.getPlayer().getFace() % 100 + 20000; diff --git a/scripts/npc/9201015.js b/scripts/npc/9201015.js index 47e71d0dc3..689222d894 100644 --- a/scripts/npc/9201015.js +++ b/scripts/npc/9201015.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Welcome to the Amoria hair shop. If you have a #b#t5150020##k, or a #b#t5151017##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150020##t5150020##l\r\n#L2#Dye your hair: #i5151017##t5151017##l"); + cm.sendSimple("Welcome to the Amoria hair shop. If you have a #b#t5150020##k, or a #b#t5151017##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L1#Haircut: #i5150020##t5150020##l\r\n#L2#Dye your hair: #i5151017##t5151017##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150020##t5150020##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151017##t5151017##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/9201016.js b/scripts/npc/9201016.js index a30ee27124..da4de68582 100644 --- a/scripts/npc/9201016.js +++ b/scripts/npc/9201016.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm Salon Seamus. If you have #b#t5150019##k or #b#t5151016##k by any chance, then how about letting me change your hairdo?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150019##t5150019##l\r\n#L2#Dye your hair: #i5151016##t5151016##l"); + cm.sendSimple("I'm Salon Seamus. If you have #b#t5150019##k or #b#t5151016##k by any chance, then how about letting me change your hairdo?\r\n#L1#Haircut: #i5150019##t5150019##l\r\n#L2#Dye your hair: #i5151016##t5151016##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150019##t5150019##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151016##t5151016##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { @@ -145,12 +142,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm Salon Seamus. If you have #b#t5150019##k or #b#t5151016##k by any chance, then how about letting me change your hairdo?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150019##t5150019##l\r\n#L2#Dye your hair: #i5151016##t5151016##l"); + cm.sendSimple("I'm Salon Seamus. If you have #b#t5150019##k or #b#t5151016##k by any chance, then how about letting me change your hairdo?\r\n#L1#Haircut: #i5150019##t5150019##l\r\n#L2#Dye your hair: #i5151016##t5151016##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150019##t5150019##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151016##t5151016##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/9201017.js b/scripts/npc/9201017.js index 97d4557bf4..3ca19ca995 100644 --- a/scripts/npc/9201017.js +++ b/scripts/npc/9201017.js @@ -46,12 +46,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hi, there~! I'm Dr.Roberts, in charge of the cosmetic lenses here at the Amoria Plastic Surgery Shop! With #b#t5152025##k or #b#t5152026##k, you can let us take care of the rest and have the kind of beautiful look you've always craved~! Remember, the first thing everyone notices about you is the eyes, and we can help you find the cosmetic lens that most fits you! Now, what would you like to use?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Cosmetic Lenses: #i5152025##t5152025##l\r\n#L2#Cosmetic Lenses: #i5152026##t5152026##l"); + cm.sendSimple("Hi, there~! I'm Dr.Roberts, in charge of the cosmetic lenses here at the Amoria Plastic Surgery Shop! With #b#t5152025##k or #b#t5152026##k, you can let us take care of the rest and have the kind of beautiful look you've always craved~! Remember, the first thing everyone notices about you is the eyes, and we can help you find the cosmetic lens that most fits you! Now, what would you like to use?\r\n#L1#Cosmetic Lenses: #i5152025##t5152025##l\r\n#L2#Cosmetic Lenses: #i5152026##t5152026##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Cosmetic Lenses for " + regprice + " mesos: #i5152025##t5152025##l\r\n#L1#Cosmetic Lenses for " + vipprice + " mesos: #i5152026##t5152026##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; if (cm.getPlayer().getGender() == 0) { var current = cm.getPlayer().getFace() % 100 + 20000; diff --git a/scripts/npc/9201018.js b/scripts/npc/9201018.js index af680d832f..35aac9042b 100644 --- a/scripts/npc/9201018.js +++ b/scripts/npc/9201018.js @@ -47,18 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Well, hello! Welcome to Amoria Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152022##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L1#I would like to buy a #b#t5152022##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to Amoria Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152022##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152022, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) { diff --git a/scripts/npc/9201019.js b/scripts/npc/9201019.js index c9981ac595..a7948308c4 100644 --- a/scripts/npc/9201019.js +++ b/scripts/npc/9201019.js @@ -47,18 +47,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152021##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L1#I would like to buy a #b#t5152021##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152021##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152021, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) { for(var i = 0; i < mface.length; i++) { diff --git a/scripts/npc/9201061.js b/scripts/npc/9201061.js index f5ad8c8a2a..477ad87fe2 100644 --- a/scripts/npc/9201061.js +++ b/scripts/npc/9201061.js @@ -44,18 +44,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hi, there~! I'm Bomack. If you have a #b#t5152035##k, I can prescribe the right kind of cosmetic lenses for you. Now, what would you like to do?\r\n#L1#I would like to buy a #b#t5152035##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Hi, there~! I'm Bomack. If you have a #b#t5152035##k, I can prescribe the right kind of cosmetic lenses for you. Now, what would you like to do?\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152035, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { if (cm.getPlayer().getGender() == 0) { var current = cm.getPlayer().getFace() % 100 + 20000; } diff --git a/scripts/npc/9201062.js b/scripts/npc/9201062.js index e1e959d333..7fd8d26eb5 100644 --- a/scripts/npc/9201062.js +++ b/scripts/npc/9201062.js @@ -44,18 +44,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("Hey, there~! I'm J.J.! I'm in charge of the cosmetic lenses here at NLC Shop! If you have a #b#t5152036##k, I can get you the best cosmetic lenses you have ever had! Now, what would you like to do?\r\n#L1#I would like to buy a #b#t5152036##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Hey, there~! I'm J.J.! I'm in charge of the cosmetic lenses here at NLC Shop! If you have a #b#t5152036##k, I can get you the best cosmetic lenses you have ever had! Now, what would you like to do?\r\n#L2#I already have a Coupon!#l"); } else if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152036, 1); - cm.sendOk("Enjoy!"); - } else { - cm.sendOk("You don't have enough mesos to buy a coupon!"); - } - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { if (cm.getPlayer().getGender() == 0) { var current = cm.getPlayer().getFace() % 100 + 20000; } diff --git a/scripts/npc/9201063.js b/scripts/npc/9201063.js index 028fbfcb67..7585600e39 100644 --- a/scripts/npc/9201063.js +++ b/scripts/npc/9201063.js @@ -48,12 +48,9 @@ function action(mode, type, selection) { else status--; if (status == 0) { - cm.sendSimple("I'm Ari the assistant. If you have #b#t5150030##k or #b#t5151025##k by any chance, then how about letting me change your hairdo?\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150030##t5150030##l\r\n#L2#Dye your hair: #i5151025##t5151025##l"); + cm.sendSimple("I'm Ari the assistant. If you have #b#t5150030##k or #b#t5151025##k by any chance, then how about letting me change your hairdo?\r\n#L1#Haircut: #i5150030##t5150030##l\r\n#L2#Dye your hair: #i5151025##t5151025##l"); } else if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150030##t5150030##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151025##t5151025##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) { diff --git a/scripts/npc/9201064.js b/scripts/npc/9201064.js index 0e4955cc48..1dd52ce443 100644 --- a/scripts/npc/9201064.js +++ b/scripts/npc/9201064.js @@ -31,7 +31,7 @@ var fhair = Array(31150, 31310, 31220, 31300, 31260, 31160, 31730, 31410, 31410) var hairnew = Array(); function start() { - cm.sendSimple("I'm the head of this hair salon Mani. If you have a #b#t5150031##k or a #b#t5151026##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L0#I want to buy a coupon!#l\r\n#L1#Haircut: #i5150031##t5150031##l\r\n#L2#Dye your hair: #i5151026##t5151026##l"); + cm.sendSimple("I'm the head of this hair salon Mani. If you have a #b#t5150031##k or a #b#t5151026##k, allow me to take care of your hairdo. Please choose the one you want.\r\n#L1#Haircut: #i5150031##t5150031##l\r\n#L2#Dye your hair: #i5151026##t5151026##l"); } function action(mode, type, selection) { @@ -47,10 +47,7 @@ function action(mode, type, selection) { else status--; if (status == 1) { - if (selection == 0) { - beauty = 0; - cm.sendSimple("Which coupon would you like to buy?\r\n#L0#Haircut for " + hairprice + " mesos: #i5150031##t5150031##l\r\n#L1#Dye your hair for " + haircolorprice + " mesos: #i5151026##t5151026##l"); - } else if (selection == 1) { + if (selection == 1) { beauty = 1; hairnew = Array(); if (cm.getPlayer().getGender() == 0) diff --git a/scripts/npc/9201065.js b/scripts/npc/9201065.js index d4db084759..7d73da7cdf 100644 --- a/scripts/npc/9201065.js +++ b/scripts/npc/9201065.js @@ -27,7 +27,7 @@ var price = 1000000; var skin = Array(0, 1, 2, 3, 4); function start() { - cm.sendSimple("Well, hello! Welcome to the NLC Skin-Care! Would you like to have a firm, tight, healthy looking skin like mine? With #b#t5153009##k, you can let us take care of the rest and have the kind of skin you've always wanted~!\r\n#L1#I would like to buy a #b#t5153009##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to the NLC Skin-Care! Would you like to have a firm, tight, healthy looking skin like mine? With #b#t5153009##k, you can let us take care of the rest and have the kind of skin you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } function action(mode, type, selection) { @@ -43,25 +43,19 @@ function action(mode, type, selection) { else status--; if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5153009, 1); - cm.sendOk("Enjoy!"); - } else - cm.sendOk("You don't have enough mesos to buy a coupon!"); - cm.dispose(); - } else if (selection == 2) + if (selection == 2) cm.sendStyle("With our specialized machine, you can see the way you'll look after the treatment PRIOR to the procedure. What kind of a look are you looking for? Go ahead and choose the style of your liking~!", skin); } else if (status == 2){ - cm.dispose(); if (cm.haveItem(5153009)){ cm.gainItem(5153009, -1); cm.setSkin(skin[selection]); cm.sendOk("Enjoy your new and improved skin!"); - } else + } else { cm.sendOk("Um...you don't have the skin-care coupon you need to receive the treatment. Sorry, but I am afraid we can't do it for you..."); + } + + cm.dispose(); } } } \ No newline at end of file diff --git a/scripts/npc/9201069.js b/scripts/npc/9201069.js index 92149e2eef..0495e04fb5 100644 --- a/scripts/npc/9201069.js +++ b/scripts/npc/9201069.js @@ -30,7 +30,7 @@ var fface = Array(21001, 21002, 21003, 21004, 21005, 21006, 21008, 21012, 21014, var facenew = Array(); function start() { - cm.sendSimple("Well, hello! Welcome to the New Leaf City Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152034##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L1#I would like to buy a #b#t5152034##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Well, hello! Welcome to the New Leaf City Plastic Surgery! Would you like to transform your face into something new? With a #b#t5152034##k, you can let us take care of the rest and have the face you've always wanted~!\r\n#L2#I already have a Coupon!#l"); } function action(mode, type, selection) { @@ -46,15 +46,7 @@ function action(mode, type, selection) { else status--; if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152034, 1); - cm.sendOk("Enjoy!"); - } else - cm.sendOk("You don't have enough mesos to buy a coupon!"); - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) for(var i = 0; i < mface.length; i++) @@ -66,13 +58,15 @@ function action(mode, type, selection) { } } else if (status == 2){ - cm.dispose(); if (cm.haveItem(5152034)){ cm.gainItem(5152034, -1); cm.setFace(facenew[selection]); cm.sendOk("Enjoy your new and improved face!"); - } else - cm.sendOk("Hmm ... it looks like you don't have the coupon specifically for this place. Sorry to say this, but without the coupon, there's no plastic surgery for you..."); + } else { + cm.sendOk("Hmm ... it looks like you don't have the coupon specifically for this place. Sorry to say this, but without the coupon, there's no plastic surgery for you..."); + } + + cm.dispose(); } } } diff --git a/scripts/npc/9201070.js b/scripts/npc/9201070.js index e3eed96002..b0b372f796 100644 --- a/scripts/npc/9201070.js +++ b/scripts/npc/9201070.js @@ -31,7 +31,7 @@ var fface = Array(21001, 21002, 21003, 21004, 21005, 21006, 21008, 21012, 21014, var facenew = Array(); function start() { - cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152033##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L1#I would like to buy a #b#t5152033##k for " + price + " mesos, please!#l\r\n\#L2#I already have a Coupon!#l"); + cm.sendSimple("Hi, I pretty much shouldn't be doing this, but with a #b#t5152033##k, I will do it anyways for you. But don't forget, it will be random!\r\n#L2#I already have a Coupon!#l"); } function action(mode, type, selection) { @@ -47,15 +47,7 @@ function action(mode, type, selection) { else status--; if (status == 1) { - if (selection == 1) { - if(cm.getMeso() >= price) { - cm.gainMeso(-price); - cm.gainItem(5152033, 1); - cm.sendOk("Enjoy!"); - } else - cm.sendOk("You don't have enough mesos to buy a coupon!"); - cm.dispose(); - } else if (selection == 2) { + if (selection == 2) { facenew = Array(); if (cm.getPlayer().getGender() == 0) for(var i = 0; i < mface.length; i++) @@ -66,13 +58,15 @@ function action(mode, type, selection) { cm.sendYesNo("If you use the regular coupon, your face may transform into a random new look...do you still want to do it using #b#t5152033##k?"); } } else if (status == 2){ - cm.dispose(); if (cm.haveItem(5152033)){ cm.gainItem(5152033, -1); cm.setFace(facenew[Math.floor(Math.random() * facenew.length)]); cm.sendOk("Enjoy your new and improved face!"); - } else + } else { cm.sendOk("Hmm ... it looks like you don't have the coupon specifically for this place. Sorry to say this, but without the coupon, there's no plastic surgery for you..."); + } + + cm.dispose(); } } } diff --git a/scripts/npc/9201135.js b/scripts/npc/9201135.js index 84a20758ea..6b0643b3a2 100644 --- a/scripts/npc/9201135.js +++ b/scripts/npc/9201135.js @@ -47,6 +47,7 @@ function start() { if (inMap[i] == cm.getPlayer().getMap().getId()) { if(inMap[i] == 550000000) { toMap[1][1] = cm.getPlayer().peekSavedLocation("WORLDTOUR"); + if(toMap[1][1] == -1) toMap[1][1] = 541000000; } location = i; @@ -116,6 +117,7 @@ function action(mode, type, selection) { } else { travelMap = cm.getPlayer().getSavedLocation("WORLDTOUR"); + if(travelMap == -1) travelMap = toMap[1][1]; } cm.warp(travelMap, travelSp); diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js index 66497492dc..73da2a4c3d 100644 --- a/scripts/npc/9977777.js +++ b/scripts/npc/9977777.js @@ -115,6 +115,7 @@ function writeFeatureTab_MonstersMapsReactors() { addFeature("Implemented Zombify disease status."); addFeature("Added Boss HP Bar for dozens of bosses."); addFeature("Game will favor showing the targeted boss HPbar."); + addFeature("Boss HPBar & Srv Message toggle - GabrielSin's idea."); addFeature("Dmg overtime on maps and neutralizers functional."); addFeature("Items will consistently stay within the walking area."); addFeature("Boats, elevator and other travel mechanics functional."); diff --git a/scripts/quest/2001.js b/scripts/quest/2001.js index 49669f72c4..79ed3f0c85 100644 --- a/scripts/quest/2001.js +++ b/scripts/quest/2001.js @@ -44,8 +44,8 @@ function end(mode, type, selection) { qm.gainItem(4003000, -30); qm.gainItem(4003001, -30); qm.gainItem(4001004, -1); - qm.gainExp(20000 * qm.getPlayer().getExpRate()); - qm.gainMeso(15000 * qm.getPlayer().getMesoRate()); + qm.gainExp(20000); + qm.gainMeso(15000); qm.gainFame(2); qm.completeQuest(); diff --git a/scripts/quest/2034.js b/scripts/quest/2034.js index b20c41ee7d..d123cc9aa0 100644 --- a/scripts/quest/2034.js +++ b/scripts/quest/2034.js @@ -35,7 +35,7 @@ function end(mode, type, selection) { qm.gainItem(item, 1); qm.gainItem(4000007, -150); - qm.gainExp(2200 * qm.getPlayer().getExpRate()); + qm.gainExp(2200); qm.completeQuest(); qm.sendOk("Alright, if you need work sometime down the road, feel free to come back and see me. This town sure can use a person like you for help~"); diff --git a/scripts/quest/20522.js b/scripts/quest/20522.js index 4ebfcc26a3..e4e52c9894 100644 --- a/scripts/quest/20522.js +++ b/scripts/quest/20522.js @@ -78,7 +78,7 @@ function end(mode, type, selection) { qm.forceCompleteQuest(); qm.gainItem(4220137, -1); - qm.gainExp(37600 * qm.getPlayer().getExpRate()); + qm.gainExp(37600); qm.dispose(); } diff --git a/scripts/quest/21703.js b/scripts/quest/21703.js index f700d0c139..e597d4190c 100644 --- a/scripts/quest/21703.js +++ b/scripts/quest/21703.js @@ -65,7 +65,7 @@ function end(mode, type, selection) { if (qm.isQuestStarted(21703)) { qm.forceCompleteQuest(); qm.teachSkill(21000000, qm.getPlayer().getSkillLevel(21000000), 10, -1); // Combo Ability Skill - qm.gainExp(2800 * qm.getPlayer().getExpRate()); + qm.gainExp(2800); } qm.sendNext("(You remembered the #bCombo Ability#k skill! You were skeptical of the training at first, since the old man suffers from Alzheimer's and all, but boy, was it effective!)", 2); qm.showInfo("Effect/BasicEff.img/AranGetSkill"); diff --git a/scripts/quest/21720.js b/scripts/quest/21720.js index 00e8bb6a15..e8039917d6 100644 --- a/scripts/quest/21720.js +++ b/scripts/quest/21720.js @@ -37,7 +37,7 @@ function end(mode, type, selection) { if (qm.getQuestStatus(21720) == 1) { qm.forceCompleteQuest(); qm.teachSkill(21001003, qm.getPlayer().getSkillLevel(21001003), 20, -1); - qm.gainExp(3900 * qm.getPlayer().getExpRate()); + qm.gainExp(3900); } qm.showIntro("Effect/BasicEff.img/AranGetSkill"); qm.sendNext('#b(You remembered the Polearm Booster skill!)#k', 2); diff --git a/scripts/quest/21728.js b/scripts/quest/21728.js index b212bb7c2f..4795cf915e 100644 --- a/scripts/quest/21728.js +++ b/scripts/quest/21728.js @@ -39,7 +39,7 @@ function end(mode, type, selection) { qm.sendNext("You haven't found the #rPuppeteer's cave#k yet, did you?"); } else { qm.sendNext("Hm, so the entrance is blocked by a powerful force? I see, gimme a time to think now..."); - qm.gainExp(200 * qm.getPlayer().getExpRate()); + qm.gainExp(200); qm.forceCompleteQuest(); } diff --git a/scripts/quest/21733.js b/scripts/quest/21733.js index 198d31a296..5f00ad6dab 100644 --- a/scripts/quest/21733.js +++ b/scripts/quest/21733.js @@ -62,7 +62,7 @@ function end(mode, type, selection) { } else if(status == 1) { qm.sendNext("I will teach you the #rPolearm Mastery#k skill, to reward your actions here. You will be able to improve your accuracy and the overall mastery of your polearm arts."); } else { - qm.gainExp(8000 * qm.getPlayer().getExpRate()); + qm.gainExp(8000); qm.teachSkill(21100000, 0, 20, -1); // polearm mastery qm.forceCompleteQuest(); diff --git a/scripts/quest/21734.js b/scripts/quest/21734.js index 109068e345..a5fa4b7f96 100644 --- a/scripts/quest/21734.js +++ b/scripts/quest/21734.js @@ -64,7 +64,7 @@ function end(mode, type, selection) { } else if(status == 2) { qm.sendNext("For your bravery inputted on these series of missions, I will now reward you properly. Behold, the #rCombo Drain#k Skill: that let's you heal back a portion of damage dealt to the monsters."); } else { - qm.gainExp(12500 * qm.getPlayer().getExpRate()); + qm.gainExp(12500); qm.teachSkill(21100005, 0, 20, -1); // combo drain qm.forceCompleteQuest(); diff --git a/scripts/quest/21735.js b/scripts/quest/21735.js index 2ce1c84b51..3d4cd3a6de 100644 --- a/scripts/quest/21735.js +++ b/scripts/quest/21735.js @@ -72,7 +72,7 @@ function end(mode, type, selection) { } } else if (status == 1) { qm.gainItem(4032323, -1); - qm.gainExp(6037 * qm.getPlayer().getExpRate()); + qm.gainExp(6037); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/21739.js b/scripts/quest/21739.js index c8e3d0dbdd..94f544f74f 100644 --- a/scripts/quest/21739.js +++ b/scripts/quest/21739.js @@ -37,7 +37,7 @@ function end(mode, type, selection) { if(status == 0) { qm.sendNext("So, have you defeated the giant? Oh, a Black Wing agent undercover? And he GOT THE SEAL STONE OF ORBIS?! Oh, no. That's horrible! We need to develop countermeasures as soon as possible! Tell the informant on Lith about the situation."); } else { - qm.gainExp(29500 * qm.getPlayer().getExpRate()); + qm.gainExp(29500); qm.forceCompleteQuest(); qm.dispose(); } diff --git a/scripts/quest/21742.js b/scripts/quest/21742.js index 01cb2d3988..d77ade41dd 100644 --- a/scripts/quest/21742.js +++ b/scripts/quest/21742.js @@ -88,7 +88,7 @@ function end(mode, type, selection) { } else if (status == 1) { qm.gainItem(4032342, -8); qm.gainItem(4220151, -1); - qm.gainExp(10000 * qm.getPlayer().getExpRate()); + qm.gainExp(10000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/21746.js b/scripts/quest/21746.js index cf701c1bd4..d7a641e604 100644 --- a/scripts/quest/21746.js +++ b/scripts/quest/21746.js @@ -73,7 +73,7 @@ function end(mode, type, selection) { } else if (status == 1) { qm.gainItem(4032342, -8); qm.gainItem(4220151, -1); - qm.gainExp(10000 * qm.getPlayer().getExpRate()); + qm.gainExp(10000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/21747.js b/scripts/quest/21747.js index c3d701502e..c09bd38375 100644 --- a/scripts/quest/21747.js +++ b/scripts/quest/21747.js @@ -64,7 +64,7 @@ function end(mode, type, selection) { } else if (status == 1) { qm.sendNext("But yet, something made you unhappy. What could it be? ... No... Black Wings took away the Seal stone? I'm afraid nothing can be done anymore. I suggest you return to your group tactician, Tru is it?, and tell him about the situation now. Tell him about the loss here in Mu Lung. There's no time to lose, hurry!"); } else if (status == 2) { - qm.gainExp(16000 * qm.getPlayer().getExpRate()); + qm.gainExp(16000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/21748.js b/scripts/quest/21748.js index bb84505fa2..f3044454d2 100644 --- a/scripts/quest/21748.js +++ b/scripts/quest/21748.js @@ -39,7 +39,7 @@ function end(mode, type, selection) { } else if (status == 1) { qm.sendNext("I've researched some skill books, trying to trace any lost skills of yours. Good news I found one of them: it's the #rFinal Charge#k! With it you will be able to draw closer opposing monsters at each swipe. It's a fine improvement for your arsenal, isn't it?"); } else if (status == 2) { - qm.gainExp(20000 * qm.getPlayer().getExpRate()); + qm.gainExp(20000); qm.teachSkill(21100002, 0, 30, -1); // final charge qm.forceCompleteQuest(); diff --git a/scripts/quest/21749.js b/scripts/quest/21749.js index 24e7a4d488..e628d27071 100644 --- a/scripts/quest/21749.js +++ b/scripts/quest/21749.js @@ -39,7 +39,7 @@ function start(mode, type, selection) { } else if (status == 1) { qm.sendNext("Aran, your next objective will be to use the #btime gate to Ellin#k again. This time you will be retrieving the long lost #rSeal Stone of Ellin Forest#k. According to informations our network have gathered, #b#p2131002##k of that time have a clue about that gem, #rfind her#k. Please be successful on this task, our world is relying on you more than ever!"); } else { - qm.gainExp(500 * qm.getPlayer().getExpRate()); + qm.gainExp(500); qm.forceCompleteQuest(); qm.dispose(); } diff --git a/scripts/quest/21757.js b/scripts/quest/21757.js index d5001fce1b..71dcf57805 100644 --- a/scripts/quest/21757.js +++ b/scripts/quest/21757.js @@ -37,7 +37,7 @@ function end(mode, type, selection) { if (status == 0) { qm.sendNext("Oh, a letter for the #rempress#k? From the #bheroes#k?!"); } else { - qm.gainExp(1000 * qm.getPlayer().getExpRate()); + qm.gainExp(1000); qm.gainItem(4032330, -1); qm.forceCompleteQuest(); diff --git a/scripts/quest/21766.js b/scripts/quest/21766.js index 3aaebdeb48..8c55c5323d 100644 --- a/scripts/quest/21766.js +++ b/scripts/quest/21766.js @@ -17,7 +17,7 @@ function start(mode, type, selection) { } function end(mode, type, selection) { - qm.gainExp(200 * qm.getPlayer().getExpRate()); + qm.gainExp(200); qm.forceCompleteQuest(); qm.dispose(); } \ No newline at end of file diff --git a/scripts/quest/2186.js b/scripts/quest/2186.js index aa91a92299..5361dd9c9e 100644 --- a/scripts/quest/2186.js +++ b/scripts/quest/2186.js @@ -8,7 +8,7 @@ function end(mode, type, selection){ if(qm.haveItem(4031853)){ if(qm.canHold(2030019)) { qm.gainItem(4031853, -1); - qm.gainExp(1700 * qm.getPlayer().getExpRate()); + qm.gainExp(1700); qm.gainItem(2030019, 10); qm.sendOk("Geez, you found my glasses! Thank you, thank you so much. Now I'm able to see everything again!"); @@ -24,7 +24,7 @@ function end(mode, type, selection){ else qm.gainItem(4031855, -1); - qm.gainExp(1000 * qm.getPlayer().getExpRate()); + qm.gainExp(1000); qm.gainItem(2030019, 5); qm.sendOk("Hm, those aren't my glasses... But alas, I'll take it anyway. Thanks."); diff --git a/scripts/quest/2214.js b/scripts/quest/2214.js index 78a1845db6..e76ce9d2ef 100644 --- a/scripts/quest/2214.js +++ b/scripts/quest/2214.js @@ -57,7 +57,7 @@ function end(mode, type, selection) { qm.sendNext("(Ah, there is a crumbled note here... Hm, it contains details about some scheme that is about to happen, that must be what #r#p1052002##k was talking about.)"); qm.gainItem(4031894, 1); - qm.gainExp(20000 * qm.getPlayer().getExpRate()); + qm.gainExp(20000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/2216.js b/scripts/quest/2216.js index 3723fa7367..0816921512 100644 --- a/scripts/quest/2216.js +++ b/scripts/quest/2216.js @@ -36,7 +36,7 @@ function start(mode, type, selection) { if (status == 0) { qm.sendNext("I've just gathered an interesting information, #rDyle looks just like regular Ligators#k, but bigger."); - qm.gainExp(7000 * qm.getPlayer().getExpRate()); + qm.gainExp(7000); qm.forceCompleteQuest(); if(isAllSubquestsDone() && qm.haveItem(4031894)) { diff --git a/scripts/quest/2217.js b/scripts/quest/2217.js index 1b6f5946c3..72b4e81f33 100644 --- a/scripts/quest/2217.js +++ b/scripts/quest/2217.js @@ -36,7 +36,7 @@ function start(mode, type, selection) { if (status == 0) { qm.sendNext("Hey, did you notice already, it looks like some awful stench is emanating from the sewers... Ewww"); - qm.gainExp(7000 * qm.getPlayer().getExpRate()); + qm.gainExp(7000); qm.forceCompleteQuest(); if(isAllSubquestsDone() && qm.haveItem(4031894)) { diff --git a/scripts/quest/2218.js b/scripts/quest/2218.js index d7a71f6183..80d8ee7748 100644 --- a/scripts/quest/2218.js +++ b/scripts/quest/2218.js @@ -36,7 +36,7 @@ function start(mode, type, selection) { if (status == 0) { qm.sendNext("Hey did you see how strange #rLakelis#k has been acting these days? We should see what's going on aabout her, her actions have been so weird lately..."); - qm.gainExp(7000 * qm.getPlayer().getExpRate()); + qm.gainExp(7000); qm.forceCompleteQuest(); if(isAllSubquestsDone() && qm.haveItem(4031894)) { diff --git a/scripts/quest/2219.js b/scripts/quest/2219.js index 05195ba79f..ee04b77db9 100644 --- a/scripts/quest/2219.js +++ b/scripts/quest/2219.js @@ -36,7 +36,7 @@ function start(mode, type, selection) { if (status == 0) { qm.sendNext("Did you know, they say someone from the sewers has been trying to #rdevelop a magic powder that let's one to grow#k, isn't that nice?"); - qm.gainExp(7000 * qm.getPlayer().getExpRate()); + qm.gainExp(7000); qm.forceCompleteQuest(); if(isAllSubquestsDone() && qm.haveItem(4031894)) { diff --git a/scripts/quest/2236.js b/scripts/quest/2236.js index 355d903c94..e460077dd0 100644 --- a/scripts/quest/2236.js +++ b/scripts/quest/2236.js @@ -38,7 +38,7 @@ function end(mode, type, selection) { if(status == 0) { if(qm.getQuestProgress(2236) == 63) { //111111 qm.sendOk("I, too, felt it. The force of the Shaman Rocks began to overpower the forces of evil. I think Sleepywood is safe now. The evil has been eliminated."); - qm.gainExp(60000 * qm.getPlayer().getExpRate()); + qm.gainExp(60000); qm.forceCompleteQuest(); } else { diff --git a/scripts/quest/2251.js b/scripts/quest/2251.js index 37272f856b..31b5cbf4f0 100644 --- a/scripts/quest/2251.js +++ b/scripts/quest/2251.js @@ -13,7 +13,7 @@ function end(mode, type, selection) { else { qm.gainItem(4032399, -20); qm.sendOk("Oh, you brought 20 #b#t4032399##k! Thank you."); - qm.gainExp(8000 * qm.getPlayer().getExpRate()); + qm.gainExp(8000); qm.forceCompleteQuest(); } diff --git a/scripts/quest/2293.js b/scripts/quest/2293.js index 1119170795..c19bb7064c 100644 --- a/scripts/quest/2293.js +++ b/scripts/quest/2293.js @@ -102,7 +102,7 @@ function end(mode, type, selection) else if(selection == 3) { qm.sendOk("So that was the song he was playing... Well, it wasn't my song after all, but I'm glad I can know that now with certainty. Thank you so much."); - qm.gainExp(32500 * qm.getPlayer().getExpRate()); + qm.gainExp(32500); qm.forceCompleteQuest(); qm.dispose(); } diff --git a/scripts/quest/2300.js b/scripts/quest/2300.js index d89202d78b..ecf094dc08 100644 --- a/scripts/quest/2300.js +++ b/scripts/quest/2300.js @@ -57,6 +57,7 @@ function end(mode, type, selection) { qm.sendNextPrev("Hmmm... okay. Since the letter is from the job instructor, I suppose you are really the one. I apologize for not introducing myself to you earlier. I'm the #bHead Security Officer#k in charge of protecting King Mush. As you can see, this temporary hideout is protected by the team of security and soldiers. Our situation may be dire, but nevertheless, welcome to Kingdom of Mushroom."); if(status == 2){ qm.gainItem(4032375, -1); + qm.gainExp(6000); qm.forceCompleteQuest(); qm.forceStartQuest(2312); qm.dispose(); diff --git a/scripts/quest/2312.js b/scripts/quest/2312.js index 2d6f7edc48..3b667a8d61 100644 --- a/scripts/quest/2312.js +++ b/scripts/quest/2312.js @@ -46,7 +46,7 @@ function end(mode, type, selection) { qm.sendOk("Did you teach those Renegade Spores a lesson?"); if (status == 1){ qm.forceCompleteQuest(); - qm.gainExp(11500 * qm.getPlayer().getExpRate()); + qm.gainExp(11500); qm.gainItem(4000499, -50); qm.sendOk("That was amazing. I apologize for doubting your abilities. Please save our Kingdom of Mushroom from this crisis!"); qm.dispose(); diff --git a/scripts/quest/2313.js b/scripts/quest/2313.js index 6f8fb102ad..40b9d04010 100644 --- a/scripts/quest/2313.js +++ b/scripts/quest/2313.js @@ -44,7 +44,7 @@ function end(mode, type, selection) { } if (status == 0) { qm.forceCompleteQuest(); - qm.gainExp(4000 * qm.getPlayer().getExpRate()); + qm.gainExp(4000); qm.dispose(); } } diff --git a/scripts/quest/2314.js b/scripts/quest/2314.js index bd9a8ac7c2..cfa542d54f 100644 --- a/scripts/quest/2314.js +++ b/scripts/quest/2314.js @@ -28,7 +28,7 @@ function start(mode, type, selection) { if(status == 2){ //qm.forceStartQuest(); //qm.forceStartQuest(2314,"1"); - qm.gainExp(8300 * qm.getPlayer().getExpRate()); + qm.gainExp(8300); qm.sendOk("I see, so it was indeed not a regular barrier by any means. Great work there. If not for you help, we wouldn't have had a clue as to what that was all about."); qm.forceCompleteQuest(); qm.dispose(); @@ -48,7 +48,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("I see that you have thoroughly investigated the barrier at the Mushroom Forest. What was it like?"); if (status == 1){ - qm.gainExp(8300 * qm.getPlayer().getExpRate()); + qm.gainExp(8300); qm.sendOk("I see, so it was indeed not a regular barrier by any means. Great work there. If not for you help, we wouldn't have had a clue as to what that was all about."); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/2315.js b/scripts/quest/2315.js index f219764a57..e345ab6e2a 100644 --- a/scripts/quest/2315.js +++ b/scripts/quest/2315.js @@ -45,7 +45,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("What? You investigated the barrier at the Mushroom Forest?"); if (status == 1){ - qm.gainExp(4000 * qm.getPlayer().getExpRate()); + qm.gainExp(4000); qm.sendOk("Hmmm...this is interesting. It's a barrier set up by someone with a powerful force of magic, which means there's no way we can manually break through it."); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/2316.js b/scripts/quest/2316.js index 9bf1c76e53..3b15ff46e8 100644 --- a/scripts/quest/2316.js +++ b/scripts/quest/2316.js @@ -45,7 +45,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("Ah, so you're the explorer people were talking about. I'm #bScarrs, the Royal Mushroom Scholar#k representing the Kingdom of Mushroom. So you need some #kKiller Mushroom Spores#k?"); if (status == 1){ - qm.gainExp(4200 * qm.getPlayer().getExpRate()); + qm.gainExp(4200); qm.sendOk("#kKiller Mushroom Spores#k... I think i've heard of them before..."); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/2317.js b/scripts/quest/2317.js index caf58b555b..359cd2b951 100644 --- a/scripts/quest/2317.js +++ b/scripts/quest/2317.js @@ -45,7 +45,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("Have you gathered up the 100 Poison Mushroom Caps like I asked you to get?"); if (status == 1){ - qm.gainExp(13500 * qm.getPlayer().getExpRate()); + qm.gainExp(13500); qm.gainItem(4000500, -100); qm.sendOk("I am amazed that you were able to gather up these 100 Poison Mushroom Caps, which is considered a difficult feat. I think I'll be able to make #bKiller Mushroom Spores#k our of these."); qm.forceCompleteQuest(); diff --git a/scripts/quest/2318.js b/scripts/quest/2318.js index 3b5d7032ce..3babb9a864 100644 --- a/scripts/quest/2318.js +++ b/scripts/quest/2318.js @@ -45,7 +45,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("Did you gather up all the necessary ingredients for it?") if (status == 1){ - qm.gainExp(11500 * qm.getPlayer().getExpRate()); + qm.gainExp(11500); qm.gainItem(4000499, -50); qm.sendNext("Okay, these should be enough for me to make the #bKiller Mushroom Spores.#k Please hold on for a bit."); qm.forceCompleteQuest(); diff --git a/scripts/quest/2319.js b/scripts/quest/2319.js index ac8484137c..8f5e650664 100644 --- a/scripts/quest/2319.js +++ b/scripts/quest/2319.js @@ -46,7 +46,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("Are the #bKiller Mushroom Spores#k finally completed?"); if (status == 1){ - qm.gainExp(4200 * qm.getPlayer().getExpRate()); + qm.gainExp(4200); qm.gainItem(4032389, -1); qm.sendOk("Okay, so this is the #bKiller Mushroom Spores.#k Thank you, thank you, and please tell #bScarrs#k the same."); qm.forceCompleteQuest(); diff --git a/scripts/quest/2320.js b/scripts/quest/2320.js index 91d82dbbc6..cf5e5d389f 100644 --- a/scripts/quest/2320.js +++ b/scripts/quest/2320.js @@ -46,7 +46,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("Oh! You're here on behalf of #bScarrs#k? \r\n\r\n#fUI/UIWindow.img/QuestIcon/4/0# \r\n#fUI/UIWindow.img/QuestIcon/8/0# 8800 exp"); if (status == 1){ - qm.gainExp(8800 * qm.getPlayer().getExpRate()); + qm.gainExp(8800); qm.gainItem(4032389, -1); qm.sendOk("Ahh, so this is the #bKiller Mushroom Spores#k that I was working on in the past. I had a tough time gathering up the ingredients, so I left it in theory only, but he was able to complete it, with a sample to show for as well. Please tell him I appreciate his good work."); qm.forceCompleteQuest(); diff --git a/scripts/quest/2321.js b/scripts/quest/2321.js index 186919f8af..8b54b52f23 100644 --- a/scripts/quest/2321.js +++ b/scripts/quest/2321.js @@ -45,7 +45,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("I have been keeping up on your fabulour work. I am aware that you have successfully created the #bKiller Mushroom Spores#k, which penetrates through the unpenetrable barrier of the forest. Congratulations!"); if (status == 1){ - qm.gainExp(2500 * qm.getPlayer().getExpRate()); + qm.gainExp(2500); qm.sendOk("The problem now is to figure out how to enter the castle."); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/2322.js b/scripts/quest/2322.js index 040641a3d6..fd114c25d1 100644 --- a/scripts/quest/2322.js +++ b/scripts/quest/2322.js @@ -30,7 +30,7 @@ function start(mode, type, selection) { if (status == 2){ //qm.forceStartQuest(); //qm.forceStartQuest(2322, "1"); - qm.gainExp(11000 * qm.getPlayer().getExpRate()); + qm.gainExp(11000); qm.sendOk("Good job navigating through the area."); qm.forceCompleteQuest(); qm.dispose(); @@ -50,7 +50,7 @@ function end(mode, type, selection) { if (status == 0) qm.sendOk("Hmmm I see... so they have completely shut off the entrance and everything."); if (status == 1){ - qm.gainExp(11000 * qm.getPlayer().getExpRate()); + qm.gainExp(11000); qm.sendOk("Good job navigating through the area."); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/2325.js b/scripts/quest/2325.js index 2704bba250..4154deb9d5 100644 --- a/scripts/quest/2325.js +++ b/scripts/quest/2325.js @@ -24,7 +24,7 @@ function end(mode, type, selection){ else if(status == 2){ qm.sendOk("What? My brother sent you here? Ahhh... I am safe now. Thank you so much..."); qm.forceCompleteQuest(); - qm.gainExp(6000 * qm.getPlayer().getExpRate()); + qm.gainExp(6000); qm.dispose(); } } \ No newline at end of file diff --git a/scripts/quest/2333.js b/scripts/quest/2333.js index 2eea658d7c..d8164d0af3 100644 --- a/scripts/quest/2333.js +++ b/scripts/quest/2333.js @@ -51,7 +51,7 @@ function end(mode, type, selection){ qm.sendNext("Hurray! #b#h ##k you defeated the #bPrime Minister#k."); } else if(status == 1){ - qm.gainExp(15000 * qm.getPlayer().getExpRate()); + qm.gainExp(15000); qm.forceCompleteQuest(); var eim = qm.getEventInstance(); diff --git a/scripts/quest/2334.js b/scripts/quest/2334.js index ac0e2aea87..bc0b739984 100644 --- a/scripts/quest/2334.js +++ b/scripts/quest/2334.js @@ -37,7 +37,7 @@ function start(mode, type, selection){ } else if(status == 6){ qm.forceStartQuest(); - qm.gainExp(1000 * qm.getPlayer().getExpRate()); + qm.gainExp(1000); qm.forceCompleteQuest(); qm.dispose(); } diff --git a/scripts/quest/3239.js b/scripts/quest/3239.js index ccccf5fdec..a73a15fdf6 100644 --- a/scripts/quest/3239.js +++ b/scripts/quest/3239.js @@ -17,7 +17,7 @@ function end(mode, type, selection) { else if(rnd == 2) qm.gainItem(2040707, 1); else qm.gainItem(2040708, 1); - qm.gainExp(2700 * qm.getPlayer().getExpRate()); + qm.gainExp(2700); qm.forceCompleteQuest(); } else { diff --git a/scripts/quest/3311.js b/scripts/quest/3311.js index 5f382b58c0..ee0f6e054e 100644 --- a/scripts/quest/3311.js +++ b/scripts/quest/3311.js @@ -37,7 +37,7 @@ function end(mode, type, selection) { if (status == 0) { if(qm.getQuestProgress(3311, 0) == 1 && qm.getQuestProgress(3311, 1) == 1) { qm.sendNext("Hmm, so the Alcadno doctor wrote something about researching some vanguardist Neo Huroid machine, that could beat by far the existing one, and was about to prepare the last steps of his rehearsal? We don't have a word about him for about three weeks now, something must have gone wrong..."); - qm.gainExp(60000 * qm.getPlayer().getExpRate()); + qm.gainExp(60000); qm.forceCompleteQuest(); } else { qm.sendNext("Found nothing yet? Please check out Dr. De Lang's house properly, something there may give out a clue about what is going on."); diff --git a/scripts/quest/3314.js b/scripts/quest/3314.js index ba26a7611b..576717e7dc 100644 --- a/scripts/quest/3314.js +++ b/scripts/quest/3314.js @@ -45,7 +45,7 @@ function end(mode, type, selection) { if(qm.canHoldAll([2050004, 2022224], [10, 20])) { qm.sendNext("You did took my experiments. Hmm, so THAT is the result of it, hehehehe... Ok, take that as compensation will you? And oh, you can #rspew that#k right away (#bright-click on the pill icon at the top-right corner of the screen#k), no worries."); - qm.gainExp(12500 * qm.getPlayer().getExpRate()); + qm.gainExp(12500); qm.gainItem(2050004, 10); var i = Math.floor(Math.random() * 5); diff --git a/scripts/quest/3345.js b/scripts/quest/3345.js index a136643d35..83cb1b74ac 100644 --- a/scripts/quest/3345.js +++ b/scripts/quest/3345.js @@ -39,7 +39,7 @@ function end(mode, type, selection) { qm.sendNext("So, you have succeeded. With this, Magatia's upfront demise has been averted, well done brave adventurer!"); qm.forceCompleteQuest(); - qm.gainExp(20000 * qm.getPlayer().getExpRate()); + qm.gainExp(20000); } else { qm.sendNext("Did you not seal the #rmagic circle beneath Magatia#k yet? It is a matter of great importance, please haste yourself."); } diff --git a/scripts/quest/3414.js b/scripts/quest/3414.js index acd2aa4e76..26c5a87aca 100644 --- a/scripts/quest/3414.js +++ b/scripts/quest/3414.js @@ -44,7 +44,7 @@ function end(mode, type, selection) { qm.gainItem(4031104, -1); qm.gainItem(4031105, -1); qm.gainItem(4031106, -1); - qm.gainExp(12000 * qm.getPlayer().getExpRate()); + qm.gainExp(12000); qm.completeQuest(); qm.dispose(); diff --git a/scripts/quest/3414_free10rate.js b/scripts/quest/3414_free10rate.js index 74c65e63b9..fa84eab33f 100644 --- a/scripts/quest/3414_free10rate.js +++ b/scripts/quest/3414_free10rate.js @@ -36,7 +36,7 @@ function end(mode, type, selection) { item = qm.gainItem(item, 1); if (item != null) { - qm.gainExp(12000 * qm.getPlayer().getExpRate()); + qm.gainExp(12000); qm.completeQuest(); } diff --git a/scripts/quest/3437.js b/scripts/quest/3437.js index 986e7f591e..2a3f4b1d5f 100644 --- a/scripts/quest/3437.js +++ b/scripts/quest/3437.js @@ -40,7 +40,7 @@ function end(mode, type, selection) { qm.gainItem(item, 1); qm.gainItem(4000122, -120); - qm.gainExp(6100 * qm.getPlayer().getExpRate()); + qm.gainExp(6100); qm.completeQuest(); qm.sendOk("Thank you so much for fulfilling your missions as one of the Mesorangers. I've told the Sector about your successful story, and the Sector seems to be very pleased with you, too. Hopefully you'll keep working with us. Bye~"); diff --git a/scripts/quest/3452.js b/scripts/quest/3452.js index 36cc817250..82c02a1ab2 100644 --- a/scripts/quest/3452.js +++ b/scripts/quest/3452.js @@ -15,7 +15,7 @@ function end(mode, type, selection) { if(qm.getPlayer().getInventory(Packages.client.inventory.MapleInventoryType.USE).getNumFreeSlot() >= 1) { qm.gainItem(4000099, -1); qm.gainItem(2000011, 50); - qm.gainExp(8000 * qm.getPlayer().getExpRate()); + qm.gainExp(8000); qm.forceCompleteQuest(); } else { diff --git a/scripts/quest/3514.js b/scripts/quest/3514.js index 3da41bc370..696e6bbcea 100644 --- a/scripts/quest/3514.js +++ b/scripts/quest/3514.js @@ -78,7 +78,7 @@ function end(mode, type, selection) { qm.sendOk("It seems the potion worked and your emotions are no longer frozen. And, oh, my... You're ailing bad, #bpurge#k that out quickly."); } } else if(status == 1) { - qm.gainExp(891500 * qm.getPlayer().getExpRate()); + qm.gainExp(891500); qm.completeQuest(3514); qm.dispose(); } diff --git a/scripts/quest/3714.js b/scripts/quest/3714.js index fce4608172..c724911816 100644 --- a/scripts/quest/3714.js +++ b/scripts/quest/3714.js @@ -44,7 +44,7 @@ function start(mode, type, selection) { qm.sendNext("You have brought a #b#t4001094##k, thank you for the effort!"); } else if (status == 1) { qm.gainItem(4001094, -1); - qm.gainExp(42000 * qm.getPlayer().getExpRate()); + qm.gainExp(42000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/3833.js b/scripts/quest/3833.js index b7d8fabf9f..7e1a3a482b 100644 --- a/scripts/quest/3833.js +++ b/scripts/quest/3833.js @@ -15,40 +15,40 @@ function end(mode, type, selection) { qm.gainItem(4000294, -1000); qm.gainItem(2040501, 1); qm.gainItem(2000005, 50); - qm.gainExp(54000 * qm.getPlayer().getExpRate()); + qm.gainExp(54000); qm.forceCompleteQuest(); } else if(qm.haveItem(4000294, 600)) { qm.gainItem(4000294, -600); qm.gainItem(2020013, 50); - qm.gainExp(54000 * qm.getPlayer().getExpRate()); + qm.gainExp(54000); qm.forceCompleteQuest(); } else if(qm.haveItem(4000294, 500)) { qm.gainItem(4000294, -500); - qm.gainExp(54000 * qm.getPlayer().getExpRate()); + qm.gainExp(54000); qm.forceCompleteQuest(); } else if(qm.haveItem(4000294, 100)) { qm.gainItem(4000294, -100); - qm.gainExp(45000 * qm.getPlayer().getExpRate()); + qm.gainExp(45000); qm.forceCompleteQuest(); } else if(qm.haveItem(4000294, 50)) { qm.gainItem(4000294, -50); qm.gainItem(2020007, 50); - qm.gainExp(10000 * qm.getPlayer().getExpRate()); + qm.gainExp(10000); qm.forceCompleteQuest(); } else if(qm.haveItem(4000294, 1)) { qm.gainItem(4000294, -1); qm.gainItem(2000000, 1); - qm.gainExp(10 * qm.getPlayer().getExpRate()); + qm.gainExp(10); qm.forceCompleteQuest(); } } diff --git a/scripts/quest/3926.js b/scripts/quest/3926.js index e0ecac3644..4a6bf56015 100644 --- a/scripts/quest/3926.js +++ b/scripts/quest/3926.js @@ -47,7 +47,7 @@ function end(mode, type, selection) { if(c == 4) { qm.sendNext("You delivered all the jewels, well done!"); - qm.gainExp(6500 * qm.getPlayer().getExpRate()); + qm.gainExp(6500); qm.forceCompleteQuest(); } else { qm.sendNext("Have you brought all the jewels from the Red Scorpions? They have to be delivered to the Residential areas of the Sand Bandits."); diff --git a/scripts/quest/3927.js b/scripts/quest/3927.js index a1627dee23..5fb4319180 100644 --- a/scripts/quest/3927.js +++ b/scripts/quest/3927.js @@ -63,7 +63,7 @@ function end(mode, type, selection) { return; } } else if (status == 3) { - qm.gainExp(1000 * qm.getPlayer().getExpRate()); + qm.gainExp(1000); qm.forceCompleteQuest(); qm.dispose(); } diff --git a/scripts/quest/3929.js b/scripts/quest/3929.js index 463bcc2335..205cd60561 100644 --- a/scripts/quest/3929.js +++ b/scripts/quest/3929.js @@ -48,7 +48,7 @@ function end(mode, type, selection) { if(c == 4) { qm.sendNext("You delivered all the food, good."); - qm.gainExp(2000 * qm.getPlayer().getExpRate()); + qm.gainExp(2000); qm.forceCompleteQuest(); } else { var missed = (4 - qm.getItemQuantity(4031580)) - c; diff --git a/scripts/quest/3953.js b/scripts/quest/3953.js index f68cb68d4d..d338f06545 100644 --- a/scripts/quest/3953.js +++ b/scripts/quest/3953.js @@ -46,7 +46,7 @@ function end(mode, type, selection) { qm.gainItem(4011008, -1); qm.sendNext("We're in great trouble, if it is like this. And it really seems like it. If the Royal Cactus Deo has gone insane, Ariant is done for. You, can you do something to defeat Deo? We really need your help now."); - qm.gainExp(20000 * qm.getPlayer().getExpRate()); + qm.gainExp(20000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/6033.js b/scripts/quest/6033.js index b054b7cd06..a44563086f 100644 --- a/scripts/quest/6033.js +++ b/scripts/quest/6033.js @@ -52,7 +52,7 @@ function end(mode, type, selection) { var skillid = Math.floor(qm.getPlayer().getJob().getId() / 1000) * 10000000 + 1007; qm.teachSkill(skillid, 2, 3, -1); - qm.gainExp(230000 * qm.getPlayer().getExpRate()); + qm.gainExp(230000); qm.forceCompleteQuest(); qm.dispose(); } diff --git a/scripts/quest/6036.js b/scripts/quest/6036.js index 12d485ffc7..b04c3e9c85 100644 --- a/scripts/quest/6036.js +++ b/scripts/quest/6036.js @@ -54,7 +54,7 @@ function end(mode, type, selection) { var skillid = Math.floor(qm.getPlayer().getJob().getId() / 1000) * 10000000 + 1007; qm.teachSkill(skillid, 3, 3, -1); - qm.gainExp(300000 * qm.getPlayer().getExpRate()); + qm.gainExp(300000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/scripts/quest/8219.js b/scripts/quest/8219.js index 33f63377ae..d99e0bfd81 100644 --- a/scripts/quest/8219.js +++ b/scripts/quest/8219.js @@ -49,7 +49,7 @@ function end(mode, type, selection) { else if (status == 2){ if(qm.canHold(3992040, 1)) { qm.gainItem(3992040, 1); - qm.gainExp(175000 * qm.getPlayer().getExpRate()); + qm.gainExp(175000); qm.forceCompleteQuest(); } else { diff --git a/scripts/quest/8229.js b/scripts/quest/8229.js index c489299daa..afd261e086 100644 --- a/scripts/quest/8229.js +++ b/scripts/quest/8229.js @@ -55,7 +55,7 @@ function end(mode, type, selection) { } } else if (status == 1){ qm.gainItem(4032018, -1); - qm.gainExp(50000 * qm.getPlayer().getExpRate()); + qm.gainExp(50000); qm.forceCompleteQuest(); qm.dispose(); diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index bbeb373149..ae84f877d2 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -261,7 +261,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { private Map summons = new LinkedHashMap<>(); private Map coolDowns = new LinkedHashMap<>(); private EnumMap> diseases = new EnumMap<>(MapleDisease.class); - private Map doors = new LinkedHashMap<>(); + private MapleDoor pdoor = null; private Map questExpirations = new LinkedHashMap<>(); private ScheduledFuture dragonBloodSchedule; private ScheduledFuture hpDecreaseTask; @@ -277,6 +277,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { private ScheduledFuture pendantOfSpirit = null; //1122017 private Lock chrLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_CHR, true); private Lock effLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EFF, true); + private Lock evtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_EVT, true); private Lock petLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PET, true); // for quest tasks as well private Lock prtLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CHARACTER_PRT); private Map> excluded = new LinkedHashMap<>(); @@ -343,7 +344,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { quests = new LinkedHashMap<>(); setPosition(new Point(0, 0)); - petLootCd = System.currentTimeMillis(); + petLootCd = Server.getInstance().getCurrentTime(); } private static MapleJob getJobStyleInternal(int jobid, byte opt) { @@ -586,25 +587,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } return pts; } - - public void addDoor(Integer owner, MapleDoor door) { - chrLock.lock(); - try { - doors.put(owner, door); - } finally { - chrLock.unlock(); - } - } - public void removeDoor(Integer owner) { - chrLock.lock(); - try { - doors.remove(owner); - } finally { - chrLock.unlock(); - } - } - public void addFame(int famechange) { this.fame += famechange; } @@ -889,13 +872,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { this.loggedIn = true; c.setAccountName(this.client.getAccountName());//No null's for accountName this.client = c; + this.map = c.getChannelServer().getMapFactory().getMap(getMapId()); MaplePortal portal = map.findClosestPlayerSpawnpoint(getPosition()); if (portal == null) { portal = map.getPortal(0); } this.setPosition(portal.getPosition()); this.initialSpawnPoint = portal.getId(); - this.map = c.getChannelServer().getMapFactory().getMap(getMapId()); } public String getMedalText() { @@ -1352,9 +1335,13 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public void changeMap(MapleMap to) { - changeMap(to, to.getPortal(0)); + changeMap(to, 0); } + public void changeMap(MapleMap to, int portal) { + changeMap(to, to.getPortal(portal)); + } + public void changeMap(final MapleMap target, final MaplePortal pto) { canWarpCounter++; @@ -1437,7 +1424,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { return lastVisited; } - public void updateMapDropsUponPartyOperation(List exPartyMembers) { + public void partyOperationUpdate(MapleParty party, List exPartyMembers) { List> mapids; petLock.lock(); @@ -1468,6 +1455,84 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { mapObj.updatePlayerItemDrops(partyId, id, partyMembers, partyLeaver); } } + + updatePartyTownDoors(party, this, partyLeaver, partyMembers); + } + + private static void addPartyPlayerDoor(MapleCharacter target) { + MapleDoor targetDoor = target.getPlayerDoor(); + if(targetDoor != null) { + target.applyPartyDoor(targetDoor, true); + } + } + + private static void removePartyPlayerDoor(MapleParty party, MapleCharacter target) { + target.removePartyDoor(party); + } + + private static void updatePartyTownDoors(MapleParty party, MapleCharacter target, MapleCharacter partyLeaver, List partyMembers) { + if(partyLeaver != null) { + removePartyPlayerDoor(party, target); + } else { + addPartyPlayerDoor(target); + } + + Map partyDoors = null; + if(!partyMembers.isEmpty()) { + partyDoors = party.getDoors(); + + for(MapleCharacter pchr : partyMembers) { + MapleDoor door = partyDoors.get(pchr.getId()); + if(door != null) { + door.updateDoorPortal(pchr); + } + } + + for(MapleDoor door : partyDoors.values()) { + for(MapleCharacter pchar : partyMembers) { + door.getTownDoor().sendDestroyData(pchar.getClient(), true); + } + } + + if(partyLeaver != null) { + Collection leaverDoors = partyLeaver.getDoors(); + for(MapleDoor door : leaverDoors) { + for(MapleCharacter pchar : partyMembers) { + door.getTownDoor().sendDestroyData(pchar.getClient(), true); + } + } + } + + List histMembers = party.getMembersSortedByHistory(); + for(Integer chrid : histMembers) { + MapleDoor door = partyDoors.get(chrid); + + if(door != null) { + for(MapleCharacter pchar : partyMembers) { + door.getTownDoor().sendSpawnData(pchar.getClient()); + } + } + } + } + + if(partyLeaver != null) { + Collection leaverDoors = partyLeaver.getDoors(); + + if(partyDoors != null) { + for(MapleDoor door : partyDoors.values()) { + door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true); + } + } + + for(MapleDoor door : leaverDoors) { + door.getTownDoor().sendDestroyData(partyLeaver.getClient(), true); + } + + for(MapleDoor door : leaverDoors) { + door.updateDoorPortal(partyLeaver); + door.getTownDoor().sendSpawnData(partyLeaver.getClient()); + } + } } private Integer getVisitedMapIndex(MapleMap map) { @@ -2238,10 +2303,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public void dispel() { - List mbsvhList = getAllStatups(); - for (MapleBuffStatValueHolder mbsvh : mbsvhList) { - if (mbsvh.effect.isSkill()) { - cancelEffect(mbsvh.effect, false, mbsvh.startTime); + if(!(ServerConstants.USE_UNDISPEL_HOLY_SHIELD && this.isActiveBuffedValue(Bishop.HOLY_SHIELD))) { + List mbsvhList = getAllStatups(); + for (MapleBuffStatValueHolder mbsvh : mbsvhList) { + if (mbsvh.effect.isSkill()) { + cancelEffect(mbsvh.effect, false, mbsvh.startTime); + } } } } @@ -3376,14 +3443,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } if (effect.isMagicDoor()) { - MapleDoor destroyDoor; - - chrLock.lock(); - try { - destroyDoor = doors.remove(this.getId()); - } finally { - chrLock.unlock(); - } + MapleDoor destroyDoor = removePartyDoor(false); if (destroyDoor != null) { destroyDoor.getTarget().removeMapObject(destroyDoor.getAreaDoor()); @@ -3392,21 +3452,18 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { for (MapleCharacter chr : destroyDoor.getTarget().getCharacters()) { destroyDoor.getAreaDoor().sendDestroyData(chr.getClient()); } - for (MapleCharacter chr : destroyDoor.getTown().getCharacters()) { + + Collection townChars = destroyDoor.getTown().getCharacters(); + for (MapleCharacter chr : townChars) { destroyDoor.getTownDoor().sendDestroyData(chr.getClient()); } - - prtLock.lock(); - try { - if (party != null) { - for (MaplePartyCharacter partyMembers : party.getMembers()) { - partyMembers.getPlayer().removeDoor(this.getId()); - partyMembers.removeDoor(this.getId()); + if(destroyDoor.getTownPortal().getId() == 0x80) { + for (MapleCharacter chr : townChars) { + MapleDoor door = chr.getMainTownDoor(); + if(door != null) { + destroyDoor.getTownDoor().sendSpawnData(chr.getClient()); } - silentPartyUpdateInternal(); } - } finally { - prtLock.unlock(); } } } else if (effect.isMapChair()) { @@ -3994,21 +4051,86 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { return dojoStage; } - public Map getDoors() { - chrLock.lock(); + public Collection getDoors() { + prtLock.lock(); try { - return Collections.unmodifiableMap(doors); + return (party != null ? Collections.unmodifiableCollection(party.getDoors().values()) : (pdoor != null ? Collections.singleton(pdoor) : new LinkedHashSet())); } finally { - chrLock.unlock(); + prtLock.unlock(); } } + + public MapleDoor getPlayerDoor() { + prtLock.lock(); + try { + return pdoor; + } finally { + prtLock.unlock(); + } + } + + public MapleDoor getMainTownDoor() { + for (MapleDoor door : getDoors()) { + if (door.getTownPortal().getId() == 0x80) { + return door; + } + } + + return null; + } + + public void applyPartyDoor(MapleDoor door, boolean partyUpdate) { + prtLock.lock(); + try { + if (!partyUpdate) { + pdoor = door; + } + + if (party != null) { + party.addDoor(id, door); + silentPartyUpdateInternal(); + } + } finally { + prtLock.unlock(); + } + } + + private MapleDoor removePartyDoor(boolean partyUpdate) { + MapleDoor ret = null; + + prtLock.lock(); + try { + if (party != null) { + party.removeDoor(id); + silentPartyUpdateInternal(); + } + + if (!partyUpdate) { + ret = pdoor; + pdoor = null; + } + } finally { + prtLock.unlock(); + } + + return ret; + } + + private void removePartyDoor(MapleParty formerParty) { // player is no longer registered at this party + formerParty.removeDoor(id); + } public int getEnergyBar() { return energybar; } public EventInstanceManager getEventInstance() { - return eventInstance; + evtLock.lock(); + try { + return eventInstance; + } finally { + evtLock.unlock(); + } } public void resetExcluded(int petId) { @@ -4499,23 +4621,14 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public void resetPlayerAggro() { + if(client.getWorldServer().unregisterDisabledServerMessage(id)) { + client.announceServerMessage(); + } + setTargetHpBarHash(0); setTargetHpBarTime(0); } - public int getDoorSlot() { - if(doorSlot == -1) { - prtLock.lock(); - try { - doorSlot = (party == null) ? 0 : party.getPartyDoor(this.getId()); - } finally { - prtLock.unlock(); - } - } - - return doorSlot; - } - public MapleMiniGame getMiniGame() { return miniGame; } @@ -4750,7 +4863,7 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { merchant.saveItems(false); } catch (SQLException ex) { ex.printStackTrace(); - System.out.println("Error while saving Hired Merchant items."); + FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, "Error while saving " + name + "'s Hired Merchant items."); } } } @@ -5895,9 +6008,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { ret.jobRank = rs.getInt("jobRank"); ret.jobRankMove = rs.getInt("jobRankMove"); - MapleInventory inv = ret.inventory[MapleInventoryType.EQUIPPED.ordinal()]; - for (Item item : equipped) { - inv.addItemFromDB(item); + if(equipped != null) { // players can have no equipped items at all, ofc + MapleInventory inv = ret.inventory[MapleInventoryType.EQUIPPED.ordinal()]; + for (Item item : equipped) { + inv.addItemFromDB(item); + } } } catch (SQLException sqle) { sqle.printStackTrace(); @@ -6641,10 +6756,11 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { if (party != null) { int channel = client.getChannel(); int mapId = getMapId(); + World wserv = Server.getInstance().getWorld(world); for (MaplePartyCharacter partychar : party.getMembers()) { if (partychar.getMapId() == mapId && partychar.getChannel() == channel) { - MapleCharacter other = Server.getInstance().getWorld(world).getChannel(channel).getPlayerStorage().getCharacterByName(partychar.getName()); + MapleCharacter other = wserv.getChannel(channel).getPlayerStorage().getCharacterById(partychar.getId()); if (other != null) { client.announce(MaplePacketCreator.updatePartyMemberHP(other.getId(), other.getHp(), other.getMaxHpEquipped())); } @@ -7498,7 +7614,12 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { } public void setEventInstance(EventInstanceManager eventInstance) { - this.eventInstance = eventInstance; + evtLock.lock(); + try { + this.eventInstance = eventInstance; + } finally { + evtLock.unlock(); + } } public void setExp(int amount) { @@ -7806,7 +7927,22 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { e.printStackTrace(); } } - + + public int getDoorSlot() { + if(doorSlot != -1) return doorSlot; + return fetchDoorSlot(); + } + + public int fetchDoorSlot() { + prtLock.lock(); + try { + doorSlot = (party == null) ? 0 : party.getPartyDoor(this.getId()); + return doorSlot; + } finally { + prtLock.unlock(); + } + } + public void setParty(MapleParty p) { prtLock.lock(); try { @@ -8917,11 +9053,17 @@ public class MapleCharacter extends AbstractAnimatedMapleMapObject { events = null; party = null; family = null; - client = null; - map = null; + + Server.getInstance().getWorld(world).registerTimedMapObject(new Runnable() { + @Override + public void run() { + client = null; // clients still triggers handlers a few times after disconnecting + map = null; + } + }, 5 * 60 * 1000); } } - + public void logOff() { this.loggedIn = false; } diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java index 7028231540..6b72a2ba67 100644 --- a/src/client/MapleClient.java +++ b/src/client/MapleClient.java @@ -112,6 +112,7 @@ public class MapleClient { private static final Lock loginLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true); private int votePoints; private int voteTime = -1; + private int visibleWorlds; private long lastNpcClick; private long sessionId; @@ -1268,6 +1269,16 @@ public class MapleClient { } } + private void announceDisableServerMessage() { + if(!this.getWorldServer().registerDisabledServerMessage(player.getId())) { + announce(MaplePacketCreator.serverMessage("")); + } + } + + public void announceServerMessage() { + announce(MaplePacketCreator.serverMessage(this.getChannelServer().getServerMessage())); + } + public synchronized void announceBossHpBar(MapleMonster mm, final int mobHash, final byte[] packet) { long timeNow = System.currentTimeMillis(); int targetHash = player.getTargetHpBarHash(); @@ -1275,12 +1286,14 @@ public class MapleClient { if(mobHash != targetHash) { if(timeNow - player.getTargetHpBarTime() >= 5 * 1000) { // is there a way to INTERRUPT this annoying thread running on the client that drops the boss bar after some time at every attack? + announceDisableServerMessage(); announce(packet); player.setTargetHpBarHash(mobHash); player.setTargetHpBarTime(timeNow); } } else { + announceDisableServerMessage(); announce(packet); player.setTargetHpBarTime(timeNow); @@ -1311,10 +1324,8 @@ public class MapleClient { return; } - String[] socket; - try { - socket = Server.getInstance().getIP(getWorld(), channel).split(":"); - } catch (Exception e) { + String[] socket = Server.getInstance().getInetSocket(getWorld(), channel); + if(socket == null) { announce(MaplePacketCreator.serverNotice(1, "Channel " + channel + " is currently disabled. Try another channel.")); announce(MaplePacketCreator.enableActions()); return; @@ -1387,6 +1398,15 @@ public class MapleClient { lastNpcClick = 0; } + public int getVisibleWorlds(){ + return visibleWorlds; + } + + public void requestedServerlist(int worlds) { + visibleWorlds = worlds; + setClickedNPC(); + } + public void closePlayerScriptInteractions() { this.removeClickedNPC(); NPCScriptManager.getInstance().dispose(this); diff --git a/src/client/command/Commands.java b/src/client/command/Commands.java index 1c5805bb2e..dec4b6f679 100644 --- a/src/client/command/Commands.java +++ b/src/client/command/Commands.java @@ -2755,7 +2755,7 @@ public class Commands { } public static boolean executeHeavenMsCommandLv6(Channel cserv, Server srv, MapleClient c, String[] sub) { //Admin - MapleCharacter player = c.getPlayer(); + final MapleCharacter player = c.getPlayer(); MapleCharacter victim; switch(sub[0]) { @@ -2788,16 +2788,20 @@ public class Commands { byte worldb = Byte.parseByte(sub[1]); if (worldb <= (server.getWorldsSize() - 1)) { try { - String[] socket = server.getIP(worldb, c.getChannel()).split(":"); - c.getWorldServer().removePlayer(player); - player.getMap().removePlayer(player);//LOL FORGOT THIS >< - c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - player.setWorld(worldb); - player.saveCharToDB();//To set the new world :O (true because else 2 player instances are created, one in both worlds) - c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); + String[] socket = server.getInetSocket(worldb, c.getChannel()); + if(socket != null) { + c.getWorldServer().removePlayer(player); + player.getMap().removePlayer(player);//LOL FORGOT THIS >< + c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); + player.setWorld(worldb); + player.saveCharToDB();//To set the new world :O (true because else 2 player instances are created, one in both worlds) + c.announce(MaplePacketCreator.getChannelChange(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]))); + } else { + player.message("Error when trying to change worlds, are you sure the world you are trying to warp to has the same amount of channels?"); + } } catch (UnknownHostException | NumberFormatException ex) { ex.printStackTrace(); - player.message("Error when trying to change worlds, are you sure the world you are trying to warp to has the same amount of channels?"); + player.message("Unexpected error when changing worlds, are you sure the world you are trying to warp to has the same amount of channels?"); } } else { @@ -2863,37 +2867,51 @@ public class Commands { break; } - int worldid = Integer.parseInt(sub[1]); + final int worldid = Integer.parseInt(sub[1]); - int chid = Server.getInstance().addChannel(worldid); - if(chid >= 0) { - player.dropMessage(5, "NEW Channel " + chid + " successfully deployed on world " + worldid + "."); - } else { - if(chid == -3) { - player.dropMessage(5, "Invalid worldid detected. Channel creation aborted."); - } else if(chid == -2) { - player.dropMessage(5, "Reached channel limit on worldid " + worldid + ". Channel creation aborted."); - } else if(chid == -1) { - player.dropMessage(5, "Error detected when loading the 'world.ini' file. Channel creation aborted."); - } else { - player.dropMessage(5, "NEW Channel failed to be deployed. Check if the needed port is already in use or other limitations are taking place."); + new Thread(new Runnable() { + @Override + public void run() { + int chid = Server.getInstance().addChannel(worldid); + if(player.isLoggedinWorld()) { + if(chid >= 0) { + player.dropMessage(5, "NEW Channel " + chid + " successfully deployed on world " + worldid + "."); + } else { + if(chid == -3) { + player.dropMessage(5, "Invalid worldid detected. Channel creation aborted."); + } else if(chid == -2) { + player.dropMessage(5, "Reached channel limit on worldid " + worldid + ". Channel creation aborted."); + } else if(chid == -1) { + player.dropMessage(5, "Error detected when loading the 'world.ini' file. Channel creation aborted."); + } else { + player.dropMessage(5, "NEW Channel failed to be deployed. Check if the needed port is already in use or other limitations are taking place."); + } + } + } } - } + }).start(); break; case "addworld": - int wid = Server.getInstance().addWorld(); + new Thread(new Runnable() { + @Override + public void run() { + int wid = Server.getInstance().addWorld(); - if(wid >= 0) { - player.dropMessage(5, "NEW World " + wid + " successfully deployed."); - } else { - if(wid == -2) { - player.dropMessage(5, "Error detected when loading the 'world.ini' file. World creation aborted."); - } else { - player.dropMessage(5, "NEW World failed to be deployed. Check if needed ports are already in use or maximum world count has been reached."); + if(player.isLoggedinWorld()) { + if(wid >= 0) { + player.dropMessage(5, "NEW World " + wid + " successfully deployed."); + } else { + if(wid == -2) { + player.dropMessage(5, "Error detected when loading the 'world.ini' file. World creation aborted."); + } else { + player.dropMessage(5, "NEW World failed to be deployed. Check if needed ports are already in use or maximum world count has been reached."); + } + } + } } - } + }).start(); break; @@ -2903,31 +2921,50 @@ public class Commands { break; } - int worldId = Integer.parseInt(sub[1]); - if(Server.getInstance().removeChannel(worldId)) { - player.dropMessage(5, "Successfully removed a channel on World " + worldId + ". Current channel count: " + Server.getInstance().getWorld(worldId).getChannelsSize() + "."); - } else { - player.dropMessage(5, "Failed to remove last Channel on world " + worldId + ". Check if either that world exists or there are people currently playing there."); - } + final int worldId = Integer.parseInt(sub[1]); + + new Thread(new Runnable() { + @Override + public void run() { + if(Server.getInstance().removeChannel(worldId)) { + if(player.isLoggedinWorld()) { + player.dropMessage(5, "Successfully removed a channel on World " + worldId + ". Current channel count: " + Server.getInstance().getWorld(worldId).getChannelsSize() + "."); + } + } else { + if(player.isLoggedinWorld()) { + player.dropMessage(5, "Failed to remove last Channel on world " + worldId + ". Check if either that world exists or there are people currently playing there."); + } + } + } + }).start(); break; case "removeworld": - int rwid = Server.getInstance().getWorldsSize() - 1; + final int rwid = Server.getInstance().getWorldsSize() - 1; if(rwid <= 0) { player.dropMessage(5, "Unable to remove world 0."); break; } - if(Server.getInstance().removeWorld()) { - player.dropMessage(5, "Successfully removed a world. Current world count: " + Server.getInstance().getWorldsSize() + "."); - } else { - if(rwid < 0) { - player.dropMessage(5, "No registered worlds to remove."); - } else { - player.dropMessage(5, "Failed to remove world " + rwid + ". Check if there are people currently playing there."); + new Thread(new Runnable() { + @Override + public void run() { + if(Server.getInstance().removeWorld()) { + if(player.isLoggedinWorld()) { + player.dropMessage(5, "Successfully removed a world. Current world count: " + Server.getInstance().getWorldsSize() + "."); + } + } else { + if(player.isLoggedinWorld()) { + if(rwid < 0) { + player.dropMessage(5, "No registered worlds to remove."); + } else { + player.dropMessage(5, "Failed to remove world " + rwid + ". Check if there are people currently playing there."); + } + } + } } - } + }).start(); break; diff --git a/src/client/inventory/MaplePet.java b/src/client/inventory/MaplePet.java index aa1e479e00..4d6dbd1423 100644 --- a/src/client/inventory/MaplePet.java +++ b/src/client/inventory/MaplePet.java @@ -222,7 +222,6 @@ public class MaplePet extends Item { } owner.getMap().broadcastMessage(MaplePacketCreator.commandResponse(owner.getId(), slot, type, enjoyed)); - if(owner.getMount() != null) owner.getMap().broadcastMessage(MaplePacketCreator.updateMount(owner.getId(), owner.getMount(), false)); saveToDb(); Item petz = owner.getInventory(MapleInventoryType.CASH).getItem(getPosition()); diff --git a/src/client/processor/DueyProcessor.java b/src/client/processor/DueyProcessor.java index 3a03da5e77..9b694c7e67 100644 --- a/src/client/processor/DueyProcessor.java +++ b/src/client/processor/DueyProcessor.java @@ -355,63 +355,66 @@ public class DueyProcessor { c.disconnect(true, false); return; } + int finalcost = mesos + fee; - boolean send = false; if (c.getPlayer().getMeso() >= finalcost) { int accid = getAccIdFromCNAME(recipient, true); if (accid != -1) { - if (accid != c.getAccID()) { - send = true; - } else { + if (accid == c.getAccID()) { c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SAMEACC_ERROR.getCode())); - } - } else { - c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NAME_DOES_NOT_EXIST.getCode())); - } - } else { - c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NOT_ENOUGH_MESOS.getCode())); - } - - MapleClient rClient = null; - - int channel = c.getWorldServer().find(recipient); - if (channel > -1) { - Channel rcserv = c.getWorldServer().getChannel(channel); - rClient = rcserv.getPlayerStorage().getCharacterByName(recipient).getClient(); - } - - if (send) { - if (inventId > 0) { - MapleInventoryType inv = MapleInventoryType.getByType(inventId); - Item item = c.getPlayer().getInventory(inv).getItem(itemPos); - if (item != null && c.getPlayer().getItemQuantity(item.getItemId(), false) >= amount) { - c.getPlayer().gainMeso(-finalcost, false); - c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode())); - - if (ItemConstants.isRechargeable(item.getItemId())) { - MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, item.getQuantity(), true); - } else { - MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, amount, true, false); - } - - MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item); - addItemToDB(item, amount, mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); - } else { - if (item != null) { - c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode())); - } return; } } else { + c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NAME_DOES_NOT_EXIST.getCode())); + return; + } + } else { + c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_NOT_ENOUGH_MESOS.getCode())); + return; + } + + MapleClient rClient = null; + int channel = c.getWorldServer().find(recipient); + if (channel > -1) { + Channel rcserv = c.getWorldServer().getChannel(channel); + if(rcserv != null) { + MapleCharacter rChr = rcserv.getPlayerStorage().getCharacterByName(recipient); + if(rChr != null) { + rClient = rChr.getClient(); + } + } + } + + if (inventId > 0) { + MapleInventoryType inv = MapleInventoryType.getByType(inventId); + Item item = c.getPlayer().getInventory(inv).getItem(itemPos); + if (item != null && c.getPlayer().getItemQuantity(item.getItemId(), false) >= amount) { c.getPlayer().gainMeso(-finalcost, false); - c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode())); + c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode())); - addMesoToDB(mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); - } + if (ItemConstants.isRechargeable(item.getItemId())) { + MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, item.getQuantity(), true); + } else { + MapleInventoryManipulator.removeFromSlot(c, inv, itemPos, amount, true, false); + } - if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) { - showDueyNotification(rClient, rClient.getPlayer()); + MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item); + addItemToDB(item, amount, mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); + } else { + if (item != null) { + c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode())); + } + return; } + } else { + c.getPlayer().gainMeso(-finalcost, false); + c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_SUCCESSFULLY_SENT.getCode())); + + addMesoToDB(mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); + } + + if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) { + showDueyNotification(rClient, rClient.getPlayer()); } } finally { c.unlockClient(); diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java index 61f686c598..a0c0ae08b3 100644 --- a/src/constants/ServerConstants.java +++ b/src/constants/ServerConstants.java @@ -72,6 +72,7 @@ public class ServerConstants { public static final boolean USE_ENFORCE_UNMERCHABLE_CASH = true;//Forces players to not sell CASH items via merchants. public static final boolean USE_ENFORCE_UNMERCHABLE_PET = true; //Forces players to not sell pets via merchants. (since non-named pets gets dirty name and other possible DB-related issues) public static final boolean USE_ENFORCE_MDOOR_POSITION = false; //Forces mystic door to be spawned near spawnpoints. + public static final boolean USE_SPAWN_LOOT_ON_ANIMATION = false;//Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly). public static final boolean USE_ERASE_PERMIT_ON_OPENSHOP = true;//Forces "shop permit" item to be consumed when player deploy his/her player shop. public static final boolean USE_ERASE_UNTRADEABLE_DROP = true; //Forces flagged untradeable items to disappear when dropped. public static final boolean USE_ERASE_PET_ON_EXPIRATION = false;//Forces pets to be removed from inventory when expire time comes, rather than converting it to a doll. @@ -81,7 +82,6 @@ public class ServerConstants { public static final boolean USE_OLD_GMS_STYLED_PQ_NPCS = true; //Enables PQ NPCs with similar behaviour to old GMS style, that skips info about the PQs and immediately tries to register the party in. public static final boolean USE_ENABLE_SOLO_EXPEDITIONS = true; //Enables start expeditions with any number of players. This will also bypass all the Zakum prequest. public static final boolean USE_ENABLE_FULL_RESPAWN = true; //At respawn task, always respawn missing mobs when they're available. Spawn count doesn't depend on how many players are currently there. - public static final boolean USE_SPAWN_LOOT_ON_ANIMATION = false;//Makes loot appear some time after the mob has been killed (following the mob death animation, instead of instantly). //Announcement Configuration public static final boolean USE_ANNOUNCE_SHOPITEMSOLD = false; //Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold. @@ -154,6 +154,7 @@ public class ServerConstants { //Other Skills Configuration public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will. public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs. + public static final boolean USE_UNDISPEL_HOLY_SHIELD = true;//Holy shield buff also prevents players from suffering dispel from mobs. //Character Configuration public static final boolean USE_ADD_SLOTS_BY_LEVEL = true; //Slots are added each 20 levels. diff --git a/src/net/server/Server.java b/src/net/server/Server.java index 45d189aca4..7a573cd5d5 100644 --- a/src/net/server/Server.java +++ b/src/net/server/Server.java @@ -60,6 +60,7 @@ import net.server.guild.MapleGuildCharacter; import net.server.worker.CharacterDiseaseWorker; import net.server.worker.CouponWorker; import net.server.worker.RankingWorker; +import net.server.worker.ReleaseLockWorker; import net.server.world.World; import org.apache.mina.core.buffer.IoBuffer; @@ -206,7 +207,11 @@ public class Server { public World getWorld(int id) { wldRLock.lock(); try { - return worlds.get(id); + try { + return worlds.get(id); + } catch (IndexOutOfBoundsException e) { + return null; + } } finally { wldRLock.unlock(); } @@ -231,21 +236,33 @@ public class Server { } public Channel getChannel(int world, int channel) { - return this.getWorld(world).getChannel(channel); + try { + return this.getWorld(world).getChannel(channel); + } catch(NullPointerException npe) { + return null; + } } public List getChannelsFromWorld(int world) { - return this.getWorld(world).getChannels(); + try { + return this.getWorld(world).getChannels(); + } catch(NullPointerException npe) { + return new ArrayList<>(0); + } } public List getAllChannels() { - List channelz = new ArrayList<>(); - for (World world : this.getWorlds()) { - for (Channel ch : world.getChannels()) { - channelz.add(ch); + try { + List channelz = new ArrayList<>(); + for (World world : this.getWorlds()) { + for (Channel ch : world.getChannels()) { + channelz.add(ch); + } } + return channelz; + } catch(NullPointerException npe) { + return new ArrayList<>(0); } - return channelz; } public Set getOpenChannels(int world) { @@ -257,7 +274,7 @@ public class Server { } } - public String getIP(int world, int channel) { + private String getIP(int world, int channel) { wldRLock.lock(); try { return channels.get(world).get(channel); @@ -266,6 +283,15 @@ public class Server { } } + public String[] getInetSocket(int world, int channel) { + try { + return getIP(world, channel).split(":"); + } catch (Exception e) { + return null; + } + } + + private void dumpData() { wldWLock.lock(); try { @@ -643,6 +669,7 @@ public class Server { long timeLeft = getTimeLeftForNextHour(); tMan.register(new CharacterDiseaseWorker(), ServerConstants.UPDATE_INTERVAL, ServerConstants.UPDATE_INTERVAL); + tMan.register(new ReleaseLockWorker(), 2 * 60 * 1000, 2 * 60 * 1000); tMan.register(new CouponWorker(), ServerConstants.COUPON_INTERVAL, timeLeft); tMan.register(new RankingWorker(), ServerConstants.RANKING_INTERVAL, timeLeft); @@ -1149,8 +1176,10 @@ public class Server { } */ - public Pair>, List>>> loadAccountCharlist(Integer accountId) { + public Pair>, List>>> loadAccountCharlist(Integer accountId, int visibleWorlds) { List wlist = this.getWorlds(); + if(wlist.size() > visibleWorlds) wlist = wlist.subList(0, visibleWorlds); + List>> accChars = new ArrayList<>(wlist.size() + 1); int chrTotal = 0; List lastwchars = null; diff --git a/src/net/server/audit/LockCollector.java b/src/net/server/audit/LockCollector.java new file mode 100644 index 0000000000..d76ac16a4e --- /dev/null +++ b/src/net/server/audit/LockCollector.java @@ -0,0 +1,75 @@ +/* + This file is part of the HeavenMS MapleStory Server + Copyleft (L) 2016 - 2018 RonanLana + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +package net.server.audit; + +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * + * @author Ronan + */ +public class LockCollector { + + private static final LockCollector instance = new LockCollector(); + + private Map disposableLocks = new HashMap<>(200); + private final Lock lock = new ReentrantLock(true); + + public static LockCollector getInstance() { + return instance; + } + + public void registerDisposeAction(Runnable r) { + lock.lock(); + try { + disposableLocks.put(r, 0); + } finally { + lock.unlock(); + } + } + + public void runLockCollector() { + List toDispose = new ArrayList<>(); + + lock.lock(); + try { + for(Entry e : disposableLocks.entrySet()) { + Integer eVal = e.getValue(); + if(eVal > 5) { // updates each 2min + toDispose.add(e.getKey()); + } else { + disposableLocks.put(e.getKey(), ++eVal); + } + } + } finally { + lock.unlock(); + } + + for(Runnable r : toDispose) { + r.run(); + } + } +} diff --git a/src/net/server/audit/ThreadTracker.java b/src/net/server/audit/ThreadTracker.java index dc916553c4..ec49dab816 100644 --- a/src/net/server/audit/ThreadTracker.java +++ b/src/net/server/audit/ThreadTracker.java @@ -57,7 +57,7 @@ public class ThreadTracker { private final Map lockCount = new HashMap<>(); private final Map lockIds = new HashMap<>(); private final Map lockThreads = new HashMap<>(); - private final Map lockUpdate = new HashMap<>(); + private final Map lockUpdate = new HashMap<>(); private final Map> locks = new HashMap<>(); ScheduledFuture threadTrackerSchedule; @@ -169,8 +169,8 @@ public class ThreadTracker { toRemove.clear(); - for(Entry it : lockUpdate.entrySet()) { - byte val = (byte)(it.getValue() + 1); + for(Entry it : lockUpdate.entrySet()) { + int val = it.getValue() + 1; if(val < 60) { lockUpdate.put(it.getKey(), val); @@ -202,7 +202,7 @@ public class ThreadTracker { lockCount.put(lockOid, c); lockIds.put(lockOid, lockId); lockThreads.put(lockOid, tid); - lockUpdate.put(lockOid, (byte) 0); + lockUpdate.put(lockOid, 0); } c.incrementAndGet(); @@ -233,7 +233,7 @@ public class ThreadTracker { else { AtomicInteger c = lockCount.get(lockOid); c.decrementAndGet(); - lockUpdate.put(lockOid, (byte) 0); + lockUpdate.put(lockOid, 0); List list = threadTracker.get(tid); for(int i = list.size() - 1; i >= 0; i--) { diff --git a/src/net/server/audit/locks/MonitoredLockType.java b/src/net/server/audit/locks/MonitoredLockType.java index ad26cea77b..5d4c57b9f3 100644 --- a/src/net/server/audit/locks/MonitoredLockType.java +++ b/src/net/server/audit/locks/MonitoredLockType.java @@ -30,6 +30,7 @@ public enum MonitoredLockType { CHARACTER_EFF, CHARACTER_PET, CHARACTER_PRT, + CHARACTER_EVT, CLIENT, CLIENT_ENCODER, CLIENT_LOGIN, @@ -40,6 +41,7 @@ public enum MonitoredLockType { SRVHANDLER_TEMP, BUFF_STORAGE, PLAYER_STORAGE, + PLAYER_DOOR, SERVER, SERVER_DISEASES, SERVER_LOGIN, @@ -59,7 +61,7 @@ public enum MonitoredLockType { GUILD, PARTY, WORLD_PARTY, - WORLD_OWL, + WORLD_SRVMESSAGES, WORLD_PETS, WORLD_CHARS, WORLD_CHANNELS, diff --git a/src/net/server/audit/locks/active/TrackerReadLock.java b/src/net/server/audit/locks/active/TrackerReadLock.java index 77f1723480..7fac952520 100644 --- a/src/net/server/audit/locks/active/TrackerReadLock.java +++ b/src/net/server/audit/locks/active/TrackerReadLock.java @@ -159,11 +159,13 @@ public class TrackerReadLock extends ReentrantReadWriteLock.ReadLock implements timeoutSchedule.cancel(false); timeoutSchedule = null; } + + reentrantCount.set(Integer.MAX_VALUE); } finally { state.unlock(); } //unlock(); - return new EmptyReadLock(); + return new EmptyReadLock(id); } } diff --git a/src/net/server/audit/locks/active/TrackerReentrantLock.java b/src/net/server/audit/locks/active/TrackerReentrantLock.java index 6ee53881c2..a96862896d 100644 --- a/src/net/server/audit/locks/active/TrackerReentrantLock.java +++ b/src/net/server/audit/locks/active/TrackerReentrantLock.java @@ -46,7 +46,7 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen private final int hashcode; private final Lock state = new ReentrantLock(true); private final AtomicInteger reentrantCount = new AtomicInteger(0); - + public TrackerReentrantLock(MonitoredLockType id) { super(); this.id = id; @@ -161,11 +161,13 @@ public class TrackerReentrantLock extends ReentrantLock implements MonitoredReen timeoutSchedule.cancel(false); timeoutSchedule = null; } + + reentrantCount.set(Integer.MAX_VALUE); } finally { state.unlock(); } //unlock(); - return new EmptyReentrantLock(); + return new EmptyReentrantLock(id); } } diff --git a/src/net/server/audit/locks/active/TrackerWriteLock.java b/src/net/server/audit/locks/active/TrackerWriteLock.java index 8262a6d3ff..41c9e92745 100644 --- a/src/net/server/audit/locks/active/TrackerWriteLock.java +++ b/src/net/server/audit/locks/active/TrackerWriteLock.java @@ -157,11 +157,13 @@ public class TrackerWriteLock extends ReentrantReadWriteLock.WriteLock implement timeoutSchedule.cancel(false); timeoutSchedule = null; } + + reentrantCount.set(Integer.MAX_VALUE); } finally { state.unlock(); } //unlock(); - return new EmptyWriteLock(); + return new EmptyWriteLock(id); } } diff --git a/src/net/server/audit/locks/empty/EmptyReadLock.java b/src/net/server/audit/locks/empty/EmptyReadLock.java index a94dfadb26..41b4279302 100644 --- a/src/net/server/audit/locks/empty/EmptyReadLock.java +++ b/src/net/server/audit/locks/empty/EmptyReadLock.java @@ -19,26 +19,56 @@ */ package net.server.audit.locks.empty; +import constants.ServerConstants; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReadLock; +import tools.FilePrinter; /** * * @author RonanLana */ public class EmptyReadLock implements MonitoredReadLock { + private final MonitoredLockType id; + + public EmptyReadLock(MonitoredLockType type) { + this.id = type; + } + + private static String printThreadStack(StackTraceElement[] list) { + DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE)); + String df = dateFormat.format(new Date()); + + String s = "\r\n" + df + "\r\n"; + for(int i = 0; i < list.length; i++) { + s += (" " + list[i].toString() + "\r\n"); + } + s += "----------------------------"; + + return s; + } + @Override - public void lock() {} + public void lock() { + FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); + } @Override public void unlock() {} @Override public boolean tryLock() { + FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); return false; } @Override public MonitoredReadLock dispose() { - return null; + return this; } } diff --git a/src/net/server/audit/locks/empty/EmptyReentrantLock.java b/src/net/server/audit/locks/empty/EmptyReentrantLock.java index 1ccd108795..39f62a799f 100644 --- a/src/net/server/audit/locks/empty/EmptyReentrantLock.java +++ b/src/net/server/audit/locks/empty/EmptyReentrantLock.java @@ -19,26 +19,56 @@ */ package net.server.audit.locks.empty; +import constants.ServerConstants; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; +import tools.FilePrinter; /** * * @author RonanLana */ public class EmptyReentrantLock implements MonitoredReentrantLock { + private final MonitoredLockType id; + + public EmptyReentrantLock(MonitoredLockType type) { + this.id = type; + } + + private static String printThreadStack(StackTraceElement[] list) { + DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE)); + String df = dateFormat.format(new Date()); + + String s = "\r\n" + df + "\r\n"; + for(int i = 0; i < list.length; i++) { + s += (" " + list[i].toString() + "\r\n"); + } + s += "----------------------------"; + + return s; + } + @Override - public void lock() {} + public void lock() { + FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); + } @Override public void unlock() {} @Override public boolean tryLock() { + FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); return false; } @Override public MonitoredReentrantLock dispose() { - return null; + return this; } } diff --git a/src/net/server/audit/locks/empty/EmptyWriteLock.java b/src/net/server/audit/locks/empty/EmptyWriteLock.java index cff88f441b..1fa8b5bf95 100644 --- a/src/net/server/audit/locks/empty/EmptyWriteLock.java +++ b/src/net/server/audit/locks/empty/EmptyWriteLock.java @@ -19,26 +19,56 @@ */ package net.server.audit.locks.empty; +import constants.ServerConstants; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredWriteLock; +import tools.FilePrinter; /** * * @author RonanLana */ public class EmptyWriteLock implements MonitoredWriteLock { + private final MonitoredLockType id; + + public EmptyWriteLock(MonitoredLockType type) { + this.id = type; + } + + private static String printThreadStack(StackTraceElement[] list) { + DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone(ServerConstants.TIMEZONE)); + String df = dateFormat.format(new Date()); + + String s = "\r\n" + df + "\r\n"; + for(int i = 0; i < list.length; i++) { + s += (" " + list[i].toString() + "\r\n"); + } + s += "----------------------------"; + + return s; + } + @Override - public void lock() {} + public void lock() { + FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); + } @Override public void unlock() {} @Override public boolean tryLock() { + FilePrinter.printError(FilePrinter.DISPOSED_LOCKS, "Captured try-locking tentative on disposed lock " + id + ":" + printThreadStack(Thread.currentThread().getStackTrace())); return false; } @Override public MonitoredWriteLock dispose() { - return null; + return this; } } diff --git a/src/net/server/channel/Channel.java b/src/net/server/channel/Channel.java index 7a51af8685..d91af5ecc1 100644 --- a/src/net/server/channel/Channel.java +++ b/src/net/server/channel/Channel.java @@ -37,6 +37,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.MonitoredReentrantReadWriteLock; @@ -266,7 +267,22 @@ public final class Channel { channelSchedulers[i].dispose(); channelSchedulers[i] = null; } - + } + + disposeLocks(); + } + + private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { + for(int i = 0; i < 4; i++) { faceLock[i] = faceLock[i].dispose(); } @@ -300,6 +316,10 @@ public final class Channel { players.addPlayer(chr); chr.announce(MaplePacketCreator.serverMessage(serverMessage)); } + + public String getServerMessage() { + return serverMessage; + } public PlayerStorage getPlayerStorage() { return players; @@ -443,6 +463,7 @@ public final class Channel { public void setServerMessage(String message) { this.serverMessage = message; broadcastPacket(MaplePacketCreator.serverMessage(message)); + Server.getInstance().getWorld(world).resetDisabledServerMessages(); } private static String [] getEvents(){ @@ -540,7 +561,7 @@ public final class Channel { resetDojo(dojoMapId, 0); } - private void resetDojo(int dojoMapId, int thisStg) { + public void resetDojo(int dojoMapId, int thisStg) { int slot = getDojoSlot(dojoMapId); this.dojoStage[slot] = thisStg; diff --git a/src/net/server/channel/handlers/DoorHandler.java b/src/net/server/channel/handlers/DoorHandler.java index ee3d97dfec..b2a2ea2888 100644 --- a/src/net/server/channel/handlers/DoorHandler.java +++ b/src/net/server/channel/handlers/DoorHandler.java @@ -21,13 +21,11 @@ */ package net.server.channel.handlers; -import java.util.Calendar; import client.MapleCharacter; import client.MapleClient; import net.AbstractMaplePacketHandler; import server.maps.MapleDoorObject; import server.maps.MapleMapObject; -import tools.FilePrinter; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; @@ -43,10 +41,6 @@ public final class DoorHandler extends AbstractMaplePacketHandler { MapleCharacter chr = c.getPlayer(); if (chr.isChangingMaps() || chr.isBanned()) { - if(chr.isChangingMaps()) { - FilePrinter.printError(FilePrinter.PORTAL_STUCK + chr.getName() + ".txt", "Player " + chr.getName() + " got stuck when changing maps (using Mystic Door). Timestamp: " + Calendar.getInstance().getTime().toString() + " Last visited mapids: " + chr.getLastVisitedMapids()); - } - c.announce(MaplePacketCreator.enableActions()); return; } diff --git a/src/net/server/channel/handlers/EnterCashShopHandler.java b/src/net/server/channel/handlers/EnterCashShopHandler.java index 4d6c044de8..5898f96d68 100644 --- a/src/net/server/channel/handlers/EnterCashShopHandler.java +++ b/src/net/server/channel/handlers/EnterCashShopHandler.java @@ -45,7 +45,13 @@ public class EnterCashShopHandler extends AbstractMaplePacketHandler { } - if(MapleMiniDungeonInfo.isDungeonMap(c.getPlayer().getMapId())) { + if(mc.getEventInstance() != null) { + c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event.")); + c.announce(MaplePacketCreator.enableActions()); + return; + } + + if(MapleMiniDungeonInfo.isDungeonMap(mc.getMapId())) { c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon.")); c.announce(MaplePacketCreator.enableActions()); return; diff --git a/src/net/server/channel/handlers/EnterMTSHandler.java b/src/net/server/channel/handlers/EnterMTSHandler.java index c2833ba12d..057b81052a 100644 --- a/src/net/server/channel/handlers/EnterMTSHandler.java +++ b/src/net/server/channel/handlers/EnterMTSHandler.java @@ -58,7 +58,13 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler { return; } - if(MapleMiniDungeonInfo.isDungeonMap(c.getPlayer().getMapId())) { + if(chr.getEventInstance() != null) { + c.announce(MaplePacketCreator.serverNotice(5, "Entering Cash Shop or MTS are disabled when registered on an event.")); + c.announce(MaplePacketCreator.enableActions()); + return; + } + + if(MapleMiniDungeonInfo.isDungeonMap(chr.getMapId())) { c.announce(MaplePacketCreator.serverNotice(5, "Changing channels or entering Cash Shop or MTS are disabled when inside a Mini-Dungeon.")); c.announce(MaplePacketCreator.enableActions()); return; diff --git a/src/net/server/channel/handlers/PartyOperationHandler.java b/src/net/server/channel/handlers/PartyOperationHandler.java index 1100099cb2..67ee473a18 100644 --- a/src/net/server/channel/handlers/PartyOperationHandler.java +++ b/src/net/server/channel/handlers/PartyOperationHandler.java @@ -82,9 +82,9 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { player.setMPC(partyplayer); player.getMap().addPartyMember(player); player.silentPartyUpdate(); - c.announce(MaplePacketCreator.partyCreated(partyplayer, party.getId())); - player.updateMapDropsUponPartyOperation(null); + player.partyOperationUpdate(party, null); + c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId())); } else { c.announce(MaplePacketCreator.serverNotice(5, "You can't create a party as you are already in one.")); } @@ -94,7 +94,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { List partymembers = player.getPartyMembers(); leaveParty(party, partyplayer, c); - player.updateMapDropsUponPartyOperation(partymembers); + player.partyOperationUpdate(party, partymembers); break; } case 3: { // join @@ -110,7 +110,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { player.receivePartyMemberHP(); player.updatePartyMemberHP(); - player.updateMapDropsUponPartyOperation(null); + player.partyOperationUpdate(party, null); } else { c.announce(MaplePacketCreator.partyStatusMessage(17)); } @@ -147,9 +147,9 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { player.setParty(party); player.setMPC(partyplayer); player.getMap().addPartyMember(player); - c.announce(MaplePacketCreator.partyCreated(partyplayer, party.getId())); - player.updateMapDropsUponPartyOperation(null); + player.partyOperationUpdate(party, null); + c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId())); } if (party.getMembers().size() < 6) { invited.getClient().announce(MaplePacketCreator.partyInvite(player)); @@ -184,7 +184,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { emc.setParty(null); world.updateParty(party.getId(), PartyOperation.EXPEL, expelled); - emc.updateMapDropsUponPartyOperation(partyMembers); + emc.partyOperationUpdate(party, partyMembers); } else { world.updateParty(party.getId(), PartyOperation.EXPEL, expelled); } diff --git a/src/net/server/channel/handlers/PetCommandHandler.java b/src/net/server/channel/handlers/PetCommandHandler.java index 452c3c993b..997ec27e74 100644 --- a/src/net/server/channel/handlers/PetCommandHandler.java +++ b/src/net/server/channel/handlers/PetCommandHandler.java @@ -54,10 +54,8 @@ public final class PetCommandHandler extends AbstractMaplePacketHandler { if (Randomizer.nextInt(101) <= petCommand.getProbability()) { pet.gainClosenessFullness(chr, petCommand.getIncrease(), 0, command); - } - else { + } else { chr.getMap().broadcastMessage(MaplePacketCreator.commandResponse(chr.getId(), petIndex, command, false)); - if(chr.getMount() != null) chr.getMap().broadcastMessage(MaplePacketCreator.updateMount(chr.getId(), chr.getMount(), false)); } } } diff --git a/src/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/net/server/channel/handlers/PlayerLoggedinHandler.java index 0560264ec5..88a9e8cc35 100644 --- a/src/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -103,12 +103,18 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { int state = c.getLoginState(); boolean allowLogin = true; - Channel cserv = c.getChannelServer(); + World world = server.getWorld(c.getWorld()); + if(world == null) { + c.disconnect(true, false); + return; + } + + Channel cserv = world.getChannel(c.getChannel()); if(cserv == null) { c.setChannel(1); - cserv = c.getChannelServer(); + cserv = world.getChannel(c.getChannel()); - if(cserv == null) { // world server is out + if(cserv == null) { c.disconnect(true, false); return; } @@ -136,8 +142,6 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { return; } c.updateLoginState(MapleClient.LOGIN_LOGGEDIN); - - World world = server.getWorld(c.getWorld()); cserv.addPlayer(player); world.addPlayer(player); diff --git a/src/net/server/channel/worker/BaseScheduler.java b/src/net/server/channel/worker/BaseScheduler.java index a95abdf053..833d5e0058 100644 --- a/src/net/server/channel/worker/BaseScheduler.java +++ b/src/net/server/channel/worker/BaseScheduler.java @@ -29,6 +29,7 @@ import java.util.Map.Entry; import java.util.concurrent.ScheduledFuture; import net.server.Server; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -196,6 +197,19 @@ public abstract class BaseScheduler { externalLocks.clear(); } + disposeLocks(); + } + + private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { schedulerLock = schedulerLock.dispose(); } } diff --git a/src/net/server/channel/worker/MobAnimationScheduler.java b/src/net/server/channel/worker/MobAnimationScheduler.java index cead942343..f313239c83 100644 --- a/src/net/server/channel/worker/MobAnimationScheduler.java +++ b/src/net/server/channel/worker/MobAnimationScheduler.java @@ -24,6 +24,7 @@ import net.server.audit.locks.MonitoredLockType; import java.util.HashSet; import java.util.List; import java.util.Set; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -76,7 +77,20 @@ public class MobAnimationScheduler extends BaseScheduler { @Override public void dispose() { - animationLock = animationLock.dispose(); + disposeLocks(); super.dispose(); } + + private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { + animationLock = animationLock.dispose(); + } } diff --git a/src/net/server/channel/worker/MobStatusScheduler.java b/src/net/server/channel/worker/MobStatusScheduler.java index 702370ebb3..9a69e891d4 100644 --- a/src/net/server/channel/worker/MobStatusScheduler.java +++ b/src/net/server/channel/worker/MobStatusScheduler.java @@ -25,6 +25,7 @@ import java.util.HashMap; import java.util.ArrayList; import java.util.List; import java.util.Map; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -111,7 +112,20 @@ public class MobStatusScheduler extends BaseScheduler { @Override public void dispose() { - overtimeStatusLock = overtimeStatusLock.dispose(); + disposeLocks(); super.dispose(); } + + private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { + overtimeStatusLock = overtimeStatusLock.dispose(); + } } diff --git a/src/net/server/handlers/login/CharSelectedHandler.java b/src/net/server/handlers/login/CharSelectedHandler.java index b25c637301..0601d93336 100644 --- a/src/net/server/handlers/login/CharSelectedHandler.java +++ b/src/net/server/handlers/login/CharSelectedHandler.java @@ -27,6 +27,7 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; @@ -52,7 +53,14 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler { } c.setWorld(server.getCharacterWorld(charId)); - if(c.getWorldServer().isWorldCapacityFull()) { + World wserv = c.getWorldServer(); + if(wserv == null || wserv.isWorldCapacityFull()) { + c.announce(MaplePacketCreator.getAfterLoginError(10)); + return; + } + + String[] socket = server.getInetSocket(c.getWorld(), c.getChannel()); + if(socket == null) { c.announce(MaplePacketCreator.getAfterLoginError(10)); return; } @@ -61,7 +69,6 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler { c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); - String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":"); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); } catch (UnknownHostException | NumberFormatException e) { diff --git a/src/net/server/handlers/login/CharSelectedWithPicHandler.java b/src/net/server/handlers/login/CharSelectedWithPicHandler.java index 55fa741b56..b2bdcf7cb5 100644 --- a/src/net/server/handlers/login/CharSelectedWithPicHandler.java +++ b/src/net/server/handlers/login/CharSelectedWithPicHandler.java @@ -6,6 +6,7 @@ import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; import client.MapleClient; @@ -34,7 +35,14 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler { if (c.checkPic(pic)) { c.setWorld(server.getCharacterWorld(charId)); - if(c.getWorldServer().isWorldCapacityFull()) { + World wserv = c.getWorldServer(); + if(wserv == null || wserv.isWorldCapacityFull()) { + c.announce(MaplePacketCreator.getAfterLoginError(10)); + return; + } + + String[] socket = server.getInetSocket(c.getWorld(), c.getChannel()); + if(socket == null) { c.announce(MaplePacketCreator.getAfterLoginError(10)); return; } @@ -42,8 +50,7 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler { server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); - - String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":"); + try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); } catch (UnknownHostException | NumberFormatException e) { diff --git a/src/net/server/handlers/login/CharlistRequestHandler.java b/src/net/server/handlers/login/CharlistRequestHandler.java index 2d70c42443..72f29c06ca 100644 --- a/src/net/server/handlers/login/CharlistRequestHandler.java +++ b/src/net/server/handlers/login/CharlistRequestHandler.java @@ -24,6 +24,7 @@ package net.server.handlers.login; import client.MapleClient; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; @@ -33,14 +34,21 @@ public final class CharlistRequestHandler extends AbstractMaplePacketHandler { public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { slea.readByte(); int world = slea.readByte(); - c.setWorld(world); - if(Server.getInstance().getWorld(world).isWorldCapacityFull()) { + World wserv = Server.getInstance().getWorld(world); + if(wserv == null || wserv.isWorldCapacityFull()) { c.announce(MaplePacketCreator.getServerStatus(2)); return; } - c.setChannel(slea.readByte() + 1); + int channel = slea.readByte() + 1; + if(wserv.getChannel(channel) == null) { + c.announce(MaplePacketCreator.getServerStatus(2)); + return; + } + + c.setWorld(world); + c.setChannel(channel); c.sendCharList(world); } } \ No newline at end of file diff --git a/src/net/server/handlers/login/RegisterPicHandler.java b/src/net/server/handlers/login/RegisterPicHandler.java index bc0d6e67f7..3b42cf3b8b 100644 --- a/src/net/server/handlers/login/RegisterPicHandler.java +++ b/src/net/server/handlers/login/RegisterPicHandler.java @@ -5,6 +5,7 @@ import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; import client.MapleClient; @@ -37,7 +38,14 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler { c.setPic(pic); c.setWorld(server.getCharacterWorld(charId)); - if(c.getWorldServer().isWorldCapacityFull()) { + World wserv = c.getWorldServer(); + if(wserv == null || wserv.isWorldCapacityFull()) { + c.announce(MaplePacketCreator.getAfterLoginError(10)); + return; + } + + String[] socket = server.getInetSocket(c.getWorld(), c.getChannel()); + if(socket == null) { c.announce(MaplePacketCreator.getAfterLoginError(10)); return; } @@ -46,7 +54,6 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler { c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); - String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":"); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); } catch (UnknownHostException e) { diff --git a/src/net/server/handlers/login/ServerlistRequestHandler.java b/src/net/server/handlers/login/ServerlistRequestHandler.java index 902a4100fa..ba29947a4c 100644 --- a/src/net/server/handlers/login/ServerlistRequestHandler.java +++ b/src/net/server/handlers/login/ServerlistRequestHandler.java @@ -23,6 +23,7 @@ package net.server.handlers.login; import client.MapleClient; import constants.GameConstants; +import java.util.List; import net.AbstractMaplePacketHandler; import net.server.Server; import net.server.world.World; @@ -34,10 +35,10 @@ public final class ServerlistRequestHandler extends AbstractMaplePacketHandler { @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { Server server = Server.getInstance(); - server.loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB. - c.setClickedNPC(); + List worlds = server.getWorlds(); + c.requestedServerlist(worlds.size()); - for (World world : server.getWorlds()) { + for (World world : worlds) { c.announce(MaplePacketCreator.getServerList(world.getId(), GameConstants.WORLD_NAMES[world.getId()], world.getFlag(), world.getEventMessage(), world.getChannels())); } c.announce(MaplePacketCreator.getEndOfServerList()); diff --git a/src/net/server/handlers/login/ViewAllCharHandler.java b/src/net/server/handlers/login/ViewAllCharHandler.java index 63a432f271..b438c82633 100644 --- a/src/net/server/handlers/login/ViewAllCharHandler.java +++ b/src/net/server/handlers/login/ViewAllCharHandler.java @@ -41,7 +41,7 @@ public final class ViewAllCharHandler extends AbstractMaplePacketHandler { } int accountId = c.getAccID(); - Pair>, List>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId); + Pair>, List>>> loginBlob = Server.getInstance().loadAccountCharlist(accountId, c.getVisibleWorlds()); List>> worldChars = loginBlob.getRight(); int chrTotal = loginBlob.getLeft().getLeft(); diff --git a/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java b/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java index c959937693..9d3fa458a2 100644 --- a/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java +++ b/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java @@ -6,12 +6,12 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.Randomizer; import tools.data.input.SeekableLittleEndianAccessor; -public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler { //Gey class name lol - +public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler { @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { @@ -26,7 +26,8 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand } c.setWorld(server.getCharacterWorld(charId)); - if(c.getWorldServer().isWorldCapacityFull()) { + World wserv = c.getWorldServer(); + if(wserv == null || wserv.isWorldCapacityFull()) { c.announce(MaplePacketCreator.getAfterLoginError(10)); return; } @@ -45,11 +46,16 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand String pic = slea.readMapleAsciiString(); c.setPic(pic); + String[] socket = server.getInetSocket(c.getWorld(), channel); + if (socket == null) { + c.announce(MaplePacketCreator.getAfterLoginError(10)); + return; + } + server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); - String[] socket = server.getIP(c.getWorld(), channel).split(":"); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); } catch (UnknownHostException e) { diff --git a/src/net/server/handlers/login/ViewAllCharSelectedHandler.java b/src/net/server/handlers/login/ViewAllCharSelectedHandler.java index 59d8d31ee2..0edce280d2 100644 --- a/src/net/server/handlers/login/ViewAllCharSelectedHandler.java +++ b/src/net/server/handlers/login/ViewAllCharSelectedHandler.java @@ -27,6 +27,7 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.Randomizer; import tools.data.input.SeekableLittleEndianAccessor; @@ -45,7 +46,9 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler } c.setWorld(server.getCharacterWorld(charId)); - if(c.getWorldServer().isWorldCapacityFull()) { + + World wserv = c.getWorldServer(); + if(wserv == null || wserv.isWorldCapacityFull()) { c.announce(MaplePacketCreator.getAfterLoginError(10)); return; } @@ -58,18 +61,23 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler } try { - int channel = Randomizer.rand(1, c.getWorldServer().getChannelsSize()); + int channel = Randomizer.rand(1, wserv.getChannelsSize()); c.setChannel(channel); } catch (Exception e) { e.printStackTrace(); c.setChannel(1); } + String[] socket = server.getInetSocket(c.getWorld(), c.getChannel()); + if(socket == null) { + c.announce(MaplePacketCreator.getAfterLoginError(10)); + return; + } + server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); - String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":"); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); } catch (UnknownHostException e) { diff --git a/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java b/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java index a5f13bad6b..3dcc5a2aee 100644 --- a/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java +++ b/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java @@ -5,6 +5,7 @@ import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; +import net.server.world.World; import tools.MaplePacketCreator; import tools.Randomizer; import tools.data.input.SeekableLittleEndianAccessor; @@ -27,7 +28,13 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle } c.setWorld(server.getCharacterWorld(charId)); - int channel = Randomizer.rand(1, c.getWorldServer().getChannelsSize()); + World wserv = c.getWorldServer(); + if(wserv == null || wserv.isWorldCapacityFull()) { + c.announce(MaplePacketCreator.getAfterLoginError(10)); + return; + } + + int channel = Randomizer.rand(1, wserv.getChannelsSize()); c.setChannel(channel); String macs = slea.readMapleAsciiString(); @@ -38,7 +45,8 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle } if (c.checkPic(pic)) { - if(c.getWorldServer().isWorldCapacityFull()) { + String[] socket = server.getInetSocket(c.getWorld(), c.getChannel()); + if(socket == null) { c.announce(MaplePacketCreator.getAfterLoginError(10)); return; } @@ -46,8 +54,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); - - String[] socket = server.getIP(c.getWorld(), c.getChannel()).split(":"); + try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); } catch (UnknownHostException e) { diff --git a/src/net/server/worker/ReleaseLockWorker.java b/src/net/server/worker/ReleaseLockWorker.java new file mode 100644 index 0000000000..ee567ee02c --- /dev/null +++ b/src/net/server/worker/ReleaseLockWorker.java @@ -0,0 +1,33 @@ +/* + This file is part of the HeavenMS MapleStory Server + Copyleft (L) 2016 - 2018 RonanLana + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +package net.server.worker; + +import net.server.audit.LockCollector; + +/** + * @author Ronan + * @info Thread responsible for expiring locks signalized for dispose. + */ +public class ReleaseLockWorker implements Runnable { + @Override + public void run() { + LockCollector.getInstance().runLockCollector(); + } +} diff --git a/src/net/server/worker/ServerMessageWorker.java b/src/net/server/worker/ServerMessageWorker.java new file mode 100644 index 0000000000..aab7456b64 --- /dev/null +++ b/src/net/server/worker/ServerMessageWorker.java @@ -0,0 +1,40 @@ +/* + This file is part of the HeavenMS MapleStory Server + Copyleft (L) 2016 - 2018 RonanLana + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +package net.server.worker; + +import net.server.world.World; + +/** + * @author Ronan + */ +public class ServerMessageWorker extends BaseWorker implements Runnable { + + @Override + public void run() { + // It's purpose is for tracking whether the player client currently displays a boss HPBar and, if so, + // temporarily disable the server message for that player. + + wserv.runDisabledServerMessagesSchedule(); + } + + public ServerMessageWorker(World world) { + super(world); + } +} diff --git a/src/net/server/world/MapleParty.java b/src/net/server/world/MapleParty.java index ac93f14522..721a5e1131 100644 --- a/src/net/server/world/MapleParty.java +++ b/src/net/server/world/MapleParty.java @@ -30,9 +30,11 @@ import java.util.HashMap; import java.util.Map.Entry; import java.util.Map; import java.util.Comparator; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; +import server.maps.MapleDoor; public class MapleParty { private int id; @@ -44,11 +46,12 @@ public class MapleParty { private Map histMembers = new HashMap<>(); private int nextEntry = 0; + private Map doors = new HashMap<>(); + private MonitoredReentrantLock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.PARTY, true); public MapleParty(int id, MaplePartyCharacter chrfor) { this.leaderId = chrfor.getId(); - this.members.add(chrfor); this.id = id; } @@ -169,7 +172,7 @@ public class MapleParty { } } - public byte getPartyDoor(int cid) { + public List getMembersSortedByHistory() { List> histList; lock.lock(); @@ -187,16 +190,53 @@ public class MapleParty { return ( o1.getValue() ).compareTo( o2.getValue() ); } }); - + + List histSort = new LinkedList<>(); + for(Entry e : histList) { + histSort.add(e.getKey()); + } + + return histSort; + } + + public byte getPartyDoor(int cid) { + List histList = getMembersSortedByHistory(); byte slot = 0; - for(Entry e: histList) { - if(e.getKey() == cid) break; + for(Integer e: histList) { + if(e == cid) break; slot++; } return slot; } + public void addDoor(Integer owner, MapleDoor door) { + lock.lock(); + try { + this.doors.put(owner, door); + } finally { + lock.unlock(); + } + } + + public void removeDoor(Integer owner) { + lock.lock(); + try { + this.doors.remove(owner); + } finally { + lock.unlock(); + } + } + + public Map getDoors() { + lock.lock(); + try { + return Collections.unmodifiableMap(doors); + } finally { + lock.unlock(); + } + } + public void assignNewLeader(MapleClient c) { World world = c.getWorldServer(); MaplePartyCharacter newLeadr = null; @@ -216,6 +256,15 @@ public class MapleParty { } public void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { lock = lock.dispose(); } diff --git a/src/net/server/world/MaplePartyCharacter.java b/src/net/server/world/MaplePartyCharacter.java index 69b1c70d6b..70d4f50cab 100644 --- a/src/net/server/world/MaplePartyCharacter.java +++ b/src/net/server/world/MaplePartyCharacter.java @@ -21,15 +21,8 @@ */ package net.server.world; -import java.util.Map; -import java.util.Map.Entry; -import java.util.LinkedHashMap; -import java.util.Collection; - -import server.maps.MapleDoor; import client.MapleCharacter; import client.MapleJob; -import java.util.Collections; public class MaplePartyCharacter { private String name; @@ -38,7 +31,6 @@ public class MaplePartyCharacter { private int channel, world; private int jobid; private int mapid; - private Map doors = new LinkedHashMap<>(); private boolean online; private MapleJob job; private MapleCharacter character; @@ -54,9 +46,6 @@ public class MaplePartyCharacter { this.mapid = maplechar.getMapId(); this.online = true; this.job = maplechar.getJob(); - for (Entry entry : maplechar.getDoors().entrySet()) { - doors.put(entry.getKey(), entry.getValue()); - } } public MaplePartyCharacter() { @@ -118,18 +107,6 @@ public class MaplePartyCharacter { public int getGuildId() { return character.getGuildId(); } - - public void addDoor(Integer owner, MapleDoor door) { - this.doors.put(owner, door); - } - - public void removeDoor(Integer owner) { - this.doors.remove(owner); - } - - public Collection getDoors() { - return Collections.unmodifiableCollection(doors.values()); - } @Override public int hashCode() { diff --git a/src/net/server/world/World.java b/src/net/server/world/World.java index 8583bde942..8fa3cb2eb8 100644 --- a/src/net/server/world/World.java +++ b/src/net/server/world/World.java @@ -63,12 +63,15 @@ import server.maps.MaplePlayerShop; import server.maps.MaplePlayerShopItem; import server.maps.AbstractMapleMapObject; import net.server.worker.CharacterAutosaverWorker; +import net.server.worker.HiredMerchantWorker; import net.server.worker.MountTirednessWorker; import net.server.worker.PetFullnessWorker; +import net.server.worker.ServerMessageWorker; import net.server.worker.TimedMapObjectWorker; import net.server.worker.WeddingReservationWorker; import net.server.PlayerStorage; import net.server.Server; +import net.server.audit.LockCollector; import net.server.channel.Channel; import net.server.channel.CharacterIdChannelPair; import net.server.guild.MapleGuild; @@ -119,15 +122,17 @@ public class World { private MonitoredReentrantLock partyLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PARTY, true); private Map owlSearched = new LinkedHashMap<>(); - private MonitoredReentrantLock owlLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_OWL); + private Map disabledServerMessages = new HashMap<>(); // reuse owl lock + private MonitoredReentrantLock srvMessagesLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_SRVMESSAGES); + private ScheduledFuture srvMessagesSchedule; private MonitoredReentrantLock activePetsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_PETS, true); - private Map activePets = new LinkedHashMap<>(); + private Map activePets = new LinkedHashMap<>(); private ScheduledFuture petsSchedule; private long petUpdate; private MonitoredReentrantLock activeMountsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MOUNTS, true); - private Map activeMounts = new LinkedHashMap<>(); + private Map activeMounts = new LinkedHashMap<>(); private ScheduledFuture mountsSchedule; private long mountUpdate; @@ -135,7 +140,8 @@ public class World { private Map activePlayerShops = new LinkedHashMap<>(); private MonitoredReentrantLock activeMerchantsLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.WORLD_MERCHS, true); - private Map> activeMerchants = new LinkedHashMap<>(); + private Map> activeMerchants = new LinkedHashMap<>(); + private ScheduledFuture merchantSchedule; private long merchantUpdate; private Map registeredTimedMapObjects = new LinkedHashMap<>(); @@ -161,7 +167,9 @@ public class World { TimerManager tman = TimerManager.getInstance(); petsSchedule = tman.register(new PetFullnessWorker(this), 60 * 1000, 60 * 1000); + srvMessagesSchedule = tman.register(new ServerMessageWorker(this), 10 * 1000, 10 * 1000); mountsSchedule = tman.register(new MountTirednessWorker(this), 60 * 1000, 60 * 1000); + merchantSchedule = tman.register(new HiredMerchantWorker(this), 10 * 60 * 1000, 10 * 60 * 1000); timedMapObjectsSchedule = tman.register(new TimedMapObjectWorker(this), 60 * 1000, 60 * 1000); charactersSchedule = tman.register(new CharacterAutosaverWorker(this), 60 * 60 * 1000, 60 * 60 * 1000); marriagesSchedule = tman.register(new WeddingReservationWorker(this), ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000, ServerConstants.WEDDING_RESERVATION_INTERVAL * 60 * 1000); @@ -189,7 +197,11 @@ public class World { public Channel getChannel(int channel) { chnRLock.lock(); try { - return channels.get(channel - 1); + try { + return channels.get(channel - 1); + } catch (IndexOutOfBoundsException e) { + return null; + } } finally { chnRLock.unlock(); } @@ -731,6 +743,7 @@ public class World { partyLock.unlock(); } + party.addMember(chrfor); return party; } @@ -784,7 +797,7 @@ public class World { updateCharacterParty(party, operation, target, partyMembers); for (MaplePartyCharacter partychar : partyMembers) { - MapleCharacter chr = getPlayerStorage().getCharacterByName(partychar.getName()); + MapleCharacter chr = getPlayerStorage().getCharacterById(partychar.getId()); if (chr != null) { if (operation == PartyOperation.DISBAND) { chr.setParty(null); @@ -799,7 +812,7 @@ public class World { switch (operation) { case LEAVE: case EXPEL: - MapleCharacter chr = getPlayerStorage().getCharacterByName(target.getName()); + MapleCharacter chr = getPlayerStorage().getCharacterById(target.getId()); if (chr != null) { chr.getClient().announce(MaplePacketCreator.updateParty(chr.getClient().getChannel(), party, operation, target)); chr.setParty(null); @@ -1126,7 +1139,7 @@ public class World { } public void addOwlItemSearch(Integer itemid) { - owlLock.lock(); + srvMessagesLock.lock(); try { Integer cur = owlSearched.get(itemid); if(cur != null) { @@ -1135,7 +1148,7 @@ public class World { owlSearched.put(itemid, 1); } } finally { - owlLock.unlock(); + srvMessagesLock.unlock(); } } @@ -1144,7 +1157,7 @@ public class World { return new ArrayList<>(0); } - owlLock.lock(); + srvMessagesLock.lock(); try { List> searchCounts = new ArrayList<>(owlSearched.size()); @@ -1154,7 +1167,7 @@ public class World { return searchCounts; } finally { - owlLock.unlock(); + srvMessagesLock.unlock(); } } @@ -1167,7 +1180,7 @@ public class World { activePetsLock.lock(); try { - byte initProc; + int initProc; if(System.currentTimeMillis() - petUpdate > 55000) initProc = ServerConstants.PET_EXHAUST_COUNT - 2; else initProc = ServerConstants.PET_EXHAUST_COUNT - 1; @@ -1189,7 +1202,7 @@ public class World { } public void runPetSchedule() { - Map deployedPets; + Map deployedPets; activePetsLock.lock(); try { @@ -1199,11 +1212,11 @@ public class World { activePetsLock.unlock(); } - for(Map.Entry dp: deployedPets.entrySet()) { + for(Map.Entry dp: deployedPets.entrySet()) { MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey() / 4); if(chr == null || !chr.isLoggedinWorld()) continue; - Byte dpVal = (byte)(dp.getValue() + 1); + Integer dpVal = dp.getValue() + 1; if(dpVal == ServerConstants.PET_EXHAUST_COUNT) { chr.runFullnessSchedule(dp.getKey() % 4); dpVal = 0; @@ -1226,7 +1239,7 @@ public class World { Integer key = chr.getId(); activeMountsLock.lock(); try { - byte initProc; + int initProc; if(System.currentTimeMillis() - mountUpdate > 45000) initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 2; else initProc = ServerConstants.MOUNT_EXHAUST_COUNT - 1; @@ -1248,7 +1261,7 @@ public class World { } public void runMountSchedule() { - Map deployedMounts; + Map deployedMounts; activeMountsLock.lock(); try { mountUpdate = System.currentTimeMillis(); @@ -1257,11 +1270,11 @@ public class World { activeMountsLock.unlock(); } - for(Map.Entry dp: deployedMounts.entrySet()) { + for(Map.Entry dp: deployedMounts.entrySet()) { MapleCharacter chr = this.getPlayerStorage().getCharacterById(dp.getKey()); if(chr == null || !chr.isLoggedinWorld()) continue; - Byte dpVal = (byte)(dp.getValue() + 1); + int dpVal = dp.getValue() + 1; if(dpVal == ServerConstants.MOUNT_EXHAUST_COUNT) { chr.runTirednessSchedule(); dpVal = 0; @@ -1320,8 +1333,8 @@ public class World { public void registerHiredMerchant(MapleHiredMerchant hm) { activeMerchantsLock.lock(); try { - byte initProc; - if(System.currentTimeMillis() - merchantUpdate > 5 * 60 * 1000) initProc = 1; + int initProc; + if(Server.getInstance().getCurrentTime() - merchantUpdate > 5 * 60 * 1000) initProc = 1; else initProc = 0; activeMerchants.put(hm.getOwnerId(), new Pair<>(hm, initProc)); @@ -1340,18 +1353,18 @@ public class World { } public void runHiredMerchantSchedule() { - Map> deployedMerchants; + Map> deployedMerchants; activeMerchantsLock.lock(); try { - merchantUpdate = System.currentTimeMillis(); + merchantUpdate = Server.getInstance().getCurrentTime(); deployedMerchants = new LinkedHashMap<>(activeMerchants); - for(Map.Entry> dm: deployedMerchants.entrySet()) { - byte timeOn = dm.getValue().getRight(); + for(Map.Entry> dm: deployedMerchants.entrySet()) { + int timeOn = dm.getValue().getRight(); MapleHiredMerchant hm = dm.getValue().getLeft(); if(timeOn <= 144) { // 1440 minutes == 24hrs - activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), (byte)(timeOn + 1))); + activeMerchants.put(hm.getOwnerId(), new Pair<>(dm.getValue().getLeft(), timeOn + 1)); } else { hm.forceClose(); this.getChannel(hm.getChannel()).removeHiredMerchant(hm.getOwnerId()); @@ -1368,7 +1381,7 @@ public class World { List hmList = new ArrayList<>(); activeMerchantsLock.lock(); try { - for(Pair hmp : activeMerchants.values()) { + for(Pair hmp : activeMerchants.values()) { MapleHiredMerchant hm = hmp.getLeft(); if(hm.isOpen()) { hmList.add(hm); @@ -1397,7 +1410,7 @@ public class World { public void registerTimedMapObject(Runnable r, long duration) { timedMapObjectLock.lock(); try { - long expirationTime = System.currentTimeMillis() + duration; + long expirationTime = Server.getInstance().getCurrentTime() + duration; registeredTimedMapObjects.put(r, expirationTime); } finally { timedMapObjectLock.unlock(); @@ -1409,7 +1422,7 @@ public class World { timedMapObjectLock.lock(); try { - long timeNow = System.currentTimeMillis(); + long timeNow = Server.getInstance().getCurrentTime(); for(Entry rtmo : registeredTimedMapObjects.entrySet()) { if(rtmo.getValue() <= timeNow) { @@ -1429,6 +1442,68 @@ public class World { } } + public void resetDisabledServerMessages() { + srvMessagesLock.lock(); + try { + disabledServerMessages.clear(); + } finally { + srvMessagesLock.unlock(); + } + } + + public boolean registerDisabledServerMessage(int chrid) { + srvMessagesLock.lock(); + try { + boolean alreadyDisabled = disabledServerMessages.containsKey(chrid); + disabledServerMessages.put(chrid, 0); + + return alreadyDisabled; + } finally { + srvMessagesLock.unlock(); + } + } + + public boolean unregisterDisabledServerMessage(int chrid) { + srvMessagesLock.lock(); + try { + return disabledServerMessages.remove(chrid) != null; + } finally { + srvMessagesLock.unlock(); + } + } + + public void runDisabledServerMessagesSchedule() { + List toRemove = new LinkedList<>(); + + srvMessagesLock.lock(); + try { + for(Entry dsm : disabledServerMessages.entrySet()) { + int b = dsm.getValue(); + if(b >= 4) { // ~35sec duration, 10sec update + toRemove.add(dsm.getKey()); + } else { + disabledServerMessages.put(dsm.getKey(), ++b); + } + } + + for(Integer chrid : toRemove) { + disabledServerMessages.remove(chrid); + } + } finally { + srvMessagesLock.unlock(); + } + + if(!toRemove.isEmpty()) { + for(Integer chrid : toRemove) { + MapleCharacter chr = players.getCharacterById(chrid); + + if(chr != null && chr.isLoggedinWorld()) { + chr.announce(MaplePacketCreator.serverMessage(chr.getClient().getChannelServer().getServerMessage())); + } + } + } + } + public void setPlayerNpcMapStep(int mapid, int step) { setPlayerNpcMapData(mapid, step, -1, false); } @@ -1670,7 +1745,7 @@ public class World { } } - private void disposeLocks() { + private void clearWorldData() { List pList; partyLock.lock(); try { @@ -1683,9 +1758,22 @@ public class World { p.disposeLocks(); } + disposeLocks(); + } + + private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { accountCharsLock = accountCharsLock.dispose(); partyLock = partyLock.dispose(); - owlLock = owlLock.dispose(); + srvMessagesLock = srvMessagesLock.dispose(); activePetsLock = activePetsLock.dispose(); activeMountsLock = activeMountsLock.dispose(); activePlayerShopsLock = activePlayerShopsLock.dispose(); @@ -1703,11 +1791,21 @@ public class World { petsSchedule = null; } + if(srvMessagesSchedule != null) { + srvMessagesSchedule.cancel(false); + srvMessagesSchedule = null; + } + if(mountsSchedule != null) { mountsSchedule.cancel(false); mountsSchedule = null; } + if(merchantSchedule != null) { + merchantSchedule.cancel(false); + merchantSchedule = null; + } + if(timedMapObjectsSchedule != null) { timedMapObjectsSchedule.cancel(false); timedMapObjectsSchedule = null; @@ -1726,6 +1824,6 @@ public class World { players.disconnectAll(); players = null; - disposeLocks(); + clearWorldData(); } } diff --git a/src/provider/wz/XMLDomMapleData.java b/src/provider/wz/XMLDomMapleData.java index 09cbccf271..60da8a96fd 100644 --- a/src/provider/wz/XMLDomMapleData.java +++ b/src/provider/wz/XMLDomMapleData.java @@ -22,7 +22,6 @@ package provider.wz; import constants.GameConstants; -import constants.ServerConstants; import java.awt.Point; import java.io.File; import java.io.FileInputStream; @@ -30,8 +29,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Locale; -import java.text.NumberFormat; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -74,22 +71,26 @@ public class XMLDomMapleData implements MapleData { return ((MapleData) getParent()).getChildByPath(path.substring(path.indexOf("/") + 1)); } - Node myNode = node; - for (int x = 0; x < segments.length; x++) { - NodeList childNodes = myNode.getChildNodes(); - boolean foundChild = false; - for (int i = 0; i < childNodes.getLength(); i++) { - Node childNode = childNodes.item(i); - if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getAttributes().getNamedItem("name").getNodeValue().equals(segments[x])) { - myNode = childNode; - foundChild = true; - break; - } - } - if (!foundChild) { - return null; - } - } + Node myNode; + synchronized (this) { // the whole XML reading system seems susceptible to give nulls on strenuous read scenarios + myNode = node; + for (int x = 0; x < segments.length; x++) { + NodeList childNodes = myNode.getChildNodes(); + boolean foundChild = false; + for (int i = 0; i < childNodes.getLength(); i++) { + Node childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE && childNode.getAttributes().getNamedItem("name").getNodeValue().equals(segments[x])) { + myNode = childNode; + foundChild = true; + break; + } + } + if (!foundChild) { + return null; + } + } + } + XMLDomMapleData ret = new XMLDomMapleData(myNode); ret.imageDataDir = new File(imageDataDir, getName() + "/" + path).getParentFile(); return ret; @@ -97,102 +98,114 @@ public class XMLDomMapleData implements MapleData { @Override public List getChildren() { - List ret = new ArrayList(); - NodeList childNodes = node.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node childNode = childNodes.item(i); - if (childNode.getNodeType() == Node.ELEMENT_NODE) { - XMLDomMapleData child = new XMLDomMapleData(childNode); - child.imageDataDir = new File(imageDataDir, getName()); - ret.add(child); - } - } + List ret = new ArrayList<>(); + synchronized (this) { + NodeList childNodes = node.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node childNode = childNodes.item(i); + if (childNode.getNodeType() == Node.ELEMENT_NODE) { + XMLDomMapleData child = new XMLDomMapleData(childNode); + child.imageDataDir = new File(imageDataDir, getName()); + ret.add(child); + } + } + } return ret; } @Override public Object getData() { - NamedNodeMap attributes = node.getAttributes(); - MapleDataType type = getType(); - switch (type) { - case DOUBLE: - case FLOAT: - case INT: - case SHORT: { - String value = attributes.getNamedItem("value").getNodeValue(); - Number nval = GameConstants.parseNumber(value); + synchronized (this) { + NamedNodeMap attributes = node.getAttributes(); + MapleDataType type = getType(); + switch (type) { + case DOUBLE: + case FLOAT: + case INT: + case SHORT: { + String value = attributes.getNamedItem("value").getNodeValue(); + Number nval = GameConstants.parseNumber(value); - switch (type) { - case DOUBLE: - return nval.doubleValue(); - case FLOAT: - return nval.floatValue(); - case INT: - return nval.intValue(); - case SHORT: - return nval.shortValue(); - default: - return null; + switch (type) { + case DOUBLE: + return nval.doubleValue(); + case FLOAT: + return nval.floatValue(); + case INT: + return nval.intValue(); + case SHORT: + return nval.shortValue(); + default: + return null; + } } + case STRING: + case UOL: { + String value = attributes.getNamedItem("value").getNodeValue(); + return value; + } + case VECTOR: { + String x = attributes.getNamedItem("x").getNodeValue(); + String y = attributes.getNamedItem("y").getNodeValue(); + return new Point(Integer.parseInt(x), Integer.parseInt(y)); + } + case CANVAS: { + String width = attributes.getNamedItem("width").getNodeValue(); + String height = attributes.getNamedItem("height").getNodeValue(); + return new FileStoredPngMapleCanvas(Integer.parseInt(width), Integer.parseInt(height), new File( + imageDataDir, getName() + ".png")); + } + default: + return null; } - case STRING: - case UOL: { - String value = attributes.getNamedItem("value").getNodeValue(); - return value; - } - case VECTOR: { - String x = attributes.getNamedItem("x").getNodeValue(); - String y = attributes.getNamedItem("y").getNodeValue(); - return new Point(Integer.parseInt(x), Integer.parseInt(y)); - } - case CANVAS: { - String width = attributes.getNamedItem("width").getNodeValue(); - String height = attributes.getNamedItem("height").getNodeValue(); - return new FileStoredPngMapleCanvas(Integer.parseInt(width), Integer.parseInt(height), new File( - imageDataDir, getName() + ".png")); - } - default: - return null; - } + } } @Override public MapleDataType getType() { - String nodeName = node.getNodeName(); - if (nodeName.equals("imgdir")) { - return MapleDataType.PROPERTY; - } else if (nodeName.equals("canvas")) { - return MapleDataType.CANVAS; - } else if (nodeName.equals("convex")) { - return MapleDataType.CONVEX; - } else if (nodeName.equals("sound")) { - return MapleDataType.SOUND; - } else if (nodeName.equals("uol")) { - return MapleDataType.UOL; - } else if (nodeName.equals("double")) { - return MapleDataType.DOUBLE; - } else if (nodeName.equals("float")) { - return MapleDataType.FLOAT; - } else if (nodeName.equals("int")) { - return MapleDataType.INT; - } else if (nodeName.equals("short")) { - return MapleDataType.SHORT; - } else if (nodeName.equals("string")) { - return MapleDataType.STRING; - } else if (nodeName.equals("vector")) { - return MapleDataType.VECTOR; - } else if (nodeName.equals("null")) { - return MapleDataType.IMG_0x00; - } + String nodeName; + synchronized(this) { + nodeName = node.getNodeName(); + } + + switch (nodeName) { + case "imgdir": + return MapleDataType.PROPERTY; + case "canvas": + return MapleDataType.CANVAS; + case "convex": + return MapleDataType.CONVEX; + case "sound": + return MapleDataType.SOUND; + case "uol": + return MapleDataType.UOL; + case "double": + return MapleDataType.DOUBLE; + case "float": + return MapleDataType.FLOAT; + case "int": + return MapleDataType.INT; + case "short": + return MapleDataType.SHORT; + case "string": + return MapleDataType.STRING; + case "vector": + return MapleDataType.VECTOR; + case "null": + return MapleDataType.IMG_0x00; + } return null; } @Override public MapleDataEntity getParent() { - Node parentNode = node.getParentNode(); - if (parentNode.getNodeType() == Node.DOCUMENT_NODE) { - return null; - } + Node parentNode; + synchronized(this) { + parentNode = node.getParentNode(); + if (parentNode.getNodeType() == Node.DOCUMENT_NODE) { + return null; + } + } XMLDomMapleData parentData = new XMLDomMapleData(parentNode); parentData.imageDataDir = imageDataDir.getParentFile(); return parentData; @@ -200,7 +213,9 @@ public class XMLDomMapleData implements MapleData { @Override public String getName() { - return node.getAttributes().getNamedItem("name").getNodeValue(); + synchronized (this) { + return node.getAttributes().getNamedItem("name").getNodeValue(); + } } @Override diff --git a/src/scripting/event/EventInstanceManager.java b/src/scripting/event/EventInstanceManager.java index 4bde63d243..8746f822c4 100644 --- a/src/scripting/event/EventInstanceManager.java +++ b/src/scripting/event/EventInstanceManager.java @@ -35,6 +35,7 @@ import java.util.Set; import java.util.Iterator; import java.util.Properties; import javax.script.ScriptException; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.MonitoredReentrantReadWriteLock; @@ -232,12 +233,11 @@ public class EventInstanceManager { wL.lock(); try { chars.put(chr.getId(), chr); + chr.setEventInstance(this); } finally { wL.unlock(); } - chr.setEventInstance(this); - sL.lock(); try { em.getIv().invokeFunction("playerEntry", this, chr); @@ -403,14 +403,13 @@ public class EventInstanceManager { wL.lock(); try { chars.remove(chr.getId()); + chr.setEventInstance(null); } finally { wL.unlock(); } gridRemove(chr); dropExclusiveItems(chr); - - chr.setEventInstance(null); } public int getPlayerCount() { @@ -635,6 +634,13 @@ public class EventInstanceManager { } public void dispose() { + rL.lock(); + try { + for(MapleCharacter chr: chars.values()) chr.setEventInstance(null); + } finally { + rL.unlock(); + } + Thread t = new Thread( new Runnable() { @Override public void run() { @@ -645,7 +651,7 @@ public class EventInstanceManager { t.start(); } - public synchronized void dispose(boolean shutdown) { + public synchronized void dispose(boolean shutdown) { // should not trigger any event script method after disposed if(disposed) return; disposed = true; @@ -660,14 +666,12 @@ public class EventInstanceManager { ex.printStackTrace(); } + mapFactory.dispose(); wL.lock(); try { for(MapleCharacter chr: chars.values()) chr.setEventInstance(null); chars.clear(); - mobs.clear(); - - mapFactory.dispose(); mapFactory = null; } finally { wL.unlock(); @@ -696,6 +700,15 @@ public class EventInstanceManager { } private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { pL = pL.dispose(); sL = sL.dispose(); } @@ -878,9 +891,9 @@ public class EventInstanceManager { return (chr.getId() == getLeaderId()); } - public final MapleMap getInstanceMap(final int mapid) { //gets instance map from the channelserv + public final MapleMap getInstanceMap(final int mapid) { if (disposed) { - return getMapFactory().getMap(mapid); + return null; } mapIds.add(mapid); return getMapFactory().getMap(mapid); @@ -1310,15 +1323,20 @@ public class EventInstanceManager { } public final void recoverOpenedGate(MapleCharacter chr, int thisMapId) { + Pair gateData = null; + rL.lock(); try { if(openedGates.containsKey(thisMapId)) { - Pair gateData = openedGates.get(thisMapId); - chr.announce(MaplePacketCreator.environmentChange(gateData.getLeft(), gateData.getRight())); + gateData = openedGates.get(thisMapId); } } finally { rL.unlock(); } + + if(gateData != null) { + chr.announce(MaplePacketCreator.environmentChange(gateData.getLeft(), gateData.getRight())); + } } public final void giveEventPlayersStageReward(int thisStage) { diff --git a/src/scripting/event/EventManager.java b/src/scripting/event/EventManager.java index efa760bea4..3ca2b74ea0 100644 --- a/src/scripting/event/EventManager.java +++ b/src/scripting/event/EventManager.java @@ -52,6 +52,7 @@ import java.util.List; import java.util.ArrayList; import java.util.LinkedList; import java.util.Queue; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -131,6 +132,15 @@ public class EventManager { } private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { lobbyLock = lobbyLock.dispose(); queueLock = queueLock.dispose(); } @@ -333,7 +343,9 @@ public class EventManager { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel())); if(eim == null) { - if(lobbyId > -1) setLockLobby(lobbyId, false); + if(lobbyId > -1) { + setLockLobby(lobbyId, false); + } return false; } instanceLocks.put(eim.getName(), lobbyId); @@ -363,15 +375,21 @@ public class EventManager { try { if(lobbyId == -1) { lobbyId = availableLobbyInstance(); - if(lobbyId == -1) return false; + if(lobbyId == -1) { + return false; + } } else { - if(!startLobbyInstance(lobbyId)) return false; + if(!startLobbyInstance(lobbyId)) { + return false; + } } EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId())); if(eim == null) { - if(lobbyId > -1) setLockLobby(lobbyId, false); + if(lobbyId > -1) { + setLockLobby(lobbyId, false); + } return false; } instanceLocks.put(eim.getName(), lobbyId); @@ -408,7 +426,9 @@ public class EventManager { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null)); if(eim == null) { - if(lobbyId > -1) setLockLobby(lobbyId, false); + if(lobbyId > -1) { + setLockLobby(lobbyId, false); + } return false; } instanceLocks.put(eim.getName(), lobbyId); @@ -446,7 +466,9 @@ public class EventManager { EventInstanceManager eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId())); if(eim == null) { - if(lobbyId > -1) setLockLobby(lobbyId, false); + if(lobbyId > -1) { + setLockLobby(lobbyId, false); + } return false; } instanceLocks.put(eim.getName(), lobbyId); @@ -487,7 +509,9 @@ public class EventManager { } if(eim == null) { - if(lobbyId > -1) setLockLobby(lobbyId, false); + if(lobbyId > -1) { + setLockLobby(lobbyId, false); + } return false; } instanceLocks.put(eim.getName(), lobbyId); diff --git a/src/scripting/event/worker/EventScriptScheduler.java b/src/scripting/event/worker/EventScriptScheduler.java index 974be7c593..665be89384 100644 --- a/src/scripting/event/worker/EventScriptScheduler.java +++ b/src/scripting/event/worker/EventScriptScheduler.java @@ -28,6 +28,7 @@ import java.util.Map.Entry; import java.util.concurrent.ScheduledFuture; import server.TimerManager; import net.server.Server; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -161,10 +162,23 @@ public class EventScriptScheduler { schedulerLock.unlock(); } - schedulerLock = schedulerLock.dispose(); + disposeLocks(); } }); t.start(); } + + private void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { + schedulerLock = schedulerLock.dispose(); + } } diff --git a/src/scripting/quest/QuestActionManager.java b/src/scripting/quest/QuestActionManager.java index 9c8001f8ba..26081fa2c2 100644 --- a/src/scripting/quest/QuestActionManager.java +++ b/src/scripting/quest/QuestActionManager.java @@ -25,6 +25,8 @@ import client.MapleClient; import scripting.npc.NPCConversationManager; import server.MapleItemInformationProvider; import server.quest.MapleQuest; +import server.quest.actions.ExpAction; +import server.quest.actions.MesoAction; /** * @@ -71,6 +73,16 @@ public class QuestActionManager extends NPCConversationManager { forceCompleteQuest(); } + @Override + public void gainExp(int gain) { + ExpAction.runAction(getPlayer(), gain); + } + + @Override + public void gainMeso(int gain) { + MesoAction.runAction(getPlayer(), gain); + } + public String getMedalName() { // usable only for medal quests (id 299XX) MapleQuest q = MapleQuest.getInstance(quest); return MapleItemInformationProvider.getInstance().getName(q.getMedalRequirement()); diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index f13ac63df2..5576be91f8 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -897,15 +897,7 @@ public class MapleStatEffect { MapleDoor door = new MapleDoor(applyto, doorPosition); if(door.getOwnerId() >= 0) { - if (applyto.getParty() != null) { - for (MaplePartyCharacter partyMember : applyto.getParty().getMembers()) { - partyMember.getPlayer().addDoor(door.getOwnerId(), door); - partyMember.addDoor(door.getOwnerId(), door); - } - applyto.silentPartyUpdate(); - } else { - applyto.addDoor(door.getOwnerId(), door); - } + applyto.applyPartyDoor(door, false); door.getTarget().spawnDoor(door.getAreaDoor()); door.getTown().spawnDoor(door.getTownDoor()); diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java index d6b0111629..f7bb54ec9d 100644 --- a/src/server/life/MapleMonster.java +++ b/src/server/life/MapleMonster.java @@ -69,6 +69,7 @@ import server.maps.MapleMapObjectType; import tools.MaplePacketCreator; import tools.Pair; import tools.Randomizer; +import net.server.audit.LockCollector; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; @@ -823,10 +824,6 @@ public class MapleMonster extends AbstractLoadedMapleLife { } if (hasBossHPBar()) { - if (this.getMap().countMonster(8810026) > 0 && this.getMap().getId() == 240060200) { - this.getMap().killAllMonsters(); - return; - } c.announceBossHpBar(this, this.hashCode(), makeBossHPBarPacket()); } } @@ -855,12 +852,7 @@ public class MapleMonster extends AbstractLoadedMapleLife { statiLock.unlock(); } - monsterLock.lock(); - try { - return stats.getEffectiveness(e); - } finally { - monsterLock.unlock(); - } + return getMonsterEffectiveness(e); } private ElementalEffectiveness getMonsterEffectiveness(Element e) { @@ -1478,6 +1470,15 @@ public class MapleMonster extends AbstractLoadedMapleLife { } public final void disposeLocks() { + LockCollector.getInstance().registerDisposeAction(new Runnable() { + @Override + public void run() { + emptyLocks(); + } + }); + } + + private void emptyLocks() { externalLock = externalLock.dispose(); monsterLock = monsterLock.dispose(); statiLock = statiLock.dispose(); diff --git a/src/server/maps/MapleDoor.java b/src/server/maps/MapleDoor.java index 8f05336911..7da336de0d 100644 --- a/src/server/maps/MapleDoor.java +++ b/src/server/maps/MapleDoor.java @@ -22,7 +22,6 @@ package server.maps; import java.awt.Point; -import java.util.List; import tools.Pair; import server.MaplePortal; @@ -43,7 +42,7 @@ public class MapleDoor { private MapleDoorObject townDoor; private MapleDoorObject areaDoor; - + public MapleDoor(MapleCharacter owner, Point targetPosition) { this.ownerId = owner.getId(); this.target = owner.getMap(); @@ -55,11 +54,11 @@ public class MapleDoor { if(posStatus == null) { this.town = this.target.getReturnMap(); - this.townPortal = getDoorPortal(owner.getDoorSlot()); + this.townPortal = getTownDoorPortal(owner.getDoorSlot()); if(townPortal != null) { - this.areaDoor = new MapleDoorObject(ownerId, town, target, false, targetPosition, townPortal.getPosition()); - this.townDoor = new MapleDoorObject(ownerId, target, town, true, townPortal.getPosition(), targetPosition); + this.areaDoor = new MapleDoorObject(ownerId, town, target, townPortal.getId(), targetPosition, townPortal.getPosition()); + this.townDoor = new MapleDoorObject(ownerId, target, town, -1, townPortal.getPosition(), targetPosition); this.areaDoor.setPairOid(this.townDoor.getObjectId()); this.townDoor.setPairOid(this.areaDoor.getObjectId()); @@ -74,20 +73,20 @@ public class MapleDoor { } } - private MaplePortal getDoorPortal(int slot) { - List avail = town.getAvailableDoorPortals(); + public void updateDoorPortal(MapleCharacter owner) { + int slot = owner.fetchDoorSlot(); - try { - return avail.get(slot); - } catch (IndexOutOfBoundsException e) { - try { - return avail.get(0); - } catch (IndexOutOfBoundsException ex) { - return null; - } + MaplePortal nextTownPortal = getTownDoorPortal(slot); + if(nextTownPortal != null) { + townPortal = nextTownPortal; + areaDoor.update(nextTownPortal.getId(), nextTownPortal.getPosition()); } } + private MaplePortal getTownDoorPortal(int doorid) { + return town.getDoorPortal(doorid); + } + public int getOwnerId() { return ownerId; } diff --git a/src/server/maps/MapleDoorObject.java b/src/server/maps/MapleDoorObject.java index 750d60c0e4..3dcded4632 100644 --- a/src/server/maps/MapleDoorObject.java +++ b/src/server/maps/MapleDoorObject.java @@ -20,8 +20,11 @@ package server.maps; import java.awt.Point; +import java.util.concurrent.locks.ReentrantReadWriteLock; import client.MapleCharacter; import client.MapleClient; +import net.server.audit.locks.MonitoredLockType; +import net.server.audit.locks.MonitoredReentrantReadWriteLock; import tools.MaplePacketCreator; /** @@ -29,28 +32,66 @@ import tools.MaplePacketCreator; * @author Ronan */ public class MapleDoorObject extends AbstractMapleMapObject { - private int ownerId; + private final int ownerId; private int pairOid; - private boolean isTown; - private MapleMap from; - private MapleMap to; - private Point toPos; + private final MapleMap from; + private final MapleMap to; + private int linkedPortalId; + private Point linkedPos; - public MapleDoorObject(int owner, MapleMap destination, MapleMap origin, boolean town, Point targetPosition, Point toPosition) { + private final ReentrantReadWriteLock locks = new MonitoredReentrantReadWriteLock(MonitoredLockType.PLAYER_DOOR, true); + private ReentrantReadWriteLock.ReadLock rlock = locks.readLock(); + private ReentrantReadWriteLock.WriteLock wlock = locks.writeLock(); + + public MapleDoorObject(int owner, MapleMap destination, MapleMap origin, int townPortalId, Point targetPosition, Point toPosition) { super(); setPosition(targetPosition); ownerId = owner; - isTown = town; + linkedPortalId = townPortalId; from = origin; to = destination; - toPos = toPosition; + linkedPos = toPosition; + } + + public void update(int townPortalId, Point toPosition) { + wlock.lock(); + try { + linkedPortalId = townPortalId; + linkedPos = toPosition; + } finally { + wlock.unlock(); + } + } + + private int getLinkedPortalId() { + rlock.lock(); + try { + return linkedPortalId; + } finally { + rlock.unlock(); + } + } + + private Point getLinkedPortalPosition() { + rlock.lock(); + try { + return linkedPos; + } finally { + rlock.unlock(); + } } public void warp(final MapleCharacter chr) { - if (chr.getId() == ownerId || (chr.getParty() != null && chr.getParty().getMemberById(ownerId) != null)) { - chr.changeMap(to, toPos); + boolean onParty = chr.getParty() != null; + + if (chr.getId() == ownerId || (onParty && chr.getParty().getMemberById(ownerId) != null)) { + if(!inTown() && !onParty) { + chr.changeMap(to, getLinkedPortalId()); + } else { + chr.changeMap(to, getLinkedPortalPosition()); + } } else { chr.getClient().announce(MaplePacketCreator.blockedMessage(6)); chr.getClient().announce(MaplePacketCreator.enableActions()); @@ -75,7 +116,14 @@ public class MapleDoorObject extends AbstractMapleMapObject { if (client.getPlayer().getParty() != null && (ownerId == client.getPlayer().getId() || client.getPlayer().getParty().getMemberById(ownerId) != null)) { client.announce(MaplePacketCreator.partyPortal(999999999, 999999999, new Point(-1, -1))); } - client.announce(MaplePacketCreator.removeDoor(ownerId, isTown)); + client.announce(MaplePacketCreator.removeDoor(ownerId, inTown())); + } + } + + public void sendDestroyData(MapleClient client, boolean partyUpdate) { + if (client != null && from.getId() == client.getPlayer().getMapId()) { + client.announce(MaplePacketCreator.partyPortal(999999999, 999999999, new Point(-1, -1))); + client.announce(MaplePacketCreator.removeDoor(ownerId, inTown())); } } @@ -92,7 +140,7 @@ public class MapleDoorObject extends AbstractMapleMapObject { } public boolean inTown() { - return isTown; + return getLinkedPortalId() == -1; } public MapleMap getFrom() { @@ -104,19 +152,19 @@ public class MapleDoorObject extends AbstractMapleMapObject { } public MapleMap getTown() { - return isTown ? from : to; + return inTown() ? from : to; } public MapleMap getArea() { - return !isTown ? from : to; + return !inTown() ? from : to; } public Point getAreaPosition() { - return !isTown ? getPosition() : toPos; + return !inTown() ? getPosition() : getLinkedPortalPosition(); } public Point toPosition() { - return toPos; + return getLinkedPortalPosition(); } @Override diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java index 6677269ee9..bb030829a3 100644 --- a/src/server/maps/MapleMap.java +++ b/src/server/maps/MapleMap.java @@ -982,7 +982,7 @@ public class MapleMap { } private static boolean shouldShowQuestItem(MapleCharacter chr, int questid, int itemid) { - return questid <= 0 || (chr.getQuestStatus(questid) == 1 && chr.needQuestItem(questid, itemid)); + return questid <= 0 || chr.needQuestItem(questid, itemid); } public void updatePlayerItemDrops(int partyid, int charid, List partyMembers, MapleCharacter partyLeaver) { @@ -1462,7 +1462,7 @@ public class MapleMap { removeMapObject(reactor); if (reactor.getDelay() > 0) { - TimerManager.getInstance().schedule(new Runnable() { + registerMapSchedule(new Runnable() { @Override public void run() { respawnReactor(reactor); @@ -1857,14 +1857,14 @@ public class MapleMap { final selfDestruction selfDestruction = monster.getStats().selfDestruction(); if (monster.getStats().removeAfter() > 0 || selfDestruction != null && selfDestruction.getHp() < 0) { if (selfDestruction == null) { - TimerManager.getInstance().schedule(new Runnable() { + registerMapSchedule(new Runnable() { @Override public void run() { killMonster(monster, null, false); } }, monster.getStats().removeAfter() * 1000); } else { - TimerManager.getInstance().schedule(new Runnable() { + registerMapSchedule(new Runnable() { @Override public void run() { killMonster(monster, null, false, selfDestruction.getAction()); @@ -2037,23 +2037,16 @@ public class MapleMap { }); } - public List getAvailableDoorPortals() { - objectRLock.lock(); - try { - List availablePortals = new ArrayList<>(); - - for (MaplePortal port : portals.values()) { - if (port.getType() == MaplePortal.DOOR_PORTAL) { - availablePortals.add(port); - } - } - - return availablePortals; - } finally { - objectRLock.unlock(); + public MaplePortal getDoorPortal(int doorid) { + MaplePortal doorPortal = portals.get(0x80 + doorid); + if(doorPortal == null) { + FilePrinter.printError(FilePrinter.EXCEPTION, "[DOOR] " + mapName + "(" + mapid + ") does not contain door portalid " + doorid); + return portals.get(0x80); } + + return doorPortal; } - + public void spawnSummon(final MapleSummon summon) { spawnAndAddRangedMapObject(summon, new DelayedPacketCreation() { @Override @@ -2945,7 +2938,7 @@ public class MapleMap { public MaplePortal getPortal(int portalid) { return portals.get(portalid); } - + public void addMapleArea(Rectangle rec) { areas.add(rec); } @@ -3323,8 +3316,9 @@ public class MapleMap { reactor.hitReactor(c); if (reactor.getDelay() > 0) { - TimerManager tMan = TimerManager.getInstance(); - tMan.schedule(new Runnable() { + MapleMap reactorMap = reactor.getMap(); + + reactorMap.getChannelServer().registerOverallAction(reactorMap.getId(), new Runnable() { @Override public void run() { reactor.lockReactor(); diff --git a/src/server/maps/MapleMapItem.java b/src/server/maps/MapleMapItem.java index 3d883a94d2..2a2624bf7f 100644 --- a/src/server/maps/MapleMapItem.java +++ b/src/server/maps/MapleMapItem.java @@ -184,7 +184,7 @@ public class MapleMapItem extends AbstractMapleMapObject { public void sendSpawnData(final MapleClient client) { MapleCharacter chr = client.getPlayer(); - if (questid <= 0 || (chr.getQuestStatus(questid) == 1 && chr.needQuestItem(questid, item.getItemId()))) { + if (questid <= 0 || chr.needQuestItem(questid, item.getItemId())) { this.lockItem(); try { client.announce(MaplePacketCreator.dropItemFromMapObject(chr.getParty() != null, this, null, getPosition(), (byte) 2)); diff --git a/src/server/quest/actions/ExpAction.java b/src/server/quest/actions/ExpAction.java index 6ed18644c5..7fa62aac6f 100644 --- a/src/server/quest/actions/ExpAction.java +++ b/src/server/quest/actions/ExpAction.java @@ -48,14 +48,18 @@ public class ExpAction extends MapleQuestAction { @Override public void run(MapleCharacter chr, Integer extSelection) { - if (chr.isBeginnerJob() && chr.getLevel() < 10) { - chr.gainExp(exp, true, true); + runAction(chr, exp); + } + + public static void runAction(MapleCharacter chr, int gain) { + if (chr.isBeginnerJob() && chr.getLevel() < 10) { + chr.gainExp(gain, true, true); } else { if(!ServerConstants.USE_QUEST_RATE) { - chr.gainExp(exp * chr.getExpRate(), true, true); + chr.gainExp(gain * chr.getExpRate(), true, true); } else { - chr.gainExp(exp * ServerConstants.EXP_RATE * ServerConstants.QUEST_RATE, true, true); + chr.gainExp(gain * ServerConstants.EXP_RATE * ServerConstants.QUEST_RATE, true, true); } } - } + } } diff --git a/src/server/quest/actions/MesoAction.java b/src/server/quest/actions/MesoAction.java index 9ea5c7d561..791c39f392 100644 --- a/src/server/quest/actions/MesoAction.java +++ b/src/server/quest/actions/MesoAction.java @@ -49,14 +49,18 @@ public class MesoAction extends MapleQuestAction { @Override public void run(MapleCharacter chr, Integer extSelection) { - if(mesos < 0) { - chr.gainMeso(mesos, true, false, true); + runAction(chr, mesos); + } + + public static void runAction(MapleCharacter chr, int gain) { + if(gain < 0) { + chr.gainMeso(gain, true, false, true); } else { if(!ServerConstants.USE_QUEST_RATE) { - chr.gainMeso(mesos * chr.getMesoRate(), true, false, true); + chr.gainMeso(gain * chr.getMesoRate(), true, false, true); } else { - chr.gainMeso(mesos * ServerConstants.MESO_RATE * ServerConstants.QUEST_RATE, true, false, true); + chr.gainMeso(gain * ServerConstants.MESO_RATE * ServerConstants.QUEST_RATE, true, false, true); } } - } + } } diff --git a/src/tools/FilePrinter.java b/src/tools/FilePrinter.java index e5d9e3875e..95e798e2f8 100644 --- a/src/tools/FilePrinter.java +++ b/src/tools/FilePrinter.java @@ -49,7 +49,8 @@ public class FilePrinter { DEADLOCK_ERROR = "deadlocks.txt", DEADLOCK_STACK = "deadlocks/path.txt", DEADLOCK_LOCKS = "deadlocks/locks.txt", - DEADLOCK_STATE = "deadlocks/state.txt"; + DEADLOCK_STATE = "deadlocks/state.txt", + DISPOSED_LOCKS = "deadlocks/disposed.txt"; private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); //for file system purposes, it's nice to use yyyy-MM-dd private static final String FILE_PATH = "logs/" + sdf.format(Calendar.getInstance().getTime()) + "/"; // + sdf.format(Calendar.getInstance().getTime()) + "/" diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index da14024165..9735bd1739 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -628,7 +628,7 @@ public class MaplePacketCreator { public static byte[] getAfterLoginError(int reason) {//same as above o.o final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(8); mplew.writeShort(SendOpcode.SELECT_CHARACTER_BY_VAC.getValue()); - mplew.writeShort(reason);//using other types then stated above = CRASH + mplew.writeShort(reason);//using other types than stated above = CRASH return mplew.getPacket(); } @@ -677,6 +677,8 @@ public class MaplePacketCreator { * @return the successful authentication packet */ public static byte[] getAuthSuccess(MapleClient c) { + Server.getInstance().loadAccountCharacters(c); // locks the login session until data is recovered from the cache or the DB. + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.LOGIN_STATUS.getValue()); mplew.writeInt(0); @@ -686,7 +688,7 @@ public class MaplePacketCreator { boolean canFly = Server.getInstance().canFly(c.getAccID()); mplew.writeBool((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) ? c.getGMLevel() > 1 : false); // thanks Steve(kaito1410) for pointing the GM account boolean here - mplew.write((c.getGMLevel() > 1 && canFly) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish. + mplew.write(((ServerConstants.USE_ENFORCE_ADMIN_ACCOUNT || canFly) && c.getGMLevel() > 1) ? 0x80 : 0); // Admin Byte. 0x80,0x40,0x20.. Rubbish. mplew.write(0); // Country Code. mplew.writeMapleAsciiString(c.getAccountName()); @@ -3689,27 +3691,23 @@ public class MaplePacketCreator { return mplew.getPacket(); } - public static byte[] partyCreated(MaplePartyCharacter partychar, int partyId) { + public static byte[] partyCreated(MapleParty party, int partycharid) { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.PARTY_OPERATION.getValue()); mplew.write(8); - mplew.writeInt(partyId); - if (partychar.getDoors().size() > 0) { - boolean deployedPortal = false; - - for (MapleDoor door : partychar.getDoors()) { - if(door.getOwnerId() == partychar.getId()) { - MapleDoorObject mdo = door.getAreaDoor(); - mplew.writeInt(mdo.getTo().getId()); - mplew.writeInt(mdo.getFrom().getId()); - mplew.writeInt(mdo.getPosition().x); - mplew.writeInt(mdo.getPosition().y); - - deployedPortal = true; - } - } + mplew.writeInt(party.getId()); + + Map partyDoors = party.getDoors(); + if (partyDoors.size() > 0) { + MapleDoor door = partyDoors.get(partycharid); - if(!deployedPortal) { + if(door != null) { + MapleDoorObject mdo = door.getAreaDoor(); + mplew.writeInt(mdo.getTo().getId()); + mplew.writeInt(mdo.getFrom().getId()); + mplew.writeInt(mdo.getPosition().x); + mplew.writeInt(mdo.getPosition().y); + } else { mplew.writeInt(999999999); mplew.writeInt(999999999); mplew.writeInt(0); @@ -3798,24 +3796,19 @@ public class MaplePacketCreator { lew.writeInt(0); } } + + Map partyDoors = party.getDoors(); for (MaplePartyCharacter partychar : partymembers) { if (partychar.getChannel() == forchannel && !leaving) { - if (partychar.getDoors().size() > 0) { - boolean deployedPortal = false; - - for (MapleDoor door : partychar.getDoors()) { - if(door.getOwnerId() == partychar.getId()) { - MapleDoorObject mdo = door.getTownDoor(); - lew.writeInt(mdo.getTown().getId()); - lew.writeInt(mdo.getArea().getId()); - lew.writeInt(mdo.getPosition().x); - lew.writeInt(mdo.getPosition().y); - - deployedPortal = true; - } - } - - if(!deployedPortal) { + if (partyDoors.size() > 0) { + MapleDoor door = partyDoors.get(partychar.getId()); + if(door != null) { + MapleDoorObject mdo = door.getTownDoor(); + lew.writeInt(mdo.getTown().getId()); + lew.writeInt(mdo.getArea().getId()); + lew.writeInt(mdo.getPosition().x); + lew.writeInt(mdo.getPosition().y); + } else { lew.writeInt(999999999); lew.writeInt(999999999); lew.writeInt(0); diff --git a/wz/Etc.wz/ItemMake.img.xml b/wz/Etc.wz/ItemMake.img.xml index b87058d68e..e417721170 100644 --- a/wz/Etc.wz/ItemMake.img.xml +++ b/wz/Etc.wz/ItemMake.img.xml @@ -8702,7 +8702,7 @@ - + diff --git a/wz/Item.wz/Consume/0204.img.xml b/wz/Item.wz/Consume/0204.img.xml index 1499cfa268..52eb310c29 100644 --- a/wz/Item.wz/Consume/0204.img.xml +++ b/wz/Item.wz/Consume/0204.img.xml @@ -2561,6 +2561,7 @@ + @@ -2579,6 +2580,7 @@ + @@ -2597,6 +2599,7 @@ + @@ -2615,6 +2618,7 @@ + @@ -2633,6 +2637,7 @@ + @@ -2651,6 +2656,7 @@ + @@ -2669,6 +2675,7 @@ + @@ -2687,6 +2694,7 @@ + @@ -2705,6 +2713,7 @@ + @@ -2723,6 +2732,7 @@ + @@ -2742,6 +2752,7 @@ + @@ -2771,6 +2782,7 @@ + diff --git a/wz/Map.wz/Map/Map1/106021400.img.xml b/wz/Map.wz/Map/Map1/106021400.img.xml index 9f8c9b9468..ba876f778e 100644 --- a/wz/Map.wz/Map/Map1/106021400.img.xml +++ b/wz/Map.wz/Map/Map1/106021400.img.xml @@ -2423,7 +2423,7 @@ - + diff --git a/wz/Map.wz/Map/Map2/250000000.img.xml b/wz/Map.wz/Map/Map2/250000000.img.xml index 2b9e7584ef..e02373cbb0 100644 --- a/wz/Map.wz/Map/Map2/250000000.img.xml +++ b/wz/Map.wz/Map/Map2/250000000.img.xml @@ -1,11893 +1,22 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + @@ -11898,254 +27,12168 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + - - - - - - - - - + + + + + + - - - - - - - - - + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + - + + - - + - - + + - + - - + + - + - - + + - - + + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wz/Map.wz/Map/Map2/261000000.img.xml b/wz/Map.wz/Map/Map2/261000000.img.xml index 01a92c5875..d86ffae50e 100644 --- a/wz/Map.wz/Map/Map2/261000000.img.xml +++ b/wz/Map.wz/Map/Map2/261000000.img.xml @@ -1,9135 +1,8470 @@ - - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - + + - - + + + + - - - - + + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + + + + - - - - + + + + - - - - - + + + + + - + + + + + - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - + - - - - + + + + - - - - + + + + - + + + + + - + + + + + - - - - - - - - - + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - + + + + + - + + + + + - - - - - + + + + + + + + - - - - - - - - - - - - + - - - - - + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - + + + + + - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + - - - - - - - - + + + + - + + + + + + + + + - - - - - + - - - - - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - - - + + + - - - + + + - - - + + + - - - - + + + + - - - + + + - - - + + + - - - + + + - + + + + + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - - - - + + + + - - - - + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + - - - - - - - - + - - - + + - - - - - - - - + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + - - - + + - - - - - - - - - - - - - - - - - - - - - - - + + - - + + + + + + + + + + - - - - + + + + + + + + + + + - + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + - - - - - - - + - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - + + + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + - - - - - - - + + + + + + + + + + + + + + - - - - + + + + - - - - - - + + + + + - - - - - + + + - - - - - - - + + + + + + + + + - - + + - - - + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - + - + - - - - - - - - + + - - - + + - - + + + + + + + + + + + + + + + + + - - - - - - + + + - - - - - - - - - - + + + + + - - - - - + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + - + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + + - - - - - - - - - + + + + + - - - - - - - - - + + + + + - - - - - - - - - + + + + + - - - - - - - - - + + + + + - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - + + + + + + - - - - - - - - - - - - - - - - + + + + + + - - + + - - - - - - + + + + + + @@ -9137,1670 +8472,982 @@ - + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + - + - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - + - - + + - - + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - + + + + + + + - + - + - + - + - + + + + + + + + + @@ -10808,1711 +9455,121 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -12520,115 +9577,3277 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - + - - + + - + - - + + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + @@ -12636,2461 +12855,1797 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + - - + + - + - - + + - + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + - - + + - + + + + + + + + + - - + + - + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + - + - + - - + + - + + + + + + + + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - - - - - - - - + - - + + - + + + + + + + + + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - - - - - - - - - + - - + + - + - - + + - - + + - + - - + + - - - - - - - - - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + + - + - - + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + - - + + - - - - - - - - - + - + - - - - - - - - - + - - + + + + + + + + + + + + + + + + + + - + + + + + + + + + - + - - - - - - - - - + - - + + - - - - - - - - - - - - - - - - - + - - + + - + + + + + + + + + + + + + + + + + - - + + - + - - + + - + - - + + - + - + - + + + + + + + + + - + - - - - - - - - - + - - + + - - - - - - - - - - - - - - - - - + - - + + - - - - - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -15100,442 +14655,932 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/wz/Map.wz/Map/Map6/600000000.img.xml b/wz/Map.wz/Map/Map6/600000000.img.xml index e7662c63b4..34ff620cb8 100644 --- a/wz/Map.wz/Map/Map6/600000000.img.xml +++ b/wz/Map.wz/Map/Map6/600000000.img.xml @@ -1,7053 +1,6092 @@ - - - - - - - - + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - + + + + - - - - + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + + + - - + + + + - - - - + + + + - - - - - + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - + + + - + + + + + - + + + + + - - - - - + + + + + - - - - - - - - - + - - - - + + + + - - - + + + - - - + + + - - - - + + + + - - - + + + - + + + + + - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - - - - - + - - - - + + + + - + + + + + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - - - - - + - - - - + + + + - - - - + + + + - - - - + + + + - + + + + + - + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - + + + + + - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - - - - - + + + + + + + + + - - - - - + - - - - - - - - + + + + - + + + + + + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - - - - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + - - - - - + - - - - + + + + - - - - + + + + - - - - + + + + - + + + + + - + + + + + - - - - - + - + + + + + - - - - - + - + + + + + - - - - - + + + - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - + + - + - - + + - + - - + + - - - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -7056,1236 +6095,1306 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - - - - - - - - - - - - - - - - - + - + - - - + + + - + - - + + - + + + + + + + + + - + - - + + - + - - + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -8293,2803 +7402,1465 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - + + + + + + + + + + + + + - + - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - + + + + - + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - + + + + - + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - - - + + + + + + - - - - - + + + + + - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + + + + + + - - + + - + - - + + - + - - + + - + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - + + + + + + + - + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + - - + + - + - - + + - - - - - - - + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - + + + + + + + - + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -11097,333 +8868,1141 @@ - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + - + - + + + + + + + + + - - + + - + - - + + - + - - + + - + - - + + - + + + + + + + + + - - + + - + - + - - - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - + - + - - - - - - - - - + - + - + - + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + + + - - - - - - - + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -11432,451 +10011,1923 @@ - - - - - - - - + + + + + + - + - - - - - - - + + + + + + + - - - - - + + + + + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + + - - - - - - + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + diff --git a/wz/String.wz/Npc.img.xml b/wz/String.wz/Npc.img.xml index e8a85d6e4e..6f61614528 100644 --- a/wz/String.wz/Npc.img.xml +++ b/wz/String.wz/Npc.img.xml @@ -3938,7 +3938,7 @@ - +