diff --git a/.github/workflows/analysis-sonarcloud.yml b/.github/workflows/analysis-sonarcloud.yml index 1b75d085097..d742af72625 100644 --- a/.github/workflows/analysis-sonarcloud.yml +++ b/.github/workflows/analysis-sonarcloud.yml @@ -2,9 +2,8 @@ name: Analysis - SonarCloud on: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - branches-ignore: + push: + branches: - main paths: - "src/**" @@ -22,14 +21,6 @@ jobs: steps: - uses: actions/checkout@v3 - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }} - with: - fetch-depth: 0 - ref: ${{github.event.pull_request.head.ref}} - repository: ${{github.event.pull_request.head.repo.full_name}} - - - uses: actions/checkout@v3 - if: ${{ github.event_name == 'push' }} with: fetch-depth: 0 @@ -75,20 +66,7 @@ jobs: mkdir -p build cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE="$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake" -DOPTIONS_ENABLE_CCACHE=ON -DSPEED_UP_BUILD_UNITY=OFF -S . -B build - - name: Run PR sonar-scanner - if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: | - sonar-scanner \ - --define sonar.cfamily.compile-commands=build/compile_commands.json \ - --define sonar.pullrequest.key=${{ github.event.pull_request.number }} \ - --define sonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} \ - --define sonar.pullrequest.base=${{ github.event.pull_request.base_ref }} - - name: Run sonar-scanner - if: ${{ github.event_name == 'push' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/data-canary/monster/demons/fury.lua b/data-canary/monster/demons/fury.lua index 7c1946d7991..cdaad15cf8f 100644 --- a/data-canary/monster/demons/fury.lua +++ b/data-canary/monster/demons/fury.lua @@ -7,9 +7,9 @@ monster.outfit = { lookType = 149, lookHead = 94, lookBody = 77, - lookLegs = 96, - lookFeet = 0, - lookAddons = 3, + lookLegs = 78, + lookFeet = 79, + lookAddons = 1, lookMount = 0, } @@ -23,8 +23,8 @@ monster.Bestiary = { CharmsPoints = 50, Stars = 4, Occurrence = 0, - Locations = "Pits of Inferno (Apocalypse's Throne Room), The Inquisition Quest \z - (The Shadow Nexus, Battlefield), Vengoth, Fury Dungeon, Oramond Fury Dungeon, The Extension Site.", + Locations = "Pits of Inferno (Apocalypse's Throne Room), The Inquisition Quest (The Shadow Nexus, Battlefield), \z + Vengoth, Fury Dungeon, Oramond Fury Dungeon, The Extension Site, Grounds of Destruction and Halls of Ascension.", } monster.health = 4100 @@ -50,7 +50,7 @@ monster.flags = { convinceable = false, pushable = false, rewardBoss = false, - illusionable = true, + illusionable = false, canPushItems = true, canPushCreatures = true, staticAttackChance = 70, @@ -59,9 +59,8 @@ monster.flags = { healthHidden = false, isBlockable = false, canWalkOnEnergy = false, - canWalkOnFire = false, + canWalkOnFire = true, canWalkOnPoison = false, - pet = false, } monster.light = { @@ -80,40 +79,41 @@ monster.voices = { monster.loot = { { id = 3007, chance = 410 }, -- crystal ring - { id = 3031, chance = 30000, maxCount = 100 }, -- gold coin - { id = 3031, chance = 30000, maxCount = 100 }, -- gold coin - { id = 3031, chance = 38000, maxCount = 69 }, -- gold coin - { id = 3035, chance = 2800, maxCount = 4 }, -- platinum coin - { id = 3065, chance = 20000 }, -- terra rod - { id = 3364, chance = 130 }, -- golden legs - { id = 3554, chance = 790 }, -- steel boots - { id = 5021, chance = 1500, maxCount = 4 }, -- orichalcum pearl - { id = 5911, chance = 4000 }, -- red piece of cloth - { id = 5944, chance = 21500 }, -- soul orb - { id = 5944, chance = 50 }, -- soul orb + { name = "gold coin", chance = 30000, maxCount = 100 }, + { name = "gold coin", chance = 30000, maxCount = 100 }, + { name = "gold coin", chance = 38000, maxCount = 69 }, + { name = "platinum coin", chance = 2800, maxCount = 4 }, + { name = "terra rod", chance = 20000 }, + { name = "golden legs", chance = 130 }, + { name = "steel boots", chance = 790 }, + { name = "orichalcum pearl", chance = 1500, maxCount = 4 }, + { name = "red piece of cloth", chance = 4000 }, + { name = "soul orb", chance = 21500 }, + { name = "soul orb", chance = 50 }, { id = 6300, chance = 60 }, -- death ring - { id = 6499, chance = 22500 }, -- demonic essence - { id = 6558, chance = 35000, maxCount = 3 }, -- concentrated demonic blood - { id = 7404, chance = 660 }, -- assassin dagger - { id = 7456, chance = 2000 }, -- noble axe - { id = 239, chance = 10500 }, -- great health potion - { id = 8016, chance = 29280, maxCount = 4 }, -- jalapeno pepper + { name = "demonic essence", chance = 22500 }, + { name = "flask of demonic blood", chance = 35000, maxCount = 3 }, + { name = "assassin dagger", chance = 660 }, + { name = "noble axe", chance = 2000 }, + { name = "great health potion", chance = 10500 }, + { name = "jalapeno pepper", chance = 29280, maxCount = 4 }, } monster.attacks = { { name = "melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -510 }, { name = "combat", interval = 2000, chance = 10, type = COMBAT_FIREDAMAGE, minDamage = -200, maxDamage = -300, length = 8, spread = 3, effect = CONST_ME_EXPLOSIONAREA, target = false }, - { name = "combat", interval = 2000, chance = 5, type = COMBAT_DEATHDAMAGE, minDamage = -120, maxDamage = -700, length = 8, spread = 3, target = false }, - { name = "combat", interval = 2000, chance = 10, type = COMBAT_DEATHDAMAGE, minDamage = -120, maxDamage = -300, radius = 4, target = false }, - -- {name ="fury skill reducer", interval = 2000, chance = 5, target = false}, + { name = "combat", interval = 2000, chance = 5, type = COMBAT_DEATHDAMAGE, minDamage = -120, maxDamage = -700, length = 8, spread = 3, effect = CONST_ME_DRAWBLOOD, target = false }, + { name = "combat", interval = 2000, chance = 10, type = COMBAT_DEATHDAMAGE, minDamage = -120, maxDamage = -300, radius = 4, effect = CONST_ME_DRAWBLOOD, target = false }, + { name = "fury skill reducer", interval = 2000, chance = 5, target = false }, { name = "combat", interval = 2000, chance = 10, type = COMBAT_LIFEDRAIN, minDamage = -120, maxDamage = -300, radius = 3, effect = CONST_ME_HITAREA, target = false }, { name = "combat", interval = 2000, chance = 10, type = COMBAT_DEATHDAMAGE, minDamage = -125, maxDamage = -250, range = 7, shootEffect = CONST_ANI_SUDDENDEATH, effect = CONST_ME_SMALLCLOUDS, target = false }, - { name = "speed", interval = 2000, chance = 15, speedChange = -100, range = 7, shootEffect = CONST_ANI_SUDDENDEATH, effect = CONST_ME_SMALLCLOUDS, target = false, duration = 30000 }, + { name = "speed", interval = 2000, chance = 15, speedChange = -800, range = 7, shootEffect = CONST_ANI_SUDDENDEATH, effect = CONST_ME_SMALLCLOUDS, target = false, duration = 30000 }, } monster.defenses = { defense = 20, - armor = 20, + armor = 35, + mitigation = 1.32, { name = "speed", interval = 2000, chance = 15, speedChange = 800, effect = CONST_ME_MAGIC_RED, target = false, duration = 5000 }, } diff --git a/data-canary/monster/familiars/sorcerer_familiar.lua b/data-canary/monster/familiars/sorcerer_familiar.lua index d153a83af28..31d61dfbf28 100644 --- a/data-canary/monster/familiars/sorcerer_familiar.lua +++ b/data-canary/monster/familiars/sorcerer_familiar.lua @@ -66,8 +66,8 @@ monster.voices = { monster.loot = {} monster.attacks = { - { name = "melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -200 }, - { name = "combat", interval = 2000, chance = 25, type = COMBAT_LIFEDRAIN, minDamage = -90, maxDamage = -150, length = 2, spread = 0, target = false }, + { name = "melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -280 }, + { name = "combat", interval = 2000, chance = 25, type = COMBAT_LIFEDRAIN, minDamage = -90, maxDamage = -150, length = 2, spread = 0, effect = CONST_ME_MAGIC_RED, target = false }, { name = "combat", interval = 2000, chance = 25, type = COMBAT_ENERGYDAMAGE, minDamage = -190, maxDamage = -210, length = 2, spread = 0, effect = CONST_ME_ENERGYHIT, target = false }, { name = "summon challenge", interval = 2000, chance = 40, target = false }, } diff --git a/data-canary/monster/magicals/frazzlemaw.lua b/data-canary/monster/magicals/frazzlemaw.lua index 366a39a1eab..4a87dce1e52 100644 --- a/data-canary/monster/magicals/frazzlemaw.lua +++ b/data-canary/monster/magicals/frazzlemaw.lua @@ -63,7 +63,6 @@ monster.flags = { canWalkOnEnergy = true, canWalkOnFire = true, canWalkOnPoison = true, - pet = false, } monster.light = { @@ -74,49 +73,49 @@ monster.light = { monster.voices = { interval = 5000, chance = 10, - { text = "Mwaaaahnducate youuuuuu *gurgle*, mwaaah!", yell = false }, { text = "Mwaaahgod! Overmwaaaaah! *gurgle*", yell = false }, - { text = "MMMWAHMWAHMWAHMWAAAAH!", yell = false }, + { text = "Mwaaaahnducate youuuuuu *gurgle*, mwaaah!", yell = false }, + { text = "MMMWAHMWAHMWAHMWAAAAH!", yell = true }, { text = "Mmmwhamwhamwhah, mwaaah!", yell = false }, } monster.loot = { - { id = 3031, chance = 100000, maxCount = 100 }, -- gold coin - { id = 3035, chance = 100000, maxCount = 7 }, -- platinum coin - { id = 3104, chance = 9500 }, -- banana skin - { id = 3110, chance = 10400 }, -- piece of iron - { id = 3111, chance = 10000 }, -- fishbone + { name = "gold coin", chance = 100000, maxCount = 100 }, + { name = "platinum coin", chance = 100000, maxCount = 7 }, + { name = "banana skin", chance = 9500 }, + { name = "piece of iron", chance = 10400 }, + { name = "fishbone", chance = 10000 }, { id = 3114, chance = 12680 }, -- skull { id = 3115, chance = 10000 }, -- bone { id = 3116, chance = 5500 }, -- big bone - { id = 3265, chance = 3200 }, -- two handed sword + { name = "two handed sword", chance = 3200 }, { id = 3578, chance = 6750, maxCount = 3 }, -- fish - { id = 3582, chance = 6000, maxCount = 2 }, -- ham - { id = 5880, chance = 3000 }, -- iron ore - { id = 5895, chance = 4700 }, -- fish fin - { id = 5925, chance = 5000 }, -- hardened bone + { name = "ham", chance = 6000, maxCount = 2 }, + { name = "iron ore", chance = 3000 }, + { name = "fish fin", chance = 4700 }, + { name = "hardened bone", chance = 5000 }, { id = 5951, chance = 10800 }, -- fish tail - { id = 7404, chance = 1000 }, -- assassin dagger - { id = 7407, chance = 2240 }, -- haunted blade - { id = 7418, chance = 1100 }, -- nightmare blade - { id = 238, chance = 15000, maxCount = 3 }, -- great mana potion - { id = 239, chance = 15000, maxCount = 2 }, -- great health potion - { id = 9058, chance = 2300 }, -- gold ingot - { id = 10389, chance = 1460 }, -- sai - { id = 16120, chance = 3000 }, -- violet crystal shard - { id = 16123, chance = 16000 }, -- brown crystal splinter - { id = 16126, chance = 7600 }, -- red crystal fragment + { name = "assassin dagger", chance = 1000 }, + { name = "haunted blade", chance = 2240 }, + { name = "nightmare blade", chance = 1100 }, + { name = "great mana potion", chance = 15000, maxCount = 3 }, + { name = "great health potion", chance = 15000, maxCount = 2 }, + { name = "gold ingot", chance = 2300 }, + { name = "sai", chance = 1460 }, + { name = "violet crystal shard", chance = 3000 }, + { name = "brown crystal splinter", chance = 16000 }, + { name = "red crystal fragment", chance = 7600 }, { id = 16279, chance = 10000 }, -- crystal rubbish - { id = 20062, chance = 450 }, -- cluster of solace - { id = 20198, chance = 18760 }, -- frazzle tongue - { id = 20199, chance = 16000 }, -- frazzle skin + { name = "cluster of solace", chance = 4450 }, + { name = "frazzle tongue", chance = 18760 }, + { name = "frazzle skin", chance = 16000 }, } monster.attacks = { { name = "melee", interval = 2000, chance = 100, minDamage = 0, maxDamage = -400 }, -- bleed - { name = "condition", type = CONDITION_BLEEDING, interval = 2000, chance = 10, minDamage = -300, maxDamage = -400, radius = 3, target = false }, - { name = "combat", interval = 2000, chance = 10, type = COMBAT_PHYSICALDAMAGE, minDamage = 0, maxDamage = -700, length = 5, spread = 3, effect = CONST_ME_EXPLOSIONAREA, target = false }, + { name = "condition", type = CONDITION_BLEEDING, interval = 2000, chance = 10, minDamage = -300, maxDamage = -400, radius = 3, effect = CONST_ME_DRAWBLOOD, target = false }, + { name = "combat", interval = 2000, chance = 10, type = COMBAT_LIFEDRAIN, minDamage = 0, maxDamage = -700, length = 5, spread = 0, effect = CONST_ME_EXPLOSIONAREA, target = false }, { name = "combat", interval = 2000, chance = 15, type = COMBAT_PHYSICALDAMAGE, minDamage = 0, maxDamage = -400, radius = 2, shootEffect = CONST_ANI_LARGEROCK, effect = CONST_ME_STONES, target = true }, { name = "speed", interval = 2000, chance = 15, speedChange = -600, radius = 5, effect = CONST_ME_MAGIC_RED, target = false, duration = 15000 }, { name = "combat", interval = 2000, chance = 10, type = COMBAT_MANADRAIN, minDamage = -80, maxDamage = -150, radius = 4, effect = CONST_ME_MAGIC_RED, target = false }, @@ -124,12 +123,13 @@ monster.attacks = { monster.defenses = { defense = 30, - armor = 30, + armor = 74, + mitigation = 2.31, { name = "combat", interval = 2000, chance = 15, type = COMBAT_HEALING, minDamage = 250, maxDamage = 425, effect = CONST_ME_HITBYPOISON, target = false }, } monster.elements = { - { type = COMBAT_PHYSICALDAMAGE, percent = 10 }, + { type = COMBAT_PHYSICALDAMAGE, percent = 5 }, { type = COMBAT_ENERGYDAMAGE, percent = 15 }, { type = COMBAT_EARTHDAMAGE, percent = 20 }, { type = COMBAT_FIREDAMAGE, percent = 10 }, @@ -137,8 +137,8 @@ monster.elements = { { type = COMBAT_MANADRAIN, percent = 0 }, { type = COMBAT_DROWNDAMAGE, percent = 0 }, { type = COMBAT_ICEDAMAGE, percent = 5 }, - { type = COMBAT_HOLYDAMAGE, percent = -10 }, - { type = COMBAT_DEATHDAMAGE, percent = 15 }, + { type = COMBAT_HOLYDAMAGE, percent = -5 }, + { type = COMBAT_DEATHDAMAGE, percent = 10 }, } monster.immunities = { diff --git a/data-canary/scripts/movements/noxious_Claw.lua b/data-canary/scripts/movements/noxious_Claw.lua deleted file mode 100644 index fc97ebcb4ba..00000000000 --- a/data-canary/scripts/movements/noxious_Claw.lua +++ /dev/null @@ -1,17 +0,0 @@ -local claw = MoveEvent() -claw:type("equip") - -function claw.onEquip(player, item, slot, isCheck) - if isCheck then - return true - end - - doTargetCombatHealth(0, player, COMBAT_PHYSICALDAMAGE, -200, -200, CONST_ME_DRAWBLOOD) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, (math.boolean_random() and "It tightens around your wrist as you take it on." or "Ouch! The serpent claw stabbed you.")) - item:transform(9392) - return true -end - -claw:id(9393) -claw:level(100) -claw:register() diff --git a/data-otservbr-global/scripts/actions/tools/noxious_claw.lua b/data-otservbr-global/scripts/actions/tools/noxious_claw.lua deleted file mode 100644 index b666ece019b..00000000000 --- a/data-otservbr-global/scripts/actions/tools/noxious_claw.lua +++ /dev/null @@ -1,15 +0,0 @@ -local noxiousClaw = Action() - -function noxiousClaw.onUse(player, item, fromPosition, target, toPosition, isHotkey) - local player, useItem, depleteChance = player, item, 5 - if player:getCondition(CONDITION_POISON) then - player:removeCondition(CONDITION_POISON) - end - useItem:transform(9394) - useItem:decay() - player:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN) - return true -end - -noxiousClaw:id(9392) -noxiousClaw:register() diff --git a/data-otservbr-global/scripts/movements/others/noxious_claw.lua b/data-otservbr-global/scripts/movements/others/noxious_claw.lua deleted file mode 100644 index 36cc6dabfee..00000000000 --- a/data-otservbr-global/scripts/movements/others/noxious_claw.lua +++ /dev/null @@ -1,17 +0,0 @@ -local noxiousClaw = MoveEvent() - -function noxiousClaw.onEquip(player, item, slot) - item:transform(9392) - if Tile(player:getPosition()):hasFlag(TILESTATE_PROTECTIONZONE) then - return true - end - - doTargetCombatHealth(0, player, COMBAT_PHYSICALDAMAGE, -200, -200, CONST_ME_DRAWBLOOD) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "It tightens around your wrist as you take it on.") - return true -end - -noxiousClaw:type("equip") -noxiousClaw:id(9393) -noxiousClaw:level(100) -noxiousClaw:register() diff --git a/data/libs/systems/exercise_training.lua b/data/libs/systems/exercise_training.lua deleted file mode 100644 index ab4282b3cbb..00000000000 --- a/data/libs/systems/exercise_training.lua +++ /dev/null @@ -1,125 +0,0 @@ -ExerciseWeaponsTable = { - -- MELE - [28540] = { skill = SKILL_SWORD }, - [28552] = { skill = SKILL_SWORD }, - [35279] = { skill = SKILL_SWORD }, - [35285] = { skill = SKILL_SWORD }, - [28553] = { skill = SKILL_AXE }, - [28541] = { skill = SKILL_AXE }, - [35280] = { skill = SKILL_AXE }, - [35286] = { skill = SKILL_AXE }, - [28554] = { skill = SKILL_CLUB }, - [28542] = { skill = SKILL_CLUB }, - [35281] = { skill = SKILL_CLUB }, - [35287] = { skill = SKILL_CLUB }, - [44064] = { skill = SKILL_SHIELD }, - [44065] = { skill = SKILL_SHIELD }, - [44066] = { skill = SKILL_SHIELD }, - [44067] = { skill = SKILL_SHIELD }, - -- ROD - [28544] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, - [28556] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, - [35283] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, - [35289] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, - -- RANGE - [28543] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, - [28555] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, - [35282] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, - [35288] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, - -- WAND - [28545] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, - [28557] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, - [35284] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, - [35290] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, -} - -local dummies = Game.getDummies() - -function LeaveTraining(playerId) - if _G.OnExerciseTraining[playerId] then - stopEvent(_G.OnExerciseTraining[playerId].event) - _G.OnExerciseTraining[playerId] = nil - end - - local player = Player(playerId) - if player then - player:setTraining(false) - end - return -end - -function ExerciseEvent(playerId, tilePosition, weaponId, dummyId) - local player = Player(playerId) - if not player then - return LeaveTraining(playerId) - end - - if player:isTraining() == 0 then - player:sendTextMessage(MESSAGE_FAILURE, "You have stopped training.") - return LeaveTraining(playerId) - end - - if not Tile(tilePosition):getItemById(dummyId) then - player:sendTextMessage(MESSAGE_FAILURE, "Someone has moved the dummy, the training has stopped.") - LeaveTraining(playerId) - return false - end - - local playerPosition = player:getPosition() - if not playerPosition:isProtectionZoneTile() then - player:sendTextMessage(MESSAGE_FAILURE, "You are no longer in a protection zone, the training has stopped.") - LeaveTraining(playerId) - return false - end - - if player:getItemCount(weaponId) <= 0 then - player:sendTextMessage(MESSAGE_FAILURE, "You need the training weapon in the backpack, the training has stopped.") - LeaveTraining(playerId) - return false - end - - local weapon = player:getItemById(weaponId, true) - if not weapon:isItem() or not weapon:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then - player:sendTextMessage(MESSAGE_FAILURE, "The selected item is not a training weapon, the training has stopped.") - LeaveTraining(playerId) - return false - end - - local weaponCharges = weapon:getAttribute(ITEM_ATTRIBUTE_CHARGES) - if not weaponCharges or weaponCharges <= 0 then - weapon:remove(1) -- ?? - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your training weapon has disappeared.") - LeaveTraining(playerId) - return false - end - - local isMagic = ExerciseWeaponsTable[weaponId].skill == SKILL_MAGLEVEL - if not dummies[dummyId] then - return false - end - local rate = dummies[dummyId] / 100 - - if isMagic then - player:addManaSpent(500 * rate) - else - player:addSkillTries(ExerciseWeaponsTable[weaponId].skill, 7 * rate) - end - - weapon:setAttribute(ITEM_ATTRIBUTE_CHARGES, (weaponCharges - 1)) - tilePosition:sendMagicEffect(CONST_ME_HITAREA) - - if ExerciseWeaponsTable[weaponId].effect then - playerPosition:sendDistanceEffect(tilePosition, ExerciseWeaponsTable[weaponId].effect) - end - - if weapon:getAttribute(ITEM_ATTRIBUTE_CHARGES) <= 0 then - weapon:remove(1) - player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your training weapon has disappeared.") - LeaveTraining(playerId) - return false - end - - local vocation = player:getVocation() - _G.OnExerciseTraining[playerId].event = addEvent(ExerciseEvent, vocation:getBaseAttackSpeed() / configManager.getFloat(configKeys.RATE_EXERCISE_TRAINING_SPEED), playerId, tilePosition, weaponId, dummyId) - return true -end diff --git a/data/libs/systems/load.lua b/data/libs/systems/load.lua index bea41404dd9..5c7073ad64e 100644 --- a/data/libs/systems/load.lua +++ b/data/libs/systems/load.lua @@ -3,7 +3,6 @@ dofile(CORE_DIRECTORY .. "/libs/systems/concoctions.lua") dofile(CORE_DIRECTORY .. "/libs/systems/daily_reward.lua") dofile(CORE_DIRECTORY .. "/libs/systems/encounters.lua") dofile(CORE_DIRECTORY .. "/libs/systems/exaltation_forge.lua") -dofile(CORE_DIRECTORY .. "/libs/systems/exercise_training.lua") dofile(CORE_DIRECTORY .. "/libs/systems/familiar.lua") dofile(CORE_DIRECTORY .. "/libs/systems/features.lua") dofile(CORE_DIRECTORY .. "/libs/systems/hazard.lua") diff --git a/data/scripts/actions/items/exercise_training_weapons.lua b/data/scripts/actions/items/exercise_training_weapons.lua index c8e7240902f..4a72f19e5c8 100644 --- a/data/scripts/actions/items/exercise_training_weapons.lua +++ b/data/scripts/actions/items/exercise_training_weapons.lua @@ -1,7 +1,132 @@ local exhaustionTime = 10 +local exerciseWeaponsTable = { + -- MELE + [28540] = { skill = SKILL_SWORD }, + [28552] = { skill = SKILL_SWORD }, + [35279] = { skill = SKILL_SWORD }, + [35285] = { skill = SKILL_SWORD }, + [28553] = { skill = SKILL_AXE }, + [28541] = { skill = SKILL_AXE }, + [35280] = { skill = SKILL_AXE }, + [35286] = { skill = SKILL_AXE }, + [28554] = { skill = SKILL_CLUB }, + [28542] = { skill = SKILL_CLUB }, + [35281] = { skill = SKILL_CLUB }, + [35287] = { skill = SKILL_CLUB }, + [44064] = { skill = SKILL_SHIELD }, + [44065] = { skill = SKILL_SHIELD }, + [44066] = { skill = SKILL_SHIELD }, + [44067] = { skill = SKILL_SHIELD }, + -- ROD + [28544] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, + [28556] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, + [35283] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, + [35289] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_SMALLICE, allowFarUse = true }, + -- RANGE + [28543] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, + [28555] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, + [35282] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, + [35288] = { skill = SKILL_DISTANCE, effect = CONST_ANI_SIMPLEARROW, allowFarUse = true }, + -- WAND + [28545] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, + [28557] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, + [35284] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, + [35290] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true }, +} + +local dummies = Game.getDummies() + +local function leaveExerciseTraining(playerId) + if _G.OnExerciseTraining[playerId] then + stopEvent(_G.OnExerciseTraining[playerId].event) + _G.OnExerciseTraining[playerId] = nil + end + + local player = Player(playerId) + if player then + player:setTraining(false) + end + return +end + +local function exerciseTrainingEvent(playerId, tilePosition, weaponId, dummyId) + local player = Player(playerId) + if not player then + return leaveExerciseTraining(playerId) + end + + if player:isTraining() == 0 then + player:sendTextMessage(MESSAGE_FAILURE, "You have stopped training.") + return leaveExerciseTraining(playerId) + end + + if not Tile(tilePosition):getItemById(dummyId) then + player:sendTextMessage(MESSAGE_FAILURE, "Someone has moved the dummy, the training has stopped.") + leaveExerciseTraining(playerId) + return false + end + + local playerPosition = player:getPosition() + if not playerPosition:isProtectionZoneTile() then + player:sendTextMessage(MESSAGE_FAILURE, "You are no longer in a protection zone, the training has stopped.") + leaveExerciseTraining(playerId) + return false + end + + if player:getItemCount(weaponId) <= 0 then + player:sendTextMessage(MESSAGE_FAILURE, "You need the training weapon in the backpack, the training has stopped.") + leaveExerciseTraining(playerId) + return false + end + + local weapon = player:getItemById(weaponId, true) + if not weapon:isItem() or not weapon:hasAttribute(ITEM_ATTRIBUTE_CHARGES) then + player:sendTextMessage(MESSAGE_FAILURE, "The selected item is not a training weapon, the training has stopped.") + leaveExerciseTraining(playerId) + return false + end + + local weaponCharges = weapon:getAttribute(ITEM_ATTRIBUTE_CHARGES) + if not weaponCharges or weaponCharges <= 0 then + weapon:remove(1) -- ?? + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your training weapon has disappeared.") + leaveExerciseTraining(playerId) + return false + end + + if not dummies[dummyId] then + return false + end + + local rate = dummies[dummyId] / 100 + local isMagic = exerciseWeaponsTable[weaponId].skill == SKILL_MAGLEVEL + if isMagic then + player:addManaSpent(500 * rate) + else + player:addSkillTries(exerciseWeaponsTable[weaponId].skill, 7 * rate) + end + + weapon:setAttribute(ITEM_ATTRIBUTE_CHARGES, (weaponCharges - 1)) + tilePosition:sendMagicEffect(CONST_ME_HITAREA) + + if exerciseWeaponsTable[weaponId].effect then + playerPosition:sendDistanceEffect(tilePosition, exerciseWeaponsTable[weaponId].effect) + end + + if weapon:getAttribute(ITEM_ATTRIBUTE_CHARGES) <= 0 then + weapon:remove(1) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Your training weapon has disappeared.") + leaveExerciseTraining(playerId) + return false + end + + local vocation = player:getVocation() + _G.OnExerciseTraining[playerId].event = addEvent(exerciseTrainingEvent, vocation:getBaseAttackSpeed() / configManager.getFloat(configKeys.RATE_EXERCISE_TRAINING_SPEED), playerId, tilePosition, weaponId, dummyId) + return true +end + local function isDummy(id) - local dummies = Game.getDummies() return dummies[id] and dummies[id] > 0 end @@ -22,7 +147,7 @@ function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, end local playerPos = player:getPosition() - if not ExerciseWeaponsTable[item.itemid].allowFarUse and (playerPos:getDistance(target:getPosition()) > 1) then + if not exerciseWeaponsTable[item.itemid].allowFarUse and (playerPos:getDistance(target:getPosition()) > 1) then player:sendTextMessage(MESSAGE_FAILURE, "Get closer to the dummy.") return true end @@ -62,7 +187,7 @@ function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, _G.OnExerciseTraining[playerId] = {} if not _G.OnExerciseTraining[playerId].event then - _G.OnExerciseTraining[playerId].event = addEvent(ExerciseEvent, 0, playerId, targetPos, item.itemid, targetId) + _G.OnExerciseTraining[playerId].event = addEvent(exerciseTrainingEvent, 0, playerId, targetPos, item.itemid, targetId) _G.OnExerciseTraining[playerId].dummyPos = targetPos player:setTraining(true) player:setExhaustion("training-exhaustion", exhaustionTime) @@ -73,7 +198,7 @@ function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, return false end -for weaponId, weapon in pairs(ExerciseWeaponsTable) do +for weaponId, weapon in pairs(exerciseWeaponsTable) do exerciseTraining:id(weaponId) if weapon.allowFarUse then exerciseTraining:allowFarUse(true) diff --git a/data/scripts/actions/tools/claw_of_the_noxious_spawn.lua b/data/scripts/actions/tools/claw_of_the_noxious_spawn.lua new file mode 100644 index 00000000000..5e49dda6e05 --- /dev/null +++ b/data/scripts/actions/tools/claw_of_the_noxious_spawn.lua @@ -0,0 +1,32 @@ +local cursed = Condition(CONDITION_CURSED) +cursed:setParameter(CONDITION_PARAM_DELAYED, true) +cursed:setParameter(CONDITION_PARAM_MINVALUE, -800) +cursed:setParameter(CONDITION_PARAM_MAXVALUE, -1200) +cursed:setParameter(CONDITION_PARAM_STARTVALUE, -1) +cursed:setParameter(CONDITION_PARAM_TICKINTERVAL, 4000) +cursed:setParameter(CONDITION_PARAM_FORCEUPDATE, true) + +local clawOfTheNoxiousSpawn = Action() + +function clawOfTheNoxiousSpawn.onUse(player, item, fromPosition, target, toPosition, isHotkey) + if item == player:getSlotItem(CONST_SLOT_RING) then + if math.random(100) <= 5 then + player:addCondition(cursed) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You are cursed by The Noxious Spawn!") + item:transform(9395) + item:decay() + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED) + player:addAchievement("Cursed!") + else + player:removeCondition(CONDITION_POISON) + item:transform(9394) + item:decay() + player:getPosition():sendMagicEffect(CONST_ME_MAGIC_GREEN) + end + return true + end + return false +end + +clawOfTheNoxiousSpawn:id(9392) +clawOfTheNoxiousSpawn:register() diff --git a/data/scripts/movements/claw_of_the_noxious_spawn.lua b/data/scripts/movements/claw_of_the_noxious_spawn.lua new file mode 100644 index 00000000000..77e0e60877c --- /dev/null +++ b/data/scripts/movements/claw_of_the_noxious_spawn.lua @@ -0,0 +1,18 @@ +local clawOfTheNoxiousSpawn = MoveEvent() + +function clawOfTheNoxiousSpawn.onEquip(player, item, slot, isCheck) + if not isCheck then + if not Tile(player:getPosition()):hasFlag(TILESTATE_PROTECTIONZONE) then + doTargetCombat(0, player, COMBAT_PHYSICALDAMAGE, -150, -200, CONST_ME_DRAWBLOOD) + player:sendTextMessage(MESSAGE_EVENT_ADVANCE, (math.boolean_random() and "It tightens around your wrist as you take it on." or "Ouch! The serpent claw stabbed you.")) + return true + end + end + return true +end + +clawOfTheNoxiousSpawn:type("equip") +clawOfTheNoxiousSpawn:slot("ring") +clawOfTheNoxiousSpawn:id(9393) +clawOfTheNoxiousSpawn:level(100) +clawOfTheNoxiousSpawn:register() diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 9bc7077c92c..56cd53bf567 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -341,8 +341,17 @@ void CanaryServer::loadModules() { } auto coreFolder = g_configManager().getString(CORE_DIRECTORY, __FUNCTION__); - // Load items dependencies + // Load appearances.dat first modulesLoadHelper((g_game().loadAppearanceProtobuf(coreFolder + "/items/appearances.dat") == ERROR_NONE), "appearances.dat"); + + // Load XML folder dependencies (order matters) + modulesLoadHelper(g_vocations().loadFromXml(), "XML/vocations.xml"); + modulesLoadHelper(g_eventsScheduler().loadScheduleEventFromXml(), "XML/events.xml"); + modulesLoadHelper(Outfits::getInstance().loadFromXml(), "XML/outfits.xml"); + modulesLoadHelper(Familiars::getInstance().loadFromXml(), "XML/familiars.xml"); + modulesLoadHelper(g_imbuements().loadFromXml(), "XML/imbuements.xml"); + modulesLoadHelper(g_storages().loadFromXML(), "XML/storages.xml"); + modulesLoadHelper(Item::items.loadFromXml(), "items.xml"); const auto datapackFolder = g_configManager().getString(DATA_DIRECTORY, __FUNCTION__); @@ -351,17 +360,10 @@ void CanaryServer::loadModules() { modulesLoadHelper((g_luaEnvironment().loadFile(coreFolder + "/core.lua", "core.lua") == 0), "core.lua"); modulesLoadHelper(g_scripts().loadScripts(coreFolder + "/scripts/lib", true, false), coreFolder + "/scripts/libs"); modulesLoadHelper(g_scripts().loadScripts(coreFolder + "/scripts", false, false), coreFolder + "/scripts"); + modulesLoadHelper((g_npcs().load(true, false)), "npclib"); - // Second XML scripts - modulesLoadHelper(g_vocations().loadFromXml(), "XML/vocations.xml"); - modulesLoadHelper(g_eventsScheduler().loadScheduleEventFromXml(), "XML/events.xml"); - modulesLoadHelper(Outfits::getInstance().loadFromXml(), "XML/outfits.xml"); - modulesLoadHelper(Familiars::getInstance().loadFromXml(), "XML/familiars.xml"); - modulesLoadHelper(g_imbuements().loadFromXml(), "XML/imbuements.xml"); - modulesLoadHelper(g_storages().loadFromXML(), "XML/storages.xml"); - modulesLoadHelper(g_modules().loadFromXml(), "modules/modules.xml"); modulesLoadHelper(g_events().loadFromXml(), "events/events.xml"); - modulesLoadHelper((g_npcs().load(true, false)), "npclib"); + modulesLoadHelper(g_modules().loadFromXml(), "modules/modules.xml"); logger.debug("Loading datapack scripts on folder: {}/", datapackName); // Load scripts diff --git a/src/creatures/combat/spells.hpp b/src/creatures/combat/spells.hpp index c33deeeb948..cd1a7aaa623 100644 --- a/src/creatures/combat/spells.hpp +++ b/src/creatures/combat/spells.hpp @@ -191,8 +191,14 @@ class Spell : public BaseSpell { [[nodiscard]] const VocSpellMap &getVocMap() const { return vocSpellMap; } - void addVocMap(uint16_t n, bool b) { - vocSpellMap[n] = b; + void addVocMap(uint16_t vocationId, bool b) { + if (vocationId == 0XFFFF) { + g_logger().error("Vocation overflow for spell: {}", getName()); + return; + } + + g_logger().trace("Adding spell: {} to voc id: {}", getName(), vocationId); + vocSpellMap[vocationId] = b; } SpellGroup_t getGroup() { diff --git a/src/game/scheduling/save_manager.cpp b/src/game/scheduling/save_manager.cpp index 6e8b76050ad..2c1eff6657c 100644 --- a/src/game/scheduling/save_manager.cpp +++ b/src/game/scheduling/save_manager.cpp @@ -59,7 +59,9 @@ void SaveManager::schedulePlayer(std::weak_ptr playerPtr) { // Disable save async if the config is set to false if (!g_configManager().getBoolean(TOGGLE_SAVE_ASYNC, __FUNCTION__)) { - logger.debug("Saving player {}.", playerToSave->getName()); + if (g_game().getGameState() == GAME_STATE_NORMAL) { + logger.debug("Saving player {}.", playerToSave->getName()); + } doSavePlayer(playerToSave); return; } @@ -90,7 +92,9 @@ bool SaveManager::doSavePlayer(std::shared_ptr player) { Benchmark bm_savePlayer; Player::PlayerLock lock(player); m_playerMap.erase(player->getGUID()); - logger.debug("Saving player {}...", player->getName()); + if (g_game().getGameState() == GAME_STATE_NORMAL) { + logger.debug("Saving player {}.", player->getName()); + } bool saveSuccess = IOLoginData::savePlayer(player); if (!saveSuccess) { diff --git a/src/io/iomapserialize.cpp b/src/io/iomapserialize.cpp index a0ac392d955..475a210a760 100644 --- a/src/io/iomapserialize.cpp +++ b/src/io/iomapserialize.cpp @@ -47,8 +47,9 @@ void IOMapSerialize::loadHouseItems(Map* map) { while (item_count--) { if (auto houseTile = std::dynamic_pointer_cast(tile)) { - const auto house = houseTile->getHouse(); - if (house->getOwner() == 0) { + const auto &house = houseTile->getHouse(); + auto isTransferOnRestart = g_configManager().getBoolean(TOGGLE_HOUSE_TRANSFER_ON_SERVER_RESTART, __FUNCTION__); + if (!isTransferOnRestart && house->getOwner() == 0) { g_logger().trace("Skipping load item from house id: {}, position: {}, house does not have owner", house->getId(), house->getEntryPosition().toString()); house->clearHouseInfo(false); continue; diff --git a/src/items/item.cpp b/src/items/item.cpp index d937f2c7bd4..b51c076d80b 100644 --- a/src/items/item.cpp +++ b/src/items/item.cpp @@ -831,7 +831,7 @@ Attr_ReadValue Item::readAttr(AttrTypes_t attr, PropStream &propStream) { return ATTR_READ_ERROR; } - g_logger().debug("Setting flag {} flags, to item id {}", flags, getID()); + g_logger().trace("Setting obtain flag {} flags, to item id {}", flags, getID()); setAttribute(ItemAttribute_t::OBTAINCONTAINER, flags); break; }