diff --git a/.gitignore b/.gitignore index aae56bd35a9..d233ae17409 100644 --- a/.gitignore +++ b/.gitignore @@ -372,12 +372,15 @@ config.lua config_canary.lua client_assertions.txt .env +otservbr.otbm +canary.otbm +otservbr-custom.otbm + # Extensions *.ini *.otb *.exe *.manifest -*.otbm *.rar *-house.xml *-monster.xml diff --git a/data-canary/scripts/actions/other/spellbook.lua b/data-canary/scripts/actions/other/spellbook.lua deleted file mode 100644 index 600f60a02e9..00000000000 --- a/data-canary/scripts/actions/other/spellbook.lua +++ /dev/null @@ -1,38 +0,0 @@ -local spellbook = Action() - -function spellbook.onUse(player, item, fromPosition, target, toPosition, isHotkey) - local text = {} - local spells = {} - for _, spell in ipairs(player:getInstantSpells()) do - if spell.level ~= 0 then - if spell.manapercent > 0 then - spell.mana = spell.manapercent .. "%" - end - spells[#spells + 1] = spell - end - end - - table.sort(spells, function(a, b) - return a.level < b.level - end) - - local prevLevel = -1 - for i, spell in ipairs(spells) do - if prevLevel ~= spell.level then - if i == 1 then - text[#text == nil and 1 or #text + 1] = "Spells for Level " - else - text[#text + 1] = "\nSpells for Level " - end - text[#text + 1] = spell.level .. "\n" - prevLevel = spell.level - end - text[#text + 1] = spell.words .. " - " .. spell.name .. " : " .. spell.mana .. "\n" - end - - player:showTextDialog(item:getId(), table.concat(text)) - return true -end - -spellbook:id(3059, 6120, 8900, 8901, 8902, 8903, 8904, 8918, 14769, 16107, 20088, 20089, 20090, 21400) -spellbook:register() diff --git a/data-otservbr-global/raids/darashia/tyrn.xml b/data-otservbr-global/raids/darashia/tyrn.xml deleted file mode 100644 index 21b39dda549..00000000000 --- a/data-otservbr-global/raids/darashia/tyrn.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/data-otservbr-global/raids/roshamuul/mawhawk.xml b/data-otservbr-global/raids/roshamuul/mawhawk.xml deleted file mode 100644 index db48081d57a..00000000000 --- a/data-otservbr-global/raids/roshamuul/mawhawk.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/data-otservbr-global/scripts/actions/other/door_shive1.lua b/data-otservbr-global/scripts/actions/other/door_shive1.lua deleted file mode 100644 index 2e0baa7052b..00000000000 --- a/data-otservbr-global/scripts/actions/other/door_shive1.lua +++ /dev/null @@ -1,16 +0,0 @@ -local doorShive1 = Action() - -function doorShive1.onUse(player, item, fromPosition, target, toPosition, isHotkey) - local position = player:getPosition() - if position.y == toPosition.y then - return false - end - - toPosition.y = position.y > toPosition.y and toPosition.y - 1 or toPosition.y + 1 - player:teleportTo(toPosition) - toPosition:sendMagicEffect(CONST_ME_TELEPORT) - return true -end - -doorShive1:id(13278, 13279, 13280, 13281, 13282, 13283) -doorShive1:register() diff --git a/data-otservbr-global/scripts/actions/other/door_shive2.lua b/data-otservbr-global/scripts/actions/other/door_shive2.lua deleted file mode 100644 index f1131295acc..00000000000 --- a/data-otservbr-global/scripts/actions/other/door_shive2.lua +++ /dev/null @@ -1,16 +0,0 @@ -local doorShive2 = Action() - -function doorShive2.onUse(player, item, fromPosition, target, toPosition, isHotkey) - local position = player:getPosition() - if position.x == toPosition.x then - return false - end - - toPosition.x = position.x > toPosition.x and toPosition.x - 1 or toPosition.x + 1 - player:teleportTo(toPosition) - toPosition:sendMagicEffect(CONST_ME_TELEPORT) - return true -end - -doorShive2:id(13290, 13291, 13292, 13293, 13294) -doorShive2:register() diff --git a/data-otservbr-global/scripts/actions/spellbook.lua b/data-otservbr-global/scripts/actions/spellbook.lua deleted file mode 100644 index 2e1328bcac4..00000000000 --- a/data-otservbr-global/scripts/actions/spellbook.lua +++ /dev/null @@ -1,58 +0,0 @@ -local spellbook = Action() - -function spellbook.onUse(player, item, fromPosition, target, toPosition, isHotkey) - local text = "" - local tlvl = {} - local tml = {} - - for _, spell in ipairs(player:getInstantSpells()) do - if spell.level ~= 0 or spell.mlevel ~= 0 then - if spell.manapercent > 0 then - spell.mana = spell.manapercent .. "%" - end - if spell.level > 0 then - tlvl[#tlvl + 1] = spell - elseif spell.mlevel > 0 then - tml[#tml + 1] = spell - end - end - end - - table.sort(tlvl, function(a, b) - return a.level < b.level - end) - local prevLevel = -1 - for i, spell in ipairs(tlvl) do - local line = "" - if prevLevel ~= spell.level then - if i ~= 1 then - line = "\n" - end - line = line .. "Spells for Level " .. spell.level .. "\n" - prevLevel = spell.level - end - text = text .. line .. " " .. spell.words .. " - " .. spell.name .. " : " .. spell.mana .. "\n" - end - text = text .. "\n" - table.sort(tml, function(a, b) - return a.mlevel < b.mlevel - end) - local prevmLevel = -1 - for i, spell in ipairs(tml) do - local line = "" - if prevLevel ~= spell.mlevel then - if i ~= 1 then - line = "\n" - end - line = line .. "Spells for Magic Level " .. spell.mlevel .. "\n" - prevmLevel = spell.mlevel - end - text = text .. line .. " " .. spell.words .. " - " .. spell.name .. " : " .. spell.mana .. "\n" - end - - player:showTextDialog(item:getId(), text) - return true -end - -spellbook:id(3059, 6120, 8072, 8073, 8074, 8075, 8076, 8090, 11691, 14769, 16107, 20088, 21400, 22755, 25699, 29431, 20089, 20090, 34153) -spellbook:register() diff --git a/data-otservbr-global/scripts/globalevents/others/hireling_save.lua b/data-otservbr-global/scripts/globalevents/others/hireling_save.lua deleted file mode 100644 index 19a3ba364f2..00000000000 --- a/data-otservbr-global/scripts/globalevents/others/hireling_save.lua +++ /dev/null @@ -1,8 +0,0 @@ -local hirelingSave = GlobalEvent("hirelingSave") -function hirelingSave.onShutdown() - logger.info("Saving Hirelings") - SaveHirelings() - return true -end - -hirelingSave:register() diff --git a/data-otservbr-global/scripts/globalevents/others/raids_schedule.lua b/data-otservbr-global/scripts/globalevents/others/raids_schedule.lua new file mode 100644 index 00000000000..be6070d857a --- /dev/null +++ b/data-otservbr-global/scripts/globalevents/others/raids_schedule.lua @@ -0,0 +1,53 @@ +local raidSchedule = { + ["Tuesday"] = { + ["16:00"] = { raidName = "Midnight Panther" }, + }, + ["Wednesday"] = { + ["12:00"] = { raidName = "Draptor" }, + }, + ["Thursday"] = { + ["19:00"] = { raidName = "Undead Cavebear" }, + }, + ["Friday"] = { + ["06:00"] = { raidName = "Titanica" }, + }, + ["Saturday"] = { + ["20:00"] = { raidName = "Draptor" }, + }, + ["Sunday"] = { + ["15:00"] = { raidName = "Midnight Panther" }, + ["13:00"] = { raidName = "Orc Backpack" }, + }, + ["31/10"] = { + ["16:00"] = { raidName = "Halloween Hare" }, + }, +} + +local spawnRaidsEvent = GlobalEvent("SpawnRaidsEvent") + +function spawnRaidsEvent.onThink(interval, lastExecution, thinkInterval) + local currentDayOfWeek, currentDate = os.date("%A"), getRealDate() + local raidsToSpawn = {} + + if raidSchedule[currentDayOfWeek] then + raidsToSpawn[#raidsToSpawn + 1] = raidSchedule[currentDayOfWeek] + end + + if raidSchedule[currentDate] then + raidsToSpawn[#raidsToSpawn + 1] = raidSchedule[currentDate] + end + + if #raidsToSpawn > 0 then + for i = 1, #raidsToSpawn do + local currentRaidSchedule = raidsToSpawn[i][getRealTime()] + if currentRaidSchedule and not currentRaidSchedule.alreadyExecuted then + Game.startRaid(currentRaidSchedule.raidName) + currentRaidSchedule.alreadyExecuted = true + end + end + end + return true +end + +spawnRaidsEvent:interval(60000) +spawnRaidsEvent:register() diff --git a/data-otservbr-global/scripts/globalevents/spawn/grimvale_respawn.lua b/data-otservbr-global/scripts/globalevents/spawn/grimvale_respawn.lua deleted file mode 100644 index aff3f6e3fa0..00000000000 --- a/data-otservbr-global/scripts/globalevents/spawn/grimvale_respawn.lua +++ /dev/null @@ -1,59 +0,0 @@ -local config = { - position = { fromPosition = Position(33330, 31670, 7), toPosition = Position(33350, 31690, 7) }, -} -local spawnDay = 13 -local currentDay = os.date("%d") -local monsters = {} - -function Game.createRandom(position) - local tile = Tile(position) - if not tile or Tile(position):getItemById(486) then - return false - end - - local ground = tile:getGround() - if not ground or ground:hasProperty(CONST_PROP_BLOCKSOLID) or tile:getTopCreature() then - return false - end - local monsterName = monsters[math.random(#monsters)] - local monster = Game.createMonster(monsterName, position) - if monster then - monster:setSpawnPosition() - monster:remove() - end - return true -end - -local grimvaleRespawn = GlobalEvent("grimvale respawn") -function grimvaleRespawn.onStartup() - if spawnDay == tonumber(currentDay) then - table.insert(monsters, "wereboar") - table.insert(monsters, "werebadger") - for x = config.position.fromPosition.x, config.position.toPosition.x do - for y = config.position.fromPosition.y, config.position.toPosition.y do - if math.random(1000) >= 983 then - if Game.createRandom(Position(x, y, 7)) then - return - end - end - end - end - else - table.insert(monsters, "bandit") - table.insert(monsters, "badger") - table.insert(monsters, "blue butterfly") - table.insert(monsters, "yellow butterfly") - for x = config.position.fromPosition.x, config.position.toPosition.x do - for y = config.position.fromPosition.y, config.position.toPosition.y do - if math.random(1000) >= 983 then - if Game.createRandom(Position(x, y, 7)) then - return - end - end - end - end - end - return true -end - -grimvaleRespawn:register() diff --git a/data-otservbr-global/scripts/globalevents/spawn/mawhawk.lua b/data-otservbr-global/scripts/globalevents/spawn/mawhawk.lua deleted file mode 100644 index e34657d211c..00000000000 --- a/data-otservbr-global/scripts/globalevents/spawn/mawhawk.lua +++ /dev/null @@ -1,18 +0,0 @@ -local config = { - monsterName = "Mawhawk", - bossPosition = Position(33703, 32461, 7), - centerPosition = Position(33703, 32461, 7), - rangeX = 50, - rangeY = 50, -} - -local mawhawk = GlobalEvent("mawhawk") -function mawhawk.onThink(interval, lastExecution) - if not checkBoss(config.centerPosition, config.rangeX, config.rangeY, config.monsterName, config.bossPosition) then - addEvent(Game.broadcastMessage, 150, "Beware! Mawhawk!", MESSAGE_EVENT_ADVANCE) - end - return true -end - -mawhawk:interval(10 * 60 * 60 * 1000) -- spawns every 10 hours -mawhawk:register() diff --git a/data-otservbr-global/scripts/globalevents/spawn/raids.lua b/data-otservbr-global/scripts/globalevents/spawn/raids.lua deleted file mode 100644 index 83d065349dd..00000000000 --- a/data-otservbr-global/scripts/globalevents/spawn/raids.lua +++ /dev/null @@ -1,65 +0,0 @@ -local raids = { - --Terça-Feira - ["Tuesday"] = { - ["16:00"] = { raidName = "Midnight Panther" }, - }, - - --Quarta-Feira - ["Wednesday"] = { - ["12:00"] = { raidName = "Draptor" }, - }, - - --Quinta-Feira - ["Thursday"] = { - ["19:00"] = { raidName = "Undead Cavebear" }, - }, - - --Sexta-feira - ["Friday"] = { - ["06:00"] = { raidName = "Titanica" }, - }, - - --Sábado - ["Saturday"] = { - ["20:00"] = { raidName = "Draptor" }, - }, - - --Domingo - ["Sunday"] = { - ["15:00"] = { raidName = "Midnight Panther" }, - ["13:00"] = { raidName = "Orc Backpack" }, - }, - - -- By date (Day/Month) - ["31/10"] = { - ["16:00"] = { raidName = "Halloween Hare" }, - }, -} - -local spawnRaids = GlobalEvent("spawn raids") -function spawnRaids.onThink(interval, lastExecution, thinkInterval) - local day, date = os.date("%A"), getRealDate() - - local raidDays = {} - if raids[day] then - raidDays[#raidDays + 1] = raids[day] - end - if raids[date] then - raidDays[#raidDays + 1] = raids[date] - end - if #raidDays == 0 then - return true - end - - for i = 1, #raidDays do - local settings = raidDays[i][getRealTime()] - if settings and not settings.alreadyExecuted then - Game.startRaid(settings.raidName) - settings.alreadyExecuted = true - end - end - return true -end - -spawnRaids:interval(60000) -spawnRaids:register() diff --git a/data-otservbr-global/scripts/globalevents/spawn/thawing_dragon_lord.lua b/data-otservbr-global/scripts/globalevents/spawn/thawing_dragon_lord.lua deleted file mode 100644 index eecbd29022b..00000000000 --- a/data-otservbr-global/scripts/globalevents/spawn/thawing_dragon_lord.lua +++ /dev/null @@ -1,17 +0,0 @@ -local config = { - monsterName = "Thawing Dragon Lord", - bossPosition = Position(33361, 31316, 5), - centerPosition = Position(33361, 31316, 5), - rangeX = 50, - rangeY = 50, -} - -local thawingDragonLord = GlobalEvent("thawing dragon lord") - -function thawingDragonLord.onThink(interval, lastExecution) - checkBoss(config.centerPosition, config.rangeX, config.rangeY, config.monsterName, config.bossPosition) - return true -end - -thawingDragonLord:interval(900000) -thawingDragonLord:register() diff --git a/data-otservbr-global/scripts/globalevents/spawn/tyrn.lua b/data-otservbr-global/scripts/globalevents/spawn/tyrn.lua deleted file mode 100644 index 47e7756f2ba..00000000000 --- a/data-otservbr-global/scripts/globalevents/spawn/tyrn.lua +++ /dev/null @@ -1,18 +0,0 @@ -local config = { - monsterName = "Tyrn", - bossPosition = Position(33056, 32393, 14), - centerPosition = Position(33056, 32393, 14), - rangeX = 50, - rangeY = 50, -} - -local tyrn = GlobalEvent("tyrn") -function tyrn.onThink(interval, lastExecution) - if not checkBoss(config.centerPosition, config.rangeX, config.rangeY, config.monsterName, config.bossPosition) then - addEvent(Game.broadcastMessage, 150, "Beware of Tyrn!", MESSAGE_EVENT_ADVANCE) - end - return true -end - -tyrn:interval(9 * 60 * 60 * 1000) -- spawns every 9 hours -tyrn:register() diff --git a/data-otservbr-global/scripts/globalevents/worldchanges/dream_courts_worldchange.lua b/data-otservbr-global/scripts/globalevents/worldchanges/dream_courts_worldchange.lua deleted file mode 100644 index 090887b9540..00000000000 --- a/data-otservbr-global/scripts/globalevents/worldchanges/dream_courts_worldchange.lua +++ /dev/null @@ -1,21 +0,0 @@ -local config = { - ["Monday"] = "Plagueroot", - ["Tuesday"] = "Malofur_Mangrinder", - ["Wednesday"] = "Maxxenius", - ["Thursday"] = "Alptramun", - ["Friday"] = "Izcandar_the_Banished", - ["Saturday"] = "Maxxenius", - ["Sunday"] = "Alptramun", -} -local spawnByDay = true - -local DreamCourts = GlobalEvent("DreamCourts") -function DreamCourts.onStartup() - if spawnByDay then - logger.info("[WorldChanges] Dream Courts loaded: {}.otbm", config[os.date("%A")]) - Game.loadMap("data-otservbr-global/world/world_changes/dream_courts_bosses/" .. config[os.date("%A")] .. ".otbm") - end - return true -end - -DreamCourts:register() diff --git a/data-otservbr-global/scripts/globalevents/worldchanges/their_masters_voice.lua b/data-otservbr-global/scripts/globalevents/worldchanges/their_masters_voice.lua deleted file mode 100644 index 2061c254cf9..00000000000 --- a/data-otservbr-global/scripts/globalevents/worldchanges/their_masters_voice.lua +++ /dev/null @@ -1,31 +0,0 @@ -local theirmastersvoice = GlobalEvent("theirmastersvoice") -function theirmastersvoice.onStartup() - local eventEnabled = true - local eventChance = 20 - local function fillFungus(fromPosition, toPosition) - for x = fromPosition.x, toPosition.x do - for y = fromPosition.y, toPosition.y do - local position = Position(x, y, 9) - local tile = Tile(position) - if tile then - local item = tile:getItemById(12065) - if item then - local slimeChance = math.random(100) - if slimeChance <= 30 then - item:transform(math.random(12059, 12063)) - position:sendMagicEffect(CONST_ME_YELLOW_RINGS) - end - end - end - end - end - end - - if eventEnabled then - if math.random(100) <= eventChance then - fillFungus({ x = 33306, y = 31847 }, { x = 33369, y = 31919 }) - end - end -end - -theirmastersvoice:register() diff --git a/data-otservbr-global/scripts/world_changes/grimvale_respawn_event.lua b/data-otservbr-global/scripts/world_changes/grimvale_respawn_event.lua new file mode 100644 index 00000000000..b1cea5504e9 --- /dev/null +++ b/data-otservbr-global/scripts/world_changes/grimvale_respawn_event.lua @@ -0,0 +1,40 @@ +local grimvaleConfig = { + position = { fromPosition = Position(33330, 31670, 7), toPosition = Position(33350, 31690, 7) }, + spawnDay = 13, +} + +local function createRandomMonster(position, availableMonsters) + local tile = Tile(position) + if not tile or tile:getItemById(486) or tile:hasProperty(CONST_PROP_BLOCKSOLID) or tile:getTopCreature() then + return false + end + + local monsterName = availableMonsters[math.random(#availableMonsters)] + local monster = Game.createMonster(monsterName, position) + if monster then + monster:setSpawnPosition() + monster:remove() + end + return true +end + +local function spawnMonsters(monstersToSpawn) + for x = grimvaleConfig.position.fromPosition.x, grimvaleConfig.position.toPosition.x do + for y = grimvaleConfig.position.fromPosition.y, grimvaleConfig.position.toPosition.y do + if math.random(1000) >= 983 then + if createRandomMonster(Position(x, y, 7), monstersToSpawn) then + break + end + end + end + end +end + +local grimvaleRespawnEvent = GlobalEvent("GrimvaleRespawnEvent") + +function grimvaleRespawnEvent.onStartup() + spawnMonsters(grimvaleConfig.spawnDay == tonumber(os.date("%d")) and { "wereboar", "werebadger" } or { "bandit", "badger", "blue butterfly", "yellow butterfly" }) + return true +end + +grimvaleRespawnEvent:register() diff --git a/data-otservbr-global/scripts/world_changes/the_dream_courts.lua b/data-otservbr-global/scripts/world_changes/the_dream_courts.lua new file mode 100644 index 00000000000..bb3bcc3a6a8 --- /dev/null +++ b/data-otservbr-global/scripts/world_changes/the_dream_courts.lua @@ -0,0 +1,26 @@ +local dreamCourtsConfig = { + ["Monday"] = { map = "plagueroot", bossName = "Plagueroot" }, + ["Tuesday"] = { map = "malofur_mangrinder", bossName = "Malofur Mangrinder" }, + ["Wednesday"] = { map = "maxxenius", bossName = "Maxxenius" }, + ["Thursday"] = { map = "alptramun", bossName = "Alptramun" }, + ["Friday"] = { map = "izcandar_the_banished", bossName = "Izcandar the Banished" }, + ["Saturday"] = { map = "maxxenius", bossName = "Maxxenius" }, + ["Sunday"] = { map = "alptramun", bossName = "Alptramun" }, +} + +local dreamCourtsEvent = GlobalEvent("DreamCourts") + +function dreamCourtsEvent.onStartup() + local currentDay = os.date("%A") + local dayConfig = dreamCourtsConfig[currentDay] + if not dayConfig then + logger.warn("[World Change] The Dream Courts map not defined for the current day: {}", currentDay) + return false + end + + Game.loadMap(DATA_DIRECTORY .. "/world/quest/the_dream_courts/" .. dayConfig.map .. ".otbm") + logger.info("[World Change] The Dream Courts today's boss is: {}!", dayConfig.bossName) + return true +end + +dreamCourtsEvent:register() diff --git a/data-otservbr-global/scripts/world_changes/their_masters_voice.lua b/data-otservbr-global/scripts/world_changes/their_masters_voice.lua new file mode 100644 index 00000000000..af1354dae6c --- /dev/null +++ b/data-otservbr-global/scripts/world_changes/their_masters_voice.lua @@ -0,0 +1,21 @@ +local theirMastersVoiceEvent = GlobalEvent("TheirMastersVoice") + +function theirMastersVoiceEvent.onStartup() + if math.random(100) <= 20 then + for x = 33306, 33369 do + for y = 31847, 31919 do + local position = Position(x, y, 9) + local tile = Tile(position) + if tile then + local fungus = tile:getItemById(12065) + if fungus and math.random(100) <= 30 then + fungus:transform(math.random(12059, 12063)) + fungus:getPosition():sendMagicEffect(CONST_ME_YELLOW_RINGS) + end + end + end + end + end +end + +theirMastersVoiceEvent:register() diff --git a/data-otservbr-global/world/world_changes/dream_courts_bosses/Alptramun.otbm b/data-otservbr-global/world/quest/the_dream_courts/alptramun.otbm similarity index 100% rename from data-otservbr-global/world/world_changes/dream_courts_bosses/Alptramun.otbm rename to data-otservbr-global/world/quest/the_dream_courts/alptramun.otbm diff --git a/data-otservbr-global/world/world_changes/dream_courts_bosses/Izcandar_the_Banished.otbm b/data-otservbr-global/world/quest/the_dream_courts/izcandar_the_banished.otbm similarity index 100% rename from data-otservbr-global/world/world_changes/dream_courts_bosses/Izcandar_the_Banished.otbm rename to data-otservbr-global/world/quest/the_dream_courts/izcandar_the_banished.otbm diff --git a/data-otservbr-global/world/world_changes/dream_courts_bosses/Malofur_Mangrinder.otbm b/data-otservbr-global/world/quest/the_dream_courts/malofur_mangrinder.otbm similarity index 100% rename from data-otservbr-global/world/world_changes/dream_courts_bosses/Malofur_Mangrinder.otbm rename to data-otservbr-global/world/quest/the_dream_courts/malofur_mangrinder.otbm diff --git a/data-otservbr-global/world/world_changes/dream_courts_bosses/Maxxenius.otbm b/data-otservbr-global/world/quest/the_dream_courts/maxxenius.otbm similarity index 100% rename from data-otservbr-global/world/world_changes/dream_courts_bosses/Maxxenius.otbm rename to data-otservbr-global/world/quest/the_dream_courts/maxxenius.otbm diff --git a/data-otservbr-global/world/world_changes/dream_courts_bosses/Plagueroot.otbm b/data-otservbr-global/world/quest/the_dream_courts/plagueroot.otbm similarity index 100% rename from data-otservbr-global/world/world_changes/dream_courts_bosses/Plagueroot.otbm rename to data-otservbr-global/world/quest/the_dream_courts/plagueroot.otbm diff --git a/data/scripts/actions/items/spellbook.lua b/data/scripts/actions/items/spellbook.lua new file mode 100644 index 00000000000..ef777b68269 --- /dev/null +++ b/data/scripts/actions/items/spellbook.lua @@ -0,0 +1,55 @@ +local function sortSpellsByLevel(spellList, levelKey) + table.sort(spellList, function(a, b) + return a[levelKey] < b[levelKey] + end) +end + +local function appendSpellsInfo(spellList, header, levelKey, manaKey) + local text = "" + local prevLevel = -1 + + for i, spell in ipairs(spellList) do + local line = "" + if prevLevel ~= spell[levelKey] then + line = (i == 1 and "" or "\n") .. header .. spell[levelKey] .. "\n" + prevLevel = spell[levelKey] + end + + text = text .. line .. " " .. spell.words .. " - " .. spell.name .. " : " .. spell[manaKey] .. "\n" + end + return text +end + +local spellbook = Action() + +function spellbook.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local spellsForLevel = {} + local spellsForMagicLevel = {} + + for _, spell in ipairs(player:getInstantSpells()) do + if (spell.level > 0 or spell.mlevel > 0) and spell.level + spell.mlevel > 0 then + if spell.manapercent > 0 then + spell.mana = spell.manapercent .. "%" + end + + if spell.level > 0 then + spellsForLevel[#spellsForLevel + 1] = spell + else + spellsForMagicLevel[#spellsForMagicLevel + 1] = spell + end + end + end + + sortSpellsByLevel(spellsForLevel, "level") + sortSpellsByLevel(spellsForMagicLevel, "mlevel") + + local spellsText = appendSpellsInfo(spellsForLevel, "Spells for Level ", "level", "mana") + spellsText = spellsText .. "\n" + spellsText = spellsText .. appendSpellsInfo(spellsForMagicLevel, "Spells for Magic Level ", "mlevel", "mana") + + player:showTextDialog(item:getId(), spellsText) + return true +end + +spellbook:id(3059, 6120, 8072, 8073, 8074, 8075, 8076, 8090, 11691, 14769, 16107, 20088, 21400, 22755, 25699, 29431, 20089, 20090, 34153) +spellbook:register() diff --git a/data/scripts/actions/objects/hive_gates.lua b/data/scripts/actions/objects/hive_gates.lua new file mode 100644 index 00000000000..12c56b8ce74 --- /dev/null +++ b/data/scripts/actions/objects/hive_gates.lua @@ -0,0 +1,25 @@ +local hiveGates = Action() + +function hiveGates.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local position = player:getPosition() + if item:getId() == 13278 or item:getId() == 13279 or item:getId() == 13280 or item:getId() == 13281 or item:getId() == 13282 or item:getId() == 13283 then + if position.y == toPosition.y then + return false + end + + toPosition.y = position.y > toPosition.y and toPosition.y - 1 or toPosition.y + 1 + elseif item:getId() == 13290 or item:getId() == 13291 or item:getId() == 13292 or item:getId() == 13293 or item:getId() == 13294 then + if position.x == toPosition.x then + return false + end + + toPosition.x = position.x > toPosition.x and toPosition.x - 1 or toPosition.x + 1 + end + + player:teleportTo(toPosition) + toPosition:sendMagicEffect(CONST_ME_TELEPORT) + return true +end + +hiveGates:id(13278, 13279, 13280, 13281, 13282, 13283, 13290, 13291, 13292, 13293, 13294) +hiveGates:register() diff --git a/data/scripts/creaturescripts/player/send_first_items.lua b/data/scripts/creaturescripts/player/send_first_items.lua new file mode 100644 index 00000000000..53fecd11554 --- /dev/null +++ b/data/scripts/creaturescripts/player/send_first_items.lua @@ -0,0 +1,113 @@ +local config = { + [VOCATION.ID.NONE] = { + container = { + { 3003, 1 }, -- rope + { 3457, 1 }, -- shovel + }, + }, + + [VOCATION.ID.SORCERER] = { + items = { + { 3059, 1 }, -- spellbook + { 3074, 1 }, -- wand of vortex + { 7991, 1 }, -- magician's robe + { 7992, 1 }, -- mage hat + { 3362, 1 }, -- studded legs + { 3552, 1 }, -- leather boots + { 3572, 1 }, -- scarf + }, + + container = { + { 3003, 1 }, -- rope + { 5710, 1 }, -- light shovel + { 268, 10 }, -- mana potion + }, + }, + + [VOCATION.ID.DRUID] = { + items = { + { 3059, 1 }, -- spellbook + { 3066, 1 }, -- snakebite rod + { 7991, 1 }, -- magician's robe + { 7992, 1 }, -- mage hat + { 3362, 1 }, -- studded legs + { 3552, 1 }, -- leather boots + { 3572, 1 }, -- scarf + }, + + container = { + { 3003, 1 }, -- rope + { 5710, 1 }, -- light shovel + { 268, 10 }, -- mana potion + }, + }, + + [VOCATION.ID.PALADIN] = { + items = { + { 3425, 1 }, -- dwarven shield + { 3277, 1 }, -- spear + { 3571, 1 }, -- ranger's cloak + { 8095, 1 }, -- ranger legs + { 3552, 1 }, -- leather boots + { 3572, 1 }, -- scarf + { 3374, 1 }, -- legion helmet + }, + + container = { + { 3003, 1 }, -- rope + { 5710, 1 }, -- light shovel + { 266, 10 }, -- health potion + { 3350, 1 }, -- bow + { 3447, 50 }, -- 50 arrows + }, + }, + + [VOCATION.ID.KNIGHT] = { + items = { + { 3425, 1 }, -- dwarven shield + { 7773, 1 }, -- steel axe + { 3359, 1 }, -- brass armor + { 3354, 1 }, -- brass helmet + { 3372, 1 }, -- brass legs + { 3552, 1 }, -- leather boots + { 3572, 1 }, -- scarf + }, + + container = { + { 7774, 1 }, -- jagged sword + { 3327, 1 }, -- daramanian mace + { 3003, 1 }, -- rope + { 5710, 1 }, -- light shovel + { 266, 10 }, -- health potion + }, + }, +} + +local sendFirstItems = CreatureEvent("SendFirstItems") + +function sendFirstItems.onLogin(player) + local targetVocation = config[player:getVocation():getId()] + if not targetVocation or player:getLastLoginSaved() ~= 0 then + return true + end + + if targetVocation.items then + for i = 1, #targetVocation.items do + player:addItem(targetVocation.items[i][1], targetVocation.items[i][2]) + end + end + + local backpack = player:addItem(2854) + if not backpack then + return true + end + + if targetVocation.container then + for i = 1, #targetVocation.container do + backpack:addItem(targetVocation.container[i][1], targetVocation.container[i][2]) + end + end + return true +end + +sendFirstItems:register() diff --git a/data/scripts/globalevents/hireling_save.lua b/data/scripts/globalevents/hireling_save.lua new file mode 100644 index 00000000000..82d5189fe45 --- /dev/null +++ b/data/scripts/globalevents/hireling_save.lua @@ -0,0 +1,14 @@ +local hirelingSave = GlobalEvent("HirelingSave") + +function hirelingSave.onShutdown() + local saved = SaveHirelings() + if saved then + logger.info("[Server Shutdown] Hirelings successfully saved.") + else + logger.warn("[Server Shutdown] Failed to save hirelings. Please check the logs for details.") + end + + return true +end + +hirelingSave:register()