Jump to content

Luna Event + bonus spell (inspirado no sot#01)


Skulls

Recommended Posts

Fala galera, tudo bem?

Então, eu li o sot#01 alguns dias atrás e achei bem legal a história no qual ele gira em torno.
Tive algumas idéias e, mesmo o evento não tendo acontecido por falta de inscritos, resolvi fazer pra lembrar algumas coisas, afinal tinha uns 7 anos que não mexia com scripts para otserv.

O resultado, que vou mostrar abaixo, é um evento global (mas que pode muito bem ser adaptado para uma quest ou outra finalidade). Como parte da recompensa do evento, fiz de bonus uma spell baseada na frozenOrb do whitewolf.

Bom vamos lá.

O Evento

Basicamente é um evento estilo aquela brincadeira antiga de criança "dança das cadeiras".
Como assim?
Bom, na área do evento o número de espaços vazios vai ser sempre o número de players restantes no evento -1. Isso implica que, em cada turno, pelo menos um player deixará o evento.

Contexto

Luna é uma estrela endeusada pelos elfos e muito poderosa. De tempo em tempo ela se desperta todos os players onlines são convocados para tentarem domar a sua ira. Aquele que sobreviver à ira de Luna sem se congelar será capaz de controlar seu poder até o próximo despertar.

 

editado: Esqueci de avisar que coloquei para ele ignorar o tile central na contagem de tiles livres pois no tile central, do meu mapa, eu coloquei um frozen starlight representando a luna e, a cada round, há uma animação na luna só para ficar bonitinho.

 

Crie um arquivo chamado lunaevent.lua dentro de scripts e coloque o código abaixo nele:

 

 

--[[Variáveis de configuração]]--
local config = {
    hour = "5 Horas", -- Time to next event (only for broadcast message, real time you can set on globalevents.xml)
    reward_id = 2361, -- Reward ID
    frozen_humans = {7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7311, 7312, 7172}, -- Frozen human ids
    area = {center = {x = 102, y = 182, z = 7}, side = 4}, -- Area do evento centrada em center, a capacidade da área é
    effects = {luna = 28, alert = 72, init = 41, frozen = 43}, -- de (1+2*side)^2 menos os itens imóveis do mapa (ex frozen humans)
    storage = 5544 --storage que vai definir quem pode usar o poder de luna
}

--[[Gera um array de numeros aleatorios distintos]]--
function getRandomArray(n, max)
    rand = {}
    flag = {}
    for i = 0, n do
        rand[i] = math.random(0, max)
        while flag[rand[i]] ~= nil do
            rand[i] = math.random(0, max)
        end
        flag [rand[i]] = i
    end

    return rand
end

--[[Remove os frozen humman ao final do evento]]--
function clearEventArea()
    for i, tile in pairs(getArea(config.area.center, config.area.side, config.area.side)) do
        tile.stackpos = 1
        tmp = getThingFromPos(tile)
        if tmp.uid ~= 0 then
            if isCreature(tmp.uid) == false then
                item_id = getItemIdByName(getItemDescriptions(tmp.uid).name)
                for k, v in pairs(config.frozen_humans) do
                    if item_id == v then
                        doRemoveItem(tmp.uid, math.min(math.max(1, tmp.type), 1))
                    end
                end
            end
        end
    end
end

--[[Conta quantos players ainda estão no evento]]--
function countPlayers()
    result = 0
    for i, tile in pairs(getArea(config.area.center, config.area.side, config.area.side)) do
        tile.stackpos = STACKPOS_TOP_MOVEABLE_ITEM_OR_CREATURE
        tmp = getThingFromPos(tile)
        if isPlayer(tmp.uid) then
            result = result + 1
        end
    end
    return result
end

--[[Congela o Player que for pego]]--
function removePlayer(rand, tiles)
    for i = 0, #rand do
        tmp = getThingFromPos(tiles[rand[i]])
        if isPlayer(tmp.uid) then
            random = config.frozen_humans[math.random(1, #config.frozen_humans)]
            doCreateItem(random, 1, tiles[rand[i]])
            doTeleportThing(tmp.uid, getTownTemplePosition(getPlayerTown(tmp.uid)))
        end
    end
end

--[[Efeitos do evento]]--
function lunaFalls(pos)
    addEvent(doSendMagicEffect, 2000, pos, config.effects.init)
    addEvent(doSendMagicEffect, 3000, pos, config.effects.init)
    addEvent(doSendMagicEffect, 4000, pos, config.effects.init)
    addEvent(doSendMagicEffect, 6000, pos, config.effects.frozen)
end

--[[Execução do evento]]--
function lunaEvent(n, round)
x = round or 0
    if countPlayers() == 0 and x > 0 then
        doBroadcastMessage("[Luna Event] Ninguém conseguiu controlar o poder de luna. Em " .. config.hour .. " Luna ascenderá novamente.")
        setGlobalStorageValue(config.storage, -1)
        clearEventArea()
    elseif (countPlayers() == 1  and x > 0) or n == 0  then
        for i, tile in pairs(getArea(config.area.center, config.area.side, config.area.side)) do
            tile.stackpos = STACKPOS_TOP_MOVEABLE_ITEM_OR_CREATURE
            tmp = getThingFromPos(tile)
            if isPlayer(tmp.uid) then
                winner = getCreatureName(tmp.uid)
                doBroadcastMessage("[Luna Event] " .. winner .. " provou-se corajoso e domou a ira de Luna.")
                doBroadcastMessage("[Luna Event] Nas próximas " .. config.hour .. " Luna ficará sobre o controle de " .. winner .. ".")
                setGlobalStorageValue(config.storage, winner)
                item = doPlayerAddItem(getPlayerByName(winner), config.reward_id, 1)
                doSetItemSpecialDescription(item, "It's a souvenir from Luna Event. Winner: " .. winner)
                doTeleportThing(getPlayerByName(winner), getTownTemplePosition(getPlayerTown(tmp.uid)))
                clearEventArea()
            end
        end
    else
        --[[Preenche um array com os tiles da área do evento que podem ser usados para o evento.
        São considerados tiles "cheios" somente aqueles que possuem detalhes de mapa que impossibilitam
        mover sobre e o tile central, onde fica a estrela luna ]]--
        local j = 0
        local emptyTiles = {}
        for i, tile in pairs(getArea(config.area.center, config.area.side, config.area.side)) do
            tile.stackpos = 1
            tmp = getThingFromPos(tile)
            tile.stackpos = STACKPOS_TOP_MOVEABLE_ITEM_OR_CREATURE
            tmp2 = getThingFromPos(tile)

            if (tmp.uid == 0) or (tmp2.uid ~= 0 and (tile.x ~= config.area.center.x and tile.y ~= config.area.center.y)) or isCreature(tmp.uid) then
                emptyTiles[j] = tile
                j = j + 1
            end
        end
        rand = getRandomArray(#emptyTiles - n, #emptyTiles)

        doSendMagicEffect(config.area.center, config.effects.luna)
        for i = 0, #emptyTiles do
            addEvent(doSendMagicEffect, 1000, emptyTiles[i], config.effects.alert)
        end
        for i = 0, #emptyTiles - n do
            lunaFalls(emptyTiles[rand[i]])
        end
        addEvent(removePlayer, 6000, rand, emptyTiles)
        addEvent(lunaEvent, 12000, n-1, x + 1)
    end
end

function onThink(interval, lastExecution)
    doBroadcastMessage("[Luna Event] Luna despertou. Todos os players online foram convocados para tentar domar seu poder.")

    --[[Checa se há alguém online, se não houver o evento acaba]]--
    if(getWorldCreatures(0) == 0)then
        doBroadcastMessage("[Luna Event] Ninguém participou do evento. Em " .. config.hour .. " Luna ascenderá novamente.")
        setGlobalStorageValue(config.storage, -1)
        clearEventArea()
        return true
    end

    --[[Traz todos os players online para o evento.
    Poderia ser um portal mas fiquei com preguiça de configurar, assim foi mais prático]]--
    local n = #getPlayersOnline()
    for k, tid in pairs(getPlayersOnline()) do
        doTeleportThing(tid, {x = config.area.center.x, y = config.area.center.y + 2, z = config.area.center.z})
    end

    lunaEvent(n-1)
return true
end
 

 

 

 

Em globalevents.xml coloque a tag:


 <globalevent name="Luna" interval="18000000" script="lunaevent.lua" />

A recompensa do evento é uma souvenir, um frozen starlight com o nome do vencedor do evento e x horas (no caso 5) podendo utilizar o poder de luna.

Bom, eu criei uma spell para ilustrar o poder de luna e como utilizar o storage que foi preenchido para o vencedor do evento para controlar o uso de uma spell.

 

Luna Strike

Primeiramente adicione a tag abaixo em spells.xml:

<instant name="Luna Strike" words="exori luna" lvl="100" manapercent="5" prem="0" range="6" casterTargetOrDirection="1" blockwalls="1" exhaustion="10000" groups="1,4000" icon="156" needlearn="0" event="script" value="attack/luna strike.lua">
        <vocation id="1"/>
        <vocation id="2"/>
        <vocation id="3"/>
        <vocation id="4"/>
        <vocation id="5"/>
        <vocation id="6"/>
        <vocation id="7"/>
        <vocation id="8"/>
    </instant>

Crie um arquivo chamado luna strike.lua dentro de scripts/attacks e coloque o código abaixo nele:

 

 

local config = {
    speed = 400,
    hits = 15,
    frozen_humans = {7303, 7304, 7305, 7306, 7307, 7308, 7309, 7310, 7311, 7312, 7172},
    effects = {hit = 43, spin = 36, big_spin = 28},
    storages = {event = 5545, use = 5544},
    cooldown = 10,
    msg = "Luna's Rage"
}

--local

local combat = createCombatObject()
setCombatParam(combat, COMBAT_PARAM_TYPE, COMBAT_ICEDAMAGE)
setCombatParam(combat, COMBAT_PARAM_EFFECT, 255)
--setCombatParam(combat, COMBAT_PARAM_DISTANCEEFFECT, CONST_ANI_ICE)
setCombatFormula(combat, COMBAT_FORMULA_LEVELMAGIC, -5, -11, -7, -24, 2, 2, 0, 0)

function backToMovement(target)
    if isCreature(target) == true then doCreatureSetNoMove(target, false) end
end

function onTargetCreature(cid, target)
    local chance = math.random(1, 18)
    if getGlobalStorageValue(5545) == -1 and isPlayer(target) and chance == 1 then
        registerCreatureEvent(target, "NoAtt")
        registerCreatureEvent(target, "NoSpell")
        registerCreatureEvent(target, "NoTgt")
        setGlobalStorageValue(config.storages.event, 1)
        addEvent(setGlobalStorageValue, 3000, 5545, -1)
    end

    chance = math.random(1, 15)
    if chance == 1 then
        doSendMagicEffect(getCreaturePosition(target), config.effects.hit)
        doCreatureSetNoMove(target, true)
        doSetItemOutfit(target, config.frozen_humans[math.random(1, #config.frozen_humans)], 1500)
        addEvent(backToMovement, 1800, target)
    end
end
setCombatCallback(combat, 4, "onTargetCreature")

local arr = {
	{1, 1, 1, 1, 1},
	{1, 1, 1, 1, 1},
	{1, 1, 3, 1, 1},
	{1, 1, 1, 1, 1},
	{1, 1, 1, 1, 1}
}

local area = createCombatArea(arr)
setCombatArea(combat, area)

function initEffect(position)
	for i = 0, 7 do
        local dir = {}
		local pos = {x = position.x, y = position.y, z = position.z}
		if (i > 3) then dir = getPosByDir(getPosByDir(pos, i), i)
		else dir = getPosByDir(pos, i) end
		doSendDistanceShoot(position, dir, config.effects.spin)
	end
return true
end

function cornerEffect(position, count)
n = count or 0
    if n < 6 then
        for i = 4, 7 do
            local pos = {x = position.x, y = position.y, z = position.z}
            local dir = getPosByDir(getPosByDir(pos, i), i)
            doSendMagicEffect(dir, config.effects.hit)
        end
        addEvent(cornerEffect, 1000, position, n + 1)
    end
end

function spin(cid, var, position, hits, count)
n = count or 0
    if n%5 == 0 then
        doCreatureAddMana(cid, -115)
    end
	if isCreature(cid) and n < hits then
		for i = 0, 3 do
			local pos = {x = position.x, y = position.y, z = position.z}
			local pos2 = {x = position.x, y = position.y, z = position.z}
			local dir = getPosByDir(pos, i)
			local dir2 = getPosByDir(pos2, i + 1 <= 3 and i + 1 or 0)
			doSendDistanceShoot(dir, dir2, config.effects.spin)
			dir = getPosByDir(getPosByDir(pos, i), i)
			dir2 = getPosByDir(getPosByDir(pos2, i + 1 <= 3 and i + 1 or 0), pos2, i + 1 <= 3 and i + 1 or 0)
			doSendDistanceShoot(dir2, dir, config.effects.big_spin)
		end
		doCombat(cid, combat, var)
		addEvent(spin, config.speed, cid, var, position, hits, n + 1)
	end
return true
end

function endEffect(position)
	for i = 0, 7 do
		local dir = {}
		local pos = {x = position.x, y = position.y, z = position.z}
		if (i > 3) then dir = getPosByDir(getPosByDir(pos, i), i)
		else dir = getPosByDir(pos, i) end
		doSendDistanceShoot(dir, position, config.effects.spin)
	end
return true
end

function onCastSpell(cid, var)
    if getGlobalStorageValue(config.storages.use) == getCreatureName(cid) and getPlayerStorageValue(cid, config.storages.use) - os.time() <= 0 then
        setPlayerStorageValue(cid, config.storages.use, os.time() + config.cooldown)

        local pos = {}
        if getCreatureTarget(cid) ~= 0 then
            pos = getCreaturePosition(getCreatureTarget(cid))
        else
            pos = getCreatureLookPosition(cid)
        end

        doCreatureSay(cid, config.msg, TALKTYPE_MONSTER_SAY)
        initEffect(pos)
        addEvent(spin, 1000, cid, var, pos, config.hits)
        addEvent(cornerEffect, 1000, pos)
        addEvent(endEffect, 7000, pos)
    elseif getGlobalStorageValue(config.storages.use) ~= getCreatureName(cid) then
        doPlayerSendCancel(cid, "You don't control Luna's power.")
    else
        doPlayerSendCancel(cid, "You're exhausted.")
    end

return true
end
 

 

 

 

Essa magia tem duas peculiaridades:

1. Ela tem uma chance de 1/15 para cada hit que ela dá de congelar o alvo e tornalo imóvel por 1.8 segundos, o que já está implementado nesse script e já funciona.

2. Em pvp, isso é, ao atacar um player, ela tem uma chance de 1/18 de liberar a Benção de Luna e tornar o caster imune aos ataques daquele player por 3 segundos (atenção, não são de todos os players da área, somente do player que liberou a benção de luna ao receber um hit).

Para implementar essa segunda parte, precisamos ir em creature scripts.

Adicione as tags abaixo a creaturescripts.xml:

<event type="attack" name="NoAtt" event="script" value="luna.lua"/>
<event type="cast" name="NoSpell" event="script" value="luna.lua"/>
<event type="target" name="NoTgt" event="script" value="luna.lua"/>

Crie um arquivo chamado luna.lua dentro de scripts e coloque o código abaixo nele:

 

 

function onCast(cid, target)
    if getGlobalStorageValue(5545) == -1 and isPlayer(target) then
        return true
    else
        return false
    end
end

function onAttack(cid, target)
    if getGlobalStorageValue(5545) == -1 and isPlayer(target) then
        return true
    else
        return false
    end
end

function onTarget(cid, target)
    if getGlobalStorageValue(5545) == -1 and isPlayer(target) then
        return true
    else
        doPlayerSendCancel(cid, "Unable to attack, Luna blessed your target.")
        return false
    end
end
 

 

 

 

Pronto, o seu evento está configura e sua magia 'Luna Strike' poderá ser castada pelo último vencedor do mesmo.

Espero que gostem, os scripts estão comentados e são bem auto-explicativos, mas qualquer dúvida podem me perguntar.

 

Abraços,

Edited by Skulls
Link to comment
Share on other sites

Belíssimo script, estou louco para testar :smile_positivo: :smile_positivo:

Muito obrigado! Quando testar me diga o que achou, :p

Descobri hoje que em algumas versões do baiak existe um evento parecido, porém com fogo, chamado fire storm (ou algo assim). Mas eu achei a de gelo mais legal, rsrs

Link to comment
Share on other sites

×
×
  • Create New...