Added Puppets on Aggro + Guild/Alliance packet info patch + Pet flags
Added pet flags recognition, such as the "pet speed same as owner" mechanic. Fixed repeatable quest "Remnants of HT..." not rewarding Dragon Stones. Refactored character object's check slots method, now using the same algorithm from the API class. Fixed a vunerability from before reviving/respawning players to towns, on where players would get their HP restored in area map before sending them back to safety. Fixed some NPC gates in Mushking Empire, allowing players to access bosses free of quest requirements. Improved dialog of NPCs for "permission to attempt Zakum expeds". Implemented (or rather improved) item scripts, now using NPC conversation methods as it was intended originally. Rehauled mob-skill "summon mobs" limit, now using the placeholders found in the wz to determine limit of concurrent underlings spawned, and "limit" now refers to total of underlings spawned from a mob. Revised IoSession closing mechanics in several login classes. Implemented automated loggedin account shutdown if another player has gained a pass from the DB to login. Improved the server-side check for teleport rocks. Fixed removeAfter from mobs being procced after they were disposed. Reviewed EIM start references on several scripts, minding the latest EIM setup implementations. Fixed equipments that were reused Scissors of Karma not not being able to sell on pshops/merchants. Fixed a bug where entering alliances would lead a player to see information from other guilds of past alliances until an update takes place. Padronized a few skillbook names. Reviewed player puppets not gaining priority properly on the recent aggro system. Improved "item sold" message of merchants, now displaying also quantity left of an item on store. Fixed a bug with itemid limits of weapons on server.
This commit is contained in:
@@ -27,6 +27,10 @@
|
||||
/tools/MapleCashDropFetcher/dist/
|
||||
/tools/MapleCashDropFetcher/nbproject/
|
||||
|
||||
/tools/MapleCashVegaChecker/build/
|
||||
/tools/MapleCashVegaChecker/dist/
|
||||
/tools/MapleCashVegaChecker/nbproject/
|
||||
|
||||
/tools/MapleCodeCouponGenerator/build/
|
||||
/tools/MapleCodeCouponGenerator/dist/
|
||||
/tools/MapleCodeCouponGenerator/nbproject/
|
||||
|
||||
@@ -23,13 +23,15 @@ Java7 SDK: https://www.oracle.com/technetwork/java/javase/downloads/java-archive
|
||||
|
||||
**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.
|
||||
|
||||
Latest localhost: https://hostr.co/m2bVtnizCtmD
|
||||
Latest localhost: https://hostr.co/tsYsQzzV6xT0
|
||||
|
||||
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:**
|
||||
|
||||
* Removed block on applying attack-based strengthening gems on non-weapon equipments.
|
||||
* Fixed some 'rn' problems with quest icons & removed "tab" from party leader changed message.
|
||||
|
||||
* Removed block on applying attack-based strengthening gems on non-weapon equipments. https://hostr.co/m2bVtnizCtmD
|
||||
|
||||
* Set a higher cap for SPEED.
|
||||
|
||||
@@ -84,6 +86,7 @@ It's never enough to tell this, thanks to everyone that have been contributing s
|
||||
Our Discord channel is still available on: https://discord.gg/Q7wKxHX
|
||||
|
||||
<hr id="donate" />
|
||||
|
||||
### Donation
|
||||
|
||||
If you REALLY liked what you have seen on the project, please feel free to donate a little something as a helping hand for my contributions towards Maple development. Also remember to **support Nexon**!
|
||||
|
||||
+1
-1
@@ -16,6 +16,7 @@ Known issues:
|
||||
- Some monster status such as freeze and weapon/magic reflect doesn't behave properly in certain scenarios. Freeze seems to not work on mobs with low OID or are starters from server boot time.
|
||||
- On low-end connections, things such as command summoning a player that is currently logging in (already visible to other players) may cause the player to freeze, consequently freezing the account as well since the server-side disconnection doesn't happen.
|
||||
- Reportedly, there are cases where mob positions fail to sync between player's client-view.
|
||||
- Visual equip EXP watch value will present stuttering for early levels requirement (EXP needed less than 100), and requirement at level 200 will not progress at all due to the level cap in client.
|
||||
---------------------------
|
||||
|
||||
---------------------------
|
||||
@@ -24,7 +25,6 @@ Missing features list:
|
||||
- Some pirate skills doesn't work for 3rd parties.
|
||||
- Cache frequently used SQL data.
|
||||
- Pet commands are not being propagated to 3rd parties, and the commandResponse packet function seems somewhat wonky.
|
||||
- Pet speed.
|
||||
---------------------------
|
||||
|
||||
|
||||
|
||||
+42
-1
@@ -1619,4 +1619,45 @@ Adicionado checagem em quantidade de itens nas lojas e mercantes de jogadores, a
|
||||
Corrigido um exploit com mercantes, envolvendo chamada à DB antes de retirar item (que está sendo inserido na loja) do inventário do jogador.
|
||||
|
||||
30 Janeiro 2019,
|
||||
Corrigido chamadas irregulares a "qm/cm" em scripts.
|
||||
Corrigido chamadas irregulares a "qm/cm" em scripts.
|
||||
|
||||
31 Janeiro 2019,
|
||||
Com a ajuda de Irenex, adicionado referência a pet flags no criador de pacotes.
|
||||
Adicionado funcionalidade de quest que permite pets a andarem na velocidade do jogador.
|
||||
Corrigido quest repetível de Dragon Stone não apropriadamente recompensando o item ao jogador.
|
||||
Corrigido método de checagem de slots em MapleCharacter, agora utilizando o método padrão implementado especificamente para checagem de slots.
|
||||
|
||||
01 Fevereiro 2019,
|
||||
Corrigido vulnerabilidade na ação de jogadores ao retornar para a cidade após reviver. Servidor poderia receber packet de dano e processá-lo legitimamente com o HP atualizado do jogador antes de enviá-lo de volta para cidade.
|
||||
|
||||
04 - 05 Fevereiro 2019,
|
||||
Corrigido NPCs de portão em Mushking Empire permitindo jogadores acesso a área de bosses sem requisitos mínimos.
|
||||
Incrementado diálogos de permissão para realizar expedições contra Zakum.
|
||||
Modificado gerenciador de item scripts, agora referenciando conversação de NPCs (como previsto pelo WZ).
|
||||
Implementado limitação de mob summons, como previsto no WZ.
|
||||
Revisado fechamento de sessões no código-fonte não utilizando o coordenador de sessões para isto.
|
||||
Revisado sistema de login, agora automaticamente desconectando contas retidas no jogo quando DB determina que uma conta está disponível para login.
|
||||
Revisado Teleport Rocks, agora devidamente checando se é possível chegar ao mapa alvo (ou se há bloqueio de uso do item para esse mapa), além de certas checagens contra exploits com esse item.
|
||||
Corrigido agendamento de removeAfter de mobs atuando quando o mesmo já foi liberado.
|
||||
|
||||
07 - 08 Fevereiro 2019,
|
||||
Corrigido ocorrências de NPE ao tentar registrar-se em instância de evento, quando existe uma outra instância que leva o mesmo nome em andamento.
|
||||
Tentativa de correção em todos os scripts de eventos, após ter atualizado o sistema de eventos para não mais ficar gerando instâncias livremente (agora, todas as instâncias orientadas-a-solo têm limite de acesso simultâneo entre jogadores).
|
||||
Corrigido lojas de jogadores e mercantes não aceitando itens em certos casos onde já se foi usado Scissors of Karma.
|
||||
Revisado novamente diversos scripts de evento, atentando às chamadas de função "setup" das mesmas.
|
||||
|
||||
09 Fevereiro 2019,
|
||||
Tentativa de correção em sessões com exceptionCaught, já que aparentemente a sessão nem sempre é fechada pelo MINA automaticamente.
|
||||
Corrigido lista de guilds em alliances não sendo atualizado corretamente ao criar-se uma nova alliance. Era possível ver guilds de alianças passadas antes de ocorrer alguma atualização de packet em jogo que resolva isso.
|
||||
Implementado comando "toggleexp", que permite jogadores a escolher ganhar nível ou não se os mesmos não estivem em instância de evento.
|
||||
Nova ferramenta: MapleCashVegaChecker. Ferramenta busca por itens que supostamente deveriam permitir uso do Vega Scroll (segundo descrição) porém não o permitem.
|
||||
Revisado nomes de skill e mastery books, que mantinham números no nome da skill (agora padronizado com os outros livros).
|
||||
|
||||
10 Fevereiro 2019,
|
||||
Editado requerimentos de level de medalhas level 200 para 180, assim evitando o problema onde nível das medalhas não apareçe na visão do cliente devido ao level cap.
|
||||
Corrigido puppets não tomando prioridade na nova mecânica de aggro.
|
||||
Incrementado mensagem custom de venda de produtos pelo mercante.
|
||||
|
||||
13 - 14 Fevereiro 2019,
|
||||
Corrigido limites na função isWeapon, que não contabilizaria certos itens corretamente.
|
||||
Resolvido comportamento de puppets usando o novo sistema de aggro.
|
||||
@@ -82,7 +82,7 @@
|
||||
1102080 - Ragged Blue Cape - (no description)
|
||||
1102081 - Ragged Yellow Cape - (no description)
|
||||
1102082 - Ragged Black Cape - (no description)
|
||||
1102083 - Ragged Red Cape - (no description)
|
||||
1102083 - Ragged Green Cape - (no description)
|
||||
1102084 - Pink Gaia Cape - (no description)
|
||||
1102085 - Yellow Gaia Cape - (no description)
|
||||
1102086 - Purple Gaia Cape - (no description)
|
||||
|
||||
+28
-28
@@ -376,15 +376,15 @@
|
||||
2030004 - Return Scroll to Henesys - Returns you to Henesys.
|
||||
2030005 - Return Scroll to Kerning City - Returns you to the dark Kerning City.
|
||||
2030006 - Return Scroll to Sleepywood - Returns you to Sleepywood, a quiet and dark forest-town.
|
||||
2030007 - Return Scroll for Dead Mine - Returns you to the dead mine at the higher ground of El Nath.nCan only be used in Orbis and El Nath.
|
||||
2030007 - Return Scroll to Dead Mine - Returns you to the dead mine at the higher ground of El Nath.nCan only be used in Orbis and El Nath.
|
||||
2030008 - Coffee Milk - Returns you to the nearest town.
|
||||
2030009 - Strawberry Milk - Returns you to Mushroom Shrine.
|
||||
2030010 - Fruit Milk - Returns you to Showa Town.
|
||||
2030011 - Command Center Warp Capsule - A warp capsule that allows the owner of the capsule to warp to the Command Center of Omega Sector.
|
||||
2030012 - Ludibrium Warp Capsule - A warp capsule that returns you to Ludibrium.
|
||||
2030016 - Phyllia's Warp Powder - Warp powder made by fairy Phyllia. Teleports you to Magatia when used inside the Nihal desert region.
|
||||
2030019 - Nautilus Return Scroll - This scroll enables you to return to the Pirate village, Nautilus. This is a one use item and will disappear after use.
|
||||
2030020 - Return to New Leaf City Scroll - Use this scroll to venture back to New Leaf City whenever you want!
|
||||
2030019 - Return Scroll to Nautilus - This scroll enables you to return to the Pirate village, Nautilus. This is a one use item and will disappear after use.
|
||||
2030020 - Return Scroll to New Leaf City - Use this scroll to venture back to New Leaf City whenever you want!
|
||||
2030100 - Return Scroll - Banished Area - Returns you to the map where you were last banished. Requires immediate use and have changed neither maps nor channels.
|
||||
2031000 - Masked Man's Invitation - An invitation from the Masked Man to the Halloween Party at the Haunted Mansion. Double-click to move straight to the mansion.
|
||||
2031001 - Studio Invitation - An invitation to the studio for the event "For Guild Only".
|
||||
@@ -1182,7 +1182,7 @@
|
||||
2280001 - Black Cloud Machine - A mechanical device that produces black clouds. Enables the character to acquire the Smokescreen skill using the clouds.
|
||||
2280002 - Firm Hand - A stimulant packaged inside a bottle that resembles a clenched fist. Drinking the stimulant will allow the character to acquire The Will of a Warrior.
|
||||
2280003 - [Skill Book] Maple Warrior - You can learn #cMaple Warrior# with this book.rnJob : All 4th jobsrnCondition : #cMaple Warrior# not acquired.
|
||||
2280004 - [Skill Book] Infinity - You can learn #Infinity# with this book.rnJob : 4th Advancement MagicianrnCondition : #cInfinity# not acquired
|
||||
2280004 - [Skill Book] Infinity - You can learn #cInfinity# with this book.rnJob : 4th Advancement MagicianrnCondition : #cInfinity# not acquired
|
||||
2280005 - [Skill Book] Dragon's Breath - You can learn #cDragon's Breath# with this book.wnJob : 4th Advancement BowmanrnCondition : #cDragon's Breath# not acquired
|
||||
2280006 - [Skill Book] Taunt - You can learn #cTaunt# with this book.rnJob : 4th Advancement ThiefrnCondition : #cTaunt# not acquired
|
||||
2280007 - [Skill Book] Advanced Combo Attack - You can learn #cAdvanced Combo Attack# with this book.rnClass : HerornCondition : #cAdvanced Combo# not acquired
|
||||
@@ -1191,6 +1191,13 @@
|
||||
2280010 - [Skill Book] Triple Throw - You can learn #cTriple Throw# with this book.rnClass : Night LordrnCondition : #cTriple Throw# not acquired
|
||||
2280011 - Ancient Ice Powder - This is a pack full of ancient ice powder. If you eat this, you will feel chilled and can learn Ice Demon.
|
||||
2280012 - [Skill Book] Rush - You can learn #cRush# with this book.rnJob : 4th Advancement WarriorrnCondition : #cRush# not acquired
|
||||
2280013 - [Skill Book] Final Blow - Skill Book from which you can learn about the #cFinal Blow# skill.\nJob: 4th Lv Aran\nCondition: #cFinal Blow# not available
|
||||
2280014 - [Skill Book] High Defense - Skill Book from which you can learn about the #cHigh Defense# skill.\nJob: 4th Lv Aran\nCondition: #cHigh Defense# not available
|
||||
2280015 - [Skill Book] Combo Tempest - Skill Book from which you can learn about the #cCombo Tempest# skill.\nJob: 4th Lv Aran\nCondition: #cCombo Tempest# not available
|
||||
2280017 - [Skill Book] Pig's Weakness - Skill Book from which you can learn about the #cPig's Weakness# skill.\nCondition: #cPig's Weakness# not available
|
||||
2280016 - [Skill Book] Combo Barrier - Skill Book from which you can learn about the #cCombo Barrier# skill.\nJob: 4th Lv Aran\nCondition: #cCombo Barrier# not available
|
||||
2280018 - [Skill Book] Stump's Weakness - Skill Book from which you can learn about the #cStump's Weakness# skill.\nCondition: #cStump's Weakness# not available
|
||||
2280019 - [Skill Book] Slime's Weakness - Skill Book from which you can learn about the #cSlime's Weakness# skill.\nCondition: #cSlime's Weakness# not available
|
||||
2290000 - [Mastery Book] Monster Magnet - This increases master level of the #cMonster Magnet# skill up to 20 with 70% chance of success.rnJob : 4th Advancement WarriorrnCondition : Skill level above 5
|
||||
2290001 - [Mastery Book] Monster Magnet - This increases master level of the #cMonster Magnet# skill up to 30 with 50% chance of success. rnJob : 4th Advancement WarriorrnCondition : Skill Level above 15
|
||||
2290002 - [Mastery Book] Achilles - This increases the master level of #cAchilles# up to 20 with 70% of chance.rnJob : 4th Advancement WarriorrnCondition : Skill level above 5
|
||||
@@ -1287,7 +1294,7 @@
|
||||
2290093 - [Mastery Book] Assassinate - This increases the master level of #cAssassinate# up to 30 with 50% of chance.rnClass : ShadowerrnCondition : Skill level above 15
|
||||
2290094 - [Mastery Book] Smokescreen - This increases the master level of #cSmokescreen# up to 20 with 70% of chance.rnClass : ShadowerrnCondition : Skill level above 5
|
||||
2290095 - [Mastery Book] Smokescreen - This increases the master level of #cSmokescreen# up to 30 with 50% of chance.rnClass : ShadowerrnCondition : Skill level above 15
|
||||
2290096 - [Mastery Book] Maple Warrior 20 - This increases the master level of #cMaple Warrior# up to 20 with 70% of chance.rnJob : All 4th Advancement JobsrnCondition : Skill level above 5
|
||||
2290096 - [Mastery Book] Maple Warrior - This increases the master level of #cMaple Warrior# up to 20 with 70% of chance.rnJob : All 4th Advancement JobsrnCondition : Skill level above 5
|
||||
2290097 - [Mastery Book] Dragon Strike - With a 70% success rate, it raises the Master Level of #cDragon Strike# to 20.nJob : BuccaneernRequirement : At least Level 5 in this skill
|
||||
2290098 - [Mastery Book] Dragon Strike - With a 50% success rate, it raises the Master Level of #cDragon Strike# to 30.nJob : BuccaneernRequirement : At least Level 15 in this skill
|
||||
2290099 - [Mastery Book] Energy Orb - With a 70% success rate, it raises the Master Level of #cEnergy Orb# to 20.nJob : BuccaneernRequirement : At least Level 5 in this skill
|
||||
@@ -1316,7 +1323,21 @@
|
||||
2290122 - [Mastery Book] Battleship Torpedo - With a 50% success rate, it raises the Master Level of #cBattleship Torpedo# to 30.nJob : CorsairnRequirement : At least Level 15 in this skill
|
||||
2290123 - [Mastery Book] Hypnotize - With a 70% success rate, it raises the Master Level of #cHypnotize# to 20.nJob : CorsairnRequirement : At least Level 5 in this skill
|
||||
2290124 - [Mastery Book] Bullseye - With a 70% success rate, it raises the Master Level of #cBullseye# to 20.nJob : CorsairnRequirement : At least Level 5 in this skill
|
||||
2290125 - [Mastery Book] Maple Warrior 30 - This increases the master level of #cMaple Warrior# up to 30 with 50% of chance.rnJob : All 4th Advancement JobsrnCondition : Skill level above 15
|
||||
2290125 - [Mastery Book] Maple Warrior - This increases the master level of #cMaple Warrior# up to 30 with 50% of chance.rnJob : All 4th Advancement JobsrnCondition : Skill level above 15
|
||||
2290126 - [Mastery Book] Overswing - With a 70% success rate, raises the Mastery Level of #cOverswing# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290127 - [Mastery Book] Overswing - With a 50% success rate, raises the Mastery Level of #cOverswing# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290128 - [Mastery Book] High Mastery - With a 70% success rate, raises the Mastery Level of #cHigh Mastery# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290129 - [Mastery Book] High Mastery - With a 50% success rate, raises the Mastery Level of #cHigh Mastery# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290130 - [Mastery Book] Freeze Standing - With a 70% success rate, raises the Mastery Level of #cFreeze Standing# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290131 - [Mastery Book] Freeze Standing - With a 50% success rate, raises the Mastery Level of #cFreeze Standing# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290132 - [Mastery Book] Final Blow - With a 70% success rate, raises the Mastery Level of #cFinal Blow# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290133 - [Mastery Book] Final Blow - With a 50% success rate, raises the Mastery Level of #cFinal Blow# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290134 - [Mastery Book] High Defense - With a 70% success rate, raises the Mastery Level of #cHigh Defense# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290135 - [Mastery Book] High Defense - With a 50% success rate, raises the Mastery Level of #cHigh Defense# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290136 - [Mastery Book] Combo Tempest - With a 70% success rate, raises the Mastery Level of #cCombo Tempest# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290137 - [Mastery Book] Combo Tempest - With a 50% success rate, raises the Mastery Level of #cCombo Tempest# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290138 - [Mastery Book] Combo Barrier - With a 70% success rate, raises the Mastery Level of #cCombo Barrier# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290139 - [Mastery Book] Combo Barrier - With a 50% success rate, raises the Mastery Level of #cCombo Barrier# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2310000 - The Owl of Minerva - #cThe Owl of Minerva#, which represents wisdom, can be used to search for items sold at the Free Market. #cDisappears right after showing the results of the item search#.
|
||||
2320000 - Teleport Rock - Remembers 5 maps of your choice. This rock will enable you to #cteleport to the map you remembered#. It can even allow you to #cmove to the map where a certain character is#, provided that the person is in the same channel at the same world.
|
||||
2330000 - Bullet - A bullet made out of steel. A set contains numerous bullets and once they are used up, they'll need to be recharged.\nAttack + 10
|
||||
@@ -2162,27 +2183,6 @@
|
||||
2109008 - Bubbling Summoning Bag - For use in the restricted bonus map area of the subway station.
|
||||
2109009 - Jr. Yeti Pharaoh Summoning Bag - Summons Jr. Yeti Pharaoh for the bonus stage of Nett's Pyramid (Easy, Normal, Hard)
|
||||
2109010 - Jr. Yeti Pharaoh Summoning Bag - Summons Jr. Yeti Pharaoh for the bonus stage of Nett's Pyramid (Hell Mode)
|
||||
2280013 - [Skill Book] Final Blow - Skill Book from which you can learn about the #cFinal Blow# skill.\nJob: 4th Lv Aran\nCondition: #cFinal Blow# not available
|
||||
2280014 - [Skill Book] High Defense - Skill Book from which you can learn about the #cHigh Defense# skill.\nJob: 4th Lv Aran\nCondition: #cHigh Defense# not available
|
||||
2280015 - [Skill Book] Combo Tempest - Skill Book from which you can learn about the #cCombo Tempest# skill.\nJob: 4th Lv Aran\nCondition: #cCombo Tempest# not available
|
||||
2280017 - [Skill Book] Pig's Weakness - Skill Book from which you can learn about the #cPig's Weakness# skill.\nCondition: #cPig's Weakness# not available
|
||||
2280016 - [Skill Book] Combo Barrier - Skill Book from which you can learn about the #cCombo Barrier# skill.\nJob: 4th Lv Aran\nCondition: #cCombo Barrier# not available
|
||||
2280018 - [Skill Book] Stump's Weakness - Skill Book from which you can learn about the #cStump's Weakness# skill.\nCondition: #cStump's Weakness# not available
|
||||
2280019 - [Skill Book] Slime's Weakness - Skill Book from which you can learn about the #cSlime's Weakness# skill.\nCondition: #cSlime's Weakness# not available
|
||||
2290126 - [Mastery Book] Overswing 20 - With a 70% success rate, raises the Mastery Level of #cOverswing# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290127 - [Mastery Book] Overswing 30 - With a 50% success rate, raises the Mastery Level of #cOverswing# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290128 - [Mastery Book] High Mastery 20 - With a 70% success rate, raises the Mastery Level of #cHigh Mastery# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290129 - [Mastery Book]High Mastery 30 - With a 50% success rate, raises the Mastery Level of #cHigh Mastery# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290130 - [Mastery Book] Freeze Standing 20 - With a 70% success rate, raises the Mastery Level of #cFreeze Standing# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290131 - [Mastery Book] Freeze Standing 30 - With a 50% success rate, raises the Mastery Level of #cFreeze Standing# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290132 - [Mastery Book] Final Blow 20 - With a 70% success rate, raises the Mastery Level of #cFinal Blow# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290133 - [Mastery Book] Final Blow 30 - With a 50% success rate, raises the Mastery Level of #cFinal Blow# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290134 - [Mastery Book] High Defense 20 - With a 70% success rate, raises the Mastery Level of #cHigh Defense# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290135 - [Mastery Book] High Defense 30 - With a 50% success rate, raises the Mastery Level of #cHigh Defense# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290136 - [Mastery Book] Combo Tempest 20 - With a 70% success rate, raises the Mastery Level of #cCombo Tempest# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290137 - [Mastery Book] Combo Tempest 30 - With a 50% success rate, raises the Mastery Level of #cCombo Tempest# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2290138 - [Mastery Book] Combo Barrier 20 - With a 70% success rate, raises the Mastery Level of #cCombo Barrier# to 20.\nJob: Aran\nCondition: Min Skill Lv. 5
|
||||
2290139 - [Mastery Book] Combo Barrier 30 - With a 50% success rate, raises the Mastery Level of #cCombo Barrier# to 30.\nJob: Aran\nCondition: Min Skill Lv. 15
|
||||
2380014 - Dejected Green Mushroom Card - A card featuring the Dejected Green Mushroom.
|
||||
2380015 - Muru Card - A card featuring Muru.
|
||||
2380016 - Murupa Card - A card featuring Murupa.
|
||||
@@ -2209,7 +2209,7 @@
|
||||
2430016 - Crystal Chest - A chest full of items that's sure to excite anyone who sees it. Open it by August 31st, 2009, or it'll disappear.
|
||||
2450000 - Hunter's Luck - For 30 minutes, doubles your EXP from hunting.
|
||||
2040758 - Scroll for Shoes for ATT - Improves attack on shoes.\nSuccess rate: 100%. Weapon Attack +1
|
||||
2040759 - Scroll for Shoes for ATT - Improves attack on gloves.\nSuccess rate: 60%. Weapon Attack +2. The success rate of this scroll can be enhanced by Vega's Spell.
|
||||
2040759 - Scroll for Shoes for ATT - Improves attack on shoes.\nSuccess rate: 60%. Weapon Attack +2. The success rate of this scroll can be enhanced by Vega's Spell.
|
||||
2040760 - Scroll for Shoes for ATT - Improves attack on shoes.\nSuccess rate: 10%, Weapon Attack +3. The success rate of this scroll can be enhanced by Vega's Spell.
|
||||
2044815 - Scroll for Knuckler for Attack 100% - Improves attack on Knucklers.\nSuccess rate: 100%. Weapon Attack +2, STR +1
|
||||
2044817 - Scroll for Knuckler for Attack 50% - Improves attack on Knucklers.\nSuccess rate: 50%. Weapon Attack +5, STR +3, DEX +1
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("3rdJob_bowman_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
eim.getInstanceMap(maxMapId).resetPQ(1);
|
||||
|
||||
@@ -97,8 +105,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("3rdJob_magician_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
eim.getInstanceMap(maxMapId).resetPQ(1);
|
||||
|
||||
@@ -97,8 +105,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -43,15 +43,38 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function checkHogHealth(eim) {
|
||||
var watchHog = eim.getInstanceMap(923010000).getMonsterById(9300102);
|
||||
if (watchHog != null) {
|
||||
var hp = watchHog.getHp();
|
||||
var oldHp = eim.getIntProperty("whog_hp");
|
||||
|
||||
if (oldHp - hp > 1000) { // or 800, if using mobHP / eventTime
|
||||
eim.dropMessage(6, "Please protect the pig from the aliens!"); // thanks Vcoc
|
||||
}
|
||||
eim.setIntProperty("whog_hp", hp);
|
||||
}
|
||||
}
|
||||
|
||||
function respawnStages(eim) {
|
||||
var i;
|
||||
for (i = 0; i < eventMaps.length; i++) {
|
||||
eim.getInstanceMap(eventMaps[i]).instanceMapRespawn();
|
||||
}
|
||||
|
||||
checkHogHealth(eim);
|
||||
|
||||
eim.schedule("respawnStages", 10 * 1000);
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("3rdJob_mount_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
eim.setProperty("whog_hp", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
var mapObj = eim.getInstanceMap(entryMap);
|
||||
|
||||
@@ -127,8 +150,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -51,6 +51,14 @@ function playerEntry(eim, player) {
|
||||
eim.startEventTimer(eventTime * 60000);
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("3rdJob_pirate_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerUnregistered(eim, player) {}
|
||||
|
||||
function playerExit(eim, player) {
|
||||
@@ -97,8 +105,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("3rdJob_thief_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
eim.getInstanceMap(maxMapId).resetPQ(1);
|
||||
|
||||
@@ -97,8 +105,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("3rdJob_warrior_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
eim.getInstanceMap(maxMapId).resetPQ(1);
|
||||
|
||||
@@ -97,8 +105,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -20,27 +20,22 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
var exitMap;
|
||||
var instanceId;
|
||||
var minPlayers = 3;
|
||||
|
||||
function init() {
|
||||
instanceId = 1;
|
||||
}
|
||||
function init() {}
|
||||
|
||||
function monsterValue(eim, mobId) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function setup() {
|
||||
function setup(level, lobbyid) {
|
||||
exitMap = em.getChannelServer().getMapFactory().getMap(105090800); // <exit>
|
||||
var instanceName = "4jberserk" + instanceId;
|
||||
|
||||
var eim = em.newInstance(instanceName);
|
||||
|
||||
var eim = em.newInstance("4jberserk_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
|
||||
var mf = eim.getMapFactory();
|
||||
|
||||
instanceId++;
|
||||
|
||||
|
||||
var map = mf.getMap(910500200);
|
||||
map.addMapTimer(3*60);
|
||||
em.schedule("timeOut", 20 * 60000);
|
||||
|
||||
@@ -27,23 +27,21 @@
|
||||
*/
|
||||
|
||||
var exitMap;
|
||||
var instanceId;
|
||||
var minPlayers = 3;
|
||||
|
||||
function init() {
|
||||
instanceId = 1;
|
||||
}
|
||||
function init() {}
|
||||
|
||||
function monsterValue(eim, mobId) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
function setup() {
|
||||
function setup(level, lobbyid) {
|
||||
exitMap = em.getChannelServer().getMapFactory().getMap(105090700); // <exit>
|
||||
var instanceName = "4jrush" + instanceId;
|
||||
var eim = em.newInstance(instanceName);
|
||||
|
||||
var eim = em.newInstance("4jrush_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
|
||||
var mf = eim.getMapFactory();
|
||||
instanceId++;
|
||||
var map = mf.getMap(910500100);
|
||||
map.addMapTimer(20*60);
|
||||
em.schedule("timeOut", 20 * 60000);
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("Aran_2ndmount_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function respawnStages(eim) {}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
@@ -114,8 +122,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("Aran_3rdmount_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function respawnStages(eim) {}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
@@ -119,8 +127,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
|
||||
@@ -41,6 +41,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("BalrogQuest_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function respawnStages(eim) {}
|
||||
|
||||
function afterSetup(eim) {}
|
||||
@@ -104,8 +112,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
function changedLeader(eim, leader) {}
|
||||
|
||||
@@ -32,6 +32,14 @@ function init() {
|
||||
em.setProperty("noEntry","false");
|
||||
}
|
||||
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("DollHouse_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
return eim;
|
||||
}
|
||||
|
||||
function playerEntry(eim, player) {
|
||||
eim.getInstanceMap(entryMap).shuffleReactors();
|
||||
eim.setExclusiveItems([4031094]);
|
||||
@@ -81,8 +89,6 @@ function dispose() {}
|
||||
|
||||
// ---------- FILLER FUNCTIONS ----------
|
||||
|
||||
function setup(eim, leaderid) {}
|
||||
|
||||
function monsterValue(eim, mobid) {return 0;}
|
||||
|
||||
function disbandParty(eim, player) {}
|
||||
|
||||
@@ -16,8 +16,8 @@ function init() {
|
||||
rideTime = em.getTransportationTime(rideTime);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var eim = em.newInstance("Hak_" + + em.getProperty("player"));
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("Hak_" + lobbyid);
|
||||
return eim;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ function init() {
|
||||
rideTime = em.getTransportationTime(rideTime);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var eim = em.newInstance("KerningTrain_" + em.getProperty("player"));
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("KerningTrain_" + lobbyid);
|
||||
return eim;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,11 @@ function init() {
|
||||
otherMap = em.getChannelServer().getMapFactory().getMap(103040420);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var eim = em.newInstance("RockSpirit_" + em.getProperty("player"));
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("RockSpirit_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
respawn(eim);
|
||||
eim.startEventTimer(timer);
|
||||
return eim;
|
||||
|
||||
@@ -34,8 +34,11 @@ function init() {
|
||||
otherMap = em.getChannelServer().getMapFactory().getMap(103040450);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var eim = em.newInstance("RockSpiritVIP_" + em.getProperty("player"));
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("RockSpiritVIP_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
eim.setProperty("boss", "0");
|
||||
|
||||
respawn(eim);
|
||||
eim.startEventTimer(timer);
|
||||
return eim;
|
||||
|
||||
@@ -33,8 +33,9 @@ function getEligibleParty(party) { //selects, from the given party, the tea
|
||||
return eligible;
|
||||
}
|
||||
|
||||
function setup() {
|
||||
var eim = em.newInstance("s4aWorld");
|
||||
function setup(level, lobbyid) {
|
||||
var eim = em.newInstance("s4aWorld_" + lobbyid);
|
||||
eim.setProperty("level", level);
|
||||
|
||||
eim.getInstanceMap(910500000).resetPQ(1);
|
||||
respawnStages(eim);
|
||||
|
||||
@@ -3,12 +3,12 @@ importPackage(Packages.tools);
|
||||
|
||||
var mapId = 200090000;
|
||||
|
||||
function start(pi) {
|
||||
var map = pi.getClient().getChannelServer().getMapFactory().getMap(mapId);
|
||||
function start(ms) {
|
||||
var map = ms.getClient().getChannelServer().getMapFactory().getMap(mapId);
|
||||
|
||||
if(map.getDocked()) {
|
||||
pi.getClient().announce(MaplePacketCreator.musicChange("Bgm04/ArabPirate"));
|
||||
pi.getClient().announce(MaplePacketCreator.crogBoatPacket(true));
|
||||
ms.getClient().announce(MaplePacketCreator.musicChange("Bgm04/ArabPirate"));
|
||||
ms.getClient().announce(MaplePacketCreator.crogBoatPacket(true));
|
||||
}
|
||||
|
||||
return(true);
|
||||
|
||||
@@ -3,12 +3,12 @@ importPackage(Packages.tools);
|
||||
|
||||
var mapId = 200090010;
|
||||
|
||||
function start(pi) {
|
||||
var map = pi.getClient().getChannelServer().getMapFactory().getMap(mapId);
|
||||
function start(ms) {
|
||||
var map = ms.getClient().getChannelServer().getMapFactory().getMap(mapId);
|
||||
|
||||
if(map.getDocked()) {
|
||||
pi.getClient().announce(MaplePacketCreator.musicChange("Bgm04/ArabPirate"));
|
||||
pi.getClient().announce(MaplePacketCreator.crogBoatPacket(true));
|
||||
ms.getClient().announce(MaplePacketCreator.musicChange("Bgm04/ArabPirate"));
|
||||
ms.getClient().announce(MaplePacketCreator.crogBoatPacket(true));
|
||||
}
|
||||
|
||||
return(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
function start(pi) {
|
||||
var map = pi.getClient().getChannelServer().getMapFactory().getMap(922000000);
|
||||
function start(ms) {
|
||||
var map = ms.getClient().getChannelServer().getMapFactory().getMap(922000000);
|
||||
map.clearDrops();
|
||||
map.resetReactors();
|
||||
map.shuffleReactors();
|
||||
|
||||
@@ -25,10 +25,11 @@ function action(mode, type, selection) {
|
||||
}
|
||||
if (status == 1) {
|
||||
if (selection == 0) {
|
||||
var train = cm.getEventManager("KerningTrain");
|
||||
train.newInstance("KerningTrain");
|
||||
train.setProperty("player", cm.getPlayer().getName());
|
||||
train.startInstance(cm.getPlayer());
|
||||
var em = cm.getEventManager("KerningTrain");
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("The passenger wagon is already full. Try again a bit later.");
|
||||
}
|
||||
|
||||
cm.dispose();
|
||||
return;
|
||||
} else if (selection == 1) {
|
||||
|
||||
@@ -47,10 +47,10 @@ function action(mode, type, selection) {
|
||||
if (status == 0) {
|
||||
if (selection == 0) {
|
||||
if (cm.isQuestStarted(2286) || cm.isQuestStarted(2287) || cm.isQuestStarted(2288)) {
|
||||
var rock = cm.getEventManager("RockSpirit");
|
||||
rock.newInstance("RockSpirit");
|
||||
rock.setProperty("player", cm.getPlayer().getName());
|
||||
rock.startInstance(cm.getPlayer());
|
||||
var em = cm.getEventManager("RockSpirit");
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("Uh... It looks like the rooms ahead are a bit crowded right now. Please wait around here for a bit, ok?");
|
||||
}
|
||||
cm.dispose();
|
||||
return;
|
||||
} else {
|
||||
|
||||
@@ -59,13 +59,12 @@ function start() {
|
||||
if (em == null)
|
||||
cm.sendOk("Sorry, but 3rd job advancement (" + js + ") is closed.");
|
||||
else {
|
||||
if (em.getProperty("noEntry") == "false") {
|
||||
var eim = em.newInstance("3rdjob_" + js);
|
||||
eim.registerPlayer(cm.getPlayer());
|
||||
}
|
||||
else {
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("Someone else is already challenging the clone. Please wait until the area is cleared.");
|
||||
}
|
||||
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition.");
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
+12
-1
@@ -6,7 +6,7 @@
|
||||
var status;
|
||||
|
||||
function start(){
|
||||
status = -1;
|
||||
status = -1;
|
||||
action(1, 0, 0);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ function action(mode, type, selection){
|
||||
|
||||
|
||||
if(cm.getMapId() == 106021402) {
|
||||
if (!(cm.isQuestCompleted(2331))) {
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status == 0){
|
||||
cm.sendSimple("#L0#Enter to fight #bKing Pepe#k and #bYeti Brothers#k.#l\r\n#L1#Enter to fight #bPrime Minister#k.#l");
|
||||
}
|
||||
@@ -48,6 +53,12 @@ function action(mode, type, selection){
|
||||
}
|
||||
}
|
||||
} else {
|
||||
var questProgress = cm.getQuestProgress(2330, 3300005) + cm.getQuestProgress(2330, 3300006) + cm.getQuestProgress(2330, 3300007); //3 Yetis
|
||||
if (!(cm.isQuestStarted(2330) && questProgress < 3)) { // thanks Vcoc for finding an exploit with boss entry through NPC
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
if(status == 0){
|
||||
cm.sendSimple("#L1#Enter to fight #bKing Pepe#k and #bYeti Brothers#k.#l");
|
||||
}
|
||||
|
||||
@@ -140,11 +140,11 @@ function action(mode, type, selection){
|
||||
}
|
||||
} else {
|
||||
if (cm.getPlayer().getLevel() >= 50){
|
||||
cm.sendNext("Ok, go.");
|
||||
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
|
||||
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
|
||||
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
|
||||
}else
|
||||
cm.sendNext("You're weak.");
|
||||
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ function action(mode, type, selection){
|
||||
}
|
||||
} else {
|
||||
if (cm.getPlayer().getLevel() >= 50){
|
||||
cm.sendNext("Ok, go.");
|
||||
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
|
||||
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
|
||||
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
|
||||
}else
|
||||
cm.sendNext("You're weak.");
|
||||
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,11 +113,11 @@ function action(mode, type, selection){
|
||||
}
|
||||
} else {
|
||||
if (cm.getPlayer().getLevel() >= 50){
|
||||
cm.sendNext("Ok, go.");
|
||||
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
|
||||
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
|
||||
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
|
||||
}else
|
||||
cm.sendNext("You're weak.");
|
||||
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,11 +112,11 @@ function action(mode, type, selection){
|
||||
}
|
||||
} else {
|
||||
if (cm.getPlayer().getLevel() >= 50){
|
||||
cm.sendNext("Ok, go.");
|
||||
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
|
||||
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
|
||||
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
|
||||
}else
|
||||
cm.sendNext("You're weak.");
|
||||
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,11 +111,11 @@ function action(mode, type, selection){
|
||||
}
|
||||
} else {
|
||||
if (cm.getPlayer().getLevel() >= 50){
|
||||
cm.sendNext("Ok, go.");
|
||||
cm.sendOk("The Chief's Residence Council grants you #bconcession#k to make part of the #rcounteroffensive team against Zakum#k. Good luck on your journey ahead.");
|
||||
if(!(cm.isQuestStarted(100200) || cm.isQuestCompleted(100200))) cm.startQuest(100200);
|
||||
if(Packages.constants.ServerConstants.USE_ENABLE_SOLO_EXPEDITIONS && !cm.isQuestCompleted(100201)) cm.completeQuest(100201);
|
||||
}else
|
||||
cm.sendNext("You're weak.");
|
||||
cm.sendOk("You're way too weak to make part of the #rcounteroffensive team against Zakum#k. Reach at least #blevel 50#k, then talk to me.");
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition."); // getValue, thanks MedicOP for finding this issue
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
@@ -78,13 +78,13 @@ function action(mode, type, selection) {
|
||||
if (getEimForString(em,passwd) != null)
|
||||
cm.sendOk("You may not use that password.");
|
||||
else { // start Zakum Battle
|
||||
var eim = em.newInstance("Zakum" + passwd);
|
||||
if(!em.startInstance(eim,cm.getPlayer().getName())) {
|
||||
cm.sendOk("A party in your name is already registered in this instance.");
|
||||
cm.dispose();
|
||||
return;
|
||||
//var em = cm.getEventManager("Zakum" + passwd);
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("A party is already registered in this instance.");
|
||||
}
|
||||
eim.registerPlayer(cm.getPlayer());
|
||||
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (state == 1) { // Member
|
||||
|
||||
@@ -56,8 +56,11 @@ function action(mode, type, selection) {
|
||||
if (status == 1)
|
||||
cm.sendYesNo("Are you ready to enter the dollhouse map?");
|
||||
else if (status == 2) {
|
||||
var eim = em.newInstance("DollHouse");
|
||||
eim.registerPlayer(cm.getPlayer());
|
||||
var em = cm.getEventManager("DollHouse");
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("Hmm... The DollHouse is being challenged already, it seems. Try again later.");
|
||||
}
|
||||
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,11 +36,7 @@ function start() {
|
||||
if (em == null)
|
||||
cm.sendOk("Sorry, but 3rd job advancement (mount) is closed.");
|
||||
else {
|
||||
if (em.getProperty("noEntry") == "false") {
|
||||
var eim = em.newInstance("3rdjob_mount");
|
||||
eim.registerPlayer(cm.getPlayer());
|
||||
}
|
||||
else {
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("There is currently someone in this map, come back later.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition.");
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
@@ -85,10 +85,14 @@ function action(mode, type, selection) {
|
||||
cm.warp(250000100, 0);
|
||||
cm.dispose();
|
||||
} else {
|
||||
var em = cm.getEventManager("Hak");
|
||||
if (!em.startInstance(cm.getPlayer())) {
|
||||
cm.sendOk("Uh... We are currently taking requests from too many maplers right now... Please try again in a bit.");
|
||||
cm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
cm.gainMeso(-cost[slct]);
|
||||
hak.newInstance("Hak");
|
||||
hak.setProperty("player", cm.getPlayer().getName());
|
||||
hak.startInstance(cm.getPlayer());
|
||||
cm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition.");
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
@@ -175,7 +175,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition.");
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
@@ -158,7 +158,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition.");
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
@@ -175,7 +175,7 @@ function action(mode, type, selection) {
|
||||
if (selection > 0) {
|
||||
var banned = expedMembers.get(selection - 1);
|
||||
expedition.ban(banned);
|
||||
cm.sendOk("You have banned " + banned.getName() + " from the expedition.");
|
||||
cm.sendOk("You have banned " + banned.getValue() + " from the expedition.");
|
||||
cm.dispose();
|
||||
} else {
|
||||
cm.sendSimple(list);
|
||||
|
||||
@@ -48,6 +48,7 @@ function writeFeatureTab_PQs() {
|
||||
addFeature("Mu Lung Dojo.");
|
||||
addFeature("Capt. Latanica with party fighting the boss.");
|
||||
addFeature("Filled up missing obligatory event script methods.");
|
||||
addFeature("Secured uniquety of active lobby-name instances.");
|
||||
}
|
||||
|
||||
function writeFeatureTab_Skills() {
|
||||
@@ -126,7 +127,9 @@ function writeFeatureTab_MonstersMapsReactors() {
|
||||
addFeature("Mobs now can drop more than one of the same equip.");
|
||||
addFeature("Mobs only drop items collectable by the player/party.");
|
||||
addFeature("Mobs shouldn't fall from foothold too often now.");
|
||||
addFeature("Puppets holds targeted mobs nearby on new aggro feat.");
|
||||
addFeature("Properly applying MP cost on non-skill mob moves.");
|
||||
addFeature("Limited underling mob spawns.");
|
||||
addFeature("Implemented mob banish by touch & skill move.");
|
||||
addFeature("Redesigned HT mechanics: assemble & dmg taken.");
|
||||
addFeature("Implemented Zombify disease status.");
|
||||
@@ -253,10 +256,12 @@ function writeFeatureTab_Project() {
|
||||
addFeature("Improved login phase, using cache over DB queries.");
|
||||
addFeature("Protected many flaws with login management system.");
|
||||
addFeature("Developed a robust anti-exploit login coordinator.");
|
||||
addFeature("Revised uniqueness aspect of logged in accounts.");
|
||||
addFeature("Usage of HikariCP to improve DB connection calls.");
|
||||
addFeature("Usage of Java Threadpool to improve runnable calls.");
|
||||
addFeature("Developed many survey tools for content profiling.");
|
||||
addFeature("Removed dangling item name throughout game files.");
|
||||
addFeature("Remodeled item scripts, properly using NPC dialogs.");
|
||||
addFeature("ThreadTracker: runtime tool for deadlock detection.");
|
||||
addFeature("Channel, World and Server-wide timer management.");
|
||||
addFeature("Thoroughly reviewed encapsulation for player stats.");
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
function enter(pi) {
|
||||
var em = pi.getEventManager("KerningTrain");
|
||||
if (!em.startInstance(pi.getPlayer())) {
|
||||
pi.message("The passenger wagon is already full. Try again a bit later.");
|
||||
return false;
|
||||
}
|
||||
|
||||
pi.playPortalSound();
|
||||
var train = pi.getEventManager("KerningTrain");
|
||||
train.newInstance("KerningTrain");
|
||||
train.setProperty("player", pi.getPlayer().getName());
|
||||
train.startInstance(pi.getPlayer());
|
||||
return true;
|
||||
}
|
||||
@@ -6,14 +6,13 @@ function enter(pi) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (em.getProperty("noEntry") == "false") {
|
||||
var eim = em.newInstance("Aran_2ndmount");
|
||||
eim.registerPlayer(pi.getPlayer());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
var em = pi.getEventManager("Aran_2ndmount");
|
||||
if (!em.startInstance(pi.getPlayer())) {
|
||||
pi.message("There is currently someone in this map, come back later.");
|
||||
return false;
|
||||
} else {
|
||||
pi.playPortalSound();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -28,6 +28,8 @@ function enter(pi) {
|
||||
pi.playPortalSound();
|
||||
pi.warp(900000000, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
pi.message("Private property. This place can only be entered when running an errand from Camila.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,9 @@ function enter(pi) {
|
||||
case 100000201:
|
||||
pi.warp(100000204, 2); //or 100000205
|
||||
break;
|
||||
case 101000003: // portal warp fix thanks to Vcoc
|
||||
pi.warp(101000004, 2); //or 101000005
|
||||
break;
|
||||
default:
|
||||
pi.warp(pi.getMapId() + 1, 1); //or + 2
|
||||
break;
|
||||
|
||||
@@ -22,13 +22,13 @@ function start(mode, type, selection) {
|
||||
} else if (status == 3) {
|
||||
qm.sendAcceptDecline("Please, Aran. Please stop me from becoming enraged. Only you can control me. It's getting out of my hands now. Please do whatever it takes to #rstop me from going berserk#k!");
|
||||
} else if (status == 4) {
|
||||
qm.startQuest();
|
||||
|
||||
var mb = qm.getEventManager("MahaBattle");
|
||||
mb.newInstance("MahaBattle");
|
||||
mb.setProperty("player", qm.getPlayer().getName());
|
||||
mb.startInstance(qm.getPlayer());
|
||||
|
||||
var em = qm.getEventManager("MahaBattle");
|
||||
if (!em.startInstance(qm.getPlayer())) {
|
||||
qm.sendOk("There is currently someone in this map, come back later.");
|
||||
} else {
|
||||
qm.startQuest();
|
||||
}
|
||||
|
||||
qm.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,17 +48,14 @@ function start(mode, type, selection) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (em.getProperty("noEntry") == "false") {
|
||||
var eim = em.newInstance("Aran_3rdmount");
|
||||
eim.registerPlayer(qm.getPlayer());
|
||||
|
||||
qm.forceStartQuest();
|
||||
qm.dispose();
|
||||
}
|
||||
else {
|
||||
var em = qm.getEventManager("Aran_3rdmount");
|
||||
if (!em.startInstance(qm.getPlayer())) {
|
||||
qm.sendOk("There is currently someone in this map, come back later.");
|
||||
qm.dispose();
|
||||
} else {
|
||||
qm.forceStartQuest();
|
||||
}
|
||||
|
||||
qm.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,17 +42,14 @@ function start(mode, type, selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (em.getProperty("noEntry") == "false") {
|
||||
var eim = em.newInstance("BalrogQuest");
|
||||
eim.registerPlayer(qm.getPlayer());
|
||||
eim.startEvent();
|
||||
|
||||
qm.dispose();
|
||||
}
|
||||
else {
|
||||
var em = qm.getEventManager("BalrogQuest");
|
||||
if (!em.startInstance(qm.getPlayer())) {
|
||||
qm.sendOk("There is currently someone in this map, come back later.");
|
||||
qm.dispose();
|
||||
} else {
|
||||
qm.forceStartQuest();
|
||||
}
|
||||
|
||||
qm.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,13 +43,14 @@ function end(mode, type, selection) {
|
||||
|
||||
qm.sendNext("You got the #b#i4032521##k with you, great. Let me show you the way.");
|
||||
} else if (status == 1) {
|
||||
var em = qm.getEventManager("RockSpiritVIP");
|
||||
if (!em.startInstance(qm.getPlayer())) {
|
||||
qm.sendOk("Uh... It looks like the rooms ahead are a bit crowded right now. Please wait around here for a bit, ok?");
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
qm.gainItem(4032521, -10);
|
||||
|
||||
var rock = qm.getEventManager("RockSpiritVIP");
|
||||
rock.newInstance("RockSpiritVIP");
|
||||
rock.setProperty("player", qm.getPlayer().getName());
|
||||
rock.startInstance(qm.getPlayer());
|
||||
|
||||
qm.forceCompleteQuest();
|
||||
qm.dispose();
|
||||
}
|
||||
|
||||
+14
-1
@@ -41,9 +41,22 @@ function start(mode, type, selection) {
|
||||
return;
|
||||
}
|
||||
|
||||
qm.sendNext("You have brought a #b#t4001094##k, thank you for the effort!");
|
||||
if (qm.haveItem(2041200, 1)) {
|
||||
qm.sendOk("(The #b#t2041200##k in my bag has grown brighter since reaching this place... Noticing again, the young dragon over there seems to be glaring bitterly towards it.)");
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
qm.sendNext("You have brought a #b#t4001094##k, thank you for retrieving one more of my kin to the nest! Please have this...\r\n\r\n....... (bleuuhnuhgh) (blahrgngnhhng) ...\r\n\r\nehh, #b#t2041200##k as a token of my kin's gratitude. And do a favor for us, please, get that thing out of here...");
|
||||
} else if (status == 1) {
|
||||
if (!qm.canHold(2041200, 1)) {
|
||||
qm.sendOk("Please make a room on your USE inventory to receive the reward.");
|
||||
qm.dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
qm.gainItem(4001094, -1);
|
||||
qm.gainItem(2041200, 1); // quest not rewarding properly found thanks to MedicOP & Thora
|
||||
qm.gainExp(42000);
|
||||
|
||||
qm.forceCompleteQuest();
|
||||
|
||||
@@ -16458,6 +16458,7 @@ CREATE TABLE IF NOT EXISTS `pets` (
|
||||
`closeness` int(10) unsigned NOT NULL,
|
||||
`fullness` int(10) unsigned NOT NULL,
|
||||
`summoned` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`flag` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`petid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import net.server.world.World;
|
||||
import scripting.event.EventInstanceManager;
|
||||
import server.CashShop;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleItemInformationProvider.ScriptedItem;
|
||||
import server.MaplePortal;
|
||||
import server.MapleShop;
|
||||
import server.MapleStatEffect;
|
||||
@@ -287,6 +288,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private AutobanManager autoban;
|
||||
private boolean isbanned = false;
|
||||
private boolean blockCashShop = false;
|
||||
private boolean allowExpGain = false;
|
||||
private byte pendantExp = 0, lastmobcount = 0, doorSlot = -1;
|
||||
private List<Integer> trockmaps = new ArrayList<>();
|
||||
private List<Integer> viptrockmaps = new ArrayList<>();
|
||||
@@ -649,6 +651,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
|
||||
public void addSummon(int id, MapleSummon summon) {
|
||||
summons.put(id, summon);
|
||||
|
||||
if (summon.isPuppet()) {
|
||||
map.addPlayerPuppet(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void addVisibleMapObject(MapleMapObject mo) {
|
||||
@@ -805,6 +811,10 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
public void toggleBlockCashShop() {
|
||||
blockCashShop = !blockCashShop;
|
||||
}
|
||||
|
||||
public void toggleExpGain() {
|
||||
allowExpGain = !allowExpGain;
|
||||
}
|
||||
|
||||
public void setClient(MapleClient c) {
|
||||
this.client = c;
|
||||
@@ -1728,6 +1738,15 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<MapleMonster> getControlledMonsters() {
|
||||
cpnLock.lock();
|
||||
try {
|
||||
return new ArrayList<>(controlled);
|
||||
} finally {
|
||||
cpnLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseControlledMonsters() {
|
||||
Collection<MapleMonster> controlledMonsters;
|
||||
|
||||
@@ -1799,7 +1818,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
mpcs = getPartyMembersOnSameMap();
|
||||
}
|
||||
|
||||
String itemScriptName = null;
|
||||
ScriptedItem itemScript = null;
|
||||
mapitem.lockItem();
|
||||
try {
|
||||
if (mapitem.isPickedUp()) {
|
||||
@@ -1872,9 +1891,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
this.gainMeso(mapitem.getMeso(), true, true, false);
|
||||
}
|
||||
} else if (mItem.getItemId() / 10000 == 243) {
|
||||
MapleItemInformationProvider.scriptedItem info = ii.getScriptedItemInfo(mItem.getItemId());
|
||||
if (info.runOnPickup()) {
|
||||
itemScriptName = info.getScript();
|
||||
ScriptedItem info = ii.getScriptedItemInfo(mItem.getItemId());
|
||||
if (info != null && info.runOnPickup()) {
|
||||
itemScript = info;
|
||||
} else {
|
||||
if (!MapleInventoryManipulator.addFromDrop(client, mItem, true)) {
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
@@ -1908,11 +1927,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
mapitem.unlockItem();
|
||||
}
|
||||
|
||||
if (itemScriptName != null) {
|
||||
if (itemScript != null) {
|
||||
ItemScriptManager ism = ItemScriptManager.getInstance();
|
||||
if (ism.scriptExists(itemScriptName)) {
|
||||
ism.runItemScript(client, itemScriptName);
|
||||
}
|
||||
ism.runItemScript(client, itemScript);
|
||||
}
|
||||
}
|
||||
client.announce(MaplePacketCreator.enableActions());
|
||||
@@ -1927,14 +1944,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public boolean canHold(int itemid, int quantity) {
|
||||
int hold = getCleanItemQuantity(itemid, false);
|
||||
|
||||
if(hold > 0) {
|
||||
if(hold + quantity <= ii.getSlotMax(client, itemid))
|
||||
return true;
|
||||
}
|
||||
|
||||
return getInventory(ItemConstants.getInventoryType(itemid)).getNextFreeSlot() > -1;
|
||||
return client.getAbstractPlayerInteraction().canHold(itemid, quantity);
|
||||
}
|
||||
|
||||
public boolean isRidingBattleship() {
|
||||
@@ -2907,7 +2917,7 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
private synchronized void gainExpInternal(long gain, int equip, int party, boolean show, boolean inChat, boolean white) { // need of method synchonization here detected thanks to MedicOP
|
||||
long total = Math.max(gain, -exp.get());
|
||||
|
||||
if (level < getMaxLevel()) {
|
||||
if (level < getMaxLevel() && (allowExpGain || this.getEventInstance() != null)) {
|
||||
long leftover = 0;
|
||||
long nextExp = exp.get() + total;
|
||||
|
||||
@@ -3464,9 +3474,11 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
getMap().broadcastMessage(MaplePacketCreator.removeSummon(summon, true), summon.getPosition());
|
||||
getMap().removeMapObject(summon);
|
||||
removeVisibleMapObject(summon);
|
||||
|
||||
summons.remove(summonId);
|
||||
|
||||
if (summon.getSkill() == DarkKnight.BEHOLDER) {
|
||||
if (summon.isPuppet()) {
|
||||
map.removePlayerPuppet(this);
|
||||
} else if (summon.getSkill() == DarkKnight.BEHOLDER) {
|
||||
if (beholderHealingSchedule != null) {
|
||||
beholderHealingSchedule.cancel(false);
|
||||
beholderHealingSchedule = null;
|
||||
@@ -4602,19 +4614,19 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public int getItemQuantity(int itemid, boolean checkEquipped) {
|
||||
int possesed = inventory[ItemConstants.getInventoryType(itemid).ordinal()].countById(itemid);
|
||||
int count = inventory[ItemConstants.getInventoryType(itemid).ordinal()].countById(itemid);
|
||||
if (checkEquipped) {
|
||||
possesed += inventory[MapleInventoryType.EQUIPPED.ordinal()].countById(itemid);
|
||||
count += inventory[MapleInventoryType.EQUIPPED.ordinal()].countById(itemid);
|
||||
}
|
||||
return possesed;
|
||||
return count;
|
||||
}
|
||||
|
||||
public int getCleanItemQuantity(int itemid, boolean checkEquipped) {
|
||||
int possesed = inventory[ItemConstants.getInventoryType(itemid).ordinal()].countNotOwnedById(itemid);
|
||||
int count = inventory[ItemConstants.getInventoryType(itemid).ordinal()].countNotOwnedById(itemid);
|
||||
if (checkEquipped) {
|
||||
possesed += inventory[MapleInventoryType.EQUIPPED.ordinal()].countNotOwnedById(itemid);
|
||||
count += inventory[MapleInventoryType.EQUIPPED.ordinal()].countNotOwnedById(itemid);
|
||||
}
|
||||
return possesed;
|
||||
return count;
|
||||
}
|
||||
|
||||
public MapleJob getJob() {
|
||||
@@ -6600,13 +6612,9 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
rs = ps.executeQuery();
|
||||
while (rs.next()) {
|
||||
String name = rs.getString("name");
|
||||
if (rs.getString("name").equals("rescueGaga")) {
|
||||
if (rs.getString("name").contentEquals("rescueGaga")) {
|
||||
ret.events.put(name, new RescueGaga(rs.getInt("info")));
|
||||
}
|
||||
//ret.events = new MapleEvents(new RescueGaga(rs.getInt("rescuegaga")), new ArtifactHunt(rs.getInt("artifacthunt")));
|
||||
}
|
||||
if (!ret.events.containsKey("rescueGaga")) {
|
||||
ret.events.put("rescueGaga", new RescueGaga(0));
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -6988,13 +6996,12 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
}
|
||||
|
||||
public void respawn(EventInstanceManager eim, int returnMap) {
|
||||
cancelAllBuffs(false);
|
||||
|
||||
updateHp(50);
|
||||
setStance(0);
|
||||
|
||||
if (eim != null) eim.unregisterPlayer(this); // some event scripts uses this...
|
||||
changeMap(returnMap);
|
||||
|
||||
cancelAllBuffs(false); // thanks Oblivium91 for finding out players still could revive in area and take damage before returning to town
|
||||
updateHp(50);
|
||||
setStance(0);
|
||||
}
|
||||
|
||||
private void prepareDragonBlood(final MapleStatEffect bloodEffect) {
|
||||
@@ -7514,6 +7521,8 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
this.getInventory(itEntry.getRight()).addItem(itEntry.getLeft());
|
||||
}
|
||||
|
||||
this.events.put("rescueGaga", new RescueGaga(0));
|
||||
|
||||
Connection con = null;
|
||||
PreparedStatement ps = null;
|
||||
|
||||
@@ -9733,7 +9742,6 @@ public class MapleCharacter extends AbstractMapleCharacterObject {
|
||||
events = null;
|
||||
mpc = null;
|
||||
mgc = null;
|
||||
events = null;
|
||||
party = null;
|
||||
family = null;
|
||||
|
||||
|
||||
+16
-10
@@ -517,11 +517,15 @@ public class MapleClient {
|
||||
}
|
||||
|
||||
public int login(String login, String pwd, String nibbleHwid) {
|
||||
loginattempt++;
|
||||
if (loginattempt > 4) {
|
||||
MapleSessionCoordinator.getInstance().closeSession(session, false);
|
||||
}
|
||||
int loginok = 5;
|
||||
|
||||
loginattempt++;
|
||||
if (loginattempt > 4) {
|
||||
loggedIn = false;
|
||||
MapleSessionCoordinator.getInstance().closeSession(session, false);
|
||||
return loginok;
|
||||
}
|
||||
|
||||
Connection con = null;
|
||||
PreparedStatement ps = null;
|
||||
ResultSet rs = null;
|
||||
@@ -748,7 +752,12 @@ public class MapleClient {
|
||||
return accId;
|
||||
}
|
||||
|
||||
public void updateLoginState(int newstate) {
|
||||
public void updateLoginState(int newstate) {
|
||||
// rules out possibility of multiple account entries
|
||||
if (newstate == LOGIN_LOGGEDIN) {
|
||||
MapleSessionCoordinator.getInstance().updateOnlineSession(this.getSession());
|
||||
}
|
||||
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, lastlogin = ? WHERE id = ?")) {
|
||||
@@ -763,6 +772,7 @@ public class MapleClient {
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (newstate == LOGIN_NOTLOGGEDIN) {
|
||||
loggedIn = false;
|
||||
serverTransition = false;
|
||||
@@ -797,9 +807,6 @@ public class MapleClient {
|
||||
MapleSessionCoordinator.getInstance().closeSession(session, null);
|
||||
updateLoginState(LOGIN_NOTLOGGEDIN);
|
||||
}
|
||||
} else if (state == LOGIN_LOGGEDIN && player == null) {
|
||||
state = LOGIN_LOGGEDIN;
|
||||
updateLoginState(LOGIN_LOGGEDIN);
|
||||
}
|
||||
rs.close();
|
||||
ps.close();
|
||||
@@ -1006,8 +1013,7 @@ public class MapleClient {
|
||||
|
||||
Server.getInstance().unregisterLoginState(this);
|
||||
|
||||
this.session.setAttribute(MapleClient.CLIENT_KEY, null);
|
||||
this.accountName = null;
|
||||
this.accountName = null;
|
||||
this.macs = null;
|
||||
this.hwid = null;
|
||||
this.birthday = null;
|
||||
|
||||
@@ -193,6 +193,7 @@ public class CommandsExecutor {
|
||||
addCommand("int", StatIntCommand.class);
|
||||
addCommand("luk", StatLukCommand.class);
|
||||
addCommand("enableauth", EnableAuthCommand.class);
|
||||
addCommand("toggleexp", ToggleExpCommand.class);
|
||||
|
||||
commandsNameDesc.add(levelCommandsCursor);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
This file is part of the HeavenMS MapleStory Server, commands OdinMS-based
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
@Author: Ronan
|
||||
*/
|
||||
package client.command.commands.gm0;
|
||||
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
|
||||
public class ToggleExpCommand extends Command {
|
||||
{
|
||||
setDescription("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(MapleClient c, String[] params) {
|
||||
if (c.tryacquireClient()) {
|
||||
try {
|
||||
c.getPlayer().toggleExpGain(); // Vcoc's idea
|
||||
} finally {
|
||||
c.releaseClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,12 +46,19 @@ public class GotoCommand extends Command {
|
||||
player.yellowMessage("Syntax: @goto <map name>");
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.getEventInstance() != null || MapleMiniDungeonInfo.isDungeonMap(player.getMapId()) || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit()) || !player.isAlive()) {
|
||||
player.dropMessage(1, "This command can not be used in this map.");
|
||||
|
||||
if (!player.isAlive()) {
|
||||
player.dropMessage(1, "This command cannot be used when you're dead.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.isGM()) {
|
||||
if (player.getEventInstance() != null || MapleMiniDungeonInfo.isDungeonMap(player.getMapId()) || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
|
||||
player.dropMessage(1, "This command can not be used in this map.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<String, Integer> gotomaps;
|
||||
if (player.isGM()) {
|
||||
gotomaps = new HashMap<>(GameConstants.GOTO_AREAS); // distinct map registry for GM/users suggested thanks to Vcoc
|
||||
|
||||
@@ -50,11 +50,18 @@ public class WarpCommand extends Command {
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.getEventInstance() != null || MapleMiniDungeonInfo.isDungeonMap(player.getMapId()) || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit()) || !player.isAlive()) {
|
||||
player.dropMessage(1, "This command cannot be used in this map.");
|
||||
if (!player.isAlive()) {
|
||||
player.dropMessage(1, "This command cannot be used when you're dead.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!player.isGM()) {
|
||||
if (player.getEventInstance() != null || MapleMiniDungeonInfo.isDungeonMap(player.getMapId()) || FieldLimit.CANNOTMIGRATE.check(player.getMap().getFieldLimit())) {
|
||||
player.dropMessage(1, "This command cannot be used in this map.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// expedition issue with this command detected thanks to Masterrulax
|
||||
player.saveLocationOnWarp();
|
||||
player.changeMap(target, target.getRandomPlayerSpawnpoint());
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleStat;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import constants.ItemConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
|
||||
public class FaceCommand extends Command {
|
||||
@@ -45,7 +46,7 @@ public class FaceCommand extends Command {
|
||||
try {
|
||||
if (params.length == 1) {
|
||||
int itemId = Integer.parseInt(params[0]);
|
||||
if (!(itemId >= 20000 && itemId < 22000) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
if (!ItemConstants.isFace(itemId) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
player.yellowMessage("Face id '" + params[0] + "' does not exist.");
|
||||
return;
|
||||
}
|
||||
@@ -55,7 +56,7 @@ public class FaceCommand extends Command {
|
||||
player.equipChanged();
|
||||
} else {
|
||||
int itemId = Integer.parseInt(params[1]);
|
||||
if (!(itemId >= 20000 && itemId < 22000) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
if (!ItemConstants.isFace(itemId) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
player.yellowMessage("Face id '" + params[1] + "' does not exist.");
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import client.MapleStat;
|
||||
import client.command.Command;
|
||||
import client.MapleClient;
|
||||
import client.MapleCharacter;
|
||||
import constants.ItemConstants;
|
||||
import server.MapleItemInformationProvider;
|
||||
|
||||
public class HairCommand extends Command {
|
||||
@@ -45,7 +46,7 @@ public class HairCommand extends Command {
|
||||
try {
|
||||
if (params.length == 1) {
|
||||
int itemId = Integer.parseInt(params[0]);
|
||||
if (!(itemId >= 30000 && itemId < 35000) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
if (!ItemConstants.isHair(itemId) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
player.yellowMessage("Hair id '" + params[0] + "' does not exist.");
|
||||
return;
|
||||
}
|
||||
@@ -55,7 +56,7 @@ public class HairCommand extends Command {
|
||||
player.equipChanged();
|
||||
} else {
|
||||
int itemId = Integer.parseInt(params[1]);
|
||||
if (!(itemId >= 30000 && itemId < 35000) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
if (!ItemConstants.isHair(itemId) || MapleItemInformationProvider.getInstance().getName(itemId) == null) {
|
||||
player.yellowMessage("Hair id '" + params[1] + "' does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,21 @@ public class MaplePet extends Item {
|
||||
private Point pos;
|
||||
private int stance;
|
||||
private boolean summoned;
|
||||
private int petFlag = 0;
|
||||
|
||||
public enum PetFlag {
|
||||
OWNER_SPEED(0x01);
|
||||
|
||||
private int i;
|
||||
|
||||
private PetFlag(int i) {
|
||||
this.i = i;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
private MaplePet(int id, short position, int uniqueid) {
|
||||
super(id, position, (short) 1);
|
||||
@@ -63,7 +78,7 @@ public class MaplePet extends Item {
|
||||
try {
|
||||
MaplePet ret = new MaplePet(itemid, position, petid);
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("SELECT name, level, closeness, fullness, summoned FROM pets WHERE petid = ?"); // Get pet details..
|
||||
PreparedStatement ps = con.prepareStatement("SELECT name, level, closeness, fullness, summoned, flag FROM pets WHERE petid = ?"); // Get pet details..
|
||||
ps.setInt(1, petid);
|
||||
ResultSet rs = ps.executeQuery();
|
||||
rs.next();
|
||||
@@ -72,6 +87,7 @@ public class MaplePet extends Item {
|
||||
ret.setLevel((byte) Math.min(rs.getByte("level"), 30));
|
||||
ret.setFullness(Math.min(rs.getInt("fullness"), 100));
|
||||
ret.setSummoned(rs.getInt("summoned") == 1);
|
||||
ret.setPetFlag(rs.getInt("flag"));
|
||||
rs.close();
|
||||
ps.close();
|
||||
con.close();
|
||||
@@ -108,13 +124,14 @@ public class MaplePet extends Item {
|
||||
public void saveToDb() {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("UPDATE pets SET name = ?, level = ?, closeness = ?, fullness = ?, summoned = ? WHERE petid = ?");
|
||||
PreparedStatement ps = con.prepareStatement("UPDATE pets SET name = ?, level = ?, closeness = ?, fullness = ?, summoned = ?, flag = ? WHERE petid = ?");
|
||||
ps.setString(1, getName());
|
||||
ps.setInt(2, getLevel());
|
||||
ps.setInt(3, getCloseness());
|
||||
ps.setInt(4, getFullness());
|
||||
ps.setInt(5, isSummoned() ? 1 : 0);
|
||||
ps.setInt(6, getUniqueId());
|
||||
ps.setInt(6, getPetFlag());
|
||||
ps.setInt(7, getUniqueId());
|
||||
ps.executeUpdate();
|
||||
ps.close();
|
||||
con.close();
|
||||
@@ -126,7 +143,7 @@ public class MaplePet extends Item {
|
||||
public static int createPet(int itemid) {
|
||||
try {
|
||||
Connection con = DatabaseConnection.getConnection();
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (petid, name, level, closeness, fullness, summoned) VALUES (?, ?, 1, 0, 100, 0)");
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (petid, name, level, closeness, fullness, summoned, flag) VALUES (?, ?, 1, 0, 100, 0, 0)");
|
||||
int ret = MapleCashidGenerator.generateCashId();
|
||||
ps.setInt(1, ret);
|
||||
ps.setString(2, MapleItemInformationProvider.getInstance().getName(itemid));
|
||||
@@ -143,7 +160,7 @@ 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 (petid, name, level, closeness, fullness, summoned) VALUES (?, ?, ?, ?, ?, 0)");
|
||||
PreparedStatement ps = con.prepareStatement("INSERT INTO pets (petid, name, level, closeness, fullness, summoned, flag) VALUES (?, ?, ?, ?, ?, 0, 0)");
|
||||
int ret = MapleCashidGenerator.generateCashId();
|
||||
ps.setInt(1, ret);
|
||||
ps.setString(2, MapleItemInformationProvider.getInstance().getName(itemid));
|
||||
@@ -274,6 +291,32 @@ public class MaplePet extends Item {
|
||||
public void setSummoned(boolean yes) {
|
||||
this.summoned = yes;
|
||||
}
|
||||
|
||||
public int getPetFlag() {
|
||||
return this.petFlag;
|
||||
}
|
||||
|
||||
private void setPetFlag(int flag) {
|
||||
this.petFlag = flag;
|
||||
}
|
||||
|
||||
public void addPetFlag(MapleCharacter owner, PetFlag flag) {
|
||||
this.petFlag |= flag.getValue();
|
||||
saveToDb();
|
||||
|
||||
Item petz = owner.getInventory(MapleInventoryType.CASH).getItem(getPosition());
|
||||
if (petz != null)
|
||||
owner.forceUpdateItem(petz);
|
||||
}
|
||||
|
||||
public void removePetFlag(MapleCharacter owner, PetFlag flag) {
|
||||
this.petFlag &= 0xFFFFFFFF ^ flag.getValue();
|
||||
saveToDb();
|
||||
|
||||
Item petz = owner.getInventory(MapleInventoryType.CASH).getItem(getPosition());
|
||||
if (petz != null)
|
||||
owner.forceUpdateItem(petz);
|
||||
}
|
||||
|
||||
public Pair<Integer, Boolean> canConsume(int itemId) {
|
||||
return MapleItemInformationProvider.getInstance().canPetConsume(this.getItemId(), itemId);
|
||||
|
||||
@@ -53,6 +53,7 @@ public class MapleKarmaManipulator {
|
||||
int flag = item.getFlag();
|
||||
|
||||
flag |= karmaFlag;
|
||||
flag &= (0xFFFFFFFF ^ ItemConstants.UNTRADEABLE);
|
||||
item.setFlag((byte) flag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ public class MakerProcessor {
|
||||
Map<Integer, Integer> reagentType = new LinkedHashMap<>();
|
||||
List<Integer> toRemove = new LinkedList<>();
|
||||
|
||||
boolean isWeapon = ItemConstants.isWeapon(toCreate) || ServerConstants.USE_MAKER_PERMISSIVE_ATKUP;
|
||||
boolean isWeapon = ItemConstants.isWeapon(toCreate) || ServerConstants.USE_MAKER_PERMISSIVE_ATKUP; // thanks Vcoc for finding a case where a weapon wouldn't be counted as such due to a bounding on isWeapon
|
||||
|
||||
for(Map.Entry<Integer, Short> r : reagentids.entrySet()) {
|
||||
int curRid = r.getKey();
|
||||
|
||||
@@ -217,7 +217,7 @@ public final class ItemConstants {
|
||||
}
|
||||
|
||||
public static boolean isWeapon(int itemId) {
|
||||
return itemId >= 1302000 && itemId < 1492024;
|
||||
return itemId >= 1302000 && itemId < 1493000;
|
||||
}
|
||||
|
||||
public static boolean isEquipment(int itemId) {
|
||||
@@ -235,4 +235,12 @@ public final class ItemConstants {
|
||||
public static boolean isWeddingToken(int itemId) {
|
||||
return itemId >= 4031357 && itemId <= 4031364;
|
||||
}
|
||||
|
||||
public static boolean isFace(int itemId) {
|
||||
return itemId >= 20000 && itemId < 22000;
|
||||
}
|
||||
|
||||
public static boolean isHair(int itemId) {
|
||||
return itemId >= 30000 && itemId < 35000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ public class ServerConstants {
|
||||
public static boolean USE_DISPLAY_NUMBERS_WITH_COMMA = true; //Enforce comma on displayed strings (use this when USE_UNITPRICE_WITH_COMMA is active and you still want to display comma-separated values).
|
||||
public static boolean USE_UNITPRICE_WITH_COMMA = true; //Set this accordingly with the layout of the unitPrices on Item.wz XML's, whether it's using commas or dots to represent fractions.
|
||||
public static final byte MIN_UNDERLEVEL_TO_EXP_GAIN = 20; //Characters are unable to get EXP from a mob if their level are under this threshold, only if "USE_ENFORCE_MOB_LEVEL_RANGE" is enabled. For bosses, this attribute is doubled.
|
||||
public static final byte MIN_UNDERLEVEL_TO_EXP_LEECH = 40; //Characters are unable to leech EXP from party member kills whose level difference are past this limit.
|
||||
public static final byte MIN_RANGELEVEL_TO_EXP_LEECH = 40; //Characters are unable to leech EXP from party member kills whose level difference are past this limit.
|
||||
public static final byte MAX_MONITORED_BUFFSTATS = 5; //Limits accounting for "dormant" buff effects, that should take place when stronger stat buffs expires.
|
||||
public static final int MAX_AP = 32767; //Max AP allotted on the auto-assigner.
|
||||
public static final int MAX_EVENT_LEVELS = 8; //Event has different levels of rewarding system.
|
||||
|
||||
@@ -88,8 +88,8 @@ public class MapleServerHandler extends IoHandlerAdapter {
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(IoSession session, Throwable cause) {
|
||||
if (cause instanceof IOException) { // mina closes session automatically and does not call sessionClosed on IOException
|
||||
session.closeNow(); // calls sessionClosed
|
||||
if (cause instanceof IOException) {
|
||||
closeMapleSession(session);
|
||||
} else {
|
||||
MapleClient client = (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
||||
|
||||
@@ -137,8 +137,7 @@ public class MapleServerHandler extends IoHandlerAdapter {
|
||||
session.setAttribute(MapleClient.CLIENT_KEY, client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionClosed(IoSession session) throws Exception {
|
||||
private void closeMapleSession(IoSession session) {
|
||||
if (isLoginServerHandler()) {
|
||||
MapleSessionCoordinator.getInstance().closeLoginSession(session);
|
||||
} else {
|
||||
@@ -157,10 +156,15 @@ public class MapleServerHandler extends IoHandlerAdapter {
|
||||
FilePrinter.printError(FilePrinter.ACCOUNT_STUCK, t);
|
||||
} finally {
|
||||
session.close();
|
||||
session.removeAttribute(MapleClient.CLIENT_KEY);
|
||||
session.removeAttribute(MapleClient.CLIENT_KEY);
|
||||
//client.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sessionClosed(IoSession session) throws Exception {
|
||||
closeMapleSession(session);
|
||||
super.sessionClosed(session);
|
||||
}
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ import constants.ItemConstants;
|
||||
import constants.GameConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.util.TimeZone;
|
||||
import net.server.coordinator.MapleSessionCoordinator;
|
||||
import server.CashShop.CashItemFactory;
|
||||
import server.MapleSkillbookInformationProvider;
|
||||
import server.ThreadManager;
|
||||
@@ -1693,7 +1694,7 @@ public class Server {
|
||||
if(c.isLoggedIn()) {
|
||||
c.disconnect(false, false);
|
||||
} else {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1766,8 +1767,13 @@ public class Server {
|
||||
System.out.println("Worlds + Channels are offline.");
|
||||
acceptor.unbind();
|
||||
acceptor = null;
|
||||
if (!restart) {
|
||||
System.exit(0);
|
||||
if (!restart) { // shutdown hook deadlocks if System.exit() method is used within its body chores, thanks MIKE for pointing that out
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.exit(0);
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
System.out.println("\r\nRestarting the server....\r\n");
|
||||
try {
|
||||
|
||||
@@ -130,7 +130,7 @@ public final class AllianceOperationHandler extends AbstractMaplePacketHandler {
|
||||
chr.saveGuildStatus();
|
||||
|
||||
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.addGuildToAlliance(alliance, guildid, c), -1, -1);
|
||||
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.updateAllianceInfo(alliance, c), -1, -1);
|
||||
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.updateAllianceInfo(alliance, c.getWorld()), -1, -1);
|
||||
Server.getInstance().allianceMessage(alliance.getId(), MaplePacketCreator.allianceNotice(alliance.getId(), alliance.getNotice()), -1, -1);
|
||||
chr.getGuild().dropMessage("Your guild has joined the [" + alliance.getName() + "] union.");
|
||||
|
||||
|
||||
@@ -29,6 +29,8 @@ import tools.MaplePacketCreator;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
public final class CharInfoRequestHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
slea.skip(4);
|
||||
int cid = slea.readInt();
|
||||
|
||||
@@ -24,7 +24,6 @@ package net.server.channel.handlers;
|
||||
import client.MapleBuffStat;
|
||||
import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.SkillFactory;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import server.maps.MapleSummon;
|
||||
import server.maps.MapleMapObject;
|
||||
|
||||
@@ -25,6 +25,7 @@ import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.autoban.AutobanFactory;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import client.inventory.manipulator.MapleInventoryManipulator;
|
||||
import client.inventory.manipulator.MapleKarmaManipulator;
|
||||
@@ -465,22 +466,41 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
} else if (mode == Action.SET_ITEMS.getCode()) {
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
MapleInventoryType ivType = MapleInventoryType.getByType(slea.readByte());
|
||||
Item item = chr.getInventory(ivType).getItem(slea.readShort());
|
||||
short pos = slea.readShort();
|
||||
Item item = chr.getInventory(ivType).getItem(pos);
|
||||
short quantity = slea.readShort();
|
||||
byte targetSlot = slea.readByte();
|
||||
|
||||
if (targetSlot < 1 || targetSlot > 9) {
|
||||
System.out.println("[h4x] " + chr.getName() + " Trying to dupe on trade slot.");
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
if (item == null) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Invalid item description."));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(ServerConstants.USE_ENFORCE_UNMERCHABLE_CASH && ii.isCash(item.getItemId())) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Cash items are not allowed to be traded."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (ServerConstants.USE_ENFORCE_UNMERCHABLE_PET && ItemConstants.isPet(item.getItemId())) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Pets are not allowed to be traded."));
|
||||
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());
|
||||
return;
|
||||
}
|
||||
if (chr.getTrade() != null) {
|
||||
|
||||
MapleTrade trade = chr.getTrade();
|
||||
if (trade != null) {
|
||||
if ((quantity <= item.getQuantity() && quantity >= 0) || ItemConstants.isRechargeable(item.getItemId())) {
|
||||
if (ii.isDropRestricted(item.getItemId())) { // ensure that undroppable items do not make it to the trade window
|
||||
if (!MapleKarmaManipulator.hasKarmaFlag(item)) {
|
||||
@@ -489,16 +509,38 @@ public final class PlayerInteractionHandler extends AbstractMaplePacketHandler {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Item tradeItem = item.copy();
|
||||
if (ItemConstants.isRechargeable(item.getItemId())) {
|
||||
tradeItem.setQuantity(item.getQuantity());
|
||||
MapleInventoryManipulator.removeFromSlot(c, ivType, item.getPosition(), item.getQuantity(), true);
|
||||
} else {
|
||||
|
||||
MapleInventory inv = chr.getInventory(ivType);
|
||||
inv.lockInventory();
|
||||
try {
|
||||
Item checkItem = chr.getInventory(ivType).getItem(pos);
|
||||
if (checkItem != item || checkItem.getPosition() != item.getPosition()) {
|
||||
c.announce(MaplePacketCreator.serverNotice(1, "Invalid item description."));
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
|
||||
Item tradeItem = item.copy();
|
||||
if (ItemConstants.isRechargeable(item.getItemId())) {
|
||||
quantity = item.getQuantity();
|
||||
}
|
||||
|
||||
tradeItem.setQuantity(quantity);
|
||||
MapleInventoryManipulator.removeFromSlot(c, ivType, item.getPosition(), quantity, true);
|
||||
tradeItem.setPosition(targetSlot);
|
||||
|
||||
if (trade.addItem(tradeItem)) {
|
||||
MapleInventoryManipulator.removeFromSlot(c, ivType, item.getPosition(), quantity, true);
|
||||
|
||||
trade.getChr().announce(MaplePacketCreator.getTradeItemAdd((byte) 0, tradeItem));
|
||||
if (trade.getPartner() != null) {
|
||||
trade.getPartner().getChr().announce(MaplePacketCreator.getTradeItemAdd((byte) 1, tradeItem));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
FilePrinter.printError(FilePrinter.TRADE_EXCEPTION, e, "Player '" + chr + "' tried to add " + ii.getName(item.getItemId()) + " qty. " + item.getQuantity() + " in trade (slot " + targetSlot + ") then exception occurred.");
|
||||
} finally {
|
||||
inv.unlockInventory();
|
||||
}
|
||||
tradeItem.setPosition(targetSlot);
|
||||
chr.getTrade().addItem(tradeItem);
|
||||
}
|
||||
}
|
||||
} else if (mode == Action.CONFIRM.getCode()) {
|
||||
|
||||
@@ -289,7 +289,7 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
}
|
||||
if (newAlliance != null) {
|
||||
c.announce(MaplePacketCreator.updateAllianceInfo(newAlliance, c));
|
||||
c.announce(MaplePacketCreator.updateAllianceInfo(newAlliance, c.getWorld()));
|
||||
c.announce(MaplePacketCreator.allianceNotice(newAlliance.getId(), newAlliance.getNotice()));
|
||||
|
||||
if (newcomer) {
|
||||
|
||||
@@ -27,8 +27,7 @@ import constants.ItemConstants;
|
||||
import net.AbstractMaplePacketHandler;
|
||||
import scripting.item.ItemScriptManager;
|
||||
import server.MapleItemInformationProvider;
|
||||
import server.MapleItemInformationProvider.scriptedItem;
|
||||
import tools.MaplePacketCreator;
|
||||
import server.MapleItemInformationProvider.ScriptedItem;
|
||||
import tools.data.input.SeekableLittleEndianAccessor;
|
||||
|
||||
/**
|
||||
@@ -38,19 +37,20 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
public final class ScriptedItemHandler extends AbstractMaplePacketHandler {
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
slea.readInt(); // trash stamp, thanks RMZero213
|
||||
short itemSlot = slea.readShort(); // item slot, thanks RMZero213
|
||||
int itemId = slea.readInt();
|
||||
|
||||
MapleItemInformationProvider ii = MapleItemInformationProvider.getInstance();
|
||||
slea.readInt(); // trash stamp (thanks rmzero)
|
||||
short itemSlot = slea.readShort(); // item slot (thanks rmzero)
|
||||
int itemId = slea.readInt(); // itemId
|
||||
scriptedItem info = ii.getScriptedItemInfo(itemId);
|
||||
ScriptedItem info = ii.getScriptedItemInfo(itemId);
|
||||
if (info == null) return;
|
||||
ItemScriptManager ism = ItemScriptManager.getInstance();
|
||||
|
||||
Item item = c.getPlayer().getInventory(ItemConstants.getInventoryType(itemId)).getItem(itemSlot);
|
||||
if (item == null || item.getItemId() != itemId || item.getQuantity() < 1 || !ism.scriptExists(info.getScript())) {
|
||||
if (item == null || item.getItemId() != itemId || item.getQuantity() < 1) {
|
||||
return;
|
||||
}
|
||||
ism.runItemScript(c, info.getScript());
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
//NPCScriptManager.getInstance().start(c, info.getNpc(), null, null);
|
||||
|
||||
ItemScriptManager ism = ItemScriptManager.getInstance();
|
||||
ism.runItemScript(c, info);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ import tools.data.input.SeekableLittleEndianAccessor;
|
||||
* @author kevintjuh93
|
||||
*/
|
||||
public final class TrockAddMapHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
@Override
|
||||
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
|
||||
MapleCharacter chr = c.getPlayer();
|
||||
byte type = slea.readByte();
|
||||
|
||||
@@ -53,6 +53,7 @@ import server.MapleShop;
|
||||
import server.MapleShopFactory;
|
||||
import server.TimerManager;
|
||||
import server.maps.AbstractMapleMapObject;
|
||||
import server.maps.FieldLimit;
|
||||
import server.maps.MaplePlayerShopItem;
|
||||
import server.maps.MapleKite;
|
||||
import server.maps.MapleMap;
|
||||
@@ -106,31 +107,32 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
if (itemType == 504) { // vip teleport rock
|
||||
String error1 = "Either the player could not be found or you were trying to teleport to an illegal location.";
|
||||
boolean vip = slea.readByte() == 1;
|
||||
boolean vip = slea.readByte() == 1 && itemId / 1000 >= 5041;
|
||||
remove(c, position, itemId);
|
||||
boolean success = false;
|
||||
if (!vip) {
|
||||
int mapId = slea.readInt();
|
||||
if (c.getChannelServer().getMapFactory().getMap(mapId).getForcedReturnId() == 999999999) {
|
||||
player.changeMap(c.getChannelServer().getMapFactory().getMap(mapId));
|
||||
if (itemId / 1000 >= 5041 || mapId / 100000000 == player.getMapId() / 100000000) { //check vip or same continent
|
||||
MapleMap targetMap = c.getChannelServer().getMapFactory().getMap(mapId);
|
||||
if (!FieldLimit.CANNOTVIPROCK.check(targetMap.getFieldLimit()) && (targetMap.getForcedReturnId() == 999999999 || mapId < 100000000)) {
|
||||
player.forceChangeMap(targetMap, targetMap.getRandomPlayerSpawnpoint());
|
||||
success = true;
|
||||
} else {
|
||||
player.dropMessage(1, error1);
|
||||
}
|
||||
} else {
|
||||
MapleInventoryManipulator.addById(c, itemId, (short) 1);
|
||||
player.dropMessage(1, error1);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
player.dropMessage(1, "You cannot teleport between continents with this teleport rock.");
|
||||
}
|
||||
} else {
|
||||
String name = slea.readMapleAsciiString();
|
||||
MapleCharacter victim = c.getChannelServer().getPlayerStorage().getCharacterByName(name);
|
||||
boolean success = false;
|
||||
|
||||
if (victim != null) {
|
||||
MapleMap target = victim.getMap();
|
||||
if (c.getChannelServer().getMapFactory().getMap(victim.getMapId()).getForcedReturnId() == 999999999 || victim.getMapId() < 100000000) {
|
||||
MapleMap targetMap = victim.getMap();
|
||||
if (!FieldLimit.CANNOTVIPROCK.check(targetMap.getFieldLimit()) && (targetMap.getForcedReturnId() == 999999999 || targetMap.getId() < 100000000)) {
|
||||
if (victim.gmLevel() <= player.gmLevel()) {
|
||||
if (itemId == 5041000 || victim.getMapId() / player.getMapId() == 1) { //viprock & same continent
|
||||
player.changeMap(target, target.findClosestPlayerSpawnpoint(victim.getPosition()));
|
||||
success = true;
|
||||
} else {
|
||||
player.dropMessage(1, "You cannot teleport between continents with this teleport rock.");
|
||||
}
|
||||
player.forceChangeMap(targetMap, targetMap.findClosestPlayerSpawnpoint(victim.getPosition()));
|
||||
success = true;
|
||||
} else {
|
||||
player.dropMessage(1, error1);
|
||||
}
|
||||
@@ -140,10 +142,11 @@ public final class UseCashItemHandler extends AbstractMaplePacketHandler {
|
||||
} else {
|
||||
player.dropMessage(1, "Player could not be found in this channel.");
|
||||
}
|
||||
if (!success) {
|
||||
MapleInventoryManipulator.addById(c, itemId, (short) 1);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
MapleInventoryManipulator.addById(c, itemId, (short) 1);
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
}
|
||||
} else if (itemType == 505) { // AP/SP reset
|
||||
if(!player.isAlive()) {
|
||||
|
||||
@@ -25,8 +25,10 @@ import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import constants.ServerConstants;
|
||||
import client.MapleCharacter;
|
||||
@@ -56,6 +58,8 @@ public class MapleMonsterAggroCoordinator {
|
||||
private Map<MapleMonster, Map<Integer, PlayerAggroEntry>> mobAggroEntries = new HashMap<>();
|
||||
private Map<MapleMonster, List<PlayerAggroEntry>> mobSortedAggros = new HashMap<>();
|
||||
|
||||
private Set<Integer> mapPuppetEntries = new HashSet<>();
|
||||
|
||||
private class PlayerAggroEntry {
|
||||
protected int cid;
|
||||
protected int averageDamage = 0;
|
||||
@@ -291,6 +295,12 @@ public class MapleMonsterAggroCoordinator {
|
||||
}
|
||||
|
||||
public boolean isLeadingCharacterAggro(MapleMonster mob, MapleCharacter player) {
|
||||
if (mob.isLeadingPuppetInVicinity()) {
|
||||
return false;
|
||||
} else if (mob.isCharacterPuppetInVicinity(player)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// by assuming the quasi-sorted nature of "mobAggroList", this method
|
||||
// returns whether the player given as parameter can be elected as next aggro leader
|
||||
|
||||
@@ -342,6 +352,24 @@ public class MapleMonsterAggroCoordinator {
|
||||
}
|
||||
}
|
||||
|
||||
public void addPuppetAggro(MapleCharacter player) {
|
||||
synchronized (mapPuppetEntries) {
|
||||
mapPuppetEntries.add(player.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public void removePuppetAggro(Integer cid) {
|
||||
synchronized (mapPuppetEntries) {
|
||||
mapPuppetEntries.remove(cid);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Integer> getPuppetAggroList() {
|
||||
synchronized (mapPuppetEntries) {
|
||||
return new ArrayList<>(mapPuppetEntries);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
stopAggroCoordinator();
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ public class MapleSessionCoordinator {
|
||||
}
|
||||
|
||||
private final LoginStorage loginStorage = new LoginStorage();
|
||||
private final Map<Integer, MapleClient> onlineClients = new HashMap<>();
|
||||
private final Set<String> onlineRemoteHwids = new HashSet<>();
|
||||
private final Map<String, Set<IoSession>> loginRemoteHosts = new HashMap<>();
|
||||
private final Set<String> pooledRemoteHosts = new HashSet<>();
|
||||
@@ -221,6 +222,24 @@ public class MapleSessionCoordinator {
|
||||
return ((InetSocketAddress) session.getRemoteAddress()).getAddress().getHostAddress();
|
||||
}
|
||||
|
||||
private static MapleClient getSessionClient(IoSession session) {
|
||||
return (MapleClient) session.getAttribute(MapleClient.CLIENT_KEY);
|
||||
}
|
||||
|
||||
public void updateOnlineSession(IoSession session) {
|
||||
MapleClient client = getSessionClient(session);
|
||||
|
||||
if (client != null) {
|
||||
int accountId = client.getAccID();
|
||||
MapleClient ingameClient = onlineClients.get(accountId);
|
||||
if (ingameClient != null) { // thanks MedicOP for finding out a loss of loggedin account uniqueness when using the CMS "Unstuck" feature
|
||||
ingameClient.forceDisconnect();
|
||||
}
|
||||
|
||||
onlineClients.put(accountId, client);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canStartLoginSession(IoSession session) {
|
||||
if (!ServerConstants.DETERRED_MULTICLIENT) return true;
|
||||
|
||||
@@ -296,6 +315,11 @@ public class MapleSessionCoordinator {
|
||||
String nibbleHwid = (String) session.removeAttribute(MapleClient.CLIENT_NIBBLEHWID);
|
||||
if (nibbleHwid != null) {
|
||||
onlineRemoteHwids.remove(nibbleHwid);
|
||||
|
||||
MapleClient client = getSessionClient(session);
|
||||
if (client != null) {
|
||||
onlineClients.remove(client.getAccID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -448,6 +472,11 @@ public class MapleSessionCoordinator {
|
||||
hwid = (String) session.removeAttribute(MapleClient.CLIENT_NIBBLEHWID); // making sure to clean up calls to this function on login phase
|
||||
onlineRemoteHwids.remove(hwid);
|
||||
|
||||
MapleClient client = getSessionClient(session);
|
||||
if (client != null) {
|
||||
onlineClients.remove(client.getAccID());
|
||||
}
|
||||
|
||||
if (immediately != null) {
|
||||
session.close(immediately);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,9 @@ public class MapleAlliance {
|
||||
|
||||
Server.getInstance().addAlliance(id, alliance);
|
||||
|
||||
Server.getInstance().allianceMessage(id, MaplePacketCreator.updateAllianceInfo(alliance, guildMasters.get(0).getClient()), -1, -1);
|
||||
int worldid = guildMasters.get(0).getWorld();
|
||||
Server.getInstance().allianceMessage(id, MaplePacketCreator.updateAllianceInfo(alliance, worldid), -1, -1);
|
||||
Server.getInstance().allianceMessage(id, MaplePacketCreator.getGuildAlliances(alliance, worldid), -1, -1); // thanks Vcoc for noticing guilds from other alliances being visually stacked here due to this not being updated
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
@@ -347,7 +349,7 @@ public class MapleAlliance {
|
||||
|
||||
public void updateAlliancePackets(MapleCharacter chr) {
|
||||
if (allianceId > 0) {
|
||||
this.broadcastMessage(MaplePacketCreator.updateAllianceInfo(this, chr.getClient()));
|
||||
this.broadcastMessage(MaplePacketCreator.updateAllianceInfo(this, chr.getWorld()));
|
||||
this.broadcastMessage(MaplePacketCreator.allianceNotice(this.getId(), this.getNotice()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,13 +78,13 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
session.close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(session, true);
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterEntry(c.getAccID(), charId)) {
|
||||
session.close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(session, true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,13 +59,13 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterEntry(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ public final class LoginPasswordHandler implements MaplePacketHandler {
|
||||
c.setAccID(rs.getInt(1));
|
||||
rs.close();
|
||||
} catch (SQLException | NoSuchAlgorithmException | UnsupportedEncodingException e) {
|
||||
c.setAccID(-1);
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
disposeSql(con, ps);
|
||||
|
||||
@@ -59,13 +59,13 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
|
||||
}
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterEntry(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public final class RegisterPicHandler extends AbstractMaplePacketHandler {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand
|
||||
c.updateHWID(hwid);
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public final class ViewAllCharRegisterPicHandler extends AbstractMaplePacketHand
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterEntry(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler
|
||||
c.updateHWID(hwid);
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public final class ViewAllCharSelectedHandler extends AbstractMaplePacketHandler
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterEntry(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
|
||||
c.updateHWID(hwid);
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ViewAllCharSelectedWithPicHandler extends AbstractMaplePacketHandle
|
||||
|
||||
Server server = Server.getInstance();
|
||||
if(!server.haveCharacterEntry(c.getAccID(), charId)) {
|
||||
c.getSession().close(true);
|
||||
MapleSessionCoordinator.getInstance().closeSession(c.getSession(), true);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,11 @@ public class AbstractPlayerInteraction {
|
||||
}
|
||||
|
||||
public boolean canHold(int itemid, int quantity) {
|
||||
return getPlayer().canHold(itemid, quantity);
|
||||
return canHoldAll(Collections.singletonList(itemid), Collections.singletonList(quantity), true);
|
||||
}
|
||||
|
||||
public boolean canHold(int itemid, int quantity, int removeItemid, int removeQuantity) {
|
||||
return canHoldAllAfterRemoving(Collections.singletonList(itemid), Collections.singletonList(quantity), Collections.singletonList(removeItemid), Collections.singletonList(removeQuantity));
|
||||
}
|
||||
|
||||
private static List<Integer> convertToIntegerArray(List<Double> list) {
|
||||
@@ -263,10 +267,6 @@ public class AbstractPlayerInteraction {
|
||||
return MapleInventory.checkSpots(c.getPlayer(), addedItems, false);
|
||||
}
|
||||
|
||||
public boolean canHold(int itemid, int quantity, int removeItemid, int removeQuantity) {
|
||||
return canHoldAllAfterRemoving(Collections.singletonList(itemid), Collections.singletonList(quantity), Collections.singletonList(removeItemid), Collections.singletonList(removeQuantity));
|
||||
}
|
||||
|
||||
private static List<Pair<Item, MapleInventoryType>> prepareProofInventoryItems(List<Pair<Integer, Integer>> items) {
|
||||
List<Pair<Item, MapleInventoryType>> addedItems = new LinkedList<>();
|
||||
for(Pair<Integer, Integer> p : items) {
|
||||
|
||||
+11
-11
@@ -1,8 +1,6 @@
|
||||
/*
|
||||
This file is part of the OdinMS Maple Story Server
|
||||
Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
|
||||
Matthias Butz <matze@odinms.de>
|
||||
Jan Christian Meyer <vimes@odinms.de>
|
||||
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
|
||||
@@ -19,17 +17,19 @@
|
||||
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 scripting.item;
|
||||
package scripting.event;
|
||||
|
||||
import client.MapleClient;
|
||||
import scripting.AbstractPlayerInteraction;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kevintjuh93
|
||||
* @author Ronan
|
||||
*/
|
||||
public class ItemScriptMethods extends AbstractPlayerInteraction {
|
||||
public ItemScriptMethods(MapleClient c) {
|
||||
super(c);
|
||||
public class EventInstanceInProgressException extends Exception {
|
||||
|
||||
public static String EIIP_KEY = "Event instance ";
|
||||
|
||||
public EventInstanceInProgressException(String eventName, String eventInstance) {
|
||||
super(EIIP_KEY + "already in progress - " + eventName + ", EM: " + eventInstance);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -260,7 +260,7 @@ public class EventManager {
|
||||
}
|
||||
}
|
||||
|
||||
public EventInstanceManager newInstance(String name) {
|
||||
public EventInstanceManager newInstance(String name) throws EventInstanceInProgressException {
|
||||
EventInstanceManager ret = getReadyInstance();
|
||||
|
||||
if(ret == null) {
|
||||
@@ -271,7 +271,7 @@ public class EventManager {
|
||||
|
||||
synchronized (instances) {
|
||||
if (instances.containsKey(name)) {
|
||||
return null;
|
||||
throw new EventInstanceInProgressException(name, this.getName());
|
||||
}
|
||||
|
||||
instances.put(name, ret);
|
||||
@@ -365,6 +365,34 @@ public class EventManager {
|
||||
return -1;
|
||||
}
|
||||
|
||||
private String getInternalScriptExceptionMessage(Throwable a) {
|
||||
if (!(a instanceof ScriptException)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
while(true) {
|
||||
Throwable t = a;
|
||||
a = a.getCause();
|
||||
|
||||
if (a == null) {
|
||||
return t.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EventInstanceManager createInstance(String name, Object... args) throws ScriptException, NoSuchMethodException {
|
||||
return (EventInstanceManager) iv.invokeFunction(name, args);
|
||||
}
|
||||
|
||||
private void registerEventInstance(String eventName, int lobbyId) {
|
||||
Integer oldLobby = instanceLocks.get(eventName);
|
||||
if (oldLobby != null) {
|
||||
setLockLobby(oldLobby, false);
|
||||
}
|
||||
|
||||
instanceLocks.put(eventName, lobbyId);
|
||||
}
|
||||
|
||||
public boolean startInstance(MapleExpedition exped) {
|
||||
return startInstance(-1, exped);
|
||||
}
|
||||
@@ -394,9 +422,14 @@ public class EventManager {
|
||||
|
||||
EventInstanceManager eim;
|
||||
try {
|
||||
eim = (EventInstanceManager) (iv.invokeFunction("setup", leader.getClient().getChannel()));
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
} catch (NullPointerException npe) {
|
||||
eim = createInstance("setup", leader.getClient().getChannel());
|
||||
registerEventInstance(eim.getName(), lobbyId);
|
||||
} catch (ScriptException | NullPointerException e) {
|
||||
String message = getInternalScriptExceptionMessage(e);
|
||||
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
@@ -460,9 +493,14 @@ public class EventManager {
|
||||
|
||||
EventInstanceManager eim;
|
||||
try {
|
||||
eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId()));
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
} catch (NullPointerException npe) {
|
||||
eim = createInstance("setup", difficulty, (lobbyId > -1) ? lobbyId : leader.getId());
|
||||
registerEventInstance(eim.getName(), lobbyId);
|
||||
} catch (ScriptException | NullPointerException e) {
|
||||
String message = getInternalScriptExceptionMessage(e);
|
||||
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
@@ -520,9 +558,14 @@ public class EventManager {
|
||||
|
||||
EventInstanceManager eim;
|
||||
try {
|
||||
eim = (EventInstanceManager) (iv.invokeFunction("setup", (Object) null));
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
} catch (NullPointerException npe) {
|
||||
eim = createInstance("setup", (Object) null);
|
||||
registerEventInstance(eim.getName(), lobbyId);
|
||||
} catch (ScriptException | NullPointerException e) {
|
||||
String message = getInternalScriptExceptionMessage(e);
|
||||
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
@@ -582,9 +625,14 @@ public class EventManager {
|
||||
|
||||
EventInstanceManager eim;
|
||||
try {
|
||||
eim = (EventInstanceManager) (iv.invokeFunction("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId()));
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
} catch (NullPointerException npe) {
|
||||
eim = createInstance("setup", difficulty, (lobbyId > -1) ? lobbyId : party.getLeaderId());
|
||||
registerEventInstance(eim.getName(), lobbyId);
|
||||
} catch (ScriptException | NullPointerException e) {
|
||||
String message = getInternalScriptExceptionMessage(e);
|
||||
if (message != null && !message.startsWith(EventInstanceInProgressException.EIIP_KEY)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
if(lobbyId > -1) {
|
||||
setLockLobby(lobbyId, false);
|
||||
}
|
||||
@@ -652,7 +700,7 @@ public class EventManager {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
instanceLocks.put(eim.getName(), lobbyId);
|
||||
registerEventInstance(eim.getName(), lobbyId);
|
||||
eim.setLeader(leader);
|
||||
|
||||
iv.invokeFunction("setup", eim);
|
||||
|
||||
@@ -22,21 +22,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package scripting.item;
|
||||
|
||||
import client.MapleClient;
|
||||
import constants.ServerConstants;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.script.Compilable;
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineFactory;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
import scripting.npc.NPCScriptManager;
|
||||
import server.MapleItemInformationProvider.ScriptedItem;
|
||||
|
||||
public class ItemScriptManager {
|
||||
|
||||
@@ -46,60 +33,7 @@ public class ItemScriptManager {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Map<String, Invocable> scripts = new HashMap<>();
|
||||
private ScriptEngineFactory sef;
|
||||
|
||||
private ItemScriptManager() {
|
||||
ScriptEngineManager sem = new ScriptEngineManager();
|
||||
sef = sem.getEngineByName("javascript").getFactory();
|
||||
}
|
||||
|
||||
public boolean scriptExists(String scriptName) {
|
||||
File scriptFile = new File("scripts/item/" + scriptName + ".js");
|
||||
return scriptFile.exists();
|
||||
}
|
||||
|
||||
public void runItemScript(MapleClient c, String scriptName) {
|
||||
if (scripts.containsKey(scriptName)) {
|
||||
try {
|
||||
scripts.get(scriptName).invokeFunction("start", new ItemScriptMethods(c));
|
||||
} catch (ScriptException | NoSuchMethodException ex) {
|
||||
FilePrinter.printError(FilePrinter.ITEM + scriptName + ".txt", ex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
File scriptFile = new File("scripts/item/" + scriptName + ".js");
|
||||
if (!scriptFile.exists()) {
|
||||
c.announce(MaplePacketCreator.enableActions());
|
||||
return;
|
||||
}
|
||||
FileReader fr = null;
|
||||
ScriptEngine portal = sef.getScriptEngine();
|
||||
try {
|
||||
fr = new FileReader(scriptFile);
|
||||
|
||||
// java 8 support here thanks to Arufonsu
|
||||
if (ServerConstants.JAVA_8){
|
||||
portal.eval("load('nashorn:mozilla_compat.js');" + System.lineSeparator());
|
||||
}
|
||||
|
||||
((Compilable) portal).compile(fr).eval();
|
||||
|
||||
final Invocable script = ((Invocable) portal);
|
||||
scripts.put(scriptName, script);
|
||||
script.invokeFunction("start", new ItemScriptMethods(c));
|
||||
} catch (final UndeclaredThrowableException | ScriptException ute) {
|
||||
FilePrinter.printError(FilePrinter.ITEM + scriptName + ".txt", ute);
|
||||
} catch (final Exception e) {
|
||||
FilePrinter.printError(FilePrinter.ITEM + scriptName + ".txt", e);
|
||||
} finally {
|
||||
if (fr != null) {
|
||||
try {
|
||||
fr.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void runItemScript(MapleClient c, ScriptedItem scriptItem) {
|
||||
NPCScriptManager.getInstance().start(c, scriptItem, null);
|
||||
}
|
||||
}
|
||||
@@ -78,18 +78,18 @@ public class MapScriptManager {
|
||||
return;
|
||||
}
|
||||
FileReader fr = null;
|
||||
ScriptEngine portal = sef.getScriptEngine();
|
||||
ScriptEngine se = sef.getScriptEngine();
|
||||
try {
|
||||
fr = new FileReader(scriptFile);
|
||||
|
||||
// java 8 support here thanks to Arufonsu
|
||||
if (ServerConstants.JAVA_8){
|
||||
portal.eval("load('nashorn:mozilla_compat.js');" + System.lineSeparator());
|
||||
se.eval("load('nashorn:mozilla_compat.js');" + System.lineSeparator());
|
||||
}
|
||||
|
||||
((Compilable) portal).compile(fr).eval();
|
||||
((Compilable) se).compile(fr).eval();
|
||||
|
||||
final Invocable script = ((Invocable) portal);
|
||||
final Invocable script = ((Invocable) se);
|
||||
scripts.put(scriptName, script);
|
||||
script.invokeFunction("start", new MapScriptMethods(c));
|
||||
} catch (final UndeclaredThrowableException | ScriptException ute) {
|
||||
|
||||
@@ -74,16 +74,18 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
private int npcOid;
|
||||
private String scriptName;
|
||||
private String getText;
|
||||
private boolean itemScript;
|
||||
|
||||
public NPCConversationManager(MapleClient c, int npc, String scriptName) {
|
||||
this(c, npc, -1, scriptName);
|
||||
this(c, npc, -1, scriptName, false);
|
||||
}
|
||||
|
||||
public NPCConversationManager(MapleClient c, int npc, int oid, String scriptName) {
|
||||
public NPCConversationManager(MapleClient c, int npc, int oid, String scriptName, boolean itemScript) {
|
||||
super(c);
|
||||
this.npc = npc;
|
||||
this.npcOid = oid;
|
||||
this.scriptName = scriptName;
|
||||
this.itemScript = itemScript;
|
||||
}
|
||||
|
||||
public int getNpc() {
|
||||
@@ -97,6 +99,14 @@ public class NPCConversationManager extends AbstractPlayerInteraction {
|
||||
public String getScriptName() {
|
||||
return scriptName;
|
||||
}
|
||||
|
||||
public boolean isItemScript() {
|
||||
return itemScript;
|
||||
}
|
||||
|
||||
public void resetItemScript() {
|
||||
this.itemScript = false;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
NPCScriptManager.getInstance().dispose(this);
|
||||
|
||||
@@ -32,6 +32,7 @@ import javax.script.Invocable;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
import scripting.AbstractScriptManager;
|
||||
import server.MapleItemInformationProvider.ScriptedItem;
|
||||
import tools.FilePrinter;
|
||||
import tools.MaplePacketCreator;
|
||||
|
||||
@@ -60,7 +61,7 @@ public class NPCScriptManager extends AbstractScriptManager {
|
||||
}
|
||||
|
||||
public boolean start(MapleClient c, int npc, MapleCharacter chr) {
|
||||
return start(c, npc, null, chr);
|
||||
return start(c, npc, -1, chr);
|
||||
}
|
||||
|
||||
public boolean start(MapleClient c, int npc, int oid, MapleCharacter chr) {
|
||||
@@ -70,27 +71,42 @@ public class NPCScriptManager extends AbstractScriptManager {
|
||||
public boolean start(MapleClient c, int npc, String fileName, MapleCharacter chr) {
|
||||
return start(c, npc, -1, fileName, chr);
|
||||
}
|
||||
|
||||
|
||||
public boolean start(MapleClient c, int npc, int oid, String fileName, MapleCharacter chr) {
|
||||
return start(c, npc, oid, fileName, chr, false, "cm");
|
||||
}
|
||||
|
||||
public boolean start(MapleClient c, ScriptedItem scriptItem, MapleCharacter chr) {
|
||||
return start(c, scriptItem.getNpc(), -1, scriptItem.getScript(), chr, true, "im");
|
||||
}
|
||||
|
||||
private boolean start(MapleClient c, int npc, int oid, String fileName, MapleCharacter chr, boolean itemScript, String engineName) {
|
||||
try {
|
||||
NPCConversationManager cm = new NPCConversationManager(c, npc, oid, fileName);
|
||||
NPCConversationManager cm = new NPCConversationManager(c, npc, oid, fileName, itemScript);
|
||||
if (cms.containsKey(c)) {
|
||||
dispose(c);
|
||||
}
|
||||
if (c.canClickNPC()) {
|
||||
cms.put(c, cm);
|
||||
Invocable iv = null;
|
||||
if (fileName != null) {
|
||||
iv = getInvocable("npc/" + fileName + ".js", c);
|
||||
if (!itemScript) {
|
||||
if (fileName != null) {
|
||||
iv = getInvocable("npc/" + fileName + ".js", c);
|
||||
}
|
||||
} else {
|
||||
if (fileName != null) { // thanks MiLin for drafting NPC-based item scripts
|
||||
iv = getInvocable("item/" + fileName + ".js", c);
|
||||
}
|
||||
}
|
||||
if (iv == null) {
|
||||
iv = getInvocable("npc/" + npc + ".js", c);
|
||||
cm.resetItemScript();
|
||||
}
|
||||
if (iv == null || NPCScriptManager.getInstance() == null) {
|
||||
dispose(c);
|
||||
return false;
|
||||
}
|
||||
engine.put("cm", cm);
|
||||
engine.put(engineName, cm);
|
||||
scripts.put(c, iv);
|
||||
c.setClickedNPC();
|
||||
try {
|
||||
@@ -142,10 +158,11 @@ public class NPCScriptManager extends AbstractScriptManager {
|
||||
cms.remove(c);
|
||||
scripts.remove(c);
|
||||
|
||||
String scriptFolder = (cm.isItemScript() ? "item" : "npc");
|
||||
if(cm.getScriptName() != null) {
|
||||
resetContext("npc/" + cm.getScriptName() + ".js", c);
|
||||
resetContext(scriptFolder + "/" + cm.getScriptName() + ".js", c);
|
||||
} else {
|
||||
resetContext("npc/" + cm.getNpc() + ".js", c);
|
||||
resetContext(scriptFolder + "/" + cm.getNpc() + ".js", c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ public class MapleItemInformationProvider {
|
||||
protected Map<Integer, Integer> monsterBookID = new HashMap<>();
|
||||
protected Map<Integer, Boolean> untradeableCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> onEquipUntradeableCache = new HashMap<>();
|
||||
protected Map<Integer, scriptedItem> scriptedItemCache = new HashMap<>();
|
||||
protected Map<Integer, ScriptedItem> scriptedItemCache = new HashMap<>();
|
||||
protected Map<Integer, Boolean> karmaCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> triggerItemCache = new HashMap<>();
|
||||
protected Map<Integer, Integer> expCache = new HashMap<>();
|
||||
@@ -1447,14 +1447,14 @@ public class MapleItemInformationProvider {
|
||||
return untradeableOnEquip;
|
||||
}
|
||||
|
||||
public scriptedItem getScriptedItemInfo(int itemId) {
|
||||
public ScriptedItem getScriptedItemInfo(int itemId) {
|
||||
if (scriptedItemCache.containsKey(itemId)) {
|
||||
return scriptedItemCache.get(itemId);
|
||||
}
|
||||
if ((itemId / 10000) != 243) {
|
||||
return null;
|
||||
}
|
||||
scriptedItem script = new scriptedItem(MapleDataTool.getInt("spec/npc", getItemData(itemId), 0),
|
||||
ScriptedItem script = new ScriptedItem(MapleDataTool.getInt("spec/npc", getItemData(itemId), 0),
|
||||
MapleDataTool.getString("spec/script", getItemData(itemId), ""),
|
||||
MapleDataTool.getInt("spec/runOnPickup", getItemData(itemId), 0) == 1);
|
||||
scriptedItemCache.put(itemId, script);
|
||||
@@ -2100,13 +2100,13 @@ public class MapleItemInformationProvider {
|
||||
return skillbook;
|
||||
}
|
||||
|
||||
public class scriptedItem {
|
||||
public class ScriptedItem {
|
||||
|
||||
private boolean runOnPickup;
|
||||
private int npc;
|
||||
private String script;
|
||||
|
||||
public scriptedItem(int npc, String script, boolean rop) {
|
||||
public ScriptedItem(int npc, String script, boolean rop) {
|
||||
this.npc = npc;
|
||||
this.script = script;
|
||||
this.runOnPickup = rop;
|
||||
|
||||
+88
-23
@@ -82,16 +82,16 @@ public class MapleTrade {
|
||||
partner.getChr().getClient().announce(MaplePacketCreator.getTradeConfirmation());
|
||||
}
|
||||
|
||||
private void complete1() {
|
||||
private void fetchExchangedItems() {
|
||||
exchangeItems = partner.getItems();
|
||||
exchangeMeso = partner.getMeso();
|
||||
}
|
||||
|
||||
private void complete2() {
|
||||
private void completeTrade() {
|
||||
boolean show = ServerConstants.USE_DEBUG;
|
||||
|
||||
items.clear();
|
||||
meso = 0;
|
||||
|
||||
for (Item item : exchangeItems) {
|
||||
MapleKarmaManipulator.toggleKarmaFlagToUntradeable(item);
|
||||
MapleInventoryManipulator.addFromDrop(chr.getClient(), item, show);
|
||||
@@ -164,12 +164,21 @@ public class MapleTrade {
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(Item item) {
|
||||
items.add(item);
|
||||
chr.getClient().announce(MaplePacketCreator.getTradeItemAdd((byte) 0, item));
|
||||
if (partner != null) {
|
||||
partner.getChr().getClient().announce(MaplePacketCreator.getTradeItemAdd((byte) 1, item));
|
||||
public boolean addItem(Item item) {
|
||||
synchronized (items) {
|
||||
if (items.size() > 9) {
|
||||
return false;
|
||||
}
|
||||
for (Item it : items) {
|
||||
if (it.getPosition() == item.getPosition()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void chat(String message) {
|
||||
@@ -214,38 +223,65 @@ public class MapleTrade {
|
||||
|
||||
return MapleInventory.checkSpotsAndOwnership(chr, tradeItems);
|
||||
}
|
||||
|
||||
|
||||
private synchronized boolean checkTradeCompleteHandshake(boolean updateSelf) {
|
||||
MapleTrade self, other;
|
||||
|
||||
if (updateSelf) {
|
||||
self = this;
|
||||
other = this.getPartner();
|
||||
} else {
|
||||
self = this.getPartner();
|
||||
other = this;
|
||||
}
|
||||
|
||||
if (self.isLocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.lockTrade();
|
||||
return other.isLocked();
|
||||
}
|
||||
|
||||
private boolean checkCompleteHandshake() { // handshake checkout thanks to Ronan
|
||||
if (this.getChr().getId() < this.getPartner().getChr().getId()) {
|
||||
return this.checkTradeCompleteHandshake(true);
|
||||
} else {
|
||||
return this.getPartner().checkTradeCompleteHandshake(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void completeTrade(MapleCharacter c) {
|
||||
c.getTrade().lockTrade();
|
||||
MapleTrade local = c.getTrade();
|
||||
MapleTrade partner = local.getPartner();
|
||||
if (partner.isLocked()) {
|
||||
local.complete1();
|
||||
partner.complete1();
|
||||
if (local.checkCompleteHandshake()) {
|
||||
local.fetchExchangedItems();
|
||||
partner.fetchExchangedItems();
|
||||
|
||||
if (!local.fitsMeso()) {
|
||||
cancelTrade(c);
|
||||
c.message("There is not enough meso inventory space to complete the trade.");
|
||||
partner.getChr().message("Partner does not have enough meso inventory space to complete the trade.");
|
||||
return;
|
||||
}
|
||||
else if (!partner.fitsMeso()) {
|
||||
} else if (!partner.fitsMeso()) {
|
||||
cancelTrade(c);
|
||||
c.message("Partner does not have enough meso inventory space to complete the trade.");
|
||||
partner.getChr().message("There is not enough meso inventory space to complete the trade.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!local.fitsInInventory()) {
|
||||
cancelTrade(c);
|
||||
c.message("There is not enough inventory space to complete the trade.");
|
||||
partner.getChr().message("Partner does not have enough inventory space to complete the trade.");
|
||||
return;
|
||||
}
|
||||
else if (!partner.fitsInInventory()) {
|
||||
} else if (!partner.fitsInInventory()) {
|
||||
cancelTrade(c);
|
||||
c.message("Partner does not have enough inventory space to complete the trade.");
|
||||
partner.getChr().message("There is not enough inventory space to complete the trade.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (local.getChr().getLevel() < 15) {
|
||||
if (local.getChr().getMesosTraded() + local.exchangeMeso > 1000000) {
|
||||
cancelTrade(c);
|
||||
@@ -263,16 +299,18 @@ public class MapleTrade {
|
||||
partner.getChr().addMesosTraded(partner.exchangeMeso);
|
||||
}
|
||||
}
|
||||
|
||||
LogHelper.logTrade(local, partner);
|
||||
local.complete2();
|
||||
partner.complete2();
|
||||
local.completeTrade();
|
||||
partner.completeTrade();
|
||||
|
||||
partner.getChr().setTrade(null);
|
||||
c.setTrade(null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void cancelTrade(MapleCharacter c) {
|
||||
MapleTrade trade = c.getTrade();
|
||||
|
||||
private static void cancelTradeInternal(MapleCharacter chr) {
|
||||
MapleTrade trade = chr.getTrade();
|
||||
if(trade == null) return;
|
||||
|
||||
trade.cancel();
|
||||
@@ -280,9 +318,36 @@ public class MapleTrade {
|
||||
trade.getPartner().cancel();
|
||||
trade.getPartner().getChr().setTrade(null);
|
||||
}
|
||||
c.setTrade(null);
|
||||
chr.setTrade(null);
|
||||
}
|
||||
|
||||
private synchronized void tradeCancelHandshake(boolean updateSelf) {
|
||||
MapleTrade self;
|
||||
|
||||
if (updateSelf) {
|
||||
self = this;
|
||||
} else {
|
||||
self = this.getPartner();
|
||||
}
|
||||
|
||||
cancelTradeInternal(self.getChr());
|
||||
}
|
||||
|
||||
private void cancelHandshake() { // handshake checkout thanks to Ronan
|
||||
if (this.getChr().getId() < this.getPartner().getChr().getId()) {
|
||||
this.tradeCancelHandshake(true);
|
||||
} else {
|
||||
this.getPartner().tradeCancelHandshake(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void cancelTrade(MapleCharacter chr) {
|
||||
MapleTrade trade = chr.getTrade();
|
||||
if(trade == null) return;
|
||||
|
||||
trade.cancelHandshake();
|
||||
}
|
||||
|
||||
public static void startTrade(MapleCharacter c) {
|
||||
if (c.getTrade() == null) {
|
||||
c.setTrade(new MapleTrade((byte) 0, c));
|
||||
|
||||
@@ -63,7 +63,6 @@ import scripting.event.EventInstanceManager;
|
||||
import server.TimerManager;
|
||||
import server.life.MapleLifeFactory.BanishInfo;
|
||||
import server.maps.MapleMap;
|
||||
import server.maps.MapleMapObject;
|
||||
import server.maps.MapleMapObjectType;
|
||||
import tools.MaplePacketCreator;
|
||||
import tools.Pair;
|
||||
@@ -72,6 +71,8 @@ import net.server.audit.LockCollector;
|
||||
import net.server.audit.locks.MonitoredLockType;
|
||||
import net.server.audit.locks.factory.MonitoredReentrantLockFactory;
|
||||
import net.server.coordinator.MapleMonsterAggroCoordinator;
|
||||
import server.MapleStatEffect;
|
||||
import server.maps.MapleSummon;
|
||||
|
||||
public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private ChangeableStats ostats = null; //unused, v83 WZs offers no support for changeable stats.
|
||||
@@ -80,7 +81,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private AtomicLong maxHpPlusHeal = new AtomicLong(1);
|
||||
private int mp;
|
||||
private WeakReference<MapleCharacter> controller = new WeakReference<>(null);
|
||||
private boolean controllerHasAggro, controllerKnowsAboutAggro;
|
||||
private boolean controllerHasAggro, controllerKnowsAboutAggro, controllerHasPuppet;
|
||||
private Collection<MonsterListener> listeners = new LinkedList<>();
|
||||
private EnumMap<MonsterStatus, MonsterStatusEffect> stati = new EnumMap<>(MonsterStatus.class);
|
||||
private ArrayList<MonsterStatus> alreadyBuffed = new ArrayList<>();
|
||||
@@ -91,10 +92,15 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private List<Pair<Integer, Integer>> usedSkills = new ArrayList<>();
|
||||
private Map<Pair<Integer, Integer>, Integer> skillsUsed = new HashMap<>();
|
||||
private Set<Integer> usedAttacks = new HashSet<>();
|
||||
private Set<Integer> calledMobOids = null;
|
||||
private int calledMobCount = 0;
|
||||
private WeakReference<MapleMonster> callerMob = new WeakReference<>(null);
|
||||
private List<Integer> stolenItems = new ArrayList<>();
|
||||
private int team;
|
||||
private int parentMobOid = 0;
|
||||
private final HashMap<Integer, AtomicInteger> takenDamage = new HashMap<>();
|
||||
private Runnable removeAfterAction = null;
|
||||
private boolean availablePuppetUpdate = true;
|
||||
|
||||
private MonitoredReentrantLock externalLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB_EXT);
|
||||
private MonitoredReentrantLock monsterLock = MonitoredReentrantLockFactory.createLock(MonitoredLockType.MOB, true);
|
||||
@@ -152,7 +158,59 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
public void setParentMobOid(int parentMobId) {
|
||||
this.parentMobOid = parentMobId;
|
||||
}
|
||||
|
||||
|
||||
public int countAvailableMobSummons(int limit, int skillLimit) { // limit prop for summons has another conotation, found thanks to MedicOP
|
||||
Set<Integer> calledOids = this.calledMobOids;
|
||||
if(calledOids != null) {
|
||||
limit -= calledOids.size();
|
||||
}
|
||||
|
||||
return Math.min(limit, skillLimit - this.calledMobCount);
|
||||
}
|
||||
|
||||
public void addSummonedMob(MapleMonster mob) {
|
||||
Set<Integer> calledOids = this.calledMobOids;
|
||||
if (calledOids == null) {
|
||||
calledOids = Collections.synchronizedSet(new HashSet<Integer>());
|
||||
this.calledMobOids = calledOids;
|
||||
}
|
||||
|
||||
calledOids.add(mob.getObjectId());
|
||||
mob.setSummonerMob(this);
|
||||
this.calledMobCount += 1;
|
||||
}
|
||||
|
||||
private void removeSummonedMob(int mobOid) {
|
||||
Set<Integer> calledOids = this.calledMobOids;
|
||||
if (calledOids != null) {
|
||||
calledOids.remove(mobOid);
|
||||
}
|
||||
}
|
||||
|
||||
private void setSummonerMob(MapleMonster mob) {
|
||||
this.callerMob = new WeakReference<>(mob);
|
||||
}
|
||||
|
||||
private void dispatchClearSummons() {
|
||||
MapleMonster caller = this.callerMob.get();
|
||||
if (caller != null) {
|
||||
caller.removeSummonedMob(this.getObjectId());
|
||||
}
|
||||
|
||||
this.calledMobOids = null;
|
||||
}
|
||||
|
||||
public void pushRemoveAfterAction(Runnable run) {
|
||||
this.removeAfterAction = run;
|
||||
}
|
||||
|
||||
public Runnable popRemoveAfterAction() {
|
||||
Runnable r = this.removeAfterAction;
|
||||
this.removeAfterAction = null;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public int getHp() {
|
||||
return hp.get();
|
||||
}
|
||||
@@ -421,7 +479,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
int expSharersLevel = 0;
|
||||
for (MapleCharacter mc : members) {
|
||||
if (mc.getLevel() >= minThresholdLevel) { //NO EXP WILL BE GIVEN for those who are underleveled!
|
||||
if (Math.abs(killerLevel - mc.getLevel()) < ServerConstants.MIN_UNDERLEVEL_TO_EXP_LEECH) {
|
||||
if (Math.abs(killerLevel - mc.getLevel()) < ServerConstants.MIN_RANGELEVEL_TO_EXP_LEECH) {
|
||||
// thanks Thora for pointing out leech level limitation
|
||||
|
||||
expSharersLevel += mc.getLevel();
|
||||
@@ -710,6 +768,7 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
|
||||
this.aggroClearDamages();
|
||||
this.dispatchClearSummons();
|
||||
|
||||
MonsterListener[] listenersList;
|
||||
statiLock.lock();
|
||||
@@ -809,6 +868,10 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
private void setControllerKnowsAboutAggro(boolean controllerKnowsAboutAggro) {
|
||||
if (!fake) this.controllerKnowsAboutAggro = controllerKnowsAboutAggro;
|
||||
}
|
||||
|
||||
private void setControllerHasPuppet(boolean controllerHasPuppet) {
|
||||
this.controllerHasPuppet = controllerHasPuppet;
|
||||
}
|
||||
|
||||
public byte[] makeBossHPBarPacket() {
|
||||
return MaplePacketCreator.showBossHP(getId(), getHp(), getMaxHp(), getTagColor(), getTagBgColor());
|
||||
@@ -1233,39 +1296,13 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
return false;
|
||||
}
|
||||
|
||||
int useLimit = toUse.getLimit();
|
||||
int useSkillid = toUse.getSkillId();
|
||||
if (useSkillid == 200) {
|
||||
int i = 0;
|
||||
for (MapleMapObject mo : getMap().getMapObjects()) {
|
||||
if (mo.getType() == MapleMapObjectType.MONSTER) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i > 100) {
|
||||
return false;
|
||||
}
|
||||
if (map.isDojoMap()) { // spawns in dojo should be unlimited
|
||||
useLimit = 0;
|
||||
}
|
||||
} else if (useSkillid >= 143 && useSkillid <= 145) {
|
||||
if (useSkillid >= 143 && useSkillid <= 145) {
|
||||
if (this.isBuffed(MonsterStatus.WEAPON_REFLECT) || this.isBuffed(MonsterStatus.MAGIC_REFLECT)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (useLimit > 0) {
|
||||
monsterLock.lock();
|
||||
try {
|
||||
Integer times = this.skillsUsed.get(new Pair<>(useSkillid, toUse.getSkillLevel()));
|
||||
if (times != null && times >= useLimit) {
|
||||
return false;
|
||||
}
|
||||
} finally {
|
||||
monsterLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
monsterLock.lock();
|
||||
try {
|
||||
/*
|
||||
@@ -1303,13 +1340,14 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
try {
|
||||
mp -= skill.getMpCon();
|
||||
|
||||
this.usedSkills.add(new Pair<>(skillId, level));
|
||||
if (this.skillsUsed.containsKey(new Pair<>(skillId, level))) {
|
||||
int times = this.skillsUsed.get(new Pair<>(skillId, level)) + 1;
|
||||
this.skillsUsed.remove(new Pair<>(skillId, level));
|
||||
this.skillsUsed.put(new Pair<>(skillId, level), times);
|
||||
Pair<Integer, Integer> skillKey = new Pair<>(skillId, level);
|
||||
this.usedSkills.add(skillKey);
|
||||
|
||||
Integer useCount = this.skillsUsed.remove(skillKey);
|
||||
if (useCount != null) {
|
||||
this.skillsUsed.put(skillKey, useCount + 1);
|
||||
} else {
|
||||
this.skillsUsed.put(new Pair<>(skillId, level), 1);
|
||||
this.skillsUsed.put(skillKey, 1);
|
||||
}
|
||||
} finally {
|
||||
monsterLock.unlock();
|
||||
@@ -1605,6 +1643,40 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
changeLevelByDifficulty(difficulty, pqMob);
|
||||
}
|
||||
|
||||
private boolean isPuppetInVicinity(MapleSummon summon) {
|
||||
return summon.getPosition().distanceSq(this.getPosition()) < 177777;
|
||||
}
|
||||
|
||||
public boolean isCharacterPuppetInVicinity(MapleCharacter chr) {
|
||||
MapleStatEffect mse = chr.getBuffEffect(MapleBuffStat.PUPPET);
|
||||
if (mse != null) {
|
||||
MapleSummon summon = chr.getSummonByKey(mse.getSourceId());
|
||||
|
||||
// check whether mob is currently under a puppet's field of action or not
|
||||
if (summon != null) {
|
||||
if (isPuppetInVicinity(summon)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
map.getAggroCoordinator().removePuppetAggro(chr.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isLeadingPuppetInVicinity() {
|
||||
MapleCharacter chrController = this.getActiveController();
|
||||
|
||||
if (chrController != null) {
|
||||
if (this.isCharacterPuppetInVicinity(chrController)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private MapleCharacter getNextControllerCandidate() {
|
||||
int mincontrolled = Integer.MAX_VALUE;
|
||||
MapleCharacter newController = null;
|
||||
@@ -1612,11 +1684,16 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
int mincontrolleddead = Integer.MAX_VALUE;
|
||||
MapleCharacter newControllerDead = null;
|
||||
|
||||
MapleCharacter newControllerWithPuppet = null;
|
||||
|
||||
for (MapleCharacter chr : getMap().getAllPlayers()) {
|
||||
if (!chr.isHidden()) {
|
||||
int ctrlMonsSize = chr.getNumControlledMonsters();
|
||||
|
||||
if (chr.isAlive()) {
|
||||
if (isCharacterPuppetInVicinity(chr)) {
|
||||
newControllerWithPuppet = chr;
|
||||
break;
|
||||
} else if (chr.isAlive()) {
|
||||
if (ctrlMonsSize < mincontrolled) {
|
||||
mincontrolled = ctrlMonsSize;
|
||||
newController = chr;
|
||||
@@ -1630,7 +1707,13 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
}
|
||||
|
||||
return newController != null ? newController : newControllerDead;
|
||||
if (newControllerWithPuppet != null) {
|
||||
return newControllerWithPuppet;
|
||||
} else if (newController != null) {
|
||||
return newController;
|
||||
} else {
|
||||
return newControllerDead;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1682,15 +1765,39 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
this.setController(newController);
|
||||
this.setControllerHasAggro(immediateAggro);
|
||||
this.setControllerKnowsAboutAggro(false);
|
||||
this.setControllerHasPuppet(false);
|
||||
} finally {
|
||||
aggroUpdateLock.unlock();
|
||||
}
|
||||
|
||||
this.aggroUpdatePuppetVisibility();
|
||||
newController.announce(MaplePacketCreator.controlMonster(this, false, immediateAggro));
|
||||
newController.controlMonster(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void aggroAddPuppet(MapleCharacter player) {
|
||||
MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator();
|
||||
mmac.addPuppetAggro(player);
|
||||
|
||||
aggroUpdatePuppetController(player);
|
||||
|
||||
if (this.isControllerHasAggro()) {
|
||||
this.aggroUpdatePuppetVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
public void aggroRemovePuppet(MapleCharacter player) {
|
||||
MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator();
|
||||
mmac.removePuppetAggro(player.getId());
|
||||
|
||||
aggroUpdatePuppetController(null);
|
||||
|
||||
if (this.isControllerHasAggro()) {
|
||||
this.aggroUpdatePuppetVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Automagically finds a new controller for the given monster from the chars
|
||||
* on the map it is from...
|
||||
@@ -1710,6 +1817,60 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
this.aggroSwitchController(newController, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a new controller for the given monster from the chars with deployed puppet
|
||||
* nearby on the map it is from...
|
||||
*
|
||||
*/
|
||||
private void aggroUpdatePuppetController(MapleCharacter newController) {
|
||||
MapleCharacter chrController = this.getActiveController();
|
||||
boolean updateController = false;
|
||||
|
||||
if (chrController != null && chrController.isAlive()) {
|
||||
if (isCharacterPuppetInVicinity(chrController)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
updateController = true;
|
||||
}
|
||||
|
||||
if (newController == null || !isCharacterPuppetInVicinity(newController)) {
|
||||
MapleMonsterAggroCoordinator mmac = map.getAggroCoordinator();
|
||||
|
||||
List<Integer> puppetOwners = mmac.getPuppetAggroList();
|
||||
List<Integer> toRemovePuppets = new LinkedList<>();
|
||||
|
||||
for (Integer cid : puppetOwners) {
|
||||
MapleCharacter chr = map.getCharacterById(cid);
|
||||
|
||||
if (chr != null) {
|
||||
if (isCharacterPuppetInVicinity(chr)) {
|
||||
newController = chr;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
toRemovePuppets.add(cid);
|
||||
}
|
||||
}
|
||||
|
||||
for (Integer cid : toRemovePuppets) {
|
||||
mmac.removePuppetAggro(cid);
|
||||
}
|
||||
|
||||
if (newController == null) { // was a new controller found? (if not there's no puppet nearby)
|
||||
if (updateController) {
|
||||
aggroUpdateController();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
} else if (chrController == newController) {
|
||||
this.aggroUpdatePuppetVisibility();
|
||||
}
|
||||
|
||||
this.aggroSwitchController(newController, this.isControllerHasAggro());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures controllability removal of the current player controller, and
|
||||
* fetches for any player on the map to start controlling in place.
|
||||
@@ -1767,6 +1928,9 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
if (chrController != attacker) {
|
||||
if (this.getMapAggroCoordinator().isLeadingCharacterAggro(this, attacker)) {
|
||||
this.aggroSwitchController(attacker, true);
|
||||
} else {
|
||||
this.setControllerHasAggro(true);
|
||||
this.aggroUpdatePuppetVisibility();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1780,9 +1944,69 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
*/
|
||||
} else {
|
||||
this.setControllerHasAggro(true);
|
||||
this.aggroUpdatePuppetVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private void aggroRefreshPuppetVisibility(MapleCharacter chrController, MapleSummon puppet) {
|
||||
// lame patch for client to redirect all aggro to the puppet
|
||||
|
||||
List<MapleMonster> puppetControlled = new LinkedList<>();
|
||||
for (MapleMonster mob : chrController.getControlledMonsters()) {
|
||||
if (mob.isPuppetInVicinity(puppet)) {
|
||||
puppetControlled.add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
for (MapleMonster mob : puppetControlled) {
|
||||
chrController.announce(MaplePacketCreator.stopControllingMonster(mob.getObjectId()));
|
||||
}
|
||||
chrController.announce(MaplePacketCreator.removeSummon(puppet, false));
|
||||
|
||||
for (MapleMonster mob : puppetControlled) {
|
||||
chrController.announce(MaplePacketCreator.controlMonster(mob, false, mob.isControllerHasAggro()));
|
||||
}
|
||||
chrController.announce(MaplePacketCreator.spawnSummon(puppet, false));
|
||||
}
|
||||
|
||||
public void aggroUpdatePuppetVisibility() {
|
||||
if (!availablePuppetUpdate) return;
|
||||
|
||||
availablePuppetUpdate = false;
|
||||
Runnable r = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
MapleCharacter chrController = MapleMonster.this.getActiveController();
|
||||
if (chrController == null) return;
|
||||
|
||||
MapleStatEffect puppetEffect = chrController.getBuffEffect(MapleBuffStat.PUPPET);
|
||||
if (puppetEffect != null) {
|
||||
MapleSummon puppet = chrController.getSummonByKey(puppetEffect.getSourceId());
|
||||
|
||||
if (puppet != null && isPuppetInVicinity(puppet)) {
|
||||
controllerHasPuppet = true;
|
||||
aggroRefreshPuppetVisibility(chrController, puppet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (controllerHasPuppet) {
|
||||
controllerHasPuppet = false;
|
||||
|
||||
chrController.announce(MaplePacketCreator.stopControllingMonster(MapleMonster.this.getObjectId()));
|
||||
chrController.announce(MaplePacketCreator.controlMonster(MapleMonster.this, false, MapleMonster.this.isControllerHasAggro()));
|
||||
}
|
||||
} finally {
|
||||
availablePuppetUpdate = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// had to schedule this since mob wouldn't stick to puppet aggro who knows why
|
||||
this.getMap().getChannelServer().registerOverallAction(this.getMap().getId(), r, ServerConstants.UPDATE_INTERVAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all applied damage input for this mob, doesn't refresh target aggro.
|
||||
*
|
||||
@@ -1805,7 +2029,12 @@ public class MapleMonster extends AbstractLoadedMapleLife {
|
||||
}
|
||||
}
|
||||
|
||||
public final void disposeLocks() {
|
||||
public void dispose() {
|
||||
this.getMap().dismissRemoveAfter(this);
|
||||
disposeLocks();
|
||||
}
|
||||
|
||||
private void disposeLocks() {
|
||||
LockCollector.getInstance().registerDisposeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user