Code Coupons + Worldmap update + Mini-games + Player Interaction wrap

Fixed several cases on the Cash Shop that would freeze some player actions when triggered, requiring exit Cash Shop to unstuck.
Implemented Code Coupons, supporting several items bundled on the same code, and also devised a way to automate code generation.
Added a current status on-demand option on the Buyback command. Info such as "current fee" or "time remaining" are available now.
Reviewed several cases where non-owned items would get stacked with owner-tagged items.
Added Door support for Happyville, Crimsonwood Keep.
Added worldmap tooltip support for some maps in Masteria's C. Keep and H. House.
Added Masteria region to the world map.
C. Keep interiors no longer relocates players to entrance after actions such as logout.
Overhauled minigame mechanics: from player boxes tooltip and in-match improvements to deploy different minigame types, accordingly with item description or player choice.
Fixed Amoria outskirts not relocating players to city after getting KO'ed.
Fixed issues with pets, rings and cash items being assigned the same cash unique ids leading to some quirks on the cash shop inventory.
Fixed an issue with the recently added HP/MP ratio update, arbitrarily taking off 1 point in certain cases.
Answer positions on the explorer's 3rd job quiz are now randomed.
Fixed several issues that showed up when the bcrypt system is disabled.
DOT from maps such as El Nath and Aqua Road now procs at a 5sec interval, GMS-like.
Improved performance of Whodrops and Search commands.
Concurrently protected player interaction handlers, thus mitigating several exploits on these lines.
Adjusted several expedition timers, such as Horntail, now having a more sane deadline.
Concurrently protected chair modules.
Fixed "seduce" debuff not working on chairs.
This commit is contained in:
ronancpl
2018-10-09 22:39:36 -03:00
parent 3a8377c283
commit 2b44b4baa2
213 changed files with 16545 additions and 11029 deletions
+12 -4
View File
@@ -11,13 +11,17 @@
/tools/MapleArrowFetcher/dist/
/tools/MapleArrowFetcher/nbproject/
/tools/MapleBossHpBarFetcher/nbproject/
/tools/MapleBossHpBarFetcher/build/
/tools/MapleBossHpBarFetcher/dist/
/tools/MapleBossHpBarFetcher/nbproject/
/tools/MapleCashDropFetcher/nbproject/
/tools/MapleCashDropFetcher/build/
/tools/MapleCashDropFetcher/dist/
/tools/MapleCashDropFetcher/nbproject/
/tools/MapleCodeCouponGenerator/build/
/tools/MapleCodeCouponGenerator/dist/
/tools/MapleCodeCouponGenerator/nbproject/
/tools/MapleCouponInstaller/build/
/tools/MapleCouponInstaller/dist/
@@ -25,7 +29,7 @@
/tools/MapleDojoUpdate/build/
/tools/MapleDojoUpdate/dist/
/tools/MapleDojoUpdate/nbproject/private/
/tools/MapleDojoUpdate/nbproject/
/tools/MapleEquipmentOmnileveler/build/
/tools/MapleEquipmentOmnileveler/dist/
@@ -59,9 +63,9 @@
/tools/MapleMobBookUpdate/dist/
/tools/MapleMobBookUpdate/nbproject/
/tools/MapleQuestItemCountFetcher/nbproject/
/tools/MapleQuestItemCountFetcher/build/
/tools/MapleQuestItemCountFetcher/dist/
/tools/MapleQuestItemCountFetcher/nbproject/
/tools/MapleQuestItemFetcher/build/
/tools/MapleQuestItemFetcher/dist/
@@ -87,5 +91,9 @@
/tools/MapleSkillMakerReagentIndexer/dist/
/tools/MapleSkillMakerReagentIndexer/nbproject/
/tools/SpiderDropFetcher/build/
/tools/SpiderDropFetcher/dist/
/tools/SpiderDropFetcher/nbproject/
/out
*.onetoc2
+39 -2
View File
@@ -22,7 +22,9 @@ Client files & general tools: https://drive.google.com/drive/folders/0BzDsHSr-0V
**Important note about localhosts**: these executables are red-flagged by antivirus tools as __potentially malicious softwares__, this happens due to the reverse engineering methods that were applied onto these software artifacts. Those depicted here have been put to use for years already and posed no harm so far, so they are soundly assumed to be safe.
Recommended localhost: https://hostr.co/m2bVtnizCtmD
Latest localhost: https://hostr.co/m2bVtnizCtmD
The following list, in bottom-up chronological order, holds information regarding all changes that were applied from the starting localhost used in this development. Some lines have a link attached, that will lead you to a snapshot of the localhost at that version of the artifact. Naturally, later versions holds all previous changes along with the proposed changes.
**Change log:**
@@ -49,10 +51,27 @@ Recommended localhost: https://hostr.co/m2bVtnizCtmD
* MapleSilver's starting on window-mode.
---
### Development status
### Development information
Status: <span style="color:grey">__In development (4th round)__</span>.
#### Mission
With non-profitting means intended, provide nostalgic pre-BB MapleStory players world-wide a quality local server for freestyle entertainment.
#### Vision
By taking the v83 MapleStory as the angular stone, incrementally look forward to improve the gaming experience whilst still retaining the "clean v83" conservative ideal. Also, through reviewing distinguished aspects of the server's behavior that could be classified as a potential server threat, in the long run look for ways to improve or even stabilize some of it's uncertain aspects.
#### Values
* Autonomy, seek self-improvement for tackling issues head-on;
* Adventurous, take no fear of failures on the path of progress;
* Light-hearted support, general people out there didn't experience what you've already had;
* Humility, no matter how good you are, there's no good in boasting yourself over experiences only a few have had;
#### Announcements
HeavenMS development achieved an acceptable state-of-the-art and will get into a halt. A heartfelt thanks for everyone that contributed in some way for the progress of this server!
Although development is halted, support for fixing features that were implemented here is still up. You can still actively help us improve the server by issuing pull requests with informative details about what's changing.
@@ -179,6 +198,24 @@ In that case, extract "lolwut.exe" from "lolwut-v0.01.rar" and place it on the M
Important: should the client be refused a connection to the game server, it may be because of firewall issues. Head to the end of this file to proceed in allowing this connection through the computer's firewall. Alternatively, one can deactivate the firewall and try opening the client again.
---
### Creating an account and logging in the game
By default, the server source is set to allow AUTO-REGISTERING. This means that, by simply typing in a "Login ID" and a "Password", you're able to create a new account.
After creating a character, experiment typing in all-chat "@commands". This will display all available commands for the current GM level your character has.
To change a character's GM level, make sure that character is not logged in, then:
* Open MySQL Query Browser;
* Double-click "heavenms" schema;
* Double click "characters" table;
* Execute the selected query;
* Mark "Edit" flag on the MySQL Query Browser UI screen;
* Locate your character's row on the displayed ResultSet;
* Edit your character's GM level;
* Hit APPLY CHANGES.
---
### Some notes about WZ/WZ.XML EDITING
+8 -2
View File
@@ -68,11 +68,14 @@ Player Social Network:
* Automated support for Player NPCs and Hall of Fame.
* Protected concurrently and improved the face expression system, guarding from trivial packet spam and exploits.
* All upgradeable non-cash equipments in inventory with level & EXP information available for read by anyone, given proper visibility.
* Further improved the existent minigame mechanics: remarkably checking out for no-item match requests, allowing different omok/matchcard match layouts and status update on the player matchbox tooltips.
Cash & Items:
* EXP/DROP/Cosmetic Coupons.
* EXP/DROP coupons now appears as a buff effect when on active time.
* Code coupons functional, with support for multiple items on the same code.
* Merged unique ids for pets, rings and cash items, thus solving some cash shop inventory issues.
* Great deal of cash items functional.
* MapleTV mechanics stabilized and separated by world.
* GMS-esque omok/match card drop chances.
@@ -80,7 +83,7 @@ Cash & Items:
* Inventory system properly checks for item slot free space and ownership.
* Storage with "Arrange Items" feature functional.
* Close-quarters evaluation mode for items (sandbox).
* Further improved Karma scissors mechanics.
* Further improved Karma scissors & Untradeable items mechanics.
* Spikes on shoes.
* Vega's spell.
* Owl of Minerva.
@@ -116,6 +119,8 @@ Monsters, Maps & Reactors:
* Updated many scripted portals not implementing SFX properly.
* Updated Crimsonwood, World Tour, Nihal Desert and Neo City, enabling quest completion and game progression in these areas.
* Added world maps for Mushroom Castle, World Tour (Singapore, Malaysia and Zipangu) & Ellin Forest areas.
* Added World Tour and Masteria continents in the world map.
* Reviewed World Map's town/field tooltips and links from the main world map and Masteria region.
* Giant Cake (anniversary-themed boss) drops Maple equipments, Maple scrolls, summoning bags and many more interesting items.
PQ potentials:
@@ -182,13 +187,14 @@ Custom NPCs:
* Donation Box: automatized item-buyer.
* Coco & Ace of Hearts: C. scroll crafters.
Admin/GM commands:
Server Commands:
* Server commands layered by GM levels.
* Spawn Zakum/Horntail/Pinkbean.
* Several new commands.
* Rank command highlighting users either by world or server-wide.
* Revamped command files layout -- thanks Arthur L.
* Optimized Search command, caching search range contents and added map search functionality.
External tools:
+61 -7
View File
@@ -1276,30 +1276,30 @@ Otimizado função goto, agora não mais gerando mapas de cidade/mapid a todo us
Melhorado função de disconnect do MapleClient, evitando múltiplos envios de dados do jogador à DB.
Desenhado (todo conteúdo de imagens creditado à Nexon) e implementado novos mapas-mundi referente a regiões de M. Shrine, Showa, CBD e Metropolis/Kampung.
03 Agosto 2018,
03 Setembro 2018,
Implementado buffs inexpiráveis.
Corrigido comando resetStats não levando em conta AP's atuais dos jogadores.
Corrigido novo sistema gerenciador de loots removendo a possibilidade de conseguir novos itens de quest após coleta do primeiro item.
04 Agosto 2018,
04 Setembro 2018,
Corrigido um flicker na animação do efeito da skill Hurricane.
Ajustado MapleSessionCoordinator, agora verificando HWID's ao invés de contar somente com o remote IP, evitando negação de serviço para usuários de VPNs.
Corrigido dispel normal incorretamente mostrando efeitos aleatórios a outros jogadores, issue apontado por Thora.
Corrigido change job não mostrando efeito a outros jogadores.
Corrigido valores incorretos sendo retirado de jogadores para expansão de guild, issue apontado por Thora.
05 Agosto 2018,
05 Setembro 2018,
Adicionado world map em Ellin Forest.
Protegido concorrentemente sistema de fames.
Adicionado ganho de quest points para jogadores que participam de PQs. Reformulado sistema de quest points para viabilizar a nova feature.
Otimizado método de ganho de experiência em equipamentos, agora devidamente cacheado e sem busca em strings no processo.
08 Agosto 2018,
08 Setembro 2018,
MapleServerHandler agora é devidamente deregistrado ao finalizar uma instância de channel, eliminando possível foco de memory leak.
Funções playerDead e playerRevive são agora opcionais em EIM scripts.
Nova ferramenta: MapleEquipmentOmnileveler. Permite adicionar e atualizar nodos referentes a níveis para todos os equipamentos. Em jogo, essa adição permite jogadores a ver nível de qualquer equipamento do jogo.
09 - 10 Agosto 2018,
09 - 10 Setembro 2018,
Adicionado cálculo de MP ao realizar ataques de mobs.
Aplicado vários pequenos ajustes no handler que lida com movimentação de mobs, procurando assim reduzir ruidos no fluxo do jogo (e.g. mob caindo de foothold).
Corrigido schedules de event instances sendo chamados após finalização da mesma, levando locks já liberados a serem chamados inesperadamente.
@@ -1307,7 +1307,7 @@ Corrigido casos onde jogadores poderiam requisitar instanciação de uma nova PQ
Aplicado reformatação geral no Character.wz, adicionando nodos de level para todos os equipamentos do jogo. Tal mudança permite que todos os equipamentos exponham nível e experiência em todos os equipamentos no inventário.
Implementado cálculo de experiência no lado do servidor que permite mostrar adequadamente EXP dos equipamentos no lado do cliente.
11 - 19 Agosto 2018,
11 - 19 Setembro 2018,
Corrigido MP Recovery skill não atuando segundo descrição, além de matando jogador com pouco HP disponível.
Refatorado completamente acessos de stats no código do server.
Refatorado check de Berserk sendo chamado em múltiplas seções do código.
@@ -1326,5 +1326,59 @@ Corrigido alliances retendo informações de guilds que foram desfeitas na DB.
Corrigido alliances não salvando nomes de ranks na DB ao serem criadas.
Adicionado suporte para doors na região de Mushroom Castle.
24 Agosto 2018,
24 Setembro 2018,
Resolvido pequenas inconsistências entre os XMLs e WZs disponibilizados.
Alterado "session write" para "announce", agora devidamente utilizando encapsulamento e lidando com sincronização de serviços.
25 Setembro 2018,
Corrigido diversas exceções no cash shop congelando próximas ações dos jogadores, somente ficando disponível após sair do mesmo.
Reimplementado sistema de code coupons no cash shop.
Removido skills Teleport e Super Dragon Roar redundantes do job SuperGM (jobid 910).
Adicionado informações detalhadas do estado corrente do buyback, em forma de comando.
Corrigido desligamento de channel com jogadores dentro do cash shop levando o sistema a lançar algumas exceções.
26 Setembro 2018,
Aprimorado code coupons, agora permitindo entrega de vários itens no mesmo código.
Revisado uso de addById no código, não permitindo adicionar itens limpos em slots de itens que possuem marcação de dono.
Implementado automatização de geração de coupon codes baseado em templates, utilizando arquivo XML para pegar os parâmetros.
29 Setembro 2018,
Corrigido Ereve faltando suporte para um Door portal.
Adicionado suporte de Doors para Happyville e Crimsonwood Keep.
Melhorado aspectos do world map da região de Masteria, adicionando interiores de Crimsonwood Keep no mapa e tooltip para interiores de Haunted House no mapa de Masteria.
Aprimorado região interior de Crimsonwood Keep, não mais reposicionando jogadores com a funcionalidade forcedReturn do WZ.
Corrigido arredores de Amoria não retornando jogadores para a cidade ao ressucitar pelo método usual.
Corrigido petids e ringids misturando valores com cashids de itens comuns, potencialmente causando problemas com os inventários do jogador e do cash shop da conta do mesmo.
30 Setembro 2018,
Adicionado região de Masteria no World Map.
Corrigido ligação de Ludibrium para Orbis não sendo mostrado corretamente.
Melhorado ratio update de HP/MP, agora memorizando ratio recentes ao efetuar ações como modificar status do inventário de itens equipados, entre outros.
01 - 03 Outubro 2018,
Corrigido diversos problemas com o sistema de login quando o uso do bcrypt está desativado.
Implementado/melhorado diversas mecânicas dos minigames (do aspecto dos tooltips dos boxes às pontuações visiveis dentro da sala e sistema de pontuação interno único), tornando agora finalmente viável a jogabilidade estendida dessa funcionalidade.
Adicionado server flag para evitar levelup em equipamentos de cash.
Melhorado verificação de itens untradeable em vários pontos do código, agora avaliando também status de Karma.
Adicionado funcionalidade de pesquisa de mapas no comando Search.
Otimizado comando Search, agora cacheando dados para as pesquisas.
Corrigido pequenas inconsistências com HPMP ratio recém implementado.
Revisado drop chance de vários itens de quest e diversos ETC drops de mobs de nível baixo.
Revisado descrições de várias skills de GM.
04 Outubro 2018,
Prequest de Zakum agora recompensa 5 Eye of Fire, valor oficial.
Modificado script de quiz do 3rd job, agora randomizando posicionamento das respostas.
Modificado damage-over-time em mapas como arredores de El Nath e Aqua Road, agora dando dano a cada 5 segundos, como previsto na versão oficial.
Corrigido comando Whodrops potencialmente lagando o servidor se comando for spammado por jogadores.
Protegido concorrentemente handler de interação de jogadores (trades, player shops, minigames, entre outros).
Melhorado checagem de acesso concorrente em alguns handlers, agora utilizando semáforos para fazer a filtragem de requisições a esses handlers.
Revertido pet pickup para permitindo coletar itens indiscriminadamente de ataque. Causa de situações onde pet pickup evita ação de ataque de jogador não está claro.
Modificado timers para diversas expedições, agora com duração máxima entre 1h30 a 2h.
08 Outubro 2018,
Protegido concorrentemente módulos de chairs.
09 Outubro 2018,
Corrigido disease seduce não funcionando da forma esperada quando jogador está sentado.
Movido Dropspider para fora do código-fonte do server, agora estando como uma ferramenta externa.
+4 -4
View File
@@ -903,10 +903,10 @@
2048003 - Scroll for Pet Equip. for Jump - Improves jump on pet equip.\nSuccess rate:100%, jump+1
2048004 - Scroll for Pet Equip. for Jump - Improves jump on pet equip.\nSuccess rate:60%, jump+2. The success rate of this scroll can be enhanced by Vega's Spell.
2048005 - Scroll for Pet Equip. for Jump - Improves jump on pet equip.\nSuccess rate:10%, jump+3. The success rate of this scroll can be enhanced by Vega's Spell.
2048006 - Scroll for Speed for Pet Equip. - Improves speed on Pet Equip. nSuccess rate:65%, speed+2
2048007 - Scroll for Speed for Pet Equip. - Improves speed on Pet Equip. nSuccess rate:15%, speed+3
2048008 - Scroll for jump for Pet Equip. - Improves jump on Pet equip. nSuccess rate:65%, jump+2
2048009 - Scroll for jump for Pet Equip. - Improves jump on Pet equip. nSuccess rate:15%, jump+3
2048006 - Scroll for Pet Equip. for Speed - Improves speed on Pet Equip. nSuccess rate:65%, speed+2
2048007 - Scroll for Pet Equip. for Speed - Improves speed on Pet Equip. nSuccess rate:15%, speed+3
2048008 - Scroll for Pet Equip. for Jump - Improves jump on Pet equip. nSuccess rate:65%, jump+2
2048009 - Scroll for Pet Equip. for Jump - Improves jump on Pet equip. nSuccess rate:15%, jump+3
2048010 - Scroll for Pet Equip. for STR 60% - Improves strength on pet equipments.\nSuccess rate:60%, STR+1. The success rate of this scroll can be enhanced by Vega's Spell.
2048011 - Scroll for Pet Equip. for INT 60% - Improves intelligence on pet equipments.\nSuccess rate:60%, INT+1. The success rate of this scroll can be enhanced by Vega's Spell.
2048012 - Scroll for Pet Equip. for DEX 60% - Improves dexterity on pet equipments.\nSuccess rate:60%, DEX+1. The success rate of this scroll can be enhanced by Vega's Spell.
-4
View File
@@ -1,10 +1,6 @@
compile.on.save=true
do.depend=false
do.jar=true
file.reference.mina-core-2.0.7.jar=C:\\Nexon\\HeavenMS\\cores\\mina-core-2.0.7.jar
file.reference.mysql-connector-java-bin.jar=C:\\Nexon\\HeavenMS\\cores\\mysql-connector-java-bin.jar
file.reference.slf4j-api-1.6.6.jar=C:\\Nexon\\HeavenMS\\cores\\slf4j-api-1.6.6.jar
file.reference.slf4j-jdk14-1.7.5.jar=C:\\Nexon\\HeavenMS\\cores\\slf4j-jdk14-1.7.5.jar
javac.debug=true
javadoc.preview=true
user.properties.file=C:\\Users\\RonanLana\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties
+6 -6
View File
@@ -30,20 +30,20 @@ endorsed.classpath=
excludes=
file.reference.HikariCP-java7-2.4.12.jar=cores/HikariCP-java7-2.4.12.jar
file.reference.MapleSolaxia-src=src
file.reference.mina-core-2.0.7.jar=cores\\mina-core-2.0.7.jar
file.reference.mysql-connector-java-bin.jar=cores\\mysql-connector-java-bin.jar
file.reference.slf4j-api-1.6.6.jar=cores\\slf4j-api-1.6.6.jar
file.reference.slf4j-jdk14-1.7.5.jar=cores\\slf4j-jdk14-1.7.5.jar
file.reference.mina-core-2.0.7.jar=cores/mina-core-2.0.7.jar
file.reference.mysql-connector-java-bin.jar=cores/mysql-connector-java-bin.jar
file.reference.slf4j-api-1.6.6.jar=cores/slf4j-api-1.6.6.jar
file.reference.slf4j-jdk14-1.7.5.jar=cores/slf4j-jdk14-1.7.5.jar
includes=**
jar.archive.disabled=${jnlp.enabled}
jar.compress=true
jar.index=${jnlp.enabled}
javac.classpath=\
${file.reference.HikariCP-java7-2.4.12.jar}:\
${file.reference.mina-core-2.0.7.jar}:\
${file.reference.mysql-connector-java-bin.jar}:\
${file.reference.slf4j-api-1.6.6.jar}:\
${file.reference.slf4j-jdk14-1.7.5.jar}:\
${file.reference.HikariCP-java7-2.4.12.jar}
${file.reference.slf4j-jdk14-1.7.5.jar}
# Space-separated list of extra javac options
javac.compilerargs=
javac.deprecation=false
+1 -1
View File
@@ -47,7 +47,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -47,7 +47,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -62,7 +62,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -47,7 +47,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -47,7 +47,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -47,7 +47,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -58,7 +58,7 @@ function playerEntry(eim, player) {
player.changeMap(map, map.getPortal(0));
//TODO: hold time across map changes
//player.getClient().getSession().write(tools.MaplePacketCreator.getClock(1800));
//player.getClient().announce(tools.MaplePacketCreator.getClock(1800));
}
function playerDead(eim, player) {
+1 -1
View File
@@ -53,7 +53,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 2);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -54,7 +54,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 1);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -56,7 +56,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 1);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -39,7 +39,7 @@ function playerEntry(eim, player) {
player.changeMap(entryMap, 0);
em.setProperty("noEntry","true");
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -237,7 +237,7 @@ function changedMap(eim, player, mapid) {
function afterChangedMap(eim, player, mapid) {
if (mapid == 990000100) {
var texttt = "So, here is the brief. You guys should be warned that, once out on the fortress outskirts, anyone that would not be equipping the #b#t1032033##k will die instantly due to the deteriorated state of the air around there. That being said, once your team moves out, make sure to #bhit the glowing rocks#k in that region and #bequip the dropped item#k before advancing stages. That will protect you thoroughly from the air sickness. Good luck!";
player.getClient().getSession().write(Packages.tools.MaplePacketCreator.getNPCTalk(9040000, /*(byte)*/ 0, texttt, "00 00", /*(byte)*/ 0));
player.getClient().announce(Packages.tools.MaplePacketCreator.getNPCTalk(9040000, /*(byte)*/ 0, texttt, "00 00", /*(byte)*/ 0));
}
}
+1 -1
View File
@@ -34,7 +34,7 @@ function playerEntry(eim, player) {
onRide = eim.getMapFactory().getMap(birdRide[myRide]);
player.changeMap(onRide, onRide.getPortal(0));
player.getClient().getSession().write(MaplePacketCreator.getClock(rideTime / 1000));
player.getClient().announce(MaplePacketCreator.getClock(rideTime / 1000));
eim.schedule("timeOut", rideTime);
}
+1 -1
View File
@@ -36,7 +36,7 @@ var clearMap = 240050600;
var minMapId = 240060000;
var maxMapId = 240060200;
var eventTime = 15; // 15 minutes
var eventTime = 120; // 120 minutes
var lobbyRange = [0, 0];
+2 -2
View File
@@ -35,8 +35,8 @@ function playerEntry(eim, player) {
onRide = eim.getMapFactory().getMap(trainRide[myRide]);
player.changeMap(onRide, onRide.getPortal(0));
player.getClient().getSession().write(MaplePacketCreator.getClock(rideTime / 1000));
player.getClient().getSession().write(MaplePacketCreator.earnTitleMessage("The next stop is at Kerning " + (myRide == 0 ? "Square" : "Subway") + " Station. The exit is to your left."));
player.getClient().announce(MaplePacketCreator.getClock(rideTime / 1000));
player.getClient().announce(MaplePacketCreator.earnTitleMessage("The next stop is at Kerning " + (myRide == 0 ? "Square" : "Subway") + " Station. The exit is to your left."));
eim.schedule("timeOut", rideTime);
}
+2 -2
View File
@@ -2,7 +2,7 @@ importPackage(Packages.tools);
importPackage(Packages.server.life);
var minPlayers = 1;
var eventTime = 10;
var eventTime = 10; // 10 minutes
var entryMap = 106021402;
var exitMap = 106021600;
@@ -36,7 +36,7 @@ function playerEntry(eim, player){
var pm = MapleLifeFactory.getMonster(3300008);
weddinghall.spawnMonsterOnGroundBelow(pm, new Packages.java.awt.Point(472, 27));
player.getClient().getSession().write(MaplePacketCreator.getClock(eventTime * 60));
player.getClient().announce(MaplePacketCreator.getClock(eventTime * 60));
eim.startEventTimer(eventTime * 60000);
}
+1 -1
View File
@@ -180,7 +180,7 @@ function playerEntry(eim, player) {
player.changeMap(map, map.getPortal(0));
var texttt = "Hi, my name is Eak, the Chamberlain of the Goddess. Don't be alarmed; you won't be able to see me right now. Back when the Goddess turned into a block of stone, I simultaneously lost my own power. If you gather up the power of the Magic Cloud of Orbis, however, then I'll be able to recover my body and re-transform back to my original self. Please collect #b20#k Magic Clouds and bring them back to me. Right now, you'll only see me as a tiny, flickering light.";
player.getClient().getSession().write(Packages.tools.MaplePacketCreator.getNPCTalk(2013001, /*(byte)*/ 0, texttt, "00 00", /*(byte)*/ 0));
player.getClient().announce(Packages.tools.MaplePacketCreator.getNPCTalk(2013001, /*(byte)*/ 0, texttt, "00 00", /*(byte)*/ 0));
}
function scheduledTimeout(eim) {
+1 -1
View File
@@ -37,7 +37,7 @@ var clearMap = 270050300;
var minMapId = 270050100;
var maxMapId = 270050300;
var eventTime = 100; // 100 minutes
var eventTime = 140; // 140 minutes
var lobbyRange = [0, 0];
+5 -5
View File
@@ -22,7 +22,7 @@
importPackage(Packages.tools);
var exitMap;
var startMap;
var entryMap;
var otherMap;
var minPlayers = 1;
var fightTime = 60;
@@ -30,7 +30,7 @@ var timer = 1000 * 60 * fightTime;
function init() {
exitMap = em.getChannelServer().getMapFactory().getMap(103040400);
startMap = em.getChannelServer().getMapFactory().getMap(103040410);
entryMap = em.getChannelServer().getMapFactory().getMap(103040410);
otherMap = em.getChannelServer().getMapFactory().getMap(103040420);
}
@@ -44,7 +44,7 @@ function setup() {
function afterSetup(eim) {}
function respawn(eim) {
var map = eim.getMapInstance(startMap.getId());
var map = eim.getMapInstance(entryMap.getId());
var map2 = eim.getMapInstance(otherMap.getId());
map.allowSummonState(true);
map2.allowSummonState(true);
@@ -55,7 +55,7 @@ function respawn(eim) {
function playerEntry(eim, player) {
var amplifierMap = eim.getMapInstance(startMap.getId());
var amplifierMap = eim.getMapInstance(entryMap.getId());
player.changeMap(amplifierMap);
eim.schedule("timeOut", timer);
}
@@ -107,7 +107,7 @@ function playerExit(eim, player) {
function moveMap(eim, player) {
if (player.getMap().getId() == exitMap.getId()) {
removePlayer(eim, player);
player.getClient().getSession().write(MaplePacketCreator.removeClock());
player.getClient().announce(MaplePacketCreator.removeClock());
eim.dispose();
}
}
+5 -5
View File
@@ -22,7 +22,7 @@
importPackage(Packages.tools);
var exitMap;
var startMap;
var entryMap;
var otherMap;
var minPlayers = 1;
var fightTime = 30;
@@ -30,7 +30,7 @@ var timer = 1000 * 60 * fightTime;
function init() {
exitMap = em.getChannelServer().getMapFactory().getMap(103040400);
startMap = em.getChannelServer().getMapFactory().getMap(103040440);
entryMap = em.getChannelServer().getMapFactory().getMap(103040440);
otherMap = em.getChannelServer().getMapFactory().getMap(103040450);
}
@@ -44,7 +44,7 @@ function setup() {
function afterSetup(eim) {}
function respawn(eim) {
var map = eim.getMapInstance(startMap.getId());
var map = eim.getMapInstance(entryMap.getId());
var map2 = eim.getMapInstance(otherMap.getId());
map.allowSummonState(true);
map2.allowSummonState(true);
@@ -55,7 +55,7 @@ function respawn(eim) {
function playerEntry(eim, player) {
var amplifierMap = eim.getMapInstance(startMap.getId());
var amplifierMap = eim.getMapInstance(entryMap.getId());
player.changeMap(amplifierMap);
eim.schedule("timeOut", timer);
}
@@ -107,7 +107,7 @@ function playerExit(eim, player) {
function moveMap(eim, player) {
if (player.getMap().getId() == exitMap.getId()) {
removePlayer(eim, player);
player.getClient().getSession().write(MaplePacketCreator.removeClock());
player.getClient().announce(MaplePacketCreator.removeClock());
eim.dispose();
}
}
+1 -1
View File
@@ -36,7 +36,7 @@ var clearMap = 211042400;
var minMapId = 280030000;
var maxMapId = 280030000;
var eventTime = 60; // 60 minutes
var eventTime = 120; // 120 minutes
var lobbyRange = [0, 0];
@@ -3,7 +3,7 @@
function start(ms) {
//var pq = ms.getPyramid();
//ms.getPlayer().resetEnteredScript();
//ms.getClient().getSession().write(MaplePacketCreator.getClock(pq.timer()));
//ms.getClient().announce(MaplePacketCreator.getClock(pq.timer()));
}
/*
killing/first/stage
@@ -29,11 +29,11 @@ var player;
function start(ms) {
player = ms.getPlayer();
player.resetEnteredScript();
ms.getClient().getSession().write(MaplePacketCreator.showEffect("event/space/start"));
ms.getClient().announce(MaplePacketCreator.showEffect("event/space/start"));
player.startMapEffect("Please rescue Gaga within the time limit.", 5120027);
var map = player.getMap();
if (map.getTimeLeft() > 0) {
ms.getClient().getSession().write(MaplePacketCreator.getClock(map.getTimeLeft()));
ms.getClient().announce(MaplePacketCreator.getClock(map.getTimeLeft()));
} else {
map.addMapTimer(180);
}
+7 -6
View File
@@ -21,13 +21,14 @@ function action(mode, type, selection) {
if(status == 0){
cm.sendYesNo("Would you like to leave?");
}else if(status == 1){
var mapid = cm.getMapId();
if(mapid == 108010101) cm.getPlayer().changeMap(105040305);
else if(mapid == 108010201) cm.getPlayer().changeMap(100040106);
else if(mapid == 108010301) cm.getPlayer().changeMap(105070001);
else if(mapid == 108010401) cm.getPlayer().changeMap(107000402);
else if(mapid == 108010501) cm.getPlayer().changeMap(105070200);
var mapid = cm.getMapId(), exitid = mapid;
if(mapid == 108010101) exitid = 105040305;
else if(mapid == 108010201) exitid = 100040106;
else if(mapid == 108010301) exitid = 105070001;
else if(mapid == 108010401) exitid = 107000402;
else if(mapid == 108010501) exitid = 105070200;
if (mapid != exitid) cm.getPlayer().changeMap(exitid);
cm.dispose();
}
}
+1 -1
View File
@@ -92,7 +92,7 @@ function action(mode, type, selection){
else if (status == 2) {
if (cm.getPlayer().getRemainingSp() > 0)
if (cm.getPlayer().getRemainingSp() > (cm.getLevel() - 70) * 3) {
cm.sendNext("Please, use all your SP before contining.");
cm.sendNext("Please, use all your SP before continuing.");
cm.dispose();
return;
}
+1 -1
View File
@@ -64,7 +64,7 @@ function action(mode, type, selection){
else if (status == 2) {
if (cm.getPlayer().getRemainingSp() > 0)
if (cm.getPlayer().getRemainingSp() > (cm.getLevel() - 70) * 3) {
cm.sendNext("Please, use all your SP before contining.");
cm.sendNext("Please, use all your SP before continuing.");
cm.dispose();
return;
}
+1 -1
View File
@@ -66,7 +66,7 @@ function action(mode, type, selection){
else if (status == 2) {
if (cm.getPlayer().getRemainingSp() > 0)
if (cm.getPlayer().getRemainingSp() > (cm.getLevel() - 70) * 3) {
cm.sendNext("Please, use all your SP before contining.");
cm.sendNext("Please, use all your SP before continuing.");
cm.dispose();
return;
}
+1 -1
View File
@@ -64,7 +64,7 @@ function action(mode, type, selection){
else if (status == 2) {
if (cm.getPlayer().getRemainingSp() > 0)
if (cm.getPlayer().getRemainingSp() > (cm.getLevel() - 70) * 3) {
cm.sendNext("Please, use all your SP before contining.");
cm.sendNext("Please, use all your SP before continuing.");
cm.dispose();
return;
}
+1 -1
View File
@@ -64,7 +64,7 @@ function action(mode, type, selection){
else if (status == 2) {
if (cm.getPlayer().getRemainingSp() > 0)
if (cm.getPlayer().getRemainingSp() > (cm.getLevel() - 70) * 3) {
cm.sendNext("Please, use all your SP before contining.");
cm.sendNext("Please, use all your SP before continuing.");
cm.dispose();
return;
}
+40 -6
View File
@@ -39,7 +39,7 @@ var questionTree = [
//Questions Related to MONSTERS
["Green Mushroom, Tree Stump, Bubbling, Axe Stump, Octopus, which is highest level of all?", ["Tree Stump", "Bubbling", "Axe Stump", "Octopus", "Green Mushroom"], 2],
["Which monster will be seen during the ship trip to Orbis/Ellinia?", ["Werewolf", "Slime", "Crimson Balrog", "Zakum", "Star Pixie"], 2],
["Maple Island doesn't have which following monsters?", ["Shroom", "Blue Snail", "Orange Mushroom", "Red Snail", "Pig"], 4],
["Maple Island doesn't have which following monsters?", ["Green Mushroom", "Blue Snail", "Orange Mushroom", "Red Snail", "Pig"], 0],
["Which monster is not at Victoria Island and Sleepywood?", ["Evil Eye", "Sentinel", "Jr. Balrog", "Ghost Stump", "Snail"], 1],
["El Nath doesn't have which following monsters?", ["Dark Yeti", "Dark Ligator", "Yeti & Pepe", "Bain", "Coolie Zombie"], 1],
["Which of following monsters can fly?", ["Malady", "Ligator", "Cold Eye", "Meerkat", "Alishar"], 0],
@@ -80,6 +80,8 @@ var question;
var questionPool;
var questionPoolCursor;
var questionAnswer;
function start() {
status = -1;
action(1, 0, 0);
@@ -121,7 +123,10 @@ function action(mode, type, selection) {
question = fetchNextQuestion();
var questionHead = generateQuestionHeading();
var questionEntry = questionTree[question][0];
var questionOptions = generateSelectionMenu(questionTree[question][1]);
var questionData = generateSelectionMenu(questionTree[question][1], questionTree[question][2]);
var questionOptions = questionData[0];
questionAnswer = questionData[1];
cm.sendSimple(questionHead + questionEntry + "\r\n\r\n#b" + questionOptions + "#k");
} else if(status >= 2 && status <= 5) {
@@ -134,7 +139,10 @@ function action(mode, type, selection) {
question = fetchNextQuestion();
var questionHead = generateQuestionHeading();
var questionEntry = questionTree[question][0];
var questionOptions = generateSelectionMenu(questionTree[question][1]);
var questionData = generateSelectionMenu(questionTree[question][1], questionTree[question][2]);
var questionOptions = questionData[0];
questionAnswer = questionData[1];
cm.sendSimple(questionHead + questionEntry + "\r\n\r\n#b" + questionOptions + "#k");
} else if(status == 6) {
@@ -155,7 +163,7 @@ function action(mode, type, selection) {
}
function evaluateAnswer(selection) {
return selection == questionTree[question][2];
return selection == questionAnswer;
}
function generateQuestionHeading() {
@@ -189,10 +197,36 @@ function fetchNextQuestion() {
return next;
}
function generateSelectionMenu(array) {
function shuffle(array) {
var currentIndex = array.length, temporaryValue, randomIndex;
// While there remain elements to shuffle...
while (0 !== currentIndex) {
// Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex -= 1;
// And swap it with the current element.
temporaryValue = array[currentIndex];
array[currentIndex] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
}
function generateSelectionMenu(array, answer) {
var answerStr = array[answer], answerPos = -1;
shuffle(array);
var menu = "";
for (var i = 0; i < array.length; i++) {
menu += "#L" + i + "#" + array[i] + "#l\r\n";
if (answerStr == array[i]) {
answerPos = i;
}
return menu;
}
return [menu, answerPos];
}
+2 -2
View File
@@ -107,14 +107,14 @@ function action(mode, type, selection) {
} else {
if(cm.haveItem(4031061) && cm.haveItem(4031062)) {
if(!cm.haveItem(4000082, 30)) {
cm.sendOk("You have completed the trials, however there's still the need of #b30 #t4000082##k to forge the #t4001017#.");
cm.sendOk("You have completed the trials, however there's still the need of #b30 #t4000082##k to forge 5 #t4001017#.");
} else {
cm.completeQuest(100201);
cm.gainItem(4031061, -1);
cm.gainItem(4031062, -1);
cm.gainItem(4000082, -30);
cm.gainItem(4001017, 1);
cm.gainItem(4001017, 5);
cm.sendNext("You #rhave completed the trials#k, from now on having my approval to challenge Zakum.");
}
+8 -2
View File
@@ -82,19 +82,22 @@ function writeFeatureTab_PlayerSocialNetwork() {
addFeature("Automated support for Player NPCs and Hall of Fame.");
addFeature("Engagement & Wedding system.");
addFeature("Equipments displays to everyone it's level & EXP info.");
addFeature("Further improved the existent minigame mechanics.");
}
function writeFeatureTab_CashItems() {
addFeature("EXP/DROP/Cosmetic Coupons.");
addFeature("EXP/DROP Coupon as buff effect during active time.");
addFeature("Great deal of cash items functional.");
addFeature("Code coupons functional, with multi-items support.");
addFeature("Merged unique ids for pets, rings and cash items.");
addFeature("MapleTV mechanics stabilized and split by world.");
addFeature("GMS-esque omok/match card drop chances.");
addFeature("New town scroll: antibanish. Counters boss banishes.");
addFeature("Inventory system checks for free slot & stack space.");
addFeature("Storage with 'Arrange Items' feature functional.");
addFeature("Close-quarters evaluation mode for items.");
addFeature("Further improved Karma scissors.");
addFeature("Reviewed Karma scissors & Untradeable items.");
addFeature("Scroll for Spikes on Shoes.");
addFeature("Scroll for Cold Protection.");
addFeature("Vega's spell.");
@@ -133,6 +136,8 @@ function writeFeatureTab_MonstersMapsReactors() {
addFeature("Updated scripted portals, now with proper portal SFX.");
addFeature("Reviewed Masteria, W. Tour, N. Desert and Neo City.");
addFeature("Added world maps for M. Castle, W. Tour & Ellin areas.");
addFeature("Added W. Tour & Masteria continents in the world map.");
addFeature("Reviewed several issues with W. Map tooltips & links.");
addFeature("Giant Cake boss drops s. bags and Maple items.");
}
@@ -197,6 +202,7 @@ function writeFeatureTab_Commands() {
addFeature("Rank command highlighting users by world or overall.");
addFeature("Server commands layered by GM levels.");
addFeature("Revamped command files layout - thanks Arthur L!");
addFeature("Improved 'Search' performance & added map search.");
}
function writeFeatureTab_CustomNPCs() {
@@ -276,7 +282,7 @@ function action(mode, type, selection) {
status--;
if (status == 0) {
var sendStr = "HeavenMS was developed on the timespan of 3 years, based on where Solaxia left. On the meantime many nice features emerged, development aimed to get back the old GMS experience. Now many of these so-long missing features are gracefully presented to you in the shape of this server. Long live MapleStory!!\r\n\r\nThese are the features from #bHeavenMS#k:\r\n\r\n";
var sendStr = "HeavenMS was developed on the timespan of 3 years, based on where Solaxia left. I'm glad to say the development itself had continuously been agraciated by dozens of contributors and cheerers (truly thanks for the trusting vow, guys & gals!).\r\n\r\nTalking about results: many nice features emerged, development aimed to get back the old GMS experience. Now many of these so-long missing features are gracefully presented to you in the shape of this server. Long live MapleStory!!\r\n\r\nThese are the features from #bHeavenMS#k:\r\n\r\n";
for(var i = 0; i < tabs.length; i++) {
sendStr += "#L" + i + "##b" + tabs[i] + "#k#l\r\n";
}
+1
View File
@@ -37,6 +37,7 @@ function writeServerStaff_HeavenMS() {
addPerson("Ronan", "Developer");
addPerson("Vcoc", "Freelance Developer");
addPerson("Thora", "Contributor");
addPerson("GabrielSin", "Contributor");
setHistory(2015, 2018);
}
+16 -27
View File
@@ -16,7 +16,6 @@ CREATE TABLE IF NOT EXISTS `accounts` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(13) NOT NULL DEFAULT '',
`password` varchar(128) NOT NULL DEFAULT '',
`salt` varchar(128) DEFAULT NULL,
`pin` varchar(10) DEFAULT NULL,
`pic` varchar(26) DEFAULT NULL,
`loggedin` tinyint(4) NOT NULL DEFAULT '0',
@@ -4517,7 +4516,7 @@ INSERT IGNORE INTO `temp_data` (`id`, `dropperid`, `itemid`, `minimum_quantity`,
(4298, 5130107, 4130006, 1, 1, 0, 6000),
(4299, 5130107, 4130011, 1, 1, 0, 6000),
(4300, 5130108, 4000069, 1, 1, 0, 600000),
(4301, 5130108, 4000082, 1, 1, 0, 40000),
(4301, 5130108, 4000082, 1, 1, 0, 20000),
(4302, 5130108, 2000003, 1, 1, 0, 20000),
(4303, 5130108, 2000004, 1, 1, 0, 20000),
(4304, 5130108, 2000002, 1, 1, 0, 20000),
@@ -12926,15 +12925,6 @@ CREATE TABLE IF NOT EXISTS `hiredmerchant` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `htsquads` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`channel` int(10) unsigned NOT NULL,
`leaderid` int(10) unsigned NOT NULL DEFAULT '0',
`status` int(10) unsigned NOT NULL DEFAULT '0',
`members` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `hwidaccounts` (
`accountid` int(11) NOT NULL DEFAULT '0',
`hwid` varchar(40) NOT NULL DEFAULT '',
@@ -16393,13 +16383,21 @@ CREATE TABLE IF NOT EXISTS `notes` (
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `nxcode` (
`code` varchar(15) NOT NULL,
`valid` int(11) NOT NULL DEFAULT '1',
`user` varchar(13) DEFAULT NULL,
`type` int(11) NOT NULL DEFAULT '0',
`item` int(11) NOT NULL DEFAULT '10000',
PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
`id` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(17) NOT NULL UNIQUE,
`retriever` varchar(13) DEFAULT NULL,
`expiration` bigint(20) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `nxcode_items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`codeid` int(11) NOT NULL,
`type` int(11) NOT NULL DEFAULT '5',
`item` int(11) NOT NULL DEFAULT '4000000',
`quantity` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `nxcoupons` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@@ -21414,15 +21412,6 @@ CREATE TABLE IF NOT EXISTS `wishlists` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `zaksquads` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`channel` int(10) unsigned NOT NULL,
`leaderid` int(10) unsigned NOT NULL DEFAULT '0',
`status` int(10) unsigned NOT NULL DEFAULT '0',
`members` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
ALTER TABLE `dueyitems`
ADD CONSTRAINT `dueyitems_ibfk_1` FOREIGN KEY (`PackageId`) REFERENCES `dueypackages` (`PackageId`) ON DELETE CASCADE;
+51 -51
View File
@@ -412,9 +412,9 @@ USE `heavenms`;
(1210102, 4030001, 1, 1, 0, 10000),
(9300229, 4030001, 1, 1, 0, 10000),
(9500102, 4030001, 1, 1, 0, 10000),
(1210102, 4001345, 1, 1, 0, 7000),
(9300229, 4001345, 1, 1, 0, 7000),
(9500102, 4001345, 1, 1, 0, 7000),
(1210102, 4001345, 1, 1, 0, 70000),
(9300229, 4001345, 1, 1, 0, 70000),
(9500102, 4001345, 1, 1, 0, 70000),
(1210102, 2000000, 1, 1, 0, 40000),
(9300229, 2000000, 1, 1, 0, 40000),
(9500102, 2000000, 1, 1, 0, 40000),
@@ -508,18 +508,18 @@ USE `heavenms`;
(1210101, 4000021, 1, 1, 0, 200000),
(9300059, 4000021, 1, 1, 0, 200000),
(9400242, 4000021, 1, 1, 0, 200000),
(1210101, 4003004, 1, 1, 0, 7000),
(9300059, 4003004, 1, 1, 0, 7000),
(9400242, 4003004, 1, 1, 0, 7000),
(1210101, 4003004, 1, 1, 0, 70000),
(9300059, 4003004, 1, 1, 0, 70000),
(9400242, 4003004, 1, 1, 0, 70000),
(1210101, 4030012, 1, 1, 0, 125000),
(9300059, 4030012, 1, 1, 0, 125000),
(9400242, 4030012, 1, 1, 0, 125000),
(1210101, 4001343, 1, 1, 0, 7000),
(9300059, 4001343, 1, 1, 0, 7000),
(9400242, 4001343, 1, 1, 0, 7000),
(1210101, 4001342, 1, 1, 0, 7000),
(9300059, 4001342, 1, 1, 0, 7000),
(9400242, 4001342, 1, 1, 0, 7000),
(1210101, 4001343, 1, 1, 0, 70000),
(9300059, 4001343, 1, 1, 0, 70000),
(9400242, 4001343, 1, 1, 0, 70000),
(1210101, 4001342, 1, 1, 0, 70000),
(9300059, 4001342, 1, 1, 0, 70000),
(9400242, 4001342, 1, 1, 0, 70000),
(1210101, 2000000, 1, 1, 0, 40000),
(9300059, 2000000, 1, 1, 0, 40000),
(9400242, 2000000, 1, 1, 0, 40000),
@@ -566,9 +566,9 @@ USE `heavenms`;
(9300059, 1072285, 1, 1, 0, 700),
(9400242, 1072285, 1, 1, 0, 700),
(1110101, 4030009, 1, 1, 0, 28000),
(1110101, 4001344, 1, 1, 0, 7000),
(1110101, 4001356, 1, 1, 0, 7000),
(1110101, 4001360, 1, 1, 0, 12000),
(1110101, 4001344, 1, 1, 0, 70000),
(1110101, 4001356, 1, 1, 0, 70000),
(1110101, 4001360, 1, 1, 0, 120000),
(1110101, 2000000, 1, 1, 0, 40000),
(1110101, 2040802, 1, 1, 0, 750),
(1110101, 2380008, 1, 1, 0, 0),
@@ -4654,7 +4654,7 @@ USE `heavenms`;
(9300186, 1082195, 1, 1, 0, 40000),
(9500339, 1082195, 1, 1, 0, 40000),
(9303003, 1082195, 1, 1, 0, 700),
(3300008, 4001318, 1, 1, 0, 7000),
(3300008, 4001318, 1, 1, 0, 600000),
(3300008, 2388070, 1, 4, 0, 20000),
(3300008, 2000002, 1, 4, 0, 40000),
(3300008, 2000003, 1, 4, 0, 40000),
@@ -16180,8 +16180,8 @@ USE `heavenms`;
(9420513, 1060106, 1, 1, 0, 40000),
(9420513, 1072173, 1, 1, 0, 40000),
(9420513, 1332026, 1, 1, 0, 40000),
(9400549, 4031903, 1, 1, 0, 7000),
(9400571, 4031903, 1, 1, 0, 7000),
(9400549, 4031903, 1, 1, 0, 100000),
(9400571, 4031903, 1, 1, 0, 100000),
(9400549, 2020014, 1, 4, 0, 3000),
(9400571, 2020014, 1, 4, 0, 3000),
(9400549, 2002025, 1, 4, 0, 10000),
@@ -20007,29 +20007,29 @@ USE `heavenms`;
(9300154, 4031782, 1, 1, 0, 400000),
(9300154, 4031783, 1, 1, 0, 400000),
(9300154, 4031784, 1, 1, 0, 400000),
(1110100, 4032317, 1, 1, 21717, 20000),
(1110130, 4032317, 1, 1, 21717, 20000),
(1110100, 4032318, 1, 1, 21718, 20000),
(1110130, 4032318, 1, 1, 21718, 20000),
(1110100, 4032317, 1, 1, 21717, 40000),
(1110130, 4032317, 1, 1, 21717, 40000),
(1110100, 4032318, 1, 1, 21718, 40000),
(1110130, 4032318, 1, 1, 21718, 40000),
(9400204, 4130020, 1, 1, 0, 3000),
(9400614, 4001341, 1, 1, 28172, 15000),
(9400615, 4001341, 1, 1, 28172, 15000),
(9400616, 4001341, 1, 1, 28172, 15000),
(1110101, 4001347, 1, 1, 28229, 80000),
(1110100, 4001348, 1, 1, 28231, 400000),
(1120100, 4001349, 1, 1, 28235, 100000),
(1210101, 4001350, 1, 1, 28235, 100000),
(2220100, 4001351, 1, 1, 28237, 100000),
(9400614, 4001352, 1, 1, 28205, 40000),
(9400615, 4001352, 1, 1, 28205, 40000),
(9400616, 4001352, 1, 1, 28205, 40000),
(9400617, 4001352, 1, 1, 28205, 40000),
(9400617, 4001362, 1, 1, 28252, 40000),
(9400655, 4001362, 1, 1, 28252, 40000),
(9400656, 4001362, 1, 1, 28252, 40000),
(9400617, 4001363, 1, 1, 28252, 40000),
(9400655, 4001363, 1, 1, 28252, 40000),
(9400656, 4001363, 1, 1, 28252, 40000),
(9400614, 4001341, 1, 1, 28172, 30000),
(9400615, 4001341, 1, 1, 28172, 30000),
(9400616, 4001341, 1, 1, 28172, 30000),
(1110101, 4001347, 1, 1, 28229, 160000),
(1110100, 4001348, 1, 1, 28231, 800000),
(1120100, 4001349, 1, 1, 28235, 200000),
(1210101, 4001350, 1, 1, 28235, 200000),
(2220100, 4001351, 1, 1, 28237, 200000),
(9400614, 4001352, 1, 1, 28205, 80000),
(9400615, 4001352, 1, 1, 28205, 80000),
(9400616, 4001352, 1, 1, 28205, 80000),
(9400617, 4001352, 1, 1, 28205, 80000),
(9400617, 4001362, 1, 1, 28252, 80000),
(9400655, 4001362, 1, 1, 28252, 80000),
(9400656, 4001362, 1, 1, 28252, 80000),
(9400617, 4001363, 1, 1, 28252, 80000),
(9400655, 4001363, 1, 1, 28252, 80000),
(9400656, 4001363, 1, 1, 28252, 80000),
(9400609, 2000002, 1, 1, 0, 40000),
(9400609, 2000003, 1, 1, 0, 40000),
(9400609, 2000004, 1, 1, 0, 10000),
@@ -20077,17 +20077,17 @@ USE `heavenms`;
(9400613, 1082258, 1, 1, 0, 5000),
(9400613, 1072421, 1, 1, 0, 5000),
(4110302, 2383007, 1, 1, 0, 8000),
(130100, 4032374, 1, 1, 2405, 40000),
(1110101, 4032374, 1, 1, 2405, 40000),
(210100, 4032376, 1, 1, 2406, 40000),
(1110101, 4032376, 1, 1, 2406, 40000),
(210100, 4032377, 1, 1, 2407, 40000),
(1210101, 4032377, 1, 1, 2407, 40000),
(130100, 4032378, 1, 1, 2408, 40000),
(1120100, 4032378, 1, 1, 2408, 40000),
(1110100, 4032379, 1, 1, 2409, 40000),
(1210100, 4032379, 1, 1, 2409, 40000),
(2130100, 4001344, 1, 1, 0, 7000),
(130100, 4032374, 1, 1, 2405, 80000),
(1110101, 4032374, 1, 1, 2405, 80000),
(210100, 4032376, 1, 1, 2406, 80000),
(1110101, 4032376, 1, 1, 2406, 80000),
(210100, 4032377, 1, 1, 2407, 80000),
(1210101, 4032377, 1, 1, 2407, 80000),
(130100, 4032378, 1, 1, 2408, 80000),
(1120100, 4032378, 1, 1, 2408, 80000),
(1110100, 4032379, 1, 1, 2409, 80000),
(1210100, 4032379, 1, 1, 2409, 80000),
(2130100, 4001344, 1, 1, 0, 70000),
(7220002, 4031789, 1, 1, 3844, 999999),
(8830007, 1302112, 1, 1, 0, 4000),
(8830007, 1302113, 1, 1, 0, 4000),
@@ -42,6 +42,7 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
protected int hpMpApUsed, remainingAp;
protected int[] remainingSp = new int[10];
protected transient int clientmaxhp, clientmaxmp, localmaxhp = 50, localmaxmp = 5;
protected float transienthp = Float.NEGATIVE_INFINITY, transientmp = Float.NEGATIVE_INFINITY;
private AbstractCharacterListener listener = null;
protected Map<MapleStat, Integer> statUpdates = new HashMap<>();
@@ -222,6 +223,8 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
} else if (thp > localmaxhp) {
thp = localmaxhp;
}
if (this.hp != thp) this.transienthp = Float.NEGATIVE_INFINITY;
this.hp = thp;
dispatchHpChanged(oldHp);
@@ -234,6 +237,8 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
} else if (tmp > localmaxmp) {
tmp = localmaxmp;
}
if (this.mp != tmp) this.transientmp = Float.NEGATIVE_INFINITY;
this.mp = tmp;
}
@@ -246,11 +251,13 @@ public abstract class AbstractMapleCharacterObject extends AbstractAnimatedMaple
}
protected void setMaxHp(int hp_) {
if (this.maxhp < hp_) this.transienthp = Float.NEGATIVE_INFINITY;
this.maxhp = hp_;
this.clientmaxhp = Math.min(30000, hp_);
}
protected void setMaxMp(int mp_) {
if (this.maxmp < mp_) this.transientmp = Float.NEGATIVE_INFINITY;
this.maxmp = mp_;
this.clientmaxmp = Math.min(30000, mp_);
}
+201 -49
View File
@@ -118,6 +118,7 @@ import client.inventory.MaplePet;
import client.inventory.MapleWeaponType;
import client.inventory.ModifyInventory;
import client.inventory.PetDataFactory;
import client.inventory.manipulator.MapleCashidGenerator;
import client.inventory.manipulator.MapleInventoryManipulator;
import client.newyear.NewYearCardRecord;
import constants.ExpTable;
@@ -1341,12 +1342,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
private boolean buffMapProtection() {
effLock.lock();
chrLock.lock();
int thisMapid = mapid;
int returnMapid = client.getChannelServer().getMapFactory().getMap(thisMapid).getReturnMapId();
effLock.lock();
chrLock.lock();
try {
for(Entry<MapleBuffStat, MapleBuffStatValueHolder> mbs : effects.entrySet()) {
if(mbs.getKey() == MapleBuffStat.MAP_PROTECTION) {
@@ -1903,7 +1903,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
Skill battleship = SkillFactory.getSkill(Corsair.BATTLE_SHIP);
int cooldown = battleship.getEffect(getSkillLevel(battleship)).getCooldown();
announce(MaplePacketCreator.skillCooldown(Corsair.BATTLE_SHIP, cooldown));
addCooldown(Corsair.BATTLE_SHIP, System.currentTimeMillis(), (long)(cooldown * 1000));
addCooldown(Corsair.BATTLE_SHIP, Server.getInstance().getCurrentTime(), (long)(cooldown * 1000));
removeCooldown(5221999);
cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING);
} else {
@@ -2080,6 +2080,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ps3.setInt(1, ringid);
ps3.executeUpdate();
}
MapleCashidGenerator.freeCashId(ringid);
}
}
}
@@ -2090,11 +2092,13 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ps2.executeUpdate();
}
if(rs.getInt("petid") > -1) {
int petid = rs.getInt("petid");
if(petid > -1) {
try (PreparedStatement ps2 = con.prepareStatement("DELETE FROM pets WHERE petid = ?")) {
ps2.setInt(1, rs.getInt("petid"));
ps2.setInt(1, petid);
ps2.executeUpdate();
}
MapleCashidGenerator.freeCashId(petid);
}
}
}
@@ -2453,6 +2457,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
chrLock.unlock();
}
if (disease == MapleDisease.SEDUCE && chair.get() != 0) {
sitChair(0);
}
final List<Pair<MapleDisease, Integer>> debuff = Collections.singletonList(new Pair<>(disease, Integer.valueOf(skill.getX())));
client.announce(MaplePacketCreator.giveDebuff(debuff, skill));
@@ -2550,7 +2558,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void run() {
doHurtHp();
}
}, 10000, 10000 - lastHpTask);
}, ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL, ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL - lastHpTask);
}
public void resetHpDecreaseTask() {
@@ -2559,7 +2567,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
long lastHpTask = Server.getInstance().getCurrentTime() - lastHpDec;
startHpDecreaseTask((lastHpTask > 10000) ? 10000 : lastHpTask);
startHpDecreaseTask((lastHpTask > ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL) ? ServerConstants.MAP_DAMAGE_OVERTIME_INTERVAL : lastHpTask);
}
public void dropMessage(String message) {
@@ -2682,7 +2690,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
effLock.unlock();
}
long curTime = System.currentTimeMillis();
long curTime = Server.getInstance().getCurrentTime();
for(Entry<Integer, MapleCoolDownValueHolder> bel : es) {
MapleCoolDownValueHolder mcdvh = bel.getValue();
if(curTime >= mcdvh.startTime + mcdvh.length) {
@@ -5247,8 +5255,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
this.battleshipHp = (int) length;
addCooldown(skillid, 0, length);
} else {
int time = (int) ((length + starttime) - System.currentTimeMillis());
addCooldown(skillid, System.currentTimeMillis(), time);
long timeNow = Server.getInstance().getCurrentTime();
int time = (int) ((length + starttime) - timeNow);
addCooldown(skillid, timeNow, time);
}
}
@@ -5433,9 +5442,43 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
int grade = Math.min(Math.max(level, 30), 120) - 30;
fee += (grade * ServerConstants.BUYBACK_LEVEL_STACK_FEE);
if (ServerConstants.USE_BUYBACK_WITH_MESOS) fee *= ServerConstants.BUYBACK_MESO_MULTIPLIER;
return (int) Math.floor(fee);
}
public void showBuybackInfo() {
String s = "#eBUYBACK STATUS#n\r\n\r\nCurrent buyback fee: #b" + getBuybackFee() + " " + (ServerConstants.USE_BUYBACK_WITH_MESOS ? "mesos" : "NX") + "#k\r\n\r\n";
long timeNow = Server.getInstance().getCurrentTime();
boolean avail = true;
if (!isAlive()) {
long timeLapsed = timeNow - lastDeathtime;
long timeRemaining = ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000 - (timeLapsed + Math.max(0, getNextBuybackTime() - timeNow));
if (timeRemaining < 1) {
s += "Buyback #e#rUNAVAILABLE#k#n";
avail = false;
} else {
s += "Buyback countdown: #e#b" + getTimeRemaining(ServerConstants.BUYBACK_RETURN_MINUTES * 60 * 1000 - timeLapsed) + "#k#n";
}
s += "\r\n";
}
if (timeNow < getNextBuybackTime() && avail) {
s += "Buyback available in #r" + getTimeRemaining(getNextBuybackTime() - timeNow) + "#k";
s += "\r\n";
}
this.showHint(s);
}
private static String getTimeRemaining(long timeLeft) {
int seconds = (int) Math.floor(timeLeft / 1000) % 60;
int minutes = (int) Math.floor(timeLeft / (1000*60)) % 60;
return (minutes > 0 ? (String.format("%02d", minutes) + " minutes, ") : "") + String.format("%02d", seconds) + " seconds";
}
public boolean couldBuyback() { // Ronan's buyback system
long timeNow = Server.getInstance().getCurrentTime();
@@ -5447,16 +5490,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
long nextBuybacktime = getNextBuybackTime();
if (timeNow < nextBuybacktime) {
long timeLeft = nextBuybacktime - timeNow;
int seconds = (int) Math.floor(timeLeft / 1000) % 60;
int minutes = (int) Math.floor(timeLeft / (1000*60)) % 60;
this.dropMessage(5, "Next buyback available in " + (minutes > 0 ? (String.format("%02d", minutes) + " minutes, ") : "") + String.format("%02d", seconds) + " seconds.");
this.dropMessage(5, "Next buyback available in " + getTimeRemaining(timeLeft) + ".");
return false;
}
boolean usingMesos = ServerConstants.USE_BUYBACK_WITH_MESOS;
int fee = getBuybackFee();
if (usingMesos) fee *= ServerConstants.BUYBACK_MESO_MULTIPLIER;
if (!canBuyback(fee, usingMesos)) {
this.dropMessage(5, "You don't have " + fee + " " + (usingMesos ? "mesos" : "NX") + " to buyback.");
@@ -5528,7 +5567,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
public void leaveMap() {
controlled.clear();
visibleMapObjects.clear();
chair.set(0);
setChair(0);
if (hpDecreaseTask != null) {
hpDecreaseTask.cancel(false);
}
@@ -5710,7 +5749,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
if (ServerConstants.USE_PERFECT_PITCH && level >= 30) {
//milestones?
if (MapleInventoryManipulator.checkSpace(client, 4310000, (short) 1, "")) {
MapleInventoryManipulator.addById(client, 4310000, (short) 1);
MapleInventoryManipulator.addById(client, 4310000, (short) 1, "", -1);
}
} else if (level == 10) {
Runnable r = new Runnable() {
@@ -6452,7 +6491,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ps = con.prepareStatement("SELECT SkillID,StartTime,length FROM cooldowns WHERE charid = ?");
ps.setInt(1, ret.getId());
rs = ps.executeQuery();
long curTime = System.currentTimeMillis();
long curTime = Server.getInstance().getCurrentTime();
while (rs.next()) {
final int skillid = rs.getInt("SkillID");
final long length = rs.getLong("length"), startTime = rs.getLong("StartTime");
@@ -6534,7 +6573,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
ret.storage = MapleStorage.loadOrCreateFromDB(ret.accountid, ret.world);
int startHp = ret.hp, startMp = ret.mp;
ret.recalcLocalStats();
ret.reapplyLocalStats();
ret.changeHpMp(startHp, startMp, true);
//ret.resetBattleshipHp();
}
@@ -6651,7 +6690,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private void playerDead() {
cancelAllBuffs(false);
dispelDebuffs();
lastDeathtime = System.currentTimeMillis();
lastDeathtime = Server.getInstance().getCurrentTime();
EventInstanceManager eim = getEventInstance();
if (eim != null) {
@@ -6702,14 +6741,53 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
cancelEffectFromBuffStat(MapleBuffStat.MONSTER_RIDING);
}
if (getChair() != 0) {
setChair(0);
client.announce(MaplePacketCreator.cancelChair(-1));
getMap().broadcastMessage(this, MaplePacketCreator.showChair(getId(), 0), false);
}
unsitChairInternal();
client.announce(MaplePacketCreator.enableActions());
}
private void unsitChairInternal() {
if (chair.get() != 0) {
setChair(0);
if (unregisterChairBuff()) {
getMap().broadcastMessage(this, MaplePacketCreator.cancelForeignChairSkillEffect(this.getId()), false);
}
getMap().broadcastMessage(this, MaplePacketCreator.showChair(this.getId(), 0), false);
}
announce(MaplePacketCreator.cancelChair(-1));
}
public void sitChair(int itemId) {
if (client.tryacquireClient()) {
try {
if (itemId >= 1000000) { // sit on item chair
if (chair.get() == 0) {
setChair(itemId);
getMap().broadcastMessage(this, MaplePacketCreator.showChair(this.getId(), itemId), false);
}
announce(MaplePacketCreator.enableActions());
} else if (itemId != 0) { // sit on map chair
if (chair.get() == 0) {
setChair(itemId);
if (registerChairBuff()) {
getMap().broadcastMessage(this, MaplePacketCreator.giveForeignChairSkillEffect(this.getId()), false);
}
announce(MaplePacketCreator.cancelChair(itemId));
}
} else { // stand up
unsitChairInternal();
}
} finally {
client.releaseClient();
}
}
}
private void setChair(int chair) {
this.chair.set(chair);
}
public void respawn(int returnMap) {
respawn(null, returnMap); // unspecified EIM, don't force EIM unregister in this case
}
@@ -6780,15 +6858,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
localwatk += equipwatk;
}
private List<Pair<MapleStat, Integer>> recalcLocalStats() {
private void reapplyLocalStats() {
effLock.lock();
chrLock.lock();
statWlock.lock();
try {
List<Pair<MapleStat, Integer>> hpmpupdate = new ArrayList<>(2);
int oldlocalmaxhp = localmaxhp;
int oldlocalmaxmp = localmaxmp;
localmaxhp = getMaxHp();
localmaxmp = getMaxMp();
localdex = getDex();
@@ -6815,11 +6889,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
localmaxhp = Math.min(30000, localmaxhp);
localmaxmp = Math.min(30000, localmaxmp);
if (ServerConstants.USE_FIXED_RATIO_HPMP_UPDATE) {
if (localmaxhp != oldlocalmaxhp) hpmpupdate.add(calcHpRatioUpdate(localmaxhp, oldlocalmaxhp));
if (localmaxmp != oldlocalmaxmp) hpmpupdate.add(calcMpRatioUpdate(localmaxmp, oldlocalmaxmp));
}
MapleStatEffect combo = getBuffEffect(MapleBuffStat.ARAN_COMBO);
if (combo != null) {
localwatk += combo.getX();
@@ -6906,10 +6975,54 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
// Add throwing stars to dmg.
}
} finally {
statWlock.unlock();
chrLock.unlock();
effLock.unlock();
}
}
private List<Pair<MapleStat, Integer>> recalcLocalStats() {
effLock.lock();
chrLock.lock();
statWlock.lock();
try {
List<Pair<MapleStat, Integer>> hpmpupdate = new ArrayList<>(2);
int oldlocalmaxhp = localmaxhp;
int oldlocalmaxmp = localmaxmp;
reapplyLocalStats();
if (ServerConstants.USE_FIXED_RATIO_HPMP_UPDATE) {
if (localmaxhp != oldlocalmaxhp) {
Pair<MapleStat, Integer> hpUpdate;
if (transienthp == Float.NEGATIVE_INFINITY) {
hpUpdate = calcHpRatioUpdate(localmaxhp, oldlocalmaxhp);
} else {
hpUpdate = calcHpRatioTransient();
}
hpmpupdate.add(hpUpdate);
}
if (localmaxmp != oldlocalmaxmp) {
Pair<MapleStat, Integer> mpUpdate;
if (transientmp == Float.NEGATIVE_INFINITY) {
mpUpdate = calcMpRatioUpdate(localmaxmp, oldlocalmaxmp);
} else {
mpUpdate = calcMpRatioTransient();
}
hpmpupdate.add(mpUpdate);
}
}
return hpmpupdate;
} finally {
statWlock.unlock();
chrLock.unlock();
effLock.unlock();
}
}
@@ -7789,10 +7902,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
}
}
public void setChair(int chair) {
this.chair.set(chair);
}
public void setChalkboard(String text) {
this.chalktext = text;
}
@@ -7968,7 +8077,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private Pair<MapleStat, Integer> calcHpRatioUpdate(int newHp, int oldHp) {
int delta = newHp - oldHp;
this.hp = calcHpMpRatioUpdate(hp, oldHp, delta);
this.hp = calcHpRatioUpdate(hp, oldHp, delta);
hpChangeAction(Short.MIN_VALUE);
return new Pair<>(MapleStat.HP, hp);
@@ -7976,19 +8085,47 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
private Pair<MapleStat, Integer> calcMpRatioUpdate(int newMp, int oldMp) {
int delta = newMp - oldMp;
this.mp = calcHpMpRatioUpdate(mp, oldMp, delta);
this.mp = calcMpRatioUpdate(mp, oldMp, delta);
return new Pair<>(MapleStat.MP, mp);
}
private static int calcHpMpRatioUpdate(int curpoint, int maxpoint, int diffpoint) {
private static int calcTransientRatio(float transientpoint) {
int ret = (int) transientpoint;
return !(ret <= 0 && transientpoint > 0.0f) ? ret : 1;
}
private Pair<MapleStat, Integer> calcHpRatioTransient() {
this.hp = calcTransientRatio(transienthp * localmaxhp);
hpChangeAction(Short.MIN_VALUE);
return new Pair<>(MapleStat.HP, hp);
}
private Pair<MapleStat, Integer> calcMpRatioTransient() {
this.mp = calcTransientRatio(transientmp * localmaxmp);
return new Pair<>(MapleStat.MP, mp);
}
private int calcHpRatioUpdate(int curpoint, int maxpoint, int diffpoint) {
int curMax = maxpoint;
int nextMax = Math.min(30000, maxpoint + diffpoint);
float temp = curpoint * nextMax;
int ret = (int) Math.round(temp / curMax);
int ret = (int) Math.ceil(temp / curMax);
//System.out.println("cur: " + curpoint + " next: " + ret + " max: " + curMax + " nextmax:" + nextMax + " diff: " + diffpoint);
return !(ret <= 0 && curpoint > 0) ? ret : 1;
transienthp = (maxpoint > nextMax) ? ((float) curpoint) / maxpoint : ((float) ret) / nextMax;
return ret;
}
private int calcMpRatioUpdate(int curpoint, int maxpoint, int diffpoint) {
int curMax = maxpoint;
int nextMax = Math.min(30000, maxpoint + diffpoint);
float temp = curpoint * nextMax;
int ret = (int) Math.ceil(temp / curMax);
transientmp = (maxpoint > nextMax) ? ((float) curpoint) / maxpoint : ((float) ret) / nextMax;
return ret;
}
public boolean applyHpMpChange(int hpCon, int hpchange, int mpchange) {
@@ -8137,7 +8274,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
doorSlot = -1;
party = null;
//cancelMagicDoor(); // cancel magic doors if kicked out / quitted from party.
} else {
party = p;
}
@@ -9083,10 +9219,26 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
pendantExp = 0;
}
private Collection<Item> getUpgradeableEquipList() {
Collection<Item> fullList = getInventory(MapleInventoryType.EQUIPPED).list();
if (ServerConstants.USE_EQUIPMNT_LVLUP_CASH) {
return fullList;
}
Collection<Item> eqpList = new LinkedHashSet<>();
for (Item it : fullList) {
if (!ii.isCash(it.getItemId())) {
eqpList.add(it);
}
}
return eqpList;
}
public void increaseEquipExp(int expGain) {
if(expGain < 0) expGain = Integer.MAX_VALUE;
for (Item item : getInventory(MapleInventoryType.EQUIPPED).list()) {
for (Item item : getUpgradeableEquipList()) {
Equip nEquip = (Equip) item;
String itemName = ii.getName(nEquip.getItemId());
if (itemName == null) {
+37 -6
View File
@@ -41,6 +41,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import tools.*;
@@ -109,8 +110,10 @@ public class MapleClient {
private String pic = null;
private String hwid = null;
private int picattempt = 0;
private byte csattempt = 0;
private byte gender = -1;
private boolean disconnecting = false;
private final Semaphore actionsSemaphore = new Semaphore(7);
private final Lock lock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT, true);
private final Lock encoderLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_ENCODER, true);
private static final Lock loginLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.CLIENT_LOGIN, true);
@@ -532,7 +535,6 @@ public class MapleClient {
gender = rs.getByte("gender");
characterSlots = rs.getByte("characterslots");
String passhash = rs.getString("password");
String salt = rs.getString("salt");
byte tos = rs.getByte("tos");
ps.close();
@@ -547,8 +549,9 @@ public class MapleClient {
loginok = 7;
} else if (passhash.charAt(0) == '$' && passhash.charAt(1) == '2' && BCrypt.checkpw(pwd, passhash)) {
loginok = (tos == 0) ? 23 : 0;
} else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd + salt)) {
loginok = (tos == 0) ? -23 : -10; // migrate to bcrypt
} else if (pwd.equals(passhash) || checkHash(passhash, "SHA-1", pwd) || checkHash(passhash, "SHA-512", pwd)) {
// thanks GabrielSin for detecting some no-bcrypt inconsistencies here
loginok = (tos == 0) ? (!ServerConstants.BCRYPT_MIGRATION ? 23 : -23) : (!ServerConstants.BCRYPT_MIGRATION ? 0 : -10); // migrate to bcrypt
} else {
loggedIn = false;
loginok = 4;
@@ -775,7 +778,7 @@ public class MapleClient {
if (!rs.next()) {
rs.close();
ps.close();
throw new RuntimeException("getLoginState - MapleClient");
throw new RuntimeException("getLoginState - MapleClient AccID: " + getAccID());
}
birthday = Calendar.getInstance();
@@ -1170,8 +1173,18 @@ public class MapleClient {
lock.unlock();
}
public boolean trylockClient() {
return lock.tryLock();
public boolean tryacquireClient() {
if (actionsSemaphore.tryAcquire()) {
lockClient();
return true;
} else {
return false;
}
}
public void releaseClient() {
unlockClient();
actionsSemaphore.release();
}
public void lockEncoder() {
@@ -1431,4 +1444,22 @@ public class MapleClient {
this.removeClickedNPC();
NPCScriptManager.getInstance().dispose(this);
}
public boolean attemptCsCoupon() {
if (csattempt > 2) {
resetCsCoupon();
return false;
}
csattempt++;
return true;
}
public void resetCsCoupon() {
csattempt = 0;
}
public void enableCSActions() {
announce(MaplePacketCreator.enableCSUse(player));
}
}
+25 -27
View File
@@ -25,8 +25,9 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import tools.Pair;
import tools.DatabaseConnection;
import client.inventory.manipulator.MapleCashidGenerator;
/**
*
@@ -86,6 +87,9 @@ public class MapleRing implements Comparable<MapleRing> {
ps.executeBatch();
ps.close();
MapleCashidGenerator.freeCashId(ring.getRingId());
MapleCashidGenerator.freeCashId(ring.getPartnerRingId());
ps = con.prepareStatement("UPDATE inventoryequipment SET ringid=-1 WHERE ringid=?");
ps.setInt(1, ring.getRingId());
ps.addBatch();
@@ -102,46 +106,40 @@ public class MapleRing implements Comparable<MapleRing> {
}
}
public static int createRing(int itemid, final MapleCharacter partner1, final MapleCharacter partner2) {
public static Pair<Integer, Integer> createRing(int itemid, final MapleCharacter partner1, final MapleCharacter partner2) {
try {
if (partner1 == null) {
return -2;
return new Pair<>(-3, -3);
} else if (partner2 == null) {
return -1;
return new Pair<>(-2, -2);
}
int[] ringID = new int[2];
ringID[0] = MapleCashidGenerator.generateCashId();
ringID[1] = MapleCashidGenerator.generateCashId();
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO rings (itemid, partnerChrId, partnername) VALUES (?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, itemid);
ps.setInt(2, partner2.getId());
ps.setString(3, partner2.getName());
PreparedStatement ps = con.prepareStatement("INSERT INTO rings (id, itemid, partnerRingId, partnerChrId, partnername) VALUES (?, ?, ?, ?, ?)");
ps.setInt(1, ringID[0]);
ps.setInt(2, itemid);
ps.setInt(3, ringID[1]);
ps.setInt(4, partner2.getId());
ps.setString(5, partner2.getName());
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
rs.next();
ringID[0] = rs.getInt(1); // ID.
rs.close();
ps.close();
ps = con.prepareStatement("INSERT INTO rings (itemid, partnerRingId, partnerChrId, partnername) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
ps.setInt(1, itemid);
ps.setInt(2, ringID[0]);
ps.setInt(3, partner1.getId());
ps.setString(4, partner1.getName());
ps.executeUpdate();
rs = ps.getGeneratedKeys();
rs.next();
ringID[1] = rs.getInt(1);
rs.close();
ps.close();
ps = con.prepareStatement("UPDATE rings SET partnerRingId = ? WHERE id = ?");
ps = con.prepareStatement("INSERT INTO rings (id, itemid, partnerRingId, partnerChrId, partnername) VALUES (?, ?, ?, ?, ?)");
ps.setInt(1, ringID[1]);
ps.setInt(2, ringID[0]);
ps.setInt(2, itemid);
ps.setInt(3, ringID[0]);
ps.setInt(4, partner1.getId());
ps.setString(5, partner1.getName());
ps.executeUpdate();
ps.close();
con.close();
return ringID[0];
return new Pair<>(ringID[0], ringID[1]);
} catch (SQLException ex) {
ex.printStackTrace();
return -1;
return new Pair<>(-1, -1);
}
}
+4 -3
View File
@@ -8,6 +8,7 @@ package client.autoban;
import client.MapleCharacter;
import java.util.HashMap;
import java.util.Map;
import net.server.Server;
import tools.FilePrinter;
/**
@@ -35,12 +36,12 @@ public class AutobanManager {
return;
}
if (lastTime.containsKey(fac)) {
if (lastTime.get(fac) < (System.currentTimeMillis() - fac.getExpire())) {
if (lastTime.get(fac) < (Server.getInstance().getCurrentTime() - fac.getExpire())) {
points.put(fac, points.get(fac) / 2); //So the points are not completely gone.
}
}
if (fac.getExpire() != -1)
lastTime.put(fac, System.currentTimeMillis());
lastTime.put(fac, Server.getInstance().getCurrentTime());
if (points.containsKey(fac)) {
points.put(fac, points.get(fac) + 1);
@@ -76,7 +77,7 @@ public class AutobanManager {
//Don't use the same type for more than 1 thing
public void spam(int type) {
this.spam[type] = System.currentTimeMillis();
this.spam[type] = Server.getInstance().getCurrentTime();
}
public void spam(int type, int timestamp) {
+2
View File
@@ -162,6 +162,7 @@ public class CommandsExecutor {
addCommand("droplimit", DropLimitCommand.class);
addCommand("time", TimeCommand.class);
addCommand("credits", StaffCommand.class);
addCommand("buyback", BuyBackCommand.class);
addCommand("uptime", UptimeCommand.class);
addCommand("gacha", GachaCommand.class);
addCommand("dispose", DisposeCommand.class);
@@ -345,6 +346,7 @@ public class CommandsExecutor {
addCommand("shutdown", 6, ShutdownCommand.class);
addCommand("clearquestcache", 6, ClearQuestCacheCommand.class);
addCommand("clearquest", 6, ClearQuestCommand.class);
addCommand("supplyratecoupon", 6, SupplyRateCouponCommand.class);
addCommand("spawnallpnpcs", 6, SpawnAllPNpcsCommand.class);
addCommand("eraseallpnpcs", 6, EraseAllPNpcsCommand.class);
addCommand("addchannel", 6, ServerAddChannelCommand.class);
@@ -30,6 +30,15 @@ import client.processor.BuybackProcessor;
public class BuyBackCommand extends Command {
@Override
public void execute(MapleClient c, String[] params) {
if (params.length < 1) {
c.getPlayer().yellowMessage("Syntax: @buyback <info|now>");
return;
}
if (params[0].contentEquals("now")) {
BuybackProcessor.processBuyback(c);
} else {
c.getPlayer().showBuybackInfo();
}
}
}
@@ -39,7 +39,7 @@ public class StatDexCommand extends Command {
int remainingAp = player.getRemainingAp();
int amount = (params.length > 0) ? Math.min(Integer.parseInt(params[0]), remainingAp) : Math.min(remainingAp, ServerConstants.MAX_AP - player.getDex());
if (!player.assignDex(amount)) {
if (!player.assignDex(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
}
}
@@ -39,7 +39,7 @@ public class StatIntCommand extends Command {
int remainingAp = player.getRemainingAp();
int amount = (params.length > 0) ? Math.min(Integer.parseInt(params[0]), remainingAp) : Math.min(remainingAp, ServerConstants.MAX_AP - player.getInt());
if (!player.assignInt(amount)) {
if (!player.assignInt(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
}
}
@@ -39,7 +39,7 @@ public class StatLukCommand extends Command {
int remainingAp = player.getRemainingAp();
int amount = (params.length > 0) ? Math.min(Integer.parseInt(params[0]), remainingAp) : Math.min(remainingAp, ServerConstants.MAX_AP - player.getLuk());
if (!player.assignLuk(amount)) {
if (!player.assignLuk(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
}
}
@@ -39,7 +39,7 @@ public class StatStrCommand extends Command {
int remainingAp = player.getRemainingAp();
int amount = (params.length > 0) ? Math.min(Integer.parseInt(params[0]), remainingAp) : Math.min(remainingAp, ServerConstants.MAX_AP - player.getStr());
if (!player.assignStr(amount)) {
if (!player.assignStr(Math.max(amount, 0))) {
player.dropMessage("Please make sure your AP is not over " + ServerConstants.MAX_AP + " and you have enough to distribute.");
}
}
@@ -49,6 +49,9 @@ public class WhoDropsCommand extends Command {
player.dropMessage(5, "Please do @whodrops <item name>");
return;
}
if (c.tryacquireClient()) {
try {
String searchString = joinStringFrom(params, 0);
String output = "";
Iterator<Pair<Integer, String>> listIterator = MapleItemInformationProvider.getInstance().getItemDataByName(searchString).iterator();
@@ -84,5 +87,11 @@ public class WhoDropsCommand extends Command {
return;
}
c.announce(MaplePacketCreator.getNPCTalk(9010000, (byte) 0, output, "00 00", (byte) 0));
} finally {
c.releaseClient();
}
} else {
player.dropMessage(5, "Please wait a while for your request to be processed.");
}
}
}
@@ -93,7 +93,6 @@ public class ItemDropCommand extends Command {
}
}
Item toDrop;
if (ItemConstants.getInventoryType(itemId) == MapleInventoryType.EQUIP) {
toDrop = ii.getEquipById(itemId);
@@ -37,8 +37,19 @@ import tools.Pair;
import java.io.File;
public class SearchCommand extends Command {
private static MapleData npcStringData;
private static MapleData mobStringData;
private static MapleData skillStringData;
private static MapleData mapStringData;
{
setDescription("");
MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz"));
npcStringData = dataProvider.getData("Npc.img");
mobStringData = dataProvider.getData("Mob.img");
skillStringData = dataProvider.getData("Skill.img");
mapStringData = dataProvider.getData("Map.img");
}
@Override
@@ -53,28 +64,45 @@ public class SearchCommand extends Command {
String search = joinStringFrom(params,1);
long start = System.currentTimeMillis();//for the lulz
MapleData data = null;
MapleDataProvider dataProvider = MapleDataProviderFactory.getDataProvider(new File("wz/String.wz"));
if (!params[0].equalsIgnoreCase("ITEM")) {
boolean mapSearch = false;
if (params[0].equalsIgnoreCase("NPC")) {
data = dataProvider.getData("Npc.img");
data = npcStringData;
} else if (params[0].equalsIgnoreCase("MOB") || params[0].equalsIgnoreCase("MONSTER")) {
data = dataProvider.getData("Mob.img");
data = mobStringData;
} else if (params[0].equalsIgnoreCase("SKILL")) {
data = dataProvider.getData("Skill.img");
/*} else if (sub[1].equalsIgnoreCase("MAP")) {
TODO
*/
data = skillStringData;
} else if (params[0].equalsIgnoreCase("MAP")) {
data = mapStringData;
mapSearch = true;
} else {
sb.append("#bInvalid search.\r\nSyntax: '!search [type] [name]', where [type] is NPC, ITEM, MOB, or SKILL.");
sb.append("#bInvalid search.\r\nSyntax: '!search [type] [name]', where [type] is MAP, NPC, ITEM, MOB, or SKILL.");
}
if (data != null) {
String name;
if (!mapSearch) {
for (MapleData searchData : data.getChildren()) {
name = MapleDataTool.getString(searchData.getChildByPath("name"), "NO-NAME");
if (name.toLowerCase().contains(search.toLowerCase())) {
sb.append("#b").append(Integer.parseInt(searchData.getName())).append("#k - #r").append(name).append("\r\n");
}
}
} else {
String mapName, streetName;
for (MapleData searchDataDir : data.getChildren()) {
for (MapleData searchData : searchDataDir.getChildren()) {
mapName = MapleDataTool.getString(searchData.getChildByPath("mapName"), "NO-NAME");
streetName = MapleDataTool.getString(searchData.getChildByPath("streetName"), "NO-NAME");
if (mapName.toLowerCase().contains(search.toLowerCase()) || streetName.toLowerCase().contains(search.toLowerCase())) {
sb.append("#b").append(Integer.parseInt(searchData.getName())).append("#k - #r").append(streetName).append(" - ").append(mapName).append("\r\n");
}
}
}
}
}
} else {
for (Pair<Integer, String> itemPair : MapleItemInformationProvider.getInstance().getAllItems()) {
@@ -17,25 +17,27 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
@Author: Arthur L - Refactored command content into modules
*/
package client.command.commands.gm6;
import client.command.Command;
import client.MapleClient;
import client.MapleCharacter;
import tools.MaplePacketCreator;
import client.MapleClient;
import client.command.Command;
import constants.ServerConstants;
public class FredCommand extends Command {
public class SupplyRateCouponCommand extends Command {
{
setDescription("");
}
@Override
public void execute(MapleClient c, String[] params) {
c.announce(MaplePacketCreator.fredrickMessage(Byte.valueOf(params[0])));
MapleCharacter player = c.getPlayer();
if (params.length < 1) {
player.dropMessage(5, "Syntax: !supplyratecoupon <yes|no>");
return;
}
ServerConstants.USE_SUPPLY_RATE_COUPONS = params[0].compareToIgnoreCase("no") != 0;
player.dropMessage(5, "Rate coupons are now " + (ServerConstants.USE_SUPPLY_RATE_COUPONS ? "enabled" : "disabled") + " for purchase at the Cash Shop.");
}
}
+8 -2
View File
@@ -26,10 +26,12 @@ import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import client.inventory.manipulator.MapleKarmaManipulator;
import server.MapleItemInformationProvider;
public class Item implements Comparable<Item> {
private static AtomicInteger runningCashId = new AtomicInteger(0);
private static AtomicInteger runningCashId = new AtomicInteger(777000000); // pets & rings shares cashid values
private int id, cashId, sn;
private short position;
@@ -83,7 +85,7 @@ public class Item implements Comparable<Item> {
public int getCashId() {
if (cashId == 0) {
cashId = runningCashId.incrementAndGet();
cashId = runningCashId.getAndIncrement();
}
return cashId;
}
@@ -177,4 +179,8 @@ public class Item implements Comparable<Item> {
public MaplePet getPet() {
return pet;
}
public boolean isUntradeable() {
return ((this.getFlag() & ItemConstants.UNTRADEABLE) == ItemConstants.UNTRADEABLE) || (MapleItemInformationProvider.getInstance().isDropRestricted(this.getItemId()) && !MapleKarmaManipulator.hasKarmaFlag(this));
}
}
+14 -20
View File
@@ -21,7 +21,6 @@
*/
package client.inventory;
import com.mysql.jdbc.Statement;
import constants.ExpTable;
import java.awt.Point;
import java.sql.PreparedStatement;
@@ -34,6 +33,7 @@ import server.movement.AbsoluteLifeMovement;
import server.movement.LifeMovement;
import server.movement.LifeMovementFragment;
import client.MapleCharacter;
import client.inventory.manipulator.MapleCashidGenerator;
import java.sql.Connection;
import tools.MaplePacketCreator;
import tools.Pair;
@@ -90,6 +90,8 @@ public class MaplePet extends Item {
ps.executeUpdate();
ps.close();
con.close();
MapleCashidGenerator.freeCashId(this.getUniqueId());
} catch (SQLException ex) {
ex.printStackTrace();
}
@@ -116,15 +118,11 @@ public class MaplePet extends Item {
public static int createPet(int itemid) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (name, level, closeness, fullness, summoned) VALUES (?, 1, 0, 100, 0)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1, MapleItemInformationProvider.getInstance().getName(itemid));
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (petid, name, level, closeness, fullness, summoned) VALUES (?, ?, 1, 0, 100, 0)");
int ret = MapleCashidGenerator.generateCashId();
ps.setInt(1, ret);
ps.setString(2, MapleItemInformationProvider.getInstance().getName(itemid));
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
int ret = -1;
if (rs.next()) {
ret = rs.getInt(1);
}
rs.close();
ps.close();
con.close();
return ret;
@@ -137,18 +135,14 @@ public class MaplePet extends Item {
public static int createPet(int itemid, byte level, int closeness, int fullness) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (name, level, closeness, fullness, summoned) VALUES (?, ?, ?, ?, 0)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1, MapleItemInformationProvider.getInstance().getName(itemid));
ps.setByte(2, level);
ps.setInt(3, closeness);
ps.setInt(4, fullness);
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (petid, name, level, closeness, fullness, summoned) VALUES (?, ?, ?, ?, ?, 0)");
int ret = MapleCashidGenerator.generateCashId();
ps.setInt(1, ret);
ps.setString(2, MapleItemInformationProvider.getInstance().getName(itemid));
ps.setByte(3, level);
ps.setInt(4, closeness);
ps.setInt(5, fullness);
ps.executeUpdate();
ResultSet rs = ps.getGeneratedKeys();
int ret = -1;
if (rs.next()) {
ret = rs.getInt(1);
}
rs.close();
ps.close();
con.close();
return ret;
@@ -0,0 +1,104 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
package client.inventory.manipulator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;
import tools.DatabaseConnection;
/**
*
* @author RonanLana
*/
public class MapleCashidGenerator {
private final static Set<Integer> existentCashids = new HashSet<>(10000);
private static Integer runningCashid = 0;
private static void loadExistentCashIdsFromQuery(Connection con, String query) throws SQLException {
PreparedStatement ps = con.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
existentCashids.add(rs.getInt(1));
}
rs.close();
ps.close();
}
public static synchronized void loadExistentCashIdsFromDb() {
Connection con = null;
try {
con = DatabaseConnection.getConnection();
loadExistentCashIdsFromQuery(con, "SELECT id FROM rings");
loadExistentCashIdsFromQuery(con, "SELECT petid FROM pets");
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
try {
if (con != null && !con.isClosed()) {
con.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
runningCashid = 0;
do {
runningCashid++; // hopefully the id will never surpass the allotted amount for pets/rings?
} while (existentCashids.contains(runningCashid));
}
private static void getNextAvailableCashId() {
runningCashid++;
if (runningCashid >= 777000000) {
existentCashids.clear();
loadExistentCashIdsFromDb();
}
}
public static synchronized int generateCashId() {
while (true) {
if (!existentCashids.contains(runningCashid)) {
int ret = runningCashid;
getNextAvailableCashId();
// existentCashids.add(ret)... no need to do this since the wrap over already refetches already used cashids from the DB
return ret;
}
getNextAvailableCashId();
}
}
public static synchronized void freeCashId(int cashId) {
existentCashids.remove(cashId);
}
}
@@ -520,17 +520,19 @@ public class MapleInventoryManipulator {
//1112413, 1112414, 1112405 (Lilin's Ring)
source = (Equip) eqpInv.getItem(src);
Equip target = (Equip) eqpdInv.getItem(dst);
eqpInv.removeSlot(src);
if (target != null) {
Equip target;
eqpdInv.lockInventory();
try {
target = (Equip) eqpdInv.getItem(dst);
if (target != null) {
chr.unequippedItem(target);
eqpdInv.removeSlot(dst);
}
} finally {
eqpdInv.unlockInventory();
}
}
final List<ModifyInventory> mods = new ArrayList<>();
if (itemChanged) {
@@ -705,7 +707,7 @@ public class MapleInventoryManipulator {
}
private static boolean isDroppedItemRestricted(Item it) {
return ServerConstants.USE_ERASE_UNTRADEABLE_DROP && ((it.getFlag() & ItemConstants.UNTRADEABLE) == ItemConstants.UNTRADEABLE);
return ServerConstants.USE_ERASE_UNTRADEABLE_DROP && it.isUntradeable();
}
public static boolean isSandboxItem(Item it) {
+1 -1
View File
@@ -43,7 +43,7 @@ public class AssignSPProcessor {
c.lockClient();
try {
if (skillid == Aran.HIDDEN_FULL_DOUBLE || skillid == Aran.HIDDEN_FULL_TRIPLE || skillid == Aran.HIDDEN_OVER_DOUBLE || skillid == Aran.HIDDEN_OVER_TRIPLE) {
c.getSession().write(MaplePacketCreator.enableActions());
c.announce(MaplePacketCreator.enableActions());
return;
}
@@ -21,16 +21,13 @@ package client.processor;
import client.MapleClient;
import client.MapleCharacter;
import client.MapleStat;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import server.maps.MapleMap;
import server.movement.AbsoluteLifeMovement;
import server.movement.LifeMovementFragment;
import tools.MaplePacketCreator;
import tools.Pair;
/**
*
+12 -8
View File
@@ -345,7 +345,7 @@ public class DueyProcessor {
}
public static void dueySendItem(MapleClient c, byte inventId, short itemPos, short amount, int mesos, String recipient) {
c.lockClient();
if (c.tryacquireClient()) {
try {
final int fee = 5000;
final long sendMesos = (long) mesos + fee;
@@ -417,22 +417,24 @@ public class DueyProcessor {
showDueyNotification(rClient, rClient.getPlayer());
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
public static void dueyRemovePackage(MapleClient c, int packageid) {
c.lockClient();
if (c.tryacquireClient()) {
try {
removeItemFromDB(packageid);
c.announce(MaplePacketCreator.removeItemFromDuey(true, packageid));
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
public static void dueyClaimPackage(MapleClient c, int packageid) {
c.lockClient();
if (c.tryacquireClient()) {
try {
List<DueyPackages> packages = new LinkedList<>();
DueyPackages dp = null;
@@ -496,16 +498,18 @@ public class DueyProcessor {
e.printStackTrace();
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
public static void dueySendTalk(MapleClient c) {
c.lockClient();
if (c.tryacquireClient()) {
try {
c.announce(MaplePacketCreator.sendDuey((byte) 8, loadItems(c.getPlayer())));
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
}
+3 -2
View File
@@ -70,7 +70,7 @@ public class FredrickProcessor {
}
public static void fredrickRetrieveItems(MapleClient c) { // thanks Gustav for pointing out the dupe on Fredrick handling
c.lockClient();
if (c.tryacquireClient()) {
try {
MapleCharacter chr = c.getPlayer();
@@ -105,7 +105,8 @@ public class FredrickProcessor {
ex.printStackTrace();
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
}
+3 -3
View File
@@ -26,7 +26,6 @@ import client.inventory.MapleInventoryType;
import constants.ItemConstants;
import constants.ServerConstants;
import client.inventory.manipulator.MapleInventoryManipulator;
import constants.EquipType;
import constants.GameConstants;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -47,7 +46,7 @@ public class MakerProcessor {
private static MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
public static void makerAction(SeekableLittleEndianAccessor slea, MapleClient c) {
c.lockClient();
if (c.tryacquireClient()) {
try {
int type = slea.readInt();
int toCreate = slea.readInt();
@@ -208,7 +207,8 @@ public class MakerProcessor {
}
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
+3 -2
View File
@@ -40,7 +40,7 @@ public class SpawnPetProcessor {
private static MapleDataProvider dataRoot = MapleDataProviderFactory.getDataProvider(new File(System.getProperty("wzpath") + "/Item.wz"));
public static void processSpawnPet(MapleClient c, byte slot, boolean lead) {
c.lockClient();
if (c.tryacquireClient()) {
try {
MapleCharacter chr = c.getPlayer();
MaplePet pet = chr.getInventory(MapleInventoryType.CASH).getItem(slot).getPet();
@@ -93,7 +93,8 @@ public class SpawnPetProcessor {
chr.getClient().getWorldServer().registerPetHunger(chr, chr.getPetIndex(pet));
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
}
+5 -4
View File
@@ -54,7 +54,7 @@ public class StorageProcessor {
return;
}
c.lockClient();
if (c.tryacquireClient()) {
try {
if (mode == 4) { // take out
byte type = slea.readByte();
@@ -145,13 +145,13 @@ public class StorageProcessor {
int playerMesos = chr.getMeso();
if ((meso > 0 && storageMesos >= meso) || (meso < 0 && playerMesos >= -meso)) {
if (meso < 0 && (storageMesos - meso) < 0) {
meso = -2147483648 + storageMesos;
meso = Integer.MIN_VALUE + storageMesos;
if (meso < playerMesos) {
c.announce(MaplePacketCreator.enableActions());
return;
}
} else if (meso > 0 && (playerMesos + meso) < 0) {
meso = 2147483647 - playerMesos;
meso = Integer.MAX_VALUE - playerMesos;
if (meso > storageMesos) {
c.announce(MaplePacketCreator.enableActions());
return;
@@ -170,7 +170,8 @@ public class StorageProcessor {
storage.close();
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
}
+5 -1
View File
@@ -54,6 +54,7 @@ public class ServerConstants {
public static final boolean USE_DEBUG = false; //Will enable some text prints on the client, oriented for debugging purposes.
public static final boolean USE_DEBUG_SHOW_INFO_EQPEXP = false; //Prints on the cmd all equip exp gain info.
public static boolean USE_DEBUG_SHOW_RCVD_PACKET = false; //Prints on the cmd all received packet ids.
public static boolean USE_SUPPLY_RATE_COUPONS = true; //Allows rate coupons to be sold through the Cash Shop.
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;
@@ -104,6 +105,7 @@ public class ServerConstants {
//Cash Shop Configuration
public static final boolean USE_JOINT_CASHSHOP_INVENTORY = true;//Enables usage of a same cash shop inventory for explorers, cygnus and legends. Items from exclusive cash shop inventories won't show up on the shared inventory, though.
public static final boolean USE_CLEAR_OUTDATED_COUPONS = true; //Enables deletion of older code coupon registry from the DB, freeing so-long irrelevant data.
//Maker Configuration
public static final boolean USE_MAKER_PERMISSIVE_ATKUP = true; //Allows players to use attack-based strengthening gems on non-weapon items.
@@ -149,6 +151,7 @@ public class ServerConstants {
public static final int ITEM_EXPIRE_CHECK = 10 * 1000; //Interval between item expiring tasks on maps, which checks and makes disappear expired items.
public static final int ITEM_LIMIT_ON_MAP = 200; //Max number of items allowed on a map.
public static final int MAP_VISITED_SIZE = 5; //Max length for last mapids visited by a player. This is used to recover and update drops on these maps accordingly with player actions.
public static final int MAP_DAMAGE_OVERTIME_INTERVAL = 5000;//Interval in seconds between map environment damage (e.g. El Nath and Aqua Road surrondings).
//Channel Mob Disease Monitor Configuration
public static final int MOB_STATUS_MONITOR_PROC = 200; //Frequency in milliseconds between each proc on the mob disease monitor schedule.
@@ -172,7 +175,7 @@ public class ServerConstants {
//Other Skills Configuration
public static final boolean USE_FAST_REUSE_HERO_WILL = true;//Greatly reduce cooldown on Hero's Will.
public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs.
public static final boolean USE_ANTI_IMMUNITY_CRASH = true; //Crash skills additionally removes the mob's invincibility buffs. Suggestion thanks to Celestial.
public static final boolean USE_UNDISPEL_HOLY_SHIELD = true;//Holy shield buff also prevents players from suffering dispel from mobs.
//Character Configuration
@@ -200,6 +203,7 @@ public class ServerConstants {
//Equipment Configuration
public static final boolean USE_EQUIPMNT_LVLUP_SLOTS = true;//Equips can upgrade slots at level up.
public static final boolean USE_EQUIPMNT_LVLUP_POWER = true;//Enable more powerful stat upgrades at equip level up.
public static final boolean USE_EQUIPMNT_LVLUP_CASH = true; //Enable equip leveling up on cash equipments as well.
public static final boolean USE_SPIKES_AVOID_BANISH = true; //Shoes equipped with spikes prevents mobs from banishing wearer.
public static final int MAX_EQUIPMNT_LVLUP_STAT_UP = 10000; //Max stat upgrade an equipment can have on a levelup.
public static final int MAX_EQUIPMNT_STAT = 32767; //Max stat on an equipment by leveling up.
-1
View File
@@ -33,6 +33,5 @@ public class SuperGM {
public static final int HIDE = 9101004;
public static final int RESURRECTION = 9101005;
public static final int SUPER_DRAGON_ROAR = 9001001;
public static final int TELEPORT = 9101007;
public static final int HYPER_BODY = 9101008;
}
+33 -12
View File
@@ -80,6 +80,7 @@ import client.MapleCharacter;
import client.SkillFactory;
import client.inventory.Item;
import client.inventory.ItemFactory;
import client.inventory.manipulator.MapleCashidGenerator;
import client.newyear.NewYearCardRecord;
import constants.ItemConstants;
import constants.GameConstants;
@@ -90,7 +91,6 @@ import server.life.MaplePlayerNPCFactory;
import server.quest.MapleQuest;
import tools.AutoJCE;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.Pair;
public class Server {
@@ -518,6 +518,34 @@ public class Server {
return couponRates;
}
public static void cleanNxcodeCoupons(Connection con) throws SQLException {
if (!ServerConstants.USE_CLEAR_OUTDATED_COUPONS) return;
long timeClear = System.currentTimeMillis() - 14 * 24 * 60 * 60 * 1000;
PreparedStatement ps = con.prepareStatement("SELECT * FROM nxcode WHERE expiration <= ?");
ps.setLong(1, timeClear);
ResultSet rs = ps.executeQuery();
if (!rs.isLast()) {
PreparedStatement ps2 = con.prepareStatement("DELETE FROM nxcode_items WHERE codeid = ?");
while (rs.next()) {
ps2.setInt(1, rs.getInt("id"));
ps2.addBatch();
}
ps2.executeBatch();
ps2.close();
ps2 = con.prepareStatement("DELETE FROM nxcode WHERE expiration <= ?");
ps2.setLong(1, timeClear);
ps2.executeUpdate();
ps2.close();
}
rs.close();
ps.close();
}
private void loadCouponRates(Connection c) throws SQLException {
PreparedStatement ps = c.prepareStatement("SELECT couponid, rate FROM nxcoupons");
ResultSet rs = ps.executeQuery();
@@ -818,6 +846,7 @@ public class Server {
ps.executeUpdate();
ps.close();
cleanNxcodeCoupons(c);
loadCouponRates(c);
updateActiveCoupons();
@@ -825,6 +854,9 @@ public class Server {
} catch (SQLException sqle) {
sqle.printStackTrace();
}
MapleCashidGenerator.loadExistentCashIdsFromDb();
IoBuffer.setUseDirectBuffer(false);
IoBuffer.setAllocator(new SimpleBufferAllocator());
acceptor = new NioSocketAcceptor();
@@ -893,17 +925,6 @@ public class Server {
online = true;
}
public void shutdown() {
try {
TimerManager.getInstance().stop();
acceptor.unbind();
} catch (NullPointerException e) {
FilePrinter.printError(FilePrinter.EXCEPTION_CAUGHT, e);
}
System.out.println("Server offline.");
System.exit(0);// BOEIEND :D
}
public static void main(String args[]) {
System.setProperty("wzpath", "wz");
Security.setProperty("crypto.policy", "unlimited");
+21 -6
View File
@@ -198,6 +198,7 @@ public final class Channel {
System.out.println("Shutting down Channel " + channel + " on World " + world);
closeAllMerchants();
disconnectAwayPlayers();
players.disconnectAll();
if(respawnTask != null) {
@@ -314,6 +315,10 @@ public final class Channel {
return world;
}
public World getWorldServer() {
return Server.getInstance().getWorld(world);
}
public void addPlayer(MapleCharacter chr) {
players.addPlayer(chr);
chr.announce(MaplePacketCreator.serverMessage(serverMessage));
@@ -394,6 +399,16 @@ public final class Channel {
return players.getSize() == 0 && playersAway.isEmpty();
}
private void disconnectAwayPlayers() {
World wserv = getWorldServer();
for (Integer cid : playersAway) {
MapleCharacter chr = wserv.getPlayerStorage().getCharacterById(cid);
if (chr != null && chr.isLoggedin()) {
chr.getClient().disconnect(true, false);
}
}
}
public class respawnMaps implements Runnable {
@Override
@@ -465,7 +480,7 @@ public final class Channel {
public void setServerMessage(String message) {
this.serverMessage = message;
broadcastPacket(MaplePacketCreator.serverMessage(message));
Server.getInstance().getWorld(world).resetDisabledServerMessages();
getWorldServer().resetDisabledServerMessages();
}
private static String [] getEvents(){
@@ -692,7 +707,7 @@ public final class Channel {
lock.unlock();
}
World wserv = Server.getInstance().getWorld(world);
World wserv = getWorldServer();
Pair<Integer, Integer> coupleId = wserv.getMarriageQueuedCouple(ret);
Pair<Boolean, Set<Integer>> typeGuests = wserv.removeMarriageQueued(ret);
@@ -704,7 +719,7 @@ public final class Channel {
}
public boolean isWeddingReserved(Integer weddingId) {
World wserv = Server.getInstance().getWorld(world);
World wserv = getWorldServer();
lock.lock();
try {
@@ -746,7 +761,7 @@ public final class Channel {
public int pushWeddingReservation(Integer weddingId, boolean cathedral, boolean premium, Integer groomId, Integer brideId) {
if(weddingId == null || isWeddingReserved(weddingId)) return -1;
World wserv = Server.getInstance().getWorld(world);
World wserv = getWorldServer();
wserv.putMarriageQueued(weddingId, cathedral, premium, groomId, brideId);
lock.lock();
@@ -935,7 +950,7 @@ public final class Channel {
public Pair<Integer, Integer> getWeddingCoupleForGuest(int guestId, boolean cathedral) {
lock.lock();
try {
return (isOngoingWeddingGuest(cathedral, guestId)) ? Server.getInstance().getWorld(world).getRelationshipCouple(getOngoingWedding(cathedral)) : null;
return (isOngoingWeddingGuest(cathedral, guestId)) ? getWorldServer().getRelationshipCouple(getOngoingWedding(cathedral)) : null;
} finally {
lock.unlock();
}
@@ -1038,7 +1053,7 @@ public final class Channel {
public void debugMarriageStatus() {
System.out.println(" ----- WORLD DATA -----");
Server.getInstance().getWorld(world).debugMarriageStatus();
getWorldServer().debugMarriageStatus();
System.out.println(" ----- CH. " + channel + " -----");
System.out.println(" ----- CATHEDRAL -----");
@@ -24,7 +24,6 @@ package net.server.channel.handlers;
import client.MapleClient;
import client.MapleCharacter;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CancelChairHandler extends AbstractMaplePacketHandler {
@@ -35,21 +34,6 @@ public final class CancelChairHandler extends AbstractMaplePacketHandler {
MapleCharacter mc = c.getPlayer();
if(!mc.isLoggedinWorld()) return;
if (id == -1) { // Cancel Chair
mc.setChair(0);
if(mc.unregisterChairBuff()) {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.cancelForeignChairSkillEffect(mc.getId()), false);
}
c.announce(MaplePacketCreator.cancelChair(-1));
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showChair(c.getPlayer().getId(), 0), false);
} else { // Use In-Map Chair
mc.setChair(id);
if(mc.registerChairBuff()) {
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.giveForeignChairSkillEffect(mc.getId()), false);
}
c.announce(MaplePacketCreator.cancelChair(id));
}
mc.sitChair(id == -1 ? 0 : id);
}
}
@@ -38,8 +38,10 @@ import server.CashShop;
import server.CashShop.CashItem;
import server.CashShop.CashItemFactory;
import client.inventory.manipulator.MapleInventoryManipulator;
import constants.ServerConstants;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
public final class CashOperationHandler extends AbstractMaplePacketHandler {
@@ -62,18 +64,20 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
CashItem cItem = CashItemFactory.getItem(snCS);
if (!canBuy(cItem, cs.getCash(useNX))) {
FilePrinter.printError(FilePrinter.ITEM, "Denied to sell cash item with SN " + cItem.getSN());
c.announce(MaplePacketCreator.enableActions());
return;
}
if(ItemConstants.isCashStore(cItem.getItemId()) && chr.getLevel() < 16) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (action == 0x03) { // Item
if(ItemConstants.isMapleLife(cItem.getItemId()) && chr.getLevel() < 30) {
c.announce(MaplePacketCreator.enableActions());
if (ItemConstants.isCashStore(cItem.getItemId()) && chr.getLevel() < 16) {
c.enableCSActions();
return;
} else if (ItemConstants.isRateCoupon(cItem.getItemId()) && !ServerConstants.USE_SUPPLY_RATE_COUPONS) {
chr.dropMessage(1, "Rate coupons are currently unavailable to purchase.");
c.enableCSActions();
return;
} else if (ItemConstants.isMapleLife(cItem.getItemId()) && chr.getLevel() < 30) {
c.enableCSActions();
return;
}
@@ -95,20 +99,17 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
Map<String, String> recipient = MapleCharacter.getCharacterFromDatabase(slea.readMapleAsciiString());
String message = slea.readMapleAsciiString();
if (!canBuy(cItem, cs.getCash(4)) || message.length() < 1 || message.length() > 73) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (!checkBirthday(c, birthday)) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC4));
c.announce(MaplePacketCreator.enableActions());
return;
} else if (recipient == null) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA9));
c.announce(MaplePacketCreator.enableActions());
return;
} else if (recipient.get("accountid").equals(String.valueOf(c.getAccID()))) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xA8));
c.announce(MaplePacketCreator.enableActions());
return;
}
cs.gift(Integer.parseInt(recipient.get("id")), chr.getName(), message, cItem.getSN());
@@ -139,7 +140,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
if (mode == 0) {
byte type = slea.readByte();
if (cs.getCash(cash) < 4000) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (chr.gainSlots(type, 4, false)) {
@@ -151,7 +152,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
int type = (cItem.getItemId() - 9110000) / 1000;
if (!canBuy(cItem, cs.getCash(cash))) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (chr.gainSlots(type, 8, false)) {
@@ -166,7 +167,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
byte mode = slea.readByte();
if (mode == 0) {
if (cs.getCash(cash) < 4000) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (chr.getStorage().gainSlots(4)) {
@@ -181,7 +182,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
if (!canBuy(cItem, cs.getCash(cash))) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (chr.getStorage().gainSlots(8)) {
@@ -196,7 +197,7 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
CashItem cItem = CashItemFactory.getItem(slea.readInt());
if (!canBuy(cItem, cs.getCash(cash))) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
@@ -206,13 +207,13 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
c.announce(MaplePacketCreator.showCash(chr));
} else {
chr.dropMessage(1, "You have already used up all 12 extra character slots.");
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
} else if (action == 0x0D) { // Take from Cash Inventory
Item item = cs.findByCashId(slea.readInt());
if (item == null) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
if (chr.getInventory(item.getInventoryType()).addItem(item) != -1) {
@@ -240,11 +241,11 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
MapleInventory mi = chr.getInventory(MapleInventoryType.getByType(invType));
Item item = mi.findByCashId(cashId);
if (item == null) {
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
} else if(c.getPlayer().getPetIndex(item.getPetId()) > -1) {
chr.getClient().announce(MaplePacketCreator.serverNotice(1, "You cannot put the pet you currently equip into the Cash Shop inventory."));
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}
cs.addToInventory(item);
@@ -265,19 +266,19 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
/* if (partner.getGender() == chr.getGender()) {
chr.dropMessage("You and your partner are the same gender, please buy a friendship ring.");
c.announce(MaplePacketCreator.enableActions());
c.enableCSActions();
return;
}*/ //Gotta let them faggots marry too, hence why this is commented out <3
if(itemRing.toItem() instanceof Equip) {
Equip eqp = (Equip) itemRing.toItem();
int ringid = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(ringid);
Pair<Integer, Integer> rings = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID()));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), (ringid + 1));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
cs.gainCash(toCharge, itemRing, chr.getWorld());
chr.addCrushRing(MapleRing.loadFromDb(ringid));
chr.addCrushRing(MapleRing.loadFromDb(rings.getLeft()));
try {
chr.sendNote(partner.getName(), text, (byte) 1);
} catch (SQLException ex) {
@@ -288,17 +289,33 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
}
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC4));
c.announce(MaplePacketCreator.enableActions());
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
} else if (action == 0x20) { // everything is 1 meso...
int itemId = CashItemFactory.getItem(slea.readInt()).getItemId();
} else if (action == 0x20) {
int serialNumber = slea.readInt(); // thanks GabrielSin for detecting a potential exploit with 1 meso cash items.
if (serialNumber / 10000000 != 8) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC0));
return;
}
if (chr.getMeso() > 0) {
CashItem item = CashItemFactory.getItem(serialNumber);
if (item == null || !item.isOnSale()) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC0));
return;
}
int itemId = item.getItemId();
int itemPrice = item.getPrice();
if (itemPrice <= 0) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC0));
return;
}
if (chr.getMeso() >= itemPrice) {
if (chr.canHold(itemId)) {
chr.gainMeso(-1, false);
MapleInventoryManipulator.addById(c, itemId, (short) 1);
chr.gainMeso(-itemPrice, false);
MapleInventoryManipulator.addById(c, itemId, (short) 1, "", -1);
c.announce(MaplePacketCreator.showBoughtQuestItem(itemId));
}
}
@@ -321,13 +338,13 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
// Need to check to make sure its actually an equip and the right SN...
if(itemRing.toItem() instanceof Equip) {
Equip eqp = (Equip) itemRing.toItem();
int ringid = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(ringid);
Pair<Integer, Integer> rings = MapleRing.createRing(itemRing.getItemId(), chr, partner);
eqp.setRingId(rings.getLeft());
cs.addToInventory(eqp);
c.announce(MaplePacketCreator.showBoughtCashItem(eqp, c.getAccID()));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), (ringid + 1));
cs.gift(partner.getId(), chr.getName(), text, eqp.getSN(), rings.getRight());
cs.gainCash(payment, -itemRing.getPrice());
chr.addFriendshipRing(MapleRing.loadFromDb(ringid));
chr.addFriendshipRing(MapleRing.loadFromDb(rings.getLeft()));
try {
chr.sendNote(partner.getName(), text, (byte) 1);
} catch (SQLException ex) {
@@ -338,7 +355,6 @@ public final class CashOperationHandler extends AbstractMaplePacketHandler {
}
} else {
c.announce(MaplePacketCreator.showCashShopMessage((byte) 0xC4));
c.announce(MaplePacketCreator.enableActions());
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
@@ -50,7 +50,7 @@ public final class CloseRangeDamageHandler extends AbstractDealDamageHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
chr.setPetLootCd(currentServerTime());
//chr.setPetLootCd(currentServerTime());
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
@@ -4,6 +4,8 @@
Matthias Butz <matze@odinms.de>
Jan Christian Meyer <vimes@odinms.de>
Copyleft (L) 2016 - 2018 RonanLana (HeavenMS)
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
@@ -21,107 +23,228 @@
*/
package net.server.channel.handlers;
import java.sql.SQLException;
import client.MapleClient;
import client.MapleCharacter;
import client.inventory.Item;
import client.inventory.manipulator.MapleInventoryManipulator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import net.AbstractMaplePacketHandler;
import client.inventory.manipulator.MapleInventoryManipulator;
import net.server.Server;
import server.CashShop;
import server.MapleItemInformationProvider;
import tools.DatabaseConnection;
import tools.FilePrinter;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Penguins (Acrylic)
* @author Ronan (HeavenMS)
*/
public final class CouponCodeHandler extends AbstractMaplePacketHandler {
private static List<Pair<Integer, Pair<Integer, Integer>>> getNXCodeItems(MapleCharacter chr, Connection con, int codeid) throws SQLException {
Map<Integer, Integer> couponItems = new HashMap<>();
Map<Integer, Integer> couponPoints = new HashMap<>(5);
PreparedStatement ps = con.prepareStatement("SELECT * FROM nxcode_items WHERE codeid = ?");
ps.setInt(1, codeid);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
int type = rs.getInt("type"), item = rs.getInt("item");
if (type < 5) {
Integer i = couponPoints.get(type);
if (i != null) {
couponPoints.put(type, i + item);
} else {
couponPoints.put(type, item);
}
} else {
int quantity = rs.getInt("quantity");
Integer i = couponItems.get(item);
if (i != null) {
couponItems.put(item, i + quantity);
} else {
couponItems.put(item, quantity);
}
}
}
rs.close();
ps.close();
List<Pair<Integer, Pair<Integer, Integer>>> ret = new LinkedList<>();
if (!couponItems.isEmpty()) {
for (Entry<Integer, Integer> e : couponItems.entrySet()) {
int item = e.getKey(), qty = e.getValue();
if (MapleItemInformationProvider.getInstance().getName(item) == null) {
item = 4000000;
qty = 1;
FilePrinter.printError(FilePrinter.UNHANDLED_EVENT, "Error trying to redeem itemid " + item + " from codeid " + codeid + ".");
}
if (!chr.canHold(item, qty)) {
return null;
}
ret.add(new Pair<>(5, new Pair<>(item, qty)));
}
}
if (!couponPoints.isEmpty()) {
for (Entry<Integer, Integer> e : couponPoints.entrySet()) {
ret.add(new Pair<>(e.getKey(), new Pair<>(e.getValue(), 777)));
}
}
return ret;
}
private static Pair<Integer, List<Pair<Integer, Pair<Integer, Integer>>>> getNXCodeResult(MapleCharacter chr, String code) {
MapleClient c = chr.getClient();
List<Pair<Integer, Pair<Integer, Integer>>> ret = new LinkedList<>();
try {
if (!c.attemptCsCoupon()) {
return new Pair<>(-5, null);
}
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT * FROM nxcode WHERE code = ?");
ps.setString(1, code);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
return new Pair<>(-1, null);
}
if (rs.getString("retriever") != null) {
return new Pair<>(-2, null);
}
if (rs.getLong("expiration") < Server.getInstance().getCurrentTime()) {
return new Pair<>(-3, null);
}
int codeid = rs.getInt("id");
rs.close();
ps.close();
ret = getNXCodeItems(chr, con, codeid);
if (ret == null) {
return new Pair<>(-4, null);
}
ps = con.prepareStatement("UPDATE nxcode SET retriever = ? WHERE code = ?");
ps.setString(1, chr.getName());
ps.setString(2, code);
ps.executeUpdate();
ps.close();
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
c.resetCsCoupon();
return new Pair<>(0, ret);
}
private static int parseCouponResult(int res) {
switch (res) {
case -1:
return 0xB0;
case -2:
return 0xB3;
case -3:
return 0xB2;
case -4:
return 0xBB;
default:
return 0xB1;
}
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
slea.skip(2);
String code = slea.readMapleAsciiString();
boolean validcode = false;
int type = -1;
int item = -1;
validcode = getNXCodeValid(code.toUpperCase(), validcode);
if (validcode) {
type = getNXCode(code, "type");
item = getNXCode(code, "item");
if (type != 5) {
if (c.tryacquireClient()) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("UPDATE nxcode SET `valid` = 0 WHERE code = " + code);
ps.executeUpdate();
ps.close();
ps = con.prepareStatement("UPDATE nxcode SET `user` = ? WHERE code = ?");
ps.setString(1, c.getPlayer().getName());
ps.setString(2, code);
ps.executeUpdate();
ps.close();
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
Pair<Integer, List<Pair<Integer, Pair<Integer, Integer>>>> codeRes = getNXCodeResult(c.getPlayer(), code.toUpperCase());
int type = codeRes.getLeft();
if (type < 0) {
c.announce(MaplePacketCreator.showCashShopMessage((byte) parseCouponResult(type)));
} else {
List<Item> couponPackage = new LinkedList<>();
for (Pair<Integer, Pair<Integer, Integer>> p : codeRes.getRight()) {
type = p.getLeft();
int item = p.getRight().getLeft();
CashShop cs = c.getPlayer().getCashShop();
switch (type) {
case 0:
case 4:
cs.gainCash(1, item); //nxCredit
break;
case 1:
cs.gainCash(2, item); //maplePoint
break;
case 2:
c.getPlayer().getCashShop().gainCash(type, item);
cs.gainCash(4, item); //nxPrepaid
break;
case 3:
c.getPlayer().getCashShop().gainCash(0, item);
c.getPlayer().getCashShop().gainCash(2, (item / 5000));
cs.gainCash(1, item);
cs.gainCash(4, (item / 5000));
break;
case 4:
MapleInventoryManipulator.addById(c, item, (short) 1, null, -1, -1);
c.announce(MaplePacketCreator.showCouponRedeemedItem(item));
break;
case 5:
c.getPlayer().getCashShop().gainCash(0, item);
break;
}
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
default:
short qty = p.getRight().getRight().shortValue();
if (MapleItemInformationProvider.getInstance().isCash(item)) {
Item it = CashShop.generateCouponItem(item, qty);
cs.addToInventory(it);
couponPackage.add(it);
} else {
//c.announce(MaplePacketCreator.wrongCouponCode());
}
c.announce(MaplePacketCreator.enableCSUse());
MapleInventoryManipulator.addById(c, item, qty, "", -1);
}
private int getNXCode(String code, String type) {
int item = -1;
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT `" + type + "` FROM nxcode WHERE code = ?");
ps.setString(1, code);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
item = rs.getInt(type);
//c.announce(MaplePacketCreator.showCouponRedeemedItem(item));
break;
}
rs.close();
ps.close();
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
return item;
}
private boolean getNXCodeValid(String code, boolean validcode) {
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT `valid` FROM nxcode WHERE code = ?");
ps.setString(1, code);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
validcode = rs.getInt("valid") != 0;
if (!couponPackage.isEmpty()) {
c.announce(MaplePacketCreator.showBoughtCashPackage(couponPackage, c.getAccID()));
} else {
c.announce(MaplePacketCreator.showBoughtQuestItem(0));
}
c.enableCSActions();
}
} finally {
c.releaseClient();
}
rs.close();
ps.close();
con.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
return validcode;
}
}
@@ -111,7 +111,7 @@ public final class EnterMTSHandler extends AbstractMaplePacketHandler {
ex.printStackTrace();
}
chr.getCashShop().open(true);// xD
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.MTSWantedListingOver(0, 0));
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
List<MTSItemInfo> items = new ArrayList<>();
@@ -40,13 +40,13 @@ public final class FaceExpressionHandler extends AbstractMaplePacketHandler {
}
}
if(c.trylockClient()) {
if(c.tryacquireClient()) {
try { // expecting players never intends to wear the emote 0 (default face, that changes back after 5sec timeout)
if (emote != 0 && chr.isLoggedinWorld()) {
chr.changeFaceExpression(emote);
}
} finally {
c.unlockClient();
c.releaseClient();
}
}
}
@@ -60,7 +60,7 @@ public final class ItemRewardHandler extends AbstractMaplePacketHandler {
}
MapleInventoryManipulator.addFromDrop(c, item, false);
} else {
MapleInventoryManipulator.addById(c, reward.itemid, reward.quantity);
MapleInventoryManipulator.addById(c, reward.itemid, reward.quantity, "", -1);
}
MapleInventoryManipulator.removeById(c, MapleInventoryType.USE, itemId, 1, false, false);
if (reward.worldmsg != null) {
@@ -214,7 +214,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
c.getPlayer().gainMeso(-5000, false);
c.announce(MaplePacketCreator.MTSConfirmSell());
c.announce(getMTS(1, 0, 0));
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
}
@@ -240,7 +240,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
}
c.getPlayer().changeTab(tab);
c.getPlayer().changeType(type);
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else if (op == 6) { //search
@@ -253,7 +253,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
c.getPlayer().changeTab(tab);
c.getPlayer().changeType(type);
c.getPlayer().changeCI(ci);
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.enableActions());
c.announce(getMTSSearch(tab, type, ci, search, c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
@@ -277,7 +277,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
} catch (SQLException e) {
e.printStackTrace();
}
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
@@ -331,7 +331,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
pse.executeUpdate();
}
MapleInventoryManipulator.addFromDrop(c, i, false);
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(getCart(c.getPlayer().getId()));
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.MTSConfirmTransfer(i.getQuantity(), i.getPosition()));
@@ -374,7 +374,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
e.printStackTrace();
}
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.enableActions());
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
@@ -393,7 +393,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
e.printStackTrace();
}
c.announce(getCart(c.getPlayer().getId()));
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
c.announce(MaplePacketCreator.notYetSoldInv(getNotYetSold(c.getPlayer().getId())));
} else if (op == 12) { //put item up for auction
@@ -445,7 +445,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
pse.executeUpdate();
pse.close();
c.getPlayer().getCashShop().gainCash(4, -price);
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(getMTS(c.getPlayer().getCurrentTab(), c.getPlayer().getCurrentType(), c.getPlayer().getCurrentPage()));
c.announce(MaplePacketCreator.MTSConfirmBuy());
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
@@ -507,7 +507,7 @@ public final class MTSHandler extends AbstractMaplePacketHandler {
pse.close();
c.getPlayer().getCashShop().gainCash(4, -price);
c.announce(getCart(c.getPlayer().getId()));
c.announce(MaplePacketCreator.enableCSUse());
c.enableCSActions();
c.announce(MaplePacketCreator.MTSConfirmBuy());
c.announce(MaplePacketCreator.showMTSCash(c.getPlayer()));
c.announce(MaplePacketCreator.transferInventory(getTransfer(c.getPlayer().getId())));
@@ -39,7 +39,7 @@ public final class MagicDamageHandler extends AbstractDealDamageHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
chr.setPetLootCd(currentServerTime());
//chr.setPetLootCd(currentServerTime());
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
@@ -23,6 +23,7 @@ package net.server.channel.handlers;
import client.MapleCharacter;
import client.MapleClient;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.inventory.MaplePet;
import client.autoban.AutobanManager;
@@ -65,18 +66,25 @@ public final class PetFoodHandler extends AbstractMaplePacketHandler {
short pos = slea.readShort();
int itemId = slea.readInt();
Item use = chr.getInventory(MapleInventoryType.USE).getItem(pos);
if (use == null || (itemId / 10000) != 212 || use.getItemId() != itemId) {
if (c.tryacquireClient()) {
try {
MapleInventory useInv = chr.getInventory(MapleInventoryType.USE);
useInv.lockInventory();
try {
Item use = useInv.getItem(pos);
if (use == null || (itemId / 10000) != 212 || use.getItemId() != itemId || use.getQuantity() < 1) {
return;
}
c.lockClient();
try {
pet.gainClosenessFullness(chr, (pet.getFullness() <= 75) ? 1 : 0, 30, 1); // 25+ "emptyness" to get +1 closeness
} finally {
c.unlockClient();
}
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, pos, (short) 1, false);
} finally {
useInv.unlockInventory();
}
} finally {
c.releaseClient();
}
}
}
}
@@ -49,6 +49,7 @@ import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Matze
* @author Ronan (concurrency safety & reviewed minigames)
*/
public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
public enum Action {
@@ -109,7 +110,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
}
}
private static int estabilishMiniroomStatus(MapleCharacter chr, boolean isMinigame) {
private static int establishMiniroomStatus(MapleCharacter chr, boolean isMinigame) {
if (isMinigame && FieldLimit.CANNOTMINIGAME.check(chr.getMap().getFieldLimit())) {
return 11;
}
@@ -127,6 +128,12 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (!c.tryacquireClient()) { // thanks GabrielSin for pointing dupes within player interactions
c.announce(MaplePacketCreator.enableActions());
return;
}
try {
byte mode = slea.readByte();
final MapleCharacter chr = c.getPlayer();
@@ -140,15 +147,31 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
if (createType == 3) {// trade
MapleTrade.startTrade(chr);
} else if (createType == 1) { // omok mini game
int status = estabilishMiniroomStatus(chr, true);
int status = establishMiniroomStatus(chr, true);
if (status > 0) {
chr.getClient().announce(MaplePacketCreator.getMiniRoomError(status));
return;
}
String desc = slea.readMapleAsciiString();
String pw;
if (slea.readByte() != 0) {
pw = slea.readMapleAsciiString();
} else {
pw = "";
}
int type = slea.readByte();
String pw = slea.available() > 1 ? slea.readMapleAsciiString() : "";
if (type > 11) {
type = 11;
} else if (type < 0) {
type = 0;
}
if (!chr.haveItem(4080000 + type)) {
chr.getClient().announce(MaplePacketCreator.getMiniRoomError(6));
return;
}
MapleMiniGame game = new MapleMiniGame(chr, desc, pw);
chr.setMiniGame(game);
@@ -158,15 +181,31 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
chr.getMap().broadcastMessage(MaplePacketCreator.addOmokBox(chr, 1, 0));
game.sendOmok(c, type);
} else if (createType == 2) { // matchcard
int status = estabilishMiniroomStatus(chr, true);
int status = establishMiniroomStatus(chr, true);
if (status > 0) {
chr.getClient().announce(MaplePacketCreator.getMiniRoomError(status));
return;
}
String desc = slea.readMapleAsciiString();
String pw;
if (slea.readByte() != 0) {
pw = slea.readMapleAsciiString();
} else {
pw = "";
}
int type = slea.readByte();
String pw = slea.available() > 1 ? slea.readMapleAsciiString() : "";
if (type > 2) {
type = 2;
} else if (type < 0) {
type = 0;
}
if (!chr.haveItem(4080100)) {
chr.getClient().announce(MaplePacketCreator.getMiniRoomError(6));
return;
}
MapleMiniGame game = new MapleMiniGame(chr, desc, pw);
game.setPieceType(type);
@@ -188,7 +227,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
return;
}
int status = estabilishMiniroomStatus(chr, false);
int status = establishMiniroomStatus(chr, false);
if (status > 0) {
chr.getClient().announce(MaplePacketCreator.getMiniRoomError(status));
return;
@@ -326,46 +365,52 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
game.broadcast(MaplePacketCreator.getMiniGameUnReady(game));
} else if (mode == Action.START.getCode()) {
MapleMiniGame game = chr.getMiniGame();
if (game.getGameType().equals("omok")) {
if (game.getGameType().equals(MiniGameType.OMOK)) {
game.minigameMatchStarted();
game.broadcast(MaplePacketCreator.getMiniGameStart(game, game.getLoser()));
chr.getMap().broadcastMessage(MaplePacketCreator.addOmokBox(game.getOwner(), 2, 1));
}
if (game.getGameType().equals("matchcard")) {
} else if (game.getGameType().equals(MiniGameType.MATCH_CARD)) {
game.minigameMatchStarted();
game.shuffleList();
game.broadcast(MaplePacketCreator.getMatchCardStart(game, game.getLoser()));
chr.getMap().broadcastMessage(MaplePacketCreator.addMatchCardBox(game.getOwner(), 2, 1));
}
} else if (mode == Action.GIVE_UP.getCode()) {
MapleMiniGame game = chr.getMiniGame();
if (game.getGameType().equals("omok")) {
if (game.getGameType().equals(MiniGameType.OMOK)) {
if (game.isOwner(chr)) {
game.broadcast(MaplePacketCreator.getMiniGameOwnerForfeit(game));
game.minigameMatchVisitorWins(true);
} else {
game.broadcast(MaplePacketCreator.getMiniGameVisitorForfeit(game));
game.minigameMatchOwnerWins(true);
}
}
if (game.getGameType().equals("matchcard")) {
} else if (game.getGameType().equals(MiniGameType.MATCH_CARD)) {
if (game.isOwner(chr)) {
game.broadcast(MaplePacketCreator.getMatchCardVisitorWin(game));
game.minigameMatchVisitorWins(true);
} else {
game.broadcast(MaplePacketCreator.getMatchCardOwnerWin(game));
game.minigameMatchOwnerWins(true);
}
}
} else if (mode == Action.REQUEST_TIE.getCode()) {
MapleMiniGame game = chr.getMiniGame();
if (!game.isTieDenied(chr)) {
if (game.isOwner(chr)) {
game.broadcastToVisitor(MaplePacketCreator.getMiniGameRequestTie(game));
} else {
game.getOwner().getClient().announce(MaplePacketCreator.getMiniGameRequestTie(game));
game.broadcastToOwner(MaplePacketCreator.getMiniGameRequestTie(game));
}
}
} else if (mode == Action.ANSWER_TIE.getCode()) {
MapleMiniGame game = chr.getMiniGame();
slea.readByte();
if (game.getGameType().equals("omok")) {
game.broadcast(MaplePacketCreator.getMiniGameTie(game));
if (slea.readByte() != 0) {
game.minigameMatchDraw();
} else {
game.denyTie(chr);
if (game.isOwner(chr)) {
game.broadcastToVisitor(MaplePacketCreator.getMiniGameDenyTie(game));
} else {
game.broadcastToOwner(MaplePacketCreator.getMiniGameDenyTie(game));
}
if (game.getGameType().equals("matchcard")) {
game.broadcast(MaplePacketCreator.getMatchCardTie(game));
}
} else if (mode == Action.SKIP.getCode()) {
MapleMiniGame game = chr.getMiniGame();
@@ -391,7 +436,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
} else {
game.getOwner().getClient().announce(MaplePacketCreator.getMatchCardSelect(game, turn, slot, firstslot, turn));
}
} else if ((game.getCardId(firstslot + 1)) == (game.getCardId(slot + 1))) {
} else if ((game.getCardId(firstslot)) == (game.getCardId(slot))) {
if (game.isOwner(chr)) {
game.broadcast(MaplePacketCreator.getMatchCardSelect(game, turn, slot, firstslot, 2));
game.setOwnerPoints();
@@ -412,6 +457,13 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
Item item = chr.getInventory(ivType).getItem(slea.readShort());
short quantity = slea.readShort();
byte targetSlot = slea.readByte();
if (item == null) {
c.announce(MaplePacketCreator.serverNotice(1, "Invalid item description."));
c.announce(MaplePacketCreator.enableActions());
return;
}
if (quantity < 1 || quantity > item.getQuantity()) {
c.announce(MaplePacketCreator.serverNotice(1, "You don't have enough quantity of the item."));
c.announce(MaplePacketCreator.enableActions());
@@ -448,7 +500,7 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
short bundles = slea.readShort();
Item ivItem = chr.getInventory(ivType).getItem(slot);
if (ivItem == null || ivItem.getFlag() == ItemConstants.UNTRADEABLE) {
if (ivItem == null || ivItem.isUntradeable()) {
c.announce(MaplePacketCreator.serverNotice(1, "Could not perform shop operation with that item."));
c.announce(MaplePacketCreator.enableActions());
return;
@@ -632,6 +684,9 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
}
}
}
} finally {
c.releaseClient();
}
}
private static boolean isTradeOpen(MapleCharacter chr) {
@@ -51,7 +51,7 @@ public final class RangedAttackHandler extends AbstractDealDamageHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
MapleCharacter chr = c.getPlayer();
chr.setPetLootCd(currentServerTime());
//chr.setPetLootCd(currentServerTime());
/*long timeElapsed = currentServerTime() - chr.getAutobanManager().getLastSpam(8);
if(timeElapsed < 300) {
@@ -273,20 +273,20 @@ public final class RingActionHandler extends AbstractMaplePacketHandler {
}
public static void giveMarriageRings(MapleCharacter player, MapleCharacter partner, int marriageRingId) {
int ringid = MapleRing.createRing(marriageRingId, player, partner);
Pair<Integer, Integer> rings = MapleRing.createRing(marriageRingId, player, partner);
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
Item ringObj = ii.getEquipById(marriageRingId);
Equip ringEqp = (Equip) ringObj;
ringEqp.setRingId(ringid);
player.addMarriageRing(MapleRing.loadFromDb(ringid));
ringEqp.setRingId(rings.getLeft());
player.addMarriageRing(MapleRing.loadFromDb(rings.getLeft()));
MapleInventoryManipulator.addFromDrop(player.getClient(), ringEqp, false, -1);
player.broadcastMarriageMessage();
ringObj = ii.getEquipById(marriageRingId);
ringEqp = (Equip) ringObj;
ringEqp.setRingId(ringid + 1);
partner.addMarriageRing(MapleRing.loadFromDb(ringid + 1));
ringEqp.setRingId(rings.getRight());
partner.addMarriageRing(MapleRing.loadFromDb(rings.getRight()));
MapleInventoryManipulator.addFromDrop(partner.getClient(), ringEqp, false, -1);
partner.broadcastMarriageMessage();
}
@@ -513,6 +513,6 @@ public final class RingActionHandler extends AbstractMaplePacketHandler {
break;
}
c.getSession().write(MaplePacketCreator.enableActions());
c.announce(MaplePacketCreator.enableActions());
}
}
@@ -28,9 +28,10 @@ import tools.data.input.SeekableLittleEndianAccessor;
/**
*
* @author Acrylic (Terry Han)
* @author Terry Han (Acrylic)
*/
public final class TouchingCashShopHandler extends AbstractMaplePacketHandler {
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
c.announce(MaplePacketCreator.showCash(c.getPlayer()));
}
@@ -276,7 +276,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
if (item == null) //hack
{
return;
} else if (((item.getFlag() & ItemConstants.UNTRADEABLE) == ItemConstants.UNTRADEABLE) || (ii.isDropRestricted(item.getItemId()) && !MapleKarmaManipulator.hasKarmaFlag(item))) {
} else if (item.isUntradeable()) {
player.dropMessage(1, "You cannot trade this item.");
c.announce(MaplePacketCreator.enableActions());
return;
@@ -299,7 +299,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
break;
}
remove(c, itemId);
} else if (itemType == 508) { // graduation banner, thanks to tmskdl12
} else if (itemType == 508) { // graduation banner, thanks to tmskdl12. Also, thanks ratency for first pointing lack of Kite handling
MapleKite kite = new MapleKite(player, slea.readMapleAsciiString(), itemId);
if (!GameConstants.isFreeMarketRoom(player.getMapId())) {
@@ -517,7 +517,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
Equip toScroll = (Equip) eitem;
if (toScroll.getUpgradeSlots() < 1) {
c.getSession().write(MaplePacketCreator.getInventoryFull());
c.announce(MaplePacketCreator.getInventoryFull());
return;
}
@@ -527,10 +527,10 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
player.toggleBlockCashShop();
final int curlevel = toScroll.getLevel();
c.getSession().write(MaplePacketCreator.sendVegaScroll(0x40));
c.announce(MaplePacketCreator.sendVegaScroll(0x40));
final Equip scrolled = (Equip) ii.scrollEquipWithId(toScroll, uitem.getItemId(), false, itemId, player.isGM());
c.getSession().write(MaplePacketCreator.sendVegaScroll(scrolled.getLevel() > curlevel ? 0x41 : 0x43));
c.announce(MaplePacketCreator.sendVegaScroll(scrolled.getLevel() > curlevel ? 0x41 : 0x43));
//opcodes 0x42, 0x44: "this item cannot be used"; 0x39, 0x45: crashes
MapleInventoryManipulator.removeFromSlot(c, MapleInventoryType.USE, uSlot, (short) 1, false);
@@ -555,7 +555,7 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
player.equipChanged();
}
client.getSession().write(MaplePacketCreator.enableActions());
client.announce(MaplePacketCreator.enableActions());
}
}, 1000 * 3);
} else {
@@ -24,7 +24,6 @@ package net.server.channel.handlers;
import client.MapleClient;
import client.inventory.MapleInventoryType;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class UseChairHandler extends AbstractMaplePacketHandler {
@@ -34,8 +33,7 @@ public final class UseChairHandler extends AbstractMaplePacketHandler {
if (c.getPlayer().getInventory(MapleInventoryType.SETUP).findById(itemId) == null) {
return;
}
c.getPlayer().setChair(itemId);
c.getPlayer().getMap().broadcastMessage(c.getPlayer(), MaplePacketCreator.showChair(c.getPlayer().getId(), itemId), false);
c.announce(MaplePacketCreator.enableActions());
c.getPlayer().sitChair(itemId);
}
}
@@ -25,6 +25,7 @@ import client.MapleClient;
import client.MapleCharacter;
import client.MapleMount;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import constants.ExpTable;
import net.AbstractMaplePacketHandler;
@@ -45,10 +46,14 @@ public final class UseMountFoodHandler extends AbstractMaplePacketHandler {
MapleCharacter chr = c.getPlayer();
MapleMount mount = chr.getMount();
Item item = chr.getInventory(MapleInventoryType.USE).getItem(pos);
if (item != null && item.getItemId() == itemid && mount != null) {
c.lockClient();
MapleInventory useInv = chr.getInventory(MapleInventoryType.USE);
if (c.tryacquireClient()) {
try {
useInv.lockInventory();
try {
Item item = useInv.getItem(pos);
if (item != null && item.getItemId() == itemid && mount != null) {
int curTiredness = mount.getTiredness();
int healedTiredness = Math.min(curTiredness, 30);
@@ -66,8 +71,12 @@ public final class UseMountFoodHandler extends AbstractMaplePacketHandler {
}
MapleInventoryManipulator.removeById(c, MapleInventoryType.USE, itemid, 1, true, false);
}
} finally {
c.unlockClient();
useInv.unlockInventory();
}
} finally {
c.releaseClient();
}
}
}
@@ -92,7 +92,7 @@ public final class WhisperHandler extends AbstractMaplePacketHandler {
} else {
c.announce(MaplePacketCreator.getFindReply(victim.getName(), victim.getMap().getId(), 1));
}
} else if (c.getPlayer().gmLevel() > 1) { // not found
} else if (c.getPlayer().isGM()) { // not found
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps = con.prepareStatement("SELECT gm FROM characters WHERE name = ?");
@@ -37,6 +37,9 @@ import tools.data.input.SeekableLittleEndianAccessor;
import client.MapleClient;
import java.sql.ResultSet;
import java.sql.Statement;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public final class LoginPasswordHandler implements MaplePacketHandler {
@@ -45,6 +48,11 @@ public final class LoginPasswordHandler implements MaplePacketHandler {
return !c.isLoggedIn();
}
private static String hashpwSHA512(String pwd) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest digester = MessageDigest.getInstance("SHA-512");
digester.update(pwd.getBytes("UTF-8"), 0, pwd.length());
return HexTool.toString(digester.digest()).replace(" ", "").toLowerCase();
}
@Override
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
@@ -65,7 +73,7 @@ public final class LoginPasswordHandler implements MaplePacketHandler {
con = DatabaseConnection.getConnection();
ps = con.prepareStatement("INSERT INTO accounts (name, password, birthday, tempban) VALUES (?, ?, ?, ?);", Statement.RETURN_GENERATED_KEYS); //Jayd: Added birthday, tempban
ps.setString(1, login);
ps.setString(2, BCrypt.hashpw(pwd, BCrypt.gensalt(12)));
ps.setString(2, ServerConstants.BCRYPT_MIGRATION ? BCrypt.hashpw(pwd, BCrypt.gensalt(12)) : hashpwSHA512(pwd));
ps.setString(3, "2018-06-20"); //Jayd's idea: was added to solve the MySQL 5.7 strict checking (birthday)
ps.setString(4, "2018-06-20"); //Jayd's idea: was added to solve the MySQL 5.7 strict checking (tempban)
ps.executeUpdate();
@@ -74,7 +82,7 @@ public final class LoginPasswordHandler implements MaplePacketHandler {
rs.next();
c.setAccID(rs.getInt(1));
rs.close();
} catch (SQLException e) {
} catch (SQLException | NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
} finally {
disposeSql(con, ps);
@@ -695,7 +695,6 @@ public class AbstractPlayerInteraction {
}
}
public void removeHPQItems() {
int[] items = {4001095, 4001096, 4001097, 4001098, 4001099, 4001100, 4001101};
for (int i = 0; i < items.length; i ++) {
@@ -345,7 +345,7 @@ public class EventInstanceManager {
private void dismissEventTimer() {
for(MapleCharacter chr: getPlayers()) {
chr.getClient().getSession().write(MaplePacketCreator.removeClock());
chr.getClient().announce(MaplePacketCreator.removeClock());
}
event_schedule = null;
+5
View File
@@ -582,4 +582,9 @@ public class CashShop {
return null;
}
}
public static Item generateCouponItem(int itemId, short quantity) {
CashItem it = new CashItem(77777777, itemId, 7777, ItemConstants.isPet(itemId) ? 30 : 0, quantity, true);
return it.toItem();
}
}
@@ -373,6 +373,7 @@ public class MapleItemInformationProvider {
private static short getExtraSlotMaxFromPlayer(MapleClient c, int itemId) {
short ret = 0;
// thanks GMChuck for detecting player sensitive data being cached into getSlotMax
if (ItemConstants.isThrowingStar(itemId)) {
if(c.getPlayer().getJob().isA(MapleJob.NIGHTWALKER1)) {
ret += c.getPlayer().getSkillLevel(SkillFactory.getSkill(NightWalker.CLAW_MASTERY)) * 10;
+6 -6
View File
@@ -94,12 +94,12 @@ public class MapleShop {
if (c.getPlayer().getMeso() >= amount) {
if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) {
if (!ItemConstants.isRechargeable(itemId)) { //Pets can't be bought from shops
MapleInventoryManipulator.addById(c, itemId, quantity);
MapleInventoryManipulator.addById(c, itemId, quantity, "", -1);
c.getPlayer().gainMeso(-amount, false);
} else {
short slotMax = ii.getSlotMax(c, item.getItemId());
quantity = slotMax;
MapleInventoryManipulator.addById(c, itemId, quantity);
MapleInventoryManipulator.addById(c, itemId, quantity, "", -1);
c.getPlayer().gainMeso(-item.getPrice(), false);
}
c.announce(MaplePacketCreator.shopTransaction((byte) 0));
@@ -115,12 +115,12 @@ public class MapleShop {
if (c.getPlayer().getInventory(MapleInventoryType.ETC).countById(4310000) >= amount) {
if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) {
if (!ItemConstants.isRechargeable(itemId)) {
MapleInventoryManipulator.addById(c, itemId, quantity);
MapleInventoryManipulator.addById(c, itemId, quantity, "", -1);
MapleInventoryManipulator.removeById(c, MapleInventoryType.ETC, 4310000, amount, false, false);
} else {
short slotMax = ii.getSlotMax(c, item.getItemId());
quantity = slotMax;
MapleInventoryManipulator.addById(c, itemId, quantity);
MapleInventoryManipulator.addById(c, itemId, quantity, "", -1);
MapleInventoryManipulator.removeById(c, MapleInventoryType.ETC, 4310000, amount, false, false);
}
c.announce(MaplePacketCreator.shopTransaction((byte) 0));
@@ -138,9 +138,9 @@ public class MapleShop {
if (MapleInventoryManipulator.checkSpace(c, itemId, quantity, "")) {
if (ItemConstants.isPet(itemId)) {
int petid = MaplePet.createPet(itemId);
MapleInventoryManipulator.addById(c, itemId, quantity, null, petid, -1);
MapleInventoryManipulator.addById(c, itemId, quantity, "", petid, -1);
} else {
MapleInventoryManipulator.addById(c, itemId, quantity);
MapleInventoryManipulator.addById(c, itemId, quantity, "", -1, -1);
}
c.getPlayer().gainMeso(diff, false);
} else {
+1 -1
View File
@@ -376,7 +376,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
if (mpsi.getItem().getInventoryType().equals(MapleInventoryType.EQUIP)) {
MapleInventoryManipulator.addFromDrop(c, mpsi.getItem(), false);
} else {
MapleInventoryManipulator.addById(c, mpsi.getItem().getItemId(), (short) (mpsi.getBundles() * mpsi.getItem().getQuantity()), null, -1, mpsi.getItem().getFlag(), mpsi.getItem().getExpiration());
MapleInventoryManipulator.addById(c, mpsi.getItem().getItemId(), (short) (mpsi.getBundles() * mpsi.getItem().getQuantity()), mpsi.getItem().getOwner(), -1, mpsi.getItem().getFlag(), mpsi.getItem().getExpiration());
}
}
}
+2 -2
View File
@@ -43,12 +43,12 @@ public class MapleKite extends AbstractMapleMapObject {
@Override
public void sendDestroyData(MapleClient client) {
client.getSession().write(makeDestroyData());
client.announce(makeDestroyData());
}
@Override
public void sendSpawnData(MapleClient client) {
client.getSession().write(makeSpawnData());
client.announce(makeSpawnData());
}
public final byte[] makeSpawnData() {
+1 -1
View File
@@ -3882,7 +3882,7 @@ public class MapleMap {
public void spawnHorntailOnGroundBelow(final Point targetPoint) { // ayy lmao
MapleMonster htIntro = MapleLifeFactory.getMonster(8810026);
spawnMonsterOnGroundBelow(htIntro, targetPoint);
spawnMonsterOnGroundBelow(htIntro, targetPoint); // htintro spawn animation converting into horntail detected thanks to Arnah
final MapleMonster ht = MapleLifeFactory.getMonster(8810018);
ht.setParentMobOid(htIntro.getObjectId());
+2 -9
View File
@@ -427,21 +427,14 @@ public class MapleMapFactory {
public Map<Integer, MapleMap> getMaps() {
mapsRLock.lock();
try {
return Collections.unmodifiableMap(maps);
return new HashMap<>(maps);
} finally {
mapsRLock.unlock();
}
}
public void dispose() {
Collection<MapleMap> mapValues;
mapsRLock.lock();
try {
mapValues = maps.values();
} finally {
mapsRLock.unlock();
}
Collection<MapleMap> mapValues = getMaps().values();
for(MapleMap map: mapValues) {
map.dispose();

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