diff --git a/README.md b/README.md index 33a2d0e088..4e5d652328 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,8 @@ If you liked this project, please don't forget to __star__ the repo ;) . It's never enough to tell this, thanks to everyone that have been contributing something for the continuous improvement of the server! Be it through bug reports, donation, code snippets and/or pull requests. +Note for anyone up to contribute further pull requests: make awareness to use __english language__ in codes and messages, as usage of any other languages will render it open to faculty of whether this content will be ready to be accepted or *further changes are going to be requested* before it becomes apt to merge. + Our Discord channel is still available on: https://discord.gg/Q7wKxHX @@ -166,11 +168,11 @@ Now open NetBeans, and click "Open a project..." . Select then the "HeavenMS" fo Inside the project, you may encounter some code errors. -These errors pops-up because you have not set yet the "cores" of the project. From the project hierarchy, right-click the project and select "Resolve Project Problems". +Firstly, a **new Java7 platform** must be defined to run the server. Click "Manage Platforms...", then "Add platform", browse through "C:\Program Files\Java" for the JDK 1.7 folder. Then, name this new platform "JDK 1.7". -Locate the "cores" folder inside the root directory of this project and manually configure the missing files with the files that are there. +In case errors still show up, these errors probably occurs because you have yet to set the core JARs of the project. From the project hierarchy, right-click the project and select "Resolve Project Problems". -Also, a new Java7 platform must be defined to run the server. Click "Manage Platforms...", then "Add platform", browse through until you locate the Java7 folder in the file system, it should be at "C:\Program Files\Java". Then, name this new platform "JDK 1.7". +Locate the folder "cores" inside the root directory of this project and manually configure the missing files on NetBeans (mina-core, slf4j-api, ...). Finally, select "Clean and Build project" to build the JAR file for the MapleStory server. Once done, make sure both WampServer and Hamachi are on and functional, then execute "launch.bat" on the root of the project. If no errors were raised from this action, your MapleStory server is now online. @@ -190,7 +192,7 @@ The client's set-up is quite straightforward: #### Editing localhost IP target -If you are not using "localhost" as the target IP on the server's config file, you will need to HEX-EDIT "localhost.exe" to fetch your IP. Track down all IP locations by searching for "Text String" "127.0.0.1", and applying the changes wherever it fits. +If you are not using "localhost" as the target IP on the server's config file, you will need to HEX-EDIT "localhost.exe" to fetch your IP. Track down all IP locations by searching for "Type: String" "127.0.0.1", and applying the changes wherever it fits. To hex-edit, install the Neo Hex Editor from "free-hex-editor-neo.exe" and follow their instructions. Once done, open "localhost.exe" for editing and overwrite the IP values under the 3 addresses. Save the changes and exit the editor. diff --git a/docs/issues.txt b/docs/issues.txt index 657eadb8e2..2cc23a47a8 100644 --- a/docs/issues.txt +++ b/docs/issues.txt @@ -50,7 +50,6 @@ Missing features list: ** Packet issues & advanced PQs ** - Mystic Doors (won't deploy players properly is some situations, only destination map matches). - Ariant Party Quest -- Monster Carnival 1/2 Party Quest - Nett's Pyramid Party Quest --------------------------- diff --git a/docs/leftover.txt b/docs/leftover.txt new file mode 100644 index 0000000000..27f2e8ae54 --- /dev/null +++ b/docs/leftover.txt @@ -0,0 +1,86 @@ +// Missing contents in HeavenMS (as of commit 311), compiled here thanks to --- + +Uncoded features: +Name Change +World transfer +MTS (v53) +Family system (v67) +Family and Medal Quests(?) + +Uncoded Party Quests: +Gold Richie (v77) +Olivia PQ (v77) +Ariant PQ (v??) +Nett's Pyramid PQ (v??) +Sheep vs Wolf (v??) +Abandoned PQ (v??) + +Uncoded pre-v83 events: +Independence Day Event (v25) +April Fools Dress Up (v53) +Find Master M (v72) +Gaga the Talent Show Star Event (v76, a "fishing" event) + +I'm not positive what these are but I'm guessing they're "give away" events: +Spirit Week (v76) +A November to Remember (v79) + +Uncoded Repeating pre-v83 events: +Easter +Lunar New Year +Christmas +Anniversary +Halloween (v10-v77) +Valentines Day (v17-v81) +Mardi Gras (v82) +Gold Richie (v77) +Turkey Event + +Post-v83 codable: +Neo City update (v84) +Evan release events (v84) (arguably no point without Evan) +General Mau (v84) +Five Year Reunion Event (v85) +Weather Effects Event (v85) +OSSS Quests (v89) (arguably not worth doing since it won't be complete without Visitor PQ) +Ghost Ship (v90) +Ulu City (v90) (New World Map) +Aramia's Book Drive (v90) +Ancient Artifact Hunt (v98) +Gate to the Future (v99) (New World Map) +Kenta PQ (v101) + +Post-v83 uncodable: +Evan (v84)(some of Evan can be hacked in but it still won't fully function) +Dragon Rider PQ (v85) +Monster Portraits event (or can it?) +Golden Temple (v86) (Not sure if Ravana can be backported, if so then codable) +Chaos Zakum/Horntail (v88) +Dual Blade (v88) +Potential (v88) +Ice Gorge PQ (v90) +Visitor PQ (v90) +Resistance (v94/95) +Ultimate Explorer (v96) +Lion's King Castle (v96) (due to von Leon being uncodable) +Chryse (v96) +Dual Raid: Balloon Hunt (v97) +PVP (v99/100) +Ice Knight PQ (v99) +Monster Park (v101) (Not actually sure if this one is uncodable, seems somewhat basic) +Familiars (v102) + +Non-GMS but English: +La Tomatina Event (EMS) (Giant Tomato boss) +Oktoberfest (EMS) +Shanghai (MSEA) (New World Map) +Thailand (MSEA) (New World Map) +Neo Tokyo (MSEA) (New World Map) (different from Neo City) + +Non-GMS no English: +Coke Town (J/KMS) +Ninja Castle (now in GMS, unsure how it compares to the "classic" version) +Ximending (TMS) (New World Map) +Taipei 101 (TMS) (New World Map) (Kerning Square Mall, v83, is the non TMS variant) +Night Market (TMS) (Now in GMS, unsure how it compares to the "classic" version) +Shaolin Temple (C/JMS) (Now in GMS, unsure how it compares to the "classic" version) \ No newline at end of file diff --git a/docs/mychanges_ptbr.txt b/docs/mychanges_ptbr.txt index 8d95393545..aa13d1a796 100644 --- a/docs/mychanges_ptbr.txt +++ b/docs/mychanges_ptbr.txt @@ -1713,6 +1713,18 @@ Implementado mecânica de pescaria no código-fonte. Corrigido membros de party não recebendo bonus devidamente após membros sairem do mapa/party em alguns casos. Revisado sistema de experiência em party. Ganhos de bonus agora levam em conta valores-base que membros de party ganham ao derrotar um mob para definir o ganho geral da equipe. Contabilização de ganhos remodelado, buscando por um modo de distribuição mais coerente. +10 Março 2019, +Ajustado ganho de APs ao mudar de classe, como esperado para o 2o avanço em diante. +Corrigido itemids impróprios presentes no sistema de fishing. +Corrigido itens one-of-a-kind sendo perdidos em transações entre jogadores. +Ajustado resultado de falha de itens one-of-a-kind em transações também aparecendo pro outro jogador (somente o jogador que gerou o problema tem esse popup mostrado). +Ajustado ganho de APs em Cygnus, agora não mais faltando AP's de acordo com a métrica definida no AP Reset. + +11 Março 2019, +Implementado sistema de matching na fase de criação de guilds. +Corrigido mudança de classes não tendo update de informação em party. +Implementado matching (na forma de tratado GMS-like) entre líder e jogadores sem party presentes no mapa durante a fase de criação de guilds. + 12 - 13 Março 2019, Iniciado operação de introdução da wishlist de casamento e MCPQ no fonte, a partir do pull request feito pelo Dragohe4rt. Implementado estrutura back-end para comportar e manter (em DB) o wishlist de casamento. @@ -1725,4 +1737,32 @@ Corrigido diversas diseases da CPQ não funcionando corretamente ao pegar do ch Modificado geração de mapas da CPQ, agora sempre carregando um novo mapa da WZ ao invés de sempre buscar e resetar o mapa carregado na cache. 15 Março 2019, -Adicionado SFX nos portais da CPQ. \ No newline at end of file +Adicionado SFX nos portais da CPQ. +Ajustado limites na CPQ para atuar GMS-like, além de ajustado a server flag USE_ENABLE_SOLO_EXPEDITIONS para permitir entradas solo nos mapas deste evento. +Corrigido sistema de login não avaliando corretamente o campo HOST em "configuration.ini" quando o mesmo é preenchido como "localhost" ao invés de um valor de IP loopback. + +16 - 18 Março 2019, +Revisado descrições em certos livros de upgrade de skill de Aran. +Adicionado server flag para remover disponibilidade da CPQ. Feito devido às mensagens nos scripts estarem atualmente em português. +Corrigido update de packet duplo ao inicializar uma instância de CPQ, fazendo funcionais aparecerem em dobro. +Corrigido instância de CPQ não terminando após retirada de um membro da party ou dispensa da mesma. +Corrigido instância de CPQ não levando jogadores ao mapa de batalha devidamente após implementado sistema de geração de mapas. +Corrigido verificação por instâncias em andamento de CPQ não sendo realizado corretamente. +Refatorado busca por nomes de jobs na CPQ e gerenciador de NPC scripts (estava em maiúsculo). + +20 Março 2019, +Revisado sistema de login, agora evitando conexões indiretas feitas ao servidor. Servidor local somente aceita conexões locais, servidor remoto somente aceita conexões remotas. +Revisado busca por cliente ao finalizar sessão. Se não há clientes registrados sob uma determinada sessão IP, o sistema vai tentar buscar a mesma dentro dos registros de transição (removendo assim possibilidade de perder detecção de accounts na fase de transição). + +22 Março 2019, +Ajustado PiratePQ stage 2, agora fazendo respawn de mobs na área ao invés de requisitar líder para chamar uma nova onda. +Refatorado busca por IP remoto de uma sessão, agora utilizando um registro na classe da sessão para manter o IP usado pela conexão. +Ajustado quest do Prime Minister, permitindo entrada de grupos de até 3 jogadores. Também alterado modo como o chefe é colocado em campo: algum dos jogadores precisa ter a quest a fazer para começar (na primeira fase). +Corrigido vários itemids inexistentes nos drops da MCPQ. +Corrigido comando "forcevac" guardando no inventário mas não usando (como deveria ser) os itens "usáveis ao pegar". + +26 Março 2019, +Revisado novamente login, para o caso onde accId = 0 estava sendo atribuído e então conta estava sendo rechecada, assim gerando conflito ao tentar logar. +Adicionado update de estado de login no módulo de disconnect, para também atualizar estado da conta quando a mesma não se encontra já logada ou em transição. +Corrigido NPC da CPQ2, saída abrupta, não retornando jogadores devidamente para o saguão de espera. +Corrigido bug na CPQ em tempo estendido não mostrando devidamente o efeito visual de fim de partida. \ No newline at end of file diff --git a/handbook/Use.txt b/handbook/Use.txt index 137f8b3141..6d47efaca2 100644 --- a/handbook/Use.txt +++ b/handbook/Use.txt @@ -1,4 +1,4 @@ -2000000 - Red Potion - A potion made out of red herbs.\nRecovers 50 HP. +2000000 - Red Potion - A potion made out of red herbs.\nRecovers 50 HP. 2000001 - Orange Potion - A concentrated potion made out of red herbs.\nRecovers 150 HP. 2000002 - White Potion - A highly-concentrated potion made out of red herbs.\nRecovers 300 HP. 2000003 - Blue Potion - A potion made out of blue herbs.\nRecovers 100 MP. @@ -1191,11 +1191,11 @@ 2280010 - [Skill Book] Triple Throw - You can learn #cTriple Throw# with this book.rnClass : Night LordrnCondition : #cTriple Throw# not acquired 2280011 - Ancient Ice Powder - This is a pack full of ancient ice powder. If you eat this, you will feel chilled and can learn Ice Demon. 2280012 - [Skill Book] Rush - You can learn #cRush# with this book.rnJob : 4th Advancement WarriorrnCondition : #cRush# not acquired -2280013 - [Skill Book] Final Blow - Skill Book from which you can learn about the #cFinal Blow# skill.\nJob: 4th Lv Aran\nCondition: #cFinal Blow# not available -2280014 - [Skill Book] High Defense - Skill Book from which you can learn about the #cHigh Defense# skill.\nJob: 4th Lv Aran\nCondition: #cHigh Defense# not available -2280015 - [Skill Book] Combo Tempest - Skill Book from which you can learn about the #cCombo Tempest# skill.\nJob: 4th Lv Aran\nCondition: #cCombo Tempest# not available +2280013 - [Skill Book] Final Blow - Skill Book from which you can learn about the #cFinal Blow# skill.\nJob: 4th Advancement Aran\nCondition: #cFinal Blow# not available +2280014 - [Skill Book] High Defense - Skill Book from which you can learn about the #cHigh Defense# skill.\nJob: 4th Advancement Aran\nCondition: #cHigh Defense# not available +2280015 - [Skill Book] Combo Tempest - Skill Book from which you can learn about the #cCombo Tempest# skill.\nJob: 4th Advancement Aran\nCondition: #cCombo Tempest# not available +2280016 - [Skill Book] Combo Barrier - Skill Book from which you can learn about the #cCombo Barrier# skill.\nJob: 4th Advancement Aran\nCondition: #cCombo Barrier# not available 2280017 - [Skill Book] Pig's Weakness - Skill Book from which you can learn about the #cPig's Weakness# skill.\nCondition: #cPig's Weakness# not available -2280016 - [Skill Book] Combo Barrier - Skill Book from which you can learn about the #cCombo Barrier# skill.\nJob: 4th Lv Aran\nCondition: #cCombo Barrier# not available 2280018 - [Skill Book] Stump's Weakness - Skill Book from which you can learn about the #cStump's Weakness# skill.\nCondition: #cStump's Weakness# not available 2280019 - [Skill Book] Slime's Weakness - Skill Book from which you can learn about the #cSlime's Weakness# skill.\nCondition: #cSlime's Weakness# not available 2290000 - [Mastery Book] Monster Magnet - This increases master level of the #cMonster Magnet# skill up to 20 with 70% chance of success.rnJob : 4th Advancement WarriorrnCondition : Skill level above 5 diff --git a/launchtest.bat b/launchtest.bat index a44a45e8fb..b6a02eb5a9 100644 --- a/launchtest.bat +++ b/launchtest.bat @@ -1,4 +1,4 @@ -REM 'launchtest.bat' Author: Tochi +REM // 'launchtest.bat' Author: Tochi @echo off set a=0 title HeavenMS: Offline @@ -11,7 +11,7 @@ echo Commands: echo ------------------------------------------------------------- echo start - Start HeavenMS server echo shutdown - Shut down HeavenMS server and close Launcher File -echo restart - Restart HeavenMS Launcher File +echo reset - Resets HeavenMS Launcher File echo clear - Clear this window echo ------------------------------------------------------------- echo. @@ -20,7 +20,7 @@ echo. set /p s="Enter command: " if "%s%"=="start" goto :start if "%s%"=="shutdown" goto :shutdown -if "%s%"=="restart" goto :restart +if "%s%"=="reset" goto :reset if "%s%"=="clear" goto :clear echo Wrong Command. echo. @@ -52,10 +52,10 @@ echo The Server Launcher will be close in a few seconds. ping localhost -w 100000 >nul taskkill /im cmd.exe -:restart +:reset color 4c -title HeavenMS: Restarting... -echo Please type 'start' in command box after bat file have been restarted. +title HeavenMS: Resetting... +echo Please type 'start' in command box after bat file have been resetted. ping localhost -w 100000 >nul -start launch.bat +start launchtest.bat REM // thanks Paxum for noting that 'launchtest.bat' is to be used here taskkill /im cmd.exe \ No newline at end of file diff --git a/scripts/event/MK_PrimeMinister.js b/scripts/event/MK_PrimeMinister.js index 628e3f01c8..c61f7b7a0d 100644 --- a/scripts/event/MK_PrimeMinister.js +++ b/scripts/event/MK_PrimeMinister.js @@ -1,31 +1,79 @@ -var minPlayers = 1; -var entryMap = 106021402; -var exitMap = 106021600; +importPackage(Packages.tools); +importPackage(Packages.server.life); -var minMapId = 106021601; -var maxMapId = 106021601; +var eventTime = 10 * 60 * 1000; // 10 minutes +var entryMap = 106021600; +var exitMap = 106021402; +var recruitMap = 106021402; + +var minPlayers = 1, maxPlayers = 3; +var minLevel = 30, maxLevel = 255; + +var minMapId = 106021600; +var maxMapId = 106021600; + +var mobId = 3300008; //Prime Minister function init(){} +function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event + var eligible = []; + var hasLeader = false; + + if(party.size() > 0) { + var partyList = party.toArray(); + + for(var i = 0; i < party.size(); i++) { + var ch = partyList[i]; + + if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) { + if(ch.isLeader()) hasLeader = true; + eligible.push(ch); + } + } + } + + if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = []; + return eligible; +} + function setup(difficulty, lobbyId){ var eim = em.newInstance("MK_PrimeMinister_" +lobbyId); - eim.getInstanceMap(106021601).resetFully(); - eim.getInstanceMap(106021601).allowSummonState(false); respawn(eim); + return eim; } function afterSetup(eim){} +function primeMinisterCheck(eim) { + var map = eim.getMapInstance(entryMap); + + var pIter = map.getAllPlayers().iterator(); + while (pIter.hasNext()) { + var player = pIter.next(); + if (player.getQuestStatus(2333) == 1 && player.getClient().getAbstractPlayerInteraction().getQuestProgress(2333, mobId) == 0) { + return true; + } + } + + return false; +} + function respawn(eim){ - var map = eim.getMapInstance(entryMap); - map.allowSummonState(true); - map.instanceMapRespawn(); - eim.schedule("respawn", 10000); + if (primeMinisterCheck(eim)) { + eim.startEventTimer(eventTime); + + var weddinghall = eim.getMapInstance(entryMap); + weddinghall.getPortal(1).setPortalState(false); + weddinghall.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(mobId), new java.awt.Point(292, 143)); + } else { + eim.schedule("respawn", 10000); + } } function playerEntry(eim, player){ - var weddinghall = eim.getMapInstance(106021601); + var weddinghall = eim.getMapInstance(entryMap); player.changeMap(weddinghall, weddinghall.getPortal(1)); } @@ -69,7 +117,7 @@ function playerUnregistered(eim, player){} function playerExit(eim, player){ eim.unregisterPlayer(player); - player.changeMap(entryMap, 2); + player.changeMap(exitMap, 2); } function changedMap(eim, chr, mapid) { @@ -86,9 +134,19 @@ function cancelSchedule(){} function dispose(){} -function clearPQ(eim){} +function clearPQ(eim){ + eim.stopEventTimer(); + eim.setEventCleared(); +} -function monsterKilled(mob, eim){} +function monsterKilled(mob, eim){ + if (mob.getId() == mobId) { + eim.getMapInstance(entryMap).getPortal(1).setPortalState(true); + + eim.showClearEffect(); + eim.clearPQ(); + } +} function allMonstersDead(eim){} diff --git a/scripts/event/MK_PrimeMinister2.js b/scripts/event/MK_PrimeMinister2.js index 6a31209680..7c31952e76 100644 --- a/scripts/event/MK_PrimeMinister2.js +++ b/scripts/event/MK_PrimeMinister2.js @@ -1,20 +1,44 @@ importPackage(Packages.tools); importPackage(Packages.server.life); -var minPlayers = 1; -var eventTime = 10; // 10 minutes -var entryMap = 106021402; -var exitMap = 106021600; +var eventTime = 10 * 60 * 1000; // 10 minutes +var entryMap = 106021601; +var exitMap = 106021402; +var recruitMap = 106021402; + +var minPlayers = 1, maxPlayers = 3; +var minLevel = 30, maxLevel = 255; var minMapId = 106021601; var maxMapId = 106021601; +var mobId = 3300008; //Prime Minister + function init(){} +function getEligibleParty(party) { //selects, from the given party, the team that is allowed to attempt this event + var eligible = []; + var hasLeader = false; + + if(party.size() > 0) { + var partyList = party.toArray(); + + for(var i = 0; i < party.size(); i++) { + var ch = partyList[i]; + + if(ch.getMapId() == recruitMap && ch.getLevel() >= minLevel && ch.getLevel() <= maxLevel) { + if(ch.isLeader()) hasLeader = true; + eligible.push(ch); + } + } + } + + if(!(hasLeader && eligible.length >= minPlayers && eligible.length <= maxPlayers)) eligible = []; + return eligible; +} + function setup(difficulty, lobbyId){ var eim = em.newInstance("MK_PrimeMinister2_" +lobbyId); - eim.getInstanceMap(106021601).resetFully(); - eim.getInstanceMap(106021601).allowSummonState(false); respawn(eim); return eim; @@ -22,22 +46,26 @@ function setup(difficulty, lobbyId){ function afterSetup(eim){} +function primeMinisterCheck(eim) { + var map = eim.getMapInstance(entryMap); + return !map.getAllPlayers().isEmpty(); +} + function respawn(eim){ - var map = eim.getMapInstance(entryMap); - map.allowSummonState(true); - map.instanceMapRespawn(); - eim.schedule("respawn", 10000); + if (primeMinisterCheck(eim)) { + eim.startEventTimer(eventTime); + + var weddinghall = eim.getMapInstance(entryMap); + weddinghall.getPortal(1).setPortalState(false); + weddinghall.spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(mobId), new java.awt.Point(292, 143)); + } else { + eim.schedule("respawn", 10000); + } } function playerEntry(eim, player){ - var weddinghall = eim.getMapInstance(106021601); + var weddinghall = eim.getMapInstance(entryMap); player.changeMap(weddinghall, weddinghall.getPortal(1)); - - var pm = MapleLifeFactory.getMonster(3300008); - weddinghall.spawnMonsterOnGroundBelow(pm, new Packages.java.awt.Point(472, 27)); - - player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60)); - eim.startEventTimer(eventTime * 60000); } function scheduledTimeout(eim){ @@ -80,7 +108,7 @@ function playerUnregistered(eim, player){} function playerExit(eim, player){ eim.unregisterPlayer(player); - player.changeMap(entryMap, 2); + player.changeMap(exitMap, 2); } function changedMap(eim, chr, mapid) { @@ -97,9 +125,19 @@ function cancelSchedule(){} function dispose(){} -function clearPQ(eim){} +function clearPQ(eim){ + eim.stopEventTimer(); + eim.setEventCleared(); +} -function monsterKilled(mob, eim){} +function monsterKilled(mob, eim){ + if (mob.getId() == mobId) { + eim.getMapInstance(entryMap).getPortal(1).setPortalState(true); + + eim.showClearEffect(); + eim.clearPQ(); + } +} function allMonstersDead(eim){} diff --git a/scripts/event/PiratePQ.js b/scripts/event/PiratePQ.js index 2f116e00ee..9d43d72678 100644 --- a/scripts/event/PiratePQ.js +++ b/scripts/event/PiratePQ.js @@ -24,7 +24,7 @@ */ var isPq = true; -var isGrindMode = true; // stages done after breaking all boxes on maps +var isGrindMode = false; // stages done after breaking all boxes on maps var minPlayers = 3, maxPlayers = 6; var minLevel = 55, maxLevel = 100; @@ -185,7 +185,7 @@ function setup(level, lobbyid) { eim.getInstanceMap(925100400).resetPQ(level); eim.getInstanceMap(925100500).resetPQ(level); - respawnStg4(eim); + respawnStages(eim); eim.startEventTimer(eventTime * 60000); setEventRewards(eim); @@ -195,9 +195,14 @@ function setup(level, lobbyid) { function afterSetup(eim) {} -function respawnStg4(eim) { +function respawnStages(eim) { + var stg = eim.getIntProperty("stage2"); + if (stg < 3) { // thanks Chloek3, seth1, BHB for suggesting map respawn rather than waves on stg2 + eim.getMapInstance(925100100).spawnAllMonsterIdFromMapSpawnList(9300114 + stg, eim.getIntProperty("level"), true); + } + eim.getMapInstance(925100400).instanceMapRespawn(); - eim.schedule("respawnStg4", 10 * 1000); + eim.schedule("respawnStages", 10 * 1000); } function playerEntry(eim, player) { diff --git a/scripts/npc/1300013.js b/scripts/npc/1300013.js index ed62c35219..e2c1aca7d6 100644 --- a/scripts/npc/1300013.js +++ b/scripts/npc/1300013.js @@ -44,9 +44,18 @@ function action(mode, type, selection){ } else if(selection == 1){ - var pm = cm.getEventManager("MK_PrimeMinister2"); - pm.setProperty("player", cm.getPlayer().getName()); - pm.startInstance(cm.getPlayer()); + var em = cm.getEventManager("MK_PrimeMinister2"); + + var party = cm.getPlayer().getParty(); + if (party != null) { + if (!em.startInstance(party, cm.getMap())) { + cm.sendOk("Another party is already challenging the boss in this channel."); + } + } else { + if (!em.startInstance(cm.getPlayer())) { + cm.sendOk("Another party is already challenging the boss in this channel."); + } + } cm.dispose(); return; diff --git a/scripts/npc/2042000.js b/scripts/npc/2042000.js index bc837166a2..e6bf0728c6 100644 --- a/scripts/npc/2042000.js +++ b/scripts/npc/2042000.js @@ -1,3 +1,11 @@ +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Ronan (HeavenMS) + 3.0 - Third Version by Jayd - translated CPQ contents to English & added Pirate items + Special thanks to 頼晏 (ryantpayton) for also stepping in to translate CPQ scripts. +--------------------------------------------------------------------------------------------------- +**/ var status = 0; var rnk = -1; @@ -8,9 +16,9 @@ var n4 = 10; //40 var n5 = 20; //50 var cpqMap = 980000000; -var cpqMinLvl = 0; -var cpqMaxLvl = 255; -var cpqMinAmt = 0; +var cpqMinLvl = 30; +var cpqMaxLvl = 50; +var cpqMinAmt = 2; var cpqMaxAmt = 6; // Ronan's custom ore refiner NPC @@ -21,6 +29,19 @@ var feeMultiplier = 7.0; function start() { status = -1; + + if (!Packages.constants.ServerConstants.USE_CPQ) { + if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { + status = 0; + action(1, 0, 4); + } else { + cm.sendOk("The Monster Carnival is currently unavailable."); + cm.dispose(); + } + + return; + } + action(1, 0, 0); } @@ -39,7 +60,7 @@ function action(mode, type, selection) { if (cm.getPlayer().getMapId() == 980000010) { if (status == 0) { - cm.sendNext("Eu espero que voc� tenha divertido na Folia dos Monstros!"); + cm.sendNext("I hope you had fun at the Monster Carnival!"); } else if (status > 0) { cm.warp(980000000, 0); cm.dispose(); @@ -50,20 +71,20 @@ function action(mode, type, selection) { var shiu = ""; if (cm.getPlayer().getFestivalPoints() >= 300) { shiu += "#rA#k"; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, apesar da sua excelente performance. A vit�ria pode ser sua da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle despite your excellent performance. Victory can be yours next time! \r\n\r\n#bYour result: " + shiu); rnk = 10; } else if (cm.getPlayer().getFestivalPoints() >= 100) { shiu += "#rB#k"; rnk = 20; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, mesmo com sua �tima performance. S� mais um pouquinho, e a vit�ria poderia ter sido sua.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle, even with your ultimate performance. Just a little bit, and the victory could have been yours! \r\n\r\n#bYour result: " + shiu); } else if (cm.getPlayer().getFestivalPoints() >= 50) { shiu += "#rC#k"; rnk = 30; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha. A vit�ria est� para aqueles que se esfor�am. Vejo seus esfor�os, ent�o a vit�ria n�o est� t�o longe do seu alcance. Continue assim!\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle. Victory is for those who strive. I see your efforts, so victory is not far from your reach. Keep it up!\r\n\r\n#bYour result: " + shiu); } else { shiu += "#rD#k"; rnk = 40; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, e sua performance claramente reflete nisso. Espero mais de voc� da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either equalized or lost the battle, and your performance clearly reflects on it. I expect more from you next time. \r\n\r\n#bYour result: " + shiu); } } else { cm.warp(980000000, 0); @@ -104,19 +125,19 @@ function action(mode, type, selection) { if (cm.getPlayer().getFestivalPoints() >= 300) { shi += "#rA#k"; rnk = 1; - cm.sendOk("Parab�ns pela sua vit�ria!!! Que �tima performance! O grupo advers�rio n�o p�de fazer nada! Espero o mesmo bom trabalho da pr�xima vez!\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory!!! What a performance! The opposite group could not do anything! I hope the same good work next time! \r\n\r\n#bYour result: " + shi); } else if (cm.getPlayer().getFestivalPoints() >= 100) { shi += "#rB#k"; rnk = 2; - cm.sendOk("Parab�ns pela sua vit�ria! Isso foi impressionante! Voc� fez um bom trabalho contra o grupo advers�rio! S� mais um pouco, e voc� definitivamente vai conseguir um A na pr�xima vez. \r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory! That was awesome! You did a good job against the opposing group! Just a little longer, and you'll definitely get an A next time! \r\n\r\n#bYour result: " + shi); } else if (cm.getPlayer().getFestivalPoints() >= 50) { shi += "#rC#k"; rnk = 3; - cm.sendOk("Parab�ns pela sua vit�ria. Voc� fez algumas coisas c� e l�, mas essa n�o pode ser considerada uma boa vit�ria. Espero mais de ti da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory. You did some things here and there, but that can not be considered a good victory. I expect more from you next time. \r\n\r\n#bYour result: " + shi); } else { shi += "#rD#k"; rnk = 4; - cm.sendOk("Parab�ns pela sua vit�ria, entretanto sua performance n�o refletiu muito bem isso. Seja mais ativo na sua pr�xima participa��o da Folia de Monstros!\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory, though your performance did not quite reflect that. Be more active in your next participation in the Monster Carnival! \r\n\r\n#bYour result: " + shi); } } else { cm.warp(980000000, 0); @@ -154,10 +175,10 @@ function action(mode, type, selection) { if (status == 0) { if (cm.getParty() == null) { status = 10; - cm.sendOk("#eÉ necessário criar um grupo antes de começar o Festival de Monstros!#k"); + cm.sendOk("You need to create a party first before you can join the battle!"); } else if (!cm.isLeader()) { status = 10; - cm.sendOk("Se você quer começar o Festival, avise o #blíder do grupo#k para falar comigo."); + cm.sendOk("If you want to start the battle, let the #bParty Leader#k talk to me."); } else { var party = cm.getParty().getMembers(); var inMap = cm.partyMembersInMap(); @@ -175,15 +196,18 @@ function action(mode, type, selection) { if (party >= 1) { status = 10; - cm.sendOk("Você não tem número suficiente de pessoas em seu grupo. Você precisa de um grupo com #b" + cpqMinAmt + "#k - #r" + cpqMaxAmt + "#k membros e eles devem estar no mapa com você."); + cm.sendOk("You do not have enough people in your party. You need a party with #b" + cpqMinAmt + "#k - #r" + cpqMaxAmt + "#k members and they should be on the map with you."); } else if (lvlOk != inMap) { status = 10; - cm.sendOk("Certifique se todos em seu grupo estão dentre os níveis corretos (" + cpqMinLvl + "~" + cpqMaxLvl + ")!"); + cm.sendOk("Make sure everyone in your party is among the correct levels (" + cpqMinLvl + "~" + cpqMaxLvl + ")!"); } else if (isOutMap > 0) { status = 10; - cm.sendOk("Existe alguém do grupo que não esta no mapa!"); + cm.sendOk("There are some of the party members that is not on the map!"); } else { - cm.sendCPQMapLists(); + if (!cm.sendCPQMapLists()) { + cm.sendOk("All Monster Carnival fields are currently in use! Try again later."); + cm.dispose(); + } } } } else if (status == 1) { @@ -192,15 +216,15 @@ function action(mode, type, selection) { cm.challengeParty(selection); cm.dispose(); } else { - cm.sendOk("A sala esta cheia."); + cm.sendOk("The room is currently full."); cm.dispose(); } } else { var party = cm.getParty().getMembers(); - if ((selection >= 0 && selection <= 3) && party.size() < 1) { - cm.sendOk("Você precisa de no mínimo 2 player para entrar na competição."); - } else if ((selection >= 4 && selection <= 5) && party.size() < 1) { - cm.sendOk("Você precisa de no mínimo 3 player para entrar na competição."); + if ((selection >= 0 && selection <= 3) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) { + cm.sendOk("You need at least 2 players to participate in the battle!"); + } else if ((selection >= 4 && selection <= 5) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) { + cm.sendOk("You need at least 3 players to participate in the battle!"); } else { cm.cpqLobby(selection); } @@ -211,7 +235,7 @@ function action(mode, type, selection) { } } else { if (status == 0) { - var talk = "O que gostaria de fazer? Se voc� nunca participou da Folia de Monstros, voc� precisar� saber de algumas coisas antes de participar.\r\n#b#L0# Ir para o campo da Folia de Monstros 1.#l\r\n#L3# Ir para o campo da Folia de Monstros 2.#l\r\n#L1# Aprender sobre a Folia de Monstros.#l\r\n#L2# Trocar #t4001129#.#l"; + var talk = "What would you like to do? If you have never participate in the Monster Carnival, you will need to know a few things before participating! \r\n#b#L0# Go to the Monster Carnival 1.#l \r\n#L3# Go to the Monster Carnival 2.#l \r\n#L1# Learn about the Monster Carnival.#l\r\n#L2# Trade #t4001129#.#l"; if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { talk += "\r\n#L4# ... Can I just refine my ores?#l"; } @@ -224,19 +248,19 @@ function action(mode, type, selection) { cm.dispose(); return; } else if (cm.getLevel() < 30) { - cm.sendOk("Voc� precisa ser no m�nimo n�vel 30 para participar da Folia de Monstros. Fale comigo quando for forte o bastante."); + cm.sendOk("You must be at least level 30 to participate in the Monster Carnival. Talk to me when you're strong enough."); cm.dispose(); return; } else { - cm.sendOk("Sinto muito, mas apenas os jogadores de n�vel 30~50 podem participar da Folia de Monstros."); + cm.sendOk("I'm sorry, but only players of level 30 ~ 50 can participate in the Monster Carnival."); cm.dispose(); return; } } else if (selection == 1) { status = 60; - cm.sendSimple("O que gostaria de fazer?\r\n#b#L0# O que � a Folia de Monstros?#l\r\n#L1# Vis�o geral sobre a Folia de Monstros#l\r\n#L2# Informa��es detalhadas sobre a Folia de Monstros#l\r\n#L3# Nada, de verdade. Mudei de ideia.#l"); + cm.sendSimple("What would you like to do?\r\n#b#L0# What is Monster Carnival?#l\r\n#L1# Overview of the Monster Carnival.#l\r\n#L2# Detailed information about the Monster Carnival.#l\r\n#L3# Nothing really, I've changed my mind.#l"); } else if (selection == 2) { - cm.sendSimple("Lembre-se se voc� possui #t4001129#, voc� pode troc�-las por itens. Tenha certeza que voc� possui #t4001129# suficientes para o item que voc� deseja. Selecione o item que voc� gostaria de troc�-las! \r\n#b#L0# #t1122007#(" + n1 + " moedas)#l\r\n#L1# #t2041211#(" + n2 + " moedas)#l\r\n#L2# Armas para Guerreiros#l\r\n#L3# Armas para Bruxos#l\r\n#L4# Armas para Arqueiros#l\r\n#L5# Armas para Gatunos#l"); + cm.sendSimple("Remember, if you have #t4001129#, you can exchange for items. Select the item you would like to change them! \r\n#b#L0# #t1122007# (" + n1 + " coins)#l\r\n#L1# #t2041211# (" + n2 + " coins)#l\r\n#L2# Weapons for Warriors#l\r\n#L3# Weapons for Magician#l\r\n#L4# Weapons for Archers#l\r\n#L5# Weapons for Thief#l\r\n#L6# Weapons for Pirate#l"); } else if (selection == 3) { cm.getChar().saveLocation("MONSTER_CARNIVAL"); cm.warp(980030000, 0); @@ -269,7 +293,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -n1); cm.dispose(); } else { - cm.sendOk("Verifique e veja se est�o faltando #b#t4001129##k ou se seu invent�rio de Equipamentos est� cheio."); + cm.sendOk("Check and see if you are missing #b#t4001129##k or if your EQUIP inventory is full."); cm.dispose(); } } else if (select == 1) { @@ -278,25 +302,28 @@ function action(mode, type, selection) { cm.gainItem(4001129, -n2); cm.dispose(); } else { - cm.sendOk("Verifique e veja se est�o faltando #b#t4001129##k ou se seu invent�rio de Uso est� cheio."); + cm.sendOk("Check and see if you are missing #b#t4001129##k or if your USE inventory is full."); cm.dispose(); } } else if (select == 2) {//S2 Warrior 26 S3 Magician 6 S4 Bowman 6 S5 Thief 8 status = 10; - cm.sendSimple("Por favor tenha certeza que voc� possui #t4001129# para a arma que voc� deseja. Selecione a arma que voc� gostaria de trocar #t4001129# por. As op��es que tenho s�o realmente boas, e eu n�o sou eu que falo � o povo que diz! \r\n#b#L0# #z1302004#(" + n3 + " moedas)#l\r\n#L1# #z1402006#(" + n3 + " moedas)#l\r\n#L2# #z1302009#(" + n4 + " moedas)#l\r\n#L3# #z1402007#(" + n4 + " moedas)#l\r\n#L4# #z1302010#(" + n5 + " moedas)#l\r\n#L5# #z1402003#(" + n5 + " moedas)#l\r\n#L6# #z1312006#(" + n3 + " moedas)#l\r\n#L7# #z1412004#(" + n3 + " moedas)#l\r\n#L8# #z1312007#(" + n4 + " moedas)#l\r\n#L9# #z1412005#(" + n4 + " moedas)#l\r\n#L10# #z1312008#(" + n5 + " moedas)#l\r\n#L11# #z1412003#(" + n5 + " moedas)#l\r\n#L12# Ir para a pr�xima p�gina(1/2)#l"); + cm.sendSimple("Please make sure you have # t4001129 # for the weapon you want. Select the weapon you would like to trade # t4001129 #. The choices I have are really good, and I'm not the one who speaks to the people who say it! \r\n#b#L0# #z1302004# (" + n3 + " coins)#l\r\n#L1# #z1402006# (" + n3 + " coins)#l\r\n#L2# #z1302009# (" + n4 + " coins)#l\r\n#L3# #z1402007# (" + n4 + " coins)#l\r\n#L4# #z1302010# (" + n5 + " coins)#l\r\n#L5# #z1402003# (" + n5 + " coins)#l\r\n#L6# #z1312006# (" + n3 + " coins)#l\r\n#L7# #z1412004# (" + n3 + " coins)#l\r\n#L8# #z1312007# (" + n4 + " coins)#l\r\n#L9# #z1412005# (" + n4 + " coins)#l\r\n#L10# #z1312008# (" + n5 + " coins)#l\r\n#L11# #z1412003# (" + n5 + " coins)#l\r\n#L12# Continue to the next page (1/2)#l"); } else if (select == 3) { status = 20; - cm.sendSimple("Selecione a arma que voc� gostaria de trocar. As armas que eu tenho aqui s�o extremamente atraentes. Veja voc� mesmo! \r\n#b#L0# #z1372001#(" + n3 + " moedas)#l\r\n#L1# #z1382018#(" + n3 + " moedas)#l\r\n#L2# #z1372012#(" + n4 + "moedas)#l\r\n#L3# #z1382019#(" + n4 + "moedas)#l\r\n#L4# #z1382001#(" + n5 + " moedas)#l\r\n#L5# #z1372007#(" + n5 + " moedas)#l"); + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely attractive. See for yourself! \r\n#b#L0# #z1372001# (" + n3 + " coins)#l\r\n#L1# #z1382018# (" + n3 + " coins)#l\r\n#L2# #z1372012# (" + n4 + " coins)#l\r\n#L3# #z1382019# (" + n4 + " coins)#l\r\n#L4# #z1382001# (" + n5 + " coins)#l\r\n#L5# #z1372007# (" + n5 + " coins)#l"); } else if (select == 4) { status = 30; - cm.sendSimple("Selecione a arma que voc� gostaria de trocar. As armas que eu tenho aqui s�o extremamente atraentes. Veja voc� mesmo! \r\n#b#L0# #z1452006#(" + n3 + " moedas)#l\r\n#L1# #z1452007#(" + n4 + " moedas)#l\r\n#L2# #z1452008#(" + n5 + " moedas)#l\r\n#L3# #z1462005#(" + n3 + " moedas)#l\r\n#L4# #z1462006#(" + n4 + " moedas)#l\r\n#L5# #z1462007#(" + n5 + " moedas)#l"); + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely attractive. See for yourself! \r\n#b#L0# #z1452006# (" + n3 + " coins)#l\r\n#L1# #z1452007# (" + n4 + " coins)#l\r\n#L2# #z1452008# (" + n5 + " coins)#l\r\n#L3# #z1462005# (" + n3 + " coins)#l\r\n#L4# #z1462006# (" + n4 + " coins)#l\r\n#L5# #z1462007# (" + n5 + " coins)#l"); } else if (select == 5) { status = 40; - cm.sendSimple("Selecione a arma que voc� gostaria de trocar por. As armas que eu tenho s�o da maior qualidade. Seleciona a mais atraente para voc�! \r\n#b#L0# #z1472013#(" + n3 + " moedas)#l\r\n#L1# #z1472017#(" + n4 + "moedas)#l\r\n#L2# #z1472021#(" + n5 + " moedas)#l\r\n#L3# #z1332014#(" + n3 + " moedas)#l\r\n#L4# #z1332031#(" + n4 + "moedas)#l\r\n#L5# #z1332011#(" + n4 + "moedas)#l\r\n#L6# #z1332016#(" + n5 + " moedas)#l\r\n#L7# #z1332003#(" + n5 + " moedas)#l"); + cm.sendSimple("Select the weapon you would like to trade for. The weapons I have are of the highest quality. Select the one most appealing to you! \r\n#b#L0# #z1472013# (" + n3 + " coins)#l\r\n#L1# #z1472017# (" + n4 + " coins)#l\r\n#L2# #z1472021# (" + n5 + " coins)#l\r\n#L3# #z1332014# (" + n3 + " coins)#l\r\n#L4# #z1332031# (" + n4 + " coins)#l\r\n#L5# #z1332011# (" + n4 + " coins)#l\r\n#L6# #z1332016# (" + n5 + " coins)#l\r\n#L7# #z1332003# (" + n5 + " coins)#l"); + } else if (select == 6) { + status = 50; //pirate rewards + cm.sendSimple("Select the weapon you would like to trade for. The weapons I have are of the highest quality. Select the one most appealing to you! \r\n#b#L0# #z1482005# (" + n3 + " coins)#l \r\n#b#L1# #z1482006# (" + n4 + " coins)#l \r\n#b#L2# #z1482007# (" + n5 + " coins)#l \r\n#b#L3# #z1492005# (" + n3 + " coins)#l \r\n#b#L4# #z1492006# (" + n4 + " coins)#l \r\n#b#L5# #z1492007# (" + n5 + " coins)#l"); } } else if (status == 11) { if (selection == 12) { - cm.sendSimple("Selecione a arma que voc� gostaria de trocar. As armas que eu tenho aqui s�o extremamente �teis. D� uma olhada! \r\n#b#L0# #z1322015#(" + n3 + " moedas)#l\r\n#L1# #z1422008#(" + n3 + " moedas)#l\r\n#L2# #z1322016#(" + n4 + "moedas)#l\r\n#L3# #z1422007#(" + n4 + "moedas)#l\r\n#L4# #z1322017#(" + n5 + " moedas)#l\r\n#L5# #z1422005#(" + n5 + " moedas)#l\r\n#L6# #z1432003#(" + n3 + " moedas)#l\r\n#L7# #z1442003#(" + n3 + " moedas)#l\r\n#L8# #z1432005#(" + n4 + "moedas)#l\r\n#L9# #z1442009#(" + n4 + "moedas)#l\r\n#L10# #z1442005#(" + n5 + " moedas)#l\r\n#L11# #z1432004#(" + n5 + " moedas)#l\r\n#L12# Voltar para a p�gina inicial(2/2)#l"); + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely useful. Take a look! \r\n#b#L0# #z1322015# (" + n3 + " coins)#l\r\n#L1# #z1422008# (" + n3 + " coins)#l\r\n#L2# #z1322016# (" + n4 + " coins)#l\r\n#L3# #z1422007# (" + n4 + " coins)#l\r\n#L4# #z1322017# (" + n5 + " coins)#l\r\n#L5# #z1422005# (" + n5 + " coins)#l\r\n#L6# #z1432003# (" + n3 + " coins)#l\r\n#L7# #z1442003# (" + n3 + " coins)#l\r\n#L8# #z1432005# (" + n4 + " coins)#l\r\n#L9# #z1442009# (" + n4 + " coins)#l\r\n#L10# #z1442005# (" + n5 + " coins)#l\r\n#L11# #z1432004# (" + n5 + " coins)#l\r\n#L12# Back to the first page (2/2)#l"); } else { var item = new Array(1302004, 1402006, 1302009, 1402007, 1302010, 1402003, 1312006, 1412004, 1312007, 1412005, 1312008, 1412003); var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5); @@ -305,14 +332,14 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Voc� ou n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } } else if (status == 12) { if (selection == 12) { status = 10; - cm.sendSimple("Por favor tenha certeza que voc� possui #t4001129# para a arma que voc� deseja. Selecione a arma que voc� gostaria de trocar #t4001129# por. As op��es que tenho s�o realmente boas, e eu n�o sou eu que falo � o povo que diz! \r\n#b#L0# #z1302004#(" + n3 + " moedas)#l\r\n#L1# #z1402006#(" + n3 + " moedas)#l\r\n#L2# #z1302009#(" + n4 + " moedas)#l\r\n#L3# #z1402007#(" + n4 + " moedas)#l\r\n#L4# #z1302010#(" + n5 + " moedas)#l\r\n#L5# #z1402003#(" + n5 + " moedas)#l\r\n#L6# #z1312006#(" + n3 + " moedas)#l\r\n#L7# #z1412004#(" + n3 + " moedas)#l\r\n#L8# #z1312007#(" + n4 + " moedas)#l\r\n#L9# #z1412005#(" + n4 + " moedas)#l\r\n#L10# #z1312008#(" + n5 + " moedas)#l\r\n#L11# #z1412003#(" + n5 + " moedas)#l\r\n#L12# Ir para a pr�xima p�gina(1/2)#l"); + cm.sendSimple("Please make sure you have #b#t4001129##k for the weapon you want. Select the weapon you would like to trade #t4001129#. The choices I have are really good, and I'm not the one who speaks to the people who say it! \r\n#b#L0# #z1302004# (" + n3 + " coins)#l\r\n#L1# #z1402006# (" + n3 + " coins)#l\r\n#L2# #z1302009# (" + n4 + " coins)#l\r\n#L3# #z1402007# (" + n4 + " coins)#l\r\n#L4# #z1302010# (" + n5 + " coins)#l\r\n#L5# #z1402003# (" + n5 + " coins)#l\r\n#L6# #z1312006# (" + n3 + " coins)#l\r\n#L7# #z1412004# (" + n3 + " coins)#l\r\n#L8# #z1312007# (" + n4 + " coins)#l\r\n#L9# #z1412005# (" + n4 + " coins)#l\r\n#L10# #z1312008# (" + n5 + " coins)#l\r\n#L11# #z1412003# (" + n5 + " coins)#l\r\n#L12# Continue to the next page(1/2)#l"); } else { var item = new Array(1322015, 1422008, 1322016, 1422007, 1322017, 1422005, 1432003, 1442003, 1432005, 1442009, 1442005, 1432004); var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5, n5); @@ -321,7 +348,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Voc� ou n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } @@ -333,7 +360,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Ou voc� n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } else if (status == 31) { @@ -344,7 +371,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Ou voc� n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } else if (status == 41) { @@ -355,54 +382,65 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Ou voc� n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } else if (status == 51) { + var item = new Array(1482005, 1482006, 1482007, 1492005, 1492006, 1492007); + var cost = new Array(n3, n4, n5, n3, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } else if (status == 61) { select = selection; if (selection == 0) { - cm.sendNext("Haha! Eu sou Spiegelmann, o l�der dessa Folia. Eu comecei a primeira #bFolia de Monstros#k aqui, aguardando por viajantes como voc� para participar dessa extravaganza!"); + cm.sendNext("Haha! I am Spiegelmann, the leader of this Monster Carnival. I got the first #bMonster Carnival#k here, waiting for travelers like you to take part in this extravaganza!"); } else if (selection == 1) { - cm.sendNext("#bFolia de Monstros#k consiste em 2 grupos entrando no campo de batalha, e ca�ando os monstros invocados pelo outro grupo. � uma #bmiss�o de combate que determina o vitorioso pela quantia de Pontos de Folia (CP) recebidos#k."); + cm.sendNext("#bMonster Carnival#k consists of 2 groups entering the battlefield, and dropping the monsters invoked by the other party. #bA combat brigade that determines the victor by the amount of Carnival Points (CP) received#k."); } else if (selection == 2) { - cm.sendNext("Quando entrar no Campo da Folia, voc� ver� a janela da Folia de Monstros aparecer. Tudo que precisa fazer � #bselecionar o que voc�e quer usar, e pressionar OK#k. Muito f�cil, n�?"); + cm.sendNext("When you enter the Carnival Field, you will see the Monster List window appear. All you need to do is #bselect what you want to use, and press OK#k. Very easy, right?"); } else { cm.dispose(); } } else if (status == 62) { if (select == 0) { - cm.sendNext("O que � a #bFolia de Monstros#k? Hahaha! Vamos dizer que � uma experi�ncia que jamais esquecer�! � uma #bbatalha contra outros viajantes assim como voc�!#k"); + cm.sendNext("What is #bMonster Carnival#k? Hahaha! Let's say it's an experience you'll never forget! It's a battle against other travelers just like you!#k"); } else if (select == 1) { - cm.sendNext("Quando entrar no Campo da Folia, sua tarefa � #breceber CP ca�ando os monstros do grupo oposto, e usar estes CP's para distrair o grupo oposto de ca�ar monstros.#k."); + cm.sendNext("When entering the Carnival Field, your task is to #breceive CP by killing the monsters from the opposite group, and using these CP's to distract the opposing group from hitting monsters#k."); } else if (select == 2) { - cm.sendNext("Assim que se acostumar com os comandos, tente usar #bas teclas TAB e F1 ~ F12#k. #bTAB alterna entre Invoca��o de Monstros/Habilidades/Protetor,#k e, #bF1~ F12 possibilita-o de acessar uma das janelas diretamente#k."); + cm.sendNext("Once you get used to the commands, try using #bTAB and F1 ~ F12#k. #bTAB toggles between Monster Invocation / Skills / Protector#k, and, #bF1 ~ F12 enables you to access one of the windows directly#k."); } } else if (status == 63) { if (select == 0) { - cm.sendNext("Eu sei que � muito perigoso para voc�s lutarem uns com os outros usando armas de verdade; e eu n�o sugeriria um ato t�o barb�rico. N�o meu amigo, o que eu ofere�o � competi��o. A emo��o da batalha e a emo��o de competir contra pessoas t�o fortes e motivadas. Eu ofere�o a premissa de que seu grupo e o grupo oposto ambos #binvoquem os monstros, e derrote os monstros invocados pelo grupo advers�rio. Essa � a ess�ncia da Folia de Monstros. Al�m disso, voc� pode usar Maple Coins ganhos durante a Folia de Monstros para obter novos itens e armas! #k"); + cm.sendNext("I know it's too dangerous for you to fight with each other using real weapons; and I would not suggest such a barbaric act. Not my friend, what I offer to the competition. The excitement of the battle and the excitement of competing against such strong and motivated people. I offer the premise that your group and the opposite group both #binvoquem the monsters, and defeat the monsters invoked by the opposing group. This is the essence of the Monster Carnival. In addition, you can use Maple Coins earned during the Monster Carnival to get new items and weapons! #k"); } else if (select == 1) { - cm.sendNext("Existem 3 maneiras de distrair o grupo advers�rio: #bInvodar um monstro, Habilidade, and Protetor#k. Vou dar-lhe um olhar mais aprofundado, se voc� quiser saber mais sobre 'Instru��es detalhadas'."); + cm.sendNext("There are 3 ways to distract the opposing group: #bSummoning a monster, Ability, and Protector#k. I will give you a more in-depth look if you want to know more about 'detailed instructions'!"); } else if (select == 2) { - cm.sendNext("#bInvocar um Monstro#k chama um monstro que ataca o grupo advers�rio, sob seu controle. Use CP para trazer um Monstro Invocado, e ele ir� aparecer na mesma �rea, atacando o grupo oposto."); + cm.sendNext("#bSummoning#k a Monster calls a monster that attacks the opposing party, under its control. Use CP to bring an Summoned Monster, and it will appear in the same area, attacking the opposing group."); } } else if (status == 64) { if (select == 0) { - cm.sendNext("Claro, n�o � t�o simples assim. Existem outras maneiras de prevenir o outro grupo de ca�ar monstros, e cabe a voc� descobrir como faz�-lo. O que acha? Interessado em uma competi��o amig�vel?"); + cm.sendNext("Of course, it's not that simple. There are other ways to prevent the other group from dropping monsters, and it's up to you to figure out how to do it. What do you think? Interested in a friendly competition?"); cm.dispose(); } else if (select == 1) { - cm.sendNext("Por favor lembre-se. Nunca � uma boa ideia guardar seus CP's. #bOs CP's que voc� usou ir�o ajudar a determinar o vencedor e o perdedor da Folia."); + cm.sendNext("Please remember. It's never a good idea to keep your CP's. #bThe CPs you used will help determine the winner and loser of Monster Carnival."); } else if (select == 2) { - cm.sendNext("#bHabilidade#k � uma op��o de usar habilidades tais como Escurid�o, Fraqueza, e outras para prevenir o grupo oposto de matar outros monstros. S�o necess�rios muitos CP's, mas vale muito a pena. O �nico problema � que eles n�o duram muito. Use essa t�tica com sabedoria!"); + cm.sendNext("#bAbility#k is an option to use abilities such as Darkness, Weakness, and others to prevent the opposing group from killing other monsters. Not many CPs are needed, but it's worth it. The only problem is they do not last very long. Use this tactic wisely!"); } } else if (status == 65) { if (select == 1) { - cm.sendNext("Oh, e n�o se preocupe em tranformar-se em um fantasma. Na Folia de Monstros, #bvoc� n�o perder� EXP ap�s a morte#k. � realmente uma exper�ncia como nenhuma outra!"); + cm.sendNext("Oh, and do not worry about turning into a ghost. In the Monster Carnival, #byou will not lose EXP after death#k. So it's really an experience like no other!"); cm.dispose(); } else if (select == 2) { - cm.sendNext("#bProtetor#k � basicamente um item invocado que aumenta dr�sticamente as habilidades dos monstros invocados pelo seu grupo. Protetor funciona enquanto n�o for demolido pelo grupo oposto, ent�o eu surigo que voc� invoque v�rios monstros primeiro, e ent�o traga o Protetor."); + cm.sendNext("#bProtetor#k basically an invoked item that drastically increases the abilities of the monsters invoked by your group. Protector works until it is demolished by the opposing group, so I'm hoping you'll summon several monsters first, and then bring the Protector."); } } else if (status == 66) { - cm.sendNext("Por �ltimo, enquanto estiver na Folia de Monstros, #bvoc� n�o pode usar items/po��es de recupera��o que voc� leva por ai contigo.#k Entretanto, os monstros deixam esses items cair de vez em quando, e #bassim que peg�-los, o item ativar� imediatamente#k. � por isso que � importante saber quando pegar estes items."); + cm.sendNext("Lastly, while in the Monster Carnival, #byou can not use items / recovery potions that you carry around with you. #kMeanwhile, the monsters let these items fall for good. when, and when you #bget them, the item will immediately activate#k. That's why it's important to know when to get these items."); cm.dispose(); } else if (status == 77) { var allDone; diff --git a/scripts/npc/2042000_old.js b/scripts/npc/2042000_old.js deleted file mode 100644 index e93563a233..0000000000 --- a/scripts/npc/2042000_old.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - This file is part of the OdinMS Maple Story Server - Copyright (C) 2008 Patrick Huy - Matthias Butz - Jan Christian Meyer - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License 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 . -*/ -var status = 0; - -function start() { - if (cm.getPlayer().getParty() != null) - cm.sendCPQMapLists(); - else { - cm.sendOk("You must be in a party!"); - cm.dispose(); - } -} - -function action(mode, type, selection) { - if (mode < 1) - cm.dispose(); - else { - status++; - if (status == 1) { - if (cm.fieldTaken(selection)) { - if (cm.fieldLobbied(selection)) { - cm.challengeParty(selection); - cm.dispose(); - } else { - cm.sendOk("The room is taken."); - cm.dispose(); - } - } else { - cm.cpqLobby(selection); - cm.dispose(); - } - } - } -} \ No newline at end of file diff --git a/scripts/npc/2042001.js b/scripts/npc/2042001.js index 1d539fa0b3..d055d281e2 100644 --- a/scripts/npc/2042001.js +++ b/scripts/npc/2042001.js @@ -1,90 +1,468 @@ -/* - This file is part of the HeavenMS MapleStory Server - Copyleft (L) 2016 - 2018 RonanLana +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Ronan (HeavenMS) + 3.0 - Third Version by Jayd - translated CPQ contents to English & added Pirate items +--------------------------------------------------------------------------------------------------- +**/ - 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. +var status = 0; +var rnk = -1; +var n1 = 50; //??? +var n2 = 40; //??? ??? +var n3 = 7; //35 +var n4 = 10; //40 +var n5 = 20; //50 - 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. +var cpqMap = 980000000; +var cpqMinLvl = 30; +var cpqMaxLvl = 50; +var cpqMinAmt = 2; +var cpqMaxAmt = 6; - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . -*/ -/* Spiegelmann - Refining NPC: - * Auto ore refiner - * - * @author RonanLana -*/ - -var status; +// Ronan's custom ore refiner NPC var refineRocks = true; // enables moon rock, star rock var refineCrystals = true; // enables common crystals var refineSpecials = true; // enables lithium, special crystals var feeMultiplier = 7.0; - + function start() { - status = -1; - action(1, 0, 0); + status = -1; + + if (!Packages.constants.ServerConstants.USE_CPQ) { + if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { + status = 0; + action(1, 0, 4); + } else { + cm.sendOk("The Monster Carnival is currently unavailable."); + cm.dispose(); + } + + return; + } + + action(1, 0, 0); } function action(mode, type, selection) { - if (mode == -1) { + if (mode == -1) { + cm.dispose(); + } else { + if (status >= 0 && mode == 0) { + cm.dispose(); + return; + } + if (mode == 1) + status++; + else + status--; + + if (cm.getPlayer().getMapId() == 980000010) { + if (status == 0) { + cm.sendNext("I hope you had fun at the Monster Carnival!"); + } else if (status > 0) { + cm.warp(980000000, 0); cm.dispose(); + } + } else if (cm.getChar().getMap().isCPQLoserMap()) { + if (status == 0) { + if (cm.getChar().getParty() != null) { + var shiu = ""; + if (cm.getPlayer().getFestivalPoints() >= 300) { + shiu += "#rA#k"; + cm.sendOk("Unfortunately, you either drew or lost the battle despite your excellent performance. Victory can be yours next time! \r\n\r\n#bYour result: " + shiu); + rnk = 10; + } else if (cm.getPlayer().getFestivalPoints() >= 100) { + shiu += "#rB#k"; + rnk = 20; + cm.sendOk("Unfortunately, you either drew or lost the battle, even with your ultimate performance. Just a little bit, and the victory could have been yours! \r\n\r\n#bYour result: " + shiu); + } else if (cm.getPlayer().getFestivalPoints() >= 50) { + shiu += "#rC#k"; + rnk = 30; + cm.sendOk("Unfortunately, you either drew or lost the battle. Victory is for those who strive. I see your efforts, so victory is not far from your reach. Keep it up!\r\n\r\n#bYour result: " + shiu); + } else { + shiu += "#rD#k"; + rnk = 40; + cm.sendOk("Unfortunately, you either equalized or lost the battle, and your performance clearly reflects on it. I expect more from you next time. \r\n\r\n#bYour result: " + shiu); + } + } else { + cm.warp(980000000, 0); + cm.dispose(); + } + } else if (status == 1) { + switch (rnk) { + case 10: + cm.warp(980000000, 0); + cm.gainExp(17500); + cm.dispose(); + break; + case 20: + cm.warp(980000000, 0); + cm.gainExp(1200); + cm.dispose(); + break; + case 30: + cm.warp(980000000, 0); + cm.gainExp(5000); + cm.dispose(); + break; + case 40: + cm.warp(980000000, 0); + cm.gainExp(2500); + cm.dispose(); + break; + default: + cm.warp(980000000, 0); + cm.dispose(); + break; + } + } + } else if (cm.getChar().getMap().isCPQWinnerMap()) { + if (status == 0) { + if (cm.getChar().getParty() != null) { + var shi = ""; + if (cm.getPlayer().getFestivalPoints() >= 300) { + shi += "#rA#k"; + rnk = 1; + cm.sendOk("Congratulations on your victory!!! What a performance! The opposite group could not do anything! I hope the same good work next time! \r\n\r\n#bYour result: " + shi); + } else if (cm.getPlayer().getFestivalPoints() >= 100) { + shi += "#rB#k"; + rnk = 2; + cm.sendOk("Congratulations on your victory! That was awesome! You did a good job against the opposing group! Just a little longer, and you'll definitely get an A next time! \r\n\r\n#bYour result: " + shi); + } else if (cm.getPlayer().getFestivalPoints() >= 50) { + shi += "#rC#k"; + rnk = 3; + cm.sendOk("Congratulations on your victory. You did some things here and there, but that can not be considered a good victory. I expect more from you next time. \r\n\r\n#bYour result: " + shi); + } else { + shi += "#rD#k"; + rnk = 4; + cm.sendOk("Congratulations on your victory, though your performance did not quite reflect that. Be more active in your next participation in the Monster Carnival! \r\n\r\n#bYour result: " + shi); + } + } else { + cm.warp(980000000, 0); + cm.dispose(); + } + } else if (status == 1) { + switch (rnk) { + case 1: + cm.warp(980000000, 0); + cm.gainExp(50000); + cm.dispose(); + break; + case 2: + cm.warp(980000000, 0); + cm.gainExp(25500); + cm.dispose(); + break; + case 3: + cm.warp(980000000, 0); + cm.gainExp(21000); + cm.dispose(); + break; + case 4: + cm.warp(980000000, 0); + cm.gainExp(19505); + cm.dispose(); + break; + default: + cm.warp(980000000, 0); + cm.dispose(); + break; + } + } + } else if (cm.getMapId() == cpqMap) { // only CPQ1 + if (status == 0) { + if (cm.getParty() == null) { + status = 10; + cm.sendOk("You need to create a party first before you can join the battle!"); + } else if (!cm.isLeader()) { + status = 10; + cm.sendOk("If you want to start the battle, let the #bParty Leader#k talk to me."); + } else { + var party = cm.getParty().getMembers(); + var inMap = cm.partyMembersInMap(); + var lvlOk = 0; + var isOutMap = 0; + for (var i = 0; i < party.size(); i++) { + if (party.get(i).getLevel() >= cpqMinLvl && party.get(i).getLevel() <= cpqMaxLvl) { + lvlOk++; + + if (party.get(i).getPlayer().getMapId() != cpqMap) { + isOutMap++; + } + } + } + + if (party >= 1) { + status = 10; + cm.sendOk("You do not have enough people in your party. You need a party with #b" + cpqMinAmt + "#k - #r" + cpqMaxAmt + "#k members and they should be on the map with you."); + } else if (lvlOk != inMap) { + status = 10; + cm.sendOk("Make sure everyone in your party is among the correct levels (" + cpqMinLvl + "~" + cpqMaxLvl + ")!"); + } else if (isOutMap > 0) { + status = 10; + cm.sendOk("There are some of the party members that is not on the map!"); + } else { + if (!cm.sendCPQMapLists()) { + cm.sendOk("All Monster Carnival fields are currently in use! Try again later."); + cm.dispose(); + } + } + } + } else if (status == 1) { + if (cm.fieldTaken(selection)) { + if (cm.fieldLobbied(selection)) { + cm.challengeParty(selection); + cm.dispose(); + } else { + cm.sendOk("The room is currently full."); + cm.dispose(); + } + } else { + var party = cm.getParty().getMembers(); + if ((selection >= 0 && selection <= 3) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) { + cm.sendOk("You need at least 2 players to participate in the battle!"); + } else if ((selection >= 4 && selection <= 5) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) { + cm.sendOk("You need at least 3 players to participate in the battle!"); + } else { + cm.cpqLobby(selection); + } + cm.dispose(); + } + } else if (status == 11) { + cm.dispose(); + } } else { - if (mode == 0 && type > 0) { + if (status == 0) { + var talk = "What would you like to do? If you have never participate in the Monster Carnival, you will need to know a few things before participating! \r\n#b#L0# Go to the Monster Carnival 1.#l \r\n#L3# Go to the Monster Carnival 2.#l \r\n#L1# Learn about the Monster Carnival.#l\r\n#L2# Trade #t4001129#.#l"; + if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { + talk += "\r\n#L4# ... Can I just refine my ores?#l"; + } + cm.sendSimple(talk); + } else if (status == 1) { + if (selection == 0) { + if ((cm.getLevel() > 29 && cm.getLevel() < 51) || cm.getPlayer().isGM()) { + cm.getChar().saveLocation("MONSTER_CARNIVAL"); + cm.warp(980000000, 0); cm.dispose(); return; - } - if (mode == 1) - status++; - else - status--; - - if(status == 0) { - var selStr = "The Monster Carnival is currently unavailable, but instead I offer a steadfast #bore refining#k service for you, taxing #r" + ((feeMultiplier * 100) | 0) + "%#k over the usual fee to synthetize them. What will you do?#b"; - - var options = new Array("Refine mineral ores","Refine jewel ores"); - if(refineCrystals) { - options.push("Refine crystal ores"); - } - if(refineRocks) { - options.push("Refine plates/jewels"); - } - - for (var i = 0; i < options.length; i++){ - selStr += "\r\n#L" + i + "# " + options[i] + "#l"; - } - - cm.sendSimple(selStr); - } else if(status == 1) { - var allDone; - - if (selection == 0) { - allDone = refineItems(0); // minerals - } else if (selection == 1) { - allDone = refineItems(1); // jewels - } else if (selection == 2 && refineCrystals) { - allDone = refineItems(2); // crystals - } else if (selection == 2 && !refineCrystals || selection == 3) { - allDone = refineRockItems(); // moon/star rock - } - - if(allDone) { - cm.sendOk("Done. Thanks for showing up~."); - } else { - cm.sendOk("Done. Be aware some of the items could not be synthetized because either you have a lack of space on your ETC inventory or there's not enough mesos to cover the fee."); - } + } else if (cm.getLevel() < 30) { + cm.sendOk("You must be at least level 30 to participate in the Monster Carnival. Talk to me when you're strong enough."); cm.dispose(); + return; + } else { + cm.sendOk("I'm sorry, but only players of level 30 ~ 50 can participate in the Monster Carnival."); + cm.dispose(); + return; + } + } else if (selection == 1) { + status = 60; + cm.sendSimple("What would you like to do?\r\n#b#L0# What is Monster Carnival?#l\r\n#L1# Overview of the Monster Carnival.#l\r\n#L2# Detailed information about the Monster Carnival.#l\r\n#L3# Nothing really, I've changed my mind.#l"); + } else if (selection == 2) { + cm.sendSimple("Remember, if you have #t4001129#, you can exchange for items. Select the item you would like to change them! \r\n#b#L0# #t1122007# (" + n1 + " coins)#l\r\n#L1# #t2041211# (" + n2 + " coins)#l\r\n#L2# Weapons for Warriors#l\r\n#L3# Weapons for Magician#l\r\n#L4# Weapons for Archers#l\r\n#L5# Weapons for Thief#l\r\n#L6# Weapons for Pirate#l"); + } else if (selection == 3) { + cm.getChar().saveLocation("MONSTER_CARNIVAL"); + cm.warp(980030000, 0); + cm.dispose(); + return; + } else if (selection == 4) { + var selStr = "Very well, instead I offer a steadfast #bore refining#k service for you, taxing #r" + ((feeMultiplier * 100) | 0) + "%#k over the usual fee to synthetize them. What will you do?#b"; + + var options = new Array("Refine mineral ores","Refine jewel ores"); + if(refineCrystals) { + options.push("Refine crystal ores"); + } + if(refineRocks) { + options.push("Refine plates/jewels"); + } + + for (var i = 0; i < options.length; i++){ + selStr += "\r\n#L" + i + "# " + options[i] + "#l"; + } + + cm.sendSimple(selStr); + + status = 76; } + } else if (status == 2) { + select = selection; + if (select == 0) { + if (cm.haveItem(4001129, n1) && cm.canHold(4001129)) { + cm.gainItem(1122007, 1); + cm.gainItem(4001129, -n1); + cm.dispose(); + } else { + cm.sendOk("Check and see if you are missing #b#t4001129##k or if your EQUIP inventory is full."); + cm.dispose(); + } + } else if (select == 1) { + if (cm.haveItem(4001129, n2) && cm.canHold(2041211)) { + cm.gainItem(2041211, 1); + cm.gainItem(4001129, -n2); + cm.dispose(); + } else { + cm.sendOk("Check and see if you are missing #b#t4001129##k or if your USE inventory is full."); + cm.dispose(); + } + } else if (select == 2) {//S2 Warrior 26 S3 Magician 6 S4 Bowman 6 S5 Thief 8 + status = 10; + cm.sendSimple("Please make sure you have # t4001129 # for the weapon you want. Select the weapon you would like to trade # t4001129 #. The choices I have are really good, and I'm not the one who speaks to the people who say it! \r\n#b#L0# #z1302004# (" + n3 + " coins)#l\r\n#L1# #z1402006# (" + n3 + " coins)#l\r\n#L2# #z1302009# (" + n4 + " coins)#l\r\n#L3# #z1402007# (" + n4 + " coins)#l\r\n#L4# #z1302010# (" + n5 + " coins)#l\r\n#L5# #z1402003# (" + n5 + " coins)#l\r\n#L6# #z1312006# (" + n3 + " coins)#l\r\n#L7# #z1412004# (" + n3 + " coins)#l\r\n#L8# #z1312007# (" + n4 + " coins)#l\r\n#L9# #z1412005# (" + n4 + " coins)#l\r\n#L10# #z1312008# (" + n5 + " coins)#l\r\n#L11# #z1412003# (" + n5 + " coins)#l\r\n#L12# Continue to the next page (1/2)#l"); + } else if (select == 3) { + status = 20; + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely attractive. See for yourself! \r\n#b#L0# #z1372001# (" + n3 + " coins)#l\r\n#L1# #z1382018# (" + n3 + " coins)#l\r\n#L2# #z1372012# (" + n4 + " coins)#l\r\n#L3# #z1382019# (" + n4 + " coins)#l\r\n#L4# #z1382001# (" + n5 + " coins)#l\r\n#L5# #z1372007# (" + n5 + " coins)#l"); + } else if (select == 4) { + status = 30; + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely attractive. See for yourself! \r\n#b#L0# #z1452006# (" + n3 + " coins)#l\r\n#L1# #z1452007# (" + n4 + " coins)#l\r\n#L2# #z1452008# (" + n5 + " coins)#l\r\n#L3# #z1462005# (" + n3 + " coins)#l\r\n#L4# #z1462006# (" + n4 + " coins)#l\r\n#L5# #z1462007# (" + n5 + " coins)#l"); + } else if (select == 5) { + status = 40; + cm.sendSimple("Select the weapon you would like to trade for. The weapons I have are of the highest quality. Select the one most appealing to you! \r\n#b#L0# #z1472013# (" + n3 + " coins)#l\r\n#L1# #z1472017# (" + n4 + " coins)#l\r\n#L2# #z1472021# (" + n5 + " coins)#l\r\n#L3# #z1332014# (" + n3 + " coins)#l\r\n#L4# #z1332031# (" + n4 + " coins)#l\r\n#L5# #z1332011# (" + n4 + " coins)#l\r\n#L6# #z1332016# (" + n5 + " coins)#l\r\n#L7# #z1332003# (" + n5 + " coins)#l"); + } else if (select == 6) { + status = 50; //pirate rewards + cm.sendSimple("Select the weapon you would like to trade for. The weapons I have are of the highest quality. Select the one most appealing to you! \r\n#b#L0# #z1482005# (" + n3 + " coins)#l \r\n#b#L1# #z1482006# (" + n4 + " coins)#l \r\n#b#L2# #z1482007# (" + n5 + " coins)#l \r\n#b#L3# #z1492005# (" + n3 + " coins)#l \r\n#b#L4# #z1492006# (" + n4 + " coins)#l \r\n#b#L5# #z1492007# (" + n5 + " coins)#l"); + } + } else if (status == 11) { + if (selection == 12) { + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely useful. Take a look! \r\n#b#L0# #z1322015# (" + n3 + " coins)#l\r\n#L1# #z1422008# (" + n3 + " coins)#l\r\n#L2# #z1322016# (" + n4 + " coins)#l\r\n#L3# #z1422007# (" + n4 + " coins)#l\r\n#L4# #z1322017# (" + n5 + " coins)#l\r\n#L5# #z1422005# (" + n5 + " coins)#l\r\n#L6# #z1432003# (" + n3 + " coins)#l\r\n#L7# #z1442003# (" + n3 + " coins)#l\r\n#L8# #z1432005# (" + n4 + " coins)#l\r\n#L9# #z1442009# (" + n4 + " coins)#l\r\n#L10# #z1442005# (" + n5 + " coins)#l\r\n#L11# #z1432004# (" + n5 + " coins)#l\r\n#L12# Back to the first page (2/2)#l"); + } else { + var item = new Array(1302004, 1402006, 1302009, 1402007, 1302010, 1402003, 1312006, 1412004, 1312007, 1412005, 1312008, 1412003); + var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } + } else if (status == 12) { + if (selection == 12) { + status = 10; + cm.sendSimple("Please make sure you have #b#t4001129##k for the weapon you want. Select the weapon you would like to trade #t4001129#. The choices I have are really good, and I'm not the one who speaks to the people who say it! \r\n#b#L0# #z1302004# (" + n3 + " coins)#l\r\n#L1# #z1402006# (" + n3 + " coins)#l\r\n#L2# #z1302009# (" + n4 + " coins)#l\r\n#L3# #z1402007# (" + n4 + " coins)#l\r\n#L4# #z1302010# (" + n5 + " coins)#l\r\n#L5# #z1402003# (" + n5 + " coins)#l\r\n#L6# #z1312006# (" + n3 + " coins)#l\r\n#L7# #z1412004# (" + n3 + " coins)#l\r\n#L8# #z1312007# (" + n4 + " coins)#l\r\n#L9# #z1412005# (" + n4 + " coins)#l\r\n#L10# #z1312008# (" + n5 + " coins)#l\r\n#L11# #z1412003# (" + n5 + " coins)#l\r\n#L12# Continue to the next page(1/2)#l"); + } else { + var item = new Array(1322015, 1422008, 1322016, 1422007, 1322017, 1422005, 1432003, 1442003, 1432005, 1442009, 1442005, 1432004); + var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } + } else if (status == 21) { + var item = new Array(1372001, 1382018, 1372012, 1382019, 1382001, 1372007); + var cost = new Array(n3, n3, n4, n4, n5, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } else if (status == 31) { + var item = new Array(1452006, 1452007, 1452008, 1462005, 1462006, 1462007); + var cost = new Array(n3, n4, n5, n3, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } else if (status == 41) { + var item = new Array(1472013, 1472017, 1472021, 1332014, 1332031, 1332011, 1332016, 1332003); + var cost = new Array(n3, n4, n5, n3, n4, n4, n5, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } else if (status == 51) { + var item = new Array(1482005, 1482006, 1482007, 1492005, 1492006, 1492007); + var cost = new Array(n3, n4, n5, n3, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } else if (status == 61) { + select = selection; + if (selection == 0) { + cm.sendNext("Haha! I am Spiegelmann, the leader of this Monster Carnival. I got the first #bMonster Carnival#k here, waiting for travelers like you to take part in this extravaganza!"); + } else if (selection == 1) { + cm.sendNext("#bMonster Carnival#k consists of 2 groups entering the battlefield, and dropping the monsters invoked by the other party. #bA combat brigade that determines the victor by the amount of Carnival Points (CP) received#k."); + } else if (selection == 2) { + cm.sendNext("When you enter the Carnival Field, you will see the Monster List window appear. All you need to do is #bselect what you want to use, and press OK#k. Very easy, right?"); + } else { + cm.dispose(); + } + } else if (status == 62) { + if (select == 0) { + cm.sendNext("What is #bMonster Carnival#k? Hahaha! Let's say it's an experience you'll never forget! It's a battle against other travelers just like you!#k"); + } else if (select == 1) { + cm.sendNext("When entering the Carnival Field, your task is to #breceive CP by killing the monsters from the opposite group, and using these CP's to distract the opposing group from hitting monsters#k."); + } else if (select == 2) { + cm.sendNext("Once you get used to the commands, try using #bTAB and F1 ~ F12#k. #bTAB toggles between Monster Invocation / Skills / Protector#k, and, #bF1 ~ F12 enables you to access one of the windows directly#k."); + } + } else if (status == 63) { + if (select == 0) { + cm.sendNext("I know it's too dangerous for you to fight with each other using real weapons; and I would not suggest such a barbaric act. Not my friend, what I offer to the competition. The excitement of the battle and the excitement of competing against such strong and motivated people. I offer the premise that your group and the opposite group both #binvoquem the monsters, and defeat the monsters invoked by the opposing group. This is the essence of the Monster Carnival. In addition, you can use Maple Coins earned during the Monster Carnival to get new items and weapons! #k"); + } else if (select == 1) { + cm.sendNext("There are 3 ways to distract the opposing group: #bSummoning a monster, Ability, and Protector#k. I will give you a more in-depth look if you want to know more about 'detailed instructions'!"); + } else if (select == 2) { + cm.sendNext("#bSummoning#k a Monster calls a monster that attacks the opposing party, under its control. Use CP to bring an Summoned Monster, and it will appear in the same area, attacking the opposing group."); + } + } else if (status == 64) { + if (select == 0) { + cm.sendNext("Of course, it's not that simple. There are other ways to prevent the other group from dropping monsters, and it's up to you to figure out how to do it. What do you think? Interested in a friendly competition?"); + cm.dispose(); + } else if (select == 1) { + cm.sendNext("Please remember. It's never a good idea to keep your CP's. #bThe CPs you used will help determine the winner and loser of Monster Carnival."); + } else if (select == 2) { + cm.sendNext("#bAbility#k is an option to use abilities such as Darkness, Weakness, and others to prevent the opposing group from killing other monsters. Not many CPs are needed, but it's worth it. The only problem is they do not last very long. Use this tactic wisely!"); + } + } else if (status == 65) { + if (select == 1) { + cm.sendNext("Oh, and do not worry about turning into a ghost. In the Monster Carnival, #byou will not lose EXP after death#k. So it's really an experience like no other!"); + cm.dispose(); + } else if (select == 2) { + cm.sendNext("#bProtetor#k basically an invoked item that drastically increases the abilities of the monsters invoked by your group. Protector works until it is demolished by the opposing group, so I'm hoping you'll summon several monsters first, and then bring the Protector."); + } + } else if (status == 66) { + cm.sendNext("Lastly, while in the Monster Carnival, #byou can not use items / recovery potions that you carry around with you. #kMeanwhile, the monsters let these items fall for good. when, and when you #bget them, the item will immediately activate#k. That's why it's important to know when to get these items."); + cm.dispose(); + } else if (status == 77) { + var allDone; + + if (selection == 0) { + allDone = refineItems(0); // minerals + } else if (selection == 1) { + allDone = refineItems(1); // jewels + } else if (selection == 2 && refineCrystals) { + allDone = refineItems(2); // crystals + } else if (selection == 2 && !refineCrystals || selection == 3) { + allDone = refineRockItems(); // moon/star rock + } + + if(allDone) { + cm.sendOk("Done. Thanks for showing up~."); + } else { + cm.sendOk("Done. Be aware some of the items #rcould not be synthetized#k because either you have a lack of space on your ETC inventory or there's not enough mesos to cover the fee."); + } + cm.dispose(); + } } + } } function getRefineFee(fee) { diff --git a/scripts/npc/2042002.js b/scripts/npc/2042002.js index 914181d11d..dac501d13b 100644 --- a/scripts/npc/2042002.js +++ b/scripts/npc/2042002.js @@ -1,3 +1,10 @@ +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Ronan (HeavenMS) + 3.0 - Third Version by Jayd - translated CPQ contents to English & added Pirate items +--------------------------------------------------------------------------------------------------- +**/ var status = 0; var rnk = -1; @@ -7,6 +14,12 @@ var n3 = 7; //35 var n4 = 10; //40 var n5 = 20; //50 +var cpqMap = 980000000; +var cpqMinLvl = 30; +var cpqMaxLvl = 50; +var cpqMinAmt = 2; +var cpqMaxAmt = 6; + // Ronan's custom ore refiner NPC var refineRocks = true; // enables moon rock, star rock var refineCrystals = true; // enables common crystals @@ -15,6 +28,19 @@ var feeMultiplier = 7.0; function start() { status = -1; + + if (!Packages.constants.ServerConstants.USE_CPQ) { + if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { + status = 0; + action(1, 0, 4); + } else { + cm.sendOk("The Monster Carnival is currently unavailable."); + cm.dispose(); + } + + return; + } + action(1, 0, 0); } @@ -33,7 +59,7 @@ function action(mode, type, selection) { if (cm.getPlayer().getMapId() == 980000010) { if (status == 0) { - cm.sendNext("Eu espero que voc� tenha divertido na Folia dos Monstros!"); + cm.sendNext("I hope you had fun at the Monster Carnival!"); } else if (status > 0) { cm.warp(980000000, 0); cm.dispose(); @@ -44,20 +70,20 @@ function action(mode, type, selection) { var shiu = ""; if (cm.getPlayer().getFestivalPoints() >= 300) { shiu += "#rA#k"; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, apesar da sua excelente performance. A vit�ria pode ser sua da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle despite your excellent performance. Victory can be yours next time! \r\n\r\n#bYour result: " + shiu); rnk = 10; } else if (cm.getPlayer().getFestivalPoints() >= 100) { shiu += "#rB#k"; rnk = 20; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, mesmo com sua �tima performance. S� mais um pouquinho, e a vit�ria poderia ter sido sua.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle, even with your ultimate performance. Just a little bit, and the victory could have been yours! \r\n\r\n#bYour result: " + shiu); } else if (cm.getPlayer().getFestivalPoints() >= 50) { shiu += "#rC#k"; rnk = 30; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha. A vit�ria est� para aqueles que se esfor�am. Vejo seus esfor�os, ent�o a vit�ria n�o est� t�o longe do seu alcance. Continue assim!\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle. Victory is for those who strive. I see your efforts, so victory is not far from your reach. Keep it up!\r\n\r\n#bYour result: " + shiu); } else { shiu += "#rD#k"; rnk = 40; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, e sua performance claramente reflete nisso. Espero mais de voc� da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either equalized or lost the battle, and your performance clearly reflects on it. I expect more from you next time. \r\n\r\n#bYour result: " + shiu); } } else { cm.warp(980000000, 0); @@ -98,19 +124,19 @@ function action(mode, type, selection) { if (cm.getPlayer().getFestivalPoints() >= 300) { shi += "#rA#k"; rnk = 1; - cm.sendOk("Parab�ns pela sua vit�ria!!! Que �tima performance! O grupo advers�rio n�o p�de fazer nada! Espero o mesmo bom trabalho da pr�xima vez!\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory!!! What a performance! The opposite group could not do anything! I hope the same good work next time! \r\n\r\n#bYour result: " + shi); } else if (cm.getPlayer().getFestivalPoints() >= 100) { shi += "#rB#k"; rnk = 2; - cm.sendOk("Parab�ns pela sua vit�ria! Isso foi impressionante! Voc� fez um bom trabalho contra o grupo advers�rio! S� mais um pouco, e voc� definitivamente vai conseguir um A na pr�xima vez. \r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory! That was awesome! You did a good job against the opposing group! Just a little longer, and you'll definitely get an A next time! \r\n\r\n#bYour result: " + shi); } else if (cm.getPlayer().getFestivalPoints() >= 50) { shi += "#rC#k"; rnk = 3; - cm.sendOk("Parab�ns pela sua vit�ria. Voc� fez algumas coisas c� e l�, mas essa n�o pode ser considerada uma boa vit�ria. Espero mais de ti da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory. You did some things here and there, but that can not be considered a good victory. I expect more from you next time. \r\n\r\n#bYour result: " + shi); } else { shi += "#rD#k"; rnk = 4; - cm.sendOk("Parab�ns pela sua vit�ria, entretanto sua performance n�o refletiu muito bem isso. Seja mais ativo na sua pr�xima participa��o da Folia de Monstros!\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory, though your performance did not quite reflect that. Be more active in your next participation in the Monster Carnival! \r\n\r\n#bYour result: " + shi); } } else { cm.warp(980000000, 0); @@ -144,9 +170,71 @@ function action(mode, type, selection) { break; } } + } else if (cm.getMapId() == cpqMap) { // only CPQ1 + if (status == 0) { + if (cm.getParty() == null) { + status = 10; + cm.sendOk("You need to create a party first before you can join the battle!"); + } else if (!cm.isLeader()) { + status = 10; + cm.sendOk("If you want to start the battle, let the #bParty Leader#k talk to me."); + } else { + var party = cm.getParty().getMembers(); + var inMap = cm.partyMembersInMap(); + var lvlOk = 0; + var isOutMap = 0; + for (var i = 0; i < party.size(); i++) { + if (party.get(i).getLevel() >= cpqMinLvl && party.get(i).getLevel() <= cpqMaxLvl) { + lvlOk++; + + if (party.get(i).getPlayer().getMapId() != cpqMap) { + isOutMap++; + } + } + } + + if (party >= 1) { + status = 10; + cm.sendOk("You do not have enough people in your party. You need a party with #b" + cpqMinAmt + "#k - #r" + cpqMaxAmt + "#k members and they should be on the map with you."); + } else if (lvlOk != inMap) { + status = 10; + cm.sendOk("Make sure everyone in your party is among the correct levels (" + cpqMinLvl + "~" + cpqMaxLvl + ")!"); + } else if (isOutMap > 0) { + status = 10; + cm.sendOk("There are some of the party members that is not on the map!"); + } else { + if (!cm.sendCPQMapLists()) { + cm.sendOk("All Monster Carnival fields are currently in use! Try again later."); + cm.dispose(); + } + } + } + } else if (status == 1) { + if (cm.fieldTaken(selection)) { + if (cm.fieldLobbied(selection)) { + cm.challengeParty(selection); + cm.dispose(); + } else { + cm.sendOk("The room is currently full."); + cm.dispose(); + } + } else { + var party = cm.getParty().getMembers(); + if ((selection >= 0 && selection <= 3) && party.size() < 1) { + cm.sendOk("You need at least 2 players to participate in the battle!"); + } else if ((selection >= 4 && selection <= 5) && party.size() < 1) { + cm.sendOk("You need at least 3 players to participate in the battle!"); + } else { + cm.cpqLobby(selection); + } + cm.dispose(); + } + } else if (status == 11) { + cm.dispose(); + } } else { if (status == 0) { - var talk = "O que gostaria de fazer? Se voc� nunca participou da Folia de Monstros, voc� precisar� saber de algumas coisas antes de participar.\r\n#b#L0# Ir para o campo da Folia de Monstros 1.#l\r\n#L3# Ir para o campo da Folia de Monstros 2.#l\r\n#L1# Aprender sobre a Folia de Monstros.#l\r\n#L2# Trocar #t4001129#.#l"; + var talk = "What would you like to do? If you have never participate in the Monster Carnival, you will need to know a few things before participating! \r\n#b#L0# Go to the Monster Carnival 1.#l \r\n#L3# Go to the Monster Carnival 2.#l \r\n#L1# Learn about the Monster Carnival.#l\r\n#L2# Trade #t4001129#.#l"; if (Packages.constants.ServerConstants.USE_ENABLE_CUSTOM_NPC_SCRIPT) { talk += "\r\n#L4# ... Can I just refine my ores?#l"; } @@ -159,19 +247,19 @@ function action(mode, type, selection) { cm.dispose(); return; } else if (cm.getLevel() < 30) { - cm.sendOk("Voc� precisa ser no m�nimo n�vel 30 para participar da Folia de Monstros. Fale comigo quando for forte o bastante."); + cm.sendOk("You must be at least level 30 to participate in the Monster Carnival. Talk to me when you're strong enough."); cm.dispose(); return; } else { - cm.sendOk("Sinto muito, mas apenas os jogadores de n�vel 30~50 podem participar da Folia de Monstros."); + cm.sendOk("I'm sorry, but only players of level 30 ~ 50 can participate in the Monster Carnival."); cm.dispose(); return; } } else if (selection == 1) { status = 60; - cm.sendSimple("O que gostaria de fazer?\r\n#b#L0# O que � a Folia de Monstros?#l\r\n#L1# Vis�o geral sobre a Folia de Monstros#l\r\n#L2# Informa��es detalhadas sobre a Folia de Monstros#l\r\n#L3# Nada, de verdade. Mudei de ideia.#l"); + cm.sendSimple("What would you like to do?\r\n#b#L0# What is Monster Carnival?#l\r\n#L1# Overview of the Monster Carnival.#l\r\n#L2# Detailed information about the Monster Carnival.#l\r\n#L3# Nothing really, I've changed my mind.#l"); } else if (selection == 2) { - cm.sendSimple("Lembre-se se voc� possui #t4001129#, voc� pode troc�-las por itens. Tenha certeza que voc� possui #t4001129# suficientes para o item que voc� deseja. Selecione o item que voc� gostaria de troc�-las! \r\n#b#L0# #t1122007#(" + n1 + " moedas)#l\r\n#L1# #t2041211#(" + n2 + " moedas)#l\r\n#L2# Armas para Guerreiros#l\r\n#L3# Armas para Bruxos#l\r\n#L4# Armas para Arqueiros#l\r\n#L5# Armas para Gatunos#l"); + cm.sendSimple("Remember, if you have #t4001129#, you can exchange for items. Select the item you would like to change them! \r\n#b#L0# #t1122007# (" + n1 + " coins)#l\r\n#L1# #t2041211# (" + n2 + " coins)#l\r\n#L2# Weapons for Warriors#l\r\n#L3# Weapons for Magician#l\r\n#L4# Weapons for Archers#l\r\n#L5# Weapons for Thief#l\r\n#L6# Weapons for Pirate#l"); } else if (selection == 3) { cm.getChar().saveLocation("MONSTER_CARNIVAL"); cm.warp(980030000, 0); @@ -204,7 +292,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -n1); cm.dispose(); } else { - cm.sendOk("Verifique e veja se est�o faltando #b#t4001129##k ou se seu invent�rio de Equipamentos est� cheio."); + cm.sendOk("Check and see if you are missing #b#t4001129##k or if your EQUIP inventory is full."); cm.dispose(); } } else if (select == 1) { @@ -213,25 +301,28 @@ function action(mode, type, selection) { cm.gainItem(4001129, -n2); cm.dispose(); } else { - cm.sendOk("Verifique e veja se est�o faltando #b#t4001129##k ou se seu invent�rio de Uso est� cheio."); + cm.sendOk("Check and see if you are missing #b#t4001129##k or if your USE inventory is full."); cm.dispose(); } } else if (select == 2) {//S2 Warrior 26 S3 Magician 6 S4 Bowman 6 S5 Thief 8 status = 10; - cm.sendSimple("Por favor tenha certeza que voc� possui #t4001129# para a arma que voc� deseja. Selecione a arma que voc� gostaria de trocar #t4001129# por. As op��es que tenho s�o realmente boas, e eu n�o sou eu que falo � o povo que diz! \r\n#b#L0# #z1302004#(" + n3 + " moedas)#l\r\n#L1# #z1402006#(" + n3 + " moedas)#l\r\n#L2# #z1302009#(" + n4 + " moedas)#l\r\n#L3# #z1402007#(" + n4 + " moedas)#l\r\n#L4# #z1302010#(" + n5 + " moedas)#l\r\n#L5# #z1402003#(" + n5 + " moedas)#l\r\n#L6# #z1312006#(" + n3 + " moedas)#l\r\n#L7# #z1412004#(" + n3 + " moedas)#l\r\n#L8# #z1312007#(" + n4 + " moedas)#l\r\n#L9# #z1412005#(" + n4 + " moedas)#l\r\n#L10# #z1312008#(" + n5 + " moedas)#l\r\n#L11# #z1412003#(" + n5 + " moedas)#l\r\n#L12# Ir para a pr�xima p�gina(1/2)#l"); + cm.sendSimple("Please make sure you have #t4001129# for the weapon you want. Select the weapon you would like to trade #t4001129#. The choices I have are really good, and I'm not the one who speaks to the people who say it! \r\n#b#L0# #z1302004# (" + n3 + " coins)#l\r\n#L1# #z1402006# (" + n3 + " coins)#l\r\n#L2# #z1302009# (" + n4 + " coins)#l\r\n#L3# #z1402007# (" + n4 + " coins)#l\r\n#L4# #z1302010# (" + n5 + " coins)#l\r\n#L5# #z1402003# (" + n5 + " coins)#l\r\n#L6# #z1312006# (" + n3 + " coins)#l\r\n#L7# #z1412004# (" + n3 + " coins)#l\r\n#L8# #z1312007# (" + n4 + " coins)#l\r\n#L9# #z1412005# (" + n4 + " coins)#l\r\n#L10# #z1312008# (" + n5 + " coins)#l\r\n#L11# #z1412003# (" + n5 + " coins)#l\r\n#L12# Continue to the next page(1/2)#l"); } else if (select == 3) { status = 20; - cm.sendSimple("Selecione a arma que voc� gostaria de trocar. As armas que eu tenho aqui s�o extremamente atraentes. Veja voc� mesmo! \r\n#b#L0# #z1372001#(" + n3 + " moedas)#l\r\n#L1# #z1382018#(" + n3 + " moedas)#l\r\n#L2# #z1372012#(" + n4 + "moedas)#l\r\n#L3# #z1382019#(" + n4 + "moedas)#l\r\n#L4# #z1382001#(" + n5 + " moedas)#l\r\n#L5# #z1372007#(" + n5 + " moedas)#l"); + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely attractive. See for yourself! \r\n#b#L0# #z1372001# (" + n3 + " coins)#l\r\n#L1# #z1382018# (" + n3 + " coins)#l\r\n#L2# #z1372012# (" + n4 + " coins)#l\r\n#L3# #z1382019# (" + n4 + " coins)#l\r\n#L4# #z1382001# (" + n5 + " coins)#l\r\n#L5# #z1372007# (" + n5 + " coins)#l"); } else if (select == 4) { status = 30; - cm.sendSimple("Selecione a arma que voc� gostaria de trocar. As armas que eu tenho aqui s�o extremamente atraentes. Veja voc� mesmo! \r\n#b#L0# #z1452006#(" + n3 + " moedas)#l\r\n#L1# #z1452007#(" + n4 + " moedas)#l\r\n#L2# #z1452008#(" + n5 + " moedas)#l\r\n#L3# #z1462005#(" + n3 + " moedas)#l\r\n#L4# #z1462006#(" + n4 + " moedas)#l\r\n#L5# #z1462007#(" + n5 + " moedas)#l"); + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely attractive. See for yourself! \r\n#b#L0# #z1452006# (" + n3 + " coins)#l\r\n#L1# #z1452007# (" + n4 + " coins)#l\r\n#L2# #z1452008# (" + n5 + " coins)#l\r\n#L3# #z1462005# (" + n3 + " coins)#l\r\n#L4# #z1462006# (" + n4 + " coins)#l\r\n#L5# #z1462007# (" + n5 + " coins)#l"); } else if (select == 5) { status = 40; - cm.sendSimple("Selecione a arma que voc� gostaria de trocar por. As armas que eu tenho s�o da maior qualidade. Seleciona a mais atraente para voc�! \r\n#b#L0# #z1472013#(" + n3 + " moedas)#l\r\n#L1# #z1472017#(" + n4 + "moedas)#l\r\n#L2# #z1472021#(" + n5 + " moedas)#l\r\n#L3# #z1332014#(" + n3 + " moedas)#l\r\n#L4# #z1332031#(" + n4 + "moedas)#l\r\n#L5# #z1332011#(" + n4 + "moedas)#l\r\n#L6# #z1332016#(" + n5 + " moedas)#l\r\n#L7# #z1332003#(" + n5 + " moedas)#l"); + cm.sendSimple("Select the weapon you would like to trade for. The weapons I have are of the highest quality. Select the one most appealing to you! \r\n#b#L0# #z1472013# (" + n3 + " coins)#l\r\n#L1# #z1472017# (" + n4 + " coins)#l\r\n#L2# #z1472021# (" + n5 + " coins)#l\r\n#L3# #z1332014# (" + n3 + " coins)#l\r\n#L4# #z1332031# (" + n4 + " coins)#l\r\n#L5# #z1332011# (" + n4 + " coins)#l\r\n#L6# #z1332016# (" + n5 + " coins)#l\r\n#L7# #z1332003# (" + n5 + " coins)#l"); + } else if (select == 6) { + status = 50; //pirate rewards + cm.sendSimple("Select the weapon you would like to trade for. The weapons I have are of the highest quality. Select the one most appealing to you! \r\n#b#L0# #z1482005# (" + n3 + " coins)#l \r\n#b#L1# #z1482006# (" + n4 + " coins)#l \r\n#b#L2# #z1482007# (" + n5 + " coins)#l \r\n#b#L3# #z1492005# (" + n3 + " coins)#l \r\n#b#L4# #z1492006# (" + n4 + " coins)#l \r\n#b#L5# #z1492007# (" + n5 + " coins)#l"); } } else if (status == 11) { if (selection == 12) { - cm.sendSimple("Selecione a arma que voc� gostaria de trocar. As armas que eu tenho aqui s�o extremamente �teis. D� uma olhada! \r\n#b#L0# #z1322015#(" + n3 + " moedas)#l\r\n#L1# #z1422008#(" + n3 + " moedas)#l\r\n#L2# #z1322016#(" + n4 + "moedas)#l\r\n#L3# #z1422007#(" + n4 + "moedas)#l\r\n#L4# #z1322017#(" + n5 + " moedas)#l\r\n#L5# #z1422005#(" + n5 + " moedas)#l\r\n#L6# #z1432003#(" + n3 + " moedas)#l\r\n#L7# #z1442003#(" + n3 + " moedas)#l\r\n#L8# #z1432005#(" + n4 + "moedas)#l\r\n#L9# #z1442009#(" + n4 + "moedas)#l\r\n#L10# #z1442005#(" + n5 + " moedas)#l\r\n#L11# #z1432004#(" + n5 + " moedas)#l\r\n#L12# Voltar para a p�gina inicial(2/2)#l"); + cm.sendSimple("Select the weapon you would like to trade. The weapons I have here are extremely useful. Take a look! \r\n#b#L0# #z1322015# (" + n3 + " coins)#l\r\n#L1# #z1422008# (" + n3 + " coins)#l\r\n#L2# #z1322016# (" + n4 + " coins)#l\r\n#L3# #z1422007# (" + n4 + " coins)#l\r\n#L4# #z1322017# (" + n5 + " coins)#l\r\n#L5# #z1422005# (" + n5 + " coins)#l\r\n#L6# #z1432003# (" + n3 + " coins)#l\r\n#L7# #z1442003# (" + n3 + " coins)#l\r\n#L8# #z1432005# (" + n4 + " coins)#l\r\n#L9# #z1442009# (" + n4 + " coins)#l\r\n#L10# #z1442005# (" + n5 + " coins)#l\r\n#L11# #z1432004# (" + n5 + " coins)#l\r\n#L12# Back to the first page (2/2)#l"); } else { var item = new Array(1302004, 1402006, 1302009, 1402007, 1302010, 1402003, 1312006, 1412004, 1312007, 1412005, 1312008, 1412003); var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5); @@ -240,14 +331,14 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Voc� ou n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } } else if (status == 12) { if (selection == 12) { status = 10; - cm.sendSimple("Por favor tenha certeza que voc� possui #t4001129# para a arma que voc� deseja. Selecione a arma que voc� gostaria de trocar #t4001129# por. As op��es que tenho s�o realmente boas, e eu n�o sou eu que falo � o povo que diz! \r\n#b#L0# #z1302004#(" + n3 + " moedas)#l\r\n#L1# #z1402006#(" + n3 + " moedas)#l\r\n#L2# #z1302009#(" + n4 + " moedas)#l\r\n#L3# #z1402007#(" + n4 + " moedas)#l\r\n#L4# #z1302010#(" + n5 + " moedas)#l\r\n#L5# #z1402003#(" + n5 + " moedas)#l\r\n#L6# #z1312006#(" + n3 + " moedas)#l\r\n#L7# #z1412004#(" + n3 + " moedas)#l\r\n#L8# #z1312007#(" + n4 + " moedas)#l\r\n#L9# #z1412005#(" + n4 + " moedas)#l\r\n#L10# #z1312008#(" + n5 + " moedas)#l\r\n#L11# #z1412003#(" + n5 + " moedas)#l\r\n#L12# Ir para a pr�xima p�gina(1/2)#l"); + cm.sendSimple("Please make sure you have #b#t4001129##k for the weapon you want. Select the weapon you would like to trade #t4001129#. The choices I have are really good, and I'm not the one who speaks to the people who say it! \r\n#b#L0# #z1302004# (" + n3 + " coins)#l\r\n#L1# #z1402006# (" + n3 + " coins)#l\r\n#L2# #z1302009# (" + n4 + " coins)#l\r\n#L3# #z1402007# (" + n4 + " coins)#l\r\n#L4# #z1302010# (" + n5 + " coins)#l\r\n#L5# #z1402003# (" + n5 + " coins)#l\r\n#L6# #z1312006# (" + n3 + " coins)#l\r\n#L7# #z1412004# (" + n3 + " coins)#l\r\n#L8# #z1312007# (" + n4 + " coins)#l\r\n#L9# #z1412005# (" + n4 + " coins)#l\r\n#L10# #z1312008# (" + n5 + " coins)#l\r\n#L11# #z1412003# (" + n5 + " coins)#l\r\n#L12# Continue to the next page(1/2)#l"); } else { var item = new Array(1322015, 1422008, 1322016, 1422007, 1322017, 1422005, 1432003, 1442003, 1432005, 1442009, 1442005, 1432004); var cost = new Array(n3, n3, n4, n4, n5, n5, n3, n3, n4, n4, n5, n5); @@ -256,7 +347,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Voc� ou n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } @@ -268,7 +359,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Ou voc� n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } else if (status == 31) { @@ -279,7 +370,7 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Ou voc� n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } else if (status == 41) { @@ -290,54 +381,65 @@ function action(mode, type, selection) { cm.gainItem(4001129, -cost[selection]); cm.dispose(); } else { - cm.sendOk("Ou voc� n�o possui #b#t4001129##k suficientes, ou seu invent�rio est� cheio. Verifique novamente."); + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); + cm.dispose(); + } + } else if (status == 51) { + var item = new Array(1482005, 1482006, 1482007, 1492005, 1492006, 1492007); + var cost = new Array(n3, n4, n5, n3, n4, n5); + if (cm.haveItem(4001129, cost[selection]) && cm.canHold(item[selection])) { + cm.gainItem(item[selection], 1); + cm.gainItem(4001129, -cost[selection]); + cm.dispose(); + } else { + cm.sendOk("You do not have enough #b#t4001129##k, or your inventory is full. Please check again."); cm.dispose(); } } else if (status == 61) { select = selection; if (selection == 0) { - cm.sendNext("Haha! Eu sou Spiegelmann, o l�der dessa Folia. Eu comecei a primeira #bFolia de Monstros#k aqui, aguardando por viajantes como voc� para participar dessa extravaganza!"); + cm.sendNext("Haha! I am Spiegelmann, the leader of this Monster Carnival. I got the first #bMonster Carnival#k here, waiting for travelers like you to take part in this extravaganza!"); } else if (selection == 1) { - cm.sendNext("#bFolia de Monstros#k consiste em 2 grupos entrando no campo de batalha, e ca�ando os monstros invocados pelo outro grupo. � uma #bmiss�o de combate que determina o vitorioso pela quantia de Pontos de Folia (CP) recebidos#k."); + cm.sendNext("#bMonster Carnival#k consists of 2 groups entering the battlefield, and dropping the monsters invoked by the other party. #bA combat brigade that determines the victor by the amount of Carnival Points (CP) received#k."); } else if (selection == 2) { - cm.sendNext("Quando entrar no Campo da Folia, voc� ver� a janela da Folia de Monstros aparecer. Tudo que precisa fazer � #bselecionar o que voc�e quer usar, e pressionar OK#k. Muito f�cil, n�?"); + cm.sendNext("When you enter the Carnival Field, you will see the Monster List window appear. All you need to do is #bselect what you want to use, and press OK#k. Very easy, right?"); } else { cm.dispose(); } } else if (status == 62) { if (select == 0) { - cm.sendNext("O que � a #bFolia de Monstros#k? Hahaha! Vamos dizer que � uma experi�ncia que jamais esquecer�! � uma #bbatalha contra outros viajantes assim como voc�!#k"); + cm.sendNext("What is #bMonster Carnival#k? Hahaha! Let's say it's an experience you'll never forget! It's a battle against other travelers just like you!#k"); } else if (select == 1) { - cm.sendNext("Quando entrar no Campo da Folia, sua tarefa � #breceber CP ca�ando os monstros do grupo oposto, e usar estes CP's para distrair o grupo oposto de ca�ar monstros.#k."); + cm.sendNext("When entering the Carnival Field, your task is to #breceive CP by killing the monsters from the opposite group, and using these CP's to distract the opposing group from hitting monsters#k."); } else if (select == 2) { - cm.sendNext("Assim que se acostumar com os comandos, tente usar #bas teclas TAB e F1 ~ F12#k. #bTAB alterna entre Invoca��o de Monstros/Habilidades/Protetor,#k e, #bF1~ F12 possibilita-o de acessar uma das janelas diretamente#k."); + cm.sendNext("Once you get used to the commands, try using #bTAB and F1 ~ F12#k. #bTAB toggles between Monster Invocation / Skills / Protector#k, and, #bF1 ~ F12 enables you to access one of the windows directly#k."); } } else if (status == 63) { if (select == 0) { - cm.sendNext("Eu sei que � muito perigoso para voc�s lutarem uns com os outros usando armas de verdade; e eu n�o sugeriria um ato t�o barb�rico. N�o meu amigo, o que eu ofere�o � competi��o. A emo��o da batalha e a emo��o de competir contra pessoas t�o fortes e motivadas. Eu ofere�o a premissa de que seu grupo e o grupo oposto ambos #binvoquem os monstros, e derrote os monstros invocados pelo grupo advers�rio. Essa � a ess�ncia da Folia de Monstros. Al�m disso, voc� pode usar Maple Coins ganhos durante a Folia de Monstros para obter novos itens e armas! #k"); + cm.sendNext("I know it's too dangerous for you to fight with each other using real weapons; and I would not suggest such a barbaric act. Not my friend, what I offer to the competition. The excitement of the battle and the excitement of competing against such strong and motivated people. I offer the premise that your group and the opposite group both #binvoquem the monsters, and defeat the monsters invoked by the opposing group. This is the essence of the Monster Carnival. In addition, you can use Maple Coins earned during the Monster Carnival to get new items and weapons! #k"); } else if (select == 1) { - cm.sendNext("Existem 3 maneiras de distrair o grupo advers�rio: #bInvodar um monstro, Habilidade, and Protetor#k. Vou dar-lhe um olhar mais aprofundado, se voc� quiser saber mais sobre 'Instru��es detalhadas'."); + cm.sendNext("There are 3 ways to distract the opposing group: #bSummoning a monster, Ability, and Protector#k. I will give you a more in-depth look if you want to know more about 'detailed instructions'!"); } else if (select == 2) { - cm.sendNext("#bInvocar um Monstro#k chama um monstro que ataca o grupo advers�rio, sob seu controle. Use CP para trazer um Monstro Invocado, e ele ir� aparecer na mesma �rea, atacando o grupo oposto."); + cm.sendNext("#bSummoning#k a Monster calls a monster that attacks the opposing party, under its control. Use CP to bring an Summoned Monster, and it will appear in the same area, attacking the opposing group."); } } else if (status == 64) { if (select == 0) { - cm.sendNext("Claro, n�o � t�o simples assim. Existem outras maneiras de prevenir o outro grupo de ca�ar monstros, e cabe a voc� descobrir como faz�-lo. O que acha? Interessado em uma competi��o amig�vel?"); + cm.sendNext("Of course, it's not that simple. There are other ways to prevent the other group from dropping monsters, and it's up to you to figure out how to do it. What do you think? Interested in a friendly competition?"); cm.dispose(); } else if (select == 1) { - cm.sendNext("Por favor lembre-se. Nunca � uma boa ideia guardar seus CP's. #bOs CP's que voc� usou ir�o ajudar a determinar o vencedor e o perdedor da Folia."); + cm.sendNext("Please remember. It's never a good idea to keep your CP's. #bThe CPs you used will help determine the winner and loser of Monster Carnival."); } else if (select == 2) { - cm.sendNext("#bHabilidade#k � uma op��o de usar habilidades tais como Escurid�o, Fraqueza, e outras para prevenir o grupo oposto de matar outros monstros. S�o necess�rios muitos CP's, mas vale muito a pena. O �nico problema � que eles n�o duram muito. Use essa t�tica com sabedoria!"); + cm.sendNext("#bAbility#k is an option to use abilities such as Darkness, Weakness, and others to prevent the opposing group from killing other monsters. Not many CPs are needed, but it's worth it. The only problem is they do not last very long. Use this tactic wisely!"); } } else if (status == 65) { if (select == 1) { - cm.sendNext("Oh, e n�o se preocupe em tranformar-se em um fantasma. Na Folia de Monstros, #bvoc� n�o perder� EXP ap�s a morte#k. � realmente uma exper�ncia como nenhuma outra!"); + cm.sendNext("Oh, and do not worry about turning into a ghost. In the Monster Carnival, #byou will not lose EXP after death#k. So it's really an experience like no other!"); cm.dispose(); } else if (select == 2) { - cm.sendNext("#bProtetor#k � basicamente um item invocado que aumenta dr�sticamente as habilidades dos monstros invocados pelo seu grupo. Protetor funciona enquanto n�o for demolido pelo grupo oposto, ent�o eu surigo que voc� invoque v�rios monstros primeiro, e ent�o traga o Protetor."); + cm.sendNext("#bProtetor#k basically an invoked item that drastically increases the abilities of the monsters invoked by your group. Protector works until it is demolished by the opposing group, so I'm hoping you'll summon several monsters first, and then bring the Protector."); } } else if (status == 66) { - cm.sendNext("Por �ltimo, enquanto estiver na Folia de Monstros, #bvoc� n�o pode usar items/po��es de recupera��o que voc� leva por ai contigo.#k Entretanto, os monstros deixam esses items cair de vez em quando, e #bassim que peg�-los, o item ativar� imediatamente#k. � por isso que � importante saber quando pegar estes items."); + cm.sendNext("Lastly, while in the Monster Carnival, #byou can not use items / recovery potions that you carry around with you. #kMeanwhile, the monsters let these items fall for good. when, and when you #bget them, the item will immediately activate#k. That's why it's important to know when to get these items."); cm.dispose(); } else if (status == 77) { var allDone; diff --git a/scripts/npc/2042003.js b/scripts/npc/2042003.js index 4a475a35ff..d9cf1d2b6e 100644 --- a/scripts/npc/2042003.js +++ b/scripts/npc/2042003.js @@ -21,7 +21,7 @@ function action(mode, type, selection) { status--; if (status == 0) { cm.warpParty(980000000); - cm.cancelarSaida(); + cm.cancelCPQLobby(); cm.dispose(); } } diff --git a/scripts/npc/2042004.js b/scripts/npc/2042004.js index fa5965c5bf..84801867a7 100644 --- a/scripts/npc/2042004.js +++ b/scripts/npc/2042004.js @@ -9,7 +9,7 @@ function start() { function action(mode, type, selection) { cm.warpParty(980000000); - cm.cancelarSaida(); + cm.cancelCPQLobby(); cm.dispose(); } diff --git a/scripts/npc/2042005.js b/scripts/npc/2042005.js index 6b205c1098..04bb08c1fd 100644 --- a/scripts/npc/2042005.js +++ b/scripts/npc/2042005.js @@ -1,6 +1,13 @@ -var cpqMinLvl = 30; -var cpqMaxLvl = 255; -var cpqMinAmt = 0; +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Jayd - translated CPQ contents to English +--------------------------------------------------------------------------------------------------- +**/ + +var cpqMinLvl = 51; +var cpqMaxLvl = 69; +var cpqMinAmt = 2; var cpqMaxAmt = 6; function start() { @@ -23,10 +30,10 @@ function action(mode, type, selection) { if (status == 0) { if (cm.getParty() == null) { status = 10; - cm.sendOk("#e� necess�rio criar um grupo antes de come�ar o Festival de Monstros!#k"); + cm.sendOk("You need to create a party before you can participate in Monster Carnival!"); } else if (!cm.isLeader()) { status = 10; - cm.sendOk("Se voc� quer come�ar o Festival, avise o #bl�der do grupo#k para falar comigo."); + cm.sendOk("If you want to start the battle, let the #bleader#k come and speak to me."); } else { var leaderMapid = cm.getMapId(); var party = cm.getParty().getMembers(); @@ -45,15 +52,18 @@ function action(mode, type, selection) { if (party >= 1) { status = 10; - cm.sendOk("Voc� n�o tem n�mero suficiente de pessoas em seu grupo. Voc� precisa de um grupo com #b" + cpqMinAmt + "#k - #r" + cpqMaxAmt + "#k membros e eles devem estar no mapa com voc�."); + cm.sendOk("You do not have enough people in your party. You need a party with #b" + cpqMinAmt + "#k - #r" + cpqMaxAmt + "#k members and they should be on the map with you."); } else if (lvlOk != inMap) { status = 10; - cm.sendOk("Certifique se todos em seu grupo est�o dentre os n�veis corretos (" + cpqMinLvl + "~" + cpqMaxLvl + ")!"); + cm.sendOk("Make sure everyone in your party is among the correct levels (" + cpqMinLvl + "~" + cpqMaxLvl + ")!"); } else if (isOutMap > 0) { status = 10; - cm.sendOk("Existe algu�m do grupo que n�o esta no mapa!"); + cm.sendOk("There are some of the party members that is not on the map!"); } else { - cm.sendCPQMapLists2(); + if (!cm.sendCPQMapLists2()) { + cm.sendOk("All Monster Carnival fields are currently in use! Try again later."); + cm.dispose(); + } } } } else if (status == 1) { @@ -62,15 +72,15 @@ function action(mode, type, selection) { cm.challengeParty2(selection); cm.dispose(); } else { - cm.sendOk("A sala esta cheia."); + cm.sendOk("The room is currently full."); cm.dispose(); } } else { var party = cm.getParty().getMembers(); - if ((selection === 0 || selection === 1 ) && party.size() < 1) { - cm.sendOk("Voc� precisa de no m�nimo 2 player para entrar na competi��o."); - } else if ((selection === 2 ) && party.size() < 1) { - cm.sendOk("Voc� precisa de no m�nimo 3 player para entrar na competi��o."); + if ((selection === 0 || selection === 1 ) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 2)) { + cm.sendOk("You need at least 2 players to participate in the battle!"); + } else if ((selection === 2 ) && party.size() < (Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS ? 1 : 3)) { + cm.sendOk("You need at least 3 players to participate in the battle!"); } else { cm.cpqLobby2(selection); } diff --git a/scripts/npc/2042007.js b/scripts/npc/2042007.js index 887b7b65c8..e47fbcc0af 100644 --- a/scripts/npc/2042007.js +++ b/scripts/npc/2042007.js @@ -1,3 +1,9 @@ +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Jayd - translated CPQ contents to English +--------------------------------------------------------------------------------------------------- +**/ var status = 0; var rnk = -1; @@ -21,26 +27,33 @@ function action(mode, type, selection) { else status--; - if (cm.getChar().getMap().isCPQLoserMap()) { + if (cm.getPlayer().getMapId() == 980030010) { + if (status == 0) { + cm.sendNext("I hope you had fun at the Monster Carnival!"); + } else if (status > 0) { + cm.warp(980030000, 0); + cm.dispose(); + } + } else if (cm.getChar().getMap().isCPQLoserMap()) { if (status == 0) { if (cm.getChar().getParty() != null) { var shiu = ""; if (cm.getPlayer().getFestivalPoints() >= 300) { shiu += "#rA#k"; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, apesar da sua excelente performance. A vit�ria pode ser sua da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle despite your excellent performance. Victory can be yours next time! \r\n\r\n#bYour result: " + shiu); rnk = 10; } else if (cm.getPlayer().getFestivalPoints() >= 100) { shiu += "#rB#k"; rnk = 20; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, mesmo com sua �tima performance. S� mais um pouquinho, e a vit�ria poderia ter sido sua.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle, even with your ultimate performance. Just a little bit, and the victory could have been yours! \r\n\r\n#bYour result: " + shiu); } else if (cm.getPlayer().getFestivalPoints() >= 50) { shiu += "#rC#k"; rnk = 30; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha. A vit�ria est� para aqueles que se esfor�am. Vejo seus esfor�os, ent�o a vit�ria n�o est� t�o longe do seu alcance. Continue assim!\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either drew or lost the battle. Victory is for those who strive. I see your efforts, so victory is not far from your reach. Keep it up!\r\n\r\n#bYour result: " + shiu); } else { shiu += "#rD#k"; rnk = 40; - cm.sendOk("Infelizmente, voc� ou empatou ou perdeu a batalha, e sua performance claramente reflete nisso. Espero mais de voc� da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shiu); + cm.sendOk("Unfortunately, you either equalized or lost the battle, and your performance clearly reflects on it. I expect more from you next time. \r\n\r\n#bYour result: " + shiu); } } else { cm.warp(980030000, 0); @@ -81,19 +94,19 @@ function action(mode, type, selection) { if (cm.getPlayer().getFestivalPoints() >= 300) { shi += "#rA#k"; rnk = 1; - cm.sendOk("Parab�ns pela sua vit�ria!!! Que �tima performance! O grupo advers�rio n�o p�de fazer nada! Espero o mesmo bom trabalho da pr�xima vez!\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory!!! What a performance! The opposite group could not do anything! I hope the same good work next time! \r\n\r\n#bYour result: " + shi); } else if (cm.getPlayer().getFestivalPoints() >= 100) { shi += "#rB#k"; rnk = 2; - cm.sendOk("Parab�ns pela sua vit�ria! Isso foi impressionante! Voc� fez um bom trabalho contra o grupo advers�rio! S� mais um pouco, e voc� definitivamente vai conseguir um A na pr�xima vez. \r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory! That was awesome! You did a good job against the opposing group! Just a little longer, and you'll definitely get an A next time! \r\n\r\n#bYour result: " + shi); } else if (cm.getPlayer().getFestivalPoints() >= 50) { shi += "#rC#k"; rnk = 3; - cm.sendOk("Parab�ns pela sua vit�ria. Voc� fez algumas coisas c� e l�, mas essa n�o pode ser considerada uma boa vit�ria. Espero mais de ti da pr�xima vez.\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory. You did some things here and there, but that can not be considered a good victory. I expect more from you next time. \r\n\r\n#bYour result: " + shi); } else { shi += "#rD#k"; rnk = 4; - cm.sendOk("Parab�ns pela sua vit�ria, entretanto sua performance n�o refletiu muito bem isso. Seja mais ativo na sua pr�xima participa��o da Folia de Monstros!\r\n\r\n#bNota da Folia de Monstros : " + shi); + cm.sendOk("Congratulations on your victory, though your performance did not quite reflect that. Be more active in your next participation in the Monster Carnival! \r\n\r\n#bYour result: " + shi); } } else { cm.warp(980030000, 0); diff --git a/scripts/npc/2042008.js b/scripts/npc/2042008.js index d8ec8d8465..3225fb385e 100644 --- a/scripts/npc/2042008.js +++ b/scripts/npc/2042008.js @@ -21,7 +21,7 @@ function action(mode, type, selection) { status--; if (status == 0) { cm.warpParty(980030000, 4); - cm.cancelarSaida(); + cm.cancelCPQLobby(); cm.dispose(); } } diff --git a/scripts/npc/2042009.js b/scripts/npc/2042009.js index d8ec8d8465..3225fb385e 100644 --- a/scripts/npc/2042009.js +++ b/scripts/npc/2042009.js @@ -21,7 +21,7 @@ function action(mode, type, selection) { status--; if (status == 0) { cm.warpParty(980030000, 4); - cm.cancelarSaida(); + cm.cancelCPQLobby(); cm.dispose(); } } diff --git a/scripts/npc/2094002.js b/scripts/npc/2094002.js index e29288247e..cd71c9f626 100644 --- a/scripts/npc/2094002.js +++ b/scripts/npc/2094002.js @@ -43,10 +43,6 @@ function action(mode, type, selection) { break; case 925100100: var emp = eim.getProperty("stage2"); - if (emp == null) { - eim.setProperty("stage2", "0"); - emp = "0"; - } if (emp.equals("0")) { if (cm.haveItem(4001120,20)) { cm.sendNext("Excellent! Now hunt me 20 Rising Medals."); @@ -55,7 +51,6 @@ function action(mode, type, selection) { eim.setProperty("stage2", "1"); } else { cm.sendNext("We are heading into the Pirate Ship now! To get in, we must qualify ourselves as noble pirates. Hunt me 20 Rookie Medals."); - if(cm.countMonster() < 1) cm.getPlayer().getMap().spawnAllMonsterIdFromMapSpawnList(9300114, level, true); } } else if (emp.equals("1")) { if (cm.haveItem(4001121,20)) { @@ -65,7 +60,6 @@ function action(mode, type, selection) { eim.setProperty("stage2", "2"); } else { cm.sendNext("We are heading into the Pirate Ship now! To get in, we must qualify ourselves as noble pirates. Hunt me 20 Rising Medals."); - if(cm.countMonster() < 1) cm.getPlayer().getMap().spawnAllMonsterIdFromMapSpawnList(9300115, level, true); } } else if (emp.equals("2")) { if (cm.haveItem(4001122,20)) { @@ -76,7 +70,6 @@ function action(mode, type, selection) { eim.showClearEffect(cm.getMapId()); } else { cm.sendNext("We are heading into the Pirate Ship now! To get in, we must qualify ourselves as noble pirates. Hunt me 20 Veteran Medals."); - if(cm.countMonster() < 1) cm.getPlayer().getMap().spawnAllMonsterIdFromMapSpawnList(9300116, level, true); } } else { cm.sendNext("The next stage has opened. GO!"); diff --git a/scripts/npc/9201014.js b/scripts/npc/9201014.js index 4f2c1a514c..8fd5c1d715 100644 --- a/scripts/npc/9201014.js +++ b/scripts/npc/9201014.js @@ -27,7 +27,7 @@ 1.0 - First Version by Angel 2.0 - Second Version by happydud3 & XotiCraze 3.0 - Third Version by RonanLana (HeavenMS) - 4.0 - Four Version bby Drago (MapleStorySA) + 4.0 - Fourth Version by Drago (MapleStorySA) --------------------------------------------------------------------------------------------------- **/ var status = -1; diff --git a/scripts/npc/9900000.js b/scripts/npc/9900000.js index f267914e84..cf5dffdb19 100644 --- a/scripts/npc/9900000.js +++ b/scripts/npc/9900000.js @@ -22,74 +22,94 @@ /* * @Name NimaKIN * @Author: Signalize + * @Author: MainlandHero - repurposed to be the style setter in-game for mesos * @NPC: 9900000 - * @Purpose: Hair/Face/Eye Changer -- May set job as GM too - * @GMSPurpose: Sets one's job as a GM. + * @Purpose: Hair/Face/Eye Changer * @Map: 180000000 */ var status = 0; var beauty = 0; var haircolor = Array(); var skin = [0, 1, 2, 3, 4, 5, 9, 10]; -var fhair= [31000, 31010, 31020, 31030, 31040, 31050, 31060, 31070, 31080, 31090, 31100, 31110, 31120, 31130, 31140, 31150, 31160, 31170, 31180, 31190, 31200, 31210, 31220, 31230, 31240, 31250, 31260, 31270, 31280, 31290, 31300, 31310, 31320, 31330, 31340, 31350, 31400, 31410, 31420, 31440, 31450, 31460, 31470, 31480, 31490, 31510, 31520, 31530, 31540, 31550, 31560, 31570, 31580, 31590, 31600, 31610, 31620, 31630, 31640, 31650, 31670, 31680, 31690, 31700, 31710, 31720, 31730, 31740, 31750, 31760, 31770, 31780, 31790, 31800, 31810]; -var hair = [30000, 30010, 30020, 30030, 30040, 30050, 30060, 30070, 30080, 30090, 30110, 30120, 30130, 30140, 30150, 30160, 30170, 30180, 30190, 30200, 30210, 30220, 30230, 30240, 30250, 30260, 30270, 30280, 30290, 30300, 30310, 30320, 30330, 30340, 30350, 30360, 30370, 30400, 30410, 30420, 30440, 30450, 30460, 30470, 30480, 30490, 30510, 30520, 30530, 30540, 30550, 30560, 30570, 30580, 30590, 30600, 30610, 30620, 30630, 30640, 30650, 30660, 30670, 30680, 30690, 30700, 30710, 30720, 30730, 30740, 30750, 30760, 30770, 30780, 30790, 30800, 30810, 30820, 30840]; +var fhair= [31000, 31010, 31020, 31030, 31040, 31050, 31060, 31070, 31080, 31090, 31100, 31110, 31120, 31130, 31140, 31150, 31160, 31170, 31180, 31190, 31200, 31210, 31220, 31230, 31240, 31250, 31260, 31270, 31280, 31290, 31300, 31310, 31320, 31330, 31340, 31350, 31400, 31410, 31420, 31440, 31450, 31460, 31470, 31480, 31490, 31510, 31520, 31530, 31540, 31550, 31560, 31570, 31580, 31590, 31600, 31610, 31620, 31630, 31640, 31650, 31670, 31660, 31680, 31690, 31700, 31710, 31720, 31730, 31740, 31750, 31760, 31770, 31780, 31790, 31800, 31810, 31820, 31830, 31840, 31850, 31860, 31870, 31880, 31890, 31910, 31920, 31930, 31940, 31950, 34010, 34020, 34030, 34050, 34110]; +var hair = [30000, 30010, 30020, 30030, 30040, 30050, 30060, 30070, 30080, 30090, 30110, 30120, 30130, 30140, 30150, 30160, 30170, 30180, 30190, 30200, 30210, 30220, 30230, 30240, 30250, 30260, 30270, 30280, 30290, 30300, 30310, 30320, 30330, 30340, 30350, 30360, 30370, 30400, 30410, 30420, 30440, 30450, 30460, 30470, 30480, 30490, 30510, 30520, 30530, 30540, 30550, 30560, 30570, 30580, 30590, 30600, 30610, 30620, 30630, 30640, 30650, 30660, 30670, 30680, 30690, 30700, 30710, 30720, 30730, 30740, 30750, 30760, 30770, 30780, 30790, 30800, 30810, 30820, 30830, 30840, 30860, 30870, 30880, 30890, 30900, 30910, 30920, 30930, 30940, 30950, 30990, 33000, 33040, 33100]; var hairnew = Array(); -var face = [20000, 20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20011, 20012, 20013, 20014, 20016, 20017, 20018, 20019, 20020, 20021, 20022, 20023, 20024, 20026]; -var fface = [21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21009, 21010, 21011, 21012, 21013, 21014, 21016, 21017, 21018, 21019, 21020, 21021, 21022, 21024, 21025]; +var face = [20000, 20001, 20002, 20003, 20004, 20005, 20006, 20007, 20008, 20009, 20010, 20011, 20012, 20013, 20014, 20015, 20016, 20017, 20018, 20019, 20020, 20021, 20022, 20023, 20024, 20025, 20026, 20027, 20028, 20029, 20031, 20032]; +var fface = [21000, 21001, 21002, 21003, 21004, 21005, 21006, 21007, 21008, 21009, 21010, 21011, 21012, 21013, 21014, 21016, 21017, 21018, 21019, 21020, 21021, 21022, 21023, 21024, 21025, 21026, 21027, 21029, 21030]; var facenew = Array(); var colors = Array(); +var price = 100000; function start() { - if(cm.getPlayer().gmLevel() < 2) { + if(cm.getPlayer().gmLevel() < 1) { cm.sendOk("Hey wassup?"); cm.dispose(); return; } - cm.sendSimple("Hey there, I can change your look. What would you like to change?\r\n#L0#Skin#l\r\n#L1#Hair#l\r\n#L5#Female Hair#l\r\n#L2#Hair Color#l\r\n#L3#Eye#l\r\n#L6#Female Eyes#l\r\n#L4#Eye Color#l\r\n#L7#Set GM job#l"); + if(cm.getPlayer().isMale()){ + cm.sendSimple("Hey there, you can change your look for " + price + " mesos. What would you like to change?\r\n#L0#Skin#l\r\n#L1#Male Hair#l\r\n#L2#Hair Color#l\r\n#L3#Male Regular Eyes#l\r\n#L4#Eye Color#l"); + }else{ + cm.sendSimple("Hey there, you can change your look for " + price + " mesos. What would you like to change?\r\n#L0#Skin#l\r\n#L5#Female Hair#l\r\n#L2#Hair Color#l\r\n#L6#Female Eyes#l\r\n#L4#Eye Color#l"); + } } function action(mode, type, selection) { status++; - if (mode != 1 || cm.getPlayer().gmLevel() < 2){ + if (mode != 1 || cm.getPlayer().gmLevel() < 1){ cm.dispose(); return; } if (status == 1) { beauty = selection + 1; - if (selection == 0) - cm.sendStyle("Pick one?", skin); - else if (selection == 1 || selection == 5) { - for each(var i in selection == 1 ? hair : fhair) - hairnew.push(i); - cm.sendStyle("Pick one?", hairnew); - } else if (selection == 2) { - for(var k = 0; k < 8; k++) - haircolor.push(cm.getPlayer().getHair() + k); - cm.sendStyle("Pick one?", haircolor); - } else if (selection == 3 || selection == 6) { - for each(var j in selection == 3 ? face : fface) - facenew.push(j); - cm.sendStyle("Pick one?", facenew); - } else if (selection == 4) { - for(var i = 0; i < 9; i++) - colors.push(cm.getPlayer().getFace() + (i*100)); - cm.sendStyle("Pick one?", colors); - } else if (selection == 7) { - cm.changeJobById(910); + if(cm.getMeso() > price){ + if (selection == 0) + cm.sendStyle("Pick one?", skin); + else if (selection == 1 || selection == 5) { + for each(var i in selection == 1 ? hair : fhair) + hairnew.push(i); + cm.sendStyle("Pick one?", hairnew); + } else if (selection == 2) { + var baseHair = parseInt(cm.getPlayer().getHair() / 10) * 10; + for(var k = 0; k < 8; k++) + haircolor.push(baseHair + k); + cm.sendStyle("Pick one?", haircolor); + } else if (selection == 3 || selection == 6) { + for each(var j in selection == 3 ? face : fface) + facenew.push(j); + cm.sendStyle("Pick one?", facenew); + } else if (selection == 4) { + var baseFace = parseInt(cm.getPlayer().getFace() / 1000) * 1000 + parseInt(cm.getPlayer().getFace() % 100); + for(var i = 0; i < 9; i++) + colors.push(baseFace + (i*100)); + cm.sendStyle("Pick one?", colors); + } + } else { + cm.sendNext("You don't have enough mesos. Sorry to say this, but without " + price + " mesos, you won't be able to change your look!"); cm.dispose(); - } + } + } else if (status == 2){ - if (beauty == 1) + if (beauty == 1){ cm.setSkin(skin[selection]); - if (beauty == 2 || beauty == 6) + cm.gainMeso(-price); + } + if (beauty == 2 || beauty == 6){ cm.setHair(hairnew[selection]); - if (beauty == 3) + cm.gainMeso(-price); + } + if (beauty == 3){ cm.setHair(haircolor[selection]); - if (beauty == 4 || beauty == 7) + cm.gainMeso(-price); + } + if (beauty == 4 || beauty == 7){ cm.setFace(facenew[selection]); - if (beauty == 5) + cm.gainMeso(-price); + } + if (beauty == 5){ cm.setFace(colors[selection]); + cm.gainMeso(-price); + } cm.dispose(); } } \ No newline at end of file diff --git a/scripts/npc/9977777.js b/scripts/npc/9977777.js index 6e3a3079d6..cb2379c314 100644 --- a/scripts/npc/9977777.js +++ b/scripts/npc/9977777.js @@ -46,6 +46,7 @@ function writeFeatureTab_PQs() { addFeature("GuildPQ & queue with multi-lobby system available."); addFeature("Brand-new PQs: BossRushPQ, CafePQ."); addFeature("Mu Lung Dojo."); + addFeature("Monster Carnival 1 & 2 - thanks Dragohe4rt & Jayd!"); addFeature("Capt. Latanica with party fighting the boss."); addFeature("Filled up missing obligatory event script methods."); addFeature("Secured uniquety of active lobby-name instances."); @@ -74,6 +75,7 @@ function writeFeatureTab_Quests() { function writeFeatureTab_PlayerSocialNetwork() { addFeature("Guild and Alliance system fully functional."); + addFeature("Guild contract system held in Guild Headquarters."); addFeature("Party for novices-only."); addFeature("P. members' HPBar accounts HP gain on equips."); addFeature("Thoroughly reviewed P. Shops and H. Merchants."); @@ -85,6 +87,7 @@ function writeFeatureTab_PlayerSocialNetwork() { addFeature("Protected and improved face expression system."); addFeature("Automated support for Player NPCs and Hall of Fame."); addFeature("Engagement & Wedding system with ring effects."); + addFeature("Wedding Wishlists - thanks Dragohe4rt!"); addFeature("Equipments displays to everyone it's level & EXP info."); addFeature("Further improved the existent minigame mechanics."); addFeature("Trade complete using handshake synchronization."); @@ -188,6 +191,7 @@ function writeFeatureTab_Serverpotentials() { addFeature("Enhanced AP auto-assigner: focus on eqp demands."); addFeature("Enhanced inventory check: free slots smartly fetched."); addFeature("Enhanced petloot handler: no brute-force inv. checks."); + addFeature("Matching system: everyone's decision to trigger action."); addFeature("Players-appointed bestsellers for Owl and Cash Shop."); addFeature("Tweaked pet/mount hunger to a balanced growth rate."); addFeature("Consistent experience and meso gain system."); diff --git a/scripts/npc/cpqchallenge.js b/scripts/npc/cpqchallenge.js index f768e46274..ab5f3ff5cf 100644 --- a/scripts/npc/cpqchallenge.js +++ b/scripts/npc/cpqchallenge.js @@ -1,4 +1,11 @@ -/* global cm */ +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Jayd - translated CPQ contents to English +--------------------------------------------------------------------------------------------------- +**/ + +importPackage(Packages.constants); var status = 0; var party; @@ -27,13 +34,14 @@ function action(mode, type, selection) { status++; else status--; + if (status == 0) { if (cm.getParty().getMembers().size() == party.size()) { cm.getPlayer().setChallenged(true); var snd = ""; for (var i = 0; i < party.size(); i++) - snd += "#bNome: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + party.get(i).getJobNameById(party.get(i).getJobId()) + "#k\r\n\r\n"; - cm.sendAcceptDecline(snd + "Gostaria de lutar contra este grupo no Festival de Monstros?"); + snd += "#bName: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + GameConstants.getJobName(party.get(i).getJobId()) + "#k\r\n\r\n"; + cm.sendAcceptDecline(snd + "Would you like to fight this party at the Monster Carnival?"); } else { return; } @@ -45,7 +53,7 @@ function action(mode, type, selection) { cm.getChar().getParty().setEnemy(ch.getParty()); cm.getChar().setChallenged(false); } else { - cm.sendOk("O numero de players entre os times nao esta igual."); + cm.sendOk("The number of players between the teams is not the same."); } cm.dispose(); } diff --git a/scripts/npc/cpqchallenge2.js b/scripts/npc/cpqchallenge2.js index 8795e8467a..d8454eb4f4 100644 --- a/scripts/npc/cpqchallenge2.js +++ b/scripts/npc/cpqchallenge2.js @@ -1,3 +1,12 @@ +/** +-- Version Info ----------------------------------------------------------------------------------- + 1.0 - First Version by Drago (MapleStorySA) + 2.0 - Second Version by Jayd - translated CPQ contents to English +--------------------------------------------------------------------------------------------------- +**/ + +importPackage(Packages.constants); + var status = 0; var party; @@ -26,13 +35,14 @@ function action(mode, type, selection) { status++; else status--; + if (status == 0) { if (cm.getParty().getMembers().size() == party.size()) { cm.getPlayer().setChallenged(true); var snd = ""; for (var i = 0; i < party.size(); i++) - snd += "#bNome: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + party.get(i).getJobNameById(party.get(i).getJobId()) + "#k\r\n\r\n"; - cm.sendAcceptDecline(snd + "Gostaria de lutar contra este grupo no Festival de Monstros?"); + snd += "#bName: " + party.get(i).getName() + " / (Level: " + party.get(i).getLevel() + ") / " + GameConstants.getJobName(party.get(i).getJobId()) + "#k\r\n\r\n"; + cm.sendAcceptDecline(snd + "Would you like to fight this party at the Monster Carnival?"); } else { return; } diff --git a/scripts/npc/credits.js b/scripts/npc/credits.js index 5e6b2a9461..b683623e81 100644 --- a/scripts/npc/credits.js +++ b/scripts/npc/credits.js @@ -90,6 +90,8 @@ function writeServerStaff_OdinMS() { } function writeServerStaff_Contributors() { + addPerson("Jayd", "Contributor"); + addPerson("Dragohe4rt", "Contributor"); addPerson("Jvlaple", "Contributor"); addPerson("Stereo", "Contributor"); addPerson("AngelSL", "Contributor"); diff --git a/scripts/portal/TD_MC_enterboss2.js b/scripts/portal/TD_MC_enterboss2.js index 0e8147e6a6..066ea6e26e 100644 --- a/scripts/portal/TD_MC_enterboss2.js +++ b/scripts/portal/TD_MC_enterboss2.js @@ -20,34 +20,50 @@ function enter(pi) { return true; } else if(pi.isQuestStarted(2332) && pi.hasItem(4032388)){ - if(pi.getPlayer().getParty() != null){ - pi.getPlayer().showHint("The next part of the quest is solo only! Must leave party."); - return false; - } - else{ - pi.forceCompleteQuest(2332, 1300002); - pi.getPlayer().message("You've found the princess!"); - pi.giveCharacterExp(4400 * 1.5, pi.getPlayer()); - var pm = pi.getEventManager("MK_PrimeMinister"); - pm.setProperty("player", pi.getPlayer().getName()); - - pm.startInstance(pi.getPlayer()); - pi.playPortalSound(); - return true; + pi.forceCompleteQuest(2332, 1300002); + pi.getPlayer().message("You've found the princess!"); + pi.giveCharacterExp(4400 * 1.5, pi.getPlayer()); + + var em = pi.getEventManager("MK_PrimeMinister"); + var party = pi.getPlayer().getParty(); + if (party != null) { + if (em.startInstance(party, pi.getMap())) { + pi.playPortalSound(); + return true; + } else { + pi.message("Another party is already challenging the boss in this channel."); + return false; + } + } else { + if (em.startInstance(pi.getPlayer(), pi.getMap())) { + pi.playPortalSound(); + return true; + } else { + pi.message("Another party is already challenging the boss in this channel."); + return false; + } } } else if(pi.isQuestStarted(2333) || (pi.isQuestCompleted(2332) && !pi.isQuestStarted(2333))){ - if(pi.getPlayer().getParty() != null){ - pi.getPlayer().showHint("The next part of the quest is solo only! Must leave party."); - return false; - } - else{ - var pm = pi.getEventManager("MK_PrimeMinister"); - pm.setProperty("player", pi.getPlayer().getName()); - - pm.startInstance(pi.getPlayer()); - pi.playPortalSound(); - return true; + var em = pi.getEventManager("MK_PrimeMinister"); + + var party = pi.getPlayer().getParty(); + if (party != null) { + if (em.startInstance(1, party, pi.getMap())) { + pi.playPortalSound(); + return true; + } else { + pi.message("Another party is already challenging the boss in this channel."); + return false; + } + } else { + if (em.startInstance(pi.getPlayer(), pi.getMap())) { + pi.playPortalSound(); + return true; + } else { + pi.message("Another party is already challenging the boss in this channel."); + return false; + } } } else{ diff --git a/scripts/quest/2333.js b/scripts/quest/2333.js index d8164d0af3..da10135554 100644 --- a/scripts/quest/2333.js +++ b/scripts/quest/2333.js @@ -2,12 +2,8 @@ QUEST: Where's Violetta? NPC: none */ -importPackage(Packages.server.life); var status = -1; -var timeLimit = 10; //10 minutes -var eventTimer = 1000 * 60 * timeLimit; -var mobId = 3300008; //Prime Minister function start(mode, type, selection){ if(mode == -1 || (mode == 0 && status == 0)){ @@ -28,10 +24,6 @@ function start(mode, type, selection){ } else if (status == 2){ qm.forceStartQuest(); - var eim = qm.getEventInstance(); - eim.startEventTimer(eventTimer); - qm.getPlayer().getMap().getPortal(1).setPortalState(false); - qm.getPlayer().getMap().spawnMonsterOnGroundBelow(MapleLifeFactory.getMonster(mobId), new java.awt.Point(292, 143)); qm.dispose(); } } @@ -53,13 +45,6 @@ function end(mode, type, selection){ else if(status == 1){ qm.gainExp(15000); qm.forceCompleteQuest(); - - var eim = qm.getEventInstance(); - qm.getPlayer().getMap().getPortal(1).setPortalState(true); - eim.stopEventTimer(); - eim.warpEventTeam(106021600); - - eim.dispose(); qm.dispose(); } } \ No newline at end of file diff --git a/sql/db_database.sql b/sql/db_database.sql index cba5708fd7..ca2d8c6e21 100644 --- a/sql/db_database.sql +++ b/sql/db_database.sql @@ -42,7 +42,7 @@ CREATE TABLE IF NOT EXISTS `accounts` ( `rewardpoints` int(11) NOT NULL DEFAULT '0', `votepoints` int(11) NOT NULL DEFAULT '0', `hwid` varchar(12) NOT NULL DEFAULT '', - `lingua` int(1) NOT NULL DEFAULT '2', + `language` int(1) NOT NULL DEFAULT '2', PRIMARY KEY (`id`), UNIQUE KEY `name` (`name`), KEY `ranking1` (`id`,`banned`), diff --git a/sql/db_drops.sql b/sql/db_drops.sql index bd979c80ba..478a60e8bc 100644 --- a/sql/db_drops.sql +++ b/sql/db_drops.sql @@ -17945,7 +17945,7 @@ USE `heavenms`; (8800002, 2280013, 1, 4, 0, 20000), (8800002, 2280015, 1, 4, 0, 20000), (8800002, 2280016, 1, 4, 0, 20000), -(8800002, 2280014, 1, 4, 0, 20000), +(8800002, 2280014, 1, 4, 0, 20000), #-- thanks Tochi for noting item description not following pattern (8800002, 2290084, 1, 4, 0, 40000), (8800002, 2290016, 1, 4, 0, 40000), (8800002, 2290022, 1, 4, 0, 40000), @@ -20769,6 +20769,7 @@ DELETE FROM temp_data WHERE dropperid >= 9300127 AND dropperid <= 9300136; DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; # add CPQ items, CPQ specific items found thanks to Dragohe4rt +# thanks Vcoc for pointing out inexistent itemids among those listed here INSERT IGNORE INTO temp_data (`dropperid`, `itemid`, `minimum_quantity`, `maximum_quantity`, `questid`, `chance`) VALUES (9300127, 2022157, 1, 1, 0, 200000), (9300127, 2022158, 1, 1, 0, 200000), @@ -20780,13 +20781,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300127, 2022164, 1, 1, 0, 200000), (9300127, 2022165, 1, 1, 0, 200000), (9300127, 2022166, 1, 1, 0, 200000), -(9300127, 2022167, 1, 1, 0, 200000), -(9300127, 2022168, 1, 1, 0, 200000), -(9300127, 2022169, 1, 1, 0, 200000), -(9300127, 2022170, 1, 1, 0, 200000), -(9300127, 2022171, 1, 1, 0, 200000), -(9300127, 2022172, 1, 1, 0, 200000), -(9300127, 2022173, 1, 1, 0, 200000), (9300127, 2022174, 1, 1, 0, 200000), (9300127, 2022175, 1, 1, 0, 200000), (9300127, 2022176, 1, 1, 0, 200000), @@ -20803,13 +20797,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300128, 2022164, 1, 1, 0, 200000), (9300128, 2022165, 1, 1, 0, 200000), (9300128, 2022166, 1, 1, 0, 200000), -(9300128, 2022167, 1, 1, 0, 200000), -(9300128, 2022168, 1, 1, 0, 200000), -(9300128, 2022169, 1, 1, 0, 200000), -(9300128, 2022170, 1, 1, 0, 200000), -(9300128, 2022171, 1, 1, 0, 200000), -(9300128, 2022172, 1, 1, 0, 200000), -(9300128, 2022173, 1, 1, 0, 200000), (9300128, 2022174, 1, 1, 0, 200000), (9300128, 2022175, 1, 1, 0, 200000), (9300128, 2022176, 1, 1, 0, 200000), @@ -20826,13 +20813,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300129, 2022164, 1, 1, 0, 200000), (9300129, 2022165, 1, 1, 0, 200000), (9300129, 2022166, 1, 1, 0, 200000), -(9300129, 2022167, 1, 1, 0, 200000), -(9300129, 2022168, 1, 1, 0, 200000), -(9300129, 2022169, 1, 1, 0, 200000), -(9300129, 2022170, 1, 1, 0, 200000), -(9300129, 2022171, 1, 1, 0, 200000), -(9300129, 2022172, 1, 1, 0, 200000), -(9300129, 2022173, 1, 1, 0, 200000), (9300129, 2022174, 1, 1, 0, 200000), (9300129, 2022175, 1, 1, 0, 200000), (9300129, 2022176, 1, 1, 0, 200000), @@ -20849,13 +20829,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300130, 2022164, 1, 1, 0, 200000), (9300130, 2022165, 1, 1, 0, 200000), (9300130, 2022166, 1, 1, 0, 200000), -(9300130, 2022167, 1, 1, 0, 200000), -(9300130, 2022168, 1, 1, 0, 200000), -(9300130, 2022169, 1, 1, 0, 200000), -(9300130, 2022170, 1, 1, 0, 200000), -(9300130, 2022171, 1, 1, 0, 200000), -(9300130, 2022172, 1, 1, 0, 200000), -(9300130, 2022173, 1, 1, 0, 200000), (9300130, 2022174, 1, 1, 0, 200000), (9300130, 2022175, 1, 1, 0, 200000), (9300130, 2022176, 1, 1, 0, 200000), @@ -20872,13 +20845,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300131, 2022164, 1, 1, 0, 200000), (9300131, 2022165, 1, 1, 0, 200000), (9300131, 2022166, 1, 1, 0, 200000), -(9300131, 2022167, 1, 1, 0, 200000), -(9300131, 2022168, 1, 1, 0, 200000), -(9300131, 2022169, 1, 1, 0, 200000), -(9300131, 2022170, 1, 1, 0, 200000), -(9300131, 2022171, 1, 1, 0, 200000), -(9300131, 2022172, 1, 1, 0, 200000), -(9300131, 2022173, 1, 1, 0, 200000), (9300131, 2022174, 1, 1, 0, 200000), (9300131, 2022175, 1, 1, 0, 200000), (9300131, 2022176, 1, 1, 0, 200000), @@ -20895,13 +20861,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300132, 2022164, 1, 1, 0, 200000), (9300132, 2022165, 1, 1, 0, 200000), (9300132, 2022166, 1, 1, 0, 200000), -(9300132, 2022167, 1, 1, 0, 200000), -(9300132, 2022168, 1, 1, 0, 200000), -(9300132, 2022169, 1, 1, 0, 200000), -(9300132, 2022170, 1, 1, 0, 200000), -(9300132, 2022171, 1, 1, 0, 200000), -(9300132, 2022172, 1, 1, 0, 200000), -(9300132, 2022173, 1, 1, 0, 200000), (9300132, 2022174, 1, 1, 0, 200000), (9300132, 2022175, 1, 1, 0, 200000), (9300132, 2022176, 1, 1, 0, 200000), @@ -20918,13 +20877,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300133, 2022164, 1, 1, 0, 200000), (9300133, 2022165, 1, 1, 0, 200000), (9300133, 2022166, 1, 1, 0, 200000), -(9300133, 2022167, 1, 1, 0, 200000), -(9300133, 2022168, 1, 1, 0, 200000), -(9300133, 2022169, 1, 1, 0, 200000), -(9300133, 2022170, 1, 1, 0, 200000), -(9300133, 2022171, 1, 1, 0, 200000), -(9300133, 2022172, 1, 1, 0, 200000), -(9300133, 2022173, 1, 1, 0, 200000), (9300133, 2022174, 1, 1, 0, 200000), (9300133, 2022175, 1, 1, 0, 200000), (9300133, 2022176, 1, 1, 0, 200000), @@ -20941,13 +20893,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300134, 2022164, 1, 1, 0, 200000), (9300134, 2022165, 1, 1, 0, 200000), (9300134, 2022166, 1, 1, 0, 200000), -(9300134, 2022167, 1, 1, 0, 200000), -(9300134, 2022168, 1, 1, 0, 200000), -(9300134, 2022169, 1, 1, 0, 200000), -(9300134, 2022170, 1, 1, 0, 200000), -(9300134, 2022171, 1, 1, 0, 200000), -(9300134, 2022172, 1, 1, 0, 200000), -(9300134, 2022173, 1, 1, 0, 200000), (9300134, 2022174, 1, 1, 0, 200000), (9300134, 2022175, 1, 1, 0, 200000), (9300134, 2022176, 1, 1, 0, 200000), @@ -20964,13 +20909,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300135, 2022164, 1, 1, 0, 200000), (9300135, 2022165, 1, 1, 0, 200000), (9300135, 2022166, 1, 1, 0, 200000), -(9300135, 2022167, 1, 1, 0, 200000), -(9300135, 2022168, 1, 1, 0, 200000), -(9300135, 2022169, 1, 1, 0, 200000), -(9300135, 2022170, 1, 1, 0, 200000), -(9300135, 2022171, 1, 1, 0, 200000), -(9300135, 2022172, 1, 1, 0, 200000), -(9300135, 2022173, 1, 1, 0, 200000), (9300135, 2022174, 1, 1, 0, 200000), (9300135, 2022175, 1, 1, 0, 200000), (9300135, 2022176, 1, 1, 0, 200000), @@ -20987,13 +20925,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300136, 2022164, 1, 1, 0, 200000), (9300136, 2022165, 1, 1, 0, 200000), (9300136, 2022166, 1, 1, 0, 200000), -(9300136, 2022167, 1, 1, 0, 200000), -(9300136, 2022168, 1, 1, 0, 200000), -(9300136, 2022169, 1, 1, 0, 200000), -(9300136, 2022170, 1, 1, 0, 200000), -(9300136, 2022171, 1, 1, 0, 200000), -(9300136, 2022172, 1, 1, 0, 200000), -(9300136, 2022173, 1, 1, 0, 200000), (9300136, 2022174, 1, 1, 0, 200000), (9300136, 2022175, 1, 1, 0, 200000), (9300136, 2022176, 1, 1, 0, 200000), @@ -21010,13 +20941,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300315, 2022164, 1, 1, 0, 200000), (9300315, 2022165, 1, 1, 0, 200000), (9300315, 2022166, 1, 1, 0, 200000), -(9300315, 2022167, 1, 1, 0, 200000), -(9300315, 2022168, 1, 1, 0, 200000), -(9300315, 2022169, 1, 1, 0, 200000), -(9300315, 2022170, 1, 1, 0, 200000), -(9300315, 2022171, 1, 1, 0, 200000), -(9300315, 2022172, 1, 1, 0, 200000), -(9300315, 2022173, 1, 1, 0, 200000), (9300315, 2022174, 1, 1, 0, 200000), (9300315, 2022175, 1, 1, 0, 200000), (9300315, 2022176, 1, 1, 0, 200000), @@ -21033,13 +20957,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300316, 2022164, 1, 1, 0, 200000), (9300316, 2022165, 1, 1, 0, 200000), (9300316, 2022166, 1, 1, 0, 200000), -(9300316, 2022167, 1, 1, 0, 200000), -(9300316, 2022168, 1, 1, 0, 200000), -(9300316, 2022169, 1, 1, 0, 200000), -(9300316, 2022170, 1, 1, 0, 200000), -(9300316, 2022171, 1, 1, 0, 200000), -(9300316, 2022172, 1, 1, 0, 200000), -(9300316, 2022173, 1, 1, 0, 200000), (9300316, 2022174, 1, 1, 0, 200000), (9300316, 2022175, 1, 1, 0, 200000), (9300316, 2022176, 1, 1, 0, 200000), @@ -21056,13 +20973,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300317, 2022164, 1, 1, 0, 200000), (9300317, 2022165, 1, 1, 0, 200000), (9300317, 2022166, 1, 1, 0, 200000), -(9300317, 2022167, 1, 1, 0, 200000), -(9300317, 2022168, 1, 1, 0, 200000), -(9300317, 2022169, 1, 1, 0, 200000), -(9300317, 2022170, 1, 1, 0, 200000), -(9300317, 2022171, 1, 1, 0, 200000), -(9300317, 2022172, 1, 1, 0, 200000), -(9300317, 2022173, 1, 1, 0, 200000), (9300317, 2022174, 1, 1, 0, 200000), (9300317, 2022175, 1, 1, 0, 200000), (9300317, 2022176, 1, 1, 0, 200000), @@ -21079,13 +20989,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300318, 2022164, 1, 1, 0, 200000), (9300318, 2022165, 1, 1, 0, 200000), (9300318, 2022166, 1, 1, 0, 200000), -(9300318, 2022167, 1, 1, 0, 200000), -(9300318, 2022168, 1, 1, 0, 200000), -(9300318, 2022169, 1, 1, 0, 200000), -(9300318, 2022170, 1, 1, 0, 200000), -(9300318, 2022171, 1, 1, 0, 200000), -(9300318, 2022172, 1, 1, 0, 200000), -(9300318, 2022173, 1, 1, 0, 200000), (9300318, 2022174, 1, 1, 0, 200000), (9300318, 2022175, 1, 1, 0, 200000), (9300318, 2022176, 1, 1, 0, 200000), @@ -21102,13 +21005,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300319, 2022164, 1, 1, 0, 200000), (9300319, 2022165, 1, 1, 0, 200000), (9300319, 2022166, 1, 1, 0, 200000), -(9300319, 2022167, 1, 1, 0, 200000), -(9300319, 2022168, 1, 1, 0, 200000), -(9300319, 2022169, 1, 1, 0, 200000), -(9300319, 2022170, 1, 1, 0, 200000), -(9300319, 2022171, 1, 1, 0, 200000), -(9300319, 2022172, 1, 1, 0, 200000), -(9300319, 2022173, 1, 1, 0, 200000), (9300319, 2022174, 1, 1, 0, 200000), (9300319, 2022175, 1, 1, 0, 200000), (9300319, 2022176, 1, 1, 0, 200000), @@ -21125,13 +21021,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300320, 2022164, 1, 1, 0, 200000), (9300320, 2022165, 1, 1, 0, 200000), (9300320, 2022166, 1, 1, 0, 200000), -(9300320, 2022167, 1, 1, 0, 200000), -(9300320, 2022168, 1, 1, 0, 200000), -(9300320, 2022169, 1, 1, 0, 200000), -(9300320, 2022170, 1, 1, 0, 200000), -(9300320, 2022171, 1, 1, 0, 200000), -(9300320, 2022172, 1, 1, 0, 200000), -(9300320, 2022173, 1, 1, 0, 200000), (9300320, 2022174, 1, 1, 0, 200000), (9300320, 2022175, 1, 1, 0, 200000), (9300320, 2022176, 1, 1, 0, 200000), @@ -21148,13 +21037,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300321, 2022164, 1, 1, 0, 200000), (9300321, 2022165, 1, 1, 0, 200000), (9300321, 2022166, 1, 1, 0, 200000), -(9300321, 2022167, 1, 1, 0, 200000), -(9300321, 2022168, 1, 1, 0, 200000), -(9300321, 2022169, 1, 1, 0, 200000), -(9300321, 2022170, 1, 1, 0, 200000), -(9300321, 2022171, 1, 1, 0, 200000), -(9300321, 2022172, 1, 1, 0, 200000), -(9300321, 2022173, 1, 1, 0, 200000), (9300321, 2022174, 1, 1, 0, 200000), (9300321, 2022175, 1, 1, 0, 200000), (9300321, 2022176, 1, 1, 0, 200000), @@ -21171,13 +21053,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300322, 2022164, 1, 1, 0, 200000), (9300322, 2022165, 1, 1, 0, 200000), (9300322, 2022166, 1, 1, 0, 200000), -(9300322, 2022167, 1, 1, 0, 200000), -(9300322, 2022168, 1, 1, 0, 200000), -(9300322, 2022169, 1, 1, 0, 200000), -(9300322, 2022170, 1, 1, 0, 200000), -(9300322, 2022171, 1, 1, 0, 200000), -(9300322, 2022172, 1, 1, 0, 200000), -(9300322, 2022173, 1, 1, 0, 200000), (9300322, 2022174, 1, 1, 0, 200000), (9300322, 2022175, 1, 1, 0, 200000), (9300322, 2022176, 1, 1, 0, 200000), @@ -21194,13 +21069,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300323, 2022164, 1, 1, 0, 200000), (9300323, 2022165, 1, 1, 0, 200000), (9300323, 2022166, 1, 1, 0, 200000), -(9300323, 2022167, 1, 1, 0, 200000), -(9300323, 2022168, 1, 1, 0, 200000), -(9300323, 2022169, 1, 1, 0, 200000), -(9300323, 2022170, 1, 1, 0, 200000), -(9300323, 2022171, 1, 1, 0, 200000), -(9300323, 2022172, 1, 1, 0, 200000), -(9300323, 2022173, 1, 1, 0, 200000), (9300323, 2022174, 1, 1, 0, 200000), (9300323, 2022175, 1, 1, 0, 200000), (9300323, 2022176, 1, 1, 0, 200000), @@ -21217,13 +21085,6 @@ DELETE FROM temp_data WHERE dropperid >= 9300315 AND dropperid <= 9300324; (9300324, 2022164, 1, 1, 0, 200000), (9300324, 2022165, 1, 1, 0, 200000), (9300324, 2022166, 1, 1, 0, 200000), -(9300324, 2022167, 1, 1, 0, 200000), -(9300324, 2022168, 1, 1, 0, 200000), -(9300324, 2022169, 1, 1, 0, 200000), -(9300324, 2022170, 1, 1, 0, 200000), -(9300324, 2022171, 1, 1, 0, 200000), -(9300324, 2022172, 1, 1, 0, 200000), -(9300324, 2022173, 1, 1, 0, 200000), (9300324, 2022174, 1, 1, 0, 200000), (9300324, 2022175, 1, 1, 0, 200000), (9300324, 2022176, 1, 1, 0, 200000), diff --git a/sql/db_shopupdate.sql b/sql/db_shopupdate.sql index fbf4e67d08..1e2c7bcb42 100644 --- a/sql/db_shopupdate.sql +++ b/sql/db_shopupdate.sql @@ -159,11 +159,10 @@ INSERT IGNORE INTO `shopitems` (`shopid`, `itemid`, `price`, `pitch`, `position` (2130000, 2030100, 450, 0, 126), (9201060, 2030100, 450, 0, 114), (9270021, 2030100, 450, 0, 118), -(9270022, 2030100, 450, 0, 114), +(9270022, 2030100, 450, 0, 114), -- Thanks Rednor for finding duplicate item on NPC (1338, 2030100, 450, 0, 114), (9270057, 2030100, 450, 0, 4), -(9270065, 2030100, 450, 0, 3), -(9270022, 2030100, 450, 0, 118); +(9270065, 2030100, 450, 0, 3); -- Thanks to Vcoc -- GMShop: Sacks, GmEquip, Cheese & Onyx, Utils, diff --git a/src/client/MapleCharacter.java b/src/client/MapleCharacter.java index 6fe61df5df..9dcade52fe 100644 --- a/src/client/MapleCharacter.java +++ b/src/client/MapleCharacter.java @@ -161,7 +161,6 @@ import constants.skills.Shadower; import constants.skills.Sniper; import constants.skills.Swordsman; import constants.skills.ThunderBreaker; -import net.server.channel.handlers.PartyOperationHandler; import scripting.item.ItemScriptManager; import server.life.MobSkillFactory; import server.maps.MapleMapItem; @@ -1063,12 +1062,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { gainSp(spGain, GameConstants.getSkillBook(newJob.getId()), true); } - // thanks xinyifly for finding out job advancements awarding APs - /* - if (newJob.getId() % 10 >= 1) { - gainAp(5, true); + // thanks xinyifly for finding out missing AP awards (AP Reset can be used as a compass) + if (newJob.getId() % 100 >= 1) { + if (this.isCygnus()) { + gainAp(7, true); + } else { + gainAp(5, true); + } } - */ if (!isGM()) { for (byte i = 1; i < 5; i++) { @@ -1128,6 +1129,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { effLock.unlock(); } + setMPC(new MaplePartyCharacter(this)); silentPartyUpdate(); if (dragon != null) { @@ -1152,7 +1154,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { if (ServerConstants.USE_ANNOUNCE_CHANGEJOB) { if (!this.isGM()) { - broadcastAcquaintances(6, "[" + GameConstants.ordinal(GameConstants.getJobBranch(newJob)) + " Job] " + name + " has just become a " + newJob.name() + "."); + broadcastAcquaintances(6, "[" + GameConstants.ordinal(GameConstants.getJobBranch(newJob)) + " Job] " + name + " has just become a " + GameConstants.getJobName(this.job.getId()) + "."); // thanks Vcoc for noticing job name appearing in uppercase here } } } @@ -1199,14 +1201,16 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public MapleMap getWarpMap(int map) { - MapleMap target; + MapleMap warpMap; EventInstanceManager eim = getEventInstance(); - if (eim == null) { - target = client.getChannelServer().getMapFactory().getMap(map); + if (eim != null) { + warpMap = eim.getMapInstance(map); + } else if (this.getMonsterCarnival() != null && this.getMonsterCarnival().getEventMap().getId() == map) { + warpMap = this.getMonsterCarnival().getEventMap(); } else { - target = eim.getMapInstance(map); + warpMap = client.getChannelServer().getMapFactory().getMap(map); } - return target; + return warpMap; } // for use ONLY inside OnUserEnter map scripts that requires a player to change map while still moving between maps. @@ -1812,14 +1816,14 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } - private boolean useItem(final int id) { - if (id / 1000000 == 2) { - if (ii.isConsumeOnPickup(id)) { - if (ItemConstants.isPartyItem(id)) { + public boolean applyConsumeOnPickup(final int itemid) { + if (itemid / 1000000 == 2) { + if (ii.isConsumeOnPickup(itemid)) { + if (ItemConstants.isPartyItem(itemid)) { List pchr = this.getPartyMembersOnSameMap(); - if(!ItemConstants.isPartyAllcure(id)) { - MapleStatEffect mse = ii.getItemEffect(id); + if(!ItemConstants.isPartyAllcure(itemid)) { + MapleStatEffect mse = ii.getItemEffect(itemid); if(!pchr.isEmpty()) { for (MapleCharacter mc : pchr) { @@ -1838,7 +1842,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } } else { - ii.getItemEffect(id).applyTo(this); + ii.getItemEffect(itemid).applyTo(this); + } + + if (itemid / 10000 == 238) { + this.getMonsterBook().addCard(client, itemid); } return true; } @@ -1955,10 +1963,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { this.getCashShop().gainCash(1, nxGain); showHint("You have earned #e#b" + nxGain + " NX#k#n. (" + this.getCashShop().getCash(1) + " NX)", 300); - } else if (useItem(mItem.getItemId())) { - if (mItem.getItemId() / 10000 == 238) { - this.getMonsterBook().addCard(client, mItem.getItemId()); - } + } else if (applyConsumeOnPickup(mItem.getItemId())) { } else if (MapleInventoryManipulator.addFromDrop(client, mItem, true)) { } else if (mItem.getItemId() == 4031868) { this.getMap().broadcastMessage(MaplePacketCreator.updateAriantPQRanking(this.getName(), this.getItemQuantity(4031868, false), false)); @@ -5647,11 +5652,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public boolean haveItem(int itemid) { - return getItemQuantity(itemid, false) > 0; + return getItemQuantity(itemid, ItemConstants.isEquipment(itemid)) > 0; } public boolean haveCleanItem(int itemid) { - return getCleanItemQuantity(itemid, false) > 0; + return getCleanItemQuantity(itemid, ItemConstants.isEquipment(itemid)) > 0; } public boolean hasEmptySlot(int itemId) { @@ -5847,7 +5852,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } public boolean attemptCatchFish(int baitLevel) { - return GameConstants.isFishingArea(mapid) && this.getPosition().getY() > 0 && ItemConstants.isFishingChair(chair.get()) && this.getWorldServer().registerFisherPlayer(this, baitLevel); + return ServerConstants.USE_FISHING_SYSTEM && GameConstants.isFishingArea(mapid) && this.getPosition().getY() > 0 && ItemConstants.isFishingChair(chair.get()) && this.getWorldServer().registerFisherPlayer(this, baitLevel); } public void leaveMap() { @@ -5969,8 +5974,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } else { int remainingAp = 5; - if (isCygnus() && level > 10 && level < 70) { - remainingAp++; + + if (isCygnus()) { + if (level > 10) { + if (level <= 17) { + remainingAp += 2; + } else if (level < 77) { + remainingAp++; + } + } } gainAp(remainingAp, true); @@ -6119,23 +6131,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject { Runnable r = new Runnable() { @Override public void run() { - MapleParty party; - boolean partyLeader; - - prtLock.lock(); - try { - party = getParty(); - partyLeader = party != null && isPartyLeader(); - } finally { - prtLock.unlock(); - } - - if (party != null) { - if(partyLeader) { - party.assignNewLeader(client); - } - PartyOperationHandler.leaveParty(party, mpc, client); - + if (leaveParty()) { showHint("You have reached #blevel 10#k, therefore you must leave your #rstarter party#k."); } } @@ -6147,6 +6143,28 @@ public class MapleCharacter extends AbstractMapleCharacterObject { levelUpMessages(); guildUpdate(); } + + public boolean leaveParty() { + MapleParty party; + boolean partyLeader; + + prtLock.lock(); + try { + party = getParty(); + partyLeader = party != null && isPartyLeader(); + } finally { + prtLock.unlock(); + } + + if (party != null) { + if(partyLeader) party.assignNewLeader(client); + MapleParty.leaveParty(party, client); + + return true; + } else { + return false; + } + } private void levelUpMessages() { if (level % 5 != 0) { //Performance FTW? @@ -10288,11 +10306,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject { this.challenged = challenged; } - public void setLingua(int num) { - getClient().setLingua(num); + public void setLanguage(int num) { + getClient().setLanguage(num); try { Connection con = DatabaseConnection.getConnection(); - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET lingua = ? WHERE id = ?")) { + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET language = ? WHERE id = ?")) { ps.setInt(1, num); ps.setInt(2, getClient().getAccID()); ps.executeUpdate(); @@ -10304,8 +10322,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject { } } - public int getLingua() { - return getClient().getLingua(); + public int getLanguage() { + return getClient().getLanguage(); } } \ No newline at end of file diff --git a/src/client/MapleClient.java b/src/client/MapleClient.java index 2847ee87e5..11d6945ba8 100644 --- a/src/client/MapleClient.java +++ b/src/client/MapleClient.java @@ -90,12 +90,13 @@ public class MapleClient { public static final String CLIENT_KEY = "CLIENT"; public static final String CLIENT_HWID = "HWID"; public static final String CLIENT_NIBBLEHWID = "HWID2"; + public static final String CLIENT_REMOTE_ADDRESS = "REMOTE_IP"; private MapleAESOFB send; private MapleAESOFB receive; private final IoSession session; private MapleCharacter player; private int channel = 1; - private int accId = 0; + private int accId = -4; private boolean loggedIn = false; private boolean serverTransition = false; private Calendar birthday = null; @@ -124,7 +125,7 @@ public class MapleClient { private int visibleWorlds; private long lastNpcClick; private long sessionId; - private int lingua = 0; + private int lang = 0; static { for (int i = 0; i < 200; i++) { @@ -534,7 +535,7 @@ public class MapleClient { if (loginattempt > 4) { loggedIn = false; MapleSessionCoordinator.getInstance().closeSession(session, false); - return loginok; + return 6; // thanks Survival_Project for finding out an issue with AUTOMATIC_REGISTER here } Connection con = null; @@ -542,16 +543,15 @@ public class MapleClient { ResultSet rs = null; try { con = DatabaseConnection.getConnection(); - ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos, lingua FROM accounts WHERE name = ?"); + ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos, language FROM accounts WHERE name = ?"); ps.setString(1, login); rs = ps.executeQuery(); + accId = -2; if (rs.next()) { accId = rs.getInt("id"); - if (accId == 0) { - // odd case where accId is actually attributed as 0 (further on this leads to getLoginState ACCID = 0, an absurd), thanks Thora for finding this issue - return 15; - } else if (accId < 0) { + if (accId <= 0) { FilePrinter.printError(FilePrinter.LOGIN_EXCEPTION, "Tried to login with accid " + accId); + return 15; } boolean banned = (rs.getByte("banned") == 1); @@ -560,7 +560,7 @@ public class MapleClient { pic = rs.getString("pic"); gender = rs.getByte("gender"); characterSlots = rs.getByte("characterslots"); - lingua = rs.getInt("lingua"); + lang = rs.getInt("language"); String passhash = rs.getString("password"); byte tos = rs.getByte("tos"); @@ -583,7 +583,9 @@ public class MapleClient { loggedIn = false; loginok = 4; } - } + } else { + accId = -3; + } } catch (SQLException e) { e.printStackTrace(); } finally { @@ -822,9 +824,10 @@ public class MapleClient { int state = rs.getInt("loggedin"); if (state == LOGIN_SERVER_TRANSITION) { if (rs.getTimestamp("lastlogin").getTime() + 30000 < Server.getInstance().getCurrentTime()) { + int accountId = accId; state = LOGIN_NOTLOGGEDIN; - MapleSessionCoordinator.getInstance().closeSession(session, null); - updateLoginState(LOGIN_NOTLOGGEDIN); + updateLoginState(LOGIN_NOTLOGGEDIN); // ACCID = 0, issue found thanks to Tochi & K u ssss o & Thora & Omo Oppa + this.setAccID(accountId); } } rs.close(); @@ -1026,6 +1029,9 @@ public class MapleClient { MapleSessionCoordinator.getInstance().closeSession(session, false); session.removeAttribute(MapleClient.CLIENT_KEY); } + if (!Server.getInstance().hasCharacteridInTransition(session)) { + updateLoginState(MapleClient.LOGIN_NOTLOGGEDIN); + } engines = null; // thanks Tochi for pointing out a NPE here } @@ -1068,7 +1074,21 @@ public class MapleClient { public boolean deleteCharacter(int cid, int senderAccId) { try { - return MapleCharacter.deleteCharFromDB(MapleCharacter.loadCharFromDB(cid, this, false), senderAccId); + MapleCharacter chr = MapleCharacter.loadCharFromDB(cid, this, false); + + Integer partyid = chr.getWorldServer().getCharacterPartyid(cid); + if (partyid != null) { + this.setPlayer(chr); + + MapleParty party = chr.getWorldServer().getParty(partyid); + chr.setParty(party); + chr.getMPC(); + chr.leaveParty(); // thanks Vcoc for pointing out deleted characters would still stay in a party + + this.setPlayer(null); + } + + return MapleCharacter.deleteCharFromDB(chr, senderAccId); } catch(SQLException ex) { ex.printStackTrace(); return false; @@ -1545,11 +1565,11 @@ public class MapleClient { return MapleLoginBypassCoordinator.getInstance().canLoginBypass(getNibbleHWID(), accId, true); } - public int getLingua() { - return lingua; + public int getLanguage() { + return lang; } - public void setLingua(int lingua) { - this.lingua = lingua; + public void setLanguage(int lingua) { + this.lang = lingua; } } \ No newline at end of file diff --git a/src/client/command/CommandsExecutor.java b/src/client/command/CommandsExecutor.java index 61227d15ea..a1d9c3e9e6 100644 --- a/src/client/command/CommandsExecutor.java +++ b/src/client/command/CommandsExecutor.java @@ -186,7 +186,7 @@ public class CommandsExecutor { addCommand("uptime", UptimeCommand.class); addCommand("gacha", GachaCommand.class); addCommand("dispose", DisposeCommand.class); - addCommand("changel", ChangeLinguaCommand.class); + addCommand("changel", ChangeLanguageCommand.class); addCommand("equiplv", EquipLvCommand.class); addCommand("showrates", ShowRatesCommand.class); addCommand("rates", RatesCommand.class); diff --git a/src/client/command/commands/gm0/ChangeLinguaCommand.java b/src/client/command/commands/gm0/ChangeLanguageCommand.java similarity index 92% rename from src/client/command/commands/gm0/ChangeLinguaCommand.java rename to src/client/command/commands/gm0/ChangeLanguageCommand.java index 219279a99f..729adfd926 100644 --- a/src/client/command/commands/gm0/ChangeLinguaCommand.java +++ b/src/client/command/commands/gm0/ChangeLanguageCommand.java @@ -26,7 +26,7 @@ package client.command.commands.gm0; import client.command.Command; import client.MapleClient; -public class ChangeLinguaCommand extends Command { +public class ChangeLanguageCommand extends Command { { setDescription(""); } @@ -37,6 +37,6 @@ public class ChangeLinguaCommand extends Command { c.getPlayer().yellowMessage("Syntax: !changel <0=ptb, 1=esp, 2=eng>"); return; } - c.setLingua(Integer.parseInt(params[0])); + c.setLanguage(Integer.parseInt(params[0])); } } diff --git a/src/client/command/commands/gm0/GmCommand.java b/src/client/command/commands/gm0/GmCommand.java index b9f2a553f9..38b4ae02e1 100644 --- a/src/client/command/commands/gm0/GmCommand.java +++ b/src/client/command/commands/gm0/GmCommand.java @@ -51,7 +51,7 @@ public class GmCommand extends Command { return; } String message = player.getLastCommandMessage(); - Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[GM MESSAGE]:" + MapleCharacter.makeMapleReadable(player.getName()) + ": " + message)); + Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[GM Message]:" + MapleCharacter.makeMapleReadable(player.getName()) + ": " + message)); Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.serverNotice(1, message)); FilePrinter.printError(FilePrinter.COMMAND_GM, MapleCharacter.makeMapleReadable(player.getName()) + ": " + message); player.dropMessage(5, "Your message '" + message + "' was sent to GMs."); diff --git a/src/client/command/commands/gm0/ReportBugCommand.java b/src/client/command/commands/gm0/ReportBugCommand.java index 27bdbd102f..eeae357f7b 100644 --- a/src/client/command/commands/gm0/ReportBugCommand.java +++ b/src/client/command/commands/gm0/ReportBugCommand.java @@ -44,7 +44,7 @@ public class ReportBugCommand extends Command { return; } String message = player.getLastCommandMessage(); - Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[BUG]:" + MapleCharacter.makeMapleReadable(player.getName()) + ": " + message)); + Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[Bug]:" + MapleCharacter.makeMapleReadable(player.getName()) + ": " + message)); Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.serverNotice(1, message)); FilePrinter.printError(FilePrinter.COMMAND_BUG, MapleCharacter.makeMapleReadable(player.getName()) + ": " + message); player.dropMessage(5, "Your bug '" + message + "' was submitted successfully to our developers. Thank you!"); diff --git a/src/client/command/commands/gm4/CakeCommand.java b/src/client/command/commands/gm4/CakeCommand.java index 1a58b65c85..161c5da434 100644 --- a/src/client/command/commands/gm4/CakeCommand.java +++ b/src/client/command/commands/gm4/CakeCommand.java @@ -42,7 +42,6 @@ public class CakeCommand extends Command { double mobHp = Double.parseDouble(params[0]); int newHp = (mobHp <= 0) ? Integer.MAX_VALUE : ((mobHp > Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) mobHp); - monster.getStats().setHp(newHp); monster.setStartingHp(newHp); } diff --git a/src/client/command/commands/gm4/ForceVacCommand.java b/src/client/command/commands/gm4/ForceVacCommand.java index 7830a66ef0..6508ae7a78 100644 --- a/src/client/command/commands/gm4/ForceVacCommand.java +++ b/src/client/command/commands/gm4/ForceVacCommand.java @@ -54,6 +54,7 @@ public class ForceVacCommand extends Command { if (mapItem.getMeso() > 0) { player.gainMeso(mapItem.getMeso(), true); + } else if (player.applyConsumeOnPickup(mapItem.getItemId())) { // thanks Vcoc for pointing out consumables on pickup not being processed here } else if (mapItem.getItemId() == 4031865 || mapItem.getItemId() == 4031866) { // Add NX to account, show effect and make item disappear player.getCashShop().gainCash(1, mapItem.getItemId() == 4031865 ? 100 : 250); diff --git a/src/client/command/commands/gm5/DebugCommand.java b/src/client/command/commands/gm5/DebugCommand.java index edc53da9cb..18700b424b 100644 --- a/src/client/command/commands/gm5/DebugCommand.java +++ b/src/client/command/commands/gm5/DebugCommand.java @@ -84,7 +84,7 @@ public class DebugCommand extends Command { case "portal": MaplePortal portal = player.getMap().findClosestPortal(player.getPosition()); if (portal != null) - player.dropMessage(6, "Closest portal: " + portal.getId() + " '" + portal.getName() + "' Type: " + portal.getType() + " --> toMap: " + portal.getTargetMapId() + " scriptname: '" + portal.getScriptName() + "' state: " + portal.getPortalState() + "."); + player.dropMessage(6, "Closest portal: " + portal.getId() + " '" + portal.getName() + "' Type: " + portal.getType() + " --> toMap: " + portal.getTargetMapId() + " scriptname: '" + portal.getScriptName() + "' state: " + (portal.getPortalState() ? 1 : 0) + "."); else player.dropMessage(6, "There is no portal on this map."); break; diff --git a/src/client/creator/CharacterFactory.java b/src/client/creator/CharacterFactory.java index 5227e90065..4aa0da0e24 100644 --- a/src/client/creator/CharacterFactory.java +++ b/src/client/creator/CharacterFactory.java @@ -93,7 +93,7 @@ public abstract class CharacterFactory { c.announce(MaplePacketCreator.addNewCharEntry(newchar)); Server.getInstance().createCharacterEntry(newchar); - Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[NEW CHAR]: " + c.getAccountName() + " has created a new character with IGN " + name)); + Server.getInstance().broadcastGMMessage(c.getWorld(), MaplePacketCreator.sendYellowTip("[New Char]: " + c.getAccountName() + " has created a new character with IGN " + name)); FilePrinter.print(FilePrinter.CREATED_CHAR + c.getAccountName() + ".txt", c.getAccountName() + " created character with IGN " + name); return 0; diff --git a/src/client/inventory/manipulator/MapleInventoryManipulator.java b/src/client/inventory/manipulator/MapleInventoryManipulator.java index 8e3c58ca1b..77c89044b8 100644 --- a/src/client/inventory/manipulator/MapleInventoryManipulator.java +++ b/src/client/inventory/manipulator/MapleInventoryManipulator.java @@ -265,8 +265,12 @@ public class MapleInventoryManipulator { MapleCharacter chr = c.getPlayer(); MapleInventory inv = chr.getInventory(type); - if(ii.isPickupRestricted(itemid) && haveItemWithId(inv, itemid)) { - return false; + if (ii.isPickupRestricted(itemid)) { + if (haveItemWithId(inv, itemid)) { + return false; + } else if (ItemConstants.isEquipment(itemid) && haveItemWithId(chr.getInventory(MapleInventoryType.EQUIPPED), itemid)) { + return false; + } } if (!type.equals(MapleInventoryType.EQUIP)) { @@ -313,8 +317,12 @@ public class MapleInventoryManipulator { MapleCharacter chr = c.getPlayer(); MapleInventory inv = chr.getInventory(type); - if(ii.isPickupRestricted(itemid) && haveItemWithId(inv, itemid)) { - return 0; + if (ii.isPickupRestricted(itemid)) { + if (haveItemWithId(inv, itemid)) { + return 0; + } else if (ItemConstants.isEquipment(itemid) && haveItemWithId(chr.getInventory(MapleInventoryType.EQUIPPED), itemid)) { + return 0; // thanks Captain & Aika & Vcoc for pointing out inventory checkup on player trades missing out one-of-a-kind items. + } } if (!type.equals(MapleInventoryType.EQUIP)) { @@ -430,7 +438,7 @@ public class MapleInventoryManipulator { } } if (removeQuantity > 0 && type != MapleInventoryType.CANHOLD) { - throw new RuntimeException("[HACK] Not enough items available of Item:" + itemId + ", Quantity (After Quantity/Over Current Quantity): " + (quantity - removeQuantity) + "/" + quantity); + throw new RuntimeException("[Hack] Not enough items available of Item:" + itemId + ", Quantity (After Quantity/Over Current Quantity): " + (quantity - removeQuantity) + "/" + quantity); } } diff --git a/src/client/newyear/NewYearCardRecord.java b/src/client/newyear/NewYearCardRecord.java index 676b94ef96..f46907eec6 100644 --- a/src/client/newyear/NewYearCardRecord.java +++ b/src/client/newyear/NewYearCardRecord.java @@ -318,7 +318,7 @@ public class NewYearCardRecord { other.removeNewYearRecord(nyc); other.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(other, nyc, 0xE, 0)); - other.dropMessage(6, "[NEW YEAR] " + chr.getName() + " threw away the New Year card."); + other.dropMessage(6, "[New Year] " + chr.getName() + " threw away the New Year card."); } } } else { @@ -336,7 +336,7 @@ public class NewYearCardRecord { other.removeNewYearRecord(nyc); other.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(other, nyc, 0xE, 0)); - other.dropMessage(6, "[NEW YEAR] " + chr.getName() + " threw away the New Year card."); + other.dropMessage(6, "[New Year] " + chr.getName() + " threw away the New Year card."); } } } diff --git a/src/client/processor/DueyProcessor.java b/src/client/processor/DueyProcessor.java index d4a8cc6674..929106d9e5 100644 --- a/src/client/processor/DueyProcessor.java +++ b/src/client/processor/DueyProcessor.java @@ -42,6 +42,7 @@ import java.util.List; import net.server.channel.Channel; import server.DueyPackages; import server.MapleItemInformationProvider; +import server.MapleTrade; import tools.DatabaseConnection; import tools.FilePrinter; import tools.MaplePacketCreator; @@ -230,24 +231,6 @@ public class DueyProcessor { } } - private static int getFee(long meso) { - long fee = 0; - if (meso >= 100000000) { - fee = (meso * 6) / 100; - } else if (meso >= 25000000) { - fee = (meso * 5) / 100; - } else if (meso >= 10000000) { - fee = (meso * 4) / 100; - } else if (meso >= 5000000) { - fee = (meso * 3) / 100; - } else if (meso >= 1000000) { - fee = (meso * 18) / 1000; - } else if (meso >= 100000) { - fee = (meso * 8) / 1000; - } - return (int) fee; - } - private static void addMesoToDB(int mesos, String sName, int recipientID) { addItemToDB(null, 1, mesos, sName, recipientID); } @@ -404,7 +387,7 @@ public class DueyProcessor { } MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item); - addItemToDB(item, amount, mesos - getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); + addItemToDB(item, amount, mesos - MapleTrade.getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); } else { if (item != null) { c.announce(MaplePacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode())); @@ -415,7 +398,7 @@ public class DueyProcessor { 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)); + addMesoToDB(mesos - MapleTrade.getFee(mesos), c.getPlayer().getName(), getAccIdFromCNAME(recipient, false)); } if (rClient != null && rClient.isLoggedIn() && !rClient.getPlayer().isAwayFromWorld()) { diff --git a/src/constants/LanguageConstants.java b/src/constants/LanguageConstants.java index 4f8dabc6ab..cde341f421 100644 --- a/src/constants/LanguageConstants.java +++ b/src/constants/LanguageConstants.java @@ -7,65 +7,65 @@ import client.MapleCharacter; * @author Drago - Dragohe4rt */ public class LanguageConstants { - // Portugues - public static String CPQAzul; - public static String CPQErro; - public static String CPQEntrada; - public static String CPQEscolha; - public static String CPQVermelho; + + public static String CPQBlue; + public static String CPQError; + public static String CPQEntry; + public static String CPQFindError; + public static String CPQRed; public static String CPQPlayerExit; - public static String CPQEntradaLobby; - public static String CPQInicioEscolha; - public static String CPQTempoExtendido; - public static String CPQLiderNaoEncontrado; - public static String CPQInicioEscolhaEmEscolha; - public static String CPQInicioEscolhaEnviada; + public static String CPQEntryLobby; + public static String CPQPickRoom; + public static String CPQExtendTime; + public static String CPQLeaderNotFound; + public static String CPQChallengeRoomAnswer; + public static String CPQChallengeRoomSent; - public static LanguageConstants Linguas(MapleCharacter chr) { - if (chr.getLingua() == 0) { - LanguageConstants.CPQAzul = "Maple Azul"; - LanguageConstants.CPQVermelho = "Maple Vermelho"; - LanguageConstants.CPQTempoExtendido = "O tempo foi estendido."; + public static LanguageConstants Languages(MapleCharacter chr) { + if (chr.getLanguage() == 0) { + LanguageConstants.CPQBlue = "Maple Azul"; + LanguageConstants.CPQRed = "Maple Vermelho"; + LanguageConstants.CPQExtendTime = "O tempo foi estendido."; LanguageConstants.CPQPlayerExit = " deixou o Carnaval de Monstros."; - LanguageConstants.CPQErro = "Ocorreu um problema. Favor recriar a sala."; - LanguageConstants.CPQLiderNaoEncontrado = "Nao foi possivel encontrar o Lider."; - LanguageConstants.CPQInicioEscolha = "Inscreva-se no Festival de Monstros!\\r\\n"; - LanguageConstants.CPQInicioEscolhaEmEscolha = "O grupo esta respondendo um desafio no momento."; - LanguageConstants.CPQInicioEscolhaEnviada = "Um desafio foi enviado para o grupo na sala. Aguarde um momento."; - LanguageConstants.CPQEscolha = "Nao foi possivel encontrar um grupo nesta sala.\\r\\nProvavelmente o grupo foi desfeito dentro da sala!"; - LanguageConstants.CPQEntradaLobby = "Agora voce ira receber desafios de outros grupos. Se voce nao aceitar um desafio em 3 minutos, voce sera levado para fora."; - LanguageConstants.CPQEntrada = "Voce pode selecionar \"Invocar Monstros\", \"Habilidade\", ou \"Protetor\" como sua tatica durante o Carnaval dos Monstros. Use Tab a F1~F12 para acesso rapido!"; + LanguageConstants.CPQError = "Ocorreu um problema. Favor recriar a sala."; + LanguageConstants.CPQLeaderNotFound = "Nao foi possivel encontrar o Lider."; + LanguageConstants.CPQPickRoom = "Inscreva-se no Festival de Monstros!\r\n"; + LanguageConstants.CPQChallengeRoomAnswer = "O grupo esta respondendo um desafio no momento."; + LanguageConstants.CPQChallengeRoomSent = "Um desafio foi enviado para o grupo na sala. Aguarde um momento."; + LanguageConstants.CPQFindError = "Nao foi possivel encontrar um grupo nesta sala.\r\nProvavelmente o grupo foi desfeito dentro da sala!"; + LanguageConstants.CPQEntryLobby = "Agora voce ira receber desafios de outros grupos. Se voce nao aceitar um desafio em 3 minutos, voce sera levado para fora."; + LanguageConstants.CPQEntry = "Voce pode selecionar \"Invocar Monstros\", \"Habilidade\", ou \"Protetor\" como sua tatica durante o Carnaval dos Monstros. Use Tab a F1~F12 para acesso rapido!"; - } else if (chr.getLingua() == 1) { - LanguageConstants.CPQAzul = "Maple Azul"; - LanguageConstants.CPQVermelho = "Maple Rojo"; - LanguageConstants.CPQTempoExtendido = "El tiempo se ha ampliado."; + } else if (chr.getLanguage() == 1) { + LanguageConstants.CPQBlue = "Maple Azul"; + LanguageConstants.CPQRed = "Maple Rojo"; + LanguageConstants.CPQExtendTime = "El tiempo se ha ampliado."; LanguageConstants.CPQPlayerExit = " ha dejado el Carnaval de Monstruos."; - LanguageConstants.CPQLiderNaoEncontrado = "No se pudo encontrar el Lider."; - LanguageConstants.CPQInicioEscolha = "!Inscribete en el Festival de Monstruos!\\r\\n"; - LanguageConstants.CPQErro = "Se ha producido un problema. Por favor, volver a crear una sala."; - LanguageConstants.CPQInicioEscolhaEmEscolha = "El grupo esta respondiendo un desafio en el momento."; - LanguageConstants.CPQInicioEscolhaEnviada = "Un desafio fue enviado al grupo en la sala. Espera un momento."; - LanguageConstants.CPQEscolha = "No se pudo encontrar un grupo en esta sala.\\r\\nProbablemente el grupo fue deshecho dentro de la sala!"; - LanguageConstants.CPQEntradaLobby = "Ahora usted recibira los retos de otros grupos. Si usted no acepta un desafio en 3 minutos, usted sera llevado hacia fuera."; - LanguageConstants.CPQEntrada = "Usted puede seleccionar \"Invocar Monstruos \", \"Habilidad \", o \"Protector \" como su tactica durante el Carnaval de los Monstruos. Utilice Tab y F1 ~ F12 para acceso rapido!"; + LanguageConstants.CPQLeaderNotFound = "No se pudo encontrar el Lider."; + LanguageConstants.CPQPickRoom = "!Inscribete en el Festival de Monstruos!\r\n"; + LanguageConstants.CPQError = "Se ha producido un problema. Por favor, volver a crear una sala."; + LanguageConstants.CPQChallengeRoomAnswer = "El grupo esta respondiendo un desafio en el momento."; + LanguageConstants.CPQChallengeRoomSent = "Un desafio fue enviado al grupo en la sala. Espera un momento."; + LanguageConstants.CPQFindError = "No se pudo encontrar un grupo en esta sala.\r\nProbablemente el grupo fue deshecho dentro de la sala!"; + LanguageConstants.CPQEntryLobby = "Ahora usted recibira los retos de otros grupos. Si usted no acepta un desafio en 3 minutos, usted sera llevado hacia fuera."; + LanguageConstants.CPQEntry = "Usted puede seleccionar \"Invocar Monstruos \", \"Habilidad \", o \"Protector \" como su tactica durante el Carnaval de los Monstruos. Utilice Tab y F1 ~ F12 para acceso rapido!"; - } else if (chr.getLingua() == 2) { - LanguageConstants.CPQAzul = "Maple Blue"; - LanguageConstants.CPQVermelho = "Maple Red"; + } else if (chr.getLanguage() == 2) { + LanguageConstants.CPQBlue = "Maple Blue"; + LanguageConstants.CPQRed = "Maple Red"; LanguageConstants.CPQPlayerExit = " left the Carnival of Monsters."; - LanguageConstants.CPQTempoExtendido = "The time has been extended."; - LanguageConstants.CPQLiderNaoEncontrado = "Could not find the Leader."; - LanguageConstants.CPQErro = "There was a problem. Please re-create a room."; - LanguageConstants.CPQInicioEscolha = "Sign up for the Monster Festival!\\r\\n"; - LanguageConstants.CPQInicioEscolhaEmEscolha = "The group is currently facing a challenge."; - LanguageConstants.CPQInicioEscolhaEnviada = "A challenge has been sent to the group in the room. Please wait a while."; - LanguageConstants.CPQEscolha = "We could not find a group in this room.\\r\\nProbably the group was scrapped inside the room!"; - LanguageConstants.CPQEntradaLobby = "You will now receive challenges from other groups. If you do not accept a challenge within 3 minutes, you will be taken out."; - LanguageConstants.CPQEntrada = "You can select \"Summon Monsters \", \"Ability \", or \"Protector \" as your tactic during the Monster Carnival. Use Tab and F1 ~ F12 for quick access!"; + LanguageConstants.CPQExtendTime = "The time has been extended."; + LanguageConstants.CPQLeaderNotFound = "Could not find the Leader."; + LanguageConstants.CPQError = "There was a problem. Please re-create a room."; + LanguageConstants.CPQPickRoom = "Sign up for the Monster Festival!\r\n"; + LanguageConstants.CPQChallengeRoomAnswer = "The group is currently facing a challenge."; + LanguageConstants.CPQChallengeRoomSent = "A challenge has been sent to the group in the room. Please wait a while."; + LanguageConstants.CPQFindError = "We could not find a group in this room.\r\nProbably the group was scrapped inside the room!"; + LanguageConstants.CPQEntryLobby = "You will now receive challenges from other groups. If you do not accept a challenge within 3 minutes, you will be taken out."; + LanguageConstants.CPQEntry = "You can select \"Summon Monsters \", \"Ability \", or \"Protector \" as your tactic during the Monster Carnival. Use Tab and F1 ~ F12 for quick access!"; } return null; diff --git a/src/constants/ServerConstants.java b/src/constants/ServerConstants.java index 1268c7faa0..e506de0c23 100644 --- a/src/constants/ServerConstants.java +++ b/src/constants/ServerConstants.java @@ -28,7 +28,7 @@ public class ServerConstants { public static final long COUPON_INTERVAL = 60 * 60 * 1000; //60 minutes, 3600000. public static final long UPDATE_INTERVAL = 777; //Dictates the frequency on which the "centralized server time" is updated. - public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character required PIC available. + public static final boolean ENABLE_PIC = false; //Pick true/false to enable or disable Pic. Delete character requires PIC available. public static final boolean ENABLE_PIN = false; //Pick true/false to enable or disable Pin. public static final int BYPASS_PIC_EXPIRATION = 20; //Enables PIC bypass, which will remain active for that account by that client machine for N minutes. Set 0 to disable. @@ -48,6 +48,7 @@ public class ServerConstants { //Ip Configuration public static String HOST; + public static boolean LOCALSERVER; //Other Configuration public static boolean JAVA_8; @@ -66,6 +67,7 @@ public class ServerConstants { public static final boolean USE_MAXRANGE = true; //Will send and receive packets from all events on a map, rather than those of only view range. public static final boolean USE_MAXRANGE_ECHO_OF_HERO = true; public static final boolean USE_MTS = false; + public static final boolean USE_CPQ = true; //Renders the CPQ available or not. public static final boolean USE_AUTOHIDE_GM = false; //When enabled, GMs are automatically hidden when joining. Thanks to Steven Deblois (steven1152). public static final boolean USE_BUYBACK_SYSTEM = true; //Enables the HeavenMS-builtin buyback system, to be used by dead players when clicking the MTS button. public static final boolean USE_FIXED_RATIO_HPMP_UPDATE = true; //Enables the HeavenMS-builtin HPMP update based on the current pool to max pool ratio. @@ -108,6 +110,7 @@ public class ServerConstants { public static final boolean USE_ENABLE_CHAT_LOG = false; //Write in-game chat to log public static final boolean USE_REBIRTH_SYSTEM = false; //Flag to enable/disable rebirth system public static final boolean USE_MAP_OWNERSHIP_SYSTEM = true; //Flag to enable/disable map ownership system + public static final boolean USE_FISHING_SYSTEM = true; //Flag to enable/disable fishing system //Events/PQs Configuration 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. @@ -219,6 +222,7 @@ public class ServerConstants { public static final int QUEST_POINT_PER_EVENT_CLEAR = 1; //Each completed event instance awards N quest points, set 0 to disable. //Guild Configuration + public static final int CREATE_GUILD_MIN_PARTNERS = 6; //Minimum number of members on Guild Headquarters to establish a new guild. public static final int CREATE_GUILD_COST = 1500000; public static final int CHANGE_EMBLEM_COST = 5000000; public static final int EXPAND_GUILD_BASE_COST = 500000; @@ -302,6 +306,7 @@ public class ServerConstants { //Server Host ServerConstants.HOST = p.getProperty("HOST"); + ServerConstants.LOCALSERVER = ServerConstants.HOST.startsWith("127.") || ServerConstants.HOST.startsWith("localhost"); //Sql Database ServerConstants.DB_URL = p.getProperty("URL"); diff --git a/src/net/MapleServerHandler.java b/src/net/MapleServerHandler.java index 484f0699ac..bd924fb78e 100644 --- a/src/net/MapleServerHandler.java +++ b/src/net/MapleServerHandler.java @@ -34,6 +34,7 @@ import org.apache.mina.core.session.IoSession; import client.MapleClient; import constants.ServerConstants; +import java.net.InetSocketAddress; import net.server.Server; import net.server.audit.locks.MonitoredLockType; @@ -105,6 +106,8 @@ public class MapleServerHandler extends IoHandlerAdapter { @Override public void sessionOpened(IoSession session) { + session.setAttribute(MapleClient.CLIENT_REMOTE_ADDRESS, ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress()); + if (!Server.getInstance().isOnline()) { MapleSessionCoordinator.getInstance().closeSession(session, true); return; diff --git a/src/net/server/Server.java b/src/net/server/Server.java index 3632e139d0..0e74859312 100644 --- a/src/net/server/Server.java +++ b/src/net/server/Server.java @@ -98,6 +98,7 @@ import server.quest.MapleQuest; import tools.AutoJCE; import tools.DatabaseConnection; import tools.Pair; +import org.apache.mina.core.session.IoSession; public class Server { @@ -1630,12 +1631,12 @@ public class Server { return gmLevel; } - private static String getRemoteIp(InetSocketAddress isa) { - return isa.getAddress().getHostAddress(); + private static String getRemoteIp(IoSession session) { + return MapleSessionCoordinator.getSessionRemoteAddress(session); } - public void setCharacteridInTransition(InetSocketAddress isa, int charId) { - String remoteIp = getRemoteIp(isa); + public void setCharacteridInTransition(IoSession session, int charId) { + String remoteIp = getRemoteIp(session); lgnWLock.lock(); try { @@ -1645,8 +1646,8 @@ public class Server { } } - public boolean validateCharacteridInTransition(InetSocketAddress isa, int charId) { - String remoteIp = getRemoteIp(isa); + public boolean validateCharacteridInTransition(IoSession session, int charId) { + String remoteIp = getRemoteIp(session); lgnWLock.lock(); try { @@ -1657,6 +1658,28 @@ public class Server { } } + public Integer freeCharacteridInTransition(IoSession session) { + String remoteIp = getRemoteIp(session); + + lgnWLock.lock(); + try { + return transitioningChars.remove(remoteIp); + } finally { + lgnWLock.unlock(); + } + } + + public boolean hasCharacteridInTransition(IoSession session) { + String remoteIp = getRemoteIp(session); + + lgnRLock.lock(); + try { + return transitioningChars.containsKey(remoteIp); + } finally { + lgnRLock.unlock(); + } + } + public void registerLoginState(MapleClient c) { srvLock.lock(); try { diff --git a/src/net/server/channel/Channel.java b/src/net/server/channel/Channel.java index 08b9aab87f..dc3c97b018 100644 --- a/src/net/server/channel/Channel.java +++ b/src/net/server/channel/Channel.java @@ -106,6 +106,7 @@ public final class Channel { private MapleEvent event; private boolean finishedShutdown = false; private int usedDojo = 0; + private Set usedMC = new HashSet<>(); private ScheduledFuture respawnTask; @@ -992,6 +993,22 @@ public final class Channel { } } + private static int getMonsterCarnivalRoom(boolean cpq1, int field) { + return (cpq1 ? 0 : 100) + field; + } + + public void initMonsterCarnival(boolean cpq1, int field) { + usedMC.add(getMonsterCarnivalRoom(cpq1, field)); + } + + public void finishMonsterCarnival(boolean cpq1, int field) { + usedMC.remove(getMonsterCarnivalRoom(cpq1, field)); + } + + public boolean canInitMonsterCarnival(boolean cpq1, int field) { + return !usedMC.contains(getMonsterCarnivalRoom(cpq1, field)); + } + private static int getChannelSchedulerIndex(int mapid) { int section = 1000000000 / ServerConstants.CHANNEL_LOCKS; return mapid / section; diff --git a/src/net/server/channel/handlers/GuildOperationHandler.java b/src/net/server/channel/handlers/GuildOperationHandler.java index 20bce7afb5..1e71f990ad 100644 --- a/src/net/server/channel/handlers/GuildOperationHandler.java +++ b/src/net/server/channel/handlers/GuildOperationHandler.java @@ -30,8 +30,13 @@ import net.AbstractMaplePacketHandler; import tools.data.input.SeekableLittleEndianAccessor; import tools.MaplePacketCreator; import client.MapleCharacter; +import java.util.HashSet; +import java.util.Set; import net.server.Server; +import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType; import net.server.guild.MapleAlliance; +import net.server.world.MapleParty; +import net.server.world.World; public final class GuildOperationHandler extends AbstractMaplePacketHandler { private boolean isGuildNameAcceptable(String name) { @@ -56,36 +61,37 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { //c.announce(MaplePacketCreator.showGuildInfo(mc)); break; case 0x02: - if (mc.getGuildId() > 0 || mc.getMapId() != 200000301) { - c.getPlayer().dropMessage(1, "You cannot create a new Guild while in one."); + if (mc.getGuildId() > 0) { + mc.dropMessage(1, "You cannot create a new Guild while in one."); return; } if (mc.getMeso() < ServerConstants.CREATE_GUILD_COST) { - c.getPlayer().dropMessage(1, "You do not have " + GameConstants.numberWithCommas(ServerConstants.CREATE_GUILD_COST) + " mesos to create a Guild."); + mc.dropMessage(1, "You do not have " + GameConstants.numberWithCommas(ServerConstants.CREATE_GUILD_COST) + " mesos to create a Guild."); return; } String guildName = slea.readMapleAsciiString(); if (!isGuildNameAcceptable(guildName)) { - c.getPlayer().dropMessage(1, "The Guild name you have chosen is not accepted."); + mc.dropMessage(1, "The Guild name you have chosen is not accepted."); return; } - int gid = Server.getInstance().createGuild(mc.getId(), guildName); - if (gid == 0) { - c.announce(MaplePacketCreator.genericGuildMessage((byte) 0x1c)); + Set eligibleMembers = new HashSet<>(MapleGuild.getEligiblePlayersForGuild(mc)); + if (eligibleMembers.size() < ServerConstants.CREATE_GUILD_MIN_PARTNERS) { + mc.dropMessage(1, "The Guild you are trying to create don't meet the minimum criteria of number of founders."); return; } - mc.gainMeso(-ServerConstants.CREATE_GUILD_COST, true, false, true); - mc.getMGC().setGuildId(gid); - Server.getInstance().getGuild(mc.getGuildId(), mc.getWorld(), mc); // initialize guild structure - Server.getInstance().changeRank(gid, mc.getId(), 1); + if (!MapleParty.createParty(mc, true)) { + mc.dropMessage(1, "You cannot create a new Guild while in a party."); + return; + } - c.announce(MaplePacketCreator.showGuildInfo(mc)); + Set eligibleCids = new HashSet<>(); + for (MapleCharacter chr : eligibleMembers) { + eligibleCids.add(chr.getId()); + } - c.getPlayer().dropMessage(1, "You have successfully created a Guild."); - mc.getGuild().broadcastNameChanged(); - mc.getGuild().broadcastEmblemChanged(); + c.getWorldServer().getMatchCheckerCoordinator().createMatchConfirmation(MatchCheckerType.GUILD_CREATION, c.getWorld(), mc.getId(), eligibleCids, guildName); break; case 0x05: if (mc.getGuildId() <= 0 || mc.getGuildRank() > 2) { @@ -101,13 +107,13 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { break; case 0x06: if (mc.getGuildId() > 0) { - System.out.println("[hax] " + mc.getName() + " attempted to join a guild when s/he is already in one."); + System.out.println("[Hack] " + mc.getName() + " attempted to join a guild when s/he is already in one."); return; } - gid = slea.readInt(); + int gid = slea.readInt(); int cid = slea.readInt(); if (cid != mc.getId()) { - System.out.println("[hax] " + mc.getName() + " attempted to join a guild with a different character id."); + System.out.println("[Hack] " + mc.getName() + " attempted to join a guild with a different character id."); return; } @@ -121,7 +127,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { int s = Server.getInstance().addGuildMember(mc.getMGC(), mc); if (s == 0) { - c.getPlayer().dropMessage(1, "The guild you are trying to join is already full."); + mc.dropMessage(1, "The guild you are trying to join is already full."); mc.getMGC().setGuildId(0); return; } @@ -139,7 +145,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { cid = slea.readInt(); String name = slea.readMapleAsciiString(); if (cid != mc.getId() || !name.equals(mc.getName()) || mc.getGuildId() <= 0) { - System.out.println("[hax] " + mc.getName() + " tried to quit guild under the name \"" + name + "\" and current guild id of " + mc.getGuildId() + "."); + System.out.println("[Hack] " + mc.getName() + " tried to quit guild under the name \"" + name + "\" and current guild id of " + mc.getGuildId() + "."); return; } @@ -162,7 +168,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { cid = slea.readInt(); name = slea.readMapleAsciiString(); if (mc.getGuildRank() > 2 || mc.getGuildId() <= 0) { - System.out.println("[hax] " + mc.getName() + " is trying to expel without rank 1 or 2."); + System.out.println("[Hack] " + mc.getName() + " is trying to expel without rank 1 or 2."); return; } @@ -171,7 +177,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { break; case 0x0d: if (mc.getGuildId() <= 0 || mc.getGuildRank() != 1) { - System.out.println("[hax] " + mc.getName() + " tried to change guild rank titles when s/he does not have permission."); + System.out.println("[Hack] " + mc.getName() + " tried to change guild rank titles when s/he does not have permission."); return; } String ranks[] = new String[5]; @@ -185,7 +191,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { cid = slea.readInt(); byte newRank = slea.readByte(); if (mc.getGuildRank() > 2 || (newRank <= 2 && mc.getGuildRank() != 1) || mc.getGuildId() <= 0) { - System.out.println("[hax] " + mc.getName() + " is trying to change rank outside of his/her permissions."); + System.out.println("[Hack] " + mc.getName() + " is trying to change rank outside of his/her permissions."); return; } if (newRank <= 1 || newRank > 5) { @@ -195,7 +201,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { break; case 0x0f: if (mc.getGuildId() <= 0 || mc.getGuildRank() != 1 || mc.getMapId() != 200000301) { - System.out.println("[hax] " + mc.getName() + " tried to change guild emblem without being the guild leader."); + System.out.println("[Hack] " + mc.getName() + " tried to change guild emblem without being the guild leader."); return; } if (mc.getMeso() < ServerConstants.CHANGE_EMBLEM_COST) { @@ -219,7 +225,7 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { break; case 0x10: if (mc.getGuildId() <= 0 || mc.getGuildRank() > 2) { - if(mc.getGuildId() <= 0) System.out.println("[hax] " + mc.getName() + " tried to change guild notice while not in a guild."); + if(mc.getGuildId() <= 0) System.out.println("[Hack] " + mc.getName() + " tried to change guild notice while not in a guild."); return; } String notice = slea.readMapleAsciiString(); @@ -227,6 +233,32 @@ public final class GuildOperationHandler extends AbstractMaplePacketHandler { return; } Server.getInstance().setGuildNotice(mc.getGuildId(), notice); + break; + case 0x1E: + slea.readInt(); + World wserv = c.getWorldServer(); + + if (mc.getParty() != null) { + wserv.getMatchCheckerCoordinator().dismissMatchConfirmation(mc.getId()); + return; + } + + int leaderid = wserv.getMatchCheckerCoordinator().getMatchConfirmationLeaderid(mc.getId()); + if (leaderid != -1) { + boolean result = slea.readByte() != 0; + if (result) { + MapleCharacter leader = wserv.getPlayerStorage().getCharacterById(leaderid); + if (leader != null) { + int partyid = leader.getPartyId(); + if (partyid != -1) { + MapleParty.joinParty(mc, partyid, true); + } + } + } + + wserv.getMatchCheckerCoordinator().answerMatchConfirmation(mc.getId(), result); + } + break; default: System.out.println("Unhandled GUILD_OPERATION packet: \n" + slea.toString()); diff --git a/src/net/server/channel/handlers/MessengerHandler.java b/src/net/server/channel/handlers/MessengerHandler.java index 1d652a77a0..3b2539afbf 100644 --- a/src/net/server/channel/handlers/MessengerHandler.java +++ b/src/net/server/channel/handlers/MessengerHandler.java @@ -37,91 +37,92 @@ import tools.data.input.SeekableLittleEndianAccessor; public final class MessengerHandler extends AbstractMaplePacketHandler { @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - c.tryacquireClient(); - try { - String input; - byte mode = slea.readByte(); - MapleCharacter player = c.getPlayer(); - World world = c.getWorldServer(); - MapleMessenger messenger = player.getMessenger(); - switch (mode) { - case 0x00: - int messengerid = slea.readInt(); - if (messenger == null) { - if (messengerid == 0) { - MapleInviteCoordinator.removeInvite(InviteType.MESSENGER, player.getId()); - - MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, 0); - messenger = world.createMessenger(messengerplayer); - player.setMessenger(messenger); - player.setMessengerPosition(0); + if (c.tryacquireClient()) { + try { + String input; + byte mode = slea.readByte(); + MapleCharacter player = c.getPlayer(); + World world = c.getWorldServer(); + MapleMessenger messenger = player.getMessenger(); + switch (mode) { + case 0x00: + int messengerid = slea.readInt(); + if (messenger == null) { + if (messengerid == 0) { + MapleInviteCoordinator.removeInvite(InviteType.MESSENGER, player.getId()); + + MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, 0); + messenger = world.createMessenger(messengerplayer); + player.setMessenger(messenger); + player.setMessengerPosition(0); + } else { + messenger = world.getMessenger(messengerid); + if (messenger != null) { + Pair inviteRes = MapleInviteCoordinator.answerInvite(InviteType.MESSENGER, player.getId(), messengerid, true); + InviteResult res = inviteRes.getLeft(); + if (res == InviteResult.ACCEPTED) { + int position = messenger.getLowestPosition(); + MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, position); + if (messenger.getMembers().size() < 3) { + player.setMessenger(messenger); + player.setMessengerPosition(position); + world.joinMessenger(messenger.getId(), messengerplayer, player.getName(), messengerplayer.getChannel()); + } + } else { + player.message("Could not verify your Maple Messenger accept since the invitation rescinded."); + } + } + } } else { - messenger = world.getMessenger(messengerid); - if (messenger != null) { - Pair inviteRes = MapleInviteCoordinator.answerInvite(InviteType.MESSENGER, player.getId(), messengerid, true); - InviteResult res = inviteRes.getLeft(); - if (res == InviteResult.ACCEPTED) { - int position = messenger.getLowestPosition(); - MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, position); - if (messenger.getMembers().size() < 3) { - player.setMessenger(messenger); - player.setMessengerPosition(position); - world.joinMessenger(messenger.getId(), messengerplayer, player.getName(), messengerplayer.getChannel()); + MapleInviteCoordinator.answerInvite(InviteType.MESSENGER, player.getId(), messengerid, false); + } + break; + case 0x02: + player.closePlayerMessenger(); + break; + case 0x03: + if (messenger == null) { + c.announce(MaplePacketCreator.messengerChat(player.getName() + " : This Maple Messenger is currently unavailable. Please quit this chat.")); + } else if (messenger.getMembers().size() < 3) { + input = slea.readMapleAsciiString(); + MapleCharacter target = c.getChannelServer().getPlayerStorage().getCharacterByName(input); + if (target != null) { + if (target.getMessenger() == null) { + if (MapleInviteCoordinator.createInvite(InviteType.MESSENGER, c.getPlayer(), messenger.getId(), target.getId())) { + target.getClient().announce(MaplePacketCreator.messengerInvite(c.getPlayer().getName(), messenger.getId())); + c.announce(MaplePacketCreator.messengerNote(input, 4, 1)); + } else { + c.announce(MaplePacketCreator.messengerChat(player.getName() + " : " + input + " is already managing a Maple Messenger invitation")); } } else { - player.message("Could not verify your Maple Messenger accept since the invitation rescinded."); - } - } - } - } else { - MapleInviteCoordinator.answerInvite(InviteType.MESSENGER, player.getId(), messengerid, false); - } - break; - case 0x02: - player.closePlayerMessenger(); - break; - case 0x03: - if (messenger == null) { - c.announce(MaplePacketCreator.messengerChat(player.getName() + " : This Maple Messenger is currently unavailable. Please quit this chat.")); - } else if (messenger.getMembers().size() < 3) { - input = slea.readMapleAsciiString(); - MapleCharacter target = c.getChannelServer().getPlayerStorage().getCharacterByName(input); - if (target != null) { - if (target.getMessenger() == null) { - if (MapleInviteCoordinator.createInvite(InviteType.MESSENGER, c.getPlayer(), messenger.getId(), target.getId())) { - target.getClient().announce(MaplePacketCreator.messengerInvite(c.getPlayer().getName(), messenger.getId())); - c.announce(MaplePacketCreator.messengerNote(input, 4, 1)); - } else { - c.announce(MaplePacketCreator.messengerChat(player.getName() + " : " + input + " is already managing a Maple Messenger invitation")); + c.announce(MaplePacketCreator.messengerChat(player.getName() + " : " + input + " is already using Maple Messenger")); } } else { - c.announce(MaplePacketCreator.messengerChat(player.getName() + " : " + input + " is already using Maple Messenger")); + if (world.find(input) > -1) { + world.messengerInvite(c.getPlayer().getName(), messenger.getId(), input, c.getChannel()); + } else { + c.announce(MaplePacketCreator.messengerNote(input, 4, 0)); + } } } else { - if (world.find(input) > -1) { - world.messengerInvite(c.getPlayer().getName(), messenger.getId(), input, c.getChannel()); - } else { - c.announce(MaplePacketCreator.messengerNote(input, 4, 0)); - } + c.announce(MaplePacketCreator.messengerChat(player.getName() + " : You cannot have more than 3 people in the Maple Messenger")); } - } else { - c.announce(MaplePacketCreator.messengerChat(player.getName() + " : You cannot have more than 3 people in the Maple Messenger")); - } - break; - case 0x05: - String targeted = slea.readMapleAsciiString(); - world.declineChat(targeted, player); - break; - case 0x06: - if (messenger != null) { - MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, player.getMessengerPosition()); - input = slea.readMapleAsciiString(); - world.messengerChat(messenger, input, messengerplayer.getName()); - } - break; + break; + case 0x05: + String targeted = slea.readMapleAsciiString(); + world.declineChat(targeted, player); + break; + case 0x06: + if (messenger != null) { + MapleMessengerCharacter messengerplayer = new MapleMessengerCharacter(player, player.getMessengerPosition()); + input = slea.readMapleAsciiString(); + world.messengerChat(messenger, input, messengerplayer.getName()); + } + break; + } + } finally { + c.releaseClient(); } - } finally { - c.releaseClient(); } } } diff --git a/src/net/server/channel/handlers/MonsterCarnivalHandler.java b/src/net/server/channel/handlers/MonsterCarnivalHandler.java index 16c78e6a80..4156bdfc3d 100644 --- a/src/net/server/channel/handlers/MonsterCarnivalHandler.java +++ b/src/net/server/channel/handlers/MonsterCarnivalHandler.java @@ -47,120 +47,117 @@ public final class MonsterCarnivalHandler extends AbstractMaplePacketHandler { @Override public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - c.tryacquireClient(); - try { + if (c.tryacquireClient()) { try { - int tab = slea.readByte(); - int num = slea.readByte(); - int neededCP = 0; - if (tab == 0) { - final List> mobs = c.getPlayer().getMap().getMobsToSpawn(); - if (num >= mobs.size() || c.getPlayer().getCP() < mobs.get(num).right) { - c.announce(MaplePacketCreator.CPQMessage((byte) 1)); - c.announce(MaplePacketCreator.enableActions()); - return; - } - - final MapleMonster mob = MapleLifeFactory.getMonster(mobs.get(num).left); - MonsterCarnival mcpq = c.getPlayer().getMonsterCarnival(); - if (mcpq != null) { - if (!mcpq.canSummonR() && c.getPlayer().getTeam() == 0 || !mcpq.canSummonB() && c.getPlayer().getTeam() == 1) { - c.announce(MaplePacketCreator.CPQMessage((byte) 2)); + try { + int tab = slea.readByte(); + int num = slea.readByte(); + int neededCP = 0; + if (tab == 0) { + final List> mobs = c.getPlayer().getMap().getMobsToSpawn(); + if (num >= mobs.size() || c.getPlayer().getCP() < mobs.get(num).right) { + c.announce(MaplePacketCreator.CPQMessage((byte) 1)); c.announce(MaplePacketCreator.enableActions()); return; } - - if (c.getPlayer().getTeam() == 0) { - mcpq.summonR(); - } else { - mcpq.summonB(); - } - - Point spawnPos = c.getPlayer().getMap().getRandomSP(c.getPlayer().getTeam()); - mob.setPosition(spawnPos); - - c.getPlayer().getMap().addMonsterSpawn(mob, 1, c.getPlayer().getTeam()); - c.getPlayer().getMap().addAllMonsterSpawn(mob, 1, c.getPlayer().getTeam()); - c.announce(MaplePacketCreator.enableActions()); - } - neededCP = mobs.get(num).right; - } else if (tab == 1) { //debuffs - final List skillid = c.getPlayer().getMap().getSkillIds(); - if (num >= skillid.size()) { - c.getPlayer().dropMessage(5, "Ocorreu um erro."); - c.announce(MaplePacketCreator.enableActions()); - return; - } - final MCSkill skill = MapleCarnivalFactory.getInstance().getSkill(skillid.get(num)); //ugh wtf - if (skill == null || c.getPlayer().getCP() < skill.cpLoss) { - c.announce(MaplePacketCreator.CPQMessage((byte) 1)); - c.announce(MaplePacketCreator.enableActions()); - return; - } - final MapleDisease dis = skill.getDisease(); - MapleParty enemies = c.getPlayer().getParty().getEnemy(); - if (skill.targetsAll) { - int chanceAcerto = 0; - if (dis.getDisease() == 121 || dis.getDisease() == 122 || dis.getDisease() == 125 || dis.getDisease() == 126) { - chanceAcerto = (int) (Math.random() * 100); - } - if (chanceAcerto <= 80) { - for (MaplePartyCharacter chrS : enemies.getPartyMembers()) { - if (dis == null) { - chrS.getPlayer().dispel(); - } else { - chrS.getPlayer().giveDebuff(dis, skill.getSkill()); - } - if (!skill.targetsAll) { - break; - } + final MapleMonster mob = MapleLifeFactory.getMonster(mobs.get(num).left); + MonsterCarnival mcpq = c.getPlayer().getMonsterCarnival(); + if (mcpq != null) { + if (!mcpq.canSummonR() && c.getPlayer().getTeam() == 0 || !mcpq.canSummonB() && c.getPlayer().getTeam() == 1) { + c.announce(MaplePacketCreator.CPQMessage((byte) 2)); + c.announce(MaplePacketCreator.enableActions()); + return; } - } - } else { - int amount = enemies.getMembers().size() - 1; - int randd = (int) Math.floor(Math.random() * amount); - MapleCharacter chrApp = c.getChannelServer().getPlayerStorage().getCharacterById(enemies.getMemberByPos(randd).getId()); - if (chrApp != null && chrApp.getMap().isCPQMap()) { - if (dis == null) { - chrApp.dispel(); + + if (c.getPlayer().getTeam() == 0) { + mcpq.summonR(); } else { - chrApp.giveDebuff(dis, skill.getSkill()); + mcpq.summonB(); + } + + Point spawnPos = c.getPlayer().getMap().getRandomSP(c.getPlayer().getTeam()); + mob.setPosition(spawnPos); + + c.getPlayer().getMap().addMonsterSpawn(mob, 1, c.getPlayer().getTeam()); + c.getPlayer().getMap().addAllMonsterSpawn(mob, 1, c.getPlayer().getTeam()); + c.announce(MaplePacketCreator.enableActions()); + } + + neededCP = mobs.get(num).right; + } else if (tab == 1) { //debuffs + final List skillid = c.getPlayer().getMap().getSkillIds(); + if (num >= skillid.size()) { + c.getPlayer().dropMessage(5, "An unexpected error has occurred."); + c.announce(MaplePacketCreator.enableActions()); + return; + } + final MCSkill skill = MapleCarnivalFactory.getInstance().getSkill(skillid.get(num)); //ugh wtf + if (skill == null || c.getPlayer().getCP() < skill.cpLoss) { + c.announce(MaplePacketCreator.CPQMessage((byte) 1)); + c.announce(MaplePacketCreator.enableActions()); + return; + } + final MapleDisease dis = skill.getDisease(); + MapleParty enemies = c.getPlayer().getParty().getEnemy(); + if (skill.targetsAll) { + int chanceAcerto = 0; + if (dis.getDisease() == 121 || dis.getDisease() == 122 || dis.getDisease() == 125 || dis.getDisease() == 126) { + chanceAcerto = (int) (Math.random() * 100); + } + if (chanceAcerto <= 80) { + for (MaplePartyCharacter chrS : enemies.getPartyMembers()) { + if (dis == null) { + chrS.getPlayer().dispel(); + } else { + chrS.getPlayer().giveDebuff(dis, skill.getSkill()); + } + } + } + } else { + int amount = enemies.getMembers().size() - 1; + int randd = (int) Math.floor(Math.random() * amount); + MapleCharacter chrApp = c.getPlayer().getMap().getCharacterById(enemies.getMemberByPos(randd).getId()); + if (chrApp != null && chrApp.getMap().isCPQMap()) { + if (dis == null) { + chrApp.dispel(); + } else { + chrApp.giveDebuff(dis, skill.getSkill()); + } } } - } - neededCP = skill.cpLoss; - c.announce(MaplePacketCreator.enableActions()); - } else if (tab == 2) { //protectors - final MCSkill skill = MapleCarnivalFactory.getInstance().getGuardian(num); - if (skill == null || c.getPlayer().getCP() < skill.cpLoss) { - c.announce(MaplePacketCreator.CPQMessage((byte) 1)); - c.announce(MaplePacketCreator.enableActions()); - return; - } - int success = c.getPlayer().getMap().spawnGuardian(c.getPlayer().getTeam(), num); - if (success == -1 || success == 0 || success == 2) { - if (success == -1) { - c.announce(MaplePacketCreator.CPQMessage((byte) 3)); - } else if (success == 0) { - c.announce(MaplePacketCreator.CPQMessage((byte) 4)); - } else if (success == 2) { - c.announce(MaplePacketCreator.CPQMessage((byte) 3)); - } - c.announce(MaplePacketCreator.enableActions()); - return; - } else { neededCP = skill.cpLoss; + c.announce(MaplePacketCreator.enableActions()); + } else if (tab == 2) { //protectors + final MCSkill skill = MapleCarnivalFactory.getInstance().getGuardian(num); + if (skill == null || c.getPlayer().getCP() < skill.cpLoss) { + c.announce(MaplePacketCreator.CPQMessage((byte) 1)); + c.announce(MaplePacketCreator.enableActions()); + return; + } + int success = c.getPlayer().getMap().spawnGuardian(c.getPlayer().getTeam(), num); + if (success == -1 || success == 0 || success == 2) { + if (success == -1) { + c.announce(MaplePacketCreator.CPQMessage((byte) 3)); + } else if (success == 0) { + c.announce(MaplePacketCreator.CPQMessage((byte) 4)); + } else if (success == 2) { + c.announce(MaplePacketCreator.CPQMessage((byte) 3)); + } + c.announce(MaplePacketCreator.enableActions()); + return; + } else { + neededCP = skill.cpLoss; + } } + c.getPlayer().gainCP(-neededCP); + c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.playerSummoned(c.getPlayer().getName(), tab, num)); + }catch (Exception e) { + e.printStackTrace(); } - c.getPlayer().gainCP(-neededCP); - c.getPlayer().getMap().broadcastMessage(MaplePacketCreator.playerSummoned(c.getPlayer().getName(), tab, num)); - }catch (Exception e) { - e.printStackTrace(); + } finally { + c.releaseClient(); } - } finally { - c.releaseClient(); } } - } diff --git a/src/net/server/channel/handlers/NewYearCardHandler.java b/src/net/server/channel/handlers/NewYearCardHandler.java index 12ee733f75..f780cbb396 100644 --- a/src/net/server/channel/handlers/NewYearCardHandler.java +++ b/src/net/server/channel/handlers/NewYearCardHandler.java @@ -100,7 +100,7 @@ public final class NewYearCardHandler extends AbstractMaplePacketHandler { NewYearCardRecord.updateNewYearCard(newyear); player.getClient().getAbstractPlayerInteraction().gainItem(4301000, (short)1); - if(!newyear.getMessage().isEmpty()) player.dropMessage(6, "[NEW YEAR] " + newyear.getSenderName() + ": " + newyear.getMessage()); + if(!newyear.getMessage().isEmpty()) player.dropMessage(6, "[New Year] " + newyear.getSenderName() + ": " + newyear.getMessage()); player.addNewYearRecord(newyear); player.announce(MaplePacketCreator.onNewYearCardRes(player, newyear, 6, 0)); // successfully rcvd @@ -110,17 +110,17 @@ public final class NewYearCardHandler extends AbstractMaplePacketHandler { MapleCharacter sender = c.getWorldServer().getPlayerStorage().getCharacterById(newyear.getSenderId()); if(sender != null && sender.isLoggedinWorld()) { sender.getMap().broadcastMessage(MaplePacketCreator.onNewYearCardRes(sender, newyear, 0xD, 0)); - sender.dropMessage(6, "[NEW YEAR] Your addressee successfully received the New Year card."); + sender.dropMessage(6, "[New Year] Your addressee successfully received the New Year card."); } } else { player.announce(MaplePacketCreator.onNewYearCardRes(player, -1, 5, 0x10)); // inventory full } } else { - player.dropMessage(6, "[NEW YEAR] The sender of the New Year card already dropped it. Nothing to receive."); + player.dropMessage(6, "[New Year] The sender of the New Year card already dropped it. Nothing to receive."); } } else { if(newyear == null) { - player.dropMessage(6, "[NEW YEAR] The sender of the New Year card already dropped it. Nothing to receive."); + player.dropMessage(6, "[New Year] The sender of the New Year card already dropped it. Nothing to receive."); } } } diff --git a/src/net/server/channel/handlers/PartyOperationHandler.java b/src/net/server/channel/handlers/PartyOperationHandler.java index cf7530c9b9..b80c4cc0d5 100644 --- a/src/net/server/channel/handlers/PartyOperationHandler.java +++ b/src/net/server/channel/handlers/PartyOperationHandler.java @@ -34,72 +34,33 @@ import constants.ServerConstants; import net.server.coordinator.MapleInviteCoordinator; import net.server.coordinator.MapleInviteCoordinator.InviteResult; import net.server.coordinator.MapleInviteCoordinator.InviteType; +import net.server.coordinator.MapleMatchCheckerCoordinator; +import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType; import scripting.event.EventInstanceManager; import server.maps.MapleMap; import tools.Pair; import java.util.List; +import server.partyquest.MonsterCarnival; public final class PartyOperationHandler extends AbstractMaplePacketHandler { - public static void leaveParty(MapleParty party, MaplePartyCharacter partyplayer, MapleClient c) { - World world = c.getWorldServer(); - MapleCharacter player = c.getPlayer(); - - if (party != null && partyplayer != null) { - if (partyplayer.getId() == party.getLeaderId()) { - c.getWorldServer().removeMapPartyMembers(party.getId()); - - world.updateParty(party.getId(), PartyOperation.DISBAND, partyplayer); - if (player.getEventInstance() != null) { - player.getEventInstance().disbandParty(); - } - } else { - player.getMap().removePartyMember(player); - - world.updateParty(party.getId(), PartyOperation.LEAVE, partyplayer); - if (player.getEventInstance() != null) { - player.getEventInstance().leftParty(player); - } - } - - player.setParty(null); - } - } - @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { int operation = slea.readByte(); MapleCharacter player = c.getPlayer(); World world = c.getWorldServer(); MapleParty party = player.getParty(); - MaplePartyCharacter partyplayer = player.getMPC(); switch (operation) { case 1: { // create - if(player.getLevel() < 10 && !ServerConstants.USE_PARTY_FOR_STARTERS) { - c.announce(MaplePacketCreator.partyStatusMessage(10)); - return; - } - if (party == null) { - partyplayer = new MaplePartyCharacter(player); - party = world.createParty(partyplayer); - player.setParty(party); - player.setMPC(partyplayer); - player.getMap().addPartyMember(player); - player.silentPartyUpdate(); - - 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.")); - } + MapleParty.createParty(player, false); break; } case 2: { // leave/disband if (party != null) { List partymembers = player.getPartyMembers(); - leaveParty(party, partyplayer, c); + MapleParty.leaveParty(party, c); player.partyOperationUpdate(party, partymembers); } break; @@ -110,27 +71,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { Pair inviteRes = MapleInviteCoordinator.answerInvite(InviteType.PARTY, player.getId(), partyid, true); InviteResult res = inviteRes.getLeft(); if (res == InviteResult.ACCEPTED) { - if (party == null) { - party = world.getParty(partyid); - if (party != null) { - if (party.getMembers().size() < 6) { - partyplayer = new MaplePartyCharacter(player); - player.getMap().addPartyMember(player); - - world.updateParty(party.getId(), PartyOperation.JOIN, partyplayer); - player.receivePartyMemberHP(); - player.updatePartyMemberHP(); - - player.partyOperationUpdate(party, null); - } else { - c.announce(MaplePacketCreator.partyStatusMessage(17)); - } - } else { - c.announce(MaplePacketCreator.serverNotice(5, "The person you have invited to the party is already in one.")); - } - } else { - c.announce(MaplePacketCreator.serverNotice(5, "You can't join the party as you are already in one.")); - } + MapleParty.joinParty(player, partyid, false); } else { c.announce(MaplePacketCreator.serverNotice(5, "You couldn't join the party due to an expired invitation request.")); } @@ -151,19 +92,11 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { if (invited.getParty() == null) { if (party == null) { - if(player.getLevel() < 10 && !ServerConstants.USE_PARTY_FOR_STARTERS) { - c.announce(MaplePacketCreator.partyStatusMessage(10)); + if (!MapleParty.createParty(player, false)) { return; } - partyplayer = new MaplePartyCharacter(player); - party = world.createParty(partyplayer); - player.setParty(party); - player.setMPC(partyplayer); - player.getMap().addPartyMember(player); - - player.partyOperationUpdate(party, null); - c.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId())); + party = player.getParty(); } if (party.getMembers().size() < 6) { if (MapleInviteCoordinator.createInvite(InviteType.PARTY, player, party.getId(), invited.getId())) { @@ -184,30 +117,7 @@ public final class PartyOperationHandler extends AbstractMaplePacketHandler { } case 5: { // expel int cid = slea.readInt(); - if (partyplayer.equals(party.getLeader())) { - MaplePartyCharacter expelled = party.getMemberById(cid); - if (expelled != null) { - MapleCharacter emc = expelled.getPlayer(); - if(emc != null) { - List partyMembers = emc.getPartyMembers(); - - MapleMap map = emc.getMap(); - if(map != null) map.removePartyMember(emc); - - EventInstanceManager eim = emc.getEventInstance(); - if(eim != null) { - eim.leftParty(emc); - } - - emc.setParty(null); - world.updateParty(party.getId(), PartyOperation.EXPEL, expelled); - - emc.partyOperationUpdate(party, partyMembers); - } else { - world.updateParty(party.getId(), PartyOperation.EXPEL, expelled); - } - } - } + MapleParty.expelFromParty(party, c, cid); break; } case 6: { // change leader diff --git a/src/net/server/channel/handlers/PlayerInteractionHandler.java b/src/net/server/channel/handlers/PlayerInteractionHandler.java index 32a13008f0..68b5a59236 100644 --- a/src/net/server/channel/handlers/PlayerInteractionHandler.java +++ b/src/net/server/channel/handlers/PlayerInteractionHandler.java @@ -484,7 +484,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler { byte targetSlot = slea.readByte(); if (targetSlot < 1 || targetSlot > 9) { - System.out.println("[h4x] " + chr.getName() + " Trying to dupe on trade slot."); + System.out.println("[Hack] " + chr.getName() + " Trying to dupe on trade slot."); c.announce(MaplePacketCreator.enableActions()); return; } diff --git a/src/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/net/server/channel/handlers/PlayerLoggedinHandler.java index 5514a7dc24..0523d9c586 100644 --- a/src/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -59,7 +59,6 @@ import client.inventory.MapleInventoryType; import client.inventory.MaplePet; import constants.GameConstants; import constants.ServerConstants; -import java.net.InetSocketAddress; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; @@ -128,7 +127,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { IoSession session = c.getSession(); String remoteHwid; if (player == null) { - if (!server.validateCharacteridInTransition((InetSocketAddress) session.getRemoteAddress(), cid)) { + if (!server.validateCharacteridInTransition(session, cid)) { c.disconnect(true, false); return; } diff --git a/src/net/server/channel/handlers/RingActionHandler.java b/src/net/server/channel/handlers/RingActionHandler.java index 7424877e31..36e632c1cb 100644 --- a/src/net/server/channel/handlers/RingActionHandler.java +++ b/src/net/server/channel/handlers/RingActionHandler.java @@ -412,10 +412,10 @@ public final class RingActionHandler extends AbstractMaplePacketHandler { MapleCharacter guestChr = c.getWorldServer().getPlayerStorage().getCharacterById(guest); if(guestChr != null && MapleInventoryManipulator.checkSpace(guestChr.getClient(), newItemId, 1, "") && MapleInventoryManipulator.addById(guestChr.getClient(), newItemId, (short) 1, expiration)) { - guestChr.dropMessage(6, "[WEDDING] You've been invited to " + groom + " and " + bride + "'s Wedding!"); + guestChr.dropMessage(6, "[Wedding] You've been invited to " + groom + " and " + bride + "'s Wedding!"); } else { if(guestChr != null && guestChr.isLoggedinWorld()) { - guestChr.dropMessage(6, "[WEDDING] You've been invited to " + groom + " and " + bride + "'s Wedding! Receive your invitation from Duey!"); + guestChr.dropMessage(6, "[Wedding] You've been invited to " + groom + " and " + bride + "'s Wedding! Receive your invitation from Duey!"); } else { c.getPlayer().sendNote(name, "You've been invited to " + groom + " and " + bride + "'s Wedding! Receive your invitation from Duey!", (byte) 0); } diff --git a/src/net/server/channel/handlers/WeddingHandler.java b/src/net/server/channel/handlers/WeddingHandler.java index f7eb05bc9b..1dae1aa6e6 100644 --- a/src/net/server/channel/handlers/WeddingHandler.java +++ b/src/net/server/channel/handlers/WeddingHandler.java @@ -33,122 +33,123 @@ public final class WeddingHandler extends AbstractMaplePacketHandler { @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { - c.tryacquireClient(); - try { - MapleCharacter chr = c.getPlayer(); - final byte mode = slea.readByte(); - - if (mode == 6) { //additem - short slot = slea.readShort(); - int itemid = slea.readInt(); - short quantity = slea.readShort(); + if (c.tryacquireClient()) { + try { + MapleCharacter chr = c.getPlayer(); + final byte mode = slea.readByte(); - MapleMarriage marriage = c.getPlayer().getMarriageInstance(); - if (marriage != null) { - try { - boolean groomWishlist = marriage.giftItemToSpouse(chr.getId()); - String groomWishlistProp = "giftedItem" + (groomWishlist ? "G" : "B") + chr.getId(); - - int giftCount = marriage.getIntProperty(groomWishlistProp); - if (giftCount < ServerConstants.WEDDING_GIFT_LIMIT) { - int cid = marriage.getIntProperty(groomWishlist ? "groomId" : "brideId"); - if (chr.getId() != cid) { // cannot gift yourself - MapleCharacter spouse = marriage.getPlayerById(cid); - if (spouse != null) { - MapleInventoryType type = ItemConstants.getInventoryType(itemid); - MapleInventory chrInv = chr.getInventory(type); + if (mode == 6) { //additem + short slot = slea.readShort(); + int itemid = slea.readInt(); + short quantity = slea.readShort(); - chrInv.lockInventory(); - try { - Item item = chrInv.getItem((byte) slot); - if (item != null) { - if (!item.isUntradeable()) { - if (itemid == item.getItemId() && quantity <= item.getQuantity()) { - Item newItem = item.copy(); + MapleMarriage marriage = c.getPlayer().getMarriageInstance(); + if (marriage != null) { + try { + boolean groomWishlist = marriage.giftItemToSpouse(chr.getId()); + String groomWishlistProp = "giftedItem" + (groomWishlist ? "G" : "B") + chr.getId(); - marriage.addGiftItem(groomWishlist, newItem); - MapleInventoryManipulator.removeFromSlot(c, type, slot, quantity, false, false); + int giftCount = marriage.getIntProperty(groomWishlistProp); + if (giftCount < ServerConstants.WEDDING_GIFT_LIMIT) { + int cid = marriage.getIntProperty(groomWishlist ? "groomId" : "brideId"); + if (chr.getId() != cid) { // cannot gift yourself + MapleCharacter spouse = marriage.getPlayerById(cid); + if (spouse != null) { + MapleInventoryType type = ItemConstants.getInventoryType(itemid); + MapleInventory chrInv = chr.getInventory(type); - if (ServerConstants.USE_ENFORCE_MERCHANT_SAVE) chr.saveCharToDB(false); - marriage.saveGiftItemsToDb(c, groomWishlist, cid); + chrInv.lockInventory(); + try { + Item item = chrInv.getItem((byte) slot); + if (item != null) { + if (!item.isUntradeable()) { + if (itemid == item.getItemId() && quantity <= item.getQuantity()) { + Item newItem = item.copy(); - MapleKarmaManipulator.toggleKarmaFlagToUntradeable(newItem); - marriage.setIntProperty(groomWishlistProp, giftCount + 1); + marriage.addGiftItem(groomWishlist, newItem); + MapleInventoryManipulator.removeFromSlot(c, type, slot, quantity, false, false); - c.announce(Wedding.OnWeddingGiftResult((byte) 0xB, marriage.getWishlistItems(groomWishlist), Collections.singletonList(newItem))); + if (ServerConstants.USE_ENFORCE_MERCHANT_SAVE) chr.saveCharToDB(false); + marriage.saveGiftItemsToDb(c, groomWishlist, cid); + + MapleKarmaManipulator.toggleKarmaFlagToUntradeable(newItem); + marriage.setIntProperty(groomWishlistProp, giftCount + 1); + + c.announce(Wedding.OnWeddingGiftResult((byte) 0xB, marriage.getWishlistItems(groomWishlist), Collections.singletonList(newItem))); + } + } else { + c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), null)); } - } else { - c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), null)); } + } finally { + chrInv.unlockInventory(); } - } finally { - chrInv.unlockInventory(); + } else { + c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), null)); } } else { c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), null)); } } else { - c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), null)); + c.announce(Wedding.OnWeddingGiftResult((byte) 0xC, marriage.getWishlistItems(groomWishlist), null)); } - } else { - c.announce(Wedding.OnWeddingGiftResult((byte) 0xC, marriage.getWishlistItems(groomWishlist), null)); - } - } catch (NumberFormatException nfe) {} - } else { - c.announce(MaplePacketCreator.enableActions()); - } - } else if (mode == 7) { // take items - slea.readByte(); // invType - int itemPos = slea.readByte(); - - MapleMarriage marriage = chr.getMarriageInstance(); - if (marriage != null) { - Boolean groomWishlist = marriage.isMarriageGroom(chr); - if (groomWishlist != null) { - Item item = marriage.getGiftItem(c, groomWishlist, itemPos); - if (item != null) { - if (MapleInventory.checkSpot(chr, item)) { - marriage.removeGiftItem(groomWishlist, item); - marriage.saveGiftItemsToDb(c, groomWishlist, chr.getId()); - - MapleInventoryManipulator.addFromDrop(c, item, true); + } catch (NumberFormatException nfe) {} + } else { + c.announce(MaplePacketCreator.enableActions()); + } + } else if (mode == 7) { // take items + slea.readByte(); // invType + int itemPos = slea.readByte(); - c.announce(Wedding.OnWeddingGiftResult((byte) 0xF, marriage.getWishlistItems(groomWishlist), marriage.getGiftItems(c, groomWishlist))); + MapleMarriage marriage = chr.getMarriageInstance(); + if (marriage != null) { + Boolean groomWishlist = marriage.isMarriageGroom(chr); + if (groomWishlist != null) { + Item item = marriage.getGiftItem(c, groomWishlist, itemPos); + if (item != null) { + if (MapleInventory.checkSpot(chr, item)) { + marriage.removeGiftItem(groomWishlist, item); + marriage.saveGiftItemsToDb(c, groomWishlist, chr.getId()); + + MapleInventoryManipulator.addFromDrop(c, item, true); + + c.announce(Wedding.OnWeddingGiftResult((byte) 0xF, marriage.getWishlistItems(groomWishlist), marriage.getGiftItems(c, groomWishlist))); + } else { + c.getPlayer().dropMessage(1, "Free a slot on your inventory before collecting this item."); + c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), marriage.getGiftItems(c, groomWishlist))); + } } else { - c.getPlayer().dropMessage(1, "Free a slot on your inventory before collecting this item."); + c.getPlayer().dropMessage(1, "You have already collected this item."); c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), marriage.getGiftItems(c, groomWishlist))); } - } else { - c.getPlayer().dropMessage(1, "You have already collected this item."); - c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, marriage.getWishlistItems(groomWishlist), marriage.getGiftItems(c, groomWishlist))); } - } - } else { - List items = c.getAbstractPlayerInteraction().getUnclaimedMarriageGifts(); - try { - Item item = items.get(itemPos); - if (MapleInventory.checkSpot(chr, item)) { - items.remove(itemPos); - MapleMarriage.saveGiftItemsToDb(c, items, chr.getId()); + } else { + List items = c.getAbstractPlayerInteraction().getUnclaimedMarriageGifts(); + try { + Item item = items.get(itemPos); + if (MapleInventory.checkSpot(chr, item)) { + items.remove(itemPos); + MapleMarriage.saveGiftItemsToDb(c, items, chr.getId()); - MapleInventoryManipulator.addFromDrop(c, item, true); - c.announce(Wedding.OnWeddingGiftResult((byte) 0xF, Collections.singletonList(""), items)); - } else { - c.getPlayer().dropMessage(1, "Free a slot on your inventory before collecting this item."); + MapleInventoryManipulator.addFromDrop(c, item, true); + c.announce(Wedding.OnWeddingGiftResult((byte) 0xF, Collections.singletonList(""), items)); + } else { + c.getPlayer().dropMessage(1, "Free a slot on your inventory before collecting this item."); + c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, Collections.singletonList(""), items)); + } + } catch (Exception e) { + c.getPlayer().dropMessage(1, "You have already collected this item."); c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, Collections.singletonList(""), items)); } - } catch (Exception e) { - c.getPlayer().dropMessage(1, "You have already collected this item."); - c.announce(Wedding.OnWeddingGiftResult((byte) 0xE, Collections.singletonList(""), items)); } + } else if (mode == 8) { // out of Wedding Registry + c.announce(MaplePacketCreator.enableActions()); + } else { + System.out.println(mode); } - } else if (mode == 8) { // out of Wedding Registry - c.announce(MaplePacketCreator.enableActions()); - } else { - System.out.println(mode); + } finally { + c.releaseClient(); } - } finally { - c.releaseClient(); } } } \ No newline at end of file diff --git a/src/net/server/coordinator/MapleMatchCheckerCoordinator.java b/src/net/server/coordinator/MapleMatchCheckerCoordinator.java new file mode 100644 index 0000000000..3172cab6ed --- /dev/null +++ b/src/net/server/coordinator/MapleMatchCheckerCoordinator.java @@ -0,0 +1,358 @@ +/* + 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.coordinator; + +import client.MapleCharacter; +import net.server.PlayerStorage; +import net.server.Server; +import net.server.coordinator.matchchecker.AbstractMatchCheckerListener; +import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType; +import net.server.world.World; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import java.util.concurrent.Semaphore; + +/** + * + * @author Ronan + */ +public class MapleMatchCheckerCoordinator { + + private final Map matchEntries = new HashMap<>(); + + private final Set pooledCids = new HashSet<>(); + private final Semaphore semaphorePool = new Semaphore(7); + + private class MapleMatchCheckingEntry { + private boolean accepted; + private int cid; + + private MapleMatchCheckingEntry(int cid) { + this.cid = cid; + this.accepted = false; + } + + private boolean setAccept() { + if (!this.accepted) { + this.accepted = true; + return true; + } else { + return false; + } + } + + private boolean getAccept() { + return this.accepted; + } + } + + private class MapleMatchCheckingElement { + private int leaderCid; + private int world; + + private MatchCheckerType matchType; + private AbstractMatchCheckerListener listener; + + private Map confirmingMembers = new HashMap<>(); + private int confirmCount; + + private String message; + + private MapleMatchCheckingElement(MatchCheckerType matchType, int leaderCid, int world, AbstractMatchCheckerListener leaderListener, Set matchPlayers, String message) { + this.leaderCid = leaderCid; + this.world = world; + this.listener = leaderListener; + this.confirmCount = 0; + this.message = message; + this.matchType = matchType; + + for (Integer cid : matchPlayers) { + MapleMatchCheckingEntry mmcEntry = new MapleMatchCheckingEntry(cid); + confirmingMembers.put(cid, mmcEntry); + } + } + + private boolean acceptEntry(int cid) { + MapleMatchCheckingEntry mmcEntry = confirmingMembers.get(cid); + if (mmcEntry != null) { + if (mmcEntry.setAccept()) { + this.confirmCount++; + + if (this.confirmCount == this.confirmingMembers.size()) { + return true; + } + } + } + + return false; + } + + private Set getMatchPlayers() { + return confirmingMembers.keySet(); + } + + private Set getMatchCharacters() { + Set players = new HashSet<>(); + + World wserv = Server.getInstance().getWorld(world); + if (wserv != null) { + PlayerStorage ps = wserv.getPlayerStorage(); + + for (Integer cid : getMatchPlayers()) { + MapleCharacter chr = ps.getCharacterById(cid); + if (chr != null) { + players.add(chr); + } + } + } + + return players; + } + + private void dispatchMatchCreated() { + Set nonLeaderMatchPlayers = getMatchCharacters(); + MapleCharacter leader = null; + + for (MapleCharacter chr : nonLeaderMatchPlayers) { + if (chr.getId() == leaderCid) { + leader = chr; + break; + } + } + + nonLeaderMatchPlayers.remove(leader); + listener.onMatchCreated(leader, nonLeaderMatchPlayers, message); + } + + private void dispatchMatchResult(boolean accept) { + if (accept) { + listener.onMatchAccepted(leaderCid, getMatchCharacters(), message); + } else { + listener.onMatchDeclined(leaderCid, getMatchCharacters(), message); + } + } + + private void dispatchMatchDismissed() { + listener.onMatchDismissed(leaderCid, getMatchCharacters(), message); + } + } + + private void unpoolMatchPlayer(Integer cid) { + unpoolMatchPlayers(Collections.singleton(cid)); + } + + private void unpoolMatchPlayers(Set matchPlayers) { + for (Integer cid : matchPlayers) { + pooledCids.remove(cid); + } + } + + private boolean poolMatchPlayer(Integer cid) { + return poolMatchPlayers(Collections.singleton(cid)); + } + + private boolean poolMatchPlayers(Set matchPlayers) { + Set pooledPlayers = new HashSet<>(); + + for (Integer cid : matchPlayers) { + if (!pooledCids.add(cid)) { + unpoolMatchPlayers(pooledPlayers); + return false; + } else { + pooledPlayers.add(cid); + } + } + + return true; + } + + private boolean isMatchingAvailable(Set matchPlayers) { + for (Integer cid : matchPlayers) { + if (matchEntries.containsKey(cid)) { + return false; + } + } + + return true; + } + + public int getMatchConfirmationLeaderid(int cid) { + MapleMatchCheckingElement mmce = matchEntries.get(cid); + if (mmce != null) { + return mmce.leaderCid; + } else { + return -1; + } + } + + public MatchCheckerType getMatchConfirmationType(int cid) { + MapleMatchCheckingElement mmce = matchEntries.get(cid); + if (mmce != null) { + return mmce.matchType; + } else { + return null; + } + } + + private void createMatchConfirmationInternal(MatchCheckerType matchType, int world, int leaderCid, AbstractMatchCheckerListener leaderListener, Set players, String message) { + MapleMatchCheckingElement mmce = new MapleMatchCheckingElement(matchType, leaderCid, world, leaderListener, players, message); + + for (Integer cid : players) { + matchEntries.put(cid, mmce); + } + + mmce.dispatchMatchCreated(); + + if (mmce.acceptEntry(leaderCid)) { + acceptMatchElement(mmce, leaderCid); + } + } + + public boolean createMatchConfirmation(MatchCheckerType matchType, int world, int leaderCid, Set players, String message) { + try { + semaphorePool.acquire(); + try { + if (poolMatchPlayers(players)) { + try { + if (isMatchingAvailable(players)) { + AbstractMatchCheckerListener leaderListener = matchType.getListener(); + createMatchConfirmationInternal(matchType, world, leaderCid, leaderListener, players, message); + return true; + } + } finally { + unpoolMatchPlayers(players); + } + } + } finally { + semaphorePool.release(); + } + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + return false; + } + + private void disposeMatchElement(MapleMatchCheckingElement mmce) { + Set matchPlayers = mmce.getMatchPlayers(); + while (!poolMatchPlayers(matchPlayers)) { + try { + Thread.sleep(1000); + } catch (InterruptedException ie) {} + } + + try { + for (Integer cid : matchPlayers) { + matchEntries.remove(cid); + } + } finally { + unpoolMatchPlayers(matchPlayers); + } + } + + private void acceptMatchElement(MapleMatchCheckingElement mmce, int cid) { + if (mmce.acceptEntry(cid)) { + unpoolMatchPlayer(cid); + disposeMatchElement(mmce); + + mmce.dispatchMatchResult(true); + } + } + + private void denyMatchElement(MapleMatchCheckingElement mmce, int cid) { + unpoolMatchPlayer(cid); + disposeMatchElement(mmce); + + mmce.dispatchMatchResult(false); + } + + private void dismissMatchElement(MapleMatchCheckingElement mmce, int cid) { + unpoolMatchPlayer(cid); + disposeMatchElement(mmce); + + mmce.dispatchMatchDismissed(); + } + + public boolean answerMatchConfirmation(int cid, boolean accept) { + try { + semaphorePool.acquire(); + try { + while (matchEntries.containsKey(cid)) { + if (poolMatchPlayer(cid)) { + try { + MapleMatchCheckingElement mmce = matchEntries.get(cid); + + if (mmce != null) { + if (accept) { + acceptMatchElement(mmce, cid); + } else { + denyMatchElement(mmce, cid); + } + + return true; + } + } finally { + unpoolMatchPlayer(cid); + } + } + } + } finally { + semaphorePool.release(); + } + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + return false; + } + + public boolean dismissMatchConfirmation(int cid) { + try { + semaphorePool.acquire(); + try { + while (matchEntries.containsKey(cid)) { + if (poolMatchPlayer(cid)) { + try { + MapleMatchCheckingElement mmce = matchEntries.get(cid); + + if (mmce != null) { + dismissMatchElement(mmce, cid); + return true; + } + } finally { + unpoolMatchPlayer(cid); + } + } + } + } finally { + semaphorePool.release(); + } + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + + return false; + } + +} diff --git a/src/net/server/coordinator/MapleSessionCoordinator.java b/src/net/server/coordinator/MapleSessionCoordinator.java index 234f684512..048a3f77fd 100644 --- a/src/net/server/coordinator/MapleSessionCoordinator.java +++ b/src/net/server/coordinator/MapleSessionCoordinator.java @@ -19,6 +19,7 @@ */ package net.server.coordinator; +import client.MapleCharacter; import client.MapleClient; import constants.ServerConstants; @@ -28,7 +29,6 @@ import net.server.audit.locks.factory.MonitoredReentrantLockFactory; import org.apache.mina.core.session.IoSession; import tools.DatabaseConnection; -import java.net.InetSocketAddress; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -220,8 +220,8 @@ public class MapleSessionCoordinator { return poolLock.get(Math.abs(remoteHost.hashCode()) % 100); } - private static String getRemoteIp(IoSession session) { - return ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress(); + public static String getSessionRemoteAddress(IoSession session) { + return (String) session.getAttribute(MapleClient.CLIENT_REMOTE_ADDRESS); } private static MapleClient getSessionClient(IoSession session) { @@ -245,7 +245,7 @@ public class MapleSessionCoordinator { public boolean canStartLoginSession(IoSession session) { if (!ServerConstants.DETERRED_MULTICLIENT) return true; - String remoteHost = getRemoteIp(session); + String remoteHost = getSessionRemoteAddress(session); Lock lock = getCoodinatorLock(remoteHost); try { @@ -305,7 +305,7 @@ public class MapleSessionCoordinator { } public void closeLoginSession(IoSession session) { - String remoteIp = getRemoteIp(session); + String remoteIp = getSessionRemoteAddress(session); Set lrh = loginRemoteHosts.get(remoteIp); if (lrh != null) { lrh.remove(session); @@ -336,7 +336,7 @@ public class MapleSessionCoordinator { return AntiMulticlientResult.SUCCESS; } - String remoteHost = getRemoteIp(session); + String remoteHost = getSessionRemoteAddress(session); Lock lock = getCoodinatorLock(remoteHost); try { @@ -402,7 +402,7 @@ public class MapleSessionCoordinator { } public AntiMulticlientResult attemptGameSession(IoSession session, int accountId, String remoteHwid) { - String remoteHost = getRemoteIp(session); + String remoteHost = getSessionRemoteAddress(session); if (!ServerConstants.DETERRED_MULTICLIENT) { associateRemoteHostHwid(remoteHost, remoteHwid); return AntiMulticlientResult.SUCCESS; @@ -472,14 +472,47 @@ public class MapleSessionCoordinator { } } + private static MapleClient fetchInTransitionSessionClient(IoSession session) { + String remoteHwid = MapleSessionCoordinator.getInstance().getGameSessionHwid(session); + + if (remoteHwid != null) { // maybe this session was currently in-transition? + int hwidLen = remoteHwid.length(); + if (hwidLen <= 8) { + session.setAttribute(MapleClient.CLIENT_NIBBLEHWID, remoteHwid); + } else { + session.setAttribute(MapleClient.CLIENT_HWID, remoteHwid); + session.setAttribute(MapleClient.CLIENT_NIBBLEHWID, remoteHwid.substring(hwidLen - 8, hwidLen)); + } + + MapleClient client = new MapleClient(null, null, session); + Integer cid = Server.getInstance().freeCharacteridInTransition(session); + if (cid != null) { + try { + client.setAccID(MapleCharacter.loadCharFromDB(cid, client, false).getAccountID()); + } catch (SQLException sqle) { + sqle.printStackTrace(); + } + } + + session.setAttribute(MapleClient.CLIENT_KEY, client); + return client; + } + + return null; + } + public void closeSession(IoSession session, Boolean immediately) { + MapleClient client = getSessionClient(session); + if (client == null) { + client = fetchInTransitionSessionClient(session); + } + String hwid = (String) session.removeAttribute(MapleClient.CLIENT_NIBBLEHWID); // making sure to clean up calls to this function on login phase onlineRemoteHwids.remove(hwid); hwid = (String) session.removeAttribute(MapleClient.CLIENT_HWID); onlineRemoteHwids.remove(hwid); - MapleClient client = getSessionClient(session); if (client != null) { if (hwid != null) { // is a game session onlineClients.remove(client.getAccID()); @@ -496,10 +529,12 @@ public class MapleSessionCoordinator { if (immediately != null) { session.close(immediately); } + + // session.removeAttribute(MapleClient.CLIENT_REMOTE_ADDRESS); No real need for removing String property on closed sessions } public String getGameSessionHwid(IoSession session) { - String remoteHost = getRemoteIp(session); + String remoteHost = getSessionRemoteAddress(session); return cachedHostHwids.get(remoteHost); } diff --git a/src/net/server/coordinator/matchchecker/AbstractMatchCheckerListener.java b/src/net/server/coordinator/matchchecker/AbstractMatchCheckerListener.java new file mode 100644 index 0000000000..f8fde0d921 --- /dev/null +++ b/src/net/server/coordinator/matchchecker/AbstractMatchCheckerListener.java @@ -0,0 +1,34 @@ +/* + 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.coordinator.matchchecker; + +import client.MapleCharacter; +import java.util.Set; + +/** + * + * @author Ronan + */ +public interface AbstractMatchCheckerListener { + public void onMatchCreated(MapleCharacter leader, Set nonLeaderMatchPlayers, String message); + public void onMatchAccepted(int leaderid, Set matchPlayers, String message); + public void onMatchDeclined(int leaderid, Set matchPlayers, String message); + public void onMatchDismissed(int leaderid, Set matchPlayers, String message); +} diff --git a/src/net/server/coordinator/matchchecker/MatchCheckerListenerFactory.java b/src/net/server/coordinator/matchchecker/MatchCheckerListenerFactory.java new file mode 100644 index 0000000000..648ab081b7 --- /dev/null +++ b/src/net/server/coordinator/matchchecker/MatchCheckerListenerFactory.java @@ -0,0 +1,45 @@ +/* + 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.coordinator.matchchecker; + +import net.server.coordinator.matchchecker.listener.MatchCheckerGuildCreation; + +/** + * + * @author Ronan + */ +public class MatchCheckerListenerFactory { + + public enum MatchCheckerType { + + GUILD_CREATION(MatchCheckerGuildCreation.loadListener()); + + private final AbstractMatchCheckerListener listener; + + private MatchCheckerType(AbstractMatchCheckerListener listener) { + this.listener = listener; + } + + public AbstractMatchCheckerListener getListener() { + return this.listener; + } + } + +} diff --git a/src/net/server/coordinator/matchchecker/MatchCheckerListenerRecipe.java b/src/net/server/coordinator/matchchecker/MatchCheckerListenerRecipe.java new file mode 100644 index 0000000000..18ee1d27ae --- /dev/null +++ b/src/net/server/coordinator/matchchecker/MatchCheckerListenerRecipe.java @@ -0,0 +1,28 @@ +/* + 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.coordinator.matchchecker; + +/** + * + * @author Ronan + */ +public interface MatchCheckerListenerRecipe { + public AbstractMatchCheckerListener getListener(); +} diff --git a/src/net/server/coordinator/matchchecker/listener/MatchCheckerGuildCreation.java b/src/net/server/coordinator/matchchecker/listener/MatchCheckerGuildCreation.java new file mode 100644 index 0000000000..49f52a4b3b --- /dev/null +++ b/src/net/server/coordinator/matchchecker/listener/MatchCheckerGuildCreation.java @@ -0,0 +1,181 @@ +/* + 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.coordinator.matchchecker.listener; + +import client.MapleCharacter; +import constants.GameConstants; +import constants.ServerConstants; +import net.server.coordinator.matchchecker.AbstractMatchCheckerListener; +import net.server.coordinator.matchchecker.MatchCheckerListenerRecipe; +import net.server.guild.MapleGuild; +import net.server.guild.MapleGuildCharacter; +import java.util.Set; +import net.server.Server; +import net.server.world.MapleParty; +import tools.MaplePacketCreator; + +/** + * + * @author Ronan + */ +public class MatchCheckerGuildCreation implements MatchCheckerListenerRecipe { + + private static void broadcastGuildCreationDismiss(Set nonLeaderMatchPlayers) { + for (MapleCharacter chr : nonLeaderMatchPlayers) { + if (chr.isLoggedinWorld()) { + chr.announce(MaplePacketCreator.genericGuildMessage((byte) 0x26)); + } + } + } + + public static AbstractMatchCheckerListener loadListener() { + return (new MatchCheckerGuildCreation()).getListener(); + } + + @Override + public AbstractMatchCheckerListener getListener() { + return new AbstractMatchCheckerListener() { + + @Override + public void onMatchCreated(MapleCharacter leader, Set nonLeaderMatchPlayers, String message) { + byte[] createGuildPacket = MaplePacketCreator.createGuildMessage(leader.getName(), message); + + for (MapleCharacter chr : nonLeaderMatchPlayers) { + if (chr.isLoggedinWorld()) { + chr.announce(createGuildPacket); + } + } + } + + @Override + public void onMatchAccepted(int leaderid, Set matchPlayers, String message) { + MapleCharacter leader = null; + for (MapleCharacter chr : matchPlayers) { + if (chr.getId() == leaderid) { + leader = chr; + break; + } + } + + if (leader == null || !leader.isLoggedinWorld()) { + broadcastGuildCreationDismiss(matchPlayers); + return; + } + matchPlayers.remove(leader); + + if (leader.getGuildId() > 0) { + leader.dropMessage(1, "You cannot create a new Guild while in one."); + broadcastGuildCreationDismiss(matchPlayers); + return; + } + int partyid = leader.getPartyId(); + if (partyid == -1 || !leader.isPartyLeader()) { + leader.dropMessage(1, "You cannot establish the creation of a new Guild without leading a party."); + broadcastGuildCreationDismiss(matchPlayers); + return; + } + if (leader.getMapId() != 200000301) { + leader.dropMessage(1, "You cannot establish the creation of a new Guild outside of the Guild Headquarters."); + broadcastGuildCreationDismiss(matchPlayers); + return; + } + for (MapleCharacter chr : matchPlayers) { + if (leader.getMap().getCharacterById(chr.getId()) == null) { + leader.dropMessage(1, "You cannot establish the creation of a new Guild if one of the members is not present here."); + broadcastGuildCreationDismiss(matchPlayers); + return; + } + } + if (leader.getMeso() < ServerConstants.CREATE_GUILD_COST) { + leader.dropMessage(1, "You do not have " + GameConstants.numberWithCommas(ServerConstants.CREATE_GUILD_COST) + " mesos to create a Guild."); + broadcastGuildCreationDismiss(matchPlayers); + return; + } + + int gid = Server.getInstance().createGuild(leader.getId(), message); + if (gid == 0) { + leader.announce(MaplePacketCreator.genericGuildMessage((byte) 0x23)); + broadcastGuildCreationDismiss(matchPlayers); + return; + } + leader.gainMeso(-ServerConstants.CREATE_GUILD_COST, true, false, true); + + leader.getMGC().setGuildId(gid); + MapleGuild guild = Server.getInstance().getGuild(leader.getGuildId(), leader.getWorld(), leader); // initialize guild structure + Server.getInstance().changeRank(gid, leader.getId(), 1); + + leader.announce(MaplePacketCreator.showGuildInfo(leader)); + leader.dropMessage(1, "You have successfully created a Guild."); + + for (MapleCharacter chr : matchPlayers) { + boolean cofounder = chr.getPartyId() == partyid; + + MapleGuildCharacter mgc = chr.getMGC(); + mgc.setGuildId(gid); + mgc.setGuildRank(cofounder ? 2 : 5); + mgc.setAllianceRank(5); + + Server.getInstance().addGuildMember(mgc, chr); + + if (chr.isLoggedinWorld()) { + chr.announce(MaplePacketCreator.showGuildInfo(chr)); + + if (cofounder) { + chr.dropMessage(1, "You have successfully cofounded a Guild."); + } else { + chr.dropMessage(1, "You have successfully joined the new Guild."); + } + } + + chr.saveGuildStatus(); // update database + } + + guild.broadcastNameChanged(); + guild.broadcastEmblemChanged(); + } + + @Override + public void onMatchDeclined(int leaderid, Set matchPlayers, String message) { + for (MapleCharacter chr : matchPlayers) { + if (chr.getId() == leaderid && chr.getClient() != null) { + MapleParty.leaveParty(chr.getParty(), chr.getClient()); + } + + if (chr.isLoggedinWorld()) { + chr.announce(MaplePacketCreator.genericGuildMessage((byte)0x24)); + } + } + } + + @Override + public void onMatchDismissed(int leaderid, Set matchPlayers, String message) { + for (MapleCharacter chr : matchPlayers) { + if (chr.getId() == leaderid && chr.getClient() != null) { + MapleParty.leaveParty(chr.getParty(), chr.getClient()); + } + + if (chr.isLoggedinWorld()) { + chr.message("All cofounders must not be in a party when performing the Guild creation."); + } + } + } + }; + } +} diff --git a/src/net/server/guild/MapleAlliance.java b/src/net/server/guild/MapleAlliance.java index 91c4a78517..947b6c62e0 100644 --- a/src/net/server/guild/MapleAlliance.java +++ b/src/net/server/guild/MapleAlliance.java @@ -57,7 +57,7 @@ public class MapleAlliance { public MapleAlliance(String name, int id) { this.name = name; allianceId = id; - String[] ranks = {"Master", "Jr.Master", "Member", "Member", "Member"}; + String[] ranks = {"Master", "Jr. Master", "Member", "Member", "Member"}; for (int i = 0; i < 5; i++) { rankTitles[i] = ranks[i]; } diff --git a/src/net/server/guild/MapleGuild.java b/src/net/server/guild/MapleGuild.java index 8fccd15f41..3c614d74bd 100644 --- a/src/net/server/guild/MapleGuild.java +++ b/src/net/server/guild/MapleGuild.java @@ -34,6 +34,7 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.HashSet; import java.util.Set; import java.util.concurrent.locks.Lock; @@ -746,7 +747,20 @@ public class MapleGuild { } return false; } - + + public static Set getEligiblePlayersForGuild(MapleCharacter guildLeader) { + Set guildMembers = new HashSet<>(); + guildMembers.add(guildLeader); + + for (MapleCharacter chr : guildLeader.getMap().getAllPlayers()) { + if (chr.getParty() == null && chr.getGuild() == null) { + guildMembers.add(chr); + } + } + + return guildMembers; + } + public static void displayGuildRanks(MapleClient c, int npcid) { try { ResultSet rs; diff --git a/src/net/server/handlers/login/CharSelectedHandler.java b/src/net/server/handlers/login/CharSelectedHandler.java index 505e61ec39..b5e7ba5d48 100644 --- a/src/net/server/handlers/login/CharSelectedHandler.java +++ b/src/net/server/handlers/login/CharSelectedHandler.java @@ -23,7 +23,6 @@ package net.server.handlers.login; import client.MapleClient; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; @@ -103,7 +102,7 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler { server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - server.setCharacteridInTransition((InetSocketAddress) session.getRemoteAddress(), charId); + server.setCharacteridInTransition(session, charId); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); diff --git a/src/net/server/handlers/login/CharSelectedWithPicHandler.java b/src/net/server/handlers/login/CharSelectedWithPicHandler.java index 8017e4967b..0a505747ff 100644 --- a/src/net/server/handlers/login/CharSelectedWithPicHandler.java +++ b/src/net/server/handlers/login/CharSelectedWithPicHandler.java @@ -1,7 +1,6 @@ package net.server.handlers.login; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; @@ -85,7 +84,7 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler { server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); + server.setCharacteridInTransition(session, charId); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); diff --git a/src/net/server/handlers/login/LoginPasswordHandler.java b/src/net/server/handlers/login/LoginPasswordHandler.java index edfb2b65e9..8692faaf1e 100644 --- a/src/net/server/handlers/login/LoginPasswordHandler.java +++ b/src/net/server/handlers/login/LoginPasswordHandler.java @@ -38,9 +38,9 @@ import client.MapleClient; import java.sql.ResultSet; import java.sql.Statement; import java.io.UnsupportedEncodingException; -import java.net.InetSocketAddress; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import net.server.coordinator.MapleSessionCoordinator; import org.apache.mina.core.session.IoSession; public final class LoginPasswordHandler implements MaplePacketHandler { @@ -57,15 +57,22 @@ public final class LoginPasswordHandler implements MaplePacketHandler { } private static String getRemoteIp(IoSession session) { - return ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress(); + return MapleSessionCoordinator.getSessionRemoteAddress(session); } @Override public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { String remoteHost = getRemoteIp(c.getSession()); - if (remoteHost.startsWith("127.") && !ServerConstants.HOST.startsWith("127.")) { - c.announce(MaplePacketCreator.getLoginFailed(13)); // cannot login as localhost if it's not a test server - return; + if (remoteHost.startsWith("127.")) { + if (!ServerConstants.LOCALSERVER) { // thanks Mills for noting HOST can also have a field named "localhost" + c.announce(MaplePacketCreator.getLoginFailed(13)); // cannot login as localhost if it's not a local server + return; + } + } else { + if (ServerConstants.LOCALSERVER) { + c.announce(MaplePacketCreator.getLoginFailed(13)); // cannot login as non-localhost if it's a local server + return; + } } String login = slea.readMapleAsciiString(); diff --git a/src/net/server/handlers/login/RegisterPicHandler.java b/src/net/server/handlers/login/RegisterPicHandler.java index c8fd76f349..ed76cee00d 100644 --- a/src/net/server/handlers/login/RegisterPicHandler.java +++ b/src/net/server/handlers/login/RegisterPicHandler.java @@ -9,7 +9,6 @@ import net.server.world.World; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; import client.MapleClient; -import java.net.InetSocketAddress; import net.server.coordinator.MapleSessionCoordinator; import net.server.coordinator.MapleSessionCoordinator.AntiMulticlientResult; import org.apache.mina.core.session.IoSession; @@ -88,7 +87,7 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler { server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); + server.setCharacteridInTransition(session, charId); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); diff --git a/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java b/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java index 5d2c13a500..b308b8ad3c 100644 --- a/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java +++ b/src/net/server/handlers/login/ViewAllCharRegisterPicHandler.java @@ -2,11 +2,11 @@ package net.server.handlers.login; import client.MapleClient; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; import net.server.coordinator.MapleSessionCoordinator; +import net.server.coordinator.MapleSessionCoordinator.AntiMulticlientResult; import net.server.world.World; import org.apache.mina.core.session.IoSession; import tools.MaplePacketCreator; @@ -15,7 +15,7 @@ import tools.data.input.SeekableLittleEndianAccessor; public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHandler { - private static int parseAntiMulticlientError(MapleSessionCoordinator.AntiMulticlientResult res) { + private static int parseAntiMulticlientError(AntiMulticlientResult res) { switch (res) { case REMOTE_PROCESSING: return 10; @@ -57,8 +57,8 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand } IoSession session = c.getSession(); - MapleSessionCoordinator.AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptGameSession(session, c.getAccID(), hwid); - if (res != MapleSessionCoordinator.AntiMulticlientResult.SUCCESS) { + AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptGameSession(session, c.getAccID(), hwid); + if (res != AntiMulticlientResult.SUCCESS) { c.announce(MaplePacketCreator.getAfterLoginError(parseAntiMulticlientError(res))); return; } @@ -90,7 +90,7 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); + server.setCharacteridInTransition(session, charId); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); diff --git a/src/net/server/handlers/login/ViewAllCharSelectedHandler.java b/src/net/server/handlers/login/ViewAllCharSelectedHandler.java index 050a0419f4..66dae5c4ad 100644 --- a/src/net/server/handlers/login/ViewAllCharSelectedHandler.java +++ b/src/net/server/handlers/login/ViewAllCharSelectedHandler.java @@ -23,11 +23,11 @@ package net.server.handlers.login; import client.MapleClient; import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.UnknownHostException; import net.AbstractMaplePacketHandler; import net.server.Server; import net.server.coordinator.MapleSessionCoordinator; +import net.server.coordinator.MapleSessionCoordinator.AntiMulticlientResult; import net.server.world.World; import org.apache.mina.core.session.IoSession; import tools.MaplePacketCreator; @@ -36,7 +36,7 @@ import tools.data.input.SeekableLittleEndianAccessor; public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler { - private static int parseAntiMulticlientError(MapleSessionCoordinator.AntiMulticlientResult res) { + private static int parseAntiMulticlientError(AntiMulticlientResult res) { switch (res) { case REMOTE_PROCESSING: return 10; @@ -77,8 +77,8 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler } IoSession session = c.getSession(); - MapleSessionCoordinator.AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptGameSession(session, c.getAccID(), hwid); - if (res != MapleSessionCoordinator.AntiMulticlientResult.SUCCESS) { + AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptGameSession(session, c.getAccID(), hwid); + if (res != AntiMulticlientResult.SUCCESS) { c.announce(MaplePacketCreator.getAfterLoginError(parseAntiMulticlientError(res))); return; } @@ -113,7 +113,7 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); + server.setCharacteridInTransition(session, charId); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); diff --git a/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java b/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java index 391c4fd7ef..ace134cb3b 100644 --- a/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java +++ b/src/net/server/handlers/login/ViewAllCharSelectedWithPicHandler.java @@ -10,13 +10,13 @@ import tools.MaplePacketCreator; import tools.Randomizer; import tools.data.input.SeekableLittleEndianAccessor; import client.MapleClient; -import java.net.InetSocketAddress; import net.server.coordinator.MapleSessionCoordinator; +import net.server.coordinator.MapleSessionCoordinator.AntiMulticlientResult; import org.apache.mina.core.session.IoSession; public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandler { - private static int parseAntiMulticlientError(MapleSessionCoordinator.AntiMulticlientResult res) { + private static int parseAntiMulticlientError(AntiMulticlientResult res) { switch (res) { case REMOTE_PROCESSING: return 10; @@ -59,8 +59,8 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle } IoSession session = c.getSession(); - MapleSessionCoordinator.AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptGameSession(session, c.getAccID(), hwid); - if (res != MapleSessionCoordinator.AntiMulticlientResult.SUCCESS) { + AntiMulticlientResult res = MapleSessionCoordinator.getInstance().attemptGameSession(session, c.getAccID(), hwid); + if (res != AntiMulticlientResult.SUCCESS) { c.announce(MaplePacketCreator.getAfterLoginError(parseAntiMulticlientError(res))); return; } @@ -90,7 +90,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle server.unregisterLoginState(c); c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION); - server.setCharacteridInTransition((InetSocketAddress) c.getSession().getRemoteAddress(), charId); + server.setCharacteridInTransition(session, charId); try { c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId)); diff --git a/src/net/server/world/MapleParty.java b/src/net/server/world/MapleParty.java index a3f155d8cc..fa9724a979 100644 --- a/src/net/server/world/MapleParty.java +++ b/src/net/server/world/MapleParty.java @@ -21,7 +21,9 @@ */ package net.server.world; +import client.MapleCharacter; import client.MapleClient; +import constants.ServerConstants; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; @@ -34,7 +36,13 @@ 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 net.server.coordinator.MapleMatchCheckerCoordinator; +import net.server.coordinator.matchchecker.MatchCheckerListenerFactory.MatchCheckerType; +import scripting.event.EventInstanceManager; import server.maps.MapleDoor; +import server.maps.MapleMap; +import server.partyquest.MonsterCarnival; +import tools.MaplePacketCreator; public class MapleParty { @@ -315,4 +323,152 @@ public class MapleParty { } return true; } + + public static boolean createParty(MapleCharacter player, boolean silentCheck) { + MapleParty party = player.getParty(); + if (party == null) { + if(player.getLevel() < 10 && !ServerConstants.USE_PARTY_FOR_STARTERS) { + player.announce(MaplePacketCreator.partyStatusMessage(10)); + return false; + } + + MaplePartyCharacter partyplayer = new MaplePartyCharacter(player); + party = player.getWorldServer().createParty(partyplayer); + player.setParty(party); + player.setMPC(partyplayer); + player.getMap().addPartyMember(player); + player.silentPartyUpdate(); + + player.partyOperationUpdate(party, null); + player.announce(MaplePacketCreator.partyCreated(party, partyplayer.getId())); + + return true; + } else { + if (!silentCheck) { + player.announce(MaplePacketCreator.partyStatusMessage(16)); + } + + return false; + } + } + + public static boolean joinParty(MapleCharacter player, int partyid, boolean silentCheck) { + MapleParty party = player.getParty(); + World world = player.getWorldServer(); + + if (party == null) { + party = world.getParty(partyid); + if (party != null) { + if (party.getMembers().size() < 6) { + MaplePartyCharacter partyplayer = new MaplePartyCharacter(player); + player.getMap().addPartyMember(player); + + world.updateParty(party.getId(), PartyOperation.JOIN, partyplayer); + player.receivePartyMemberHP(); + player.updatePartyMemberHP(); + + player.partyOperationUpdate(party, null); + return true; + } else { + if (!silentCheck) { + player.announce(MaplePacketCreator.partyStatusMessage(17)); + } + } + } else { + player.announce(MaplePacketCreator.serverNotice(5, "You couldn't join the party since it had already been disbanded.")); + } + } else { + if (!silentCheck) { + player.announce(MaplePacketCreator.serverNotice(5, "You can't join the party as you are already in one.")); + } + } + + return false; + } + + public static void leaveParty(MapleParty party, MapleClient c) { + World world = c.getWorldServer(); + MapleCharacter player = c.getPlayer(); + MaplePartyCharacter partyplayer = player.getMPC(); + + if (party != null && partyplayer != null) { + if (partyplayer.getId() == party.getLeaderId()) { + c.getWorldServer().removeMapPartyMembers(party.getId()); + + MonsterCarnival mcpq = player.getMonsterCarnival(); + if (mcpq != null) { + mcpq.leftParty(player.getId()); + } + + world.updateParty(party.getId(), PartyOperation.DISBAND, partyplayer); + + EventInstanceManager eim = player.getEventInstance(); + if(eim != null) { + eim.disbandParty(); + } + } else { + MapleMap map = player.getMap(); + if (map != null) { + map.removePartyMember(player); + } + + MonsterCarnival mcpq = player.getMonsterCarnival(); + if (mcpq != null) { + mcpq.leftParty(player.getId()); + } + + world.updateParty(party.getId(), PartyOperation.LEAVE, partyplayer); + + EventInstanceManager eim = player.getEventInstance(); + if(eim != null) { + eim.leftParty(player); + } + } + + player.setParty(null); + + MapleMatchCheckerCoordinator mmce = c.getWorldServer().getMatchCheckerCoordinator(); + if (mmce.getMatchConfirmationLeaderid(player.getId()) == player.getId() && mmce.getMatchConfirmationType(player.getId()) == MatchCheckerType.GUILD_CREATION) { + mmce.dismissMatchConfirmation(player.getId()); + } + } + } + + public static void expelFromParty(MapleParty party, MapleClient c, int expelCid) { + World world = c.getWorldServer(); + MapleCharacter player = c.getPlayer(); + MaplePartyCharacter partyplayer = player.getMPC(); + + if (party != null && partyplayer != null) { + if (partyplayer.equals(party.getLeader())) { + MaplePartyCharacter expelled = party.getMemberById(expelCid); + if (expelled != null) { + MapleCharacter emc = expelled.getPlayer(); + if(emc != null) { + List partyMembers = emc.getPartyMembers(); + + MapleMap map = emc.getMap(); + if(map != null) map.removePartyMember(emc); + + MonsterCarnival mcpq = player.getMonsterCarnival(); + if (mcpq != null) { + mcpq.leftParty(emc.getId()); + } + + EventInstanceManager eim = emc.getEventInstance(); + if(eim != null) { + eim.leftParty(emc); + } + + emc.setParty(null); + world.updateParty(party.getId(), PartyOperation.EXPEL, expelled); + + emc.partyOperationUpdate(party, partyMembers); + } else { + world.updateParty(party.getId(), PartyOperation.EXPEL, expelled); + } + } + } + } + } } diff --git a/src/net/server/world/MaplePartyCharacter.java b/src/net/server/world/MaplePartyCharacter.java index 4fd23306cf..2d0f677925 100644 --- a/src/net/server/world/MaplePartyCharacter.java +++ b/src/net/server/world/MaplePartyCharacter.java @@ -142,99 +142,4 @@ public class MaplePartyCharacter { return world; } - public String getJobNameById(int job) { - switch (job) { - case 0: - return "Aprendiz"; - case 100: - return "Guerreiro";// Warrior - case 110: - return "Soldado"; - case 111: - return "Templario"; - case 112: - return "Heroi"; - case 120: - return "Escudeiro"; - case 121: - return "Cavaleiro Branco"; - case 122: - return "Paladino"; - case 130: - return "Lanceiro"; - case 131: - return "Cavaleiro Draconiano"; - case 132: - return "Cavaleiro Negro"; - - case 200: - return "Bruxo"; - case 210: - return "Feiticeiro (Fogo, Veneno)"; - case 211: - return "Mago (Fogo, Veneno)"; - case 212: - return "Arquimago (Fogo, Veneno)"; - case 220: - return "Feiticeiro (Gelo, Raio)"; - case 221: - return "Mago (Gelo, Raio)"; - case 222: - return "Arquimago (Gelo, Raio)"; - case 230: - return "Clerigo"; - case 231: - return "Sacerdote"; - case 232: - return "Sumo Sacerdote"; - - case 300: - return "Arqueiro"; - case 310: - return "Cacador"; - case 311: - return "Rastreador"; - case 312: - return "Mestre Arqueiro"; - case 320: - return "Balestreiro"; - case 321: - return "Atirador"; - case 322: - return "Atirador De Elite"; - - case 400: - return "Gatuno"; - case 410: - return "Mercenario"; - case 411: - return "Andarilho"; - case 412: - return "Lorde Negro"; - case 420: - return "Arruaceiro"; - case 421: - return "Mestre Arruaceiro"; - case 422: - return "Mestre Das Sombras"; - - case 500: - return "Pirata"; - case 510: - return "Lutador"; - case 511: - return "Saqueador"; - case 512: - return "Foragido"; - case 520: - return "Pistoleiro"; - case 521: - return "Bucaneiro"; - case 522: - return "Capitao"; - - default: - return "Unknown Job"; - } - } } diff --git a/src/net/server/world/World.java b/src/net/server/world/World.java index 062282a6a1..b4fef1e337 100644 --- a/src/net/server/world/World.java +++ b/src/net/server/world/World.java @@ -85,6 +85,7 @@ import net.server.guild.MapleGuildSummary; import tools.DatabaseConnection; import tools.MaplePacketCreator; import tools.Pair; +import tools.packets.Fishing; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.MonitoredReentrantLock; import net.server.audit.locks.MonitoredReentrantReadWriteLock; @@ -92,7 +93,7 @@ import net.server.audit.locks.factory.MonitoredReentrantLockFactory; import net.server.coordinator.MapleInviteCoordinator; import net.server.coordinator.MapleInviteCoordinator.InviteResult; import net.server.coordinator.MapleInviteCoordinator.InviteType; -import tools.packets.Fishing; +import net.server.coordinator.MapleMatchCheckerCoordinator; /** * @@ -113,6 +114,7 @@ public class World { private Map> relationshipCouples = new HashMap<>(); private Map gsStore = new HashMap<>(); private PlayerStorage players = new PlayerStorage(); + private MapleMatchCheckerCoordinator matchChecker = new MapleMatchCheckerCoordinator(); private final ReentrantReadWriteLock chnLock = new MonitoredReentrantReadWriteLock(MonitoredLockType.WORLD_CHANNELS, true); private ReadLock chnRLock = chnLock.readLock(); @@ -488,6 +490,10 @@ public class World { public PlayerStorage getPlayerStorage() { return players; } + + public MapleMatchCheckerCoordinator getMatchCheckerCoordinator() { + return matchChecker; + } public void addPlayer(MapleCharacter chr) { players.addPlayer(chr); @@ -1267,7 +1273,15 @@ public class World { private List>> getBoughtCashItems() { if (ServerConstants.USE_ENFORCE_ITEM_SUGGESTION) { - return new ArrayList<>(0); + List>> boughtCounts = new ArrayList<>(9); + + // thanks GabrielSin for pointing out an issue here + for (int i = 0; i < 9; i++) { + List> tabCounts = new ArrayList<>(0); + boughtCounts.add(tabCounts); + } + + return boughtCounts; } suggestRLock.lock(); diff --git a/src/scripting/npc/NPCConversationManager.java b/src/scripting/npc/NPCConversationManager.java index 76a6741a3a..267b83352c 100644 --- a/src/scripting/npc/NPCConversationManager.java +++ b/src/scripting/npc/NPCConversationManager.java @@ -57,6 +57,7 @@ import client.SkillFactory; import client.inventory.Item; import client.inventory.ItemFactory; import client.inventory.MaplePet; +import constants.GameConstants; import constants.ItemConstants; import constants.LanguageConstants; import net.server.PlayerStorage; @@ -400,8 +401,8 @@ public class NPCConversationManager extends AbstractPlayerInteraction { getPlayer().changeJob(job); } - public MapleJob getJobName(int id) { - return MapleJob.getById(id); + public String getJobName(int id) { + return GameConstants.getJobName(id); } public MapleStatEffect getItemEffect(int itemId) { @@ -617,7 +618,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction { } // By Drago/Dragohe4rt CPQ + WED - public int calcAvgLvl(int map) { + public int cpqCalcAvgLvl(int map) { int num = 0; int avg = 0; for (MapleMapObject mmo : c.getChannelServer().getMapFactory().getMap(map).getAllPlayer()) { @@ -628,30 +629,38 @@ public class NPCConversationManager extends AbstractPlayerInteraction { return avg; } - public void sendCPQMapLists() { - String msg = LanguageConstants.Linguas(getPlayer()).CPQInicioEscolha; + public boolean sendCPQMapLists() { + String msg = LanguageConstants.Languages(getPlayer()).CPQPickRoom; + int msgLen = msg.length(); for (int i = 0; i < 6; i++) { if (fieldTaken(i)) { if (fieldLobbied(i)) { - msg += "#b#L" + i + "#Map " + (i + 1) + " (nível: " - + calcAvgLvl(980000100 + i * 100) + " / " + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (Level: " // "Carnival field" GMS-like improvement thanks to Jayd + + cpqCalcAvgLvl(980000100 + i * 100) + " / " + getPlayerCount(980000100 + i * 100) + "x" - + getPlayerCount(980000100 + i * 100) + ") #l\\r\\n"; - } else { - continue; + + getPlayerCount(980000100 + i * 100) + ") #l\r\n"; } } else { if (i >= 0 && i <= 3) { - msg += "#b#L" + i + "#Map " + (i + 1) + " (2x2) #l\\r\\n"; + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (2x2) #l\r\n"; } else { - msg += "#b#L" + i + "#Map " + (i + 1) + " (3x3) #l\\r\\n"; + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (3x3) #l\r\n"; } } } - sendSimple(msg); + + if (msg.length() > msgLen) { + sendSimple(msg); + return true; + } else { + return false; + } } public boolean fieldTaken(int field) { + if (!c.getChannelServer().canInitMonsterCarnival(true, field)) { + return true; + } if (!c.getChannelServer().getMapFactory().getMap(980000100 + field * 100).getAllPlayer().isEmpty()) { return true; } @@ -684,7 +693,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction { mc = ps.getCharacterById(mpc.getId()); if (mc != null) { mc.changeMap(map, map.getPortal(0)); - mc.announce(MaplePacketCreator.serverNotice(6, LanguageConstants.Linguas(mc).CPQEntradaLobby)); + mc.announce(MaplePacketCreator.serverNotice(6, LanguageConstants.Languages(mc).CPQEntryLobby)); TimerManager tMan = TimerManager.getInstance(); tMan.schedule(new Runnable() { @Override @@ -710,7 +719,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction { return c.getChannelServer().getPlayerStorage().getCharacterById(id); } - public void cancelarSaida() { + public void cancelCPQLobby() { PlayerStorage ps = c.getChannelServer().getPlayerStorage(); for (MaplePartyCharacter mpc : c.getPlayer().getParty().getMembers()) { MapleCharacter mc = ps.getCharacterById(mpc.getId()); @@ -719,10 +728,21 @@ public class NPCConversationManager extends AbstractPlayerInteraction { } } } + + private void warpoutCPQLobby() { + MapleMap lobbyMap = c.getPlayer().getMap(); + MapleMap out = this.getWarpMap((lobbyMap.getId() > 980030000) ? 980000000 : 980030000); + for (MapleCharacter mc : lobbyMap.getAllPlayers()) { + mc.resetCP(); + mc.setTeam(-1); + mc.setMonsterCarnival(null); + mc.changeMap(out, out.getPortal(0)); + } + } public void startCPQ(final MapleCharacter challenger, final int field) { try { - cancelarSaida(); + cancelCPQLobby(); if (challenger != null) { if (challenger.getParty() == null) { throw new RuntimeException("Nao existe oponente!"); @@ -759,14 +779,19 @@ public class NPCConversationManager extends AbstractPlayerInteraction { tMan.schedule(new Runnable() { @Override public void run() { - PlayerStorage ps = c.getChannelServer().getPlayerStorage(); - for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { - MapleCharacter mc = ps.getCharacterById(mpc.getId()); - mc.setMonsterCarnival(null); - } - for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { - MapleCharacter mc = ps.getCharacterById(mpc.getId()); - mc.setMonsterCarnival(null); + try { + PlayerStorage ps = c.getChannelServer().getPlayerStorage(); + for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { + MapleCharacter mc = ps.getCharacterById(mpc.getId()); + mc.setMonsterCarnival(null); + } + for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { + MapleCharacter mc = ps.getCharacterById(mpc.getId()); + mc.setMonsterCarnival(null); + } + } catch (NullPointerException npe) { + warpoutCPQLobby(); + return; } new MonsterCarnival(getPlayer().getParty(), challenger.getParty(), mapid, true, (field / 100) % 10); @@ -779,7 +804,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction { public void startCPQ2(final MapleCharacter challenger, final int field) { try { - cancelarSaida(); + cancelCPQLobby(); if (challenger != null) { if (challenger.getParty() == null) { throw new RuntimeException("Não existe oponente!"); @@ -798,15 +823,19 @@ public class NPCConversationManager extends AbstractPlayerInteraction { tMan.schedule(new Runnable() { @Override public void run() { - PlayerStorage ps = c.getChannelServer().getPlayerStorage(); - - for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { - MapleCharacter mc = ps.getCharacterById(mpc.getId()); - mc.setMonsterCarnival(null); - } - for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { - MapleCharacter mc = ps.getCharacterById(mpc.getId()); - mc.setMonsterCarnival(null); + try { + PlayerStorage ps = c.getChannelServer().getPlayerStorage(); + for (MaplePartyCharacter mpc : getPlayer().getParty().getMembers()) { + MapleCharacter mc = ps.getCharacterById(mpc.getId()); + mc.setMonsterCarnival(null); + } + for (MaplePartyCharacter mpc : challenger.getParty().getMembers()) { + MapleCharacter mc = ps.getCharacterById(mpc.getId()); + mc.setMonsterCarnival(null); + } + } catch (NullPointerException npe) { + warpoutCPQLobby(); + return; } new MonsterCarnival(getPlayer().getParty(), challenger.getParty(), mapid, false, (field / 1000) % 10); @@ -817,35 +846,45 @@ public class NPCConversationManager extends AbstractPlayerInteraction { } } - public void sendCPQMapLists2() { - String msg = LanguageConstants.Linguas(getPlayer()).CPQInicioEscolha; + public boolean sendCPQMapLists2() { + String msg = LanguageConstants.Languages(getPlayer()).CPQPickRoom; + int msgLen = msg.length(); for (int i = 0; i < 3; i++) { if (fieldTaken2(i)) { if (fieldLobbied2(i)) { - msg += "#b#L" + i + "#Map " + (i + 1) + " (Nível: " - + calcAvgLvl(980031000 + i * 1000) + "#l\\r\\n"; - } else { - continue; + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (Level: " // "Carnival field" GMS-like improvement thanks to Jayd + + cpqCalcAvgLvl(980031000 + i * 1000) + " / " + + getPlayerCount(980031000 + i * 1000) + "x" + + getPlayerCount(980031000 + i * 1000) + ") #l\r\n"; } } else { if (i == 0 || i == 1) { - msg += "#b#L" + i + "#Map " + (i + 1) + " (2x2) #l\\r\\n"; + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (2x2) #l\r\n"; } else { - msg += "#b#L" + i + "#Map " + (i + 1) + " (3x3) #l\\r\\n"; + msg += "#b#L" + i + "#Carnival Field " + (i + 1) + " (3x3) #l\r\n"; } } } - sendSimple(msg); + + if (msg.length() > msgLen) { + sendSimple(msg); + return true; + } else { + return false; + } } public boolean fieldTaken2(int field) { - if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { + if (!c.getChannelServer().canInitMonsterCarnival(false, field)) { return true; } if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { return true; } - if (!c.getChannelServer().getMapFactory().getMap(980031000 + field * 1000).getAllPlayer().isEmpty()) { + if (!c.getChannelServer().getMapFactory().getMap(980031100 + field * 1000).getAllPlayer().isEmpty()) { + return true; + } + if (!c.getChannelServer().getMapFactory().getMap(980031200 + field * 1000).getAllPlayer().isEmpty()) { return true; } return false; @@ -868,10 +907,10 @@ public class NPCConversationManager extends AbstractPlayerInteraction { map = cs.getMapFactory().getMap(980031000 + 1000 * field); for (MaplePartyCharacter mpc : c.getPlayer().getParty().getMembers()) { final MapleCharacter mc; - mc = ps.getCharacterByName(mpc.getName()); + mc = ps.getCharacterById(mpc.getId()); if (mc != null) { mc.changeMap(map, map.getPortal(0)); - mc.announce(MaplePacketCreator.serverNotice(6, LanguageConstants.Linguas(mc).CPQEntradaLobby)); + mc.announce(MaplePacketCreator.serverNotice(6, LanguageConstants.Languages(mc).CPQEntryLobby)); TimerManager tMan = TimerManager.getInstance(); tMan.schedule(new Runnable() { @Override @@ -899,7 +938,7 @@ public class NPCConversationManager extends AbstractPlayerInteraction { for (MapleMapObject mmo : map.getAllPlayer()) { MapleCharacter mc = (MapleCharacter) mmo; if (mc.getParty() == null) { - sendOk(LanguageConstants.Linguas(mc).CPQEscolha); + sendOk(LanguageConstants.Languages(mc).CPQFindError); return; } if (mc.getParty().getLeader().getId() == mc.getId()) { @@ -915,10 +954,10 @@ public class NPCConversationManager extends AbstractPlayerInteraction { } NPCScriptManager.getInstance().start("cpqchallenge2", leader.getClient(), npc, members); } else { - sendOk(LanguageConstants.Linguas(leader).CPQInicioEscolhaEmEscolha); + sendOk(LanguageConstants.Languages(leader).CPQChallengeRoomAnswer); } } else { - sendOk(LanguageConstants.Linguas(leader).CPQLiderNaoEncontrado); + sendOk(LanguageConstants.Languages(leader).CPQLeaderNotFound); } } @@ -930,13 +969,13 @@ public class NPCConversationManager extends AbstractPlayerInteraction { MapleCharacter leader = null; MapleMap map = c.getChannelServer().getMapFactory().getMap(980000100 + 100 * field); if (map.getAllPlayer().size() != getPlayer().getParty().getMembers().size()) { - sendOk("erro"); + sendOk("An unexpected error regarding the other party has occurred."); return; } for (MapleMapObject mmo : map.getAllPlayer()) { MapleCharacter mc = (MapleCharacter) mmo; if (mc.getParty() == null) { - sendOk(LanguageConstants.Linguas(mc).CPQEscolha); + sendOk(LanguageConstants.Languages(mc).CPQFindError); return; } if (mc.getParty().getLeader().getId() == mc.getId()) { @@ -952,23 +991,15 @@ public class NPCConversationManager extends AbstractPlayerInteraction { } NPCScriptManager.getInstance().start("cpqchallenge", leader.getClient(), npc, members); - sendOk(LanguageConstants.Linguas(leader).CPQInicioEscolhaEnviada); + sendOk(LanguageConstants.Languages(leader).CPQChallengeRoomSent); } else { - sendOk(LanguageConstants.Linguas(leader).CPQInicioEscolhaEmEscolha); + sendOk(LanguageConstants.Languages(leader).CPQChallengeRoomAnswer); } } else { - sendOk(LanguageConstants.Linguas(leader).CPQLiderNaoEncontrado); + sendOk(LanguageConstants.Languages(leader).CPQLeaderNotFound); } } - - public MapleCharacter getCharByName(String namee) { - try { - return getClient().getChannelServer().getPlayerStorage().getCharacterByName(namee); - } catch (Exception e) { - return null; - } - } - + public void sendMarriageWishlist(boolean groom) { MapleCharacter player = this.getPlayer(); MapleMarriage marriage = player.getMarriageInstance(); diff --git a/src/server/MapleItemInformationProvider.java b/src/server/MapleItemInformationProvider.java index ccbf21cf57..0ce3949a28 100644 --- a/src/server/MapleItemInformationProvider.java +++ b/src/server/MapleItemInformationProvider.java @@ -1657,7 +1657,7 @@ public class MapleItemInformationProvider { if (!EquipSlot.getFromTextSlot(islot).isAllowed(dst, isCash(id))) { equip.wear(false); String itemName = MapleItemInformationProvider.getInstance().getName(equip.getItemId()); - Server.getInstance().broadcastGMMessage(chr.getWorld(), MaplePacketCreator.sendYellowTip("[WARNING]: " + chr.getName() + " tried to equip " + itemName + " into slot " + dst + ".")); + Server.getInstance().broadcastGMMessage(chr.getWorld(), MaplePacketCreator.sendYellowTip("[Warning]: " + chr.getName() + " tried to equip " + itemName + " into slot " + dst + ".")); AutobanFactory.PACKET_EDIT.alert(chr, chr.getName() + " tried to forcibly equip an item."); FilePrinter.printError(FilePrinter.EXPLOITS + chr.getName() + ".txt", chr.getName() + " tried to equip " + itemName + " into " + dst + " slot."); return false; diff --git a/src/server/MapleMarriage.java b/src/server/MapleMarriage.java index 69c7853091..5d75c62040 100644 --- a/src/server/MapleMarriage.java +++ b/src/server/MapleMarriage.java @@ -69,15 +69,18 @@ public class MapleMarriage extends EventInstanceManager { } public List getGiftItems(MapleClient c, boolean groom) { - c.tryacquireClient(); - try { - List gifts = getGiftItemsList(groom); - synchronized (gifts) { - return new LinkedList<>(gifts); + if (c.tryacquireClient()) { + try { + List gifts = getGiftItemsList(groom); + synchronized (gifts) { + return new LinkedList<>(gifts); + } + } finally { + c.releaseClient(); } - } finally { - c.releaseClient(); } + + return new LinkedList<>(); } private List getGiftItemsList(boolean groom) { @@ -140,21 +143,22 @@ public class MapleMarriage extends EventInstanceManager { } public static List loadGiftItemsFromDb(MapleClient c, int cid) { - c.tryacquireClient(); - try { - List items = new LinkedList<>(); + List items = new LinkedList<>(); + if (c.tryacquireClient()) { try { - for (Pair it : ItemFactory.MARRIAGE_GIFTS.loadItems(cid, false)) { - items.add(it.getLeft()); + try { + for (Pair it : ItemFactory.MARRIAGE_GIFTS.loadItems(cid, false)) { + items.add(it.getLeft()); + } + } catch (SQLException sqle) { + sqle.printStackTrace(); } - } catch (SQLException sqle) { - sqle.printStackTrace(); + } finally { + c.releaseClient(); } - - return items; - } finally { - c.releaseClient(); } + + return items; } public void saveGiftItemsToDb(MapleClient c, boolean groom, int cid) { @@ -167,17 +171,18 @@ public class MapleMarriage extends EventInstanceManager { items.add(new Pair<>(it, it.getInventoryType())); } - c.tryacquireClient(); - try { + if (c.tryacquireClient()) { try { - Connection con = DatabaseConnection.getConnection(); - ItemFactory.MARRIAGE_GIFTS.saveItems(items, cid, con); - con.close(); - } catch (SQLException sqle) { - sqle.printStackTrace(); + try { + Connection con = DatabaseConnection.getConnection(); + ItemFactory.MARRIAGE_GIFTS.saveItems(items, cid, con); + con.close(); + } catch (SQLException sqle) { + sqle.printStackTrace(); + } + } finally { + c.releaseClient(); } - } finally { - c.releaseClient(); } } } diff --git a/src/server/MapleStatEffect.java b/src/server/MapleStatEffect.java index 3acf762f62..8b5591062e 100644 --- a/src/server/MapleStatEffect.java +++ b/src/server/MapleStatEffect.java @@ -944,13 +944,26 @@ public class MapleStatEffect { if (skill != null) { final MapleDisease dis = skill.getDisease(); MapleParty opposition = applyfrom.getParty().getEnemy(); - for (MaplePartyCharacter enemyChrs : opposition.getPartyMembers()) { - MapleCharacter chrApp = enemyChrs.getPlayer(); + if (skill.targetsAll) { + for (MaplePartyCharacter enemyChrs : opposition.getPartyMembers()) { + MapleCharacter chrApp = enemyChrs.getPlayer(); + if (chrApp != null && chrApp.getMap().isCPQMap()) { + if (dis == null) { + chrApp.dispel(); + } else { + chrApp.giveDebuff(dis, MCSkill.getMobSkill(dis.getDisease(), skill.level)); + } + } + } + } else { + int amount = opposition.getMembers().size() - 1; + int randd = (int) Math.floor(Math.random() * amount); + MapleCharacter chrApp = applyfrom.getMap().getCharacterById(opposition.getMemberByPos(randd).getId()); if (chrApp != null && chrApp.getMap().isCPQMap()) { if (dis == null) { chrApp.dispel(); } else { - chrApp.giveDebuff(dis, MCSkill.getMobSkill(dis.getDisease())); + chrApp.giveDebuff(dis, MCSkill.getMobSkill(dis.getDisease(), skill.level)); } } } diff --git a/src/server/MapleTrade.java b/src/server/MapleTrade.java index 13a096f8b2..bba71f378e 100644 --- a/src/server/MapleTrade.java +++ b/src/server/MapleTrade.java @@ -83,7 +83,7 @@ public class MapleTrade { this.number = number; } - private static int getFee(long meso) { + public static int getFee(long meso) { long fee = 0; if (meso >= 100000000) { fee = (meso * 6) / 100; @@ -179,7 +179,7 @@ public class MapleTrade { throw new RuntimeException("Trade is locked."); } if (meso < 0) { - System.out.println("[h4x] " + chr.getName() + " Trying to trade < 0 mesos"); + System.out.println("[Hack] " + chr.getName() + " Trying to trade < 0 mesos"); return; } if (chr.getMeso() >= meso) { @@ -372,12 +372,30 @@ public class MapleTrade { chr.setTrade(null); } + private static byte[] tradeResultsPair(byte result) { + byte selfResult, partnerResult; + + if (result == TradeResult.PARTNER_CANCEL.getValue()) { + partnerResult = result; + selfResult = TradeResult.NO_RESPONSE.getValue(); + } else if (result == TradeResult.UNSUCCESSFUL_UNIQUE_ITEM_LIMIT.getValue()) { + partnerResult = TradeResult.UNSUCCESSFUL.getValue(); + selfResult = result; + } else { + partnerResult = result; + selfResult = result; + } + + return new byte[]{selfResult, partnerResult}; + } + private synchronized void tradeCancelHandshake(boolean updateSelf, byte result) { byte selfResult, partnerResult; MapleTrade self; - partnerResult = result; - selfResult = (result == TradeResult.PARTNER_CANCEL.getValue() ? TradeResult.NO_RESPONSE.getValue() : result); + byte[] pairedResult = tradeResultsPair(result); + selfResult = pairedResult[0]; + partnerResult = pairedResult[1]; if (updateSelf) { self = this; diff --git a/src/server/life/MapleMonster.java b/src/server/life/MapleMonster.java index dc98c71dc2..7aa48eb766 100644 --- a/src/server/life/MapleMonster.java +++ b/src/server/life/MapleMonster.java @@ -127,9 +127,9 @@ public class MapleMonster extends AbstractLoadedMapleLife { externalLock.unlock(); } - private void initWithStats(MapleMonsterStats stats) { + private void initWithStats(MapleMonsterStats baseStats) { setStance(5); - this.stats = stats; + this.stats = baseStats.copy(); hp.set(stats.getHp()); mp = stats.getMp(); @@ -223,7 +223,8 @@ public class MapleMonster extends AbstractLoadedMapleLife { this.hp.addAndGet(hp); } - public void setStartingHp(int hp) { + public synchronized void setStartingHp(int hp) { + stats.setHp(hp); // refactored mob stats after non-static HP pool suggestion thanks to twigs this.hp.set(hp); } diff --git a/src/server/life/MapleMonsterStats.java b/src/server/life/MapleMonsterStats.java index bc97e2794c..bf8073b4ab 100644 --- a/src/server/life/MapleMonsterStats.java +++ b/src/server/life/MapleMonsterStats.java @@ -21,6 +21,7 @@ */ package server.life; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -36,20 +37,20 @@ import tools.Pair; * @author Frz */ public class MapleMonsterStats { - private boolean changeable; - private int exp, hp, mp, level, PADamage, PDDamage, MADamage, MDDamage, dropPeriod, cp, buffToGive = -1, removeAfter; - private boolean boss, undead, ffaLoot, isExplosiveReward, firstAttack, removeOnMiss; - private String name; - private Map animationTimes = new HashMap(); - private Map resistance = new HashMap(); - private List revives = Collections.emptyList(); - private byte tagColor, tagBgColor; - private List> skills = new ArrayList>(); - private Pair cool = null; - private BanishInfo banish = null; - private List loseItem = null; - private selfDestruction selfDestruction = null; - private boolean friendly; + public boolean changeable; + public int exp, hp, mp, level, PADamage, PDDamage, MADamage, MDDamage, dropPeriod, cp, buffToGive = -1, removeAfter; + public boolean boss, undead, ffaLoot, isExplosiveReward, firstAttack, removeOnMiss; + public String name; + public Map animationTimes = new HashMap(); + public Map resistance = new HashMap(); + public List revives = Collections.emptyList(); + public byte tagColor, tagBgColor; + public List> skills = new ArrayList>(); + public Pair cool = null; + public BanishInfo banish = null; + public List loseItem = null; + public selfDestruction selfDestruction = null; + public boolean friendly; public void setChange(boolean change) { this.changeable = change; @@ -337,4 +338,40 @@ public class MapleMonsterStats { public void setMDDamage(int MDDamage) { this.MDDamage = MDDamage; } + + public MapleMonsterStats copy() { + MapleMonsterStats copy = new MapleMonsterStats(); + try { + FieldCopyUtil.setFields(this, copy); + } catch (Exception e) { + e.printStackTrace(); + try { + Thread.sleep(10000); + } catch (Exception ex) { + + } + + } + + return copy; + } + + // FieldCopyUtil src: http://www.codesenior.com/en/tutorial/Java-Copy-Fields-From-One-Object-to-Another-Object-with-Reflection + private static class FieldCopyUtil { // thanks to Codesenior dev team + private static void setFields(Object from, Object to) { + Field[] fields = from.getClass().getDeclaredFields(); + for (Field field : fields) { + try { + Field fieldFrom = from.getClass().getDeclaredField(field.getName()); + Object value = fieldFrom.get(from); + to.getClass().getDeclaredField(field.getName()).set(to, value); + + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + } + } + } } diff --git a/src/server/maps/MapleHiredMerchant.java b/src/server/maps/MapleHiredMerchant.java index 0fca0338c7..06853f45e8 100644 --- a/src/server/maps/MapleHiredMerchant.java +++ b/src/server/maps/MapleHiredMerchant.java @@ -48,6 +48,7 @@ import tools.DatabaseConnection; import tools.MaplePacketCreator; import tools.Pair; import net.server.audit.locks.MonitoredLockType; +import server.MapleTrade; /** * @@ -274,6 +275,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject { if (c.getPlayer().getMeso() >= price) { if (canBuy(c, newItem)) { c.getPlayer().gainMeso(-price, false); + price -= MapleTrade.getFee(price); // thanks BHB for pointing out trade fees not applying here synchronized (sold) { sold.add(new SoldItem(c.getPlayer().getName(), pItem.getItem().getItemId(), newItem.getQuantity(), price)); diff --git a/src/server/maps/MapleMap.java b/src/server/maps/MapleMap.java index c912ce82f9..5bac4baeb6 100644 --- a/src/server/maps/MapleMap.java +++ b/src/server/maps/MapleMap.java @@ -1264,19 +1264,19 @@ public class MapleMap { } public void broadcastBalrogVictory(String leaderName) { - getWorldServer().dropMessage(6, "[VICTORY] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive."); + getWorldServer().dropMessage(6, "[Victory] " + leaderName + "'s party has successfully defeated the Balrog! Praise to them, they finished with " + countAlivePlayers() + " players alive."); } public void broadcastHorntailVictory() { - getWorldServer().dropMessage(6, "[VICTORY] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!"); + getWorldServer().dropMessage(6, "[Victory] To the crew that have finally conquered Horned Tail after numerous attempts, I salute thee! You are the true heroes of Leafre!!"); } public void broadcastZakumVictory() { - getWorldServer().dropMessage(6, "[VICTORY] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!"); + getWorldServer().dropMessage(6, "[Victory] At last, the tree of evil that for so long overwhelmed Ossyria has fallen. To the crew that managed to finally conquer Zakum, after numerous attempts, victory! You are the true heroes of Ossyria!!"); } public void broadcastPinkBeanVictory(int channel) { - getWorldServer().dropMessage(6, "[VICTORY] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!"); + getWorldServer().dropMessage(6, "[Victory] In a swift stroke of sorts, the crew that has attempted Pink Bean at channel " + channel + " has ultimately defeated it. The Temple of Time shines radiantly once again, the day finally coming back, as the crew that managed to finally conquer it returns victoriously from the battlefield!!"); } private boolean removeKilledMonsterObject(MapleMonster monster) { @@ -1893,7 +1893,7 @@ public class MapleMap { public void spawnAllMonsterIdFromMapSpawnList(int id, int difficulty, boolean isPq) { for(SpawnPoint sp: getAllMonsterSpawn()) { - if(sp.getMonsterId() == id) { + if(sp.getMonsterId() == id && sp.shouldForceSpawn()) { spawnMonster(sp.getMonster(), difficulty, isPq); } } @@ -2079,7 +2079,7 @@ public class MapleMap { 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); + FilePrinter.printError(FilePrinter.EXCEPTION, "[Door] " + mapName + "(" + mapid + ") does not contain door portalid " + doorid); return portals.get(0x80); } @@ -4334,10 +4334,10 @@ public class MapleMap { if (team == 0 && redTeamBuffs.size() >= 4 || team == 1 && blueTeamBuffs.size() >= 4) { return 2; } - final MCSkill skil = MapleCarnivalFactory.getInstance().getGuardian(num); - if (team == 0 && redTeamBuffs.contains(skil)) { + final MCSkill skill = MapleCarnivalFactory.getInstance().getGuardian(num); + if (team == 0 && redTeamBuffs.contains(skill)) { return 0; - } else if (team == 1 && blueTeamBuffs.contains(skil)) { + } else if (team == 1 && blueTeamBuffs.contains(skill)) { return 0; } GuardianSpawnPoint pt = this.getRandomGuardianSpawn(team); @@ -4352,7 +4352,7 @@ public class MapleMap { reactor.resetReactorActions(0); this.spawnReactor(reactor); reactor.setGuardian(pt); - this.buffMonsters(team, skil); + this.buffMonsters(team, skill); getReactorByOid(reactor.getObjectId()).hitReactor(((MapleCharacter) this.getAllPlayer().get(0)).getClient()); } catch (Exception e) { e.printStackTrace(); @@ -4360,21 +4360,20 @@ public class MapleMap { return 1; } - public void buffMonsters(int team, MCSkill skil) { + public void buffMonsters(int team, MCSkill skill) { + if (skill == null) return; + if (team == 0) { - redTeamBuffs.add(skil); + redTeamBuffs.add(skill); } else if (team == 1) { - blueTeamBuffs.add(skil); + blueTeamBuffs.add(skill); } for (MapleMapObject mmo : this.mapobjects.values()) { if (mmo.getType() == MapleMapObjectType.MONSTER) { MapleMonster mob = (MapleMonster) mmo; if (mob.getTeam() == team) { - if (skil != null) { - skil.getSkill().applyEffect(null, mob, false, null); - } + skill.getSkill().applyEffect(null, mob, false, null); } - } } } diff --git a/src/server/maps/MaplePlayerShop.java b/src/server/maps/MaplePlayerShop.java index 43ba5746f9..ed3ba67bc7 100644 --- a/src/server/maps/MaplePlayerShop.java +++ b/src/server/maps/MaplePlayerShop.java @@ -42,6 +42,7 @@ import tools.Pair; import tools.data.output.MaplePacketLittleEndianWriter; import net.server.audit.locks.MonitoredLockType; import net.server.audit.locks.factory.MonitoredReentrantLockFactory; +import server.MapleTrade; /** * @@ -279,6 +280,7 @@ public class MaplePlayerShop extends AbstractMapleMapObject { } c.getPlayer().gainMeso(-price, false); + price -= MapleTrade.getFee(price); // thanks BHB for pointing out trade fees not applying here owner.gainMeso(price, true); SoldItem soldItem = new SoldItem(c.getPlayer().getName(), pItem.getItem().getItemId(), quantity, price); diff --git a/src/server/partyquest/MapleCarnivalFactory.java b/src/server/partyquest/MapleCarnivalFactory.java index 81483bcd81..7f006f1714 100644 --- a/src/server/partyquest/MapleCarnivalFactory.java +++ b/src/server/partyquest/MapleCarnivalFactory.java @@ -2,7 +2,9 @@ package server.partyquest; import client.MapleDisease; import java.io.File; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import server.life.MobSkillFactory; import provider.MapleDataProvider; @@ -20,6 +22,9 @@ public class MapleCarnivalFactory { private final Map skills = new HashMap(); private final Map guardians = new HashMap(); private final MapleDataProvider dataRoot = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Skill.wz")); + + private final List singleTargetedSkills = new ArrayList<>(); + private final List multiTargetedSkills = new ArrayList<>(); public MapleCarnivalFactory() { //whoosh @@ -35,15 +40,36 @@ public class MapleCarnivalFactory { return; } for (MapleData z : dataRoot.getData("MCSkill.img")) { - skills.put(Integer.parseInt(z.getName()), new MCSkill(MapleDataTool.getInt("spendCP", z, 0), MapleDataTool.getInt("mobSkillID", z, 0), MapleDataTool.getInt("level", z, 0), MapleDataTool.getInt("target", z, 1) > 1)); + Integer id = Integer.parseInt(z.getName()); + MCSkill ms = new MCSkill(MapleDataTool.getInt("spendCP", z, 0), MapleDataTool.getInt("mobSkillID", z, 0), MapleDataTool.getInt("level", z, 0), MapleDataTool.getInt("target", z, 1) > 1); + + skills.put(id, ms); + if (ms.targetsAll) { + multiTargetedSkills.add(id); + } else { + singleTargetedSkills.add(id); + } } for (MapleData z : dataRoot.getData("MCGuardian.img")) { guardians.put(Integer.parseInt(z.getName()), new MCSkill(MapleDataTool.getInt("spendCP", z, 0), MapleDataTool.getInt("mobSkillID", z, 0), MapleDataTool.getInt("level", z, 0), true)); } } + private MCSkill randomizeSkill(boolean multi) { + if (multi) { + return skills.get(multiTargetedSkills.get((int) (Math.random() * multiTargetedSkills.size()))); + } else { + return skills.get(multiTargetedSkills.get((int) (Math.random() * multiTargetedSkills.size()))); + } + } + public MCSkill getSkill(final int id) { - return skills.get(id); + MCSkill skill = skills.get(id); + if (skill != null && skill.skillid <= 0) { + return randomizeSkill(skill.targetsAll); + } else { + return skill; + } } public MCSkill getGuardian(final int id) { @@ -63,17 +89,14 @@ public class MapleCarnivalFactory { } public MobSkill getSkill() { - return getMobSkill(skillid); + return getMobSkill(skillid, level); } - public static MobSkill getMobSkill(int skillid) { - return MobSkillFactory.getMobSkill(skillid, 1); //level? + public static MobSkill getMobSkill(int skillid, int level) { + return MobSkillFactory.getMobSkill(skillid, level); } public MapleDisease getDisease() { - if (skillid <= 0) { - return MapleDisease.getRandom(); - } return MapleDisease.getBySkill(skillid); } } diff --git a/src/server/partyquest/MonsterCarnival.java b/src/server/partyquest/MonsterCarnival.java index e310a0aeb5..26bff2ec17 100644 --- a/src/server/partyquest/MonsterCarnival.java +++ b/src/server/partyquest/MonsterCarnival.java @@ -29,7 +29,7 @@ public class MonsterCarnival { private long startTime = 0; private int summonsR = 8, summonsB = 8, room = 0; private MapleCharacter leader1, leader2, Grupo1, Grupo2; - private int redCP, blueCP, redTotalCP, blueTotalCP; + private int redCP, blueCP, redTotalCP, blueTotalCP, redTimeupCP, blueTimeupCP; private boolean cpq1; public MonsterCarnival(MapleParty p1, MapleParty p2, int mapid, boolean cpq1, int room) { @@ -42,6 +42,7 @@ public class MonsterCarnival { p1.setEnemy(p2); p2.setEnemy(p1); map = cs.getMapFactory().getDisposableMap(mapid); + startTime = System.currentTimeMillis() + 10 * 60 * 1000; int redPortal = 0; int bluePortal = 0; if (map.isPurpleCPQMap()) { @@ -55,7 +56,7 @@ public class MonsterCarnival { mc.setTeam(0); mc.setFestivalPoints(0); mc.forceChangeMap(map, map.getPortal(redPortal)); - mc.dropMessage(6, LanguageConstants.Linguas(mc).CPQEntrada); + mc.dropMessage(6, LanguageConstants.Languages(mc).CPQEntry); if (p1.getLeader().getId() == mc.getId()) { leader1 = mc; } @@ -69,7 +70,7 @@ public class MonsterCarnival { mc.setTeam(1); mc.setFestivalPoints(0); mc.forceChangeMap(map, map.getPortal(bluePortal)); - mc.dropMessage(6, LanguageConstants.Linguas(mc).CPQEntrada); + mc.dropMessage(6, LanguageConstants.Languages(mc).CPQEntry); if (p2.getLeader().getId() == mc.getId()) { leader2 = mc; } @@ -78,16 +79,16 @@ public class MonsterCarnival { } if (Grupo1 == null || Grupo2 == null) { for (MaplePartyCharacter mpc : p2.getMembers()) { - mpc.getPlayer().dropMessage(5, LanguageConstants.Linguas(mpc.getPlayer()).CPQErro); + mpc.getPlayer().dropMessage(5, LanguageConstants.Languages(mpc.getPlayer()).CPQError); } for (MaplePartyCharacter mpc : p2.getMembers()) { - mpc.getPlayer().dropMessage(5, LanguageConstants.Linguas(mpc.getPlayer()).CPQErro); + mpc.getPlayer().dropMessage(5, LanguageConstants.Languages(mpc.getPlayer()).CPQError); } return; } - Grupo1.getClient().announce(MaplePacketCreator.startMonsterCarnival(Grupo1, 0, 1)); - Grupo2.getClient().announce(MaplePacketCreator.startMonsterCarnival(Grupo2, 1, 0)); - startTime = System.currentTimeMillis() + 60 * 10000; + + // thanks Atoot, Vcoc for noting double CPQ functional being sent to players in CPQ start + timer = TimerManager.getInstance().schedule(new Runnable() { @Override public void run() { @@ -106,12 +107,8 @@ public class MonsterCarnival { respawn(); } }, ServerConstants.RESPAWN_INTERVAL); - TimerManager.getInstance().schedule(new Runnable() { - @Override - public void run() { - map.addClock(60 * 10); - } - }, 2000); + + cs.initMonsterCarnival(cpq1, room); } catch (Exception e) { e.printStackTrace(); } @@ -140,18 +137,18 @@ public class MonsterCarnival { String teamS = ""; switch (team) { case 0: - teamS = LanguageConstants.Linguas(chrMap).CPQVermelho; + teamS = LanguageConstants.Languages(chrMap).CPQRed; break; case 1: - teamS = LanguageConstants.Linguas(chrMap).CPQAzul; + teamS = LanguageConstants.Languages(chrMap).CPQBlue; break; } - chrMap.dropMessage(5, teamS + LanguageConstants.Linguas(chrMap).CPQPlayerExit); + chrMap.dropMessage(5, teamS + LanguageConstants.Languages(chrMap).CPQPlayerExit); } earlyFinish(); } - public void earlyFinish() { + private void earlyFinish() { dispose(true); } @@ -180,12 +177,12 @@ public class MonsterCarnival { } protected void dispose(boolean warpout) { - Channel cs = Server.getInstance().getWorld(p1.getLeader().getWorld()).getChannel(p1.getLeader().getChannel()); + Channel cs = map.getChannelServer(); MapleMap out; if (!cpq1) { // cpq2 - out = cs.getMapFactory().getMap(980030000); + out = cs.getMapFactory().getMap(980030010); } else { - out = cs.getMapFactory().getMap(980000000); + out = cs.getMapFactory().getMap(980000010); } for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { MapleCharacter mc = cs.getPlayerStorage().getCharacterById(mpc.getId()); @@ -227,7 +224,8 @@ public class MonsterCarnival { leader2.getParty().setEnemy(null); map.dispose(); map = null; - + + cs.finishMonsterCarnival(cpq1, room); } public void exit() { @@ -238,9 +236,9 @@ public class MonsterCarnival { return this.timer; } - public void finish(int winningTeam) { + private void finish(int winningTeam) { try { - Channel cs = Server.getInstance().getWorld(p1.getLeader().getWorld()).getChannel(p1.getLeader().getChannel()); + Channel cs = map.getChannelServer(); if (winningTeam == 0) { for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { MapleCharacter mc = cs.getPlayerStorage().getCharacterById(mpc.getId()); @@ -306,9 +304,9 @@ public class MonsterCarnival { } } - public void timeUp() { - int cp1 = this.redTotalCP; - int cp2 = this.blueTotalCP; + private void timeUp() { + int cp1 = this.redTimeupCP; + int cp2 = this.blueTimeupCP; if (cp1 == cp2) { extendTime(); return; @@ -328,11 +326,11 @@ public class MonsterCarnival { return (int) (getTimeLeft() / 1000); } - public void extendTime() { + private void extendTime() { for (MapleCharacter chrMap : map.getAllPlayers()) { - chrMap.dropMessage(5, LanguageConstants.Linguas(chrMap).CPQTempoExtendido); + chrMap.dropMessage(5, LanguageConstants.Languages(chrMap).CPQExtendTime); } - startTime = System.currentTimeMillis() + 3 * 1000; + startTime = System.currentTimeMillis() + 3 * 60 * 1000; map.addClock(3 * 60); timer = TimerManager.getInstance().schedule(new Runnable() { @Override @@ -345,12 +343,16 @@ public class MonsterCarnival { public void run() { complete(); } - }, 3 * 60 * 1000 - 10); + }, 3 * 60 * 1000 - 10 * 1000); // thanks Vcoc for noticing a time set issue here } public void complete() { int cp1 = this.redTotalCP; int cp2 = this.blueTotalCP; + + this.redTimeupCP = cp1; + this.blueTimeupCP = cp2; + if (cp1 == cp2) { return; } @@ -361,7 +363,7 @@ public class MonsterCarnival { throw new RuntimeException("Os lideres estao em canais diferentes."); } - Channel cs = Server.getInstance().getWorld(p1.getLeader().getWorld()).getChannel(p1.getLeader().getChannel()); + Channel cs = map.getChannelServer(); map.killAllMonsters(); for (MaplePartyCharacter mpc : leader1.getParty().getMembers()) { MapleCharacter mc; @@ -508,4 +510,8 @@ public class MonsterCarnival { public int getRoom() { return this.room; } + + public MapleMap getEventMap() { + return this.map; + } } diff --git a/src/tools/MaplePacketCreator.java b/src/tools/MaplePacketCreator.java index 6be1f9ca81..2ffeaf616c 100644 --- a/src/tools/MaplePacketCreator.java +++ b/src/tools/MaplePacketCreator.java @@ -4212,8 +4212,8 @@ public class MaplePacketCreator { mplew.writeInt(reactor.getId()); mplew.write(reactor.getState()); mplew.writePos(pos); - mplew.writeShort(0); mplew.write(0); + mplew.writeShort(0); return mplew.getPacket(); } @@ -4225,8 +4225,8 @@ public class MaplePacketCreator { mplew.writeInt(reactor.getObjectId()); mplew.write(reactor.getState()); mplew.writePos(pos); - mplew.writeShort(stance); - mplew.write(0); + mplew.write(stance); + mplew.writeShort(0); mplew.write(5); // frame delay, set to 5 since there doesn't appear to be a fixed formula for it return mplew.getPacket(); } @@ -4387,7 +4387,17 @@ public class MaplePacketCreator { mplew.writeMapleAsciiString(charName); return mplew.getPacket(); } - + + public static byte[] createGuildMessage(String masterName, String guildName) { + final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); + mplew.writeShort(SendOpcode.GUILD_OPERATION.getValue()); + mplew.write(0x3); + mplew.writeInt(0); + mplew.writeMapleAsciiString(masterName); + mplew.writeMapleAsciiString(guildName); + return mplew.getPacket(); + } + /** * Gets a Heracle/guild message packet. * diff --git a/src/tools/packets/Fishing.java b/src/tools/packets/Fishing.java index b7d1c7c90a..672215c05e 100644 --- a/src/tools/packets/Fishing.java +++ b/src/tools/packets/Fishing.java @@ -125,9 +125,9 @@ public class Fishing { public static int getRandomItem(){ int rand = (int)(100.0 * Math.random()); - int[] commons = {1002851, 2002020, 2002020, 2000006, 2000018, 2002018, 2002024, 2002027, 2002027, 2000018, 2000018, 2000018 , 2000018, 2002030, 2002018, 2000016}; // filler' up + int[] commons = {1002851, 2002020, 2002020, 2000006, 2000018, 2002018, 2002024, 2002027, 2002027, 2000018, 2000018, 2000018, 2000018, 2002030, 2002018, 2000016}; // filler' up int[] uncommons = {1000025, 1002662, 1002812, 1002850, 1002881, 1002880, 1012072, 4020009, 2043220, 2043022, 2040543, 2044420, 2040943, 2043713, 2044220, 2044120, 2040429, 2043220, 2040943}; // filler' uptoo - int[] rares = {1002859, 1002553, 01002762, 01002763, 01002764, 01002765, 01002766, 01002663, 1002788, 1002949, 2049100, 2340000, 2040822,2040822,2040822,2040822,2040822,2040822,2040822,2040822}; // filler' uplast + int[] rares = {1002859, 1002553, 1002762, 1002763, 1002764, 1002765, 1002766, 1002663, 1002788, 1002949, 2049100, 2340000, 2040822, 2040822, 2040822, 2040822}; // filler' uplast if(rand >= 25){ return commons[(int)(commons.length * Math.random())]; diff --git a/tools/MapleQuestItemFetcher/nbproject/private/private.xml b/tools/MapleQuestItemFetcher/nbproject/private/private.xml index 9c5c7b5d0b..6807a2ba19 100644 --- a/tools/MapleQuestItemFetcher/nbproject/private/private.xml +++ b/tools/MapleQuestItemFetcher/nbproject/private/private.xml @@ -2,9 +2,6 @@ - - file:/C:/Nexon/HeavenMS/tools/MapleQuestItemFetcher/src/tools/MapleItemInformationProvider.java - file:/C:/Nexon/HeavenMS/tools/MapleQuestItemFetcher/src/maplequestitemfetcher/MapleQuestItemFetcher.java - + diff --git a/wz/Map.wz/WorldMap/WorldMap010.img.xml b/wz/Map.wz/WorldMap/WorldMap010.img.xml index 3fc7819f2b..8625d7136c 100644 --- a/wz/Map.wz/WorldMap/WorldMap010.img.xml +++ b/wz/Map.wz/WorldMap/WorldMap010.img.xml @@ -783,6 +783,7 @@ + diff --git a/wz/Map.wz/WorldMap/WorldMap014.img.xml b/wz/Map.wz/WorldMap/WorldMap014.img.xml index b7c69b34be..ab0b1a06c8 100644 --- a/wz/Map.wz/WorldMap/WorldMap014.img.xml +++ b/wz/Map.wz/WorldMap/WorldMap014.img.xml @@ -150,6 +150,7 @@ + diff --git a/wz/String.wz/Consume.img.xml b/wz/String.wz/Consume.img.xml index e398dc4076..3bdd97de95 100644 --- a/wz/String.wz/Consume.img.xml +++ b/wz/String.wz/Consume.img.xml @@ -8017,15 +8017,15 @@ - + - + - + @@ -8033,7 +8033,7 @@ - +