Server upload

RD Core / Commit #2

Commit Server upload

Alex Alex committed 18/10/2026 23:38 main Patch
1,106 files +223,404 -0
A data/npc/muriel.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Muriel" walkinterval="2000" floorchange="0" script="default.lua" speechbubble="4" attackable = "1">
3+ <health now="100" max="100"/>
4+ <look type="130" head="115" body="94" legs="97" feet="76" addons="0"/>
5+</npc>
A data/npc/naji.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Naji" walkinterval="2000" floorchange="0" script="default.lua" speechbubble="4" attackable = "1">
3+ <health now="100" max="100"/>
4+ <look type="129" head="57" body="113" legs="95" feet="113" addons="0"/>
5+</npc>
A data/npc/norf.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Norf" walkinterval="2000" floorchange="0" script="default.lua" speechbubble="4" attackable = "1">
3+ <health now="100" max="100"/>
4+ <look type="57"/>
5+</npc>
A data/npc/palomino.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Palomino" walkinterval="2000" floorchange="0" script="default.lua" speechbubble="4" attackable = "1">
3+ <health now="100" max="100"/>
4+ <look type="128" head="116" body="39" legs="12" feet="97" addons="2"/>
5+</npc>
A data/npc/partos.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Partos" walkinterval="2000" floorchange="0" script="default.lua" speechbubble="4" attackable = "1">
3+ <health now="100" max="100"/>
4+ <look type="128" head="116" body="56" legs="95" feet="121" addons="0"/>
5+</npc>
A data/npc/robin.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Robin" walkinterval="0" floorchange="0" speed="130" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="129" head="77" body="118" legs="118" feet="115" addons="0"/>
5+</npc>
A data/npc/sam.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Sam" walkinterval="0" floorchange="0" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="131" head="38" body="113" legs="67" feet="95" addons="0"/>
5+</npc>
A data/npc/scott.xml +7-0 View file
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Scott" walkinterval="0" floorchange="0" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="131" head="75" body="38" legs="77" feet="116" addons="0"/>
5+ <parameters>
6+ </parameters>
7+</npc>
A data/npc/scripts/default.lua +10-0 View file
@@ -0,0 +1,10 @@
1+local keywordHandler = KeywordHandler:new()
2+local npcHandler = NpcHandler:new(keywordHandler)
3+NpcSystem.parseParameters(npcHandler)
4+
5+function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end
6+function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end
7+function onCreatureSay(cid, type, msg) npcHandler:onCreatureSay(cid, type, msg) end
8+function onThink() npcHandler:onThink() end
9+
10+npcHandler:addModule(FocusModule:new())
A data/npc/scripts/magnus_blackwater.lua +76-0 View file
@@ -0,0 +1,76 @@
1+local keywordHandler = KeywordHandler:new()
2+local npcHandler = NpcHandler:new(keywordHandler)
3+NpcSystem.parseParameters(npcHandler)
4+
5+function onCreatureAppear(cid) npcHandler:onCreatureAppear(cid) end
6+function onCreatureDisappear(cid) npcHandler:onCreatureDisappear(cid) end
7+function onCreatureSay(cid, type, msg) npcHandler:onCreatureSay(cid, type, msg) end
8+function onThink() npcHandler:onThink() end
9+
10+local function creatureSayCallback(cid, type, msg)
11+ if(not npcHandler:isFocused(cid)) then
12+ return false
13+ end
14+ local player = Player(cid)
15+ if msg:lower() == "discover" then
16+ npcHandler:say("Ssshh puff, ssshh puff, so ahem, ahem, sorry about that, you want {explore} the ocean and found lost treasures ?.", cid)
17+ elseif msg:lower() == "explore" then
18+ npcHandler:say("Before explore the ocean, you need a boat, let's construct a boat, for this you need some {materials}, some exquisite planks for the hull and deck, some nails to hold the boat together, metal fittings to reinforce and connect various components, a silk, important to stretch the sail of the boat, a small golden anchor to keep the boat in place when not sailing and some paint to protect the wood. Of course, you can buy all of this items to an old merchant. A whimsical merchant, an elusive ally, hoarding every ship part to sell to any daring enough to brave the tumultuous seas, called Shipwright Trader. You can found him on at north of Thais at exit.", cid)
19+ elseif msg:lower() == "materials" then
20+ npcHandler:say("Here is the list about what we need. You can found Shipwright Trader at north of Thais, come back when you get the materials for we start construction of the boat.\nFor Start we need some exquisite {planks}, for the hull and deck.", cid)
21+ player:addItem(7844, 1)
22+ elseif msg:lower() == "planks" then
23+ if player:removeItem(12503, 10) then
24+ npcHandler:say("Now for hold the boat together we need some {nails}", cid)
25+ player:setStorageValue(BoatMissions.MagnusBlackWaterFirst, 1)
26+ else
27+ npcHandler:say("For this you need 10 exquisite planks.", cid)
28+ end
29+ elseif msg:lower() == "nails" then
30+ if player:removeItem(8309, 10) and player:getStorageValue(BoatMissions.MagnusBlackWaterFirst) == 1 then
31+ npcHandler:say("We need also some extra {metal} fitting parts.", cid)
32+ player:setStorageValue(BoatMissions.MagnusBlackWaterSecond, 1)
33+ else
34+ npcHandler:say("You need 10 nails to continue the construction.", cid)
35+ end
36+ elseif msg:lower() == "metal" then
37+ if player:removeItem(10034, 5) and player:getStorageValue(BoatMissions.MagnusBlackWaterSecond) == 1 then
38+ npcHandler:say("Great, to continue we need one exquisite {silk} to connect various components.", cid)
39+ player:setStorageValue(BoatMissions.MagnusBlackWaterThird, 1)
40+ else
41+ npcHandler:say("You need 5 mettal fitting to reinforce the boat.", cid)
42+ end
43+ elseif msg:lower() == "silk" then
44+ if player:removeItem(12501, 1) and player:getStorageValue(BoatMissions.MagnusBlackWaterThird) == 1 then
45+ npcHandler:say("It's taking a while to construct the boat, is not so easy, well now we need a small golden {anchor} to keep the boat in place.", cid)
46+ player:setStorageValue(BoatMissions.MagnusBlackWaterFourth, 1)
47+ else
48+ npcHandler:say("You need 1 Silk to connect various components.", cid)
49+ end
50+ elseif msg:lower() == "anchor" then
51+ if player:removeItem(15432, 1) and player:getStorageValue(BoatMissions.MagnusBlackWaterFourth) == 1 then
52+ npcHandler:say("Perfect, now the last thing we need some red {paint} to protect the wood.", cid)
53+ player:setStorageValue(BoatMissions.MagnusBlackWaterFifth, 1)
54+ else
55+ npcHandler:say("You need 1 small golden anchor to keep the boat in place.", cid)
56+ end
57+ elseif msg:lower() == "paint" then
58+ if player:getStorageValue(BoatMissions.MagnusBlackWaterSixth) == 1 then
59+ npcHandler:say("You already have construct your boat.", cid)
60+ elseif player:removeItem(25308, 1) and player:getStorageValue(BoatMissions.MagnusBlackWaterFifth) == 1 then
61+ npcHandler:say("Fantastic! The boat is now ready, to start navigating, place the explorer to the boat slot on your inventory and walk through the deck that leads to the water.", cid)
62+ player:say("Get ready to explore the ocean. Equip the explorer on the Boat Slot of your inventory, and walk to the ocean through the deck that leads to the water.", TALKTYPE_MONSTER_SAY)
63+ player:setStorageValue(BoatMissions.MagnusBlackWaterSixth, 1)
64+ player:addItem(27799, 1)
65+ else
66+ npcHandler:say("You need 1 Red Paint to protect the wood.", cid)
67+ end
68+ end
69+ return true
70+end
71+
72+npcHandler:setMessage(MESSAGE_GREET, "Psst.... Come here... You want {discover} the vast ocean and found treasures ?.")
73+npcHandler:setMessage(MESSAGE_FAREWELL, "Venture forth, my hearty crew! The boundless ocean awaits, where treasures lie hidden beneath each cresting wave. Hoist the sails high and let the winds of fortune guide our course to riches beyond measure!")
74+npcHandler:setMessage(MESSAGE_WALKAWAY, "Psst.... Come here... You want {discover} the vast ocean and found treasures ?")
75+npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
76+npcHandler:addModule(FocusModule:new())
A data/npc/stutch.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Stutch" walkinterval="0" floorchange="0" speed="130" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="131" head="79" body="79" legs="79" feet="79" addons="0"/>
5+</npc>
A data/npc/thanita.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Thanita" script="default.lua" walkinterval="0" floorchange="0">
3+ <health now="100" max="100" />
4+ <look type="139" head="77" body="71" legs="82" feet="71" addons="0" />
5+</npc>
A data/npc/topsy.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Topsy" walkinterval="0" floorchange="0" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="139" head="78" body="52" legs="100" feet="115" addons="0"/>
5+</npc>
A data/npc/towncryer.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Towncryer" walkinterval="0" floorchange="0" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="131" head="95" body="86" legs="10" feet="114" addons="1"/>
5+</npc>
A data/npc/victor.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="utf-8"?>
2+<npc name="Victor" walkinterval="0" floorchange="0" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="134" head="21" body="78" legs="38" feet="95" addons="3"/>
5+</npc>
A data/npc/wyat.xml +5-0 View file
@@ -0,0 +1,5 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<npc name="Wyat" walkinterval="0" floorchange="0" speed="130" script="default.lua">
3+ <health now="100" max="100"/>
4+ <look type="129" head="98" body="96" legs="95" feet="116" addons="0"/>
5+</npc>
A data/raids/raids.xml +7-0 View file
@@ -0,0 +1,7 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<raids>
3+ <!--
4+ <raid name="Testraid" file="testraid.xml" interval2="30" margin="0" />
5+ executed on average once every 30 minutes
6+ -->
7+</raids>
A data/reports/bugs/bugs.txt +0-0 View file
Empty file.
A data/reports/criptomoeda/criptomoeda.txt +35-0 View file
@@ -0,0 +1,35 @@
1+Name: Sonnyz
2+Ter�a, 8 de Fevereiro, as 16:34
3+Tipo: Fazendo Pedido [ID: 1]
4+O jogador [ Felipe da Silva Oliveira ] realizou um pedido de pagamento no valor de [ R$ 5.76 ] usando [ 96 ] criptomoedas sob o pre�o fixo de [ 0.06 ] e estando no Level [ 103 (0.06)].
5+
6+------------------------------------------------
7+
8+Name: Sonnyz
9+Ter�a, 8 de Fevereiro, as 16:34
10+Tipo: Editando Pedido [ID: 1]
11+O jogador [ Felipe da Silva Oliveira ] alterou um pedido de pagamento de [ R$ 5.76 para R$ 5.7 ] gastando [ 95 ] criptomoedas. Seu saldo final de criptomoedas � de [ 1 ].
12+
13+------------------------------------------------
14+
15+Name: Sonnyz
16+Ter�a, 8 de Fevereiro, as 16:35
17+Tipo: Editando Pedido [ID: 1]
18+O jogador [ Felipe da Silva Oliveira ] alterou um pedido de pagamento de [ R$ 5.7 para R$ 1.44 ] gastando [ 24 ] criptomoedas. Seu saldo final de criptomoedas � de [ 72 ].
19+
20+------------------------------------------------
21+
22+Name: Sonnyz
23+Ter�a, 8 de Fevereiro, as 16:36
24+Tipo: Editando Pedido [ID: 1]
25+O jogador [ Felipe da Silva Oliveira ] alterou um pedido de pagamento de [ R$ 1.44 para R$ 5.76 ] gastando [ 96 ] criptomoedas. Seu saldo final de criptomoedas � de [ 0 ].
26+
27+------------------------------------------------
28+
29+Name: Frenesy
30+S�bado, 19 de Fevereiro, as 22:37
31+Tipo: Fazendo Pedido [ID: 2]
32+O jogador [ Felipe da Silva Oliveira ] realizou um pedido de pagamento no valor de [ R$ 13.14 ] usando [ 219 ] criptomoedas sob o pre�o fixo de [ 0.06 ] e estando no Level [ 150 (0.06)].
33+
34+------------------------------------------------
35+
A data/scripts/-_opcode-spellbar.lua +27-0 View file
@@ -0,0 +1,27 @@
1+--CREATURESCRIPT--
2+
3+creatureEvent = CreatureEvent("LoginSpellBar")
4+
5+function creatureEvent.onLogin(player)
6+
7+ player:registerEvent("CreateSpellBar")
8+
9+ return true
10+end
11+
12+creatureEvent:register()
13+
14+
15+
16+creatureEvent = CreatureEvent("CreateSpellBar")
17+
18+function creatureEvent.onExtendedOpcode(player, opcode, buffer)
19+
20+ if opcode == 193 then
21+ player:sendExtendedOpcode(193, ''..player:getVocation():getId()..'')
22+ end
23+
24+return true
25+end
26+
27+creatureEvent:register()
A data/scripts/add_player_wings.lua +28-0 View file
@@ -0,0 +1,28 @@
1+local config = {
2+ [8888] = {wingId = 1, effect = CONST_ME_FIREWORK_RED, storage = 2929}, -- ItemID in [8888]
3+ [8887] = {wingId = 2, effect = CONST_ME_FIREWORK_RED, storage = 2930},
4+}
5+
6+local addWingsSystem = Action()
7+
8+function addWingsSystem.onUse(player, item, fromPosition, target, toPosition, isHotkey)
9+ local wings = config[item.itemid]
10+ if not wings then
11+ return true
12+ end
13+ if player:getStorageValue(wings.storage) == 1 then
14+ player:sendTextMessage(MESSAGE_INFO_DESCR, 'You alredy received those wings!')
15+ return true
16+ end
17+ player:addWings(wings.wingId)
18+ player:setStorageValue(wings.storage, 1)
19+ player:getPosition():sendMagicEffect(wings.effect)
20+ player:sendTextMessage(MESSAGE_INFO_DESCR, 'You received new wings!')
21+ player:removeItem()
22+ return true
23+end
24+
25+for v, _ in pairs(config) do
26+ addWingsSystem:id(v)
27+end
28+addWingsSystem:register()
A data/scripts/Clon.lua +75-0 View file
@@ -0,0 +1,75 @@
1+local config = {
2+ maxClones = 3, -- Número máximo de clones que podem ser criados
3+ healthPercent = 0.10, -- Porcentagem da vida do jogador que o clone terá (10%)
4+ spellName = "Clone das Sombras", -- Nome fixo da magia (não altere esta linha)
5+ words = "utamo clone", -- Nome da magia, pode ser alterado para o nome preferido (ex.: diga no jogo "utamo clone")
6+ cooldown = 30, -- Tempo de espera em segundos para usar novamente
7+ manaCost = 500, -- Quantidade de mana necessária para usar
8+ minLevel = 20, -- Nível mínimo necessário para usar a magia
9+ monsterName = "clone", -- Nome do monstro base que será usado como clone
10+ exhaustGroup = "support", -- Grupo de exaustão da magia
11+ -- Lista de vocações que podem usar a magia
12+ vocations = {
13+ "Soldier", "elder Soldier",
14+ "Regen", "master Regen",
15+ "Shooter", "royal Shooter",
16+ "vital", "royal vital",
17+ "lucky", "royal lucky",
18+ "Tanker", "elite Tanker"
19+ },
20+ needPremium = false -- Define se precisa ser conta premium para usar
21+}
22+
23+local spell = Spell("instant")
24+
25+function spell.onCastSpell(creature, variant)
26+ local player = creature:getPlayer()
27+ if not player then
28+ return false
29+ end
30+
31+ local summons = player:getSummons()
32+ if #summons >= config.maxClones then
33+ player:sendCancelMessage("Você já atingiu o número máximo de clones permitidos!")
34+ return false
35+ end
36+
37+ local remainingClones = config.maxClones - #summons
38+ local playerHealth = player:getHealth()
39+ local playerOutfit = player:getOutfit()
40+ local playerSpeed = player:getSpeed()
41+
42+ for i = 1, remainingClones do
43+ local clone = Game.createMonster(config.monsterName, player:getPosition())
44+ if clone then
45+ clone:setMaster(player)
46+ clone:rename(player:getName())
47+
48+ player:addSummon(clone)
49+
50+ local cloneHealth = math.ceil(playerHealth * config.healthPercent)
51+ clone:setMaxHealth(cloneHealth)
52+ clone:addHealth(cloneHealth)
53+
54+ clone:setOutfit(playerOutfit)
55+ clone:changeSpeed(playerSpeed)
56+ end
57+ end
58+
59+ return true
60+end
61+
62+spell:name(config.spellName)
63+spell:words(config.words)
64+spell:group(config.exhaustGroup)
65+spell:vocation(unpack(config.vocations))
66+spell:id(24)
67+spell:cooldown(config.cooldown * 1000)
68+spell:groupCooldown(2 * 1000)
69+spell:level(config.minLevel)
70+spell:mana(config.manaCost)
71+spell:isSelfTarget(true)
72+spell:isAggressive(false)
73+spell:needLearn(false)
74+spell:isPremium(config.needPremium)
75+spell:register()
A data/scripts/customs/admin_minimap_teleport.lua +63-0 View file
@@ -0,0 +1,63 @@
1+-- Left-click on the minimap teleports gamemasters and above.
2+-- The client (gamelib/ui/uiminimap.lua) only sends the request after the
3+-- server says on login that this player is allowed to use it.
4+local OPCODE_ADMIN_MINIMAP_TELEPORT = 215
5+
6+local function canUseMinimapTeleport(player)
7+ return player:getGroup():getAccess()
8+end
9+
10+local loginEvent = CreatureEvent("AdminMinimapTeleportLogin")
11+
12+function loginEvent.onLogin(player)
13+ player:registerEvent("AdminMinimapTeleportOpcode")
14+ player:sendExtendedOpcode(OPCODE_ADMIN_MINIMAP_TELEPORT, json.encode({
15+ action = "access",
16+ enabled = canUseMinimapTeleport(player)
17+ }))
18+ return true
19+end
20+
21+loginEvent:register()
22+
23+local opcodeEvent = CreatureEvent("AdminMinimapTeleportOpcode")
24+
25+function opcodeEvent.onExtendedOpcode(player, opcode, buffer)
26+ if opcode ~= OPCODE_ADMIN_MINIMAP_TELEPORT then
27+ return true
28+ end
29+
30+ if not canUseMinimapTeleport(player) then
31+ return true
32+ end
33+
34+ local ok, data = pcall(json.decode, buffer)
35+ if not ok or type(data) ~= "table" or data.action ~= "teleport" or type(data.position) ~= "table" then
36+ return true
37+ end
38+
39+ local x = tonumber(data.position.x)
40+ local y = tonumber(data.position.y)
41+ local z = tonumber(data.position.z)
42+ if not x or not y or not z then
43+ return true
44+ end
45+
46+ local destination = Position(math.floor(x), math.floor(y), math.floor(z))
47+ if not Tile(destination) then
48+ player:sendCancelMessage("There is no tile there.")
49+ return true
50+ end
51+
52+ local ghost = player:isInGhostMode()
53+ if not ghost then
54+ player:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
55+ end
56+ player:teleportTo(destination)
57+ if not ghost then
58+ destination:sendMagicEffect(CONST_ME_TELEPORT)
59+ end
60+ return true
61+end
62+
63+opcodeEvent:register()
A data/scripts/customs/attacks_moves/attack_spell.lua +13-0 View file
@@ -0,0 +1,13 @@
1+local attackAnimationOutfitId = 1423
2+local attackAnimationTotalTick = 1200
3+local attackAnimationDamageTime = 450
4+
5+local damageMin = 100
6+local damageMax = 200
7+
8+function onCastSpell(cid)
9+ local originalOutfit = cid:getOutfit()
10+ cid:setOutfit(attackAnimationOutfitId)
11+ addEvent(function() cid:setOutfit(originalOutfit) end, attackAnimationTotalTick)
12+ addEvent(function() doCombatDamage(cid, COMBAT_PHYSICALDAMAGE, damageMin, damageMax) end, attackAnimationDamageTime)
13+end
A data/scripts/customs/boat/boat_navigation.lua +131-0 View file
@@ -0,0 +1,131 @@
1+-- =====================================================
2+-- BOAT NAVIGATION SYSTEM
3+-- AID 40000 = Embark (dock tile -> water)
4+-- AID 40001 = Disembark (water tile -> dock)
5+-- =====================================================
6+
7+-- Helper: apply boat outfit and store original
8+local function applyBoatOutfit(player, item, position, fromPosition)
9+ local playerOutfit = player:getOutfit()
10+
11+ -- Store current outfit
12+ player:setStorageValue(709919, playerOutfit.lookType)
13+ player:setStorageValue(709920, playerOutfit.lookAddons)
14+ player:setStorageValue(709921, playerOutfit.lookWings or 0)
15+ player:setStorageValue(709922, playerOutfit.lookAura or 0)
16+ player:setStorageValue(709923, playerOutfit.lookShader or 0)
17+
18+ -- Check equipped ship using the custom inventory storage system
19+ -- _SYSTEM.INVENTARIO[07] = RING slot, UID_01 = storage 1061
20+ local shipId = player:getStorageValue(_SYSTEM.INVENTARIO[07].UID_01)
21+
22+ local boatLookType = 0
23+ if shipId == 42430 then boatLookType = 9017
24+ elseif shipId == 42431 then boatLookType = 9018
25+ elseif shipId == 42432 then boatLookType = 9019
26+ elseif shipId == 42433 then boatLookType = 9541
27+ elseif shipId == 42434 then boatLookType = 9542
28+ elseif shipId == 42435 then boatLookType = 9543
29+ elseif shipId == 42436 then boatLookType = 9544
30+ end
31+
32+ if boatLookType > 0 then
33+ playerOutfit.lookType = boatLookType
34+ playerOutfit.lookAddons = 0
35+ playerOutfit.lookWings = 0
36+ playerOutfit.lookAura = 0
37+ playerOutfit.lookShader = 0
38+ player:setOutfit(playerOutfit)
39+ return true
40+ end
41+
42+ return false
43+end
44+
45+-- Helper: restore original outfit
46+local function restoreOutfit(player)
47+ local storedLookType = player:getStorageValue(709919)
48+ local storedLookAddons = player:getStorageValue(709920)
49+ local storedLookWings = player:getStorageValue(709921)
50+ local storedLookAura = player:getStorageValue(709922)
51+ local storedLookShader = player:getStorageValue(709923)
52+
53+ if storedLookType > 0 then
54+ local playerOutfit = player:getOutfit()
55+ playerOutfit.lookType = storedLookType
56+ playerOutfit.lookAddons = storedLookAddons
57+ playerOutfit.lookWings = storedLookWings
58+ playerOutfit.lookAura = storedLookAura
59+ playerOutfit.lookShader = storedLookShader
60+ player:setOutfit(playerOutfit)
61+ end
62+end
63+
64+-- =====================================================
65+-- TELEPORT EVENT (AID 40000 = embark / AID 40001 = disembark)
66+-- =====================================================
67+local boatTeleport = MoveEvent()
68+
69+function boatTeleport.onStepIn(creature, item, position, fromPosition)
70+ local player = creature:getPlayer()
71+ if not player then
72+ return true
73+ end
74+
75+ local actionId = item:getActionId()
76+
77+ -- Prevent trigger if player was already on a tile with the same AID
78+ -- (avoids loop when teleporting onto another AID tile)
79+ local fromTile = Tile(fromPosition)
80+ if fromTile then
81+ local items = fromTile:getItems()
82+ if items then
83+ for _, i in ipairs(items) do
84+ if i:getActionId() == actionId then
85+ return true
86+ end
87+ end
88+ end
89+ end
90+
91+ -- Calculate movement direction (1 step = 1 tile difference)
92+ local diffX = position.x - fromPosition.x
93+ local diffY = position.y - fromPosition.y
94+
95+ if diffX == 0 and diffY == 0 then
96+ return true
97+ end
98+
99+ -- Project destination 4 tiles ahead in walking direction
100+ local targetPos = Position(
101+ position.x + (diffX * 4),
102+ position.y + (diffY * 4),
103+ position.z
104+ )
105+
106+ if actionId == 40000 then
107+ -- EMBARK: verify boat equipped, apply outfit, teleport to water (Z+1)
108+ if not applyBoatOutfit(player, item, position, fromPosition) then
109+ player:teleportTo(fromPosition, true)
110+ player:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
111+ player:say("You need to equip a boat in your ring slot to sail.", TALKTYPE_MONSTER_SAY)
112+ return false
113+ end
114+
115+ targetPos.z = position.z + 1
116+ player:teleportTo(targetPos)
117+ targetPos:sendMagicEffect(CONST_ME_TELEPORT)
118+
119+ elseif actionId == 40001 then
120+ -- DISEMBARK: restore outfit and teleport to dock (Z-1)
121+ restoreOutfit(player)
122+ targetPos.z = position.z - 1
123+ player:teleportTo(targetPos)
124+ targetPos:sendMagicEffect(CONST_ME_TELEPORT)
125+ end
126+
127+ return true
128+end
129+
130+boatTeleport:aid(40000, 40001)
131+boatTeleport:register()
Top