Resolved Lua Script for Dismount on ZoneID (For Jump Event) Trinitycore 3.3.5 Rev 2022

iThorgrim

Member
iThorgrim Rep
0
0
0
Rep
0
iThorgrim Vouches
0
0
0
Vouches
0
Posts
5
Likes
3
Bits
2 YEARS
2 YEARS OF SERVICE
LEVEL 3 90 XP
If you want, you can also use a Lua module I've created that lets you create polygons (without using radius) that weave a line between each coordinate, so that if your area isn't round but looks like a polygon you can disallow mounts.

I personally use it for housing, but you can vary the uses. I think you'll have to optimize it in the future, but you can use it easily :)

Name this file "RayTracing2D.lua", the comment are in french (sorry)
Code:
--[[
    Compléxité algorithmique :
        reverseVertexOrder : O(n) car la fonction parcourt tous les éléments d'un tableau une seule fois.
        doLineSegmentsIntersect : O(1) car la fonction ne parcourt pas de tableaux et ne contient pas de boucles.
        createBoundingBox : O(n) car la fonction parcourt tous les éléments d'un tableau une seule fois.
        isInsideBoundingBox : O(1) car la fonction ne parcourt pas de tableaux et ne contient pas de boucles.
        RayTracing2D : O(n) car la fonction parcourt tous les éléments d'un tableau une seule fois.
]]--


local RayTrace = {}


--[[
    La fonction reverseVertexOrder prend en paramètre une table d'objets contenant des verticles (points) nommée "verticles".
    Elle crée une nouvelle table vide nommée "reversedVerticles".
    En utilisant une boucle for qui parcourt les éléments de la table "verticles" en commençant par le dernier élément et en finissant par le premier,
    elle insère chaque élément dans la table "reversedVerticles" en utilisant la fonction table.insert.
    La fonction retourne finalement la table "reversedVerticles" qui contient les éléments de la table "verticles" dans l'ordre inverse.
]]--
local function reverseVertexOrder(verticles)
    local reversedverticles = {}
    for i = #verticles, 1, -1 do
        table.insert(reversedverticles, verticles[i])
    end
    return reversedverticles
end


--[[
    La fonction "doLineSegmentsIntersect" vérifie si un segment de ligne donné et un rayon donné se croisent.
    Le point, le rayon, le vertex, le nextVertex et la position du joueur sont passés en tant que paramètres.
    Les deux premières lignes de la fonction définissent les vecteurs de bord et de rayon en utilisant les positions des points de vertex,
    de nextVertex par rapport à la position du joueur.
    La première partie du if-statement vérifie si le produit vectoriel entre le vecteur de bord et le vecteur de rayon est négatif ou positif.
    Si c'est le cas, cela signifie que le rayon et le segment de ligne ne se croisent pas et la fonction renvoie false.
    La deuxième partie du if-statement vérifie si le produit vectoriel entre le vecteur de bord suivant et le vecteur de rayon est négatif ou positif.
    Si c'est le cas, cela signifie que le rayon et le segment de ligne suivant ne se croisent pas et la fonction renvoie false.
    Ensuite, la fonction calcule l'angle entre les vecteurs de bord et de nextEdge en utilisant la fonction math.acos et vérifie si ces angles sont inférieurs à pi/2.
    Si c'est le cas, cela signifie que le rayon et les segments de ligne se croisent, et la fonction renvoie true.
    Sinon, elle renvoie false.
]]--
local function doLineSegmentsIntersect(point, ray, vertex, nextVertex, playerPosition)
    local edgeVector = {x = vertex.x - playerPosition.x, y = vertex.y - playerPosition.y}
    local rayVector = {x = ray.x - playerPosition.x, y = ray.y - playerPosition.y}
    local nextEdgeVector = {x = nextVertex.x - playerPosition.x, y = nextVertex.y - playerPosition.y}
    if (edgeVector.y > 0 and rayVector.y < 0) or (edgeVector.y < 0 and rayVector.y > 0) then
        return false
    end
    if (nextEdgeVector.y > 0 and rayVector.y < 0) or (nextEdgeVector.y < 0 and rayVector.y > 0) then
        return false
    end
    local cross1 = edgeVector.x * rayVector.y - edgeVector.y * rayVector.x
    local cross2 = nextEdgeVector.x * rayVector.y - nextEdgeVector.y * rayVector.x
    if cross1 * cross2 > 0 then
        return false
    end
    local angle1 = math.acos(edgeVector.x / math.sqrt(edgeVector.x * edgeVector.x + edgeVector.y * edgeVector.y))
    local angle2 = math.acos(nextEdgeVector.x / math.sqrt(nextEdgeVector.x * nextEdgeVector.x + nextEdgeVector.y * nextEdgeVector.y))
    if angle1 < math.pi / 2 and angle2 < math.pi / 2 then
        return true
    end
    return false
end


--[[
    La fonction createBoundingBox prend en entrée un polygone sous forme de tableau de sommets.
    Elle initialise les variables minX, maxX, minY et maxY avec des valeurs extrêmes (respectivement math.huge et -math.huge),
    qui seront utilisées pour définir les limites de la boîte englobante.
    Ensuite, elle parcourt tous les sommets du polygone en utilisant une boucle for et ipairs, et met à jour les variables minX, maxX, minY et maxY,
    en utilisant les fonctions math.min et math.max pour définir les valeurs minimales et maximales pour chacune des coordonnées x et y.
    Enfin, la fonction affiche les valeurs minimales et maximales obtenues pour les coordonnées x et y,
    puis retourne un tableau contenant ces valeurs sous forme de clés minX, maxX, minY et maxY.
]]--
function RayTrace.createBoundingBox(polygon)
    local minX, maxX, minY, maxY = math.huge, -math.huge, math.huge, -math.huge
    for _, vertex in ipairs(polygon) do
        minX = math.min(minX, vertex.x)
        maxX = math.max(maxX, vertex.x)
        minY = math.min(minY, vertex.y)
        maxY = math.max(maxY, vertex.y)
    end
 
    return {minX = minX, maxX = maxX, minY = minY, maxY = maxY}
end


--[[
    La fonction "isInsideBoundingBox" prend en entrée un "boundingBox" et une "position".
    Elle vérifie si la "position" se trouve à l'intérieur de la "boundingBox" en comparant les coordonnées x et y de "position" avec les limites de la "boundingBox"
    (minX, maxX, minY, maxY).
 
    Si les coordonnées x et y de "position" se situent entre les limites de la "boundingBox",
    la fonction renvoie "true" sinon elle renvoie "false".
]]--
local function isInsideBoundingBox(boundingBox, position)
    return position.x >= boundingBox.minX and position.x <= boundingBox.maxX and
        position.y >= boundingBox.minY and position.y <= boundingBox.maxY
end


--[[
    La fonction Player:RayTracing2D prend en entrée un polygone et une boîte englobante.
    Elle vérifie si le joueur est à l'intérieur du polygone en utilisant une méthode de rayonnement 2D. Elle utilise les fonctions reverseVertexOrder,
    isInsideBoundingBox et doLineSegmentsIntersect pour effectuer cette vérification.
    Elle utilise la variable "position" pour stocker la position actuelle du joueur.
    La variable "pData" est utilisée pour stocker si le joueur était déjà à l'intérieur du polygone lors de la dernière vérification.
    Si le joueur est à l'intérieur de la boîte englobante, la fonction inverse l'ordre des sommets du polygone,
    puis calcule un rayon qui part du point le plus à droite du polygone et passe par la position actuelle du joueur.
    Elle compte ensuite le nombre d'intersections entre ce rayon et les segments formés par les sommets consécutifs du polygone.
    Si ce nombre est impair, cela signifie que le joueur est à l'intérieur du polygone. Sinon, il est à l'extérieur.
    La fonction utilise également la variable "pData" pour vérifier si le joueur était déjà à l'intérieur du polygone lors de la dernière vérification.
    Si oui, la fonction retourne "true" pour indiquer que le joueur est toujours à l'intérieur du polygone.
    Sinon, elle retourne "false" pour indiquer qu'il est à l'extérieur.
    Enfin, elle met à jour la variable "pData" en fonction de la résultat de la vérification.
 
]]--
function Player:RayTracing2D(polygon, boundingBox)
    local position = self:GetPosition()
    local pData = self:GetData("inside_polygon") or false
    if isInsideBoundingBox(boundingBox, position) then
        polygon = reverseVertexOrder(polygon)
        local max = -1
        for i, vertex in ipairs(polygon) do
            if vertex.x > max then
                max = vertex.x
            end
        end
        local ray = {x = position.x + max + 1, y = position.y}
        local intersections = 0
        for i = 1, #polygon do
            if doLineSegmentsIntersect(position, ray, polygon[i], polygon[i % #polygon + 1], position) then
                intersections = intersections + 1
            end
        end
        if intersections % 2 == 1 and pData == false then
            self:SetData("inside_polygon", true)
            return true
        else
            if (intersections % 2 ~= 1) then
                if (pData == true) then
                    self:SetData("inside_polygon", false)
                end
                return false
            end
        end
    else
        if (pData == true) then
            self:SetData("inside_polygon", false)
        end
        return false
    end
end
return RayTrace

This si your "main" script for locked mount in Polygon

Code:
local RayTrace = require("RayTracing2D")
local Points = {
    [0] = { -- This is your MapID
        [1519] = { -- This is your AreaID
            {x = -8808.886719,  y = 629.936768, z = 94.228920}, -- This is a vertices of your polygon
            {x = -8794.510742,  y = 637.831726, z = 94.232796},-- This is a vertices of your polygon
            {x = -8800.683594,  y = 650.272400, z = 94.518021},-- This is a vertices of your polygon
            {x = -8815.123047,  y = 643.107849, z = 94.229118},-- This is a vertices of your polygon
        }
    }
}
local BoundingBox = {}
function Player:GetPosition()
    return {
        x = self:GetX(),
        y = self:GetY(),
        z = self:GetZ(),
        o = self:GetO(),
        a = self:GetAreaId(),
        m = self:GetMapId()
    }
end

local function Timed(eventid, delay, repeats, player)
    local position = player:GetPosition()
    player:RayTracing2D(Points[position.m][position.a], BoundingBox[position.m][position.a])

    local pInside = player:GetData("inside_polygon")
    local pNotification = player:GetData("last_notification")

    if (pInside and pNotification ~= 2) then
       if player:IsMounted() then
            player:Dismount()
            player:SendAreaTriggerMessage("Mounts are not allowed in this zone.")
            player:SetData("last_notification", 2)
       end
    end

end
local function onPlayerUpdateZone(event, player, newZone, newArea)
    local position = player:GetPosition()
    local playerEvent = player:GetData("subzone_event_id")

    if (playerEvent) then
        player:RemoveEventById(playerEvent)
    end

    if(Points[position.m] ~= nil and Points[position.m][position.a] ~= nil) then
        if (BoundingBox[position.m] == nil) then
            BoundingBox[position.m] = { }
        end

        if (BoundingBox[position.m][position.a] == nil) then
            BoundingBox[position.m][position.a] = RayTrace.createBoundingBox(Points[position.m][position.a])
        end

        playerEvent = player:RegisterEvent(Timed, 1000, 0)
        player:SetData("subzone_event_id", playerEvent)
    end
end
RegisterPlayerEvent(27, onPlayerUpdateZone)

local function onPlayerCastSpell(event, player, spell)
    local pInside = player:GetData("inside_polygon")
    if pInside then
        player:StopSpellCast()
        player:SendAreaTriggerMessage("Spells or Mounts are not allowed in this area.")
    end
end
RegisterPlayerEvent(5, onPlayerCastSpell)

Edit this, [0] is your MapId, [1519] is your AreaID and all subarray are all of your points (the vertices of your polygon)​


Code:
local Points = {
    [0] = { -- This is your MapID
        [1519] = { -- This is your AreaID
            {x = -8808.886719,  y = 629.936768, z = 94.228920}, -- This is a vertices of your polygon
            {x = -8794.510742,  y = 637.831726, z = 94.232796},-- This is a vertices of your polygon
            {x = -8800.683594,  y = 650.272400, z = 94.518021},-- This is a vertices of your polygon
            {x = -8815.123047,  y = 643.107849, z = 94.229118},-- This is a vertices of your polygon
        }
    }
}
 
Last edited:
Liked By 2 members :

3,388

1,270

9,554

428

Top