diff --git a/data-otservbr-global/monster/bosses/black_knight.lua b/data-otservbr-global/monster/bosses/black_knight.lua index fe50d74af3f..2905e1a7814 100644 --- a/data-otservbr-global/monster/bosses/black_knight.lua +++ b/data-otservbr-global/monster/bosses/black_knight.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "BlackKnightDeath", +} + monster.bosstiary = { bossRaceId = 46, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/bosses/diseased_bill.lua b/data-otservbr-global/monster/bosses/diseased_bill.lua index b8982c4e259..c2524dd8267 100644 --- a/data-otservbr-global/monster/bosses/diseased_bill.lua +++ b/data-otservbr-global/monster/bosses/diseased_bill.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DiseasedTrioDeath", +} + monster.bosstiary = { bossRaceId = 485, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/bosses/diseased_dan.lua b/data-otservbr-global/monster/bosses/diseased_dan.lua index 8eb9d3a1535..7ee84a080a1 100644 --- a/data-otservbr-global/monster/bosses/diseased_dan.lua +++ b/data-otservbr-global/monster/bosses/diseased_dan.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DiseasedTrioDeath", +} + monster.bosstiary = { bossRaceId = 486, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/bosses/diseased_fred.lua b/data-otservbr-global/monster/bosses/diseased_fred.lua index e516fd9e2df..d2ab31a5578 100644 --- a/data-otservbr-global/monster/bosses/diseased_fred.lua +++ b/data-otservbr-global/monster/bosses/diseased_fred.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DiseasedTrioDeath", +} + monster.bosstiary = { bossRaceId = 484, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/bosses/energized_raging_mage.lua b/data-otservbr-global/monster/bosses/energized_raging_mage.lua index d8d7d4809e8..0d3aea8aaf0 100644 --- a/data-otservbr-global/monster/bosses/energized_raging_mage.lua +++ b/data-otservbr-global/monster/bosses/energized_raging_mage.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "EnergizedRagingMageDeath", +} + monster.health = 3500 monster.maxHealth = 3500 monster.race = "blood" diff --git a/data-otservbr-global/monster/bosses/kroazur.lua b/data-otservbr-global/monster/bosses/kroazur.lua index 78357fbf8e7..14740f8f522 100644 --- a/data-otservbr-global/monster/bosses/kroazur.lua +++ b/data-otservbr-global/monster/bosses/kroazur.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ThreatenedDreamsNightmareMonstersDeath", +} + monster.bosstiary = { bossRaceId = 1515, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/bosses/pythius_the_rotten.lua b/data-otservbr-global/monster/bosses/pythius_the_rotten.lua index 3331d64e027..b635ea69133 100644 --- a/data-otservbr-global/monster/bosses/pythius_the_rotten.lua +++ b/data-otservbr-global/monster/bosses/pythius_the_rotten.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "PythiusTheRottenDeath", +} + monster.health = 9000 monster.maxHealth = 9000 monster.race = "undead" diff --git a/data-otservbr-global/monster/bosses/raging_mage.lua b/data-otservbr-global/monster/bosses/raging_mage.lua index 39518d5431a..5fd30131b8a 100644 --- a/data-otservbr-global/monster/bosses/raging_mage.lua +++ b/data-otservbr-global/monster/bosses/raging_mage.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RagingMageDeath", +} + monster.health = 3500 monster.maxHealth = 3500 monster.race = "blood" diff --git a/data-otservbr-global/monster/bosses/renegade_orc.lua b/data-otservbr-global/monster/bosses/renegade_orc.lua index c12f3d73e39..53f075751ae 100644 --- a/data-otservbr-global/monster/bosses/renegade_orc.lua +++ b/data-otservbr-global/monster/bosses/renegade_orc.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RenegadeOrcDeath", +} + monster.health = 450 monster.maxHealth = 450 monster.race = "blood" diff --git a/data-otservbr-global/monster/bosses/splasher.lua b/data-otservbr-global/monster/bosses/splasher.lua index 670c402c859..b579d921327 100644 --- a/data-otservbr-global/monster/bosses/splasher.lua +++ b/data-otservbr-global/monster/bosses/splasher.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "QuaraLeadersDeath", +} + monster.health = 1700 monster.maxHealth = 1700 monster.race = "blood" diff --git a/data-otservbr-global/monster/constructs/diamond_servant_replica.lua b/data-otservbr-global/monster/constructs/diamond_servant_replica.lua index 487811413e1..733ea51c2fe 100644 --- a/data-otservbr-global/monster/constructs/diamond_servant_replica.lua +++ b/data-otservbr-global/monster/constructs/diamond_servant_replica.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ReplicaServantDeath", +} + monster.raceId = 1326 monster.Bestiary = { class = "Construct", diff --git a/data-otservbr-global/monster/constructs/golden_servant_replica.lua b/data-otservbr-global/monster/constructs/golden_servant_replica.lua index dbf2b07dfeb..4a93d0d9635 100644 --- a/data-otservbr-global/monster/constructs/golden_servant_replica.lua +++ b/data-otservbr-global/monster/constructs/golden_servant_replica.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ReplicaServantDeath", +} + monster.raceId = 1327 monster.Bestiary = { class = "Construct", diff --git a/data-otservbr-global/monster/dawnport/mountain_troll.lua b/data-otservbr-global/monster/dawnport/mountain_troll.lua index 86e38adf4cd..fab1ebf82b5 100644 --- a/data-otservbr-global/monster/dawnport/mountain_troll.lua +++ b/data-otservbr-global/monster/dawnport/mountain_troll.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MorrisTrollDeath", +} + monster.health = 30 monster.maxHealth = 30 monster.race = "blood" diff --git a/data-otservbr-global/monster/dawnport/muglex_clan_footman.lua b/data-otservbr-global/monster/dawnport/muglex_clan_footman.lua index 53bc52730f5..2695c29aea9 100644 --- a/data-otservbr-global/monster/dawnport/muglex_clan_footman.lua +++ b/data-otservbr-global/monster/dawnport/muglex_clan_footman.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MorrisGoblinDeath", +} + monster.health = 50 monster.maxHealth = 50 monster.race = "blood" diff --git a/data-otservbr-global/monster/dragons/dragon.lua b/data-otservbr-global/monster/dragons/dragon.lua index 52ca6324429..16dd2aa26c7 100644 --- a/data-otservbr-global/monster/dragons/dragon.lua +++ b/data-otservbr-global/monster/dragons/dragon.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "TheGreatDragonHuntDeath", + "TheFirstDragonDragonTaskDeath", +} + monster.raceId = 34 monster.Bestiary = { class = "Dragon", diff --git a/data-otservbr-global/monster/dragons/dragon_lord.lua b/data-otservbr-global/monster/dragons/dragon_lord.lua index 57ce3725109..65d7e225e47 100644 --- a/data-otservbr-global/monster/dragons/dragon_lord.lua +++ b/data-otservbr-global/monster/dragons/dragon_lord.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "TheGreatDragonHuntDeath", +} + monster.raceId = 39 monster.Bestiary = { class = "Dragon", diff --git a/data-otservbr-global/monster/extra_dimensional/yielothax.lua b/data-otservbr-global/monster/extra_dimensional/yielothax.lua index 76b1194cd07..487a8d5c30d 100644 --- a/data-otservbr-global/monster/extra_dimensional/yielothax.lua +++ b/data-otservbr-global/monster/extra_dimensional/yielothax.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "YielothaxDeath", +} + monster.raceId = 717 monster.Bestiary = { class = "Extra Dimensional", diff --git a/data-otservbr-global/monster/humanoids/lost_exile.lua b/data-otservbr-global/monster/humanoids/lost_exile.lua index 8fc53213306..d1bb52aaa09 100644 --- a/data-otservbr-global/monster/humanoids/lost_exile.lua +++ b/data-otservbr-global/monster/humanoids/lost_exile.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "LastExileDeath", +} + monster.raceId = 1529 monster.Bestiary = { class = "Humanoid", diff --git a/data-otservbr-global/monster/humanoids/minotaur_bruiser.lua b/data-otservbr-global/monster/humanoids/minotaur_bruiser.lua index b704e765d2c..51eb241298c 100644 --- a/data-otservbr-global/monster/humanoids/minotaur_bruiser.lua +++ b/data-otservbr-global/monster/humanoids/minotaur_bruiser.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MorrisMinotaurDeath", +} + monster.health = 100 monster.maxHealth = 100 monster.race = "blood" diff --git a/data-otservbr-global/monster/humanoids/minotaur_cult_follower.lua b/data-otservbr-global/monster/humanoids/minotaur_cult_follower.lua index 1aff1c992c6..18883c46827 100644 --- a/data-otservbr-global/monster/humanoids/minotaur_cult_follower.lua +++ b/data-otservbr-global/monster/humanoids/minotaur_cult_follower.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MinotaurCultTaskDeath", +} + monster.raceId = 1508 monster.Bestiary = { class = "Humanoid", diff --git a/data-otservbr-global/monster/humanoids/minotaur_cult_prophet.lua b/data-otservbr-global/monster/humanoids/minotaur_cult_prophet.lua index 13e823fa17a..5f86e2de209 100644 --- a/data-otservbr-global/monster/humanoids/minotaur_cult_prophet.lua +++ b/data-otservbr-global/monster/humanoids/minotaur_cult_prophet.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MinotaurCultTaskDeath", +} + monster.raceId = 1509 monster.Bestiary = { class = "Humanoid", diff --git a/data-otservbr-global/monster/humanoids/minotaur_cult_zealot.lua b/data-otservbr-global/monster/humanoids/minotaur_cult_zealot.lua index be4fc8a4bdc..571d3faa060 100644 --- a/data-otservbr-global/monster/humanoids/minotaur_cult_zealot.lua +++ b/data-otservbr-global/monster/humanoids/minotaur_cult_zealot.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MinotaurCultTaskDeath", +} + monster.raceId = 1510 monster.Bestiary = { class = "Humanoid", diff --git a/data-otservbr-global/monster/humans/burning_gladiator.lua b/data-otservbr-global/monster/humans/burning_gladiator.lua index 70f9f4f0c1d..8923d0928cb 100644 --- a/data-otservbr-global/monster/humans/burning_gladiator.lua +++ b/data-otservbr-global/monster/humans/burning_gladiator.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "FafnarMissionsDeath", +} + monster.raceId = 1798 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/humans/nomad.lua b/data-otservbr-global/monster/humans/nomad.lua index d656857b42f..9c34282bf80 100644 --- a/data-otservbr-global/monster/humans/nomad.lua +++ b/data-otservbr-global/monster/humans/nomad.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "NomadDeath", +} + monster.raceId = 310 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/humans/nomad_blue.lua b/data-otservbr-global/monster/humans/nomad_blue.lua index 02465d966f7..07ba7aff29a 100644 --- a/data-otservbr-global/monster/humans/nomad_blue.lua +++ b/data-otservbr-global/monster/humans/nomad_blue.lua @@ -14,6 +14,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "NomadDeath", +} + monster.raceId = 777 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/humans/nomad_female.lua b/data-otservbr-global/monster/humans/nomad_female.lua index 2703f84d4c6..9460aab59cf 100644 --- a/data-otservbr-global/monster/humans/nomad_female.lua +++ b/data-otservbr-global/monster/humans/nomad_female.lua @@ -14,6 +14,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "NomadDeath", +} + monster.raceId = 776 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/humans/priestess_of_the_wild_sun.lua b/data-otservbr-global/monster/humans/priestess_of_the_wild_sun.lua index 25eea0d8723..a97c9a3c56d 100644 --- a/data-otservbr-global/monster/humans/priestess_of_the_wild_sun.lua +++ b/data-otservbr-global/monster/humans/priestess_of_the_wild_sun.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "FafnarMissionsDeath", +} + monster.raceId = 1799 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/magicals/crystalcrusher.lua b/data-otservbr-global/monster/magicals/crystalcrusher.lua index c0698ab34b5..4da886c9df3 100644 --- a/data-otservbr-global/monster/magicals/crystalcrusher.lua +++ b/data-otservbr-global/monster/magicals/crystalcrusher.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MiddleSpikeDeath", +} + monster.raceId = 869 monster.Bestiary = { class = "Magical", diff --git a/data-otservbr-global/monster/magicals/enfeebled_silencer.lua b/data-otservbr-global/monster/magicals/enfeebled_silencer.lua index 95bd1948831..c631f75d0cb 100644 --- a/data-otservbr-global/monster/magicals/enfeebled_silencer.lua +++ b/data-otservbr-global/monster/magicals/enfeebled_silencer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ThreatenedDreamsNightmareMonstersDeath", +} + monster.raceId = 1443 monster.Bestiary = { class = "Magical", diff --git a/data-otservbr-global/monster/magicals/frazzlemaw.lua b/data-otservbr-global/monster/magicals/frazzlemaw.lua index 50927628608..32a053b1dcc 100644 --- a/data-otservbr-global/monster/magicals/frazzlemaw.lua +++ b/data-otservbr-global/monster/magicals/frazzlemaw.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RoshamuulKillsDeath", +} + monster.raceId = 1022 monster.Bestiary = { class = "Magical", diff --git a/data-otservbr-global/monster/magicals/silencer.lua b/data-otservbr-global/monster/magicals/silencer.lua index e71ec572cef..b2399ce294d 100644 --- a/data-otservbr-global/monster/magicals/silencer.lua +++ b/data-otservbr-global/monster/magicals/silencer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RoshamuulKillsDeath", +} + monster.raceId = 1014 monster.Bestiary = { class = "Magical", diff --git a/data-otservbr-global/monster/magicals/weakened_frazzlemaw.lua b/data-otservbr-global/monster/magicals/weakened_frazzlemaw.lua index d44126f9518..d7e8eba093f 100644 --- a/data-otservbr-global/monster/magicals/weakened_frazzlemaw.lua +++ b/data-otservbr-global/monster/magicals/weakened_frazzlemaw.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ThreatenedDreamsNightmareMonstersDeath", +} + monster.raceId = 1442 monster.Bestiary = { class = "Magical", diff --git a/data-otservbr-global/monster/mammals/husky.lua b/data-otservbr-global/monster/mammals/husky.lua index 314d948e454..dae58bcc664 100644 --- a/data-otservbr-global/monster/mammals/husky.lua +++ b/data-otservbr-global/monster/mammals/husky.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "HuskyDeath", +} + monster.raceId = 325 monster.Bestiary = { class = "Mammal", diff --git a/data-otservbr-global/monster/mammals/rat.lua b/data-otservbr-global/monster/mammals/rat.lua index 17747658eea..205888f9a55 100644 --- a/data-otservbr-global/monster/mammals/rat.lua +++ b/data-otservbr-global/monster/mammals/rat.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RationalRequestRatDeath", +} + monster.raceId = 21 monster.Bestiary = { class = "Mammal", diff --git a/data-otservbr-global/monster/quests/bigfoots_burden/bosses/abyssador.lua b/data-otservbr-global/monster/quests/bigfoots_burden/bosses/abyssador.lua index 177700eedf9..24c993fda5b 100644 --- a/data-otservbr-global/monster/quests/bigfoots_burden/bosses/abyssador.lua +++ b/data-otservbr-global/monster/quests/bigfoots_burden/bosses/abyssador.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "BossesWarzoneDeath", +} + monster.bosstiary = { bossRaceId = 887, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/bigfoots_burden/bosses/deathstrike.lua b/data-otservbr-global/monster/quests/bigfoots_burden/bosses/deathstrike.lua index 9fef07f960d..b7e88ede791 100644 --- a/data-otservbr-global/monster/quests/bigfoots_burden/bosses/deathstrike.lua +++ b/data-otservbr-global/monster/quests/bigfoots_burden/bosses/deathstrike.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "BossesWarzoneDeath", +} + monster.bosstiary = { bossRaceId = 892, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/bigfoots_burden/bosses/gnomevil.lua b/data-otservbr-global/monster/quests/bigfoots_burden/bosses/gnomevil.lua index b0d0a7487a1..cd287d83709 100644 --- a/data-otservbr-global/monster/quests/bigfoots_burden/bosses/gnomevil.lua +++ b/data-otservbr-global/monster/quests/bigfoots_burden/bosses/gnomevil.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "BossesWarzoneDeath", +} + monster.bosstiary = { bossRaceId = 893, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/bigfoots_burden/versperoth.lua b/data-otservbr-global/monster/quests/bigfoots_burden/versperoth.lua index d8e260236fd..c422f817bb2 100644 --- a/data-otservbr-global/monster/quests/bigfoots_burden/versperoth.lua +++ b/data-otservbr-global/monster/quests/bigfoots_burden/versperoth.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "VesperothDeath", +} + monster.health = 100000 monster.maxHealth = 100000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/dorokoll_the_mystic.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/dorokoll_the_mystic.lua index 018dc2c092e..926fb0c79ac 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/dorokoll_the_mystic.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/dorokoll_the_mystic.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "EssenceOfMaliceSpawnsDeath", +} + monster.health = 30000 monster.maxHealth = 30000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eliz_the_unyielding.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eliz_the_unyielding.lua index bc6aa5b1741..41c7815e73c 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eliz_the_unyielding.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eliz_the_unyielding.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "EssenceOfMaliceSpawnsDeath", +} + monster.health = 30000 monster.maxHealth = 30000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eshtaba_the_conjurer.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eshtaba_the_conjurer.lua index 175b0df635e..b6190942dbc 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eshtaba_the_conjurer.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/eshtaba_the_conjurer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "EssenceOfMaliceSpawnsDeath", +} + monster.health = 30000 monster.maxHealth = 30000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/essence_of_malice.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/essence_of_malice.lua index e9b7c7d9105..ef49131374d 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/essence_of_malice.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/essence_of_malice.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1487, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/malkhar_deathbringer.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/malkhar_deathbringer.lua index 14013f130ec..7b800bd8f22 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/malkhar_deathbringer.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/malkhar_deathbringer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "EssenceOfMaliceSpawnsDeath", +} + monster.health = 30000 monster.maxHealth = 30000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/mezlon_the_defiler.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/mezlon_the_defiler.lua index 425ae3cc725..3576693ea0f 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/mezlon_the_defiler.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/mezlon_the_defiler.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "EssenceOfMaliceSpawnsDeath", +} + monster.health = 30000 monster.maxHealth = 30000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_death.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_death.lua index 9ef05c56c67..5ad9d82334b 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_death.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_death.lua @@ -14,6 +14,10 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "DestroyedPillar", +} + monster.changeTarget = { interval = 4000, chance = 20, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_draining.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_draining.lua index ec8fb38d78e..c2bb501e3b6 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_draining.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_draining.lua @@ -14,6 +14,10 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "DestroyedPillar", +} + monster.changeTarget = { interval = 4000, chance = 20, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_healing.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_healing.lua index fff5544ece4..95c185f7d4c 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_healing.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_healing.lua @@ -14,6 +14,10 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "DestroyedPillar", +} + monster.changeTarget = { interval = 4000, chance = 20, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_protection.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_protection.lua index d8d103b22f3..5729390a4d8 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_protection.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_protection.lua @@ -14,6 +14,10 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "DestroyedPillar", +} + monster.changeTarget = { interval = 4000, chance = 20, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_summoning.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_summoning.lua index a6e02db4fbc..27937b85537 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_summoning.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/pillars/pillar_of_summoning.lua @@ -14,6 +14,10 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "DestroyedPillar", +} + monster.changeTarget = { interval = 4000, chance = 20, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/ravenous_hunger.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/ravenous_hunger.lua index cee0dd32fc6..ee9b5d37a66 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/ravenous_hunger.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/ravenous_hunger.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "LeidenHeal", + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1427, bossRace = RARITY_ARCHFOE, @@ -57,10 +62,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "LeidenHeal", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_corruptor_of_souls.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_corruptor_of_souls.lua index dfcc46ab6d7..adc1b89d393 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_corruptor_of_souls.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_corruptor_of_souls.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.health = 290000 monster.maxHealth = 290000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_false_god.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_false_god.lua index 888f068159b..a1ec678bdf0 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_false_god.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_false_god.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1409, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_sandking.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_sandking.lua index 89ef694e51a..3e0914007db 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_sandking.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_sandking.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1444, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_souldespoiler.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_souldespoiler.lua index abcf4d8fc27..35878eae9bf 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_souldespoiler.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_souldespoiler.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1422, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_source_of_corruption.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_source_of_corruption.lua index ef660075883..83f14ead593 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_source_of_corruption.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_source_of_corruption.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1500, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_unarmored_voidborn.lua b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_unarmored_voidborn.lua index 40c70d77fb7..0dbf6743e2d 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_unarmored_voidborn.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/bosses/the_unarmored_voidborn.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CultsOfTibiaBossDeath", +} + monster.bosstiary = { bossRaceId = 1406, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/cult_believer.lua b/data-otservbr-global/monster/quests/cults_of_tibia/cult_believer.lua index 71a717df8f3..18c727b1eab 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/cult_believer.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/cult_believer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CarlinVortexDeath", +} + monster.raceId = 1512 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/cult_enforcer.lua b/data-otservbr-global/monster/quests/cults_of_tibia/cult_enforcer.lua index 27b33840d4c..abe7c8d4a9a 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/cult_enforcer.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/cult_enforcer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CarlinVortexDeath", +} + monster.raceId = 1513 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/cult_scholar.lua b/data-otservbr-global/monster/quests/cults_of_tibia/cult_scholar.lua index e4d9b02ada5..bd743a11076 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/cult_scholar.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/cult_scholar.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "CarlinVortexDeath", +} + monster.raceId = 1514 monster.Bestiary = { class = "Human", diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/misguided_bully.lua b/data-otservbr-global/monster/quests/cults_of_tibia/misguided_bully.lua index 8f653d2f2dd..5cf1c3b8582 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/misguided_bully.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/misguided_bully.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GlowingRubbishAmuletDeath", +} + monster.raceId = 1412 monster.Bestiary = { class = "Humanoid", diff --git a/data-otservbr-global/monster/quests/cults_of_tibia/misguided_shadow.lua b/data-otservbr-global/monster/quests/cults_of_tibia/misguided_shadow.lua index 5886f068e97..547c67f7cf1 100644 --- a/data-otservbr-global/monster/quests/cults_of_tibia/misguided_shadow.lua +++ b/data-otservbr-global/monster/quests/cults_of_tibia/misguided_shadow.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GlowingRubbishAmuletDeath", +} + monster.health = 3000 monster.maxHealth = 3000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_baron_from_below.lua b/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_baron_from_below.lua index 12c461e44a3..e780ac65c8b 100644 --- a/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_baron_from_below.lua +++ b/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_baron_from_below.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DepthWarzoneBossDeath", + "TheBaronFromBelowThink", +} + monster.health = 350000 monster.maxHealth = 350000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_count_of_the_core.lua b/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_count_of_the_core.lua index 3a9b1726e29..80878aaa360 100644 --- a/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_count_of_the_core.lua +++ b/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_count_of_the_core.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DepthWarzoneBossDeath", +} + monster.health = 350000 monster.maxHealth = 350000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_duke_of_the_depths.lua b/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_duke_of_the_depths.lua index eb960a171e0..31c354f7667 100644 --- a/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_duke_of_the_depths.lua +++ b/data-otservbr-global/monster/quests/dangerous_depth/bosses/the_duke_of_the_depths.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DepthWarzoneBossDeath", +} + monster.health = 350000 monster.maxHealth = 350000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/dangerous_depth/makeshift_home.lua b/data-otservbr-global/monster/quests/dangerous_depth/makeshift_home.lua index fc70f937f66..0b64ccee736 100644 --- a/data-otservbr-global/monster/quests/dangerous_depth/makeshift_home.lua +++ b/data-otservbr-global/monster/quests/dangerous_depth/makeshift_home.lua @@ -14,6 +14,10 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "MakeshiftHomeDeath", +} + monster.changeTarget = { interval = 5000, chance = 10, diff --git a/data-otservbr-global/monster/quests/dangerous_depth/organic_matter.lua b/data-otservbr-global/monster/quests/dangerous_depth/organic_matter.lua index a7d5ec477be..bf292570fb8 100644 --- a/data-otservbr-global/monster/quests/dangerous_depth/organic_matter.lua +++ b/data-otservbr-global/monster/quests/dangerous_depth/organic_matter.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "OrganicMatterDeath", +} + monster.health = 10000 monster.maxHealth = 10000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/dangerous_depth/snail_slime.lua b/data-otservbr-global/monster/quests/dangerous_depth/snail_slime.lua index e5e4942e6d4..2bfa943c47a 100644 --- a/data-otservbr-global/monster/quests/dangerous_depth/snail_slime.lua +++ b/data-otservbr-global/monster/quests/dangerous_depth/snail_slime.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SnailSlimeDeath", + "SnailSlimeThink", +} + monster.health = 4500 monster.maxHealth = 4500 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/dark_trails/death_priest_shargon.lua b/data-otservbr-global/monster/quests/dark_trails/death_priest_shargon.lua index 13fd2f07c51..c64a01061b9 100644 --- a/data-otservbr-global/monster/quests/dark_trails/death_priest_shargon.lua +++ b/data-otservbr-global/monster/quests/dark_trails/death_priest_shargon.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ShargonDeath", +} + monster.bosstiary = { bossRaceId = 1047, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/dark_trails/the_ravager.lua b/data-otservbr-global/monster/quests/dark_trails/the_ravager.lua index 1c10ace0db9..a8683a6f92e 100644 --- a/data-otservbr-global/monster/quests/dark_trails/the_ravager.lua +++ b/data-otservbr-global/monster/quests/dark_trails/the_ravager.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "TheRavagerDeath", +} + monster.bosstiary = { bossRaceId = 1035, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/feaster_of_souls/the_dread_maiden.lua b/data-otservbr-global/monster/quests/feaster_of_souls/the_dread_maiden.lua index 9ca5ba11862..83308c9c2fc 100644 --- a/data-otservbr-global/monster/quests/feaster_of_souls/the_dread_maiden.lua +++ b/data-otservbr-global/monster/quests/feaster_of_souls/the_dread_maiden.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "FeasterOfSoulsBossDeath", +} + monster.bosstiary = { bossRaceId = 1872, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/feaster_of_souls/the_fear_feaster.lua b/data-otservbr-global/monster/quests/feaster_of_souls/the_fear_feaster.lua index 058842c7089..b5f69b05e3f 100644 --- a/data-otservbr-global/monster/quests/feaster_of_souls/the_fear_feaster.lua +++ b/data-otservbr-global/monster/quests/feaster_of_souls/the_fear_feaster.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "FeasterOfSoulsBossDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua b/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua index 41bf63ad767..bde610ee680 100644 --- a/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua +++ b/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua @@ -22,6 +22,7 @@ monster.manaCost = 0 monster.events = { "paleWormDeath", + "FeasterOfSoulsBossDeath", } monster.changeTarget = { diff --git a/data-otservbr-global/monster/quests/feaster_of_souls/the_unwelcome.lua b/data-otservbr-global/monster/quests/feaster_of_souls/the_unwelcome.lua index 383795d8bbe..7c0cd052961 100644 --- a/data-otservbr-global/monster/quests/feaster_of_souls/the_unwelcome.lua +++ b/data-otservbr-global/monster/quests/feaster_of_souls/the_unwelcome.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "FeasterOfSoulsBossDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ferumbras_mortal_shell.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ferumbras_mortal_shell.lua index 0d1cb775768..27160109571 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ferumbras_mortal_shell.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ferumbras_mortal_shell.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/mazoran.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/mazoran.lua index e412a2af7c3..1a25d435223 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/mazoran.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/mazoran.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.bosstiary = { bossRaceId = 1186, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/plagirath.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/plagirath.lua index e0cb0b883ff..b86ac1a47bd 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/plagirath.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/plagirath.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.bosstiary = { bossRaceId = 1199, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ragiaz.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ragiaz.lua index 0f196297f4a..e9f97824c97 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ragiaz.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/ragiaz.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.bosstiary = { bossRaceId = 1180, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/razzagorn.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/razzagorn.lua index 480df7868fa..07d2a55b07b 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/razzagorn.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/razzagorn.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.bosstiary = { bossRaceId = 1177, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/shulgrax.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/shulgrax.lua index 2ad81b631c7..69eae8f369b 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/shulgrax.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/shulgrax.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.health = 40000 monster.maxHealth = 40000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/tarbaz.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/tarbaz.lua index 9b6bf3492f0..16fd12f63e8 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/tarbaz.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/tarbaz.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.health = 290000 monster.maxHealth = 290000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_lord_of_the_lice.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_lord_of_the_lice.lua index 1a9d2504c4d..08b0fd0a836 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_lord_of_the_lice.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_lord_of_the_lice.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.bosstiary = { bossRaceId = 1179, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_shatterer.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_shatterer.lua index 76a70e53189..eb414a427f3 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_shatterer.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/the_shatterer.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "TheShattererDeath", +} + monster.health = 220000 monster.maxHealth = 220000 monster.race = "fire" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh.lua index 00d02c7c38d..f3bbd04efd4 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh2.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh2.lua index e3f7a2cfceb..5adb3a046bc 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh2.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh2.lua @@ -14,6 +14,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh3.lua b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh3.lua index 3d8b71189eb..ec8cb0ade3a 100644 --- a/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh3.lua +++ b/data-otservbr-global/monster/quests/ferumbras_ascendant/bosses/zamulosh3.lua @@ -14,6 +14,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AscendantBossesDeath", + "ZamuloshClone", +} + monster.health = 1000 monster.maxHealth = 1000 monster.race = "undead" @@ -53,10 +58,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "ZamuloshClone", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lady_tenebris.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lady_tenebris.lua index 40452abcabe..c7087a421ba 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lady_tenebris.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lady_tenebris.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", + "HealthForgotten", +} + monster.bosstiary = { bossRaceId = 1315, bossRace = RARITY_ARCHFOE, @@ -57,10 +62,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "HealthForgotten", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lloyd.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lloyd.lua index 4cb143dd933..2cd9bdcd5b0 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lloyd.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/lloyd.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", + "LloydPrepareDeath", +} + monster.bosstiary = { bossRaceId = 1329, bossRace = RARITY_ARCHFOE, @@ -57,10 +62,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "LloydPrepareDeath", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/melting_frozen_horror.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/melting_frozen_horror.lua index d856af4495c..6fa44fff690 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/melting_frozen_horror.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/melting_frozen_horror.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", + "MeltingDeath", +} + monster.health = 70000 monster.maxHealth = 70000 monster.race = "undead" @@ -57,10 +62,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "MeltingDeath", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/mounted_thorn_knight.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/mounted_thorn_knight.lua index 05e436339b9..f46efa303a8 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/mounted_thorn_knight.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/mounted_thorn_knight.lua @@ -38,7 +38,7 @@ monster.flags = { hostile = true, convinceable = false, pushable = false, - rewardBoss = true, + rewardBoss = false, illusionable = false, canPushItems = true, canPushCreatures = true, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/soul_of_dragonking_zyrtarch.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/soul_of_dragonking_zyrtarch.lua index 030838fa5d5..2def55d9283 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/soul_of_dragonking_zyrtarch.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/soul_of_dragonking_zyrtarch.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", +} + monster.bosstiary = { bossRaceId = 1289, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_blazing_time_guardian.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_blazing_time_guardian.lua index 736c3233d4e..dd4144c4aad 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_blazing_time_guardian.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_blazing_time_guardian.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", +} + monster.health = 150000 monster.maxHealth = 150000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_enraged_thorn_knight.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_enraged_thorn_knight.lua index 6e74ec8281e..38d27e009af 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_enraged_thorn_knight.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_enraged_thorn_knight.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", + "HealthForgotten", +} + monster.bosstiary = { bossRaceId = 1297, bossRace = RARITY_ARCHFOE, @@ -57,10 +62,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "HealthForgotten", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_freezing_time_guardian.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_freezing_time_guardian.lua index e43d501838b..ec4aac0f9fa 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_freezing_time_guardian.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_freezing_time_guardian.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", +} + monster.health = 150000 monster.maxHealth = 150000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_last_lore_keeper.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_last_lore_keeper.lua index 893cade4723..a875379d558 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_last_lore_keeper.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_last_lore_keeper.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", +} + monster.health = 750000 monster.maxHealth = 750000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_shielded_thorn_knight.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_shielded_thorn_knight.lua index 15adaa5ef7f..f3539476809 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_shielded_thorn_knight.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_shielded_thorn_knight.lua @@ -38,7 +38,7 @@ monster.flags = { hostile = true, convinceable = false, pushable = false, - rewardBoss = true, + rewardBoss = false, illusionable = false, canPushItems = true, canPushCreatures = true, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_time_guardian.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_time_guardian.lua index 86d45d2d7ff..53d7eee517a 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_time_guardian.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bosses/the_time_guardian.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ForgottenKnowledgeBossDeath", +} + monster.health = 150000 monster.maxHealth = 150000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/bound_astral_power.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/bound_astral_power.lua index f012b1c1185..42be68d8ebe 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/bound_astral_power.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/bound_astral_power.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "BoundAstralPowerDeath", +} + monster.health = 70000 monster.maxHealth = 70000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_a.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_a.lua index c85eda464fe..7dde9b15691 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_a.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_a.lua @@ -14,6 +14,11 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "EnergyPrismDeath", + "EnergyPrismHealthChange", +} + monster.changeTarget = { interval = 2000, chance = 0, @@ -43,10 +48,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "EnergyPrism", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_b.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_b.lua index eb90930545e..cfd5dd674a3 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_b.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_b.lua @@ -14,6 +14,11 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "EnergyPrismHealthChange", + "EnergyPrismDeath", +} + monster.changeTarget = { interval = 2000, chance = 0, @@ -43,10 +48,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "EnergyPrism", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_c.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_c.lua index b8de11033d7..92045bac1b9 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_c.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_c.lua @@ -44,7 +44,7 @@ monster.flags = { } monster.events = { - "EnergyPrism", + "EnergyPrismHealthChange", } monster.light = { diff --git a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_d.lua b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_d.lua index cf53e32a384..ec58b3ead68 100644 --- a/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_d.lua +++ b/data-otservbr-global/monster/quests/forgotten_knowledge/cosmic_energy_prism_d.lua @@ -14,6 +14,11 @@ monster.corpse = 0 monster.speed = 0 monster.manaCost = 0 +monster.events = { + "EnergyPrismHealthChange", + "EnergyPrismDeath", +} + monster.changeTarget = { interval = 2000, chance = 0, @@ -43,10 +48,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "EnergyPrism", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/grave_danger/bosses/count_vlarkorth.lua b/data-otservbr-global/monster/quests/grave_danger/bosses/count_vlarkorth.lua index 929bd2f90b6..ebe04c8ec92 100644 --- a/data-otservbr-global/monster/quests/grave_danger/bosses/count_vlarkorth.lua +++ b/data-otservbr-global/monster/quests/grave_danger/bosses/count_vlarkorth.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GraveDangerBossDeath", +} + monster.health = 75000 monster.maxHealth = 75000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/grave_danger/bosses/duke_krule.lua b/data-otservbr-global/monster/quests/grave_danger/bosses/duke_krule.lua index 121f09f2d4b..0760491d1bc 100644 --- a/data-otservbr-global/monster/quests/grave_danger/bosses/duke_krule.lua +++ b/data-otservbr-global/monster/quests/grave_danger/bosses/duke_krule.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GraveDangerBossDeath", +} + monster.health = 75000 monster.maxHealth = 75000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/grave_danger/bosses/earl_osam.lua b/data-otservbr-global/monster/quests/grave_danger/bosses/earl_osam.lua index ccc260d201e..c996116a336 100644 --- a/data-otservbr-global/monster/quests/grave_danger/bosses/earl_osam.lua +++ b/data-otservbr-global/monster/quests/grave_danger/bosses/earl_osam.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GraveDangerBossDeath", +} + monster.health = 75000 monster.maxHealth = 75000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/grave_danger/bosses/king_zelos.lua b/data-otservbr-global/monster/quests/grave_danger/bosses/king_zelos.lua index 7b3adde7c04..0201e821448 100644 --- a/data-otservbr-global/monster/quests/grave_danger/bosses/king_zelos.lua +++ b/data-otservbr-global/monster/quests/grave_danger/bosses/king_zelos.lua @@ -14,6 +14,7 @@ monster.outfit = { } monster.events = { + "GraveDangerBossDeath", "zelosDeath", } diff --git a/data-otservbr-global/monster/quests/grave_danger/bosses/lord_azaram.lua b/data-otservbr-global/monster/quests/grave_danger/bosses/lord_azaram.lua index 8e47689c9e5..701a0b6f92b 100644 --- a/data-otservbr-global/monster/quests/grave_danger/bosses/lord_azaram.lua +++ b/data-otservbr-global/monster/quests/grave_danger/bosses/lord_azaram.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GraveDangerBossDeath", +} + monster.health = 75000 monster.maxHealth = 75000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/grave_danger/bosses/sir_baeloc.lua b/data-otservbr-global/monster/quests/grave_danger/bosses/sir_baeloc.lua index d9a43a7dc01..042ce32e981 100644 --- a/data-otservbr-global/monster/quests/grave_danger/bosses/sir_baeloc.lua +++ b/data-otservbr-global/monster/quests/grave_danger/bosses/sir_baeloc.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "GraveDangerBossDeath", +} + monster.health = 75000 monster.maxHealth = 75000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/hero_of_rathleton/deep_terror.lua b/data-otservbr-global/monster/quests/hero_of_rathleton/deep_terror.lua index d5715452efa..534175a881a 100644 --- a/data-otservbr-global/monster/quests/hero_of_rathleton/deep_terror.lua +++ b/data-otservbr-global/monster/quests/hero_of_rathleton/deep_terror.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RathletonBossDeath", +} + monster.bosstiary = { bossRaceId = 1087, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/hero_of_rathleton/empowered_glooth_horror.lua b/data-otservbr-global/monster/quests/hero_of_rathleton/empowered_glooth_horror.lua index 8f3e9d0e482..b99cd1f87d7 100644 --- a/data-otservbr-global/monster/quests/hero_of_rathleton/empowered_glooth_horror.lua +++ b/data-otservbr-global/monster/quests/hero_of_rathleton/empowered_glooth_horror.lua @@ -13,6 +13,11 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RathletonBossDeath", + "GloothHorror", +} + monster.health = 25000 monster.maxHealth = 25000 monster.race = "venom" @@ -52,10 +57,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "GloothHorror", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/hero_of_rathleton/professor_maxxen.lua b/data-otservbr-global/monster/quests/hero_of_rathleton/professor_maxxen.lua index 8bb03ae7631..8a1ec35e913 100644 --- a/data-otservbr-global/monster/quests/hero_of_rathleton/professor_maxxen.lua +++ b/data-otservbr-global/monster/quests/hero_of_rathleton/professor_maxxen.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "RathletonBossDeath", +} + monster.health = 90000 monster.maxHealth = 90000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus.lua b/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus.lua index cd5ad5ae043..87329f07738 100644 --- a/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus.lua +++ b/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AzerusDeath", +} + monster.health = 26000 monster.maxHealth = 26000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus2.lua b/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus2.lua index ef0b7d49807..19f074c17eb 100644 --- a/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus2.lua +++ b/data-otservbr-global/monster/quests/in_service_of_yalahar/azerus2.lua @@ -14,6 +14,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "AzerusDeath", +} + monster.health = 26000 monster.maxHealth = 26000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/in_service_of_yalahar/inky.lua b/data-otservbr-global/monster/quests/in_service_of_yalahar/inky.lua index 7326ed59abc..bcb266254fe 100644 --- a/data-otservbr-global/monster/quests/in_service_of_yalahar/inky.lua +++ b/data-otservbr-global/monster/quests/in_service_of_yalahar/inky.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "QuaraLeadersDeath", +} + monster.health = 750 monster.maxHealth = 750 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/in_service_of_yalahar/sharptooth.lua b/data-otservbr-global/monster/quests/in_service_of_yalahar/sharptooth.lua index d707fc89581..583df08b8b5 100644 --- a/data-otservbr-global/monster/quests/in_service_of_yalahar/sharptooth.lua +++ b/data-otservbr-global/monster/quests/in_service_of_yalahar/sharptooth.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "QuaraLeadersDeath", +} + monster.health = 3100 monster.maxHealth = 3100 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/kilmaresh/an_astral_glyph.lua b/data-otservbr-global/monster/quests/kilmaresh/an_astral_glyph.lua index 5b76352b45d..a9c8792332a 100644 --- a/data-otservbr-global/monster/quests/kilmaresh/an_astral_glyph.lua +++ b/data-otservbr-global/monster/quests/kilmaresh/an_astral_glyph.lua @@ -14,6 +14,11 @@ monster.corpse = 0 monster.speed = 235 monster.manaCost = 0 +monster.events = { + "ForgottenKnowledgeBossDeath", + "AstralGlyphDeath", +} + monster.changeTarget = { interval = 2000, chance = 0, @@ -46,10 +51,6 @@ monster.flags = { canWalkOnPoison = true, } -monster.events = { - "AstralGlyphDeath", -} - monster.light = { level = 0, color = 0, diff --git a/data-otservbr-global/monster/quests/kilmaresh/bragrumol.lua b/data-otservbr-global/monster/quests/kilmaresh/bragrumol.lua index b653df68c89..bb7ef950744 100644 --- a/data-otservbr-global/monster/quests/kilmaresh/bragrumol.lua +++ b/data-otservbr-global/monster/quests/kilmaresh/bragrumol.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "BragrumolDeath", +} + monster.health = 38000 monster.maxHealth = 38000 monster.race = "fire" diff --git a/data-otservbr-global/monster/quests/kilmaresh/mozradek.lua b/data-otservbr-global/monster/quests/kilmaresh/mozradek.lua index 093b8d7ceeb..8602923a08b 100644 --- a/data-otservbr-global/monster/quests/kilmaresh/mozradek.lua +++ b/data-otservbr-global/monster/quests/kilmaresh/mozradek.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "MozradekDeath", +} + monster.bosstiary = { bossRaceId = 1829, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/kilmaresh/xogixath.lua b/data-otservbr-global/monster/quests/kilmaresh/xogixath.lua index 886b7632944..3c77465e1ab 100644 --- a/data-otservbr-global/monster/quests/kilmaresh/xogixath.lua +++ b/data-otservbr-global/monster/quests/kilmaresh/xogixath.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "XogixathDeath", +} + monster.health = 28000 monster.maxHealth = 28000 monster.race = "fire" diff --git a/data-otservbr-global/monster/quests/liquid_black/jaul.lua b/data-otservbr-global/monster/quests/liquid_black/jaul.lua index c9fa8b2c7fe..965bbacb14c 100644 --- a/data-otservbr-global/monster/quests/liquid_black/jaul.lua +++ b/data-otservbr-global/monster/quests/liquid_black/jaul.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DeeplingBossDeath", +} + monster.bosstiary = { bossRaceId = 773, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/liquid_black/obujos.lua b/data-otservbr-global/monster/quests/liquid_black/obujos.lua index b8c84b54c61..1f32fd54f1c 100644 --- a/data-otservbr-global/monster/quests/liquid_black/obujos.lua +++ b/data-otservbr-global/monster/quests/liquid_black/obujos.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DeeplingBossDeath", +} + monster.bosstiary = { bossRaceId = 774, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/liquid_black/tanjis.lua b/data-otservbr-global/monster/quests/liquid_black/tanjis.lua index 4313a4a74ab..586af950be3 100644 --- a/data-otservbr-global/monster/quests/liquid_black/tanjis.lua +++ b/data-otservbr-global/monster/quests/liquid_black/tanjis.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DeeplingBossDeath", +} + monster.bosstiary = { bossRaceId = 775, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/primal_ordeal_quest/magma_bubble.lua b/data-otservbr-global/monster/quests/primal_ordeal_quest/magma_bubble.lua index eb7d9a7aeff..8f3bf7f6166 100644 --- a/data-otservbr-global/monster/quests/primal_ordeal_quest/magma_bubble.lua +++ b/data-otservbr-global/monster/quests/primal_ordeal_quest/magma_bubble.lua @@ -15,6 +15,7 @@ monster.outfit = { monster.events = { "MagmaBubbleDeath", + "ThePrimeOrdealBossDeath", } monster.bosstiary = { diff --git a/data-otservbr-global/monster/quests/primal_ordeal_quest/the_primal_menace.lua b/data-otservbr-global/monster/quests/primal_ordeal_quest/the_primal_menace.lua index c6a7eb46164..b81e83f7af7 100644 --- a/data-otservbr-global/monster/quests/primal_ordeal_quest/the_primal_menace.lua +++ b/data-otservbr-global/monster/quests/primal_ordeal_quest/the_primal_menace.lua @@ -66,6 +66,7 @@ monster.outfit = { monster.events = { "ThePrimalMenaceDeath", + "ThePrimeOrdealBossDeath", } monster.health = 400000 diff --git a/data-otservbr-global/monster/quests/soul_war/goshnars_cruelty.lua b/data-otservbr-global/monster/quests/soul_war/goshnars_cruelty.lua index 502c11e7db8..40957e0bde4 100644 --- a/data-otservbr-global/monster/quests/soul_war/goshnars_cruelty.lua +++ b/data-otservbr-global/monster/quests/soul_war/goshnars_cruelty.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SoulwarsBossDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/soul_war/goshnars_greed.lua b/data-otservbr-global/monster/quests/soul_war/goshnars_greed.lua index 834edccf59f..0c8ddbbac42 100644 --- a/data-otservbr-global/monster/quests/soul_war/goshnars_greed.lua +++ b/data-otservbr-global/monster/quests/soul_war/goshnars_greed.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SoulwarsBossDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/soul_war/goshnars_malice.lua b/data-otservbr-global/monster/quests/soul_war/goshnars_malice.lua index ce6699ea39a..5e79dcccbdd 100644 --- a/data-otservbr-global/monster/quests/soul_war/goshnars_malice.lua +++ b/data-otservbr-global/monster/quests/soul_war/goshnars_malice.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SoulwarsBossDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua b/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua index 1c871919b87..18cfdeacd90 100644 --- a/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua +++ b/data-otservbr-global/monster/quests/soul_war/goshnars_megalomania.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SoulwarsBossDeath", +} + monster.health = 500000 monster.maxHealth = 500000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/soul_war/goshnars_spite.lua b/data-otservbr-global/monster/quests/soul_war/goshnars_spite.lua index f6180e7ff6d..cf46b89a76d 100644 --- a/data-otservbr-global/monster/quests/soul_war/goshnars_spite.lua +++ b/data-otservbr-global/monster/quests/soul_war/goshnars_spite.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SoulwarsBossDeath", +} + monster.health = 300000 monster.maxHealth = 300000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/the_dream_courts/bosses/alptramun.lua b/data-otservbr-global/monster/quests/the_dream_courts/bosses/alptramun.lua index a46b6610aff..76275c2cd0f 100644 --- a/data-otservbr-global/monster/quests/the_dream_courts/bosses/alptramun.lua +++ b/data-otservbr-global/monster/quests/the_dream_courts/bosses/alptramun.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DreamCourtsBossDeath", +} + monster.health = 320000 monster.maxHealth = 320000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/the_dream_courts/bosses/izcandar_the_banished.lua b/data-otservbr-global/monster/quests/the_dream_courts/bosses/izcandar_the_banished.lua index 26b2c837282..9c693024899 100644 --- a/data-otservbr-global/monster/quests/the_dream_courts/bosses/izcandar_the_banished.lua +++ b/data-otservbr-global/monster/quests/the_dream_courts/bosses/izcandar_the_banished.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DreamCourtsBossDeath", +} + monster.bosstiary = { bossRaceId = 1699, bossRace = RARITY_NEMESIS, diff --git a/data-otservbr-global/monster/quests/the_dream_courts/bosses/malofur_mangrinder.lua b/data-otservbr-global/monster/quests/the_dream_courts/bosses/malofur_mangrinder.lua index 4e85ee19d95..2bd63f042be 100644 --- a/data-otservbr-global/monster/quests/the_dream_courts/bosses/malofur_mangrinder.lua +++ b/data-otservbr-global/monster/quests/the_dream_courts/bosses/malofur_mangrinder.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DreamCourtsBossDeath", +} + monster.health = 320000 monster.maxHealth = 320000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/the_dream_courts/bosses/maxxenius.lua b/data-otservbr-global/monster/quests/the_dream_courts/bosses/maxxenius.lua index d5dd3890976..8db50108f56 100644 --- a/data-otservbr-global/monster/quests/the_dream_courts/bosses/maxxenius.lua +++ b/data-otservbr-global/monster/quests/the_dream_courts/bosses/maxxenius.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DreamCourtsBossDeath", +} + monster.health = 320000 monster.maxHealth = 320000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/the_dream_courts/bosses/the_nightmare_beast.lua b/data-otservbr-global/monster/quests/the_dream_courts/bosses/the_nightmare_beast.lua index c8c3f8da275..d0520193aad 100644 --- a/data-otservbr-global/monster/quests/the_dream_courts/bosses/the_nightmare_beast.lua +++ b/data-otservbr-global/monster/quests/the_dream_courts/bosses/the_nightmare_beast.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "DreamCourtsBossDeath", +} + monster.health = 850000 monster.maxHealth = 850000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/the_elemental_spheres/earth_overlord.lua b/data-otservbr-global/monster/quests/the_elemental_spheres/earth_overlord.lua index c651694c21e..33251b292d5 100644 --- a/data-otservbr-global/monster/quests/the_elemental_spheres/earth_overlord.lua +++ b/data-otservbr-global/monster/quests/the_elemental_spheres/earth_overlord.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ElementalOverlordDeath", +} + monster.health = 4000 monster.maxHealth = 4000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/the_elemental_spheres/energy_overlord.lua b/data-otservbr-global/monster/quests/the_elemental_spheres/energy_overlord.lua index 10846df7c35..844a6504d33 100644 --- a/data-otservbr-global/monster/quests/the_elemental_spheres/energy_overlord.lua +++ b/data-otservbr-global/monster/quests/the_elemental_spheres/energy_overlord.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ElementalOverlordDeath", +} + monster.health = 4000 monster.maxHealth = 4000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/the_elemental_spheres/fire_overlord.lua b/data-otservbr-global/monster/quests/the_elemental_spheres/fire_overlord.lua index c3b7d152a96..7364324263d 100644 --- a/data-otservbr-global/monster/quests/the_elemental_spheres/fire_overlord.lua +++ b/data-otservbr-global/monster/quests/the_elemental_spheres/fire_overlord.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ElementalOverlordDeath", +} + monster.health = 4000 monster.maxHealth = 4000 monster.race = "fire" diff --git a/data-otservbr-global/monster/quests/the_elemental_spheres/ice_overlord.lua b/data-otservbr-global/monster/quests/the_elemental_spheres/ice_overlord.lua index 7da731c90ab..9a65a1c8ef2 100644 --- a/data-otservbr-global/monster/quests/the_elemental_spheres/ice_overlord.lua +++ b/data-otservbr-global/monster/quests/the_elemental_spheres/ice_overlord.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ElementalOverlordDeath", +} + monster.health = 4000 monster.maxHealth = 4000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/the_elemental_spheres/lord_of_the_elements.lua b/data-otservbr-global/monster/quests/the_elemental_spheres/lord_of_the_elements.lua index eba6b1c9412..7bdc28f7421 100644 --- a/data-otservbr-global/monster/quests/the_elemental_spheres/lord_of_the_elements.lua +++ b/data-otservbr-global/monster/quests/the_elemental_spheres/lord_of_the_elements.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ElementalOverlordDeath", +} + monster.bosstiary = { bossRaceId = 454, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/the_inquisition/annihilon.lua b/data-otservbr-global/monster/quests/the_inquisition/annihilon.lua index e35249ea832..26013b74ece 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/annihilon.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/annihilon.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.bosstiary = { bossRaceId = 418, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/the_inquisition/eye_of_the_seven.lua b/data-otservbr-global/monster/quests/the_inquisition/eye_of_the_seven.lua index 4a409d1a8ee..492e09217ea 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/eye_of_the_seven.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/eye_of_the_seven.lua @@ -17,7 +17,7 @@ monster.health = 120 monster.maxHealth = 120 monster.race = "venom" monster.corpse = 6036 -monster.speed = 40 +monster.speed = 0 monster.manaCost = 0 monster.changeTarget = { diff --git a/data-otservbr-global/monster/quests/the_inquisition/golgordan.lua b/data-otservbr-global/monster/quests/the_inquisition/golgordan.lua index 7da1ca0e093..59a74148ed6 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/golgordan.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/golgordan.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.bosstiary = { bossRaceId = 416, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/the_inquisition/hellgorak.lua b/data-otservbr-global/monster/quests/the_inquisition/hellgorak.lua index 2fcb10ece1f..79209cb8560 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/hellgorak.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/hellgorak.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.bosstiary = { bossRaceId = 403, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/the_inquisition/latrivan.lua b/data-otservbr-global/monster/quests/the_inquisition/latrivan.lua index 9854d2060b4..be2d46288fa 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/latrivan.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/latrivan.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.health = 25000 monster.maxHealth = 25000 monster.race = "fire" diff --git a/data-otservbr-global/monster/quests/the_inquisition/madareth.lua b/data-otservbr-global/monster/quests/the_inquisition/madareth.lua index 344609d71bf..66caf4329f5 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/madareth.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/madareth.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.bosstiary = { bossRaceId = 414, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/the_inquisition/ungreez.lua b/data-otservbr-global/monster/quests/the_inquisition/ungreez.lua index be3f10a6e37..c19b2199920 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/ungreez.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/ungreez.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "UngreezDeath", +} + monster.health = 8200 monster.maxHealth = 8200 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/the_inquisition/ushuriel.lua b/data-otservbr-global/monster/quests/the_inquisition/ushuriel.lua index 25b14bd6298..35c7d81b030 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/ushuriel.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/ushuriel.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.health = 31500 monster.maxHealth = 31500 monster.race = "fire" diff --git a/data-otservbr-global/monster/quests/the_inquisition/zugurosh.lua b/data-otservbr-global/monster/quests/the_inquisition/zugurosh.lua index 796346d7a31..fedf47e5fe1 100644 --- a/data-otservbr-global/monster/quests/the_inquisition/zugurosh.lua +++ b/data-otservbr-global/monster/quests/the_inquisition/zugurosh.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "InquisitionBossDeath", +} + monster.bosstiary = { bossRaceId = 434, bossRace = RARITY_BANE, diff --git a/data-otservbr-global/monster/quests/the_new_frontier/shard_of_corruption.lua b/data-otservbr-global/monster/quests/the_new_frontier/shard_of_corruption.lua index a818d413269..c7ba3fa0e02 100644 --- a/data-otservbr-global/monster/quests/the_new_frontier/shard_of_corruption.lua +++ b/data-otservbr-global/monster/quests/the_new_frontier/shard_of_corruption.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ShardOfCorruptionDeath", +} + monster.health = 600 monster.maxHealth = 600 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/the_new_frontier/tirecz.lua b/data-otservbr-global/monster/quests/the_new_frontier/tirecz.lua index 8bd994210c8..42cbd1f2b9f 100644 --- a/data-otservbr-global/monster/quests/the_new_frontier/tirecz.lua +++ b/data-otservbr-global/monster/quests/the_new_frontier/tirecz.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "TireczDeath", +} + monster.health = 25000 monster.maxHealth = 25000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/the_secret_library/bosses/ghulosh.lua b/data-otservbr-global/monster/quests/the_secret_library/bosses/ghulosh.lua index 789d59fc8fd..4324a573ec4 100644 --- a/data-otservbr-global/monster/quests/the_secret_library/bosses/ghulosh.lua +++ b/data-otservbr-global/monster/quests/the_secret_library/bosses/ghulosh.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SecretLibraryBossDeath", +} + monster.bosstiary = { bossRaceId = 1608, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/the_secret_library/bosses/gorzindel.lua b/data-otservbr-global/monster/quests/the_secret_library/bosses/gorzindel.lua index bd05efbfc7c..b00bffd6d60 100644 --- a/data-otservbr-global/monster/quests/the_secret_library/bosses/gorzindel.lua +++ b/data-otservbr-global/monster/quests/the_secret_library/bosses/gorzindel.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SecretLibraryBossDeath", +} + monster.bosstiary = { bossRaceId = 1591, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/the_secret_library/bosses/the_scourge_of_oblivion.lua b/data-otservbr-global/monster/quests/the_secret_library/bosses/the_scourge_of_oblivion.lua index 9529a00cedb..5965afef0a3 100644 --- a/data-otservbr-global/monster/quests/the_secret_library/bosses/the_scourge_of_oblivion.lua +++ b/data-otservbr-global/monster/quests/the_secret_library/bosses/the_scourge_of_oblivion.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SecretLibraryBossDeath", +} + monster.bosstiary = { bossRaceId = 1642, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/the_secret_library/lokathmor.lua b/data-otservbr-global/monster/quests/the_secret_library/lokathmor.lua index 47484e5dc22..537b2584d82 100644 --- a/data-otservbr-global/monster/quests/the_secret_library/lokathmor.lua +++ b/data-otservbr-global/monster/quests/the_secret_library/lokathmor.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SecretLibraryBossDeath", +} + monster.bosstiary = { bossRaceId = 1574, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/the_secret_library/mazzinor.lua b/data-otservbr-global/monster/quests/the_secret_library/mazzinor.lua index bbf93c31425..a9be1bc3221 100644 --- a/data-otservbr-global/monster/quests/the_secret_library/mazzinor.lua +++ b/data-otservbr-global/monster/quests/the_secret_library/mazzinor.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "SecretLibraryBossDeath", +} + monster.bosstiary = { bossRaceId = 1605, bossRace = RARITY_ARCHFOE, diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/fury_of_the_emperor.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/fury_of_the_emperor.lua index 463d57908da..46f365304c3 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/fury_of_the_emperor.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/fury_of_the_emperor.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WrathOfTheEmperorBossDeath", +} + monster.health = 51000 monster.maxHealth = 51000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/lizard_abomination.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/lizard_abomination.lua index eab957f402d..9b0e18c6cc3 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/lizard_abomination.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/lizard_abomination.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ZalamonDeath", +} + monster.health = 95000 monster.maxHealth = 95000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/mutated_zalamon.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/mutated_zalamon.lua index ad7c98a1abe..39aa68ae966 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/mutated_zalamon.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/mutated_zalamon.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ZalamonDeath", +} + monster.health = 155000 monster.maxHealth = 155000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/scorn_of_the_emperor.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/scorn_of_the_emperor.lua index bbb474fa652..7b0b97c6354 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/scorn_of_the_emperor.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/scorn_of_the_emperor.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WrathOfTheEmperorBossDeath", +} + monster.health = 45000 monster.maxHealth = 45000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_god_essence.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_god_essence.lua index 9d7e4f4fbaa..8479eeba806 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_god_essence.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_god_essence.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ZalamonDeath", +} + monster.health = 65000 monster.maxHealth = 65000 monster.race = "blood" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_thing.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_thing.lua index 272ef668f54..0085b08ca09 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_thing.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/snake_thing.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ZalamonDeath", +} + monster.health = 70000 monster.maxHealth = 70000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/spite_of_the_emperor.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/spite_of_the_emperor.lua index f0951ea2dbc..2ab41632582 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/spite_of_the_emperor.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/spite_of_the_emperor.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WrathOfTheEmperorBossDeath", +} + monster.health = 48000 monster.maxHealth = 48000 monster.race = "undead" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/the_keeper.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/the_keeper.lua index 43d731d6bdd..3062b6f2f5e 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/the_keeper.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/the_keeper.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "TheKeeperDeath", +} + monster.health = 40000 monster.maxHealth = 40000 monster.race = "venom" diff --git a/data-otservbr-global/monster/quests/wrath_of_the_emperor/wrath_of_the_emperor.lua b/data-otservbr-global/monster/quests/wrath_of_the_emperor/wrath_of_the_emperor.lua index 70494aee5f9..99ad2361003 100644 --- a/data-otservbr-global/monster/quests/wrath_of_the_emperor/wrath_of_the_emperor.lua +++ b/data-otservbr-global/monster/quests/wrath_of_the_emperor/wrath_of_the_emperor.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WrathOfTheEmperorBossDeath", +} + monster.health = 55000 monster.maxHealth = 55000 monster.race = "undead" diff --git a/data-otservbr-global/monster/reptiles/lizard_magistratus.lua b/data-otservbr-global/monster/reptiles/lizard_magistratus.lua index 410adcacc4b..cce60cb8d2d 100644 --- a/data-otservbr-global/monster/reptiles/lizard_magistratus.lua +++ b/data-otservbr-global/monster/reptiles/lizard_magistratus.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "LizardMagistratusDeath", +} + monster.raceId = 655 monster.Bestiary = { class = "Reptile", diff --git a/data-otservbr-global/monster/reptiles/lizard_noble.lua b/data-otservbr-global/monster/reptiles/lizard_noble.lua index 18847211c0a..1dcfe3d2873 100644 --- a/data-otservbr-global/monster/reptiles/lizard_noble.lua +++ b/data-otservbr-global/monster/reptiles/lizard_noble.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "LizardNobleDeath", +} + monster.raceId = 656 monster.Bestiary = { class = "Reptile", diff --git a/data-otservbr-global/monster/undeads/demon_skeleton.lua b/data-otservbr-global/monster/undeads/demon_skeleton.lua index 7e133b866cc..c40806e299b 100644 --- a/data-otservbr-global/monster/undeads/demon_skeleton.lua +++ b/data-otservbr-global/monster/undeads/demon_skeleton.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "UpperSpikeDeath", +} + monster.raceId = 37 monster.Bestiary = { class = "Undead", diff --git a/data-otservbr-global/monster/vermins/deepworm.lua b/data-otservbr-global/monster/vermins/deepworm.lua index 1127359392b..91b2ded8752 100644 --- a/data-otservbr-global/monster/vermins/deepworm.lua +++ b/data-otservbr-global/monster/vermins/deepworm.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WarzoneWormDeath", +} + monster.raceId = 1531 monster.Bestiary = { class = "Vermin", diff --git a/data-otservbr-global/monster/vermins/diremaw.lua b/data-otservbr-global/monster/vermins/diremaw.lua index 530c3203922..1e3accb0fd3 100644 --- a/data-otservbr-global/monster/vermins/diremaw.lua +++ b/data-otservbr-global/monster/vermins/diremaw.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WarzoneWormDeath", +} + monster.raceId = 1532 monster.Bestiary = { class = "Vermin", diff --git a/data-otservbr-global/monster/vermins/drillworm.lua b/data-otservbr-global/monster/vermins/drillworm.lua index f1ae51b1df4..3cf92fce18a 100644 --- a/data-otservbr-global/monster/vermins/drillworm.lua +++ b/data-otservbr-global/monster/vermins/drillworm.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "LowerSpikeDeath", +} + monster.raceId = 878 monster.Bestiary = { class = "Vermin", diff --git a/data-otservbr-global/monster/vermins/parasite.lua b/data-otservbr-global/monster/vermins/parasite.lua index da981020291..65e83dbb7f2 100644 --- a/data-otservbr-global/monster/vermins/parasite.lua +++ b/data-otservbr-global/monster/vermins/parasite.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "ParasiteDeath", +} + monster.health = 550 monster.maxHealth = 550 monster.race = "venom" diff --git a/data-otservbr-global/monster/vermins/wiggler.lua b/data-otservbr-global/monster/vermins/wiggler.lua index 3c438edb4bc..76c994cdff5 100644 --- a/data-otservbr-global/monster/vermins/wiggler.lua +++ b/data-otservbr-global/monster/vermins/wiggler.lua @@ -13,6 +13,10 @@ monster.outfit = { lookMount = 0, } +monster.events = { + "WigglerDeath", +} + monster.raceId = 899 monster.Bestiary = { class = "Vermin", diff --git a/data-otservbr-global/npc/battlemart.lua b/data-otservbr-global/npc/battlemart.lua index ec668947aa9..2461fc91129 100644 --- a/data-otservbr-global/npc/battlemart.lua +++ b/data-otservbr-global/npc/battlemart.lua @@ -7,7 +7,7 @@ npcConfig.description = internalNpcName npcConfig.health = 100 npcConfig.maxHealth = npcConfig.health -npcConfig.walkInterval = 0 +npcConfig.walkInterval = 2000 npcConfig.walkRadius = 2 npcConfig.outfit = { diff --git a/data-otservbr-global/npc/imbuement_assistant.lua b/data-otservbr-global/npc/imbuement_assistant.lua index a4f1228ecd6..38cf813408e 100644 --- a/data-otservbr-global/npc/imbuement_assistant.lua +++ b/data-otservbr-global/npc/imbuement_assistant.lua @@ -106,18 +106,18 @@ local imbuementPackagesData = { text = "skill club", moneyRequired = 6250, itemList = { - { itemId = 9657, count = 20 }, - { itemId = 22189, count = 15 }, - { itemId = 10405, count = 10 }, + { itemId = 9657, count = 20 }, -- cyclops toe + { itemId = 22189, count = 15 }, -- ogre nose ring + { itemId = 10405, count = 10 }, -- warmaster's wristguards }, }, ["blockade"] = { text = "skill shield", moneyRequired = 16150, itemList = { - { itemId = 9641, count = 20 }, - { itemId = 11703, count = 25 }, - { itemId = 20199, count = 25 }, + { itemId = 9641, count = 20 }, -- piece of scarab shell + { itemId = 11703, count = 25 }, -- brimstone shell + { itemId = 20199, count = 25 }, -- frazzle skin }, }, ["chop"] = { @@ -333,7 +333,8 @@ local function creatureSayCallback(npc, creature, type, message) return false end - local imbuementPackages = "Available imbuement packages: {bash}, {blockade}, {chop}, {epiphany}, {precision}, {slash}. additional attributes: {featherweight}, {strike}, {swiftness}, {vampirism}, {vibrancy}, {void}. elemental damage: {electrify}, {frost}, {reap}, {scorch}, {venom}. elemental protection: {cloud fabric}, {demon presence}, {dragon hide}, {lich shroud}, {quara scale}, {snake skin}." + local imbuementPackages = + "These are the available imbuement packages, Skill increase: {bash}, {blockade}, {chop}, {epiphany}, {precision}, {slash}. Additional attributes: {featherweight}, {strike}, {swiftness}, {vampirism}, {vibrancy}, {void}. Elemental damage: {electrify}, {frost}, {reap}, {scorch}, {venom}. Elemental protection: {cloud fabric}, {demon presence}, {dragon hide}, {lich shroud}, {quara scale}, {snake skin}." if MsgContains(message, "imbuement packages") then npcHandler:setTopic(playerId, 1) npcHandler:say(imbuementPackages, npc, creature) diff --git a/data-otservbr-global/npc/lokur.lua b/data-otservbr-global/npc/lokur.lua index 0da622e8ba8..62fb5a50864 100644 --- a/data-otservbr-global/npc/lokur.lua +++ b/data-otservbr-global/npc/lokur.lua @@ -63,6 +63,13 @@ local function creatureSayCallback(npc, creature, type, message) return false end + -- Parse bank + npc:parseBank(message, npc, creature, npcHandler) + -- Parse guild bank + npc:parseGuildBank(message, npc, creature, playerId, npcHandler) + -- Normal messages + npc:parseBankMessages(message, npc, creature, npcHandler) + if MsgContains(message, "ticket") then if Player(creature):getStorageValue(Storage.WagonTicket) >= os.time() then npcHandler:say("Your weekly ticket is still valid. Would be a waste of money to purchase a second one", npc, creature) @@ -89,12 +96,6 @@ local function creatureSayCallback(npc, creature, type, message) npcHandler:setTopic(playerId, 0) end - -- Parse bank - npc:parseBank(message, npc, creature, npcHandler) - -- Parse guild bank - npc:parseGuildBank(message, npc, creature, playerId, npcHandler) - -- Normal messages - npc:parseBankMessages(message, npc, creature, npcHandler) return true end diff --git a/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua b/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua index ca95fa99bc9..68a348fc08f 100644 --- a/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua +++ b/data-otservbr-global/scripts/actions/quests/dangerous_depth/using_crystals.lua @@ -370,10 +370,7 @@ end local function startWarzoneIV() addEvent(function() - local monstro = Game.createMonster("The Baron From Below", Position(33648, 32303, 15)) - if monstro then - monstro:registerEvent("TheBaronFromBelowThink") - end + Game.createMonster("The Baron From Below", Position(33648, 32303, 15)) addEvent(sumonarLavasIV, 15 * 1000, 5) addEvent(lavaHoles, 15 * 1000, 1) end, 10 * 1000) diff --git a/data-otservbr-global/scripts/actions/quests/feaster_of_souls/bosses_killed.lua b/data-otservbr-global/scripts/actions/quests/feaster_of_souls/bosses_killed.lua index b77304f5627..5d021a9659d 100644 --- a/data-otservbr-global/scripts/actions/quests/feaster_of_souls/bosses_killed.lua +++ b/data-otservbr-global/scripts/actions/quests/feaster_of_souls/bosses_killed.lua @@ -5,24 +5,17 @@ local bosses = { ["the pale worm"] = { storage = Storage.Quest.U12_30.FeasterOfSouls.PaleWormKilled }, } -local bossesFeasterOfSouls = CreatureEvent("FeasterOfSoulsKill") -function bossesFeasterOfSouls.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesFeasterOfSouls = CreatureEvent("FeasterOfSoulsBossDeath") +function bossesFeasterOfSouls.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for key, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(key) - if attackerPlayer then - if bossConfig.storage then - attackerPlayer:setStorageValue(bossConfig.storage, 1) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if bossConfig.storage then + player:setStorageValue(bossConfig.storage, 1) end - end + end) return true end diff --git a/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/thorn_knight_lever.lua b/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/thorn_knight_lever.lua index 2a7811d3423..c62514fbaf3 100644 --- a/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/thorn_knight_lever.lua +++ b/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/thorn_knight_lever.lua @@ -68,7 +68,7 @@ function forgottenKnowledgeThorn.onUse(player, item, fromPosition, target, toPos return true end lever:teleportPlayers() - lever:setCooldownAllPlayers(config.bossName, os.time() + config.timeToFightAgain * 3600) + lever:setCooldownAllPlayers("The Enraged Thorn Knight", os.time() + config.timeToFightAgain * 3600) addEvent(function() local old_players = lever:getInfoPositions() spec:clearCreaturesCache() diff --git a/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/time_guardian_lever.lua b/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/time_guardian_lever.lua index f4d42e52c45..832e42e2c6c 100644 --- a/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/time_guardian_lever.lua +++ b/data-otservbr-global/scripts/actions/quests/forgotten_knowledge/time_guardian_lever.lua @@ -14,12 +14,6 @@ local config = { { bossPosition = Position(32975, 31664, 13), bossName = "The Freezing Time Guardian" }, { bossPosition = Position(32980, 31664, 13), bossName = "The Blazing Time Guardian" }, }, - monsters = { - { cosmic = "cosmic energy prism a invu", pos = Position(32801, 32827, 14) }, - { cosmic = "cosmic energy prism b invu", pos = Position(32798, 32827, 14) }, - { cosmic = "cosmic energy prism c invu", pos = Position(32803, 32826, 14) }, - { cosmic = "cosmic energy prism d invu", pos = Position(32796, 32826, 14) }, - }, specPos = { from = Position(32967, 31654, 13), to = Position(32989, 31677, 14), diff --git a/data-otservbr-global/scripts/actions/quests/grave_danger/bosses_killed.lua b/data-otservbr-global/scripts/actions/quests/grave_danger/bosses_killed.lua index 60716e7ab6b..8b1ed5b2c89 100644 --- a/data-otservbr-global/scripts/actions/quests/grave_danger/bosses_killed.lua +++ b/data-otservbr-global/scripts/actions/quests/grave_danger/bosses_killed.lua @@ -7,33 +7,26 @@ local bosses = { ["king zelos"] = { storage = Storage.Quest.U12_20.GraveDanger.Bosses.KingZelosKilled }, } -local bossesGraveDanger = CreatureEvent("GraveDangerKill") -function bossesGraveDanger.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesGraveDanger = CreatureEvent("GraveDangerBossDeath") +function bossesGraveDanger.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for key, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(key) - if attackerPlayer then - if bossConfig.storage then - attackerPlayer:setStorageValue(bossConfig.storage, 1) + onDeathForDamagingPlayers(creature, function(creature, player) + if bossConfig.storage then + player:setStorageValue(bossConfig.storage, 1) + end + local bossesKilled = 0 + for value in pairs(bosses) do + if player:getStorageValue(bosses[value].storage) > 0 then + bossesKilled = bossesKilled + 1 end end - end - local bossesKilled = 0 - for value in pairs(bosses) do - if creature:getStorageValue(bosses[value].storage) > 0 then - bossesKilled = bossesKilled + 1 + if bossesKilled >= 5 then -- number of mini bosses + player:setStorageValue(Storage.Quest.U12_20.GraveDanger.Bosses.KingZelosDoor, 1) end - end - if bossesKilled >= 5 then -- number of mini bosses - creature:setStorageValue(Storage.Quest.U12_20.GraveDanger.Bosses.KingZelosDoor, 1) - end + end) return true end diff --git a/data-otservbr-global/scripts/actions/quests/secret_library/bosses_killed.lua b/data-otservbr-global/scripts/actions/quests/secret_library/bosses_killed.lua index a825983987c..a62b922469e 100644 --- a/data-otservbr-global/scripts/actions/quests/secret_library/bosses_killed.lua +++ b/data-otservbr-global/scripts/actions/quests/secret_library/bosses_killed.lua @@ -6,33 +6,26 @@ local bosses = { ["scourge of oblivion"] = { storage = Storage.Quest.U11_80.TheSecretLibrary.ScourgeOfOblivionKilled }, } -local bossesSecretLibrary = CreatureEvent("SecretLibraryKill") -function bossesSecretLibrary.onKill(player, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesSecretLibrary = CreatureEvent("SecretLibraryBossDeath") +function bossesSecretLibrary.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for key, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(key) - if attackerPlayer then - if bossConfig.storage then - attackerPlayer:setStorageValue(bossConfig.storage, 1) + onDeathForDamagingPlayers(creature, function(creature, player) + if bossConfig.storage then + player:setStorageValue(bossConfig.storage, 1) + end + local bossesKilled = 0 + for value in pairs(bosses) do + if player:getStorageValue(bosses[value].storage) > 0 then + bossesKilled = bossesKilled + 1 end end - end - local bossesKilled = 0 - for value in pairs(bosses) do - if player:getStorageValue(bosses[value].storage) > 0 then - bossesKilled = bossesKilled + 1 + if bossesKilled >= 4 then -- number of mini bosses + player:setStorageValue(Storage.Quest.U11_80.TheSecretLibrary.ScourgeOfOblivionDoor, 1) end - end - if bossesKilled >= 4 then -- number of mini bosses - player:setStorageValue(Storage.Quest.U11_80.TheSecretLibrary.ScourgeOfOblivionDoor, 1) - end + end) return true end diff --git a/data-otservbr-global/scripts/actions/quests/soul_war/bosses_killed.lua b/data-otservbr-global/scripts/actions/quests/soul_war/bosses_killed.lua index 06aeff3c652..de4b8ae182f 100644 --- a/data-otservbr-global/scripts/actions/quests/soul_war/bosses_killed.lua +++ b/data-otservbr-global/scripts/actions/quests/soul_war/bosses_killed.lua @@ -7,24 +7,17 @@ local bosses = { ["goshnar's megalomania"] = { storage = Storage.Quest.U12_40.SoulWar.GoshnarMegalomaniaKilled }, } -local bossesSoulWar = CreatureEvent("SoulWarKill") -function bossesSoulWar.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesSoulWar = CreatureEvent("SoulwarsBossDeath") +function bossesSoulWar.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for key, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(key) - if attackerPlayer then - if bossConfig.storage then - attackerPlayer:setStorageValue(bossConfig.storage, 1) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if bossConfig.storage then + player:setStorageValue(bossConfig.storage, 1) end - end + end) return true end diff --git a/data-otservbr-global/scripts/actions/quests/the_dream_courts/bosses_killed.lua b/data-otservbr-global/scripts/actions/quests/the_dream_courts/bosses_killed.lua index cd6eb327972..ebbff0713ef 100644 --- a/data-otservbr-global/scripts/actions/quests/the_dream_courts/bosses_killed.lua +++ b/data-otservbr-global/scripts/actions/quests/the_dream_courts/bosses_killed.lua @@ -7,24 +7,17 @@ local bosses = { ["the nightmare beast"] = { storage = Storage.Quest.U12_00.TheDreamCourts.NightmareBeastKilled }, } -local bossesDreamCourts = CreatureEvent("DreamCourtsKill") -function bossesDreamCourts.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesDreamCourts = CreatureEvent("DreamCourtsBossDeath") +function bossesDreamCourts.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for key, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(key) - if attackerPlayer then - if bossConfig.storage then - attackerPlayer:setStorageValue(bossConfig.storage, 1) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if bossConfig.storage then + player:setStorageValue(bossConfig.storage, 1) end - end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/monster/lower_roshamuul.lua b/data-otservbr-global/scripts/creaturescripts/monster/lower_roshamuul.lua index c27c83a21b1..a7a6ef8f1f0 100644 --- a/data-otservbr-global/scripts/creaturescripts/monster/lower_roshamuul.lua +++ b/data-otservbr-global/scripts/creaturescripts/monster/lower_roshamuul.lua @@ -1,14 +1,18 @@ local setting = { - ["frazzlemaw"] = roshamuul_killed_frazzlemaws, + ["frazzlemaw"] = ROSHAMUUL_KILLED_FRAZZLEMAWS, ["silencer"] = ROSHAMUUL_KILLED_SILENCERS, } -local lowerRoshamuul = CreatureEvent("LowerRoshamuul") -function lowerRoshamuul.onKill(creature, target) - local monster = setting[target:getName():lower()] - if monster then - creature:setStorageValue(monster, math.max(0, creature:getStorageValue(monster)) + 1) +local lowerRoshamuul = CreatureEvent("RoshamuulKillsDeath") +function lowerRoshamuul.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local monster = setting[creature:getName():lower()] + if not monster then + return true end + + onDeathForParty(creature, mostDamageKiller, function(creature, player) + player:setStorageValue(monster, math.max(0, player:getStorageValue(monster)) + 1) + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/others/login_events.lua b/data-otservbr-global/scripts/creaturescripts/others/login_events.lua index f61182bea3f..7adef4c07a1 100644 --- a/data-otservbr-global/scripts/creaturescripts/others/login_events.lua +++ b/data-otservbr-global/scripts/creaturescripts/others/login_events.lua @@ -1,12 +1,8 @@ local loginEvents = CreatureEvent("LoginEvents") function loginEvents.onLogin(player) local events = { - --Monster - "LowerRoshamuul", --Others "AdvanceSave", - "BestiaryOnKill", - "BosstiaryOnKill", "BossParticipation", "DropLoot", "PlayerDeath", @@ -14,114 +10,10 @@ function loginEvents.onLogin(player) "FamiliarLogin", "FamiliarAdvance", --Quests - --Adventurers Guild Quest - "Thegreatdragonhuntkill", - --Bigfoot Burden Quest - "BossesWarzone", - "ParasiteWarzone", - "VersperothKill", - "WigglerKill", --Cults Of Tibia Quest - "BossesCults", - "MinotaurTask", - "VortexCarlin", "LeidenHeal", - "GlowingRubbishAmulet", - "DestroyedPillar", "HealthPillar", "YalahariHealth", - "EssenceOfMalice", - --Dangerous Depths Quest - "LostExileKill", - "SnailSlimeKill", - "TheBaronFromBelowKill", - --Dawnport Quest - "MorrisMinotaurKill", - "MorrisGoblinKill", - "MorrisTrollKill", - --Elemental Spheres Quest - "OverlordKill", - --Ferumbras Ascendant Quest - "AscendantBossesKill", - "TheShattererKill", - --Firewalker Boots - "PythiusTheRottenKill", - --Forgotten Knowledge Quest - "BossesForgottenKill", - "AstralPower", - "EnergyPrismDeath", - "ReplicaServant", - --Hero Of Rathleton - "RathletonBossKill", - --Secret Service - "BlackKnightKill", - --Service Of Yalahar - "DiseasedTrio", - "Azerus", - "QuaraLeaders", - --Inquisition - "InquisitionBossKill", - "UngreezKill", - --Killing In The Name Of - "KillingInTheNameOfKill", - "KillingInTheNameOfMinotaurKill", - "TiquandasRevengeKill", - "DemodrasKill", - --Kilmaresh - "BragrumolKill", - "MozradekKill", - "XogixathKill", - "FafnarKill", - --Liquid Black - "DeeplingBosses", - --Raging Mage Worldchange - "EnergizedRagingMageKill", - "RagingMageKill", - "YielothaxKill", - --Spike Tasks - "LowerSpikeKill", - "UpperSpikeKill", - "MiddleSpikeKill", - --Svargrond Arena - "SvargrondArenaKill", - --The Ice Islands Quest - "HuskyKill", - --The First Dragon - "KillDragon", - "SomewhatBeatableDeath", - --The New Frontier - "ShardOfCorruptionKill", - "TireczKill", - --Thieves Guild - "NomadKill", - --Threatened Dreams - Nightmare Intruders - "ThreatenedDreamsNightmareMonstersKills", - --Wrath of the Emperor - "LizardMagistratusKill", - "LizardNobleKill", - "KeeperKill", - "BossesKill", - "ZalamonKill", - -- The Rookie Guard - "VascalirRatKills", - -- An Uneasy Alliance - "RenegadeOrcKill", - -- Grave Danger - "GraveDangerKill", - -- Feaster of Souls - "FeasterOfSoulsKill", - -- Soul War - "SoulWarKill", - -- Secret Library - "SecretLibraryKill", - -- The Dream Courts - "DreamCourtsKill", - -- Prime Ordeal - "PrimeOrdealKill", - -- Concoctions - "ConcoctionsOnLogin", - -- Hazard System - "PrimalHazardKill", } for i = 1, #events do diff --git a/data-otservbr-global/scripts/creaturescripts/quests/adventurers_guild/the_great_dragon_hunt.lua b/data-otservbr-global/scripts/creaturescripts/quests/adventurers_guild/the_great_dragon_hunt.lua index d4011bbfc8a..75cd6f92366 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/adventurers_guild/the_great_dragon_hunt.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/adventurers_guild/the_great_dragon_hunt.lua @@ -8,24 +8,21 @@ local areas = { { from = Position(32993, 32632, 7), to = Position(33042, 32688, 7) }, } -local adventurersGuildHunt = CreatureEvent("TheGreatDragonHuntKill") -function adventurersGuildHunt.onKill(creature, target) - if not creature or not creature:isPlayer() then - return true +local adventurersGuildHunt = CreatureEvent("TheGreatDragonHuntDeath") +function adventurersGuildHunt.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local valid = false + for _, area in ipairs(areas) do + if creature:getPosition():isInRange(area.from, area.to) then + valid = true + break + end end - - if not target or not target:isMonster() then + if not valid then return true end - - if table.contains({ "dragon lord", "dragon" }, target:getName():lower()) then - for _, area in ipairs(areas) do - if creature:getPosition():isInRange(area.from, area.to) then - creature:setStorageValue(Storage.AdventurersGuild.GreatDragonHunt.DragonCounter, creature:getStorageValue(Storage.AdventurersGuild.GreatDragonHunt.DragonCounter) + 1) - break - end - end - end + onDeathForParty(creature, mostDamageKiller, function(creature, player) + player:setStorageValue(Storage.AdventurersGuild.GreatDragonHunt.DragonCounter, math.max(0, player:getStorageValue(Storage.AdventurersGuild.GreatDragonHunt.DragonCounter)) + 1) + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/an_uneasy_alliance/renegade_orc_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/an_uneasy_alliance/renegade_orc_kill.lua index 90fcb9c5ae0..dbff7a11b45 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/an_uneasy_alliance/renegade_orc_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/an_uneasy_alliance/renegade_orc_kill.lua @@ -1,16 +1,10 @@ -local renegadeOrcKill = CreatureEvent("RenegadeOrcKill") -function renegadeOrcKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - if targetMonster:getName():lower() ~= "renegade orc" then - return true - end - local player = creature:getPlayer() - if player:getStorageValue(Storage.Quest.U8_54.AnUneasyAlliance.QuestDoor) == 0 then - player:setStorageValue(Storage.Quest.U8_54.AnUneasyAlliance.QuestDoor, 1) - end +local renegadeOrcKill = CreatureEvent("RenegadeOrcDeath") +function renegadeOrcKill.onDeath(creature, _corpse, _lastHitKiller, player, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if player:getStorageValue(Storage.Quest.U8_54.AnUneasyAlliance.QuestDoor) == 0 then + player:setStorageValue(Storage.Quest.U8_54.AnUneasyAlliance.QuestDoor, 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/bosses_warzone.lua b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/bosses_warzone.lua index b123a941a37..f526f67b171 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/bosses_warzone.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/bosses_warzone.lua @@ -5,31 +5,24 @@ local bosses = { } -- This will set the status of warzone (killing 1, 2 and 3 wz bosses in order you can open the chest and get "some golden fruits") and the reward chest storages -local bossesWarzone = CreatureEvent("BossesWarzone") -function bossesWarzone.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesWarzone = CreatureEvent("BossesWarzoneDeath") +function bossesWarzone.onDeath(target) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for index, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(index) - if attackerPlayer then - if (attackerPlayer:getStorageValue(Storage.BigfootBurden.WarzoneStatus) + 1) == bossConfig.status then - attackerPlayer:setStorageValue(Storage.BigfootBurden.WarzoneStatus, bossConfig.status) - if bossConfig.status == 4 then - attackerPlayer:setStorageValue(Storage.BigfootBurden.DoorGoldenFruits, 1) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if (player:getStorageValue(Storage.BigfootBurden.WarzoneStatus) + 1) == bossConfig.status then + player:setStorageValue(Storage.BigfootBurden.WarzoneStatus, bossConfig.status) + if bossConfig.status == 4 then + player:setStorageValue(Storage.BigfootBurden.DoorGoldenFruits, 1) end - attackerPlayer:setStorageValue(bossConfig.storage, 1) - attackerPlayer:setStorageValue(Storage.BigfootBurden.BossKills, attackerPlayer:getStorageValue(Storage.BigfootBurden.BossKills) + 1) end - end + player:setStorageValue(bossConfig.storage, 1) + player:setStorageValue(Storage.BigfootBurden.BossKills, player:getStorageValue(Storage.BigfootBurden.BossKills) + 1) + end) + return true end bossesWarzone:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/parasite.lua b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/parasite.lua index 912e6704225..35cd862a602 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/parasite.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/parasite.lua @@ -25,31 +25,21 @@ local function recreateCrystals(c) end end -local parasiteWarzone = CreatureEvent("ParasiteWarzone") -function parasiteWarzone.onKill(player, target) - local targetMonster = target:getMonster() - if not targetMonster then - return false - end - - local targetName = targetMonster:getName():lower() - if targetName ~= "parasite" then - return false - end - - local master = targetMonster:getMaster() +local parasiteWarzone = CreatureEvent("ParasiteDeath") +function parasiteWarzone.onDeath(creature) + local master = creature:getMaster() if not master or master:isPlayer() then return false end - local pos = targetMonster:getPosition() + local pos = creature:getPosition() if pos.x ~= 33097 or pos.y > 31979 or pos.y < 31976 or pos.z ~= 11 then return false end local config = warzoneConfig.findByName("Gnomevil") if config.locked then - targetMonster:say("It seems that someone has already destroyed the walls in the last 30 minutes.", TALKTYPE_MONSTER_SAY) + creature:say("It seems that someone has already destroyed the walls in the last 30 minutes.", TALKTYPE_MONSTER_SAY) return false end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/versperoth_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/versperoth_kill.lua index 4c7df5f6f43..c736981bd4d 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/versperoth_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/versperoth_kill.lua @@ -15,18 +15,9 @@ local function transformTeleport(open) end end -local versperothKill = CreatureEvent("VersperothKill") -function versperothKill.onKill(creature, target) +local versperothKill = CreatureEvent("VersperothDeath") +function versperothKill.onDeath(creature) local config = warzoneConfig.findByName("Abyssador") - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "versperoth" then - return true - end - Game.setStorageValue(GlobalStorage.BigfootBurden.Versperoth.Battle, 2) addEvent(Game.setStorageValue, 30 * 60 * 1000, GlobalStorage.BigfootBurden.Versperoth.Battle, 0) diff --git a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/wiggler_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/wiggler_kill.lua index 72421a59925..41e41ca1e66 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/wiggler_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/bigfoot_burden/wiggler_kill.lua @@ -1,19 +1,11 @@ -local wigglerKill = CreatureEvent("WigglerKill") -function wigglerKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "wiggler" then - return true - end - - local player = creature:getPlayer() - local value = player:getStorageValue(Storage.BigfootBurden.ExterminatedCount) - if value < 10 and player:getStorageValue(Storage.BigfootBurden.MissionExterminators) == 1 then - player:setStorageValue(Storage.BigfootBurden.ExterminatedCount, value + 1) - end +local wigglerKill = CreatureEvent("WigglerDeath") +function wigglerKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local value = player:getStorageValue(Storage.BigfootBurden.ExterminatedCount) + if value < 10 and player:getStorageValue(Storage.BigfootBurden.MissionExterminators) == 1 then + player:setStorageValue(Storage.BigfootBurden.ExterminatedCount, value + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/bosses_mission_cults.lua b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/bosses_mission_cults.lua index a0186fa664d..54e4511eb47 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/bosses_mission_cults.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/bosses_mission_cults.lua @@ -1,16 +1,16 @@ -local bossesCults = CreatureEvent("BossesCults") -function bossesCults.onKill(player, creature) - local bosses = { - ["ravenous hunger"] = { storage = Storage.CultsOfTibia.Barkless.Mission, value = 6 }, - ["the souldespoiler"] = { storage = Storage.CultsOfTibia.Misguided.Mission, value = 4 }, - ["essence of malice"] = { storage = Storage.CultsOfTibia.Humans.Mission, value = 2 }, - ["the unarmored voidborn"] = { storage = Storage.CultsOfTibia.Orcs.Mission, value = 2 }, - ["the false god"] = { storage = Storage.CultsOfTibia.Minotaurs.Mission, value = 4 }, - ["the sandking"] = { storage = Storage.CultsOfTibia.Life.Mission, value = 8, global = "sandking", g_value = 5 }, - ["the corruptor of souls"] = { createNew = "The Source Of Corruption", pos = Position(33039, 31922, 15), removeMonster = "zarcorix of yalahar", area1 = Position(33073, 31885, 15), area2 = Position(33075, 31887, 15) }, - ["the source of corruption"] = { storage = Storage.CultsOfTibia.FinalBoss.Mission, value = 2 }, - } +local bosses = { + ["ravenous hunger"] = { storage = Storage.CultsOfTibia.Barkless.Mission, value = 6 }, + ["the souldespoiler"] = { storage = Storage.CultsOfTibia.Misguided.Mission, value = 4 }, + ["essence of malice"] = { storage = Storage.CultsOfTibia.Humans.Mission, value = 2 }, + ["the unarmored voidborn"] = { storage = Storage.CultsOfTibia.Orcs.Mission, value = 2 }, + ["the false god"] = { storage = Storage.CultsOfTibia.Minotaurs.Mission, value = 4 }, + ["the sandking"] = { storage = Storage.CultsOfTibia.Life.Mission, value = 8, global = "sandking", g_value = 5 }, + ["the corruptor of souls"] = { createNew = "The Source Of Corruption", pos = Position(33039, 31922, 15), removeMonster = "zarcorix of yalahar", area1 = Position(33073, 31885, 15), area2 = Position(33075, 31887, 15) }, + ["the source of corruption"] = { storage = Storage.CultsOfTibia.FinalBoss.Mission, value = 2 }, +} +local bossesCults = CreatureEvent("CultsOfTibiaBossDeath") +function bossesCults.onDeath(creature) if not player:isPlayer() then return true end @@ -21,40 +21,36 @@ function bossesCults.onKill(player, creature) local monsterName = creature:getName():lower() local boss = bosses[monsterName] - if boss then - if boss.global and Game.getStorageValue(boss.global) < boss.g_value then - return true - end - if boss.createNew then - Game.setStorageValue("CheckTile", -1) - Game.createMonster(boss.createNew, boss.pos) - if removeMonster then - for _x = boss.area1.x, boss.area2.x, 1 do - for _y = boss.area1.y, boss.area2.y, 1 do - for _z = boss.area1.z, boss.area2.z, 1 do - if Tile(Position(_x, _y, _z)) then - local monster = Tile(Position(_x, _y, _z)):getTopCreature() - if monster and monster:isMonster() and monster:getName():lower() == string.lower(boss.removeMonster) then - monster:remove() - end + if not boss then + return true + end + if boss.global and Game.getStorageValue(boss.global) < boss.g_value then + return true + end + if boss.createNew then + Game.setStorageValue("CheckTile", -1) + Game.createMonster(boss.createNew, boss.pos) + if removeMonster then + for _x = boss.area1.x, boss.area2.x, 1 do + for _y = boss.area1.y, boss.area2.y, 1 do + for _z = boss.area1.z, boss.area2.z, 1 do + if Tile(Position(_x, _y, _z)) then + local monster = Tile(Position(_x, _y, _z)):getTopCreature() + if monster and monster:isMonster() and monster:getName():lower() == string.lower(boss.removeMonster) then + monster:remove() end end end end end - return true - end - for playerid, damage in pairs(creature:getDamageMap()) do - -- broadcastMessage(playerid.." damage:"..damage.total) - local p = Player(playerid) - if p then - -- broadcastMessage(p:getName()) - if p:getStorageValue(boss.storage) < boss.value then - p:setStorageValue(boss.storage, boss.value) - end - end end + return true end + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(boss.storage) < boss.value then + player:setStorageValue(boss.storage, boss.value) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/carlin_vortex_spawn.lua b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/carlin_vortex_spawn.lua index 9b4037c31e3..43c0b4332f0 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/carlin_vortex_spawn.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/carlin_vortex_spawn.lua @@ -1,24 +1,14 @@ -local vortexCarlin = CreatureEvent("VortexCarlin") -function vortexCarlin.onKill(creature, target, item) - if not creature or not creature:isPlayer() then - return true - end - - if not target or not target:isMonster() then - return true - end - - if table.contains({ "cult enforcer", "cult believer", "cult scholar" }, target:getName():lower()) then - local corpsePosition = target:getPosition() - local rand = math.random(32414, 32415) - Game.createItem(rand, 1, corpsePosition):setActionId(5580) - addEvent(function() - local teleport1 = Tile(corpsePosition):getItemById(rand) - if teleport1 then - teleport1:remove(1) - end - end, (1 * 60 * 1000), rand, 1, corpsePosition) - end +local vortexCarlin = CreatureEvent("CarlinVortexDeath") +function vortexCarlin.onDeath(creature) + local corpsePosition = creature:getPosition() + local rand = math.random(32414, 32415) + Game.createItem(rand, 1, corpsePosition):setActionId(5580) + addEvent(function() + local teleport = Tile(corpsePosition):getItemById(rand) + if teleport then + teleport:remove(1) + end + end, (1 * 60 * 1000), rand, 1, corpsePosition) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/destroyed_pillar.lua b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/destroyed_pillar.lua index 2c2bd08dfc8..a727a877b23 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/destroyed_pillar.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/destroyed_pillar.lua @@ -1,28 +1,21 @@ -local destroyedPillar = CreatureEvent("DestroyedPillar") -function destroyedPillar.onKill(creature, target) - if not creature or not creature:isPlayer() then - return true - end - if not target or not target:isMonster() then - return true - end +local pillar = { + [1] = "pillar of summoning", + [2] = "pillar of death", + [3] = "pillar of protection", + [4] = "pillar of healing", + [5] = "pillar of draining", +} - local pillar = { - [1] = "pillar of summoning", - [2] = "pillar of death", - [3] = "pillar of protection", - [4] = "pillar of healing", - [5] = "pillar of draining", - } - - local monsterName = target:getName():lower() +local destroyedPillar = CreatureEvent("DestroyedPillar") +function destroyedPillar.onDeath(creature) + local monsterName = creature:getName():lower() local summoning = "summoning" local death = "death" local healing = "healing" local protection = "protection" local draining = "draining" for i = 1, #pillar do - local position = target:getPosition() + local position = creature:getPosition() local pilar = "" local newpos = {} pilar = pillar[i] diff --git a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/essence_of_malice.lua b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/essence_of_malice.lua index c107bd7957b..207b64345a6 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/essence_of_malice.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/essence_of_malice.lua @@ -1,6 +1,7 @@ -local essenceOfMalice = CreatureEvent("EssenceOfMalice") -function essenceOfMalice.onKill(creature, target) - local boss = { "eshtaba the conjurer", "mezlon the defiler", "eliz the unyielding", "malkhar deathbringer", "dorokoll the mystic" } +local boss = { "eshtaba the conjurer", "mezlon the defiler", "eliz the unyielding", "malkhar deathbringer", "dorokoll the mystic" } + +local essenceOfMalice = CreatureEvent("EssenceOfMaliceSpawnsDeath") +function essenceOfMalice.onDeath(creature) local newBoss = 0 local fromPos = Position(33087, 31909, 15) local toPos = Position(33112, 31932, 15) @@ -19,7 +20,7 @@ function essenceOfMalice.onKill(creature, target) end end end - if table.contains(boss, target:getName():lower()) and newBoss == 1 then + if table.contains(boss, creature:getName():lower()) and newBoss == 1 then Game.createMonster("Essence Of Malice", Position(33098, 31920, 15)) end return true diff --git a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/glowing_rubbish_amulet.lua b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/glowing_rubbish_amulet.lua index bdedfae09bb..55a16295bb3 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/glowing_rubbish_amulet.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/glowing_rubbish_amulet.lua @@ -1,43 +1,35 @@ -local glowingRubbishAmulet = CreatureEvent("GlowingRubbishAmulet") -function glowingRubbishAmulet.onKill(creature, killed) - local player = Player(creature) - if not player then - return true - end - - local monster = Monster(killed) - if not monster then - return true - end - - local amulet = player:getSlotItem(CONST_SLOT_NECKLACE) - if not amulet or amulet:getId() ~= 25296 then - return true - end +local glowingRubbishAmulet = CreatureEvent("GlowingRubbishAmuletDeath") +function glowingRubbishAmulet.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local amulet = player:getSlotItem(CONST_SLOT_NECKLACE) + if not amulet or amulet:getId() ~= 25296 then + return true + end - if player:getStorageValue(Storage.CultsOfTibia.Misguided.Mission) ~= 3 then - return true - end + if player:getStorageValue(Storage.CultsOfTibia.Misguided.Mission) ~= 3 then + return true + end - local mStg = math.max(player:getStorageValue(Storage.CultsOfTibia.Misguided.Monsters), 0) - local eStg = math.max(player:getStorageValue(Storage.CultsOfTibia.Misguided.Exorcisms), 0) - if monster:getName():lower() == "misguided shadow" then - if eStg < 5 then - player:setStorageValue(Storage.CultsOfTibia.Misguided.Exorcisms, eStg + 1) + local mStg = math.max(player:getStorageValue(Storage.CultsOfTibia.Misguided.Monsters), 0) + local eStg = math.max(player:getStorageValue(Storage.CultsOfTibia.Misguided.Exorcisms), 0) + if monster:getName():lower() == "misguided shadow" then + if eStg < 5 then + player:setStorageValue(Storage.CultsOfTibia.Misguided.Exorcisms, eStg + 1) + end + return true end - return true - end - if monster:getName():lower() == "misguided bully" or monster:getName():lower() == "misguided thief" then - player:setStorageValue(Storage.CultsOfTibia.Misguided.Monsters, mStg + 1) - if player:getStorageValue(Storage.CultsOfTibia.Misguided.Monsters) >= 10 then - amulet:remove() - local it = player:addItem(25297, 1) - if it then - it:decay() + if monster:getName():lower() == "misguided bully" or monster:getName():lower() == "misguided thief" then + player:setStorageValue(Storage.CultsOfTibia.Misguided.Monsters, mStg + 1) + if player:getStorageValue(Storage.CultsOfTibia.Misguided.Monsters) >= 10 then + amulet:remove() + local it = player:addItem(25297, 1) + if it then + it:decay() + end end end - end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/minotaur_task_count.lua b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/minotaur_task_count.lua index 83c5e2000cc..68f3a0f93a1 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/minotaur_task_count.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/cults_of_tibia/minotaur_task_count.lua @@ -1,17 +1,11 @@ -local minotaurTask = CreatureEvent("MinotaurTask") -function minotaurTask.onKill(creature, target) - if not creature or not creature:isPlayer() then - return true - end - - if not target or not target:isMonster() then - return true - end - - local storage = creature:getStorageValue(Storage.CultsOfTibia.Minotaurs.JamesfrancisTask) - if table.contains({ "minotaur cult follower", "minotaur cult zealot", "minotaur cult prophet" }, target:getName():lower()) and storage >= 0 and storage < 50 then - creature:setStorageValue(Storage.CultsOfTibia.Minotaurs.JamesfrancisTask, storage + 1) - end +local minotaurTask = CreatureEvent("MinotaurCultTaskDeath") +function minotaurTask.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local storage = player:getStorageValue(Storage.CultsOfTibia.Minotaurs.JamesfrancisTask) + if storage >= 0 and storage < 50 then + player:setStorageValue(Storage.CultsOfTibia.Minotaurs.JamesfrancisTask, storage + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/bosses_mission_depths.lua b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/bosses_mission_depths.lua index 15d23787b7a..63ffa3c6ffd 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/bosses_mission_depths.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/bosses_mission_depths.lua @@ -1,3 +1,9 @@ +local bosses = { + ["the count of the core"] = { storage = Storage.DangerousDepths.Bosses.TheCountOfTheCore, value = os.time() + configManager.getNumber(configKeys.BOSS_DEFAULT_TIME_TO_FIGHT_AGAIN), teleportPosition = Position(33681, 32340, 15), toPosition = Position(33682, 32315, 15), toPositionBack = Position(33324, 32111, 15) }, + ["the duke of the depths"] = { storage = Storage.DangerousDepths.Bosses.TheDukeOfTheDepths, value = os.time() + configManager.getNumber(configKeys.BOSS_DEFAULT_TIME_TO_FIGHT_AGAIN), teleportPosition = Position(33719, 32302, 15), toPosition = Position(33691, 32301, 15), toPositionBack = Position(33275, 32318, 15) }, + ["the baron from below"] = { storage = Storage.DangerousDepths.Bosses.TheBaronFromBelow, value = os.time() + configManager.getNumber(configKeys.BOSS_DEFAULT_TIME_TO_FIGHT_AGAIN), teleportPosition = Position(33650, 32312, 15), toPosition = Position(33668, 32301, 15), toPositionBack = Position(33462, 32267, 15) }, +} + local function revert(position, toPosition) local teleport = Tile(position):getItemById(22761) if teleport then @@ -6,38 +12,23 @@ local function revert(position, toPosition) end end -local bossesMissionDepth = CreatureEvent("BossesMissionDepth") -function bossesMissionDepth.onKill(creature, creature) - if not creature or not creature:isPlayer() then +local bossesMissionDepth = CreatureEvent("DepthWarzoneBossDeath") +function bossesMissionDepth.onDeath(creature) + local boss = bosses[player:getName():lower()] + if not boss then return true end - - if not target or not target:isMonster() then - return true - end - - local bosses = { - ["the count of the core"] = { stg = Storage.DangerousDepths.Bosses.TheCountOfTheCore, value = os.time() + configManager.getNumber(configKeys.BOSS_DEFAULT_TIME_TO_FIGHT_AGAIN), teleportPosition = Position(33681, 32340, 15), toPosition = Position(33682, 32315, 15), toPositionBack = Position(33324, 32111, 15) }, - ["the duke of the depths"] = { stg = Storage.DangerousDepths.Bosses.TheDukeOfTheDepths, value = os.time() + configManager.getNumber(configKeys.BOSS_DEFAULT_TIME_TO_FIGHT_AGAIN), teleportPosition = Position(33719, 32302, 15), toPosition = Position(33691, 32301, 15), toPositionBack = Position(33275, 32318, 15) }, - ["the baron from below"] = { stg = Storage.DangerousDepths.Bosses.TheBaronFromBelow, value = os.time() + configManager.getNumber(configKeys.BOSS_DEFAULT_TIME_TO_FIGHT_AGAIN), teleportPosition = Position(33650, 32312, 15), toPosition = Position(33668, 32301, 15), toPositionBack = Position(33462, 32267, 15) }, - } - - local boss = bosses[creature:getName():lower()] - if boss then - for playerid, damage in pairs(creature:getDamageMap()) do - local player = Player(playerid) - if player then - if player:getStorageValue(boss.stg) < boss.value then - player:setStorageValue(boss.stg, boss.value) - end - end - end - local teleport = Tile(boss.teleportPosition):getItemById(1949) - if teleport then - teleport:transform(22761) - teleport:setDestination(boss.toPosition) - addEvent(revert, 20 * 60 * 1000, boss.teleportPosition, boss.toPositionBack) + onDeathForDamagingPlayers(creature, function(player, _value) + if player:getStorageValue(boss.storage) < boss.value then + player:setStorageValue(boss.storage, boss.value) end + end) + + local teleport = Tile(boss.teleportPosition):getItemById(1949) + if teleport then + teleport:transform(22761) + teleport:setDestination(boss.toPosition) + addEvent(revert, 20 * 60 * 1000, boss.teleportPosition, boss.toPositionBack) end return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/lost_exile_task.lua b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/lost_exile_task.lua index ce1062785e0..de627fc2229 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/lost_exile_task.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/lost_exile_task.lua @@ -1,44 +1,53 @@ -local lostExileKill = CreatureEvent("LostExileKill") -function lostExileKill.onKill(creature, target) - if not creature or not creature:isPlayer() then - return true - end +local fromPos = Position(33768, 32227, 14) +local toPos = Position(33781, 32249, 14) - if not target or not target:isMonster() then - return true - end +local lostExileKill = CreatureEvent("LastExileDeath") +function lostExileKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if player:getStorageValue(Storage.DangerousDepths.Dwarves.Home) ~= 1 then + return + end + if not creature:getPosition():isInRange(fromPos, toPos) then + return + end + local storage = player:getStorageValue(Storage.DangerousDepths.Dwarves.LostExiles) + if storage < 20 then + if storage < 0 then + player:setStorageValue(Storage.DangerousDepths.Dwarves.LostExiles, 1) + end + player:setStorageValue(Storage.DangerousDepths.Dwarves.LostExiles, storage + 1) + end + end) + return true +end - local fromPos = Position(33768, 32227, 14) - local toPos = Position(33781, 32249, 14) - local monsterName = target:getName():lower() +lostExileKill:register() - local storage = creature:getStorageValue(Storage.DangerousDepths.Dwarves.LostExiles) - local storage2 = creature:getStorageValue(Storage.DangerousDepths.Dwarves.Organisms) - if table.contains({ "lost exile" }, monsterName) then - if creature:getStorageValue(Storage.DangerousDepths.Dwarves.Home) == 1 then - if target:getPosition():isInRange(fromPos, toPos) then - if storage < 20 then - if storage < 0 then - creature:setStorageValue(Storage.DangerousDepths.Dwarves.LostExiles, 1) - end - creature:setStorageValue(Storage.DangerousDepths.Dwarves.LostExiles, storage + 1) - end - end +local wormKill = CreatureEvent("WarzoneWormDeath") +function wormKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local storage = player:getStorageValue(Storage.DangerousDepths.Dwarves.Organisms) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if player:getStorageValue(Storage.DangerousDepths.Dwarves.Subterranean) ~= 1 then + return end - elseif table.contains({ "deepworm", "diremaw" }, monsterName) then - if creature:getStorageValue(Storage.DangerousDepths.Dwarves.Subterranean) == 1 then - if storage2 < 50 then - if storage2 < 0 then - creature:setStorageValue(Storage.DangerousDepths.Dwarves.Organisms, 1) - end - creature:setStorageValue(Storage.DangerousDepths.Dwarves.Organisms, storage2 + 1) + if storage < 50 then + if storage < 0 then + player:setStorageValue(Storage.DangerousDepths.Dwarves.Organisms, 1) end + player:setStorageValue(Storage.DangerousDepths.Dwarves.Organisms, storage + 1) end - elseif table.contains({ "makeshift home" }, monsterName) then - local woodenTrash = Game.createItem(398, 1, target:getPosition()) - woodenTrash:setActionId(57233) - end + end) + return true end -lostExileKill:register() +wormKill:register() + +local makeshiftKill = CreatureEvent("MakeshiftHomeDeath") +function makeshiftKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local woodenTrash = Game.createItem(398, 1, creature:getPosition()) + woodenTrash:setActionId(57233) + return true +end + +makeshiftKill:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/snail_slime_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/snail_slime_kill.lua index c6886b27128..2134758a8e5 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/snail_slime_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/snail_slime_kill.lua @@ -27,20 +27,17 @@ end combat:setCallback(CALLBACK_PARAM_TARGETTILE, "onTargetTile") local function summonSlimes(master) - local contador = 0 + local count = 0 local slimeCheck = Game.getSpectators(master:getPosition(), false, false, 20, 20, 20, 20) for _, slime in pairs(slimeCheck) do if slime:isMonster() then if slime:getName():lower() == "snail slime" then - contador = contador + 1 + count = count + 1 end end end - if contador < 3 then - local summon = Game.createMonster("Snail Slime", master:getPosition(), true) - if summon then - summon:registerEvent("SnailSlimeKill") - end + if count < 3 then + Game.createMonster("Snail Slime", master:getPosition(), true) end end @@ -60,24 +57,11 @@ end snailSlimeThink:register() -local snailSlimeKill = CreatureEvent("SnailSlimeKill") -function snailSlimeKill.onKill(player, creature) - if not player:isPlayer() then - return true - end - if not creature:isMonster() or creature:getMaster() then - return true - end - - local monsterName = creature:getName():lower() - if monsterName == "snail slime" then - if not creature then - return - end - creature:say("!!", TALKTYPE_ORANGE_2) - local var = { type = 1, number = creature:getId() } - combat:execute(creature, var) - end +local snailSlimeKill = CreatureEvent("SnailSlimeDeath") +function snailSlimeKill.onDeath(creature) + creature:say("!!", TALKTYPE_ORANGE_2) + local var = { type = 1, number = creature:getId() } + combat:execute(creature, var) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/the_baron_from_below.lua b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/the_baron_from_below.lua index be3bcca38cd..22963bfb56b 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/the_baron_from_below.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dangerous_depths/the_baron_from_below.lua @@ -9,8 +9,8 @@ local function summonHungry(creature) monster:addHealth(-(monster:getHealth() - oldBossHealth)) monster:teleportTo(Position(33648, 32300, 15)) local organicMatter = Game.createMonster("organic matter", Position(33647, 32300, 15), true, true) - if organicMatter then - organicMatter:registerEvent("OrganicMatterKill") + if not organicMatter then + return false end if monster and monster:getName():lower() == "the hungry baron from below" then monster:addHealth(-(monster:getHealth() - oldBossHealth)) @@ -52,34 +52,18 @@ end local theBaronFromBelowThink = CreatureEvent("TheBaronFromBelowThink") function theBaronFromBelowThink.onThink(creature) - if not creature:isMonster() then - return true - end - - if creature:getName():lower() == "the baron from below" then - if not timers[creature:getId()] then - timers[creature:getId()] = addEvent(summonHungry, 30 * 1000, creature:getId()) - end + if not timers[creature:getId()] then + timers[creature:getId()] = addEvent(summonHungry, 30 * 1000, creature:getId()) end return true end theBaronFromBelowThink:register() -local organicMatterKill = CreatureEvent("OrganicMatterKill") -function organicMatterKill.onKill(player, creature) - if not player:isPlayer() then - return true - end - - if not creature:isMonster() then - return true - end - - if creature:getName():lower() == "organic matter" then - for i = 1, 4 do - Game.createMonster("aggressive matter", creature:getPosition(), true, false) - end +local organicMatterKill = CreatureEvent("OrganicMatterDeath") +function organicMatterKill.onDeath(creature) + for i = 1, 4 do + Game.createMonster("aggressive matter", creature:getPosition(), true, false) end end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_death_priest_shargon.lua b/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_death_priest_shargon.lua index 489c033bc33..1cd88f5243c 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_death_priest_shargon.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_death_priest_shargon.lua @@ -15,23 +15,21 @@ local function removeTeleport(position) end end -local deathPriestShargon = CreatureEvent("ShargonKill") -function deathPriestShargon.onKill(creature, target) - if target:isPlayer() or target:getMaster() or target:getName():lower() ~= "death priest shargon" then - return true - end - - local position = target:getPosition() +local deathPriestShargon = CreatureEvent("ShargonDeath") +function deathPriestShargon.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local position = creature:getPosition() position:sendMagicEffect(CONST_ME_TELEPORT) local item = Game.createItem(config.teleportId, 1, config.teleportPosition) if item:isTeleport() then item:setDestination(config.destinationPosition) end - if config.storageKey ~= nil then - if creature:getStorageValue(config.storageKey) < config.getStorageValue then - creature:setStorageValue(config.storageKey, config.setStorageValue) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if config.storageKey ~= nil then + if player:getStorageValue(config.storageKey) < config.getStorageValue then + player:setStorageValue(config.storageKey, config.setStorageValue) + end end - end + end) addEvent(removeTeleport, 5 * 60 * 1000, position) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_the_ravager.lua b/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_the_ravager.lua index 0cc355f90c9..97798dadfeb 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_the_ravager.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dark_trails/kill_the_ravager.lua @@ -6,21 +6,19 @@ local function removeTeleport(position) end end -local theRavager = CreatureEvent("TheRavager") -function theRavager.onKill(creature, target) - if target:isPlayer() or target:getMaster() or target:getName():lower() ~= "the ravager" then - return true - end - - local position = target:getPosition() +local theRavager = CreatureEvent("TheRavagerDeath") +function theRavager.onDeath(player, creature) + local position = creature:getPosition() position:sendMagicEffect(CONST_ME_TELEPORT) local item = Game.createItem(1949, 1, { x = 33496, y = 32070, z = 8 }) if item:isTeleport() then item:setDestination(Position(33459, 32083, 8)) end - if creature:getStorageValue(Storage.DarkTrails.Mission11) < 1 then - creature:setStorageValue(Storage.DarkTrails.Mission11, 1) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.DarkTrails.Mission11) < 1 then + player:setStorageValue(Storage.DarkTrails.Mission11, 1) + end + end) addEvent(removeTeleport, 5 * 60 * 1000, position) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dawnport/goblin_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/dawnport/goblin_kill.lua index 9d847279991..3464d10e90e 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dawnport/goblin_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dawnport/goblin_kill.lua @@ -1,17 +1,11 @@ -local goblinKill = CreatureEvent("MorrisGoblinKill") -function goblinKill.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - - if target:getName():lower() ~= "muglex clan footman" then - return true - end - - local killAmount = player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisGoblinCount) - if player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisGoblin) == 1 and killAmount < 20 then - player:setStorageValue(Storage.Quest.U10_55.Dawnport.MorrisGoblinCount, killAmount + 1) - end +local goblinKill = CreatureEvent("MorrisGoblinDeath") +function goblinKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local killAmount = player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisGoblinCount) + if player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisGoblin) == 1 and killAmount < 20 then + player:setStorageValue(Storage.Quest.U10_55.Dawnport.MorrisGoblinCount, killAmount + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dawnport/minotaur_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/dawnport/minotaur_kill.lua index f1b11b45895..dd8718aa0ee 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dawnport/minotaur_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dawnport/minotaur_kill.lua @@ -1,17 +1,11 @@ -local minotaurKill = CreatureEvent("MorrisMinotaurKill") -function minotaurKill.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - - if target:getName():lower() ~= "minotaur bruiser" then - return true - end - - local killAmount = player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisMinosCount) - if player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisMinos) == 1 and killAmount < 20 then - player:setStorageValue(Storage.Quest.U10_55.Dawnport.MorrisMinosCount, killAmount + 1) - end +local minotaurKill = CreatureEvent("MorrisMinotaurDeath") +function minotaurKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local killAmount = player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisMinosCount) + if player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisMinos) == 1 and killAmount < 20 then + player:setStorageValue(Storage.Quest.U10_55.Dawnport.MorrisMinosCount, killAmount + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/dawnport/troll_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/dawnport/troll_kill.lua index 6e43a8a5e79..ce7fbeeb252 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/dawnport/troll_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/dawnport/troll_kill.lua @@ -1,17 +1,11 @@ -local trollKill = CreatureEvent("MorrisTrollKill") -function trollKill.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - - if target:getName():lower() ~= "mountain troll" then - return true - end - - local killAmount = player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisTrollCount) - if player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorriskTroll) == 1 and killAmount < 20 then - player:setStorageValue(Storage.Quest.U10_55.Dawnport.MorrisTrollCount, killAmount + 1) - end +local trollKill = CreatureEvent("MorrisTrollDeath") +function trollKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local killAmount = player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorrisTrollCount) + if player:getStorageValue(Storage.Quest.U10_55.Dawnport.MorriskTroll) == 1 and killAmount < 20 then + player:setStorageValue(Storage.Quest.U10_55.Dawnport.MorrisTrollCount, killAmount + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/elemental_spheres/overlord_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/elemental_spheres/overlord_kill.lua index 206923c3328..2d5b7b98f91 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/elemental_spheres/overlord_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/elemental_spheres/overlord_kill.lua @@ -6,13 +6,9 @@ local overlords = { ["lord of the elements"] = {}, } -local elementalSpheresOver = CreatureEvent("OverlordKill") -function elementalSpheresOver.onKill(creature, target) - if not target:isMonster() then - return true - end - - local bossName = target:getName() +local elementalSpheresOver = CreatureEvent("ElementalOverlordDeath") +function elementalSpheresOver.onDeath(creature) + local bossName = creature:getName() local bossConfig = overlords[bossName:lower()] if not bossConfig then return true @@ -21,12 +17,17 @@ function elementalSpheresOver.onKill(creature, target) if bossConfig.globalStorage then Game.setStorageValue(bossConfig.globalStorage, 0) end - - if bossConfig.storage and creature:getStorageValue(bossConfig.storage) < 1 then - creature:setStorageValue(bossConfig.storage, 1) + if not bossConfig.storage then + return true end - creature:say("You slayed " .. bossName .. ".", TALKTYPE_MONSTER_SAY) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(bossConfig.storage) < 1 then + player:setStorageValue(bossConfig.storage, 1) + end + player:say("You slayed " .. bossName .. ".", TALKTYPE_MONSTER_SAY) + end) + return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bone_capsule.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bone_capsule.lua index 2d6e90036c4..36a9e3272c9 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bone_capsule.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bone_capsule.lua @@ -1,9 +1,8 @@ local boneCapsule = CreatureEvent("BoneCapsule") function boneCapsule.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - local position = targetMonster:getPosition() + local position = creature:getPosition() position:sendMagicEffect(CONST_ME_POFF) - if not targetMonster or targetMonster:getName():lower() ~= "bone capsule" then + if creature:getName():lower() ~= "bone capsule" then return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bosses_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bosses_kill.lua index b0a2f27aba5..9babbd3a0ed 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bosses_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/bosses_kill.lua @@ -41,27 +41,19 @@ local function revertTeleport(position, itemId, transformId, destination) end local ascendantBossesKill = CreatureEvent("AscendantBossesKill") -function ascendantBossesKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - - local bossConfig = bosses[targetMonster:getName():lower()] +function ascendantBossesKill.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for player, _ in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(player) - if attackerPlayer then - if targetMonster:getName():lower() == "ferumbras mortal shell" then - attackerPlayer:setBossCooldown(targetMonster:getName(), os.time() + 60 * 60 * 14 * 24) - elseif targetMonster:getName():lower() == "the lord of the lice" then - attackerPlayer:setStorageValue(Storage.FerumbrasAscension.TheLordOfTheLiceAccess, 1) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if creature:getName():lower() == "ferumbras mortal shell" then + player:setBossCooldown(creature:getName(), os.time() + 60 * 60 * 14 * 24) + elseif creature:getName():lower() == "the lord of the lice" then + player:setStorageValue(Storage.FerumbrasAscension.TheLordOfTheLiceAccess, 1) end - end + end) local teleport = Tile(bossConfig.teleportPos):getItemById(1949) if not teleport then @@ -70,12 +62,12 @@ function ascendantBossesKill.onKill(creature, target) if teleport then teleport:transform(22761) - targetMonster:getPosition():sendMagicEffect(CONST_ME_THUNDER) + creature:getPosition():sendMagicEffect(CONST_ME_THUNDER) teleport:setDestination(bossConfig.godbreakerPos) addEvent(revertTeleport, 2 * 60 * 1000, bossConfig.teleportPos, 22761, 1949, Position(33319, 32318, 13)) end - if targetMonster:getName():lower() == "ferumbras mortal shell" then + if creature:getName():lower() == "ferumbras mortal shell" then addEvent(transformCrystal, 2 * 60 * 1000) end return true diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/death_dragon.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/death_dragon.lua index ad1a355a5b2..2f952dd81d8 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/death_dragon.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/death_dragon.lua @@ -1,7 +1,6 @@ local deathDragon = CreatureEvent("DeathDragon") function deathDragon.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster or targetMonster:getName():lower() ~= "death dragon" then + if not targetMonster or creature:getName():lower() ~= "death dragon" then return true end @@ -10,7 +9,7 @@ function deathDragon.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, return true end - local spectators = Game.getSpectators(targetMonster:getPosition(), false, false, 10, 10, 10, 10) + local spectators = Game.getSpectators(creature:getPosition(), false, false, 10, 10, 10, 10) for i = 1, #spectators do local spectator = spectators[i] if spectator:isMonster() and spectator:getName():lower() == "ragiaz" then diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/disgusting_ooze_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/disgusting_ooze_death.lua index 691b3c2c145..6231122703c 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/disgusting_ooze_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/disgusting_ooze_death.lua @@ -1,19 +1,18 @@ local disgustingOozeDeath = CreatureEvent("DisgustingOozeDeath") function disgustingOozeDeath.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster or targetMonster:getName():lower() ~= "disgusting ooze" then + if creature:getName():lower() ~= "disgusting ooze" then return true end if math.random(20) < 3 then for i = 1, 2 do - local monster = Game.createMonster("disgusting ooze", targetMonster:getPosition(), false, true) + local monster = Game.createMonster("disgusting ooze", creature:getPosition(), false, true) if not monster then return true end - monster:setMaster(targetMonster:getMaster()) + monster:setMaster(creature:getMaster()) end - targetMonster:say("The ooze splits and regenerates.", TALKTYPE_MONSTER_SAY) + creature:say("The ooze splits and regenerates.", TALKTYPE_MONSTER_SAY) end return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_mortal_shell_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_mortal_shell_death.lua index 32f3216c48e..9add0b883ff 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_mortal_shell_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_mortal_shell_death.lua @@ -1,7 +1,6 @@ local ferumbrasMortalShell = CreatureEvent("FerumbrasMortalShell") function ferumbrasMortalShell.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster or targetMonster:getName():lower() ~= "destabilized ferumbras" then + if creature:getName():lower() ~= "destabilized ferumbras" then return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_soul_splinter.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_soul_splinter.lua index b259d727fe6..73238b09b03 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_soul_splinter.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/ferumbras_soul_splinter.lua @@ -1,11 +1,6 @@ local ferumbrasSoulSplinter = CreatureEvent("FerumbrasSoulSplinter") function ferumbrasSoulSplinter.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster or targetMonster:getName():lower() ~= "ferumbras soul splinter" then - return true - end - - local monster = Game.createMonster("ferumbras essence", targetMonster:getPosition(), true, true) + local monster = Game.createMonster("ferumbras essence", creature:getPosition(), true, true) if not monster then return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/rift_invader_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/rift_invader_death.lua index 73109373b8d..29eb15c99df 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/rift_invader_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/rift_invader_death.lua @@ -11,18 +11,16 @@ local crystals = { local riftInvaderDeath = CreatureEvent("RiftInvaderDeath") function riftInvaderDeath.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - if not targetMonster or targetMonster:getName():lower() ~= "rift invader" then + local pos = Position(33392 + math.random(-10, 10), 31473 + math.random(-10, 10), 14) + local name = creature:getName():lower() + if name ~= "rift invader" then return true end - - local targetMonster = creature:getMonster() - local pos = Position(33392 + math.random(-10, 10), 31473 + math.random(-10, 10), 14) - local name = targetMonster:getName():lower() Game.createMonster(name, pos) for i = 1, #crystals do local crystal = crystals[i] - if isInRange(targetMonster:getPosition(), crystal.fromPosition, crystal.toPosition) then + if isInRange(creature:getPosition(), crystal.fromPosition, crystal.toPosition) then if Game.getStorageValue(crystal.globalStorage) > 8 then local item = Tile(crystal.crystalPosition):getItemById(14955) if not item then diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/the_shatterer_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/the_shatterer_kill.lua index 3267107d8f5..a132bf68f17 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/the_shatterer_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/the_shatterer_kill.lua @@ -45,12 +45,14 @@ local chains = { [7] = { itemid = 2126, position = Position(33406, 32421, 14) }, }, } + local levers = { [1] = { position = Position(33385, 32410, 14) }, [2] = { position = Position(33403, 32391, 14) }, [3] = { position = Position(33430, 32418, 14) }, [4] = { position = Position(33410, 32441, 14) }, } + local function revert() for i = 1, #chains.West do local chainWest = chains.West[i] @@ -77,27 +79,20 @@ local function revert() end end -local theShattererKill = CreatureEvent("TheShattererKill") -function theShattererKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() or targetMonster:getName():lower() ~= "the shatterer" then - return true - end - for pid, _ in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(pid) - if attackerPlayer then - if targetMonster:getName():lower() == "the shatterer" then - attackerPlayer:setStorageValue(Storage.FerumbrasAscension.TheShatterer, 1) - end - end - end +local teleportPos = Position(33393, 32438, 14) +local newPos = Position(33436, 32443, 15) + +local theShattererKill = CreatureEvent("TheShattererDeath") +function theShattererKill.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + player:setStorageValue(Storage.FerumbrasAscension.TheShatterer, 1) + end) + local teleport = Tile(Position(33393, 32438, 14)):getItemById(1949) if not teleport then return true end local oldPos = teleport:getDestination() - local teleportPos = Position(33393, 32438, 14) - local newPos = Position(33436, 32443, 15) if teleport then teleport:transform(22761) targetMonster:getPosition():sendMagicEffect(CONST_ME_THUNDER) diff --git a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/zamulosh_clone.lua b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/zamulosh_clone.lua index 6b73b47c2e8..6b6a2b4494c 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/zamulosh_clone.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/ferumbras_ascendant/zamulosh_clone.lua @@ -1,10 +1,5 @@ function onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster or targetMonster:getName():lower() ~= "zamulosh" and not targetMonster:getMaster() then - return true - end - - local monster = Game.createMonster("Zamulosh3", targetMonster:getPosition(), true, true) + local monster = Game.createMonster("Zamulosh3", creature:getPosition(), true, true) if not monster then return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/firewalker_boots/pythius_the_rotten_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/firewalker_boots/pythius_the_rotten_kill.lua index 43543a8cbd7..d1c3f1e7232 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/firewalker_boots/pythius_the_rotten_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/firewalker_boots/pythius_the_rotten_kill.lua @@ -1,11 +1,8 @@ -local firewalkerBootsKill = CreatureEvent("PythiusTheRottenKill") -function firewalkerBootsKill.onKill(player, target) - if not target:isMonster() or target:getName():lower() ~= "pythius the rotten" then - return true - end - - target:say("NICE FIGHTING LITTLE WORM, YOUR VICTORY SHALL BE REWARDED!", TALKTYPE_MONSTER_SAY, false, player, Position(32572, 31405, 15)) +local firewalkerBootsKill = CreatureEvent("PythiusTheRottenDeath") +function firewalkerBootsKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + creature:say("NICE FIGHTING LITTLE WORM, YOUR VICTORY SHALL BE REWARDED!", TALKTYPE_MONSTER_SAY, false, player, Position(32572, 31405, 15)) + local player = Player(mostDamageKiller) player:teleportTo(Position(32577, 31403, 15)) player:getPosition():sendMagicEffect(CONST_ME_TELEPORT) return true diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/astral_glyph_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/astral_glyph_death.lua index 07e48921c7d..18cb3f3a9f5 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/astral_glyph_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/astral_glyph_death.lua @@ -1,13 +1,6 @@ local astralGlyphDeath = CreatureEvent("AstralGlyphDeath") function astralGlyphDeath.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() == "an astral glyph" then - Game.createMonster("the last lore keeper", targetMonster:getPosition(), true, true) - end + Game.createMonster("the last lore keeper", creature:getPosition(), true, true) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bosses_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bosses_kill.lua index 047da278310..6bd27821be6 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bosses_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bosses_kill.lua @@ -13,38 +13,32 @@ local bosses = { ["an astral glyph"] = {}, } -local bossesForgottenKill = CreatureEvent("BossesForgottenKill") -function bossesForgottenKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesForgottenKill = CreatureEvent("ForgottenKnowledgeBossDeath") +function bossesForgottenKill.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for key, value in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(key) - if attackerPlayer then - if bossConfig.storage then - attackerPlayer:setStorageValue(bossConfig.storage, os.time() + 20 * 3600) - elseif targetMonster:getName():lower() == "the enraged thorn knight" then - attackerPlayer:setStorageValue(Storage.ForgottenKnowledge.PlantCounter, 0) - attackerPlayer:setStorageValue(Storage.ForgottenKnowledge.BirdCounter, 0) - elseif targetMonster:getName():lower() == "melting frozen horror" then - local egg = Tile(Position(32269, 31084, 14)):getTopCreature() - if egg then - local pos = egg:getPosition() - egg:remove() - Game.createMonster("baby dragon", pos, true, true) - end - local horror = Tile(Position(32267, 31071, 14)):getTopCreature() - if horror then - horror:remove() - end - end + onDeathForDamagingPlayers(creature, function(creature, player) + if bossConfig.storage then + player:setStorageValue(bossConfig.storage, os.time() + 20 * 3600) + elseif creature:getName():lower() == "the enraged thorn knight" then + player:setStorageValue(Storage.ForgottenKnowledge.PlantCounter, 0) + player:setStorageValue(Storage.ForgottenKnowledge.BirdCounter, 0) + end + end) + + if creature:getName():lower() == "melting frozen horror" then + local egg = Tile(Position(32269, 31084, 14)):getTopCreature() + if egg then + local pos = egg:getPosition() + egg:remove() + Game.createMonster("baby dragon", pos, true, true) + end + local horror = Tile(Position(32267, 31071, 14)):getTopCreature() + if horror then + horror:remove() end end return true diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bound_astral_power.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bound_astral_power.lua index c0c327f92ab..3709d5c559a 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bound_astral_power.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/bound_astral_power.lua @@ -5,31 +5,21 @@ local positions = { [4] = { pos = Position(31995, 32856, 15), nextPos = Position(31975, 32856, 15) }, } -local astralPower = CreatureEvent("AstralPower") -function astralPower.onKill(creature, target) - local player = creature:getPlayer() - if not player then - return true - end - - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - - local bossConfig = targetMonster:getName():lower() == "bound astral power" - if not bossConfig then - return true - end +local astralPower = CreatureEvent("BoundAstralPowerDeath") +function astralPower.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) Game.setStorageValue(GlobalStorage.ForgottenKnowledge.AstralPowerCounter, Game.getStorageValue(GlobalStorage.ForgottenKnowledge.AstralPowerCounter) + 1) if Game.getStorageValue(GlobalStorage.ForgottenKnowledge.AstralPowerCounter) >= 4 then Game.setStorageValue(GlobalStorage.ForgottenKnowledge.AstralPowerCounter, 1) end local msg = "The destruction of the power source gained you more time until the glyph is powered up!" + local player = Player(mostDamageKiller) + if not player then + return true + end for i = 1, #positions do - if creature:getPosition():getDistance(positions[i].pos) < 7 then - target:say(msg, TALKTYPE_MONSTER_SAY, false, nil, positions[i].pos) + if player:getPosition():getDistance(positions[i].pos) < 7 then + creature:say(msg, TALKTYPE_MONSTER_SAY, false, nil, positions[i].pos) Game.createMonster("bound astral power", positions[i].nextPos, true, true) Game.setStorageValue(GlobalStorage.ForgottenKnowledge.AstralGlyph, 1) addEvent(Game.setStorageValue, 1 * 60 * 1000, GlobalStorage.ForgottenKnowledge.AstralGlyph, 0) diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism.lua index 52ac5e0dc7f..c6611448f83 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism.lua @@ -1,4 +1,4 @@ -local energyPrism = CreatureEvent("EnergyPrism") +local energyPrism = CreatureEvent("EnergyPrismHealthChange") function energyPrism.onHealthChange(creature, attacker, primaryDamage, primaryType, secondaryDamage, secondaryType, origin) if not Tile(Position(32799, 32826, 14)):getTopCreature() then if creature:getHealth() < creature:getMaxHealth() then diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism_death.lua index ecdc212f69a..140362d92b3 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/energy_prism_death.lua @@ -1,6 +1,5 @@ local energyPrismDeath = CreatureEvent("EnergyPrismDeath") - -function energyPrismDeath.onKill(creature, target) +function energyPrismDeath.onDeath(creature) stopEvent(Storage.ForgottenKnowledge.LloydEvent) local tile = Tile(Position(32799, 32826, 14)) if not tile then diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/lloyd_preparedeath.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/lloyd_preparedeath.lua index ba912aed7f2..e00624aa53d 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/lloyd_preparedeath.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/lloyd_preparedeath.lua @@ -9,21 +9,26 @@ local function revertLloyd(prismId) local lloydTile = Tile(Position(32799, 32826, 14)) if lloydTile then local lloyd = lloydTile:getTopCreature() - lloyd:teleportTo(Position(32799, 32829, 14)) - lloyd:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + if lloyd then + lloyd:teleportTo(Position(32799, 32829, 14)) + lloyd:getPosition():sendMagicEffect(CONST_ME_TELEPORT) + end end - Tile(monsters[prismId].pos):getTopCreature():remove() - Game.createMonster(monsters[prismId].cosmicInvu, Position(monsters[prismId].pos), true, true) + local tile = Tile(monsters[prismId].pos) + if tile then + local creatures = tile:getCreatures() + for _, creature in ipairs(creatures) do + if creature:isMonster() then + creature:remove() + end + end + Game.createMonster(monsters[prismId].cosmicInvu, Position(monsters[prismId].pos), true, true) + end end local lloydPrepareDeath = CreatureEvent("LloydPrepareDeath") function lloydPrepareDeath.onPrepareDeath(creature, lastHitKiller, mostDamageKiller) - local targetMonster = creature:getMonster() - if not creature or not targetMonster then - return true - end - local prismCount = 1 for m = 1, #monsters do local cosmic = Tile(Position(monsters[m].pos)):getTopCreature() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/replica_servants.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/replica_servants.lua index 6c8811a29fc..acb25740216 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/replica_servants.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/replica_servants.lua @@ -8,19 +8,9 @@ local servants = { playerStorage = Storage.ForgottenKnowledge.DiamondServantCounter, }, } -local replicaServant = CreatureEvent("ReplicaServant") -function replicaServant.onKill(creature, target) - local player = creature:getPlayer() - if not player then - return true - end - - local targetMonster = target:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - - local bossConfig = servants[targetMonster:getName():lower()] +local replicaServant = CreatureEvent("ReplicaServantDeath") +function replicaServant.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local bossConfig = servants[creature:getName():lower()] if not bossConfig then return true end @@ -36,6 +26,10 @@ function replicaServant.onKill(creature, target) end end end + local player = Player(mostDamageKiller) + if not player then + return true + end if player:getStorageValue(bossConfig.playerStorage) < 0 then player:setStorageValue(bossConfig.playerStorage, 0) end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/thorn_knight_death.lua b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/thorn_knight_death.lua index 058612fc21d..f8b17adf708 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/thorn_knight_death.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/forgotten_knowledge/thorn_knight_death.lua @@ -10,19 +10,15 @@ local function checkBlood(position) end local thornKnightDeath = CreatureEvent("ThornKnightDeath") function thornKnightDeath.onDeath(creature, corpse, lasthitkiller, mostdamagekiller, lasthitunjustified, mostdamageunjustified) - local targetMonster = creature:getMonster() - if not targetMonster then + if creature:getName():lower() == "mounted thorn knight" then + creature:say("The thorn knight unmounts!", TALKTYPE_MONSTER_SAY) + Game.createMonster("the shielded thorn knight", creature:getPosition(), true, true) + Game.createMonster("thorn steed", creature:getPosition(), false, true) + addEvent(checkBlood, 1, creature:getPosition()) return true - end - if targetMonster:getName():lower() == "mounted thorn knight" then - targetMonster:say("The thorn knight unmounts!", TALKTYPE_MONSTER_SAY) - Game.createMonster("the shielded thorn knight", targetMonster:getPosition(), true, true) - Game.createMonster("thorn steed", targetMonster:getPosition(), false, true) - addEvent(checkBlood, 1, targetMonster:getPosition()) - return true - elseif targetMonster:getName():lower() == "the shielded thorn knight" then - Game.createMonster("the enraged thorn knight", targetMonster:getPosition(), true, true) - addEvent(checkBlood, 1, targetMonster:getPosition()) + elseif creature:getName():lower() == "the shielded thorn knight" then + Game.createMonster("the enraged thorn knight", creature:getPosition(), true, true) + addEvent(checkBlood, 1, creature:getPosition()) return true end return true diff --git a/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/bosses_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/bosses_kill.lua index 99478b3b603..4a0687ee059 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/bosses_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/bosses_kill.lua @@ -45,17 +45,13 @@ local function revertTeleport(position, itemId, transformId, destination) end end -local rathletonBossKill = CreatureEvent("RathletonBossKill") -function rathletonBossKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not target or not targetMonster or targetMonster:getMaster() then - return true - end - local bossConfig = bosses[targetMonster:getName():lower()] +local rathletonBossKill = CreatureEvent("RathletonBossDeath") +function rathletonBossKill.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - if targetMonster:getName():lower() == "empowered glooth horror" then + if creature:getName():lower() == "empowered glooth horror" then if checkHorror() == true then return true end @@ -71,7 +67,7 @@ function rathletonBossKill.onKill(creature, target) local newPos = bossConfig.nextpos if teleport then teleport:transform(22761) - targetMonster:getPosition():sendMagicEffect(CONST_ME_THUNDER) + creature:getPosition():sendMagicEffect(CONST_ME_THUNDER) teleport:setDestination(newPos) addEvent(revertTeleport, 2 * 60 * 1000, teleportPos, 22761, 1949, oldPos) Game.setStorageValue(bossConfig.globaltimer, 0) diff --git a/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/glooth_horror.lua b/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/glooth_horror.lua index 6a3bb27b3dc..e09c7b0fc6f 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/glooth_horror.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/hero_of_rathleton/glooth_horror.lua @@ -7,12 +7,7 @@ local config = { local gloothHorror = CreatureEvent("GloothHorror") function gloothHorror.onDeath(creature, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified) - local targetMonster = creature:getMonster() - if not targetMonster or targetMonster:getMaster() then - return true - end - - local name = targetMonster:getName() + local name = creature:getName() for i = 1, #config do if name == config[i].name then for j = 1, 2 do diff --git a/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/azerus_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/azerus_kill.lua index d150950da65..478dafc6e68 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/azerus_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/azerus_kill.lua @@ -6,13 +6,8 @@ local function removeTeleport(position) end end -local azerus = CreatureEvent("Azerus") -function azerus.onKill(creature, target) - local targetMonster = target:getMonster() - if not target or not targetMonster or targetMonster:getName():lower() ~= "azerus" then - return true - end - +local azerus = CreatureEvent("AzerusDeath") +function azerus.onDeath(creature) local position = targetMonster:getPosition() position:sendMagicEffect(CONST_ME_TELEPORT) local item = Game.createItem(1949, 1, position) diff --git a/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/diseased_trio_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/diseased_trio_kill.lua index d0d92ac7c08..b9a0aea39b3 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/diseased_trio_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/diseased_trio_kill.lua @@ -4,27 +4,23 @@ local diseasedTrio = { ["diseased fred"] = Storage.InServiceofYalahar.DiseasedFred, } -local diseasedTrioKill = CreatureEvent("DiseasedTrio") -function diseasedTrioKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - local bossStorage = diseasedTrio[targetMonster:getName():lower()] +local diseasedTrioKill = CreatureEvent("DiseasedTrioDeath") +function diseasedTrioKill.onDeath(creature) + local bossStorage = diseasedTrio[creature:getName():lower()] if not bossStorage then return true end - local player = creature:getPlayer() - if player:getStorageValue(bossStorage) < 1 then - player:setStorageValue(bossStorage, 1) - player:say("You slayed " .. targetMonster:getName() .. ".", TALKTYPE_MONSTER_SAY) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(bossStorage) < 1 then + player:setStorageValue(bossStorage, 1) + player:say("You slayed " .. creature:getName() .. ".", TALKTYPE_MONSTER_SAY) + end - if player:getStorageValue(Storage.InServiceofYalahar.DiseasedDan) == 1 and player:getStorageValue(Storage.InServiceofYalahar.DiseasedBill) == 1 and player:getStorageValue(Storage.InServiceofYalahar.DiseasedFred) == 1 and player:getStorageValue(Storage.InServiceofYalahar.AlchemistFormula) ~= 1 then - player:setStorageValue(Storage.InServiceofYalahar.AlchemistFormula, 0) - end + if player:getStorageValue(Storage.InServiceofYalahar.DiseasedDan) == 1 and player:getStorageValue(Storage.InServiceofYalahar.DiseasedBill) == 1 and player:getStorageValue(Storage.InServiceofYalahar.DiseasedFred) == 1 and player:getStorageValue(Storage.InServiceofYalahar.AlchemistFormula) ~= 1 then + player:setStorageValue(Storage.InServiceofYalahar.AlchemistFormula, 0) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/quara_leader_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/quara_leader_kill.lua index 51eb420a80f..91f2faeb951 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/quara_leader_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/in_service_of_yalahar/quara_leader_kill.lua @@ -4,27 +4,23 @@ local quaraLeaders = { ["splasher"] = Storage.InServiceofYalahar.QuaraSplasher, } -local quaraLeadersKill = CreatureEvent("QuaraLeaders") -function quaraLeadersKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - local bossStorage = quaraLeaders[targetMonster:getName():lower()] +local quaraLeadersKill = CreatureEvent("QuaraLeadersDeath") +function quaraLeadersKill.onDeath(creature) + local bossStorage = quaraLeaders[creature:getName():lower()] if not bossStorage then return true end - local player = creature:getPlayer() - if player:getStorageValue(bossStorage) < 1 then - player:setStorageValue(bossStorage, 1) - player:say("You slayed " .. targetMonster:getName() .. ".", TALKTYPE_MONSTER_SAY) - player:setStorageValue(Storage.InServiceofYalahar.QuaraState, 2) - player:setStorageValue(Storage.InServiceofYalahar.Questline, 41) - -- StorageValue for Questlog 'Mission 07: A Fishy Mission' - player:setStorageValue(Storage.InServiceofYalahar.Mission07, 4) - end + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(bossStorage) < 1 then + player:setStorageValue(bossStorage, 1) + player:say("You slayed " .. creature:getName() .. ".", TALKTYPE_MONSTER_SAY) + player:setStorageValue(Storage.InServiceofYalahar.QuaraState, 2) + player:setStorageValue(Storage.InServiceofYalahar.Questline, 41) + -- StorageValue for Questlog 'Mission 07: A Fishy Mission' + player:setStorageValue(Storage.InServiceofYalahar.Mission07, 4) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_boss.lua b/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_boss.lua index e2b15b60137..21546e005ad 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_boss.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_boss.lua @@ -8,14 +8,9 @@ local bosses = { ["hellgorak"] = 205, } -local inquisitionBossKill = CreatureEvent("InquisitionBossKill") -function inquisitionBossKill.onKill(player, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - local targetName = targetMonster:getName():lower() +local inquisitionBossKill = CreatureEvent("InquisitionBossDeath") +function inquisitionBossKill.onDeath(creature) + local targetName = creature:getName():lower() local bossStorage = bosses[targetName] if not bossStorage then return true @@ -28,7 +23,9 @@ function inquisitionBossKill.onKill(player, target) Game.setStorageValue(bossStorage, newValue) if newValue == 2 then - player:say("You now have 10 minutes to exit this room through the teleporter. It will bring you to the next room.", TALKTYPE_MONSTER_SAY) + onDeathForDamagingPlayers(creature, function(creature, player) + player:say("You now have 10 minutes to exit this room through the teleporter. It will bring you to the next room.", TALKTYPE_MONSTER_SAY) + end) addEvent(Game.setStorageValue, 10 * 60 * 1000, bossStorage, 0) end return true diff --git a/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_ungreez.lua b/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_ungreez.lua index 22cdf8b76fb..6859446d9d4 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_ungreez.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/inquisition/inquisition_ungreez.lua @@ -1,15 +1,9 @@ -local ungreezKill = CreatureEvent("UngreezKill") -function ungreezKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then +local ungreezKill = CreatureEvent("UngreezDeath") +function ungreezKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local player = Player(mostDamageKiller) + if not player then return true end - - if targetMonster:getName():lower() ~= "ungreez" then - return true - end - - local player = creature:getPlayer() if player:getStorageValue(Storage.TheInquisition.Questline) == 18 then -- The Inquisition Questlog- 'Mission 6: The Demon Ungreez' player:setStorageValue(Storage.TheInquisition.Mission06, 2) diff --git a/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/boss_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/boss_kill.lua new file mode 100644 index 00000000000..9fa65883199 --- /dev/null +++ b/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/boss_kill.lua @@ -0,0 +1,68 @@ +local taskBoss = { + [0] = "the snapper", + [1] = "hide", + [2] = "deathbine", + [3] = "the bloodtusk", + [4] = "shardhead", + [5] = "esmeralda", + [6] = "fleshcrawler", + [7] = "ribstride", + [8] = "the bloodweb", + [9] = "thul", + [10] = "the old widow", + [11] = "hemming", + [12] = "tormentor", + [13] = "flameborn", + [14] = "fazzrah", + [15] = "tromphonyte", + [16] = "sulphur scuttler", + [17] = "bruise payne", + [18] = "the many", + [19] = "the noxious spawn", + [20] = "gorgo", + [21] = "stonecracker", + [22] = "leviathan", + [23] = "kerberos", + [24] = "ethershreck", + [25] = "paiz the pauperizer", + [26] = "bretzecutioner", + [27] = "zanakeph", + [28] = "tiquandas revenge", + [29] = "demodras", + [30] = "necropharus", + [31] = "the horned fox", +} + +local bossKillCount = Storage.Quest.U8_5.KillingInTheNameOf.BossKillCount.SnapperCount + +local deathEvent = CreatureEvent("KillingInTheNameOfBossDeath") +function deathEvent.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local targetName = creature:getName():lower() + + onDeathForParty(creature, mostDamageKiller, function(creature, player) + for i, bossName in ipairs(taskBoss) do + if targetName == bossName then + if player:getStorageValue(bossKillCount + i) == 0 then + player:setStorageValue(bossKillCount + i, 1) + end + return true + end + end + end) + return true +end + +deathEvent:register() + +local serverstartup = GlobalEvent("KillingInTheNameOfBossDeathStartup") +function serverstartup.onStartup() + for _, bossName in pairs(taskBoss) do + local mType = MonsterType(bossName) + if not mType then + logger.error("[KillingInTheNameOfBossDeathStartup] boss with name {} is not a valid MonsterType", bossName) + else + mType:registerEvent("KillingInTheNameOfBossDeath") + end + end +end +serverstartup:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/kill.lua deleted file mode 100644 index 254e72273d4..00000000000 --- a/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/kill.lua +++ /dev/null @@ -1,121 +0,0 @@ -local taskBoss = { - [0] = "the snapper", - [1] = "hide", - [2] = "deathbine", - [3] = "the bloodtusk", - [4] = "shardhead", - [5] = "esmeralda", - [6] = "fleshcrawler", - [7] = "ribstride", - [8] = "the bloodweb", - [9] = "thul", - [10] = "the old widow", - [11] = "hemming", - [12] = "tormentor", - [13] = "flameborn", - [14] = "fazzrah", - [15] = "tromphonyte", - [16] = "sulphur scuttler", - [17] = "bruise payne", - [18] = "the many", - [19] = "the noxious spawn", - [20] = "gorgo", - [21] = "stonecracker", - [22] = "leviathan", - [23] = "kerberos", - [24] = "ethershreck", - [25] = "paiz the pauperizer", - [26] = "bretzecutioner", - [27] = "zanakeph", - [28] = "tiquandas revenge", - [29] = "demodras", - [30] = "necropharus", - [31] = "the horned fox", -} -local function killCheck(player, targetName, taskName, taskStage, taskInfo, taskAltKillCount, taskkillCount) - if player:getStorageValue(taskName) == taskStage then - if table.contains(taskInfo, targetName) then - for k = 1, #taskInfo do - if taskAltKillCount ~= nil and targetName == taskInfo[k] then - player:setStorageValue(taskAltKillCount + k - 1, player:getStorageValue(taskAltKillCount + k - 1) + 1) - end - end - player:setStorageValue(taskkillCount, player:getStorageValue(taskkillCount) + 1) - player:setStorageValue(taskName, player:getStorageValue(taskName)) -- fake update quest tracker - end - end -end -local killCounter = Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.KillCount -local BossKillCount = Storage.Quest.U8_5.KillingInTheNameOf.BossKillCount.SnapperCount -local killingInTheNameOfKill = CreatureEvent("KillingInTheNameOfKill") -function killingInTheNameOfKill.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - local targetName, startedTasks, taskId = target:getName():lower(), player:getStartedTasks() - for i = 1, #startedTasks do - taskId = startedTasks[i] - if table.contains(tasks.GrizzlyAdams[taskId].creatures, targetName) then - if #tasks.GrizzlyAdams[taskId].creatures > 1 then - for a = 1, #tasks.GrizzlyAdams[taskId].creatures do - if targetName == tasks.GrizzlyAdams[taskId].creatures[a] then - if tasks.GrizzlyAdams[taskId].raceName == "Apes" then - local apes = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.KongraCount + a - 1 - player:setStorageValue(apes, player:getStorageValue(apes) + 1) - elseif tasks.GrizzlyAdams[taskId].raceName == "Quara Scouts" then - local scouts = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.QuaraConstrictorScoutCount + a - 1 - player:setStorageValue(scouts, player:getStorageValue(scouts) + 1) - elseif tasks.GrizzlyAdams[taskId].raceName == "Underwater Quara" then - local underwater = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.QuaraConstrictorCount + a - 1 - player:setStorageValue(underwater, player:getStorageValue(underwater) + 1) - elseif tasks.GrizzlyAdams[taskId].raceName == "Nightmares" then - local nightmares = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.NightmareCount + a - 1 - player:setStorageValue(nightmares, player:getStorageValue(nightmares) + 1) - elseif tasks.GrizzlyAdams[taskId].raceName == "High Class Lizards" then - local lizards = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.LizardChosenCount + a - 1 - player:setStorageValue(lizards, player:getStorageValue(lizards) + 1) - elseif tasks.GrizzlyAdams[taskId].raceName == "Sea Serpents" then - local serpents = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.SeaSerpentCount + a - 1 - player:setStorageValue(serpents, player:getStorageValue(serpents) + 1) - elseif tasks.GrizzlyAdams[taskId].raceName == "Drakens" then - local drakens = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.DrakenAbominationCount + a - 1 - player:setStorageValue(drakens, player:getStorageValue(drakens) + 1) - end - end - end - end - local killAmount = player:getStorageValue(killCounter + taskId) - player:setStorageValue(killCounter + taskId, killAmount + 1) - player:setStorageValue(KILLSSTORAGE_BASE + taskId, player:getStorageValue(KILLSSTORAGE_BASE + taskId)) -- fake update quest tracker - end - end - for j = 0, #taskBoss do - if targetName == taskBoss[j] then - if player:getStorageValue(BossKillCount + j) == 0 then - player:setStorageValue(BossKillCount + j, 1) - end - end - end - -- Minotaurs - killCheck(player, targetName, Storage.KillingInTheNameOf.BudrikMinos, 0, tasks.Budrik[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.MinotaurCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.MinotaurCount) - -- Necromancers and Priestesses - killCheck(player, targetName, Storage.KillingInTheNameOf.LugriNecromancers, 0, tasks.Lugri[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.NecromancerCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.NecromancerCount) - killCheck(player, targetName, Storage.KillingInTheNameOf.LugriNecromancers, 3, tasks.Lugri[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.NecromancerCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.NecromancerCount) - -- Green Djinns or Efreets - killCheck(player, targetName, Storage.KillingInTheNameOf.GreenDjinnTask, 0, tasks.Gabel[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.GreenDjinnCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.GreenDjinnCount) - -- Blue Djinns or Marids - killCheck(player, targetName, Storage.KillingInTheNameOf.BlueDjinnTask, 0, tasks.Malor[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.BlueDjinnCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.BlueDjinnCount) - -- Pirates - killCheck(player, targetName, Storage.KillingInTheNameOf.PirateTask, 0, tasks.RaymondStriker[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.PirateMarauderCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.PirateCount) - -- Trolls - killCheck(player, targetName, Storage.KillingInTheNameOf.TrollTask, 0, tasks.DanielSteelsoul[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.TrollCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.TrollCount) - -- Goblins - killCheck(player, targetName, Storage.KillingInTheNameOf.GoblinTask, 0, tasks.DanielSteelsoul[2].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.GoblinCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.GoblinCount) - -- Rotworms - killCheck(player, targetName, Storage.KillingInTheNameOf.RotwormTask, 0, tasks.DanielSteelsoul[3].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.RotwormCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.RotwormCount) - -- Cyclops - killCheck(player, targetName, Storage.KillingInTheNameOf.CyclopsTask, 0, tasks.DanielSteelsoul[4].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.CyclopsCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.CyclopsCount) - return true -end - -killingInTheNameOfKill:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/monster_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/monster_kill.lua new file mode 100644 index 00000000000..b2ba681d251 --- /dev/null +++ b/data-otservbr-global/scripts/creaturescripts/quests/killing_in_the_name_of/monster_kill.lua @@ -0,0 +1,110 @@ +local function killCheck(player, targetName, taskName, taskStage, taskInfo, taskAltKillCount, taskkillCount) + if player:getStorageValue(taskName) == taskStage then + if table.contains(taskInfo, targetName) then + for k = 1, #taskInfo do + if taskAltKillCount ~= nil and targetName == taskInfo[k] then + player:setStorageValue(taskAltKillCount + k - 1, player:getStorageValue(taskAltKillCount + k - 1) + 1) + end + end + player:setStorageValue(taskkillCount, player:getStorageValue(taskkillCount) + 1) + player:setStorageValue(taskName, player:getStorageValue(taskName)) -- fake update quest tracker + end + end +end + +local killCounter = Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.KillCount + +local deathEvent = CreatureEvent("KillingInTheNameOfMonsterDeath") +function deathEvent.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local targetName = creature:getName():lower() + + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local startedTasks, taskId = player:getStartedTasks() + for i = 1, #startedTasks do + taskId = startedTasks[i] + if table.contains(tasks.GrizzlyAdams[taskId].creatures, targetName) then + if #tasks.GrizzlyAdams[taskId].creatures > 1 then + for a = 1, #tasks.GrizzlyAdams[taskId].creatures do + if targetName == tasks.GrizzlyAdams[taskId].creatures[a] then + if tasks.GrizzlyAdams[taskId].raceName == "Apes" then + local apes = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.KongraCount + a - 1 + player:setStorageValue(apes, player:getStorageValue(apes) + 1) + elseif tasks.GrizzlyAdams[taskId].raceName == "Quara Scouts" then + local scouts = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.QuaraConstrictorScoutCount + a - 1 + player:setStorageValue(scouts, player:getStorageValue(scouts) + 1) + elseif tasks.GrizzlyAdams[taskId].raceName == "Underwater Quara" then + local underwater = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.QuaraConstrictorCount + a - 1 + player:setStorageValue(underwater, player:getStorageValue(underwater) + 1) + elseif tasks.GrizzlyAdams[taskId].raceName == "Nightmares" then + local nightmares = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.NightmareCount + a - 1 + player:setStorageValue(nightmares, player:getStorageValue(nightmares) + 1) + elseif tasks.GrizzlyAdams[taskId].raceName == "High Class Lizards" then + local lizards = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.LizardChosenCount + a - 1 + player:setStorageValue(lizards, player:getStorageValue(lizards) + 1) + elseif tasks.GrizzlyAdams[taskId].raceName == "Sea Serpents" then + local serpents = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.SeaSerpentCount + a - 1 + player:setStorageValue(serpents, player:getStorageValue(serpents) + 1) + elseif tasks.GrizzlyAdams[taskId].raceName == "Drakens" then + local drakens = Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.DrakenAbominationCount + a - 1 + player:setStorageValue(drakens, player:getStorageValue(drakens) + 1) + end + end + end + end + local killAmount = player:getStorageValue(killCounter + taskId) + player:setStorageValue(killCounter + taskId, killAmount + 1) + player:setStorageValue(KILLSSTORAGE_BASE + taskId, player:getStorageValue(KILLSSTORAGE_BASE + taskId)) -- fake update quest tracker + end + end + -- Minotaurs + killCheck(player, targetName, Storage.KillingInTheNameOf.BudrikMinos, 0, tasks.Budrik[1].creatures, nil, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.MinotaurCount) + -- Necromancers and Priestesses + killCheck(player, targetName, Storage.KillingInTheNameOf.LugriNecromancers, 0, tasks.Lugri[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.NecromancerCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.NecromancerCount) + killCheck(player, targetName, Storage.KillingInTheNameOf.LugriNecromancers, 3, tasks.Lugri[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.NecromancerCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.NecromancerCount) + -- Green Djinns or Efreets + killCheck(player, targetName, Storage.KillingInTheNameOf.GreenDjinnTask, 0, tasks.Gabel[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.GreenDjinnCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.GreenDjinnCount) + -- Blue Djinns or Marids + killCheck(player, targetName, Storage.KillingInTheNameOf.BlueDjinnTask, 0, tasks.Malor[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.BlueDjinnCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.BlueDjinnCount) + -- Pirates + killCheck(player, targetName, Storage.KillingInTheNameOf.PirateTask, 0, tasks.RaymondStriker[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.PirateMarauderCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.PirateCount) + -- Trolls + killCheck(player, targetName, Storage.KillingInTheNameOf.TrollTask, 0, tasks.DanielSteelsoul[1].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.TrollCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.TrollCount) + -- Goblins + killCheck(player, targetName, Storage.KillingInTheNameOf.GoblinTask, 0, tasks.DanielSteelsoul[2].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.GoblinCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.GoblinCount) + -- Rotworms + killCheck(player, targetName, Storage.KillingInTheNameOf.RotwormTask, 0, tasks.DanielSteelsoul[3].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.RotwormCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.RotwormCount) + -- Cyclops + killCheck(player, targetName, Storage.KillingInTheNameOf.CyclopsTask, 0, tasks.DanielSteelsoul[4].creatures, Storage.Quest.U8_5.KillingInTheNameOf.AltKillCount.CyclopsCount, Storage.Quest.U8_5.KillingInTheNameOf.MonsterKillCount.CyclopsCount) + end) + return true +end + +deathEvent:register() + +local serverstartup = GlobalEvent("KillingInTheNameOfMonsterDeathStartup") +function serverstartup.onStartup() + local monsters = Set({}, { insensitive = true }) + for _, task in pairs(tasks.GrizzlyAdams) do + monsters = monsters:union(task.creatures) + end + + monsters = monsters:union(tasks.Budrik[1].creatures) + monsters = monsters:union(tasks.Lugri[1].creatures) + monsters = monsters:union(tasks.Gabel[1].creatures) + monsters = monsters:union(tasks.Malor[1].creatures) + monsters = monsters:union(tasks.RaymondStriker[1].creatures) + monsters = monsters:union(tasks.DanielSteelsoul[1].creatures) + monsters = monsters:union(tasks.DanielSteelsoul[2].creatures) + monsters = monsters:union(tasks.DanielSteelsoul[3].creatures) + monsters = monsters:union(tasks.DanielSteelsoul[4].creatures) + + for monster in monsters:iter() do + local mType = MonsterType(monster) + if not mType then + logger.error("[KillingInTheNameOfMonsterDeathStartup] monster with name {} is not a valid MonsterType", monster) + else + mType:registerEvent("KillingInTheNameOfMonsterDeath") + end + end +end +serverstartup:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/bragrumol.lua b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/bragrumol.lua index 9310a34737c..02846ec6cfd 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/bragrumol.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/bragrumol.lua @@ -1,16 +1,11 @@ -local bragrumol = CreatureEvent("BragrumolKill") +local bragrumol = CreatureEvent("BragrumolDeath") -function bragrumol.onKill(cid, target, damage, flags, corpse) - if isMonster(target) then - if string.lower(getCreatureName(target)) == "bragrumol" then - for attackerUid, damage in pairs(target:getDamageMap()) do - local player = Player(attackerUid) - if player and player:getStorageValue(Storage.Kilmaresh.Twelve.Bragrumol) == 1 then - player:setStorageValue(Storage.Kilmaresh.Twelve.Bragrumol, 2) - end - end +function bragrumol.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.Kilmaresh.Twelve.Bragrumol) == 1 then + player:setStorageValue(Storage.Kilmaresh.Twelve.Bragrumol, 2) end - end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/fafnar.lua b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/fafnar.lua index 157b2302848..4d94f0e6d3b 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/fafnar.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/fafnar.lua @@ -3,22 +3,25 @@ local monster = { ["priestess of the wild sun"] = Storage.Kilmaresh.Thirteen.Fafnar, } -local fafnar = CreatureEvent("FafnarKill") +local fafnar = CreatureEvent("FafnarMissionsDeath") -function fafnar.onKill(creature, target) - local storage = monster[target:getName():lower()] - if target:isPlayer() or target:getMaster() or not storage then +function fafnar.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local storage = monster[creature:getName():lower()] + if not storage then return false end - local kills = creature:getStorageValue(storage) - if kills == 300 and creature:getStorageValue(storage) == 1 then - creature:say("You slayed " .. target:getName() .. ".", TALKTYPE_MONSTER_SAY) - else - kills = kills + 1 - creature:say("You have slayed " .. target:getName() .. " " .. kills .. " times!", TALKTYPE_MONSTER_SAY) - creature:setStorageValue(storage, kills) - end + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local kills = player:getStorageValue(storage) + if kills == 300 and player:getStorageValue(storage) == 1 then + player:say("You slayed " .. creature:getName() .. ".", TALKTYPE_MONSTER_SAY) + else + kills = kills + 1 + player:say("You have slayed " .. creature:getName() .. " " .. kills .. " times!", TALKTYPE_MONSTER_SAY) + player:setStorageValue(storage, kills) + end + end) + return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/mozradek.lua b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/mozradek.lua index e87fef037eb..23507b878b0 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/mozradek.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/mozradek.lua @@ -1,16 +1,11 @@ -local mozradek = CreatureEvent("MozradekKill") +local mozradek = CreatureEvent("MozradekDeath") -function mozradek.onKill(cid, target, damage, flags, corpse) - if isMonster(target) then - if string.lower(getCreatureName(target)) == "mozradek" then - for attackerUid, damage in pairs(target:getDamageMap()) do - local player = Player(attackerUid) - if player and player:getStorageValue(Storage.Kilmaresh.Twelve.Mozradek) == 1 then - player:setStorageValue(Storage.Kilmaresh.Twelve.Mozradek, 2) - end - end +function mozradek.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.Kilmaresh.Twelve.Mozradek) == 1 then + player:setStorageValue(Storage.Kilmaresh.Twelve.Mozradek, 2) end - end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/xogixath.lua b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/xogixath.lua index d9e2dba2e5e..cbfe0daeb3b 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/xogixath.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/kilmaresh/xogixath.lua @@ -1,16 +1,11 @@ -local xogixath = CreatureEvent("XogixathKill") +local xogixath = CreatureEvent("XogixathDeath") -function xogixath.onKill(cid, target, damage, flags, corpse) - if isMonster(target) then - if string.lower(getCreatureName(target)) == "xogixath" then - for attackerUid, damage in pairs(target:getDamageMap()) do - local player = Player(attackerUid) - if player and player:getStorageValue(Storage.Kilmaresh.Twelve.Xogixath) == 1 then - player:setStorageValue(Storage.Kilmaresh.Twelve.Xogixath, 2) - end - end +function xogixath.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.Kilmaresh.Twelve.Xogixath) == 1 then + player:setStorageValue(Storage.Kilmaresh.Twelve.Xogixath, 2) end - end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/liquid_black/deepling_boss_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/liquid_black/deepling_boss_kill.lua index 369d57155ca..6916f3dfa5a 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/liquid_black/deepling_boss_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/liquid_black/deepling_boss_kill.lua @@ -4,27 +4,19 @@ local bosses = { ["obujos"] = { status = 4, storage = Storage.DeeplingBosses.Obujos }, } -local deeplingBosses = CreatureEvent("DeeplingBosses") -function deeplingBosses.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - local bossConfig = bosses[targetMonster:getName():lower()] +local deeplingBosses = CreatureEvent("DeeplingBossDeath") +function deeplingBosses.onDeath(player, creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end - for pid, _ in pairs(targetMonster:getDamageMap()) do - local attackerPlayer = Player(pid) - if attackerPlayer then - if attackerPlayer:getStorageValue(Storage.DeeplingBosses.DeeplingStatus) < bossConfig.status then - attackerPlayer:setStorageValue(Storage.DeeplingBosses.DeeplingStatus, bossConfig.status) - end - attackerPlayer:setStorageValue(bossConfig.storage, 1) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.DeeplingBosses.DeeplingStatus) < bossConfig.status then + player:setStorageValue(Storage.DeeplingBosses.DeeplingStatus, bossConfig.status) end - end + player:setStorageValue(bossConfig.storage, 1) + end) end deeplingBosses:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/energized_raging_mage_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/energized_raging_mage_kill.lua index 95cf707a712..d04b37bf6ee 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/energized_raging_mage_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/energized_raging_mage_kill.lua @@ -1,13 +1,5 @@ -local energizedRagingMageKill = CreatureEvent("EnergizedRagingMageKill") -function energizedRagingMageKill.onKill(player, creature, damage, flags) - if not creature or not creature:isMonster() then - return true - end - - if creature:getName():lower() ~= "energized raging mage" then - return true - end - +local deathEvent = CreatureEvent("EnergizedRagingMageDeath") +function deathEvent.onDeath(creature) if getGlobalStorageValue(673003) < 2000 then return true end @@ -15,10 +7,10 @@ function energizedRagingMageKill.onKill(player, creature, damage, flags) local monster = Game.createMonster("Raging Mage", creature:getPosition()) monster:setReward(true) - doCreatureSayWithRadius(player, "GNAAAAAHRRRG!! WHAT? WHAT DID YOU DO TO ME!! I... I feel the energies crawling away... from me... DIE!!!", TALKTYPE_ORANGE_1, 35, 71) + doCreatureSayWithRadius(creature, "GNAAAAAHRRRG!! WHAT? WHAT DID YOU DO TO ME!! I... I feel the energies crawling away... from me... DIE!!!", TALKTYPE_ORANGE_1, 35, 71) setGlobalStorageValue(673003, 0) return true end -energizedRagingMageKill:register() +deathEvent:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_2.lua b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_2.lua index 222ac163523..50dd16de684 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_2.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_2.lua @@ -1,16 +1,11 @@ local ragingMage2 = CreatureEvent("RagingMage2") function ragingMage2.onDeath(creature, corpse, killer, mostDamageKiller, unjustified, mostDamageUnjustified) - local targetMonster = creature:getMonster() - if not creature or not targetMonster or targetMonster:getName():lower() ~= "raging mage" then - return true - end - broadcastMessage( "The remains of the Raging Mage are scattered on the floor of his Tower. \z The dimensional portal quakes.", MESSAGE_EVENT_ADVANCE ) - targetMonster:say( + creature:say( "I WILL RETURN!! My death will just be a door to await my homecoming, \z my physical hull will be... my... argh...", TALKTYPE_MONSTER_SAY, diff --git a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_kill.lua index a99341b7eaa..a24f174f5e7 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/raging_mage_kill.lua @@ -1,26 +1,20 @@ -local ragingMageKill = CreatureEvent("ragingMageKill") +local deathEvent = CreatureEvent("RagingMageDeath") -function ragingMageKill.onKill(cid, target, damage, flags, corpse) - if not target or type(target) ~= "userdata" or not target:isMonster() then - return true - end +function deathEvent.onDeath(creature) + broadcastMessage("The remains of the Raging Mage are scattered on the floor of his Tower. The dimensional portal quakes.", MESSAGE_EVENT_ADVANCE) + doCreatureSay(creature, "I WILL RETURN!! My death will just be a door to await my homecoming, my physical hull will be... my... argh...", TALKTYPE_ORANGE_1) - if target:getName():lower() == "raging mage" then - broadcastMessage("The remains of the Raging Mage are scattered on the floor of his Tower. The dimensional portal quakes.", MESSAGE_EVENT_ADVANCE) - doCreatureSay(target, "I WILL RETURN!! My death will just be a door to await my homecoming, my physical hull will be... my... argh...", TALKTYPE_ORANGE_1) - - addEvent(function() - broadcastMessage("With a great bang the dimensional portal in Zao collapsed and with it the connection to the other dimension shattered.", MESSAGE_EVENT_ADVANCE) - local tile = Tile(Position({ x = 33143, y = 31527, z = 2 })) - if tile then - local item = tile:getItemById(11796) - if item then - item:remove(1) - end + addEvent(function() + broadcastMessage("With a great bang the dimensional portal in Zao collapsed and with it the connection to the other dimension shattered.", MESSAGE_EVENT_ADVANCE) + local tile = Tile(Position({ x = 33143, y = 31527, z = 2 })) + if tile then + local item = tile:getItemById(11796) + if item then + item:remove(1) end - end, 5 * 60 * 1000) - end + end + end, 5 * 60 * 1000) return true end -ragingMageKill:register() +deathEvent:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/yielothax_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/yielothax_kill.lua index c22332db7a2..8ff28ceb824 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/yielothax_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/raging_mage_tower/yielothax_kill.lua @@ -1,10 +1,6 @@ -local yielothaxKill = CreatureEvent("YielothaxKill") -function yielothaxKill.onKill(cid, target, damage, flags) - if isMonster(target) then - if string.lower(getCreatureName(target)) == "yielothax" then - setGlobalStorageValue(673003, getGlobalStorageValue(673003) + 1) - end - end +local yielothaxKill = CreatureEvent("YielothaxDeath") +function yielothaxKill.onDeath(creature) + setGlobalStorageValue(673003, getGlobalStorageValue(673003) + 1) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/secret_service/black_knight_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/secret_service/black_knight_kill.lua index 611de73ce09..d63dac6a194 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/secret_service/black_knight_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/secret_service/black_knight_kill.lua @@ -1,19 +1,10 @@ -local blackKnightKill = CreatureEvent("BlackKnightKill") -function blackKnightKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "black knight" then - return true - end - - local player = creature:getPlayer() - if player:getStorageValue(Storage.SecretService.AVINMission04) == 1 then - player:setStorageValue(Storage.SecretService.AVINMission04, 2) - end - +local blackKnightKill = CreatureEvent("BlackKnightDeath") +function blackKnightKill.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.SecretService.AVINMission04) == 1 then + player:setStorageValue(Storage.SecretService.AVINMission04, 2) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/lower_spike_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/lower_spike_kill.lua index 02282ff3f37..16c79963c42 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/lower_spike_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/lower_spike_kill.lua @@ -4,20 +4,23 @@ local range = { to = Position(32345, 32710, 15), } -local lowerSpikeKill = CreatureEvent("LowerSpikeKill") -function lowerSpikeKill.onKill(creature, target) - if not table.contains({ -1, 7 }, creature:getStorageValue(SPIKE_LOWER_KILL_MAIN)) then - if creature:getPosition():isInRange(range.from, range.to) then - if target:isMonster() and (target:getMaster() == nil) and (target:getName():lower() == "drillworm") then - local sum = creature:getStorageValue(SPIKE_LOWER_KILL_MAIN) + 1 - creature:setStorageValue(SPIKE_LOWER_KILL_MAIN, sum) - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have slayed " .. sum .. " out of 7 Drillworms.") - if sum == 7 then - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Report the task to Gnomargery.") - end +local lowerSpikeKill = CreatureEvent("LowerSpikeDeath") +function lowerSpikeKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + if not creature:getPosition():isInRange(range.from, range.to) then + return true + end + + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if not table.contains({ -1, 7 }, player:getStorageValue(SPIKE_LOWER_KILL_MAIN)) then + local sum = player:getStorageValue(SPIKE_LOWER_KILL_MAIN) + 1 + player:setStorageValue(SPIKE_LOWER_KILL_MAIN, sum) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have slayed " .. sum .. " out of 7 Drillworms.") + if sum == 7 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Report the task to Gnomargery.") end end - end + end) + return true end lowerSpikeKill:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/middle_spike_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/middle_spike_kill.lua index f5f8e0b673f..2dd6017d106 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/middle_spike_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/middle_spike_kill.lua @@ -4,20 +4,22 @@ local range = { to = Position(32380, 32725, 12), } -local middleSpikeKill = CreatureEvent("MiddleSpikeKill") -function middleSpikeKill.onKill(creature, target) - if not table.contains({ -1, 7 }, creature:getStorageValue(SPIKE_MIDDLE_KILL_MAIN)) then - if creature:getPosition():isInRange(range.from, range.to) then - if target:isMonster() and (target:getMaster() == nil) and (target:getName():lower() == "crystalcrusher") then - local sum = creature:getStorageValue(SPIKE_MIDDLE_KILL_MAIN) + 1 - creature:setStorageValue(SPIKE_MIDDLE_KILL_MAIN, sum) - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have slayed " .. sum .. " out of 7 Crystalcrushers.") - if sum == 7 then - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Report the task to Gnombold.") - end +local middleSpikeKill = CreatureEvent("MiddleSpikeDeath") +function middleSpikeKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + if not creature:getPosition():isInRange(range.from, range.to) then + return true + end + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if not table.contains({ -1, 7 }, player:getStorageValue(SPIKE_MIDDLE_KILL_MAIN)) then + local sum = player:getStorageValue(SPIKE_MIDDLE_KILL_MAIN) + 1 + player:setStorageValue(SPIKE_MIDDLE_KILL_MAIN, sum) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have slayed " .. sum .. " out of 7 Crystalcrushers.") + if sum == 7 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Report the task to Gnombold.") end end - end + end) + return true end middleSpikeKill:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/upper_spike_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/upper_spike_kill.lua index d06f4e2c94f..96f9dc6b397 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/upper_spike_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/spike_tasks/upper_spike_kill.lua @@ -4,20 +4,23 @@ local range = { to = Position(32365, 32759, 10), } -local upperSpikeKill = CreatureEvent("UpperSpikeKill") -function upperSpikeKill.onKill(creature, target) - if not table.contains({ -1, 7 }, creature:getStorageValue(SPIKE_UPPER_KILL_MAIN)) then - if creature:getPosition():isInRange(range.from, range.to) then - if target:isMonster() and (target:getMaster() == nil) and (target:getName():lower() == "demon skeleton") then - local sum = creature:getStorageValue(SPIKE_UPPER_KILL_MAIN) + 1 - creature:setStorageValue(SPIKE_UPPER_KILL_MAIN, sum) - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have slayed " .. sum .. " out of 7 Demon Skeletons.") - if sum == 7 then - creature:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Report the task to Gnomilly.") - end +local upperSpikeKill = CreatureEvent("UpperSpikeDeath") +function upperSpikeKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + if not creature:getPosition():isInRange(range.from, range.to) then + return false + end + + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if not table.contains({ -1, 7 }, player:getStorageValue(SPIKE_UPPER_KILL_MAIN)) then + local sum = player:getStorageValue(SPIKE_UPPER_KILL_MAIN) + 1 + player:setStorageValue(SPIKE_UPPER_KILL_MAIN, sum) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have slayed " .. sum .. " out of 7 Demon Skeletons.") + if sum == 7 then + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Report the task to Gnomilly.") end end - end + end) + return true end upperSpikeKill:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/svargrond_arena/arena_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/svargrond_arena/arena_kill.lua index 7798c4b3738..674dc5d27d5 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/svargrond_arena/arena_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/svargrond_arena/arena_kill.lua @@ -1,11 +1,10 @@ -local svargrondArenaKill = CreatureEvent("SvargrondArenaKill") -function svargrondArenaKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return +local deathEvent = CreatureEvent("SvargrondArenaBossDeath") +function deathEvent.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + local player = Player(mostDamageKiller) + if not player then + return true end - local player = creature:getPlayer() local pit = player:getStorageValue(Storage.SvargrondArena.PitDoor) if pit < 1 or pit > 10 then return @@ -16,7 +15,7 @@ function svargrondArenaKill.onKill(creature, target) return end - if not table.contains(ARENA[arena].creatures, targetMonster:getName():lower()) then + if not table.contains(ARENA[arena].creatures, creature:getName():lower()) then return end @@ -40,4 +39,19 @@ function svargrondArenaKill.onKill(creature, target) return true end -svargrondArenaKill:register() +deathEvent:register() + +local serverstartup = GlobalEvent("SvargrondArenaBossDeathStartup") +function serverstartup.onStartup() + for _, arena in pairs(ARENA) do + for _, bossName in pairs(arena.creatures) do + local mType = MonsterType(bossName) + if not mType then + logger.error("[SvargrondArenaBossDeathStartup] boss with name {} is not a valid MonsterType", bossName) + else + mType:registerEvent("SvargrondArenaBossDeath") + end + end + end +end +serverstartup:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/the_first_dragon/kill_dragon.lua b/data-otservbr-global/scripts/creaturescripts/quests/the_first_dragon/kill_dragon.lua index eae77dc5437..55045c65e9d 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/the_first_dragon/kill_dragon.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/the_first_dragon/kill_dragon.lua @@ -1,18 +1,12 @@ -local killDragon = CreatureEvent("KillDragon") +local killDragon = CreatureEvent("TheFirstDragonDragonTaskDeath") -function killDragon.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - if target:getName():lower() == "dragon" then +function killDragon.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) local storage = player:getStorageValue(Storage.FirstDragon.DragonCounter) if storage >= 0 and storage < 200 then player:setStorageValue(Storage.FirstDragon.DragonCounter, player:getStorageValue(Storage.FirstDragon.DragonCounter) + 1) end - end - if player:getStorageValue(Storage.FirstDragon.TazhadurTimer) >= os.time() then - return true - end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/the_ice_islands/husky_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/the_ice_islands/husky_kill.lua index 3103f924e44..b5a3f4c4dff 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/the_ice_islands/husky_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/the_ice_islands/husky_kill.lua @@ -1,13 +1,10 @@ -local huskyKill = CreatureEvent("HuskyKill") +local huskyKill = CreatureEvent("HuskyDeath") -function huskyKill.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - - if target:getName():lower() == "husky" then - player:setStorageValue(Storage.TheIceIslands.HuskyKill, player:getStorageValue(Storage.TheIceIslands.HuskyKill) + 1) - end +function huskyKill.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + local value = player:getStorageValue(Storage.TheIceIslands.HuskyKill) or 0 + player:setStorageValue(Storage.TheIceIslands.HuskyKill, value + 1) + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/the_primal_ordeal/the_primal_menace_killed.lua b/data-otservbr-global/scripts/creaturescripts/quests/the_primal_ordeal/the_primal_menace_killed.lua index 2f5af644afa..3cafb041e31 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/the_primal_ordeal/the_primal_menace_killed.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/the_primal_ordeal/the_primal_menace_killed.lua @@ -1,29 +1,21 @@ local thePrimalMenaceDeath = CreatureEvent("ThePrimalMenaceDeath") -function thePrimalMenaceDeath.onDeath(creature, corpse, killer, mostDamage, unjustified, mostDamage_unjustified) - if not creature then - return - end - +function thePrimalMenaceDeath.onDeath(creature) local damageMap = creature:getMonster():getDamageMap() local hazard = Hazard.getByName("hazard.gnomprona-gardens") if not hazard then return end local _, hazardPoints = hazard:getHazardPlayerAndPoints(damageMap) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(Storage.Quest.U12_90.PrimalOrdeal.Bosses.ThePrimalMenaceKilled) < 1 then + player:setStorageValue(Storage.Quest.U12_90.PrimalOrdeal.Bosses.ThePrimalMenaceKilled, 1) + end - for key, value in pairs(damageMap) do - local player = Player(key) - if player then - if player:getStorageValue(Storage.Quest.U12_90.PrimalOrdeal.Bosses.ThePrimalMenaceKilled) < 1 then - player:setStorageValue(Storage.Quest.U12_90.PrimalOrdeal.Bosses.ThePrimalMenaceKilled, 1) - end - - if hazard:getPlayerMaxLevel(player) == hazardPoints then - hazard:levelUp(player) - end + if hazard:getPlayerMaxLevel(player) == hazardPoints then + hazard:levelUp(player) end - end + end) end thePrimalMenaceDeath:register() diff --git a/data-otservbr-global/scripts/creaturescripts/quests/thieves_guild/nomad_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/thieves_guild/nomad_kill.lua index 1bf05869998..6f9c3d32547 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/thieves_guild/nomad_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/thieves_guild/nomad_kill.lua @@ -1,19 +1,10 @@ -local nomadKill = CreatureEvent("NomadKill") -function nomadKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "nomad" then - return true - end - - local player = creature:getPlayer() - if player:getStorageValue(Storage.ThievesGuild.Mission04) == 3 then - player:setStorageValue(Storage.ThievesGuild.Mission04, 4) - end - +local nomadKill = CreatureEvent("NomadDeath") +function nomadKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if player:getStorageValue(Storage.ThievesGuild.Mission04) == 3 then + player:setStorageValue(Storage.ThievesGuild.Mission04, 4) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/bosses_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/bosses_kill.lua index 2cb2db29438..37a823a67ac 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/bosses_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/bosses_kill.lua @@ -17,14 +17,9 @@ local bosses = { }, } -local bossesKill = CreatureEvent("BossesKill") -function bossesKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - local bossConfig = bosses[targetMonster:getName():lower()] +local bossesKill = CreatureEvent("WrathOfTheEmperorBossDeat") +function bossesKill.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] if not bossConfig then return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/keeper_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/keeper_kill.lua index f43204ce59c..5be3f6f6dbe 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/keeper_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/keeper_kill.lua @@ -1,13 +1,6 @@ -local keeperKill = CreatureEvent("KeeperKill") -function keeperKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() == "the keeper" then - Game.setStorageValue(Storage.WrathoftheEmperor.Mission03, 0) - end +local keeperKill = CreatureEvent("TheKeeperDeath") +function keeperKill.onDeath(creature) + Game.setStorageValue(Storage.WrathoftheEmperor.Mission03, 0) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_magistratus_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_magistratus_kill.lua index e526a699b20..8be99184fda 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_magistratus_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_magistratus_kill.lua @@ -1,20 +1,11 @@ -local lizardMagistratusKill = CreatureEvent("LizardMagistratusKill") -function lizardMagistratusKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "lizard magistratus" then - return true - end - - local player = creature:getPlayer() - local storage = player:getStorageValue(Storage.WrathoftheEmperor.Mission06) - if storage >= 0 and storage < 4 then - player:setStorageValue(Storage.WrathoftheEmperor.Mission06, math.max(1, storage) + 1) - end - +local lizardMagistratusKill = CreatureEvent("LizardMagistratusDeath") +function lizardMagistratusKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local storage = player:getStorageValue(Storage.WrathoftheEmperor.Mission06) + if storage >= 0 and storage < 4 then + player:setStorageValue(Storage.WrathoftheEmperor.Mission06, math.max(1, storage) + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_noble_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_noble_kill.lua index ab45524fba1..112feffa73f 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_noble_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/lizard_noble_kill.lua @@ -1,20 +1,11 @@ -local lizardNobleKill = CreatureEvent("LizardNobleKill") -function lizardNobleKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "lizard noble" then - return true - end - - local player = creature:getPlayer() - local storage = player:getStorageValue(Storage.WrathoftheEmperor.Mission07) - if storage >= 0 and storage < 6 then - player:setStorageValue(Storage.WrathoftheEmperor.Mission07, math.max(1, storage) + 1) - end - +local lizardNobleKill = CreatureEvent("LizardNobleDeath") +function lizardNobleKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local storage = player:getStorageValue(Storage.WrathoftheEmperor.Mission07) + if storage >= 0 and storage < 6 then + player:setStorageValue(Storage.WrathoftheEmperor.Mission07, math.max(1, storage) + 1) + end + end) return true end diff --git a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/zalamon_kill.lua b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/zalamon_kill.lua index 143049aaece..349c704ca64 100644 --- a/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/zalamon_kill.lua +++ b/data-otservbr-global/scripts/creaturescripts/quests/wrath_of_the_emperor/zalamon_kill.lua @@ -13,26 +13,21 @@ local bossForms = { }, } -local zalamonKill = CreatureEvent("ZalamonKill") -function zalamonKill.onKill(player, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() == "mutated zalamon" then +local zalamonKill = CreatureEvent("ZalamonDeath") +function zalamonKill.onDeath(creature) + if creature:getName():lower() == "mutated zalamon" then Game.setStorageValue(Storage.WrathoftheEmperor.Mission11, -1) return true end - local name = targetMonster:getName():lower() + local name = creature:getName():lower() local bossConfig = bossForms[name] if not bossConfig then return true end local found = false - for k, v in ipairs(Game.getSpectators(targetMonster:getPosition())) do + for k, v in ipairs(Game.getSpectators(creature:getPosition())) do if v:getName():lower() == bossConfig.newForm then found = true break @@ -40,8 +35,10 @@ function zalamonKill.onKill(player, target) end if not found then - Game.createMonster(bossConfig.newForm, targetMonster:getPosition(), false, true) - player:say(bossConfig.text, TALKTYPE_MONSTER_SAY) + local monster = Game.createMonster(bossConfig.newForm, creature:getPosition(), false, true) + if monster then + monster:say(bossConfig.text, TALKTYPE_MONSTER_SAY) + end end return true end diff --git a/data-otservbr-global/scripts/hazard/primal.lua b/data-otservbr-global/scripts/hazard/primal.lua index 8aeb80a555c..e4309b78f67 100644 --- a/data-otservbr-global/scripts/hazard/primal.lua +++ b/data-otservbr-global/scripts/hazard/primal.lua @@ -82,8 +82,14 @@ function createPrimalPod(position) end end -local primalKill = CreatureEvent("PrimalHazardKill") -function primalKill.onKill(_player, creature) +local spawnEvent = ZoneEvent(hazardZone) +function spawnEvent.onSpawn(monster, position) + monster:registerEvent("PrimalHazardDeath") +end +spawnEvent:register() + +local deathEvent = CreatureEvent("PrimalHazardDeath") +function deathEvent.onDeath(creature) if not configManager.getBoolean(configKeys.TOGGLE_HAZARDSYSTEM) then return true end @@ -123,4 +129,4 @@ function primalKill.onKill(_player, creature) return true end -primalKill:register() +deathEvent:register() diff --git a/data-otservbr-global/scripts/quests/primal_ordeal_quest/bosses_killed.lua b/data-otservbr-global/scripts/quests/primal_ordeal_quest/bosses_killed.lua new file mode 100644 index 00000000000..cb0c34b6401 --- /dev/null +++ b/data-otservbr-global/scripts/quests/primal_ordeal_quest/bosses_killed.lua @@ -0,0 +1,18 @@ +local bosses = { + ["magma bubble"] = { storage = Storage.Quest.U12_90.PrimalOrdeal.Bosses.MagmaBubbleKilled }, + ["the primal menace"] = { storage = Storage.Quest.U12_90.PrimalOrdeal.Bosses.ThePrimalMenaceKilled }, +} + +local bossesPrimeOrdeal = CreatureEvent("ThePrimeOrdealBossDeath") +function bossesPrimeOrdeal.onDeath(creature) + local bossConfig = bosses[creature:getName():lower()] + if not bossConfig or not bossConfig.storage then + return true + end + onDeathForDamagingPlayers(creature, function(creature, player) + player:setStorageValue(bossConfig.storage, 1) + end) + return true +end + +bossesPrimeOrdeal:register() diff --git a/data-otservbr-global/scripts/quests/the_new_frontier/creaturescripts-shard_of_corruption_kill.lua b/data-otservbr-global/scripts/quests/the_new_frontier/creaturescripts-shard_of_corruption_kill.lua deleted file mode 100644 index 4d97191766a..00000000000 --- a/data-otservbr-global/scripts/quests/the_new_frontier/creaturescripts-shard_of_corruption_kill.lua +++ /dev/null @@ -1,22 +0,0 @@ -local TheNewFrontier = Storage.Quest.U8_54.TheNewFrontier - -local shardOfCorruptionKill = CreatureEvent("ShardOfCorruptionKill") - -function shardOfCorruptionKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "shard of corruption" then - return true - end - - local player = creature:getPlayer() - if player:getStorageValue(TheNewFrontier.Questline) == 11 then - player:setStorageValue(TheNewFrontier.Questline, 12) - end - return true -end - -shardOfCorruptionKill:register() diff --git a/data-otservbr-global/scripts/quests/the_new_frontier/shard_of_corruption_kill.lua b/data-otservbr-global/scripts/quests/the_new_frontier/shard_of_corruption_kill.lua new file mode 100644 index 00000000000..24d4a02922c --- /dev/null +++ b/data-otservbr-global/scripts/quests/the_new_frontier/shard_of_corruption_kill.lua @@ -0,0 +1,14 @@ +local TheNewFrontier = Storage.Quest.U8_54.TheNewFrontier + +local shardOfCorruptionKill = CreatureEvent("ShardOfCorruptionDeath") + +function shardOfCorruptionKill.onDeath(creature) + onDeathForDamagingPlayers(creature, function(creature, player) + if player:getStorageValue(TheNewFrontier.Questline) == 11 then + player:setStorageValue(TheNewFrontier.Questline, 12) + end + end) + return true +end + +shardOfCorruptionKill:register() diff --git a/data-otservbr-global/scripts/quests/the_new_frontier/creaturescripts-tirecz_kill.lua b/data-otservbr-global/scripts/quests/the_new_frontier/tirecz_kill.lua similarity index 83% rename from data-otservbr-global/scripts/quests/the_new_frontier/creaturescripts-tirecz_kill.lua rename to data-otservbr-global/scripts/quests/the_new_frontier/tirecz_kill.lua index 3bd59a34450..5de50bf0eb1 100644 --- a/data-otservbr-global/scripts/quests/the_new_frontier/creaturescripts-tirecz_kill.lua +++ b/data-otservbr-global/scripts/quests/the_new_frontier/tirecz_kill.lua @@ -14,18 +14,9 @@ local function clearArena() end end -local tireczKill = CreatureEvent("TireczKill") - -function tireczKill.onKill(creature, target) - local targetMonster = target:getMonster() - if not targetMonster then - return true - end - - if targetMonster:getName():lower() ~= "tirecz" then - return true - end +local tireczKill = CreatureEvent("TireczDeath") +function tireczKill.onDeath(creature) local spectators, spectator = Game.getSpectators(Position({ x = 33063, y = 31034, z = 3 }), false, true, 10, 10, 10, 10) for i = 1, #spectators do spectator = spectators[i] diff --git a/data-otservbr-global/scripts/quests/the_rookie_guard/mission03_rational_request.lua b/data-otservbr-global/scripts/quests/the_rookie_guard/mission03_rational_request.lua index 7bd56fbd633..ee2e814656e 100644 --- a/data-otservbr-global/scripts/quests/the_rookie_guard/mission03_rational_request.lua +++ b/data-otservbr-global/scripts/quests/the_rookie_guard/mission03_rational_request.lua @@ -2,21 +2,17 @@ -- Mission Kills -local ratKill = CreatureEvent("VascalirRatKills") +local ratKill = CreatureEvent("RationalRequestRatDeath") -function ratKill.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - if not target:getName():lower() == "rat" then - return true - end - if player:getStorageValue(Storage.TheRookieGuard.Mission03) == 1 then - local counter = player:getStorageValue(Storage.TheRookieGuard.RatKills) - if counter < 5 then - player:setStorageValue(Storage.TheRookieGuard.RatKills, counter + 1) +function ratKill.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + onDeathForParty(creature, mostDamageKiller, function(creature, player) + if player:getStorageValue(Storage.TheRookieGuard.Mission03) == 1 then + local counter = player:getStorageValue(Storage.TheRookieGuard.RatKills) + if counter < 5 then + player:setStorageValue(Storage.TheRookieGuard.RatKills, counter + 1) + end end - end + end) return true end diff --git a/data-otservbr-global/scripts/quests/threatened_dreams/creaturescript-nightmare_monsters_kills.lua b/data-otservbr-global/scripts/quests/threatened_dreams/creaturescript-nightmare_monsters_kills.lua deleted file mode 100644 index 42aa18e5471..00000000000 --- a/data-otservbr-global/scripts/quests/threatened_dreams/creaturescript-nightmare_monsters_kills.lua +++ /dev/null @@ -1,33 +0,0 @@ -local nightmareMonsters = { - "enfeebled silencer", - "weakened frazzlemaw", - "kroazur", -} -local ThreatenedDreams = Storage.Quest.U11_40.ThreatenedDreams - -local threatenedDreamsNightmareMonstersKills = CreatureEvent("ThreatenedDreamsNightmareMonstersKills") -function threatenedDreamsNightmareMonstersKills.onKill(player, target) - if target:isPlayer() or target:getMaster() then - return true - end - - if not table.contains(nightmareMonsters, target:getName():lower()) then - return true - end - - local enfeebledKills = player:getStorageValue(ThreatenedDreams.Mission02.EnfeebledCount) - local frazzlemawsKills = player:getStorageValue(ThreatenedDreams.Mission02.FrazzlemawsCount) - if player:getStorageValue(ThreatenedDreams.Mission02[1]) == 1 then - player:setStorageValue(ThreatenedDreams.Mission02[1], 1) - if target:getName():lower() == nightmareMonsters[1] then - player:setStorageValue(ThreatenedDreams.Mission02.EnfeebledCount, enfeebledKills + 1) - elseif target:getName():lower() == nightmareMonsters[2] then - player:setStorageValue(ThreatenedDreams.Mission02.FrazzlemawsCount, frazzlemawsKills + 1) - elseif target:getName():lower() == nightmareMonsters[3] then - player:setStorageValue(ThreatenedDreams.Mission02.KroazurKill, 1) - end - end - return true -end - -threatenedDreamsNightmareMonstersKills:register() diff --git a/data-otservbr-global/scripts/quests/threatened_dreams/nightmare_monsters_kills.lua b/data-otservbr-global/scripts/quests/threatened_dreams/nightmare_monsters_kills.lua new file mode 100644 index 00000000000..2b66a2c1eb7 --- /dev/null +++ b/data-otservbr-global/scripts/quests/threatened_dreams/nightmare_monsters_kills.lua @@ -0,0 +1,31 @@ +local nightmareMonsters = { + "enfeebled silencer", + "weakened frazzlemaw", + "kroazur", +} +local ThreatenedDreams = Storage.Quest.U11_40.ThreatenedDreams + +local deathEvent = CreatureEvent("ThreatenedDreamsNightmareMonstersDeath") +function deathEvent.onDeath(creature, _corpse, _lastHitKiller, mostDamageKiller) + if not table.contains(nightmareMonsters, creature:getName():lower()) then + return true + end + + onDeathForParty(creature, mostDamageKiller, function(creature, player) + local enfeebledKills = player:getStorageValue(ThreatenedDreams.Mission02.EnfeebledCount) + local frazzlemawsKills = player:getStorageValue(ThreatenedDreams.Mission02.FrazzlemawsCount) + if player:getStorageValue(ThreatenedDreams.Mission02[1]) == 1 then + player:setStorageValue(ThreatenedDreams.Mission02[1], 1) + if creature:getName():lower() == nightmareMonsters[1] then + player:setStorageValue(ThreatenedDreams.Mission02.EnfeebledCount, enfeebledKills + 1) + elseif creature:getName():lower() == nightmareMonsters[2] then + player:setStorageValue(ThreatenedDreams.Mission02.FrazzlemawsCount, frazzlemawsKills + 1) + elseif creature:getName():lower() == nightmareMonsters[3] then + player:setStorageValue(ThreatenedDreams.Mission02.KroazurKill, 1) + end + end + end) + return true +end + +deathEvent:register() diff --git a/data-otservbr-global/scripts/spells/healing/mass_healing.lua b/data-otservbr-global/scripts/spells/healing/mass_healing.lua index 880c08cb666..ac412dd370d 100644 --- a/data-otservbr-global/scripts/spells/healing/mass_healing.lua +++ b/data-otservbr-global/scripts/spells/healing/mass_healing.lua @@ -58,7 +58,6 @@ spell:cooldown(2 * 1000) spell:groupCooldown(1 * 1000) spell:level(36) spell:mana(150) -spell:isAggressive(false) spell:isPremium(true) spell:isAggressive(false) spell:needLearn(false) diff --git a/data/items/items.xml b/data/items/items.xml index ec4ab6f9bbb..c46348b55b7 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -3690,7 +3690,7 @@ - + diff --git a/data/libs/functions/load.lua b/data/libs/functions/load.lua index 0ab33f5de11..9319bc97ac6 100644 --- a/data/libs/functions/load.lua +++ b/data/libs/functions/load.lua @@ -26,3 +26,4 @@ dofile(CORE_DIRECTORY .. "/libs/functions/tables.lua") dofile(CORE_DIRECTORY .. "/libs/functions/teleport.lua") dofile(CORE_DIRECTORY .. "/libs/functions/tile.lua") dofile(CORE_DIRECTORY .. "/libs/functions/vocation.lua") +dofile(CORE_DIRECTORY .. "/libs/functions/set.lua") diff --git a/data/libs/functions/party.lua b/data/libs/functions/party.lua index d33d8dbd703..c2fdffffc28 100644 --- a/data/libs/functions/party.lua +++ b/data/libs/functions/party.lua @@ -73,3 +73,16 @@ end function Party.hasDruid(self) return self:hasVocation(VOCATION.BASE_ID.DRUID) end + +function Participants(player, requireSharedExperience) + local party = player:getParty() + if not party then + return { player } + end + if requiredSharedExperience and not party:isSharedExperienceActive() then + return { player } + end + local members = party:getMembers() + table.insert(members, party:getLeader()) + return members +end diff --git a/data/libs/functions/set.lua b/data/libs/functions/set.lua new file mode 100644 index 00000000000..e3e6b6f921d --- /dev/null +++ b/data/libs/functions/set.lua @@ -0,0 +1,146 @@ +---@class Set +---@field values table +---@field options table +---@field options.insensitive boolean +---@method contains(key: any): boolean +---@method insert(key: any): void +---@method remove(key: any): void +---@method union(other: Set): Set +---@method intersection(other: Set): Set +---@method iter(): function +---@method __eq(other: Set): boolean +---@method __key(k: any): any +---@method __len(): number +---@method __tostring(): string +Set = {} + +---@param initial table|Set +---@param options table +---@return Set +setmetatable(Set, { + __call = function(self, initial, options) + local set = setmetatable({ + values = {}, + options = options or {}, + }, { __index = Set }) + if Set.isSet(initial) then + for k in initial:iter() do + set:insert(k) + end + elseif type(initial) == "table" then + for _, k in ipairs(initial) do + set:insert(k) + end + end + return set + end, +}) + +function Set.isSet(t) + local meta = getmetatable(t) + return meta and (meta == Set or meta.__index == Set) +end + +function Set:contains(key) + key = self:__key(key) + return self.values[key] ~= nil +end + +function Set:insert(key) + key = self:__key(key) + self.values[key] = true +end + +function Set:remove(key) + key = self:__key(key) + self.values[key] = nil +end + +function Set:union(other) + local set = Set(self, self.options) + for k in Set(other, self.options):iter() do + set:insert(k) + end + return set +end + +function Set:intersection(other) + local set = Set({}, self.options) + for k in Set(other, self.options):iter() do + if self:contains(k) then + set:insert(k) + end + end + return set +end + +function Set:__eq(other) + if #self ~= #other then + return false + end + for k in pairs(self.values) do + if not other:contains(k) then + return false + end + end + return true +end + +function Set:__key(k) + if self.options.insensitive then + if type(k) ~= "string" then + logger.error("key must be a string when insensitive option is enabled") + end + k = k:lower() + end + return k +end + +function Set:iter() + return pairs(self.values) +end + +function Set:__len() + return #self.values +end + +function Set:__tostring() + local t = {} + for k in self:iter() do + table.insert(t, k) + end + return "{ " .. table.concat(t, ", ") .. " }" +end + +function Set:tostring() + return self:__tostring() +end + +-- Usage: +-- local s = Set({ 1, 2, 3 }) +-- s:insert(4) +-- s:remove(2) +-- print(s:contains(1)) -- true +-- print(s:contains(2)) -- false +-- print(s:contains(3)) -- true +-- print(s:contains(4)) -- true +-- print(s:contains(5)) -- false +-- print(#s) -- 3 +-- print(s) -- { 1, 3, 4 } +-- for k in s:iter() do +-- print(k) +-- end +-- local s2 = Set({ 3, 4, 5 }) +-- print(s:union(s2)) -- { 1, 3, 4, 5 } +-- print(s2:union(s)) -- { 3, 4, 5, 1 } +-- print(s:union(s2) == s2:union(s)) -- true +-- +-- Strings +-- local s = Set({}, { insensitive = true }) +-- s:insert("a") +-- s:insert("B") +-- s:insert("c") +-- print(s) -- { a, b, c } +-- print(s:contains("a")) -- true +-- print(s:contains("A")) -- true +-- print(s:contains("b")) -- true diff --git a/data/libs/kill_lib.lua b/data/libs/kill_lib.lua new file mode 100644 index 00000000000..257be4722de --- /dev/null +++ b/data/libs/kill_lib.lua @@ -0,0 +1,21 @@ +-- Utility to combine onDeath event with a "kill" event for a player with a party (or not). + +function onDeathForParty(creature, player, func) + if not player or not player:isPlayer() then + return + end + + local participants = Participants(player, true) + for _, participant in ipairs(participants) do + func(creature, participant) + end +end + +function onDeathForDamagingPlayers(creature, func) + for key, value in pairs(creature:getDamageMap()) do + local player = Player(key) + if player then + func(creature, player) + end + end +end diff --git a/data/libs/libs.lua b/data/libs/libs.lua index ccc71dc8961..bd6164111de 100644 --- a/data/libs/libs.lua +++ b/data/libs/libs.lua @@ -32,3 +32,4 @@ dofile(CORE_DIRECTORY .. "/libs/loyalty_lib.lua") dofile(CORE_DIRECTORY .. "/libs/encounters_lib.lua") dofile(CORE_DIRECTORY .. "/libs/raids_lib.lua") dofile(CORE_DIRECTORY .. "/libs/concoctions_lib.lua") +dofile(CORE_DIRECTORY .. "/libs/kill_lib.lua") diff --git a/data/scripts/reward_chest/boss_death.lua b/data/scripts/reward_chest/boss_death.lua index f3a80909c8f..1a979e945ab 100644 --- a/data/scripts/reward_chest/boss_death.lua +++ b/data/scripts/reward_chest/boss_death.lua @@ -14,7 +14,7 @@ function bossDeath.onDeath(creature, corpse, killer, mostDamageKiller, lastHitUn -- Make sure it is a boss if monsterType and monsterType:isRewardBoss() then if not corpse.isContainer or not corpse:isContainer() then - if corpse.getId() then + if corpse.getId then logger.warn("[bossDeath.onDeath] Corpse (id: {}, name: {}) for reward boss {} is not a container.", corpse:getId(), corpse:getName(), creature:getName()) else logger.warn("[bossDeath.onDeath] Error to get corpseId from boss: {}", creature:getName()) diff --git a/data/scripts/talkactions/player/auto_loot.lua b/data/scripts/talkactions/player/auto_loot.lua index 0b03b0101bd..a5541d51438 100644 --- a/data/scripts/talkactions/player/auto_loot.lua +++ b/data/scripts/talkactions/player/auto_loot.lua @@ -16,7 +16,7 @@ function autoLoot.onSay(player, words, param) player:setStorageValue(STORAGEVALUE_AUTO_LOOT, 1) player:sendTextMessage(MESSAGE_LOOK, "You have successfully enabled your automatic looting!") elseif param == "off" then - player:setStorageValue(STORAGEVALUE_AUTO_LOOT, 0) + player:setStorageValue(STORAGEVALUE_AUTO_LOOT, -1) player:sendTextMessage(MESSAGE_LOOK, "You have successfully disabled your automatic looting!") end return true diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 6d833e0ce0b..7facada14d5 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -40,8 +40,7 @@ CanaryServer::CanaryServer( ) : logger(logger), rsa(rsa), - serviceManager(serviceManager), - loaderUniqueLock(loaderLock) { + serviceManager(serviceManager) { logInfos(); toggleForceCloseButton(); g_game().setGameState(GAME_STATE_STARTUP); @@ -93,10 +92,9 @@ int CanaryServer::run() { g_webhook().sendMessage("Server is now online", "Server has successfully started.", WEBHOOK_COLOR_ONLINE); - loaderDone = true; - loaderSignal.notify_all(); + loaderStatus = LoaderStatus::LOADED; } catch (FailedToInitializeCanary &err) { - loadFailed = true; + loaderStatus = LoaderStatus::FAILED; logger.error(err.what()); logger.error("The program will close after pressing the enter key..."); @@ -104,16 +102,16 @@ int CanaryServer::run() { if (isatty(STDIN_FILENO)) { getchar(); } - - loaderSignal.notify_all(); } + + loaderStatus.notify_one(); }, "CanaryServer::run" ); - loaderSignal.wait(loaderUniqueLock, [this] { return loaderDone || loadFailed; }); + loaderStatus.wait(LoaderStatus::LOADING); - if (loadFailed || !serviceManager.is_running()) { + if (loaderStatus == LoaderStatus::FAILED || !serviceManager.is_running()) { logger.error("No services running. The server is NOT online!"); shutdown(); return EXIT_FAILURE; diff --git a/src/canary_server.hpp b/src/canary_server.hpp index 6d75f64dc16..d9374309c4a 100644 --- a/src/canary_server.hpp +++ b/src/canary_server.hpp @@ -40,18 +40,17 @@ class CanaryServer { int run(); private: + enum class LoaderStatus : uint8_t { + LOADING, + LOADED, + FAILED + }; + RSA &rsa; Logger &logger; ServiceManager &serviceManager; - std::mutex loaderLock; - std::condition_variable loaderSignal; - std::condition_variable mapSignal; - std::unique_lock loaderUniqueLock; - std::string threadFailMsg; - - bool loaderDone = false; - bool loadFailed = false; + std::atomic loaderStatus = LoaderStatus::LOADING; void logInfos(); static void toggleForceCloseButton(); diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index c398f07a2b2..9a80ad55ce3 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -898,7 +898,7 @@ void Combat::addDistanceEffect(std::shared_ptr caster, const Position void Combat::doChainEffect(const Position &origin, const Position &dest, uint8_t effect) { if (effect > 0) { - std::forward_list dirList; + stdext::arraylist dirList(128); FindPathParams fpp; fpp.minTargetDist = 0; fpp.maxTargetDist = 1; @@ -1311,7 +1311,7 @@ std::vector>> Combat::pickChainTargets std::vector>> resultMap; std::vector> targets; - std::set visited; + phmap::flat_hash_set visited; if (initialTarget && initialTarget != caster) { targets.push_back(initialTarget); diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index f69488175bd..4cf1834e1a4 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -1929,7 +1929,7 @@ bool ConditionFeared::getFleeDirection(std::shared_ptr creature) { return false; } -bool ConditionFeared::getFleePath(std::shared_ptr creature, const Position &pos, std::forward_list &dirList) { +bool ConditionFeared::getFleePath(std::shared_ptr creature, const Position &pos, stdext::arraylist &dirList) { const std::vector walkSize { 15, 9, 3, 1 }; bool found = false; std::ptrdiff_t found_size = 0; @@ -2030,7 +2030,7 @@ bool ConditionFeared::startCondition(std::shared_ptr creature) { bool ConditionFeared::executeCondition(std::shared_ptr creature, int32_t interval) { Position currentPos = creature->getPosition(); - std::forward_list listDir; + stdext::arraylist listDir(128); g_logger().debug("[ConditionFeared::executeCondition] Executing condition, current position is {}", currentPos.toString()); @@ -2040,7 +2040,7 @@ bool ConditionFeared::executeCondition(std::shared_ptr creature, int32 } if (getFleePath(creature, currentPos, listDir)) { - g_dispatcher().addEvent(std::bind(&Game::forcePlayerAutoWalk, &g_game(), creature->getID(), listDir), "ConditionFeared::executeCondition"); + g_dispatcher().addEvent(std::bind(&Game::forcePlayerAutoWalk, &g_game(), creature->getID(), listDir.data()), "ConditionFeared::executeCondition"); g_logger().debug("[ConditionFeared::executeCondition] Walking Scheduled"); } } diff --git a/src/creatures/combat/condition.hpp b/src/creatures/combat/condition.hpp index f8228e074ca..28d637b8b87 100644 --- a/src/creatures/combat/condition.hpp +++ b/src/creatures/combat/condition.hpp @@ -333,7 +333,7 @@ class ConditionFeared final : public Condition { private: bool canWalkTo(std::shared_ptr creature, Position pos, Direction moveDirection) const; bool getFleeDirection(std::shared_ptr creature); - bool getFleePath(std::shared_ptr creature, const Position &pos, std::forward_list &dirList); + bool getFleePath(std::shared_ptr creature, const Position &pos, stdext::arraylist &dirList); bool getRandomDirection(std::shared_ptr creature, Position pos); bool isStuck(std::shared_ptr creature, Position pos) const; diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 980bab34155..2b3d9ae0ebd 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -133,16 +133,21 @@ void Creature::onThink(uint32_t interval) { } } + auto onThink = [self = getCreature(), interval] { + // scripting event - onThink + const auto &thinkEvents = self->getCreatureEvents(CREATURE_EVENT_THINK); + for (const auto creatureEventPtr : thinkEvents) { + creatureEventPtr->executeOnThink(self->static_self_cast(), interval); + } + }; + if (isUpdatingPath) { isUpdatingPath = false; - goToFollowCreature(); + goToFollowCreature_async(onThink); + return; } - // scripting event - onThink - const CreatureEventList &thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); - for (const auto creatureEventPtr : thinkEvents) { - creatureEventPtr->executeOnThink(static_self_cast(), interval); - } + onThink(); } void Creature::onAttacking(uint32_t interval) { @@ -224,18 +229,20 @@ bool Creature::getNextStep(Direction &dir, uint32_t &) { return true; } -void Creature::startAutoWalk(const std::forward_list &listDir, bool ignoreConditions /* = false*/) { +void Creature::startAutoWalk(const std::vector &listDir, bool ignoreConditions /* = false*/) { + listWalkDir.clear(); + if (!ignoreConditions && (hasCondition(CONDITION_ROOTED) || hasCondition(CONDITION_FEARED))) { return; } - listWalkDir = listDir; + listWalkDir = { listDir.begin(), listDir.end() }; - size_t size = 0; - for (auto it = listDir.begin(); it != listDir.end() && size <= 1; ++it) { - size++; + if (listWalkDir.empty()) { + return; } - addEventWalk(size == 1); + + addEventWalk(listWalkDir.size() == 1); } void Creature::addEventWalk(bool firstStep) { @@ -249,20 +256,22 @@ void Creature::addEventWalk(bool firstStep) { return; } - int64_t ticks = getEventStepTicks(firstStep); + const int64_t ticks = getEventStepTicks(firstStep); if (ticks <= 0) { return; } - // Take first step right away, but still queue the next - if (ticks == 1) { - g_game().checkCreatureWalk(getID()); - } + g_dispatcher().context().tryAddEvent([ticks, self = getCreature()]() { + // Take first step right away, but still queue the next + if (ticks == 1) { + g_game().checkCreatureWalk(self->getID()); + } - eventWalk = g_dispatcher().scheduleEvent( - static_cast(ticks), std::bind(&Game::checkCreatureWalk, &g_game(), getID()), - "Creature::checkCreatureWalk" - ); + self->eventWalk = g_dispatcher().scheduleEvent( + static_cast(ticks), std::bind(&Game::checkCreatureWalk, &g_game(), self->getID()), + "Creature::checkCreatureWalk" + ); + }); } void Creature::stopEventWalk() { @@ -320,11 +329,7 @@ int32_t Creature::getWalkCache(const Position &pos) { if (std::abs(dx) <= maxWalkCacheWidth) { int32_t dy = Position::getOffsetY(pos, myPos); if (std::abs(dy) <= maxWalkCacheHeight) { - if (localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx]) { - return 1; - } else { - return 0; - } + return localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx]; } } @@ -426,9 +431,9 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { if (hasSummons()) { std::vector> despawnMonsterList; for (const auto &summon : getSummons()) { - const Position &pos = summon->getPosition(); - std::shared_ptr monster = summon->getMonster(); - auto tile = getTile(); + const auto &pos = summon->getPosition(); + const auto &monster = summon->getMonster(); + const auto &tile = getTile(); bool protectionZoneCheck = tile ? tile->hasFlag(TILESTATE_PROTECTIONZONE) : false; // Check if any of our summons is out of range (+/- 0 floors or 15 tiles away) bool checkSummonDist = Position::getDistanceZ(newPos, pos) > 0 || (std::max(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 15); @@ -436,12 +441,12 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { bool checkRemoveDist = Position::getDistanceZ(newPos, pos) > 2 || (std::max(Position::getDistanceX(newPos, pos), Position::getDistanceY(newPos, pos)) > 30); if (monster && monster->isFamiliar() && checkSummonDist || teleportSummon && !protectionZoneCheck && checkSummonDist) { - auto creatureMaster = summon->getMaster(); + const auto &creatureMaster = summon->getMaster(); if (!creatureMaster) { continue; } - if (std::shared_ptr masterTile = creatureMaster->getTile()) { + if (const auto &masterTile = creatureMaster->getTile()) { if (masterTile->hasFlag(TILESTATE_TELEPORT)) { g_logger().warn("[{}] cannot teleport summon, position has teleport. {}", __FUNCTION__, creatureMaster->getPosition().toString()); } else { @@ -456,7 +461,7 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { } } - for (std::shared_ptr despawnCreature : despawnMonsterList) { + for (const auto &despawnCreature : despawnMonsterList) { if (!despawnMonsterList.empty()) { g_game().removeCreature(despawnCreature, true); } @@ -464,7 +469,7 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { } } -void Creature::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Creature::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { if (creature == getCreature()) { lastStep = OTSYS_TIME(); lastStepCost = 1; @@ -512,7 +517,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt // update 0 for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) { - std::shared_ptr cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() - maxWalkCacheHeight), myPos.z); + const auto &cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() - maxWalkCacheHeight), myPos.z); updateTileCache(cacheTile, x, -maxWalkCacheHeight); } } else if (oldPos.y < newPos.y) { // south @@ -523,7 +528,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt // update mapWalkHeight - 1 for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) { - std::shared_ptr cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() + maxWalkCacheHeight), myPos.z); + const auto &cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() + maxWalkCacheHeight), myPos.z); updateTileCache(cacheTile, x, maxWalkCacheHeight); } } @@ -548,7 +553,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt // update mapWalkWidth - 1 for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) { - std::shared_ptr cacheTile = g_game().map.getTile(myPos.x + maxWalkCacheWidth, static_cast(myPos.y + y), myPos.z); + const auto &cacheTile = g_game().map.getTile(myPos.x + maxWalkCacheWidth, static_cast(myPos.y + y), myPos.z); updateTileCache(cacheTile, maxWalkCacheWidth, y); } } else if (oldPos.x > newPos.x) { // west @@ -593,7 +598,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt } } - auto followCreature = getFollowCreature(); + const auto &followCreature = getFollowCreature(); if (followCreature && (creature == getCreature() || creature == followCreature)) { if (hasFollowPath) { isUpdatingPath = true; @@ -605,7 +610,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt } } - auto attackedCreature = getAttackedCreature(); + const auto &attackedCreature = getAttackedCreature(); if (attackedCreature && (creature == attackedCreature || creature == getCreature())) { if (newPos.z != oldPos.z || !canSee(attackedCreature->getPosition())) { onCreatureDisappear(attackedCreature, false); @@ -948,7 +953,7 @@ bool Creature::setAttackedCreature(std::shared_ptr creature) { return true; } -void Creature::getPathSearchParams(std::shared_ptr, FindPathParams &fpp) { +void Creature::getPathSearchParams(const std::shared_ptr &, FindPathParams &fpp) { fpp.fullPathSearch = !hasFollowPath; fpp.clearSight = true; fpp.maxSearchDist = 12; @@ -956,55 +961,64 @@ void Creature::getPathSearchParams(std::shared_ptr, FindPathParams &fp fpp.maxTargetDist = 1; } +void Creature::goToFollowCreature_async(std::function &&onComplete) { + if (pathfinderRunning.load()) { + return; + } + + pathfinderRunning.store(true); + g_dispatcher().asyncEvent([self = getCreature()] { + self->goToFollowCreature(); + self->pathfinderRunning.store(false); + }); + + if (onComplete) { + g_dispatcher().context().addEvent(std::move(onComplete)); + } +} + void Creature::goToFollowCreature() { - auto followCreature = getFollowCreature(); - if (followCreature) { - if (isSummon() && !getMonster()->isFamiliar() && !canFollowMaster()) { - hasFollowPath = false; - return; - } + const auto &followCreature = getFollowCreature(); + if (!followCreature) { + return; + } - FindPathParams fpp; - getPathSearchParams(followCreature, fpp); - std::shared_ptr monster = getMonster(); - if (monster && !monster->getMaster() && (monster->isFleeing() || fpp.maxTargetDist > 1)) { - Direction dir = DIRECTION_NONE; - - if (monster->isFleeing()) { - monster->getDistanceStep(followCreature->getPosition(), dir, true); - } else { // maxTargetDist > 1 - if (!monster->getDistanceStep(followCreature->getPosition(), dir)) { - // if we can't get anything then let the A* calculate - listWalkDir.clear(); - if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) { - hasFollowPath = true; - startAutoWalk(listWalkDir); - } else { - hasFollowPath = false; - } - return; - } - } + const auto &monster = getMonster(); - if (dir != DIRECTION_NONE) { - listWalkDir.clear(); - listWalkDir.push_front(dir); + if (isSummon() && !monster->isFamiliar() && !canFollowMaster()) { + listWalkDir.clear(); + return; + } - hasFollowPath = true; - startAutoWalk(listWalkDir); - } - } else { - listWalkDir.clear(); - if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) { - hasFollowPath = true; - startAutoWalk(listWalkDir); - } else { - hasFollowPath = false; - } + bool executeOnFollow = true; + stdext::arraylist listDir(128); + + FindPathParams fpp; + getPathSearchParams(followCreature, fpp); + + if (monster && !monster->getMaster() && (monster->isFleeing() || fpp.maxTargetDist > 1)) { + Direction dir = DIRECTION_NONE; + + if (monster->isFleeing()) { + monster->getDistanceStep(followCreature->getPosition(), dir, true); + } else if (!monster->getDistanceStep(followCreature->getPosition(), dir)) { // maxTargetDist > 1 + // if we can't get anything then let the A* calculate + executeOnFollow = false; + } else if (dir != DIRECTION_NONE) { + listDir.push_back(dir); + hasFollowPath = true; } } - onFollowCreatureComplete(followCreature); + if (listDir.empty()) { + hasFollowPath = getPathTo(getFollowCreature()->getPosition(), listDir, fpp); + } + + startAutoWalk(listDir.data()); + + if (executeOnFollow) { + onFollowCreatureComplete(getFollowCreature()); + } } bool Creature::canFollowMaster() { @@ -1229,13 +1243,16 @@ bool Creature::setMaster(std::shared_ptr newMaster, bool reloadCreatur g_game().reloadCreature(self); } if (newMaster) { - newMaster->m_summons.insert(self); + newMaster->m_summons.emplace_back(self); } m_master = newMaster; if (oldMaster) { - oldMaster->m_summons.erase(self); + const auto &it = std::ranges::find(oldMaster->m_summons, self); + if (it != oldMaster->m_summons.end()) { + oldMaster->m_summons.erase(it); + } } return true; } @@ -1248,7 +1265,6 @@ bool Creature::addCondition(std::shared_ptr condition) { std::shared_ptr prevCond = getCondition(condition->getType(), condition->getId(), condition->getSubId()); if (prevCond) { prevCond->addCondition(getCreature(), condition); - return true; } @@ -1638,11 +1654,11 @@ bool Creature::isInvisible() const { != conditions.end(); } -bool Creature::getPathTo(const Position &targetPos, std::forward_list &dirList, const FindPathParams &fpp) { +bool Creature::getPathTo(const Position &targetPos, stdext::arraylist &dirList, const FindPathParams &fpp) { return g_game().map.getPathMatching(getCreature(), dirList, FrozenPathingConditionCall(targetPos), fpp); } -bool Creature::getPathTo(const Position &targetPos, std::forward_list &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 7*/) { +bool Creature::getPathTo(const Position &targetPos, stdext::arraylist &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 7*/) { FindPathParams fpp; fpp.fullPathSearch = fullPathSearch; fpp.maxSearchDist = maxSearchDist; @@ -1783,9 +1799,8 @@ void Creature::setIncreasePercent(CombatType_t combat, int32_t value) { } } -phmap::flat_hash_set> Creature::getZones() { - auto tile = getTile(); - if (tile) { +std::unordered_set> Creature::getZones() { + if (const auto &tile = getTile()) { return tile->getZones(); } return {}; diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index 0195ec17c30..e6e8e005ee7 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -43,6 +43,10 @@ class FrozenPathingConditionCall { bool isInRange(const Position &startPos, const Position &testPos, const FindPathParams &fpp) const; + Position getTargetPos() const { + return targetPos; + } + private: Position targetPos; }; @@ -263,12 +267,14 @@ class Creature : virtual public Thing, public SharedObject { return ZONE_NORMAL; } - phmap::flat_hash_set> getZones(); + std::unordered_set> getZones(); // walk functions - void startAutoWalk(const std::forward_list &listDir, bool ignoreConditions = false); + void startAutoWalk(const std::vector &listDir, bool ignoreConditions = false); void addEventWalk(bool firstStep = false); void stopEventWalk(); + + void goToFollowCreature_async(std::function &&onComplete = nullptr); virtual void goToFollowCreature(); // walk events @@ -283,8 +289,12 @@ class Creature : virtual public Thing, public SharedObject { virtual bool setFollowCreature(std::shared_ptr creature); // follow events - virtual void onFollowCreature(std::shared_ptr) { } - virtual void onFollowCreatureComplete(std::shared_ptr) { } + virtual void onFollowCreature(const std::shared_ptr &) { + /* empty */ + } + virtual void onFollowCreatureComplete(const std::shared_ptr &) { + /* empty */ + } // combat functions std::shared_ptr getAttackedCreature() { @@ -331,7 +341,7 @@ class Creature : virtual public Thing, public SharedObject { return m_master.lock(); } - const phmap::flat_hash_set> &getSummons() const { + const auto &getSummons() const { return m_summons; } @@ -446,7 +456,7 @@ class Creature : virtual public Thing, public SharedObject { * @return false */ void checkSummonMove(const Position &newPos, bool teleportSummon = false); - virtual void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport); + virtual void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport); virtual void onAttackedCreatureDisappear(bool) { } virtual void onFollowCreatureDisappear(bool) { } @@ -524,8 +534,8 @@ class Creature : virtual public Thing, public SharedObject { double getDamageRatio(std::shared_ptr attacker) const; - bool getPathTo(const Position &targetPos, std::forward_list &dirList, const FindPathParams &fpp); - bool getPathTo(const Position &targetPos, std::forward_list &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 7); + bool getPathTo(const Position &targetPos, stdext::arraylist &dirList, const FindPathParams &fpp); + bool getPathTo(const Position &targetPos, stdext::arraylist &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 7); struct CountBlock_t { int32_t total; @@ -656,11 +666,11 @@ class Creature : virtual public Thing, public SharedObject { CountMap damageMap; - phmap::flat_hash_set> m_summons; + std::vector> m_summons; CreatureEventList eventsList; ConditionList conditions; - std::forward_list listWalkDir; + std::deque listWalkDir; std::weak_ptr m_tile; std::weak_ptr m_attackedCreature; @@ -721,16 +731,18 @@ class Creature : virtual public Thing, public SharedObject { bool skillLoss = true; bool lootDrop = true; bool cancelNextWalk = false; - bool hasFollowPath = false; bool forceUpdateFollowPath = false; bool hiddenHealth = false; bool floorChange = false; bool canUseDefense = true; bool moveLocked = false; + bool hasFollowPath = false; int8_t charmChanceModifier = 0; uint8_t wheelOfDestinyDrainBodyDebuff = 0; + std::atomic_bool pathfinderRunning = false; + // use map here instead of phmap to keep the keys in a predictable order std::map creatureIcons = {}; @@ -756,7 +768,7 @@ class Creature : virtual public Thing, public SharedObject { virtual uint16_t getLookCorpse() const { return 0; } - virtual void getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp); + virtual void getPathSearchParams(const std::shared_ptr &, FindPathParams &fpp); virtual void death(std::shared_ptr) { } virtual bool dropCorpse(std::shared_ptr lastHitCreature, std::shared_ptr mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified); virtual std::shared_ptr getCorpse(std::shared_ptr lastHitCreature, std::shared_ptr mostDamageCreature); @@ -769,4 +781,5 @@ class Creature : virtual public Thing, public SharedObject { bool canFollowMaster(); bool isLostSummon(); void handleLostSummon(bool teleportSummons); + void executeAsyncPathTo(bool executeOnFollow, FindPathParams &fpp, std::function &&onComplete); }; diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index 9bef75a5ecb..97c18e6d855 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -178,7 +178,7 @@ void Monster::onRemoveCreature(std::shared_ptr creature, bool isLogout } } -void Monster::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Monster::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); if (mType->info.creatureMoveEvent != -1) { @@ -596,16 +596,17 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL return false; } -void Monster::onFollowCreatureComplete(std::shared_ptr creature) { +void Monster::onFollowCreatureComplete(const std::shared_ptr &creature) { if (!creature) { return; } + auto it = std::find(targetIDList.begin(), targetIDList.end(), creature->getID()); - if (it != targetIDList.end()) { - auto target = targetListMap[*it].lock(); - if (!target) { - return; - } + if (it == targetIDList.end()) { + return; + } + + if (const auto &target = targetListMap[*it].lock()) { targetIDList.erase(it); if (hasFollowPath) { @@ -870,7 +871,7 @@ void Monster::doAttacking(uint32_t interval) { } } -bool Monster::canUseAttack(const Position &pos, std::shared_ptr target) const { +bool Monster::canUseAttack(const Position &pos, const std::shared_ptr &target) const { if (isHostile()) { const Position &targetPos = target->getPosition(); uint32_t distance = std::max(Position::getDistanceX(pos, targetPos), Position::getDistanceY(pos, targetPos)); @@ -2066,7 +2067,7 @@ bool Monster::isImmune(CombatType_t combatType) const { return mType->info.m_damageImmunities[combatTypeToIndex(combatType)]; } -void Monster::getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) { +void Monster::getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) { Creature::getPathSearchParams(creature, fpp); fpp.minTargetDist = 1; diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index adcb0258503..29182fe6865 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -17,7 +17,6 @@ class Creature; class Game; class Spawn; -using CreatureHashSet = phmap::flat_hash_set>; using CreatureList = std::list>; using CreatureWeakHashMap = phmap::flat_hash_map>; @@ -99,7 +98,7 @@ class Monster final : public Creature { if (master && master->getMonster()) { return master->getMonster()->isEnemyFaction(faction); } - return mType->info.enemyFactions.empty() ? false : mType->info.enemyFactions.find(faction) != mType->info.enemyFactions.end(); + return mType->info.enemyFactions.empty() ? false : mType->info.enemyFactions.contains(faction); } bool isPushable() override { @@ -147,13 +146,13 @@ class Monster final : public Creature { void onCreatureAppear(std::shared_ptr creature, bool isLogin) override; void onRemoveCreature(std::shared_ptr creature, bool isLogout) override; - void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) override; + void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) override; void onCreatureSay(std::shared_ptr creature, SpeakClasses type, const std::string &text) override; void drainHealth(std::shared_ptr attacker, int32_t damage) override; void changeHealth(int32_t healthChange, bool sendHealthChange = true) override; bool getNextStep(Direction &direction, uint32_t &flags) override; - void onFollowCreatureComplete(std::shared_ptr creature) override; + void onFollowCreatureComplete(const std::shared_ptr &creature) override; void onThink(uint32_t interval) override; @@ -204,17 +203,19 @@ class Monster final : public Creature { } return list; } - CreatureHashSet getFriendList() { - CreatureHashSet set; + + std::vector> getFriendList() { + std::vector> list; + for (auto it = friendList.begin(); it != friendList.end();) { if (auto friendCreature = it->second.lock()) { - set.insert(friendCreature); + list.emplace_back(friendCreature); ++it; } else { it = friendList.erase(it); } } - return set; + return list; } bool isTarget(std::shared_ptr creature); @@ -407,7 +408,7 @@ class Monster final : public Creature { void onAddCondition(ConditionType_t type) override; void onEndCondition(ConditionType_t type) override; - bool canUseAttack(const Position &pos, std::shared_ptr target) const; + bool canUseAttack(const Position &pos, const std::shared_ptr &target) const; bool canUseSpell(const Position &pos, const Position &targetPos, const spellBlock_t &sb, uint32_t interval, bool &inRange, bool &resetTicks); bool getRandomStep(const Position &creaturePos, Direction &direction); bool getDanceStep(const Position &creaturePos, Direction &direction, bool keepAttack = true, bool keepDistance = true); @@ -434,7 +435,7 @@ class Monster final : public Creature { return mType->info.lookcorpse; } void dropLoot(std::shared_ptr corpse, std::shared_ptr lastHitCreature) override; - void getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) override; + void getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) override; bool useCacheMap() const override { return !randomStepping; } diff --git a/src/creatures/monsters/monsters.hpp b/src/creatures/monsters/monsters.hpp index e0cc79b88e9..a4723fcaac2 100644 --- a/src/creatures/monsters/monsters.hpp +++ b/src/creatures/monsters/monsters.hpp @@ -136,7 +136,7 @@ class MonsterType { bool targetPreferMaster = false; Faction_t faction = FACTION_DEFAULT; - phmap::flat_hash_set enemyFactions; + stdext::vector_set enemyFactions; bool canPushItems = false; bool canPushCreatures = false; diff --git a/src/creatures/npcs/npc.cpp b/src/creatures/npcs/npc.cpp index 89eabdae28b..431d3113ccd 100644 --- a/src/creatures/npcs/npc.cpp +++ b/src/creatures/npcs/npc.cpp @@ -113,7 +113,7 @@ void Npc::onRemoveCreature(std::shared_ptr creature, bool isLogout) { shopPlayerMap.clear(); } -void Npc::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Npc::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); // onCreatureMove(self, creature, oldPosition, newPosition) @@ -134,7 +134,7 @@ void Npc::onCreatureMove(std::shared_ptr creature, std::shared_ptrgetPlayer()) { + if (const auto &player = creature->getPlayer()) { handlePlayerMove(player, newPos); } } @@ -151,7 +151,7 @@ void Npc::onPlayerAppear(std::shared_ptr player) { if (player->hasFlag(PlayerFlags_t::IgnoredByNpcs) || playerSpectators.contains(player)) { return; } - playerSpectators.emplace_back(player); + playerSpectators.emplace(player); manageIdle(); } @@ -531,7 +531,7 @@ void Npc::onThinkWalk(uint32_t interval) { void Npc::onCreatureWalk() { Creature::onCreatureWalk(); - playerSpectators.erase_if([this](const auto &creature) { return !this->canSee(creature->getPosition()); }); + phmap::erase_if(playerSpectators, [this](const auto &creature) { return !this->canSee(creature->getPosition()); }); } void Npc::onPlacedCreature() { @@ -542,7 +542,7 @@ void Npc::loadPlayerSpectators() { auto spec = Spectators().find(position, true); for (const auto &creature : spec) { if (!creature->getPlayer()->hasFlag(PlayerFlags_t::IgnoredByNpcs)) { - playerSpectators.emplace_back(creature->getPlayer()); + playerSpectators.emplace(creature->getPlayer()); } } } diff --git a/src/creatures/npcs/npc.hpp b/src/creatures/npcs/npc.hpp index 27f46cbeec6..993934374d5 100644 --- a/src/creatures/npcs/npc.hpp +++ b/src/creatures/npcs/npc.hpp @@ -137,7 +137,7 @@ class Npc final : public Creature { void onCreatureAppear(std::shared_ptr creature, bool isLogin) override; void onRemoveCreature(std::shared_ptr creature, bool isLogout) override; - void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) override; + void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) override; void onCreatureSay(std::shared_ptr creature, SpeakClasses type, const std::string &text) override; void onThink(uint32_t interval) override; void onPlayerBuyItem(std::shared_ptr player, uint16_t itemid, uint8_t count, uint16_t amount, bool ignore, bool inBackpacks); @@ -188,7 +188,7 @@ class Npc final : public Creature { bool ignoreHeight; - stdext::vector_set> playerSpectators; + phmap::flat_hash_set> playerSpectators; Position masterPos; friend class LuaScriptInterface; diff --git a/src/creatures/players/management/ban.cpp b/src/creatures/players/management/ban.cpp index 0c08fdc6f1e..3315836ebea 100644 --- a/src/creatures/players/management/ban.cpp +++ b/src/creatures/players/management/ban.cpp @@ -15,7 +15,7 @@ #include "utils/tools.hpp" bool Ban::acceptConnection(uint32_t clientIP) { - std::lock_guard lockClass(lock); + std::scoped_lock lockClass(lock); uint64_t currentTime = OTSYS_TIME(); diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index aba77e44c60..d26952bc54c 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -484,54 +484,48 @@ uint32_t Player::getClientIcons() { } void Player::addMonsterToCyclopediaTrackerList(const std::shared_ptr mtype, bool isBoss, bool reloadClient /* = false */) { - if (client) { - uint16_t raceId = mtype ? mtype->info.raceid : 0; - // Bostiary tracker logic - if (isBoss) { - m_bosstiaryMonsterTracker.insert(mtype); - if (reloadClient && raceId != 0) { + if (!client) { + return; + } + + const uint16_t raceId = mtype ? mtype->info.raceid : 0; + auto &tracker = isBoss ? m_bosstiaryMonsterTracker : m_bestiaryMonsterTracker; + if (tracker.emplace(mtype).second) { + if (reloadClient && raceId != 0) { + if (isBoss) { client->parseSendBosstiary(); + } else { + client->sendBestiaryEntryChanged(raceId); } - client->refreshCyclopediaMonsterTracker(m_bosstiaryMonsterTracker, true); - return; } - // Bestiary tracker logic - m_bestiaryMonsterTracker.insert(mtype); - if (reloadClient && raceId != 0) { - client->sendBestiaryEntryChanged(raceId); - } - client->refreshCyclopediaMonsterTracker(m_bestiaryMonsterTracker, false); + client->refreshCyclopediaMonsterTracker(tracker, isBoss); } } void Player::removeMonsterFromCyclopediaTrackerList(std::shared_ptr mtype, bool isBoss, bool reloadClient /* = false */) { - if (client) { - uint16_t raceId = mtype ? mtype->info.raceid : 0; - // Bostiary tracker logic - if (isBoss) { - m_bosstiaryMonsterTracker.erase(mtype); - if (reloadClient && raceId != 0) { + if (!client) { + return; + } + + const uint16_t raceId = mtype ? mtype->info.raceid : 0; + auto &tracker = isBoss ? m_bosstiaryMonsterTracker : m_bestiaryMonsterTracker; + + if (tracker.erase(mtype) > 0) { + if (reloadClient && raceId != 0) { + if (isBoss) { client->parseSendBosstiary(); + } else { + client->sendBestiaryEntryChanged(raceId); } - client->refreshCyclopediaMonsterTracker(m_bosstiaryMonsterTracker, true); - return; } - // Bestiary tracker logic - m_bestiaryMonsterTracker.erase(mtype); - if (reloadClient && raceId != 0) { - client->sendBestiaryEntryChanged(raceId); - } - client->refreshCyclopediaMonsterTracker(m_bestiaryMonsterTracker, false); + client->refreshCyclopediaMonsterTracker(tracker, isBoss); } } -bool Player::isBossOnBosstiaryTracker(const std::shared_ptr monsterType) const { - if (!monsterType) { - return false; - } - return m_bosstiaryMonsterTracker.contains(monsterType); +bool Player::isBossOnBosstiaryTracker(const std::shared_ptr &monsterType) const { + return monsterType ? m_bosstiaryMonsterTracker.contains(monsterType) : false; } void Player::updateInventoryWeight() { @@ -1830,10 +1824,10 @@ void Player::onWalk(Direction &dir) { setNextAction(OTSYS_TIME() + getStepDuration(dir)); } -void Player::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Player::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); - auto followCreature = getFollowCreature(); + const auto &followCreature = getFollowCreature(); if (hasFollowPath && (creature == followCreature || (creature.get() == this && followCreature))) { isUpdatingPath = false; g_dispatcher().addEvent(std::bind(&Game::updateCreatureWalk, &g_game(), getID()), "Game::updateCreatureWalk"); @@ -1850,7 +1844,7 @@ void Player::onCreatureMove(std::shared_ptr creature, std::shared_ptr< } if (tradePartner && !Position::areInRange<2, 2, 0>(tradePartner->getPosition(), getPosition())) { - g_game().internalCloseTrade(static_self_cast()); + g_game().internalCloseTrade(getPlayer()); } } @@ -1873,13 +1867,13 @@ void Player::onCreatureMove(std::shared_ptr creature, std::shared_ptr< if (party) { party->updateSharedExperience(); - party->updatePlayerStatus(static_self_cast(), oldPos, newPos); + party->updatePlayerStatus(getPlayer(), oldPos, newPos); } if (teleport || oldPos.z != newPos.z) { int32_t ticks = g_configManager().getNumber(STAIRHOP_DELAY); if (ticks > 0) { - if (std::shared_ptr condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks, 0)) { + if (const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks, 0)) { addCondition(condition); } } @@ -2925,7 +2919,7 @@ void Player::removePlayer(bool displayEffect, bool forced /*= true*/) { } } -void Player::notifyStatusChange(std::shared_ptr loginPlayer, VipStatus_t status, bool message) { +void Player::notifyStatusChange(std::shared_ptr loginPlayer, VipStatus_t status, bool message) const { if (!client) { return; } @@ -2989,7 +2983,7 @@ bool Player::addVIPInternal(uint32_t vipGuid) { return VIPList.insert(vipGuid).second; } -bool Player::editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify) { +bool Player::editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify) const { auto it = VIPList.find(vipGuid); if (it == VIPList.end()) { return false; // player is not in VIP @@ -4223,7 +4217,7 @@ void Player::goToFollowCreature() { } } -void Player::getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) { +void Player::getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) { Creature::getPathSearchParams(creature, fpp); fpp.fullPathSearch = true; } @@ -4287,7 +4281,7 @@ uint64_t Player::getGainedExperience(std::shared_ptr attacker) const { return 0; } -void Player::onFollowCreature(std::shared_ptr creature) { +void Player::onFollowCreature(const std::shared_ptr &creature) { if (!creature) { stopWalk(); } @@ -7558,9 +7552,9 @@ SoundEffect_t Player::getAttackSoundEffect() const { bool Player::canAutoWalk(const Position &toPosition, const std::function &function, uint32_t delay /* = 500*/) { if (!Position::areInRange<1, 1>(getPosition(), toPosition)) { // Check if can walk to the toPosition and send event to use function - std::forward_list listDir; + stdext::arraylist listDir(128); if (getPathTo(toPosition, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, &g_game(), getID(), listDir), __FUNCTION__); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, &g_game(), getID(), listDir.data()), __FUNCTION__); std::shared_ptr task = createPlayerTask(delay, function, __FUNCTION__); setNextWalkActionTask(task); diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 83b28e88364..418f8659e49 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -304,7 +304,7 @@ class Player final : public Creature, public Cylinder, public Bankable { return guildWarVector; } - const phmap::parallel_flat_hash_set> &getCyclopediaMonsterTrackerSet(bool isBoss) const { + const std::unordered_set> &getCyclopediaMonsterTrackerSet(bool isBoss) const { return isBoss ? m_bosstiaryMonsterTracker : m_bestiaryMonsterTracker; } @@ -318,17 +318,17 @@ class Player final : public Creature, public Cylinder, public Bankable { } } - void refreshCyclopediaMonsterTracker(bool isBoss = false) const { + void refreshCyclopediaMonsterTracker(bool isBoss = false) { refreshCyclopediaMonsterTracker(getCyclopediaMonsterTrackerSet(isBoss), isBoss); } - void refreshCyclopediaMonsterTracker(const phmap::parallel_flat_hash_set> &trackerList, bool isBoss) const { + void refreshCyclopediaMonsterTracker(const std::unordered_set> &trackerList, bool isBoss) const { if (client) { client->refreshCyclopediaMonsterTracker(trackerList, isBoss); } } - bool isBossOnBosstiaryTracker(const std::shared_ptr monsterType) const; + bool isBossOnBosstiaryTracker(const std::shared_ptr &monsterType) const; Vocation* getVocation() const { return vocation; @@ -804,18 +804,18 @@ class Player final : public Creature, public Cylinder, public Bankable { } // V.I.P. functions - void notifyStatusChange(std::shared_ptr player, VipStatus_t status, bool message = true); + void notifyStatusChange(std::shared_ptr player, VipStatus_t status, bool message = true) const; bool removeVIP(uint32_t vipGuid); bool addVIP(uint32_t vipGuid, const std::string &vipName, VipStatus_t status); bool addVIPInternal(uint32_t vipGuid); - bool editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify); + bool editVIP(uint32_t vipGuid, const std::string &description, uint32_t icon, bool notify) const; // follow functions bool setFollowCreature(std::shared_ptr creature) override; void goToFollowCreature() override; // follow events - void onFollowCreature(std::shared_ptr creature) override; + void onFollowCreature(const std::shared_ptr &) override; // walk events void onWalk(Direction &dir) override; @@ -1230,7 +1230,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void onCreatureAppear(std::shared_ptr creature, bool isLogin) override; void onRemoveCreature(std::shared_ptr creature, bool isLogout) override; - void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) override; + void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) override; void onAttackedCreatureDisappear(bool isLogout) override; void onFollowCreatureDisappear(bool isLogout) override; @@ -2502,7 +2502,7 @@ class Player final : public Creature, public Cylinder, public Bankable { } bool checkAutoLoot() const { - const bool autoLoot = g_configManager().getBoolean(AUTOLOOT) && getStorageValue(STORAGEVALUE_AUTO_LOOT) != 0; + const bool autoLoot = g_configManager().getBoolean(AUTOLOOT) && getStorageValue(STORAGEVALUE_AUTO_LOOT) > 0; if (g_configManager().getBoolean(VIP_SYSTEM_ENABLED) && g_configManager().getBoolean(VIP_AUTOLOOT_VIP_ONLY)) { return autoLoot && isVip(); } @@ -2609,7 +2609,6 @@ class Player final : public Creature, public Cylinder, public Bankable { bool onKilledMonster(const std::shared_ptr &target, bool lastHit); phmap::flat_hash_set attackedSet; - phmap::flat_hash_set VIPList; std::map openContainers; @@ -2646,8 +2645,8 @@ class Player final : public Creature, public Cylinder, public Bankable { // TODO: This variable is only temporarily used when logging in, get rid of it somehow. std::forward_list> storedConditionList; - phmap::parallel_flat_hash_set> m_bestiaryMonsterTracker; - phmap::parallel_flat_hash_set> m_bosstiaryMonsterTracker; + std::unordered_set> m_bestiaryMonsterTracker; + std::unordered_set> m_bosstiaryMonsterTracker; std::string name; std::string guildNick; @@ -2888,7 +2887,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void addConditionSuppression(const std::array &addConditions); uint16_t getLookCorpse() const override; - void getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) override; + void getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) override; void setDead(bool isDead) { dead = isDead; diff --git a/src/game/game.cpp b/src/game/game.cpp index 76c83737f60..64cbf5cec97 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1144,9 +1144,9 @@ void Game::playerMoveCreature(std::shared_ptr player, std::shared_ptr(movingCreatureOrigPos, player->getPosition())) { // need to walk to the creature first before moving it - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(movingCreatureOrigPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(600, std::bind(&Game::playerMoveCreatureByID, this, player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()), "Game::playerMoveCreatureByID"); @@ -1441,9 +1441,9 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo if (!Position::areInRange<1, 1>(playerPos, mapFromPos)) { // need to walk to the item first before using it - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(item->getPosition(), listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), fromPos, itemId, fromStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); player->setNextWalkActionTask(task); @@ -1498,9 +1498,9 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo internalGetPosition(moveItem, itemPos, itemStackPos); } - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(walkPos, listDir, 0, 0, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), itemPos, itemId, itemStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); player->setNextWalkActionTask(task); @@ -3020,7 +3020,7 @@ void Game::playerMove(uint32_t playerId, Direction direction) { player->setNextWalkActionTask(nullptr); player->cancelPush(); - player->startAutoWalk(std::forward_list { direction }, false); + player->startAutoWalk(std::vector { direction }, false); } void Game::forcePlayerMove(uint32_t playerId, Direction direction) { @@ -3033,7 +3033,7 @@ void Game::forcePlayerMove(uint32_t playerId, Direction direction) { player->setNextWalkActionTask(nullptr); player->cancelPush(); - player->startAutoWalk(std::forward_list { direction }, true); + player->startAutoWalk(std::vector { direction }, true); } bool Game::playerBroadcastMessage(std::shared_ptr player, const std::string &text) const { @@ -3198,7 +3198,7 @@ void Game::playerReceivePingBack(uint32_t playerId) { player->sendPingBack(); } -void Game::playerAutoWalk(uint32_t playerId, const std::forward_list &listDir) { +void Game::playerAutoWalk(uint32_t playerId, const std::vector &listDir) { std::shared_ptr player = getPlayerByID(playerId); if (!player) { return; @@ -3209,7 +3209,7 @@ void Game::playerAutoWalk(uint32_t playerId, const std::forward_list player->startAutoWalk(listDir, false); } -void Game::forcePlayerAutoWalk(uint32_t playerId, const std::forward_list &listDir) { +void Game::forcePlayerAutoWalk(uint32_t playerId, const std::vector &listDir) { std::shared_ptr player = getPlayerByID(playerId); if (!player) { return; @@ -3298,9 +3298,9 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f internalGetPosition(moveItem, itemPos, itemStackPos); } - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseItemEx, this, playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId), "Game::playerUseItemEx"); if (it.isRune() || it.type == ITEM_TYPE_POTION) { @@ -3403,9 +3403,9 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo ReturnValue ret = g_actions().canUse(player, pos); if (ret != RETURNVALUE_NOERROR) { if (ret == RETURNVALUE_TOOFARAWAY) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseItem, this, playerId, pos, stackPos, index, itemId), "Game::playerUseItem"); if (it.isRune() || it.type == ITEM_TYPE_POTION) { @@ -3537,9 +3537,9 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin internalGetPosition(moveItem, itemPos, itemStackPos); } - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseWithCreature, this, playerId, itemPos, itemStackPos, creatureId, itemId), "Game::playerUseWithCreature"); if (it.isRune() || it.type == ITEM_TYPE_POTION) { @@ -3676,9 +3676,9 @@ void Game::playerRotateItem(uint32_t playerId, const Position &pos, uint8_t stac } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerRotateItem, this, playerId, pos, stackPos, itemId), "Game::playerRotateItem"); player->setNextWalkActionTask(task); @@ -3717,9 +3717,9 @@ void Game::playerConfigureShowOffSocket(uint32_t playerId, const Position &pos, bool isPodiumOfRenown = itemId == ITEM_PODIUM_OF_RENOWN1 || itemId == ITEM_PODIUM_OF_RENOWN2; if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task; if (isPodiumOfRenown) { task = createPlayerTask(400, std::bind_front(&Player::sendPodiumWindow, player, item, pos, itemId, stackPos), "Game::playerConfigureShowOffSocket"); @@ -3764,9 +3764,9 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos } if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); player->setNextWalkActionTask(task); } else { @@ -3893,9 +3893,9 @@ void Game::playerWrapableItem(uint32_t playerId, const Position &pos, uint8_t st } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerWrapableItem, this, playerId, pos, stackPos, itemId), "Game::playerWrapableItem"); player->setNextWalkActionTask(task); @@ -4063,9 +4063,9 @@ void Game::playerBrowseField(uint32_t playerId, const Position &pos) { } if (!Position::areInRange<1, 1>(playerPos, pos)) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); player->setNextWalkActionTask(task); } else { @@ -4313,9 +4313,9 @@ void Game::playerRequestTrade(uint32_t playerId, const Position &pos, uint8_t st } if (!Position::areInRange<1, 1>(tradeItemPosition, playerPosition)) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerRequestTrade, this, playerId, pos, stackPos, tradePlayerId, itemId), "Game::playerRequestTrade"); player->setNextWalkActionTask(task); @@ -4862,9 +4862,9 @@ void Game::playerQuickLoot(uint32_t playerId, const Position &pos, uint16_t item if (!autoLoot && pos.x != 0xffff) { if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { // need to walk to the corpse first before looting it - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(0, std::bind(&Game::playerQuickLoot, this, player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot), "Game::playerQuickLoot"); player->setNextWalkActionTask(task); } else { @@ -5747,7 +5747,7 @@ bool Game::internalCreatureSay(std::shared_ptr creature, SpeakClasses } void Game::checkCreatureWalk(uint32_t creatureId) { - std::shared_ptr creature = getCreatureByID(creatureId); + const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { creature->onCreatureWalk(); cleanup(); @@ -5755,20 +5755,20 @@ void Game::checkCreatureWalk(uint32_t creatureId) { } void Game::updateCreatureWalk(uint32_t creatureId) { - std::shared_ptr creature = getCreatureByID(creatureId); + const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { - creature->goToFollowCreature(); + creature->goToFollowCreature_async(); } } void Game::checkCreatureAttack(uint32_t creatureId) { - std::shared_ptr creature = getCreatureByID(creatureId); + const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { creature->onAttacking(0); } } -void Game::addCreatureCheck(std::shared_ptr creature) { +void Game::addCreatureCheck(const std::shared_ptr &creature) { creature->creatureCheck = true; if (creature->inCheckCreaturesVector) { @@ -5777,10 +5777,10 @@ void Game::addCreatureCheck(std::shared_ptr creature) { } creature->inCheckCreaturesVector = true; - checkCreatureLists[uniform_random(0, EVENT_CREATURECOUNT - 1)].push_back(creature); + checkCreatureLists[uniform_random(0, EVENT_CREATURECOUNT - 1)].emplace_back(creature); } -void Game::removeCreatureCheck(std::shared_ptr creature) { +void Game::removeCreatureCheck(const std::shared_ptr &creature) { if (creature->inCheckCreaturesVector) { creature->creatureCheck = false; } @@ -5792,7 +5792,7 @@ void Game::checkCreatures() { auto &checkCreatureList = checkCreatureLists[index]; size_t it = 0, end = checkCreatureList.size(); while (it < end) { - std::shared_ptr creature = checkCreatureList[it]; + const auto &creature = checkCreatureList[it]; if (creature && creature->creatureCheck) { if (creature->getHealth() > 0) { creature->onThink(EVENT_CREATURE_THINK_INTERVAL); @@ -7617,8 +7617,7 @@ void Game::updatePlayerHelpers(std::shared_ptr player) { return; } - uint16_t helpers = player->getHelpers(); - + const uint16_t helpers = player->getHelpers(); for (const auto &spectator : Spectators().find(player->getPosition(), true)) { spectator->getPlayer()->sendCreatureHelpers(player->getID(), helpers); } @@ -8995,9 +8994,9 @@ void Game::playerSetMonsterPodium(uint32_t playerId, uint32_t monsterRaceId, con } if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - if (std::forward_list listDir; + if (stdext::arraylist listDir(128); player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind_front(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); player->setNextWalkActionTask(task); } else { @@ -9086,9 +9085,9 @@ void Game::playerRotatePodium(uint32_t playerId, const Position &pos, uint8_t st } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - if (std::forward_list listDir; + if (stdext::arraylist listDir(128); player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind_front(&Game::playerRotatePodium, this, playerId, pos, stackPos, itemId), "Game::playerRotatePodium"); player->setNextWalkActionTask(task); @@ -9864,7 +9863,7 @@ void Game::playerRewardChestCollect(uint32_t playerId, const Position &pos, uint reward->setParent(playerRewardChest); } - std::lock_guard lock(player->quickLootMutex); + std::scoped_lock lock(player->quickLootMutex); ReturnValue returnValue = collectRewardChestItems(player, maxMoveItems); if (returnValue != RETURNVALUE_NOERROR) { @@ -9925,25 +9924,28 @@ void Game::setTransferPlayerHouseItems(uint32_t houseId, uint32_t playerId) { } template -phmap::parallel_flat_hash_set setDifference(const phmap::flat_hash_set &setA, const phmap::flat_hash_set &setB) { - phmap::parallel_flat_hash_set setResult; +std::vector setDifference(const std::unordered_set &setA, const std::unordered_set &setB) { + std::vector setResult; + setResult.reserve(setA.size()); + for (const auto &elem : setA) { - if (setB.find(elem) == setB.end()) { - setResult.insert(elem); + if (!setB.contains(elem)) { + setResult.emplace_back(elem); } } + return setResult; } -ReturnValue Game::beforeCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones, bool force /* = false*/) const { +ReturnValue Game::beforeCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones, bool force /* = false*/) const { if (!creature) { return RETURNVALUE_NOTPOSSIBLE; } // fromZones - toZones = zones that creature left - auto zonesLeaving = setDifference(fromZones, toZones); + const auto &zonesLeaving = setDifference(fromZones, toZones); // toZones - fromZones = zones that creature entered - auto zonesEntering = setDifference(toZones, fromZones); + const auto &zonesEntering = setDifference(toZones, fromZones); if (zonesLeaving.empty() && zonesEntering.empty()) { return RETURNVALUE_NOERROR; @@ -9965,15 +9967,15 @@ ReturnValue Game::beforeCreatureZoneChange(std::shared_ptr creature, c return RETURNVALUE_NOERROR; } -void Game::afterCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones) const { +void Game::afterCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones) const { if (!creature) { return; } // fromZones - toZones = zones that creature left - auto zonesLeaving = setDifference(fromZones, toZones); + const auto &zonesLeaving = setDifference(fromZones, toZones); // toZones - fromZones = zones that creature entered - auto zonesEntering = setDifference(toZones, fromZones); + const auto &zonesEntering = setDifference(toZones, fromZones); for (const auto &zone : zonesLeaving) { zone->creatureRemoved(creature); diff --git a/src/game/game.hpp b/src/game/game.hpp index a5c7cd116c0..9dbbbca9f63 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -168,8 +168,8 @@ class Game { bool removeCreature(std::shared_ptr creature, bool isLogout = true); void executeDeath(uint32_t creatureId); - void addCreatureCheck(std::shared_ptr creature); - static void removeCreatureCheck(std::shared_ptr creature); + void addCreatureCheck(const std::shared_ptr &creature); + static void removeCreatureCheck(const std::shared_ptr &creature); size_t getPlayersOnline() const { return players.size(); @@ -320,8 +320,8 @@ class Game { void playerCloseNpcChannel(uint32_t playerId); void playerReceivePing(uint32_t playerId); void playerReceivePingBack(uint32_t playerId); - void playerAutoWalk(uint32_t playerId, const std::forward_list &listDir); - void forcePlayerAutoWalk(uint32_t playerId, const std::forward_list &listDir); + void playerAutoWalk(uint32_t playerId, const std::vector &listDir); + void forcePlayerAutoWalk(uint32_t playerId, const std::vector &listDir); void playerStopAutoWalk(uint32_t playerId); void playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t fromStackPos, uint16_t fromItemId, const Position &toPos, uint8_t toStackPos, uint16_t toItemId); void playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPos, uint8_t index, uint16_t itemId); @@ -557,7 +557,7 @@ class Game { Raids raids; Canary::protobuf::appearances::Appearances appearances; - phmap::flat_hash_set> getTilesToClean() const { + auto getTilesToClean() const { return tilesToClean; } void addTileToClean(std::shared_ptr tile) { @@ -599,11 +599,11 @@ class Game { mapLuaItemsStored[position] = itemId; } - std::set getFiendishMonsters() const { + auto getFiendishMonsters() const { return fiendishMonsters; } - std::set getInfluencedMonsters() const { + auto getInfluencedMonsters() const { return influencedMonsters; } @@ -673,8 +673,8 @@ class Game { */ bool tryRetrieveStashItems(std::shared_ptr player, std::shared_ptr item); - ReturnValue beforeCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones, bool force = false) const; - void afterCreatureZoneChange(std::shared_ptr creature, const phmap::flat_hash_set> &fromZones, const phmap::flat_hash_set> &toZones) const; + ReturnValue beforeCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones, bool force = false) const; + void afterCreatureZoneChange(std::shared_ptr creature, const std::unordered_set> &fromZones, const std::unordered_set> &toZones) const; std::unique_ptr &getIOWheel(); const std::unique_ptr &getIOWheel() const; @@ -684,8 +684,8 @@ class Game { private: std::map forgeMonsterEventIds; - std::set fiendishMonsters; - std::set influencedMonsters; + std::unordered_set fiendishMonsters; + std::unordered_set influencedMonsters; void checkImbuements(); bool playerSaySpell(std::shared_ptr player, SpeakClasses type, const std::string &text); void playerWhisper(std::shared_ptr player, const std::string &text); @@ -822,7 +822,7 @@ class Game { std::map> bedSleepersMap; - phmap::flat_hash_set> tilesToClean; + std::unordered_set> tilesToClean; ModalWindow offlineTrainingWindow { std::numeric_limits::max(), "Choose a Skill", "Please choose a skill:" }; diff --git a/src/game/scheduling/dispatcher.cpp b/src/game/scheduling/dispatcher.cpp index 1bb7512f11d..a24ef770466 100644 --- a/src/game/scheduling/dispatcher.cpp +++ b/src/game/scheduling/dispatcher.cpp @@ -14,7 +14,6 @@ #include "lib/di/container.hpp" #include "utils/tools.hpp" -constexpr static auto ASYNC_TIME_OUT = std::chrono::seconds(15); thread_local DispatcherContext Dispatcher::dispacherContext; Dispatcher &Dispatcher::getInstance() { @@ -30,7 +29,7 @@ void Dispatcher::init() { while (!threadPool.getIoContext().stopped()) { updateClock(); - executeEvents(asyncLock); + executeEvents(); executeScheduledEvents(); mergeEvents(); @@ -56,12 +55,12 @@ void Dispatcher::executeSerialEvents(std::vector &tasks) { dispacherContext.reset(); } -void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t groupId, std::unique_lock &asyncLock) { - const size_t totalTaskSize = tasks.size(); - std::atomic_uint_fast64_t executedTasks = 0; +void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t groupId) { + std::atomic_uint_fast64_t totalTaskSize = tasks.size(); + std::atomic_bool isTasksCompleted = false; for (const auto &task : tasks) { - threadPool.addLoad([this, &task, &executedTasks, groupId, totalTaskSize] { + threadPool.addLoad([groupId, &task, &isTasksCompleted, &totalTaskSize] { dispacherContext.type = DispatcherType::AsyncEvent; dispacherContext.group = static_cast(groupId); dispacherContext.taskName = task.getContext(); @@ -70,21 +69,21 @@ void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t g dispacherContext.reset(); - executedTasks.fetch_add(1); - if (executedTasks.load() >= totalTaskSize) { - signalAsync.notify_one(); + totalTaskSize.fetch_sub(1); + if (totalTaskSize.load() == 0) { + isTasksCompleted.store(true); + isTasksCompleted.notify_one(); } }); } - if (signalAsync.wait_for(asyncLock, ASYNC_TIME_OUT) == std::cv_status::timeout) { - g_logger().warn("A timeout occurred when executing the async dispatch in the context({}). Executed Tasks: {}/{}.", groupId, executedTasks.load(), totalTaskSize); - } + isTasksCompleted.wait(false); + tasks.clear(); } -void Dispatcher::executeEvents(std::unique_lock &asyncLock) { - for (uint_fast8_t groupId = 0; groupId < static_cast(TaskGroup::Last); ++groupId) { +void Dispatcher::executeEvents(const TaskGroup startGroup) { + for (uint_fast8_t groupId = static_cast(startGroup); groupId < static_cast(TaskGroup::Last); ++groupId) { auto &tasks = m_tasks[groupId]; if (tasks.empty()) { return; @@ -92,9 +91,9 @@ void Dispatcher::executeEvents(std::unique_lock &asyncLock) { if (groupId == static_cast(TaskGroup::Serial)) { executeSerialEvents(tasks); - mergeEvents(); // merge request, as there may be async event requests + mergeAsyncEvents(); } else { - executeParallelEvents(tasks, groupId, asyncLock); + executeParallelEvents(tasks, groupId); } } } @@ -128,18 +127,37 @@ void Dispatcher::executeScheduledEvents() { } dispacherContext.reset(); + + mergeAsyncEvents(); // merge async events requested by scheduled events + executeEvents(TaskGroup::GenericParallel); // execute async events requested by scheduled events } -// Merge thread events with main dispatch events -void Dispatcher::mergeEvents() { +// Merge only async thread events with main dispatch events +void Dispatcher::mergeAsyncEvents() { + constexpr uint8_t start = static_cast(TaskGroup::GenericParallel); + constexpr uint8_t end = static_cast(TaskGroup::Last); + for (const auto &thread : threads) { std::scoped_lock lock(thread->mutex); - for (uint_fast8_t i = 0; i < static_cast(TaskGroup::Last); ++i) { + for (uint_fast8_t i = start; i < end; ++i) { if (!thread->tasks[i].empty()) { m_tasks[i].insert(m_tasks[i].end(), make_move_iterator(thread->tasks[i].begin()), make_move_iterator(thread->tasks[i].end())); thread->tasks[i].clear(); } } + } +} + +// Merge thread events with main dispatch events +void Dispatcher::mergeEvents() { + constexpr uint8_t serial = static_cast(TaskGroup::Serial); + + for (const auto &thread : threads) { + std::scoped_lock lock(thread->mutex); + if (!thread->tasks[serial].empty()) { + m_tasks[serial].insert(m_tasks[serial].end(), make_move_iterator(thread->tasks[serial].begin()), make_move_iterator(thread->tasks[serial].end())); + thread->tasks[serial].clear(); + } if (!thread->scheduledTasks.empty()) { scheduledTasks.insert(make_move_iterator(thread->scheduledTasks.begin()), make_move_iterator(thread->scheduledTasks.end())); @@ -196,3 +214,19 @@ void Dispatcher::stopEvent(uint64_t eventId) { scheduledTasksRef.erase(it); } } + +void DispatcherContext::addEvent(std::function &&f) const { + g_dispatcher().addEvent(std::move(f), taskName); +} + +void DispatcherContext::tryAddEvent(std::function &&f) const { + if (!f) { + return; + } + + if (isAsync()) { + g_dispatcher().addEvent(std::move(f), taskName); + } else { + f(); + } +} diff --git a/src/game/scheduling/dispatcher.hpp b/src/game/scheduling/dispatcher.hpp index 73ba38ed224..9d0a5c51750 100644 --- a/src/game/scheduling/dispatcher.hpp +++ b/src/game/scheduling/dispatcher.hpp @@ -55,6 +55,12 @@ struct DispatcherContext { return type; } + // postpone the event + void addEvent(std::function &&f) const; + + // if the context is async, the event will be postponed, if not, it will be executed immediately. + void tryAddEvent(std::function &&f) const; + private: void reset() { group = TaskGroup::ThreadPool; @@ -143,15 +149,16 @@ class Dispatcher { void init(); void shutdown() { - signalAsync.notify_all(); + signalSchedule.notify_all(); } + inline void mergeAsyncEvents(); inline void mergeEvents(); - inline void executeEvents(std::unique_lock &asyncLock); + inline void executeEvents(const TaskGroup startGroup = TaskGroup::Serial); inline void executeScheduledEvents(); inline void executeSerialEvents(std::vector &tasks); - inline void executeParallelEvents(std::vector &tasks, const uint8_t groupId, std::unique_lock &asyncLock); + inline void executeParallelEvents(std::vector &tasks, const uint8_t groupId); inline std::chrono::nanoseconds timeUntilNextScheduledTask() const; inline void checkPendingTasks() { @@ -174,7 +181,6 @@ class Dispatcher { uint_fast64_t dispatcherCycle = 0; ThreadPool &threadPool; - std::condition_variable signalAsync; std::condition_variable signalSchedule; std::atomic_bool hasPendingTasks = false; std::mutex dummyMutex; // This is only used for signaling the condition variable and not as an actual lock. diff --git a/src/game/scheduling/events_scheduler.cpp b/src/game/scheduling/events_scheduler.cpp index d5c71378f4a..fc41f2c8b64 100644 --- a/src/game/scheduling/events_scheduler.cpp +++ b/src/game/scheduling/events_scheduler.cpp @@ -28,7 +28,7 @@ bool EventsScheduler::loadScheduleEventFromXml() { // Keep track of loaded scripts to check for duplicates int count = 0; - std::set> loadedScripts; + phmap::flat_hash_set loadedScripts; std::map eventsOnSameDay; for (const auto &eventNode : doc.child("events").children()) { std::string eventScript = eventNode.attribute("script").as_string(); diff --git a/src/game/zones/zone.hpp b/src/game/zones/zone.hpp index 4a0c0318006..91fa6f25e29 100644 --- a/src/game/zones/zone.hpp +++ b/src/game/zones/zone.hpp @@ -9,7 +9,6 @@ #pragma once -#include #include "game/movement/position.hpp" #include "items/item.hpp" #include "creatures/creature.hpp" diff --git a/src/io/io_bosstiary.cpp b/src/io/io_bosstiary.cpp index e4aecee5fc8..10c4f2f088c 100644 --- a/src/io/io_bosstiary.cpp +++ b/src/io/io_bosstiary.cpp @@ -234,14 +234,13 @@ uint32_t IOBosstiary::calculateBossPoints(uint16_t lootBonus) const { return static_cast((2.5 * lootBonus * lootBonus) - (477.5 * lootBonus) + 24000); } -phmap::parallel_flat_hash_set IOBosstiary::getBosstiaryFinished(std::shared_ptr player, uint8_t level /* = 1*/) const { - phmap::parallel_flat_hash_set unlockedMonsters; +std::vector IOBosstiary::getBosstiaryFinished(const std::shared_ptr &player, uint8_t level /* = 1*/) const { if (!player) { - return unlockedMonsters; + return {}; } - for (std::map bossesMap = getBosstiaryMap(); - const auto &[bossId, bossName] : bossesMap) { + stdext::vector_set unlockedMonsters; + for (const auto &[bossId, bossName] : getBosstiaryMap()) { uint32_t bossKills = player->getBestiaryKillCount(bossId); if (bossKills == 0) { continue; @@ -258,14 +257,14 @@ phmap::parallel_flat_hash_set IOBosstiary::getBosstiaryFinished(std::s const std::vector &infoForCurrentRace = it->second; auto levelKills = infoForCurrentRace.at(level - 1).kills; if (bossKills >= levelKills) { - unlockedMonsters.insert(bossId); + unlockedMonsters.emplace(bossId); } } else { g_logger().warn("[{}] boss with id {} and name {} not found in bossRace", __FUNCTION__, bossId, bossName); } } - return unlockedMonsters; + return unlockedMonsters.data(); } uint8_t IOBosstiary::getBossCurrentLevel(std::shared_ptr player, uint16_t bossId) const { diff --git a/src/io/io_bosstiary.hpp b/src/io/io_bosstiary.hpp index a253be3b467..b491247b295 100644 --- a/src/io/io_bosstiary.hpp +++ b/src/io/io_bosstiary.hpp @@ -63,7 +63,7 @@ class IOBosstiary { void addBosstiaryKill(std::shared_ptr player, const std::shared_ptr mtype, uint32_t amount = 1) const; uint16_t calculateLootBonus(uint32_t bossPoints) const; uint32_t calculateBossPoints(uint16_t lootBonus) const; - phmap::parallel_flat_hash_set getBosstiaryFinished(std::shared_ptr player, uint8_t level = 1) const; + std::vector getBosstiaryFinished(const std::shared_ptr &player, uint8_t level = 1) const; uint8_t getBossCurrentLevel(std::shared_ptr player, uint16_t bossId) const; uint32_t calculteRemoveBoss(uint8_t removeTimes) const; const std::vector &getBossRaceKillStages(BosstiaryRarity_t race) const; diff --git a/src/io/iobestiary.cpp b/src/io/iobestiary.cpp index c9fb933bc8c..2f66c53ad26 100644 --- a/src/io/iobestiary.cpp +++ b/src/io/iobestiary.cpp @@ -227,7 +227,6 @@ void IOBestiary::addBestiaryKill(std::shared_ptr player, const std::shar (curCount < mtype->info.bestiaryFirstUnlock && (curCount + amount) >= mtype->info.bestiaryFirstUnlock) || // First kill stage reached (curCount < mtype->info.bestiarySecondUnlock && (curCount + amount) >= mtype->info.bestiarySecondUnlock) || // Second kill stage reached (curCount < mtype->info.bestiaryToUnlock && (curCount + amount) >= mtype->info.bestiaryToUnlock)) { // Final kill stage reached - ss << "You unlocked details for the creature '" << mtype->name << "'"; player->sendTextMessage(MESSAGE_STATUS, ss.str()); player->sendBestiaryEntryChanged(raceid); @@ -305,7 +304,6 @@ void IOBestiary::sendBuyCharmRune(std::shared_ptr player, charmRune_t ru int32_t value = bitToggle(player->getUnlockedRunesBit(), charm, true); player->setUnlockedRunesBit(value); - } else if (action == 1) { std::list usedRunes = getCharmUsedRuneBitAll(player); uint16_t limitRunes = 0; @@ -396,18 +394,21 @@ std::map IOBestiary::getBestiaryKillCountByMonsterIDs(std::s return raceMonsters; } -phmap::parallel_flat_hash_set IOBestiary::getBestiaryFinished(std::shared_ptr player) const { - phmap::parallel_flat_hash_set finishedMonsters; - auto bestiaryMap = g_game().getBestiaryList(); +std::vector IOBestiary::getBestiaryFinished(const std::shared_ptr &player) const { + const auto &bestiaryMap = g_game().getBestiaryList(); + + stdext::vector_set finishedMonsters; + finishedMonsters.reserve(bestiaryMap.size()); for (const auto &[monsterTypeRaceId, monsterTypeName] : bestiaryMap) { - uint32_t thisKilled = player->getBestiaryKillCount(monsterTypeRaceId); - auto mtype = g_monsters().getMonsterType(monsterTypeName); + const auto &mtype = g_monsters().getMonsterType(monsterTypeName); + const uint32_t thisKilled = player->getBestiaryKillCount(monsterTypeRaceId); + if (mtype && thisKilled >= mtype->info.bestiaryToUnlock) { finishedMonsters.insert(monsterTypeRaceId); } } - return finishedMonsters; + return finishedMonsters.data(); } int8_t IOBestiary::calculateDifficult(uint32_t chance) const { diff --git a/src/io/iobestiary.hpp b/src/io/iobestiary.hpp index 26f802dcb5b..896e00434a1 100644 --- a/src/io/iobestiary.hpp +++ b/src/io/iobestiary.hpp @@ -72,7 +72,7 @@ class IOBestiary { bool hasCharmUnlockedRuneBit(const std::shared_ptr charm, int32_t input) const; std::list getCharmUsedRuneBitAll(std::shared_ptr player); - phmap::parallel_flat_hash_set getBestiaryFinished(std::shared_ptr player) const; + std::vector getBestiaryFinished(const std::shared_ptr &player) const; charmRune_t getCharmFromTarget(std::shared_ptr player, const std::shared_ptr mtype); diff --git a/src/items/containers/container.cpp b/src/items/containers/container.cpp index 54ce00acec4..af17ce692bc 100644 --- a/src/items/containers/container.cpp +++ b/src/items/containers/container.cpp @@ -278,8 +278,8 @@ std::deque> Container::getStoreInboxFilteredItems() const return storeInboxFilteredList; } -phmap::flat_hash_set Container::getStoreInboxValidCategories() const { - phmap::flat_hash_set validCategories; +std::vector Container::getStoreInboxValidCategories() const { + stdext::vector_set validCategories; for (const auto &item : itemlist) { auto itemId = item->getID(); auto attribute = item->getCustomAttribute("unWrapId"); @@ -297,7 +297,7 @@ phmap::flat_hash_set Container::getStoreInboxValidCategorie } } - return validCategories; + return validCategories.data(); } std::shared_ptr Container::getFilteredItemByIndex(size_t index) const { diff --git a/src/items/containers/container.hpp b/src/items/containers/container.hpp index 0b014aee58f..56d048f3b10 100644 --- a/src/items/containers/container.hpp +++ b/src/items/containers/container.hpp @@ -109,7 +109,7 @@ class Container : public Item, public Cylinder { bool isStoreInbox() const; bool isStoreInboxFiltered() const; std::deque> getStoreInboxFilteredItems() const; - phmap::flat_hash_set getStoreInboxValidCategories() const; + std::vector getStoreInboxValidCategories() const; std::shared_ptr getFilteredItemByIndex(size_t index) const; std::shared_ptr getItemByIndex(size_t index) const; bool isHoldingItem(std::shared_ptr item); diff --git a/src/items/items_definitions.hpp b/src/items/items_definitions.hpp index 8b54fa679b5..c6326acd28b 100644 --- a/src/items/items_definitions.hpp +++ b/src/items/items_definitions.hpp @@ -431,6 +431,11 @@ enum TileFlags_t : uint32_t { TILESTATE_IMMOVABLENOFIELDBLOCKPATH = 1 << 21, TILESTATE_NOFIELDBLOCKPATH = 1 << 22, TILESTATE_SUPPORTS_HANGABLE = 1 << 23, + TILESTATE_MOVEABLE = 1 << 24, + TILESTATE_ISHORIZONTAL = 1 << 25, + TILESTATE_ISVERTICAL = 1 << 26, + TILESTATE_BLOCKPROJECTILE = 1 << 27, + TILESTATE_HASHEIGHT = 1 << 28, TILESTATE_FLOORCHANGE = TILESTATE_FLOORCHANGE_DOWN | TILESTATE_FLOORCHANGE_NORTH | TILESTATE_FLOORCHANGE_SOUTH | TILESTATE_FLOORCHANGE_EAST | TILESTATE_FLOORCHANGE_WEST | TILESTATE_FLOORCHANGE_SOUTH_ALT | TILESTATE_FLOORCHANGE_EAST_ALT, }; diff --git a/src/items/tile.cpp b/src/items/tile.cpp index 92beb20d52f..22c325cfda2 100644 --- a/src/items/tile.cpp +++ b/src/items/tile.cpp @@ -26,18 +26,34 @@ auto real_nullptr_tile = std::make_shared(0xFFFF, 0xFFFF, 0xFF); const std::shared_ptr &Tile::nullptr_tile = real_nullptr_tile; bool Tile::hasProperty(ItemProperty prop) const { - if (ground && ground->hasProperty(prop)) { - return true; + switch (prop) { + case CONST_PROP_BLOCKSOLID: + return hasFlag(TILESTATE_BLOCKSOLID); + case CONST_PROP_HASHEIGHT: + return hasFlag(TILESTATE_HASHEIGHT); + case CONST_PROP_BLOCKPROJECTILE: + return hasFlag(TILESTATE_BLOCKPROJECTILE); + case CONST_PROP_BLOCKPATH: + return hasFlag(TILESTATE_BLOCKPATH); + case CONST_PROP_ISVERTICAL: + return hasFlag(TILESTATE_ISVERTICAL); + case CONST_PROP_ISHORIZONTAL: + return hasFlag(TILESTATE_ISHORIZONTAL); + case CONST_PROP_MOVEABLE: + return hasFlag(TILESTATE_MOVEABLE); + case CONST_PROP_IMMOVABLEBLOCKSOLID: + return hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID); + case CONST_PROP_IMMOVABLEBLOCKPATH: + return hasFlag(TILESTATE_IMMOVABLEBLOCKPATH); + case CONST_PROP_IMMOVABLENOFIELDBLOCKPATH: + return hasFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH); + case CONST_PROP_NOFIELDBLOCKPATH: + return hasFlag(TILESTATE_NOFIELDBLOCKPATH); + case CONST_PROP_SUPPORTHANGABLE: + return hasFlag(TILESTATE_SUPPORTS_HANGABLE); + default: + return false; } - - if (const TileItemVector* items = getItemList()) { - for (auto &item : *items) { - if (item->hasProperty(prop)) { - return true; - } - } - } - return false; } bool Tile::hasProperty(std::shared_ptr exclude, ItemProperty prop) const { @@ -943,6 +959,7 @@ void Tile::addThing(int32_t, std::shared_ptr thing) { if (creature) { Spectators::clearCache(); creature->setParent(static_self_cast()); + CreatureVector* creatures = makeCreatures(); creatures->insert(creatures->begin(), creature); } else { @@ -1530,6 +1547,7 @@ void Tile::internalAddThing(uint32_t, std::shared_ptr thing) { std::shared_ptr creature = thing->getCreature(); if (creature) { Spectators::clearCache(); + CreatureVector* creatures = makeCreatures(); creatures->insert(creatures->begin(), creature); } else { @@ -1574,14 +1592,14 @@ void Tile::internalAddThing(uint32_t, std::shared_ptr thing) { } } -void Tile::updateTileFlags(std::shared_ptr item) { +void Tile::updateTileFlags(const std::shared_ptr &item) { resetTileFlags(item); setTileFlags(item); } -void Tile::setTileFlags(std::shared_ptr item) { +void Tile::setTileFlags(const std::shared_ptr &item) { if (!hasFlag(TILESTATE_FLOORCHANGE)) { - const ItemType &it = Item::items[item->getID()]; + const auto &it = Item::items[item->getID()]; if (it.floorChange != 0) { setFlag(it.floorChange); } @@ -1603,6 +1621,10 @@ void Tile::setTileFlags(std::shared_ptr item) { setFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH); } + if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) { + setFlag(TILESTATE_SUPPORTS_HANGABLE); + } + if (item->getTeleport()) { setFlag(TILESTATE_TELEPORT); } @@ -1627,9 +1649,34 @@ void Tile::setTileFlags(std::shared_ptr item) { setFlag(TILESTATE_BED); } - std::shared_ptr container = item->getContainer(); - if (container && container->getDepotLocker()) { - setFlag(TILESTATE_DEPOT); + if (item->hasProperty(CONST_PROP_IMMOVABLEBLOCKPATH)) { + setFlag(TILESTATE_IMMOVABLEBLOCKPATH); + } + + if (item->hasProperty(CONST_PROP_MOVEABLE)) { + setFlag(TILESTATE_MOVEABLE); + } + + if (item->hasProperty(CONST_PROP_ISHORIZONTAL)) { + setFlag(TILESTATE_ISHORIZONTAL); + } + + if (item->hasProperty(CONST_PROP_ISVERTICAL)) { + setFlag(TILESTATE_ISVERTICAL); + } + + if (item->hasProperty(CONST_PROP_BLOCKPROJECTILE)) { + setFlag(TILESTATE_BLOCKPROJECTILE); + } + + if (item->hasProperty(CONST_PROP_HASHEIGHT)) { + setFlag(TILESTATE_HASHEIGHT); + } + + if (const auto &container = item->getContainer()) { + if (container->getDepotLocker()) { + setFlag(TILESTATE_DEPOT); + } } if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) { @@ -1637,7 +1684,7 @@ void Tile::setTileFlags(std::shared_ptr item) { } } -void Tile::resetTileFlags(std::shared_ptr item) { +void Tile::resetTileFlags(const std::shared_ptr &item) { const ItemType &it = Item::items[item->getID()]; if (it.floorChange != 0) { resetFlag(TILESTATE_FLOORCHANGE); @@ -1667,6 +1714,26 @@ void Tile::resetTileFlags(std::shared_ptr item) { resetFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH); } + if (item->hasProperty(CONST_PROP_MOVEABLE) && !hasProperty(item, CONST_PROP_MOVEABLE)) { + resetFlag(TILESTATE_MOVEABLE); + } + + if (item->hasProperty(CONST_PROP_ISHORIZONTAL) && !hasProperty(item, CONST_PROP_ISHORIZONTAL)) { + resetFlag(TILESTATE_ISHORIZONTAL); + } + + if (item->hasProperty(CONST_PROP_ISVERTICAL) && !hasProperty(item, CONST_PROP_ISVERTICAL)) { + resetFlag(TILESTATE_ISVERTICAL); + } + + if (item->hasProperty(CONST_PROP_BLOCKPROJECTILE) && !hasProperty(item, CONST_PROP_BLOCKPROJECTILE)) { + resetFlag(TILESTATE_BLOCKPROJECTILE); + } + + if (item->hasProperty(CONST_PROP_HASHEIGHT) && !hasProperty(item, CONST_PROP_HASHEIGHT)) { + resetFlag(TILESTATE_HASHEIGHT); + } + if (item->getTeleport()) { resetFlag(TILESTATE_TELEPORT); } @@ -1687,9 +1754,10 @@ void Tile::resetTileFlags(std::shared_ptr item) { resetFlag(TILESTATE_BED); } - std::shared_ptr container = item->getContainer(); - if (container && container->getDepotLocker()) { - resetFlag(TILESTATE_DEPOT); + if (const auto &container = item->getContainer()) { + if (container->getDepotLocker()) { + resetFlag(TILESTATE_DEPOT); + } } if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) { @@ -1732,12 +1800,8 @@ std::shared_ptr Tile::getDoorItem() const { return nullptr; } -phmap::flat_hash_set> Tile::getZones() { - return zones; -} - void Tile::addZone(std::shared_ptr zone) { - zones.insert(zone); + zones.emplace(zone); const auto &items = getItemList(); if (items) { for (const auto &item : *items) { @@ -1753,12 +1817,12 @@ void Tile::addZone(std::shared_ptr zone) { } void Tile::clearZones() { - phmap::flat_hash_set> zonesToRemove; + std::vector> zonesToRemove; for (const auto &zone : zones) { if (zone->isStatic()) { continue; } - zonesToRemove.insert(zone); + zonesToRemove.emplace_back(zone); const auto &items = getItemList(); if (items) { for (const auto &item : *items) { diff --git a/src/items/tile.hpp b/src/items/tile.hpp index de5dd4f0e43..bb10b309147 100644 --- a/src/items/tile.hpp +++ b/src/items/tile.hpp @@ -140,6 +140,7 @@ class Tile : public Cylinder, public SharedObject { std::shared_ptr getTopCreature() const; std::shared_ptr getBottomCreature() const; std::shared_ptr getTopVisibleCreature(std::shared_ptr creature) const; + std::shared_ptr getBottomVisibleCreature(std::shared_ptr creature) const; std::shared_ptr getTopTopItem() const; std::shared_ptr getTopDownItem() const; @@ -175,7 +176,9 @@ class Tile : public Cylinder, public SharedObject { void addZone(std::shared_ptr zone); void clearZones(); - phmap::flat_hash_set> getZones(); + auto getZones() const { + return zones; + } ZoneType_t getZoneType() const { if (hasFlag(TILESTATE_PROTECTIONZONE)) { @@ -210,7 +213,7 @@ class Tile : public Cylinder, public SharedObject { void addThing(std::shared_ptr thing) override final; void addThing(int32_t index, std::shared_ptr thing) override; - void updateTileFlags(std::shared_ptr item); + void updateTileFlags(const std::shared_ptr &item); void updateThing(std::shared_ptr thing, uint16_t itemId, uint32_t count) override final; void replaceThing(uint32_t index, std::shared_ptr thing) override final; @@ -244,8 +247,14 @@ class Tile : public Cylinder, public SharedObject { std::shared_ptr getGround() const { return ground; } - void setGround(std::shared_ptr item) { - ground = item; + void setGround(const std::shared_ptr &item) { + if (ground) { + resetTileFlags(ground); + } + + if (ground = item) { + setTileFlags(item); + } } private: @@ -254,8 +263,8 @@ class Tile : public Cylinder, public SharedObject { void onRemoveTileItem(const CreatureVector &spectators, const std::vector &oldStackPosVector, std::shared_ptr item); void onUpdateTile(const CreatureVector &spectators); - void setTileFlags(std::shared_ptr item); - void resetTileFlags(std::shared_ptr item); + void setTileFlags(const std::shared_ptr &item); + void resetTileFlags(const std::shared_ptr &item); bool hasHarmfulField() const; ReturnValue checkNpcCanWalkIntoTile() const; @@ -263,7 +272,7 @@ class Tile : public Cylinder, public SharedObject { std::shared_ptr ground = nullptr; Position tilePos; uint32_t flags = 0; - phmap::flat_hash_set> zones; + std::unordered_set> zones; }; // Used for walkable tiles, where there is high likeliness of diff --git a/src/kv/kv.cpp b/src/kv/kv.cpp index e5dbc974b76..0e2f4b2f836 100644 --- a/src/kv/kv.cpp +++ b/src/kv/kv.cpp @@ -27,7 +27,7 @@ void KVStore::set(const std::string &key, const std::initializer_list KVStore::get(const std::string &key, bool forceLoad /*= false */) { logger.debug("KVStore::get({})", key); - std::lock_guard lock(mutex_); + std::scoped_lock lock(mutex_); if (forceLoad || !store_.contains(key)) { auto value = load(key); if (value) { diff --git a/src/lib/di/shared.hpp b/src/lib/di/shared.hpp index e206cbd4b4c..c1e2f0c6743 100644 --- a/src/lib/di/shared.hpp +++ b/src/lib/di/shared.hpp @@ -29,9 +29,9 @@ namespace extension { #if !defined(BOOST_DI_NOT_THREAD_SAFE) //<> explicit scope(scope &&other) noexcept : - scope(std::move(other), std::lock_guard(other.mutex_)) { } + scope(std::move(other), std::scoped_lock(other.mutex_)) { } //<> - scope(scope &&other, const std::lock_guard &) noexcept : + scope(scope &&other, const std::scoped_lock &) noexcept : object_(std::move(other.object_)) { } #endif @@ -49,7 +49,7 @@ namespace extension { wrappers::shared create(const TProvider &provider) & { if (!object_) { #if !defined(BOOST_DI_NOT_THREAD_SAFE) - std::lock_guard lock(mutex_); + std::scoped_lock lock(mutex_); if (!object_) #endif object_ = std::shared_ptr { provider.get() }; @@ -65,7 +65,7 @@ namespace extension { auto &object = provider.cfg().template data(); if (!object) { #if !defined(BOOST_DI_NOT_THREAD_SAFE) - std::lock_guard lock(mutex_); + std::scoped_lock lock(mutex_); if (!object) #endif object = std::shared_ptr { provider.get() }; diff --git a/src/lua/creature/creatureevent.cpp b/src/lua/creature/creatureevent.cpp index b1984be2fd6..29feb652036 100644 --- a/src/lua/creature/creatureevent.cpp +++ b/src/lua/creature/creatureevent.cpp @@ -326,8 +326,14 @@ bool CreatureEvent::executeAdvance(std::shared_ptr player, skills_t skil return getScriptInterface()->callFunction(4); } +/** + * @deprecated Prefer using registered onDeath events instead for better performance. + */ void CreatureEvent::executeOnKill(std::shared_ptr creature, std::shared_ptr target, bool lastHit) const { // onKill(creature, target, lastHit) + g_logger().warn("[CreatureEvent::executeOnKill - Creature {} target {} event {}] " + "Deprecated use of onKill event. Use registered onDeath events instead for better performance.", + creature->getName(), target->getName(), getName()); if (!getScriptInterface()->reserveScriptEnv()) { g_logger().error("[CreatureEvent::executeOnKill - Creature {} target {} event {}] " "Call stack overflow. Too many lua script calls being nested.", diff --git a/src/lua/creature/events.cpp b/src/lua/creature/events.cpp index 176044d666e..055394214b1 100644 --- a/src/lua/creature/events.cpp +++ b/src/lua/creature/events.cpp @@ -30,14 +30,14 @@ bool Events::loadFromXml() { info = {}; - std::set classes; + phmap::flat_hash_set classes; for (auto eventNode : doc.child("events").children()) { if (!eventNode.attribute("enabled").as_bool()) { continue; } const std::string &className = eventNode.attribute("class").as_string(); - auto res = classes.insert(className); + auto res = classes.emplace(className); if (res.second) { const std::string &lowercase = asLowerCaseString(className); const std::string &scriptName = lowercase + ".lua"; diff --git a/src/lua/functions/creatures/creature_functions.cpp b/src/lua/functions/creatures/creature_functions.cpp index 14d86f1e291..c5221a9c3ad 100644 --- a/src/lua/functions/creatures/creature_functions.cpp +++ b/src/lua/functions/creatures/creature_functions.cpp @@ -911,7 +911,7 @@ int CreatureFunctions::luaCreatureGetPathTo(lua_State* L) { fpp.clearSight = getBoolean(L, 6, fpp.clearSight); fpp.maxSearchDist = getNumber(L, 7, fpp.maxSearchDist); - std::forward_list dirList; + stdext::arraylist dirList(128); if (creature->getPathTo(position, dirList, fpp)) { lua_newtable(L); diff --git a/src/lua/functions/creatures/monster/loot_functions.cpp b/src/lua/functions/creatures/monster/loot_functions.cpp index 81e42535f92..b23508033bc 100644 --- a/src/lua/functions/creatures/monster/loot_functions.cpp +++ b/src/lua/functions/creatures/monster/loot_functions.cpp @@ -259,7 +259,13 @@ int LootFunctions::luaLootAddChildLoot(lua_State* L) { // loot:addChildLoot(loot) const auto loot = getUserdataShared(L, 1); if (loot) { - loot->lootBlock.childLoot.push_back(getUserdata(L, 2)->lootBlock); + const auto childLoot = getUserdata(L, 2); + if (childLoot) { + loot->lootBlock.childLoot.push_back(childLoot->lootBlock); + pushBoolean(L, true); + } else { + pushBoolean(L, false); + } } else { lua_pushnil(L); } diff --git a/src/lua/functions/creatures/monster/monster_functions.cpp b/src/lua/functions/creatures/monster/monster_functions.cpp index 60e60fe876c..e0f702f249e 100644 --- a/src/lua/functions/creatures/monster/monster_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_functions.cpp @@ -219,11 +219,11 @@ int MonsterFunctions::luaMonsterGetFriendList(lua_State* L) { return 1; } - const auto friendList = monster->getFriendList(); + const auto &friendList = monster->getFriendList(); lua_createtable(L, friendList.size(), 0); int index = 0; - for (std::shared_ptr creature : friendList) { + for (const auto &creature : friendList) { pushUserdata(L, creature); setCreatureMetatable(L, -1, creature); lua_rawseti(L, -2, ++index); diff --git a/src/lua/functions/creatures/monster/monster_type_functions.cpp b/src/lua/functions/creatures/monster/monster_type_functions.cpp index e08d322189c..146ee7b1a20 100644 --- a/src/lua/functions/creatures/monster/monster_type_functions.cpp +++ b/src/lua/functions/creatures/monster/monster_type_functions.cpp @@ -13,6 +13,7 @@ #include "io/io_bosstiary.hpp" #include "creatures/combat/spells.hpp" #include "creatures/monsters/monsters.hpp" +#include "creatures/monsters/monster.hpp" #include "lua/functions/creatures/monster/monster_type_functions.hpp" #include "lua/scripts/scripts.hpp" @@ -425,13 +426,13 @@ int MonsterTypeFunctions::luaMonsterTypeEnemyFactions(lua_State* L) { lua_createtable(L, monsterType->info.enemyFactions.size(), 0); int index = 0; - for (auto faction : monsterType->info.enemyFactions) { + for (const auto &faction : monsterType->info.enemyFactions) { lua_pushnumber(L, faction); lua_rawseti(L, -2, ++index); } } else { Faction_t faction = getNumber(L, 2); - monsterType->info.enemyFactions.emplace(faction); + monsterType->info.enemyFactions.insert(faction); pushBoolean(L, true); } } else { @@ -1002,7 +1003,13 @@ int MonsterTypeFunctions::luaMonsterTypeRegisterEvent(lua_State* L) { // monsterType:registerEvent(name) const auto monsterType = getUserdataShared(L, 1); if (monsterType) { - monsterType->info.scripts.push_back(getString(L, 2)); + auto eventName = getString(L, 2); + monsterType->info.scripts.push_back(eventName); + for (const auto &[_, monster] : g_game().getMonsters()) { + if (monster->getMonsterType() == monsterType) { + monster->registerCreatureEvent(eventName); + } + } pushBoolean(L, true); } else { lua_pushnil(L); diff --git a/src/lua/functions/creatures/player/player_functions.cpp b/src/lua/functions/creatures/player/player_functions.cpp index 12e7379a26d..7c8934b4574 100644 --- a/src/lua/functions/creatures/player/player_functions.cpp +++ b/src/lua/functions/creatures/player/player_functions.cpp @@ -328,8 +328,7 @@ int PlayerFunctions::luaPlayerIsMonsterBestiaryUnlocked(lua_State* L) { return 0; } - for (auto finishedMonsters = g_iobestiary().getBestiaryFinished(player); - uint16_t finishedRaceId : finishedMonsters) { + for (uint16_t finishedRaceId : g_iobestiary().getBestiaryFinished(player)) { if (raceId == finishedRaceId) { pushBoolean(L, true); return 1; diff --git a/src/lua/functions/lua_functions_loader.cpp b/src/lua/functions/lua_functions_loader.cpp index 0973876c294..bdf7dbb37bc 100644 --- a/src/lua/functions/lua_functions_loader.cpp +++ b/src/lua/functions/lua_functions_loader.cpp @@ -239,11 +239,11 @@ void LuaFunctionsLoader::setMetatable(lua_State* L, int32_t index, const std::st } void LuaFunctionsLoader::setWeakMetatable(lua_State* L, int32_t index, const std::string &name) { + static phmap::flat_hash_set weakObjectTypes; if (validateDispatcherContext(__FUNCTION__)) { return; } - static std::set weakObjectTypes; const std::string &weakName = name + "_weak"; auto result = weakObjectTypes.emplace(name); diff --git a/src/lua/functions/map/position_functions.cpp b/src/lua/functions/map/position_functions.cpp index 5cee3f2d847..3e5582a1cd2 100644 --- a/src/lua/functions/map/position_functions.cpp +++ b/src/lua/functions/map/position_functions.cpp @@ -97,7 +97,7 @@ int PositionFunctions::luaPositionGetPathTo(lua_State* L) { fpp.clearSight = getBoolean(L, 6, fpp.clearSight); fpp.maxSearchDist = getNumber(L, 7, fpp.maxSearchDist); - std::forward_list dirList; + stdext::arraylist dirList(128); if (g_game().map.getPathMatching(pos, dirList, FrozenPathingConditionCall(position), fpp)) { lua_newtable(L); diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index 8bb26bcfb6b..748e24aeed8 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -163,7 +163,7 @@ void House::updateDoorDescription() const { } } -AccessHouseLevel_t House::getHouseAccessLevel(std::shared_ptr player) { +AccessHouseLevel_t House::getHouseAccessLevel(std::shared_ptr player) const { if (!player) { return HOUSE_OWNER; } @@ -369,10 +369,6 @@ bool House::getAccessList(uint32_t listId, std::string &list) const { return door->getAccessList(list); } -bool House::isInvited(std::shared_ptr player) { - return getHouseAccessLevel(player) != HOUSE_NOT_INVITED; -} - void House::addDoor(std::shared_ptr door) { doorList.push_back(door); door->setHouse(static_self_cast()); @@ -414,7 +410,7 @@ std::shared_ptr House::getDoorByPosition(const Position &pos) { return nullptr; } -bool House::canEditAccessList(uint32_t listId, std::shared_ptr player) { +bool House::canEditAccessList(uint32_t listId, const std::shared_ptr &player) const { switch (getHouseAccessLevel(player)) { case HOUSE_OWNER: return true; @@ -602,18 +598,17 @@ void AccessList::addGuildRank(const std::string &name, const std::string &guildN } } -bool AccessList::isInList(std::shared_ptr player) { +bool AccessList::isInList(std::shared_ptr player) const { if (allowEveryone) { return true; } - auto playerIt = playerList.find(player->getGUID()); - if (playerIt != playerList.end()) { + if (playerList.contains(player->getGUID())) { return true; } - GuildRank_ptr rank = player->getGuildRank(); - return rank && guildRankList.find(rank->id) != guildRankList.end(); + const auto &rank = player->getGuildRank(); + return rank && guildRankList.contains(rank->id); } void AccessList::getList(std::string &retList) const { @@ -648,7 +643,7 @@ void Door::setHouse(std::shared_ptr newHouse) { } } -bool Door::canUse(std::shared_ptr player) { +bool Door::canUse(std::shared_ptr player) const { if (!house) { return true; } diff --git a/src/map/house/house.hpp b/src/map/house/house.hpp index 845693e303e..2e8427a57a0 100644 --- a/src/map/house/house.hpp +++ b/src/map/house/house.hpp @@ -25,7 +25,7 @@ class AccessList { void addGuild(const std::string &name); void addGuildRank(const std::string &name, const std::string &rankName); - bool isInList(std::shared_ptr player); + bool isInList(std::shared_ptr player) const; void getList(std::string &list) const; @@ -63,7 +63,7 @@ class Door final : public Item { return getAttribute(ItemAttribute_t::DOORID); } - bool canUse(std::shared_ptr player); + bool canUse(std::shared_ptr player) const; void setAccessList(const std::string &textlist); bool getAccessList(std::string &list) const; @@ -104,16 +104,18 @@ class House : public SharedObject { void addTile(std::shared_ptr tile); void updateDoorDescription() const; - bool canEditAccessList(uint32_t listId, std::shared_ptr player); + bool canEditAccessList(uint32_t listId, const std::shared_ptr &player) const; // listId special = values: // GUEST_LIST = guest list // SUBOWNER_LIST = subowner list void setAccessList(uint32_t listId, const std::string &textlist); bool getAccessList(uint32_t listId, std::string &list) const; - bool isInvited(std::shared_ptr player); + bool isInvited(const std::shared_ptr &player) const { + return getHouseAccessLevel(player) != HOUSE_NOT_INVITED; + } - AccessHouseLevel_t getHouseAccessLevel(std::shared_ptr player); + AccessHouseLevel_t getHouseAccessLevel(std::shared_ptr player) const; bool kickPlayer(std::shared_ptr player, std::shared_ptr target); void setEntryPos(Position pos) { diff --git a/src/map/map.cpp b/src/map/map.cpp index 53f7c98db38..3771f5662ec 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -17,6 +17,7 @@ #include "game/zones/zone.hpp" #include "io/iomap.hpp" #include "io/iomapserialize.hpp" +#include "game/scheduling/dispatcher.hpp" #include "map/spectators.hpp" void Map::load(const std::string &identifier, const Position &pos) { @@ -324,8 +325,8 @@ void Map::moveCreature(const std::shared_ptr &creature, const std::sha Position oldPos = oldTile->getPosition(); Position newPos = newTile->getPosition(); - auto fromZones = oldTile->getZones(); - auto toZones = newTile->getZones(); + const auto &fromZones = oldTile->getZones(); + const auto &toZones = newTile->getZones(); if (auto ret = g_game().beforeCreatureZoneChange(creature, fromZones, toZones); ret != RETURNVALUE_NOERROR) { return; } @@ -484,30 +485,39 @@ bool Map::isSightClear(const Position &fromPos, const Position &toPos, bool floo } std::shared_ptr Map::canWalkTo(const std::shared_ptr &creature, const Position &pos) { - int32_t walkCache = creature->getWalkCache(pos); + if (!creature || creature->isRemoved()) { + return nullptr; + } + + const int32_t walkCache = creature->getWalkCache(pos); + if (walkCache == 0) { return nullptr; - } else if (walkCache == 1) { + } + + if (walkCache == 1) { return getTile(pos.x, pos.y, pos.z); } // used for non-cached tiles - std::shared_ptr tile = getTile(pos.x, pos.y, pos.z); + const auto &tile = getTile(pos.x, pos.y, pos.z); if (creature->getTile() != tile) { if (!tile || tile->queryAdd(0, creature, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) != RETURNVALUE_NOERROR) { return nullptr; } } + return tile; } -bool Map::getPathMatching(const std::shared_ptr &creature, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { - Position pos = creature->getPosition(); - Position endPos; - - AStarNodes nodes(pos.x, pos.y); +bool Map::getPathMatching(const std::shared_ptr &creature, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + return getPathMatching(creature, creature->getPosition(), dirList, pathCondition, fpp); +} - int32_t bestMatch = 0; +bool Map::getPathMatching(const std::shared_ptr &creature, const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + static int_fast32_t allNeighbors[8][2] = { + { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } + }; static int_fast32_t dirNeighbors[8][5][2] = { { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 } }, @@ -519,186 +529,14 @@ bool Map::getPathMatching(const std::shared_ptr &creature, std::forwar { { 0, 1 }, { 1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }, { { -1, 0 }, { 0, 1 }, { -1, -1 }, { 1, 1 }, { -1, 1 } } }; - static int_fast32_t allNeighbors[8][2] = { - { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } - }; - const Position startPos = pos; - - AStarNode* found = nullptr; - while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { - AStarNode* n = nodes.getBestNode(); - if (!n) { - if (found) { - break; - } - return false; - } - - const int_fast32_t x = n->x; - const int_fast32_t y = n->y; - pos.x = x; - pos.y = y; - if (pathCondition(startPos, pos, fpp, bestMatch)) { - found = n; - endPos = pos; - if (bestMatch == 0) { - break; - } - } - - uint_fast32_t dirCount; - int_fast32_t* neighbors; - if (n->parent) { - const int_fast32_t offset_x = n->parent->x - x; - const int_fast32_t offset_y = n->parent->y - y; - if (offset_y == 0) { - if (offset_x == -1) { - neighbors = *dirNeighbors[DIRECTION_WEST]; - } else { - neighbors = *dirNeighbors[DIRECTION_EAST]; - } - } else if (!fpp.allowDiagonal || offset_x == 0) { - if (offset_y == -1) { - neighbors = *dirNeighbors[DIRECTION_NORTH]; - } else { - neighbors = *dirNeighbors[DIRECTION_SOUTH]; - } - } else if (offset_y == -1) { - if (offset_x == -1) { - neighbors = *dirNeighbors[DIRECTION_NORTHWEST]; - } else { - neighbors = *dirNeighbors[DIRECTION_NORTHEAST]; - } - } else if (offset_x == -1) { - neighbors = *dirNeighbors[DIRECTION_SOUTHWEST]; - } else { - neighbors = *dirNeighbors[DIRECTION_SOUTHEAST]; - } - dirCount = fpp.allowDiagonal ? 5 : 3; - } else { - dirCount = 8; - neighbors = *allNeighbors; - } - - const int_fast32_t f = n->f; - for (uint_fast32_t i = 0; i < dirCount; ++i) { - pos.x = x + *neighbors++; - pos.y = y + *neighbors++; - - if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { - continue; - } - - if (fpp.keepDistance && !pathCondition.isInRange(startPos, pos, fpp)) { - continue; - } - - std::shared_ptr tile; - AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); - if (neighborNode) { - tile = getTile(pos.x, pos.y, pos.z); - } else { - tile = canWalkTo(creature, pos); - if (!tile) { - continue; - } - } - - // The cost (g) for this neighbor - const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos); - const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile); - const int_fast32_t newf = f + cost + extraCost; - - if (neighborNode) { - if (neighborNode->f <= newf) { - // The node on the closed/open list is cheaper than this one - continue; - } - - neighborNode->f = newf; - neighborNode->parent = n; - nodes.openNode(neighborNode); - } else { - // Does not exist in the open/closed list, create a std::make_shared - neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); - if (!neighborNode) { - if (found) { - break; - } - return false; - } - } - } - - nodes.closeNode(n); - } - - if (!found) { - return false; - } - - int_fast32_t prevx = endPos.x; - int_fast32_t prevy = endPos.y; - - found = found->parent; - while (found) { - pos.x = found->x; - pos.y = found->y; - - int_fast32_t dx = pos.getX() - prevx; - int_fast32_t dy = pos.getY() - prevy; - - prevx = pos.x; - prevy = pos.y; - - if (dx == 1 && dy == 1) { - dirList.push_front(DIRECTION_NORTHWEST); - } else if (dx == -1 && dy == 1) { - dirList.push_front(DIRECTION_NORTHEAST); - } else if (dx == 1 && dy == -1) { - dirList.push_front(DIRECTION_SOUTHWEST); - } else if (dx == -1 && dy == -1) { - dirList.push_front(DIRECTION_SOUTHEAST); - } else if (dx == 1) { - dirList.push_front(DIRECTION_WEST); - } else if (dx == -1) { - dirList.push_front(DIRECTION_EAST); - } else if (dy == 1) { - dirList.push_front(DIRECTION_NORTH); - } else if (dy == -1) { - dirList.push_front(DIRECTION_SOUTH); - } - - found = found->parent; - } - return true; -} - -bool Map::getPathMatching(const Position &start, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { - Position pos = start; + Position pos = startPos; Position endPos; AStarNodes nodes(pos.x, pos.y); int32_t bestMatch = 0; - static int_fast32_t dirNeighbors[8][5][2] = { - { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 } }, - { { -1, 0 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 1 } }, - { { -1, 0 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 } }, - { { 0, 1 }, { 1, 0 }, { 0, -1 }, { 1, -1 }, { 1, 1 } }, - { { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 } }, - { { -1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { -1, 1 } }, - { { 0, 1 }, { 1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }, - { { -1, 0 }, { 0, 1 }, { -1, -1 }, { 1, 1 }, { -1, 1 } } - }; - static int_fast32_t allNeighbors[8][2] = { - { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } - }; - - const Position startPos = pos; - AStarNode* found = nullptr; while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { AStarNode* n = nodes.getBestNode(); @@ -768,20 +606,18 @@ bool Map::getPathMatching(const Position &start, std::forward_list &d continue; } - std::shared_ptr tile; AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); - if (neighborNode) { - tile = getTile(pos.x, pos.y, pos.z); - } else { - tile = getTile(pos.x, pos.y, pos.z); - if (!tile || tile->hasFlag(TILESTATE_BLOCKSOLID)) { - continue; - } + + const bool withoutCreature = creature == nullptr; + const auto &tile = neighborNode || withoutCreature ? getTile(pos.x, pos.y, pos.z) : canWalkTo(creature, pos); + + if (!tile || !neighborNode && withoutCreature && tile->hasFlag(TILESTATE_BLOCKSOLID)) { + continue; } // The cost (g) for this neighbor - const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos, true); - const int_fast32_t extraCost = 0; + const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos, withoutCreature); + const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile); const int_fast32_t newf = f + cost + extraCost; if (neighborNode) { @@ -820,8 +656,8 @@ bool Map::getPathMatching(const Position &start, std::forward_list &d pos.x = found->x; pos.y = found->y; - int_fast32_t dx = pos.getX() - prevx; - int_fast32_t dy = pos.getY() - prevy; + const int_fast32_t dx = pos.getX() - prevx; + const int_fast32_t dy = pos.getY() - prevy; prevx = pos.x; prevy = pos.y; @@ -858,13 +694,13 @@ uint32_t Map::clean() { } std::vector> toRemove; - for (auto tile : g_game().getTilesToClean()) { + for (const auto &tile : g_game().getTilesToClean()) { if (!tile) { continue; } - if (auto items = tile->getItemList()) { + if (const auto items = tile->getItemList()) { ++tiles; - for (auto item : *items) { + for (const auto &item : *items) { if (item->isCleanable()) { toRemove.emplace_back(item); } @@ -872,7 +708,7 @@ uint32_t Map::clean() { } } - for (auto item : toRemove) { + for (const auto &item : toRemove) { g_game().internalRemoveItem(item, -1); } diff --git a/src/map/map.hpp b/src/map/map.hpp index ac0211c7daf..d5ca9b2af14 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -123,9 +123,11 @@ class Map : protected MapCache { std::shared_ptr canWalkTo(const std::shared_ptr &creature, const Position &pos); - bool getPathMatching(const std::shared_ptr &creature, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatching(const std::shared_ptr &creature, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); - bool getPathMatching(const Position &startPos, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatching(const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + return getPathMatching(nullptr, startPos, dirList, pathCondition, fpp); + } std::map waypoints; @@ -145,6 +147,8 @@ class Map : protected MapCache { Houses housesCustomMaps[50]; private: + bool getPathMatching(const std::shared_ptr &creature, const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + /** * Set a single tile. */ diff --git a/src/map/spectators.hpp b/src/map/spectators.hpp index 886a51d8c1f..8e73df9ad6f 100644 --- a/src/map/spectators.hpp +++ b/src/map/spectators.hpp @@ -64,7 +64,7 @@ class Spectators { Spectators insert(const std::shared_ptr &creature) { if (creature) { - creatures.emplace_back(creature); + creatures.emplace(creature); } return *this; } diff --git a/src/map/utils/astarnodes.cpp b/src/map/utils/astarnodes.cpp index 36265dd7f12..e4cccd4e694 100644 --- a/src/map/utils/astarnodes.cpp +++ b/src/map/utils/astarnodes.cpp @@ -104,23 +104,28 @@ int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position &neighbo return MAP_NORMALWALKCOST; } -int_fast32_t AStarNodes::getTileWalkCost(const std::shared_ptr &creature, std::shared_ptr tile) { +int_fast32_t AStarNodes::getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile) { + if (!creature || !tile) { + return 0; + } + int_fast32_t cost = 0; if (tile->getTopVisibleCreature(creature) != nullptr) { // destroy creature cost cost += MAP_NORMALWALKCOST * 3; } - if (std::shared_ptr field = tile->getFieldItem()) { - CombatType_t combatType = field->getCombatType(); - std::shared_ptr monster = creature->getMonster(); + if (const auto &field = tile->getFieldItem()) { + const CombatType_t combatType = field->getCombatType(); + const auto &monster = creature->getMonster(); + if (!creature->isImmune(combatType) && !creature->hasCondition(Combat::DamageToConditionType(combatType)) && (monster && !monster->canWalkOnFieldType(combatType))) { cost += MAP_NORMALWALKCOST * 18; } /** * Make player try to avoid magic fields, when calculating pathing */ - std::shared_ptr player = creature->getPlayer(); + const auto &player = creature->getPlayer(); if (player && !field->isBlocking() && field->getDamage() != 0) { cost += MAP_NORMALWALKCOST * 18; } diff --git a/src/map/utils/astarnodes.hpp b/src/map/utils/astarnodes.hpp index eba694de218..26f33cdfcc4 100644 --- a/src/map/utils/astarnodes.hpp +++ b/src/map/utils/astarnodes.hpp @@ -31,7 +31,7 @@ class AStarNodes { AStarNode* getNodeByPosition(uint32_t x, uint32_t y); static int_fast32_t getMapWalkCost(AStarNode* node, const Position &neighborPos, bool preferDiagonal = false); - static int_fast32_t getTileWalkCost(const std::shared_ptr &creature, std::shared_ptr tile); + static int_fast32_t getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile); private: static constexpr int32_t MAX_NODES = 512; diff --git a/src/pch.hpp b/src/pch.hpp index ab57f178e84..0f5775b73d3 100644 --- a/src/pch.hpp +++ b/src/pch.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/src/server/network/connection/connection.cpp b/src/server/network/connection/connection.cpp index 8e637c053ee..d2937756cf0 100644 --- a/src/server/network/connection/connection.cpp +++ b/src/server/network/connection/connection.cpp @@ -53,7 +53,7 @@ void Connection::close(bool force) { // any thread ConnectionManager::getInstance().releaseConnection(shared_from_this()); - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); ip = 0; if (connectionState == CONNECTION_STATE_CLOSED) { return; @@ -114,7 +114,7 @@ void Connection::accept(bool toggleParseHeader /* = true */) { } void Connection::parseProxyIdentification(const std::error_code &error) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); readTimer.cancel(); if (error) { @@ -167,7 +167,7 @@ void Connection::parseProxyIdentification(const std::error_code &error) { } void Connection::parseHeader(const std::error_code &error) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); readTimer.cancel(); if (error) { @@ -209,7 +209,7 @@ void Connection::parseHeader(const std::error_code &error) { } void Connection::parsePacket(const std::error_code &error) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); readTimer.cancel(); if (error) { @@ -275,7 +275,7 @@ void Connection::parsePacket(const std::error_code &error) { } void Connection::resumeWork() { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); try { // Wait to the next packet @@ -287,7 +287,7 @@ void Connection::resumeWork() { } void Connection::send(const OutputMessage_ptr &outputMessage) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); if (connectionState == CONNECTION_STATE_CLOSED) { return; } @@ -324,7 +324,7 @@ uint32_t Connection::getIP() { return ip; } - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); // IP-address is expressed in network byte order std::error_code error; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 6da9e94180e..8b1a67aaada 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -217,7 +217,7 @@ namespace { * @param msg The network message to send the category to. */ template - void sendContainerCategory(NetworkMessage &msg, phmap::flat_hash_set categories = {}, uint8_t categoryType = 0) { + void sendContainerCategory(NetworkMessage &msg, const std::vector &categories = {}, uint8_t categoryType = 0) { msg.addByte(categoryType); g_logger().debug("Sendding category type '{}', categories total size '{}'", categoryType, categories.size()); msg.addByte(categories.size()); @@ -1555,7 +1555,7 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { msg.skipBytes(numdirs); - std::forward_list path; + stdext::arraylist path; for (uint8_t i = 0; i < numdirs; ++i) { uint8_t rawdir = msg.getPreviousByte(); switch (rawdir) { @@ -1592,7 +1592,7 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { return; } - addGameTask(&Game::playerAutoWalk, player->getID(), path); + addGameTask(&Game::playerAutoWalk, player->getID(), path.data()); } void ProtocolGame::parseSetOutfit(NetworkMessage &msg) { @@ -2728,7 +2728,7 @@ void ProtocolGame::parseSendBuyCharmRune(NetworkMessage &msg) { g_iobestiary().sendBuyCharmRune(player, runeID, action, raceid); } -void ProtocolGame::refreshCyclopediaMonsterTracker(const phmap::parallel_flat_hash_set> &trackerSet, bool isBoss) { +void ProtocolGame::refreshCyclopediaMonsterTracker(const std::unordered_set> &trackerSet, bool isBoss) { if (!player || oldProtocol) { return; } @@ -2809,12 +2809,11 @@ void ProtocolGame::BestiarysendCharms() { msg.addByte(4); // Unknown auto finishedMonstersSet = g_iobestiary().getBestiaryFinished(player); - std::list usedRunes = g_iobestiary().getCharmUsedRuneBitAll(player); - - for (charmRune_t charmRune : usedRunes) { + for (charmRune_t charmRune : g_iobestiary().getCharmUsedRuneBitAll(player)) { const auto tmpCharm = g_iobestiary().getBestiaryCharm(charmRune); uint16_t tmp_raceid = player->parseRacebyCharm(tmpCharm->id, false, 0); - finishedMonstersSet.erase(tmp_raceid); + + std::erase(finishedMonstersSet, tmp_raceid); } msg.add(finishedMonstersSet.size()); @@ -4261,7 +4260,7 @@ void ProtocolGame::sendContainer(uint8_t cid, std::shared_ptr contain } if (container->isStoreInbox()) { - auto categories = container->getStoreInboxValidCategories(); + const auto &categories = container->getStoreInboxValidCategories(); const auto enumName = container->getAttribute(ItemAttribute_t::STORE_INBOX_CATEGORY); auto category = magic_enum::enum_cast(enumName); if (category.has_value()) { @@ -5819,7 +5818,7 @@ void ProtocolGame::sendPartyCreatureUpdate(std::shared_ptr target) { void ProtocolGame::sendPartyCreatureShield(std::shared_ptr target) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -5837,7 +5836,7 @@ void ProtocolGame::sendPartyCreatureSkull(std::shared_ptr target) { } uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -5851,7 +5850,7 @@ void ProtocolGame::sendPartyCreatureSkull(std::shared_ptr target) { void ProtocolGame::sendPartyCreatureHealth(std::shared_ptr target, uint8_t healthPercent) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -5865,7 +5864,7 @@ void ProtocolGame::sendPartyCreatureHealth(std::shared_ptr target, uin void ProtocolGame::sendPartyPlayerMana(std::shared_ptr target, uint8_t manaPercent) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); } @@ -5883,7 +5882,7 @@ void ProtocolGame::sendPartyPlayerMana(std::shared_ptr target, uint8_t m void ProtocolGame::sendPartyCreatureShowStatus(std::shared_ptr target, bool showStatus) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); } @@ -5901,7 +5900,7 @@ void ProtocolGame::sendPartyCreatureShowStatus(std::shared_ptr target, void ProtocolGame::sendPartyPlayerVocation(std::shared_ptr target) { uint32_t cid = target->getID(); - if (knownCreatureSet.find(cid) == knownCreatureSet.end()) { + if (!knownCreatureSet.contains(cid)) { sendPartyCreatureUpdate(target); return; } @@ -7808,8 +7807,7 @@ void ProtocolGame::reloadCreature(std::shared_ptr creature) { NetworkMessage msg; - phmap::flat_hash_set::iterator it = std::find(knownCreatureSet.begin(), knownCreatureSet.end(), creature->getID()); - if (it != knownCreatureSet.end()) { + if (knownCreatureSet.contains(creature->getID())) { msg.addByte(0x6B); msg.addPosition(creature->getPosition()); msg.addByte(stackpos); @@ -8308,7 +8306,7 @@ void ProtocolGame::parseBosstiarySlot(NetworkMessage &msg) { addGameTask(&Game::playerBosstiarySlot, player->getID(), slotBossId, selectedBossId); } -void ProtocolGame::sendPodiumDetails(NetworkMessage &msg, const phmap::parallel_flat_hash_set &toSendMonsters, bool isBoss) const { +void ProtocolGame::sendPodiumDetails(NetworkMessage &msg, const std::vector &toSendMonsters, bool isBoss) const { auto toSendMonstersSize = static_cast(toSendMonsters.size()); msg.add(toSendMonstersSize); for (const auto &raceId : toSendMonsters) { @@ -8388,10 +8386,10 @@ void ProtocolGame::sendMonsterPodiumWindow(std::shared_ptr podium, const P bool isBossPodium = podium->getID() == ITEM_PODIUM_OF_VIGOUR; msg.addByte(isBossPodium ? 0x01 : 0x00); // Bosstiary or bestiary if (isBossPodium) { - const auto unlockedBosses = g_ioBosstiary().getBosstiaryFinished(player, 2); + const auto &unlockedBosses = g_ioBosstiary().getBosstiaryFinished(player, 2); sendPodiumDetails(msg, unlockedBosses, true); } else { - const auto unlockedMonsters = g_iobestiary().getBestiaryFinished(player); + const auto &unlockedMonsters = g_iobestiary().getBestiaryFinished(player); sendPodiumDetails(msg, unlockedMonsters, false); } diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index 2295c1036ea..8838fc39e7d 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -145,7 +145,7 @@ class ProtocolGame final : public Protocol { void parseBestiarysendCreatures(NetworkMessage &msg); void BestiarysendCharms(); void sendBestiaryEntryChanged(uint16_t raceid); - void refreshCyclopediaMonsterTracker(const phmap::parallel_flat_hash_set> &trackerSet, bool isBoss); + void refreshCyclopediaMonsterTracker(const std::unordered_set> &trackerSet, bool isBoss); void sendTeamFinderList(); void sendLeaderTeamFinder(bool reset); void createLeaderTeamFinder(NetworkMessage &msg); @@ -265,7 +265,7 @@ class ProtocolGame final : public Protocol { void parseSendBosstiary(); void parseSendBosstiarySlots(); void parseBosstiarySlot(NetworkMessage &msg); - void sendPodiumDetails(NetworkMessage &msg, const phmap::parallel_flat_hash_set &toSendMonsters, bool isBoss) const; + void sendPodiumDetails(NetworkMessage &msg, const std::vector &toSendMonsters, bool isBoss) const; void sendMonsterPodiumWindow(std::shared_ptr podium, const Position &position, uint16_t itemId, uint8_t stackPos); void parseSetMonsterPodium(NetworkMessage &msg) const; void sendBosstiaryCooldownTimer(); @@ -471,7 +471,7 @@ class ProtocolGame final : public Protocol { friend class Player; friend class PlayerWheel; - phmap::flat_hash_set knownCreatureSet; + std::unordered_set knownCreatureSet; std::shared_ptr player = nullptr; uint32_t eventConnect = 0; diff --git a/src/utils/arraylist.hpp b/src/utils/arraylist.hpp index ea803ab8cf0..94e05e2eb76 100644 --- a/src/utils/arraylist.hpp +++ b/src/utils/arraylist.hpp @@ -21,6 +21,25 @@ namespace stdext { template class arraylist { public: + arraylist() = default; + + explicit arraylist(size_t reserveSize) { + reserve(reserveSize); + } + + explicit arraylist(std::initializer_list _Ilist) { + backContainer.assign(_Ilist); + } + + arraylist &operator=(std::initializer_list _Ilist) { + backContainer.assign(_Ilist); + return *this; + } + + void assign(std::initializer_list _Ilist) { + backContainer.assign(_Ilist); + } + bool contains(const T &v) { update(); return std::ranges::find(backContainer, v) != backContainer.end(); @@ -128,7 +147,7 @@ namespace stdext { const auto &data() noexcept { update(); - return backContainer.data(); + return backContainer; } T &operator[](const size_t i) { diff --git a/src/utils/vectorset.hpp b/src/utils/vectorset.hpp index 29c6b37665e..dab8901bfc5 100644 --- a/src/utils/vectorset.hpp +++ b/src/utils/vectorset.hpp @@ -22,13 +22,13 @@ namespace stdext { public: bool contains(const T &v) { update(); - return v && std::ranges::binary_search(container, v); + return std::ranges::binary_search(container.begin(), container.end(), v, std::less()); } bool erase(const T &v) { update(); - const auto &it = std::ranges::lower_bound(container, v); + const auto it = std::ranges::lower_bound(container.begin(), container.end(), v, std::less()); if (it == container.end()) { return false; } @@ -43,13 +43,13 @@ namespace stdext { return std::erase_if(container, std::move(fnc)) > 0; } - void push_back(const T &v) { + void insert(const T &v) { needUpdate = true; return container.push_back(v); } template - auto emplace_back(_Valty &&... v) { + auto emplace(_Valty &&... v) { needUpdate = true; return container.emplace_back(v...); } @@ -64,6 +64,22 @@ namespace stdext { return container.insert(container.end(), list.begin(), list.end()); } + constexpr auto insert(std::vector::const_iterator _Where, const T &_Val) { + needUpdate = true; + return container.insert(_Where, _Val); + } + + constexpr auto insert(std::vector::const_iterator _Where, T &&_Val) { + needUpdate = true; + return container.insert(_Where, std::move(_Val)); + } + + template + constexpr auto insert(std::vector::const_iterator _Where, _Iter _First, _Iter _Last) { + needUpdate = true; + return container.insert(_Where, _First, _Last); + } + bool empty() const noexcept { return container.empty(); } @@ -95,6 +111,11 @@ namespace stdext { return container; } + T &operator[](const size_t i) { + update(); + return container[i]; + } + private: void update() noexcept { if (!needUpdate) { @@ -102,7 +123,7 @@ namespace stdext { } needUpdate = false; - std::ranges::sort(container); + std::ranges::sort(container.begin(), container.end(), std::less()); const auto &[f, l] = std::ranges::unique(container); container.erase(f, l); }