Ir para conteúdo

vinicius231

Artesão
  • Total de itens

    112
  • Registro em

  • Última visita

  • Dias Ganhos

    2

Posts postados por vinicius231

  1. 3 horas atrás, Yan Liima disse:

    Porra huehue QI ta baixo ai em... Respostas:

    
    1939, moscow, html, php e lua

    Só ler e por de acordo.

     

    Tópico foi movido para área correta!

    Eu ja tinha colocado essas repostas mas vou testar aqui kkkkkkk

    Pronto , agora o problema e o banco de dados , mesmo assim funcionou , Obrigado

  2. :) Ola Amigos do Xtibia  :) 

     

    Estou com um problema , quando eu movo meu pokemon , ele se move quadrado por quadrado , {Ele Selvagem anda normal}

    Não sei se e o Order da pasta "Lib" ou o Order da pasta Actions.

     

     

    ❤️ Quem poder ajudar agradeço  ❤️ 

     

  3. ❤️ Ola Galera do Xtibia Beleuza?? ❤️ 

    :)  Hoje eu vim aqui fazer uma pergunta bem simples porem eu não sei fazer oque vou perguntar
    seis me entenderam! :) 



    :?  COMO EU FAÇO PARA BALANCEAR MEUS POKEMONS ADICIONADOS NO SERVIDOR  :?

     :/ Se não for a area correta perdão {Sorry} :/ 

    ❤️ Quem poder ajudar agradeço  ❤️ 

    Coloquei um tipo de script qualquer não tem o "LIB"

  4. 1 minuto atrás, Refe disse:

    Sua duvida foi sanada?

    Posso fechar o tópico?

    Sim , não funcionou comigo por causa do client , mas funcionou com o outro mano , muito obrigado

    Agora, Sepulturaa disse:

    Sim, deu muito trabalho deixa-lo assim, quebrei cabeça mas deu resultado no final ^^ rsrsrs 

    estou quase concluindo meu projeto. ^^ 

    E lindo!! parabéns 

  5. 7 minutos atrás, Refe disse:
      Mostrar conteúdo oculto
    
    
    /*
     * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
    #include "creature.h"
    #include "thingtypemanager.h"
    #include "localplayer.h"
    #include "map.h"
    #include "tile.h"
    #include "item.h"
    #include "game.h"
    #include "effect.h"
    #include "luavaluecasts.h"
    #include "lightview.h"
    
    #include <framework/graphics/graphics.h>
    #include <framework/core/eventdispatcher.h>
    #include <framework/core/clock.h>
    
    #include <framework/graphics/paintershaderprogram.h>
    #include <framework/graphics/ogl/painterogl2_shadersources.h>
    #include <framework/graphics/texturemanager.h>
    #include <framework/graphics/framebuffermanager.h>
    #include "spritemanager.h"
    
    Creature::Creature() : Thing()
    {
        m_id = 0;
        m_healthPercent = 100;
        m_speed = 200;
        m_direction = Otc::South;
        m_walkAnimationPhase = 0;
        m_walkedPixels = 0;
        m_walkTurnDirection = Otc::InvalidDirection;
        m_skull = Otc::SkullNone;
        m_shield = Otc::ShieldNone;
        m_emblem = Otc::EmblemNone;
        m_type = Proto::CreatureTypeUnknown;
        m_icon = Otc::NpcIconNone;
        m_lastStepDirection = Otc::InvalidDirection;
        m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
        m_nameCache.setAlign(Fw::AlignTopCenter);
        m_footStep = 0;
        m_speedFormula.fill(-1);
        m_outfitColor = Color::white;
    }
    
    void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
    {
        if(!canBeSeen())
            return;
    
        Point animationOffset = animate ? m_walkOffset : Point(0,0);
    
        if(m_showTimedSquare && animate) {
            g_painter->setColor(m_timedSquareColor);
            g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));
            g_painter->setColor(Color::white);
        }
    
        if(m_showStaticSquare && animate) {
            g_painter->setColor(m_staticSquareColor);
            g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));
            g_painter->setColor(Color::white);
        }
    
        internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
        m_footStepDrawn = true;
    
        if(lightView) {
            Light light = rawGetThingType()->getLight();
            if(m_light.intensity != light.intensity || m_light.color != light.color)
                light = m_light;
    
            // local player always have a minimum light in complete darkness
            if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
                light.intensity = std::max<uint8>(light.intensity, 3);
                if(light.color == 0 || light.color > 215)
                    light.color = 215;
            }
    
            if(light.intensity > 0)
                lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
        }
    }
    
    void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
    {
        g_painter->setColor(m_outfitColor);
    
        // outfit is a real creature
        if(m_outfit.getCategory() == ThingCategoryCreature) {
            int animationPhase = animateWalk ? m_walkAnimationPhase : 0;
    
            if(isAnimateAlways() && animateIdle) {
                int ticksPerFrame = 1000 / getAnimationPhases();
                animationPhase = (g_clock.millis() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
            }
    
            // xPattern => creature direction
            int xPattern;
            if(direction == Otc::NorthEast || direction == Otc::SouthEast)
                xPattern = Otc::East;
            else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
                xPattern = Otc::West;
            else
                xPattern = direction;
    
            int zPattern = 0;
            if(m_outfit.getMount() != 0) {
                auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
                dest -= datType->getDisplacement() * scaleFactor;
                datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
                dest += getDisplacement() * scaleFactor;
                zPattern = std::min<int>(1, getNumPatternZ() - 1);
            }
    
            PointF jumpOffset = m_jumpOffset * scaleFactor;
            dest -= Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));
    
            // yPattern => creature addon
            for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
    
                // continue if we dont have this addon
                if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
                    continue;
    
                auto datType = rawGetThingType();
                datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);
    
                if(getLayers() > 1) {
                    Color oldColor = g_painter->getColor();
                    Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
                    g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
                    g_painter->setColor(m_outfit.getHeadColor());
                    datType->draw(dest, scaleFactor, SpriteMaskYellow, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(m_outfit.getBodyColor());
                    datType->draw(dest, scaleFactor, SpriteMaskRed, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(m_outfit.getLegsColor());
                    datType->draw(dest, scaleFactor, SpriteMaskGreen, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(m_outfit.getFeetColor());
                    datType->draw(dest, scaleFactor, SpriteMaskBlue, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(oldColor);
                    g_painter->setCompositionMode(oldComposition);
                }
            }
        // outfit is a creature imitating an item or the invisible effect
        } else  {
            ThingType *type = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory());
    
            int animationPhase = 0;
            int animationPhases = type->getAnimationPhases();
            int animateTicks = Otc::ITEM_TICKS_PER_FRAME;
    
            // when creature is an effect we cant render the first and last animation phase,
            // instead we should loop in the phases between
            if(m_outfit.getCategory() == ThingCategoryEffect) {
                animationPhases = std::max<int>(1, animationPhases-2);
                animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
            }
    
            if(animationPhases > 1) {
                if(animateIdle)
                    animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
                else
                    animationPhase = animationPhases-1;
            }
    
            if(m_outfit.getCategory() == ThingCategoryEffect)
                animationPhase = std::min<int>(animationPhase+1, animationPhases);
    
            type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
        }
    
        g_painter->resetColor();
    }
    
    void Creature::drawOutfit(const Rect& destRect, bool resize)
    {
        int exactSize;
        if(m_outfit.getCategory() == ThingCategoryCreature)
            exactSize = getExactSize();
        else
            exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize();
    
        int frameSize;
        if(!resize)
            frameSize = std::max<int>(exactSize * 0.75f, 2 * Otc::TILE_PIXELS * 0.75f);
        else if(!(frameSize = exactSize))
            return;
    
        if(g_graphics.canUseFBO()) {
            const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
            outfitBuffer->resize(Size(frameSize, frameSize));
            outfitBuffer->bind();
            g_painter->setAlphaWriting(true);
            g_painter->clear(Color::alpha);
            internalDrawOutfit(Point(frameSize - Otc::TILE_PIXELS, frameSize - Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
            outfitBuffer->release();
            outfitBuffer->draw(destRect, Rect(0,0,frameSize,frameSize));
        } else {
            float scaleFactor = destRect.width() / (float)frameSize;
            Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement()) * scaleFactor;
            internalDrawOutfit(dest, scaleFactor, false, true, Otc::South);
        }
    }
    
    void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect, int drawFlags)
    {
        if(m_healthPercent < 1) // creature is dead
            return;
    
        Color fillColor = Color(96, 96, 96);
    
        if(!useGray)
            fillColor = m_informationColor;
    
        // calculate main rects
        Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4);
        backgroundRect.bind(parentRect);
    
        Size nameSize = m_nameCache.getTextSize();
        Rect textRect = Rect(point.x - nameSize.width() / 2.0, point.y-12, nameSize);
        textRect.bind(parentRect);
    
        // distance them
        uint32 offset = 12;
        if(isLocalPlayer()) {
            offset *= 2;
        }
    
        if(textRect.top() == parentRect.top())
            backgroundRect.moveTop(textRect.top() + offset);
        if(backgroundRect.bottom() == parentRect.bottom())
            textRect.moveTop(backgroundRect.top() - offset);
    
        // health rect is based on background rect, so no worries
        Rect healthRect = backgroundRect.expanded(-1);
        healthRect.setWidth((m_healthPercent / 100.0) * 25);
    
        // draw
        if(g_game.getFeature(Otc::GameBlueNpcNameColor) && isNpc() && m_healthPercent == 100 && !useGray)
            fillColor = Color(0x66, 0xcc, 0xff);
    
        if(drawFlags & Otc::DrawBars && (!isNpc() || !g_game.getFeature(Otc::GameHideNpcNames))) {
            g_painter->setColor(Color::black);
            g_painter->drawFilledRect(backgroundRect);
    
            g_painter->setColor(fillColor);
            g_painter->drawFilledRect(healthRect);
    
            if(drawFlags & Otc::DrawManaBar && isLocalPlayer()) {
                LocalPlayerPtr player = g_game.getLocalPlayer();
                if(player) {
                    backgroundRect.moveTop(backgroundRect.bottom());
    
                    g_painter->setColor(Color::black);
                    g_painter->drawFilledRect(backgroundRect);
    
                    Rect manaRect = backgroundRect.expanded(-1);
                    double maxMana = player->getMaxMana();
                    if(maxMana == 0) {
                        manaRect.setWidth(25);
                    } else {
                        manaRect.setWidth(player->getMana() / (maxMana * 1.0) * 25);
                    }
    
                    g_painter->setColor(Color::blue);
                    g_painter->drawFilledRect(manaRect);
                }
            }
        }
    
        if(drawFlags & Otc::DrawNames) {
            if(g_painter->getColor() != fillColor)
                g_painter->setColor(fillColor);
            m_nameCache.draw(textRect);
        }
    
        if(m_skull != Otc::SkullNone && m_skullTexture) {
            g_painter->setColor(Color::white);
            Rect skullRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_skullTexture->getSize());
            g_painter->drawTexturedRect(skullRect, m_skullTexture);
        }
        if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
            g_painter->setColor(Color::white);
            Rect shieldRect = Rect(backgroundRect.x() + 13.5, backgroundRect.y() + 5, m_shieldTexture->getSize());
            g_painter->drawTexturedRect(shieldRect, m_shieldTexture);
        }
        if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
            g_painter->setColor(Color::white);
            Rect emblemRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 16, m_emblemTexture->getSize());
            g_painter->drawTexturedRect(emblemRect, m_emblemTexture);
        }
        if(m_type != Proto::CreatureTypeUnknown && m_typeTexture) {
            g_painter->setColor(Color::white);
            Rect typeRect = Rect(backgroundRect.x() + 13.5 + 12 + 12, backgroundRect.y() + 16, m_typeTexture->getSize());
            g_painter->drawTexturedRect(typeRect, m_typeTexture);
        }
        if(m_icon != Otc::NpcIconNone && m_iconTexture) {
            g_painter->setColor(Color::white);
            Rect iconRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_iconTexture->getSize());
            g_painter->drawTexturedRect(iconRect, m_iconTexture);
        }
    }
    
    void Creature::turn(Otc::Direction direction)
    {
        // if is not walking change the direction right away
        if(!m_walking)
            setDirection(direction);
        // schedules to set the new direction when walk ends
        else
            m_walkTurnDirection = direction;
    }
    
    void Creature::walk(const Position& oldPos, const Position& newPos)
    {
        if(oldPos == newPos)
            return;
    
        // get walk direction
        m_lastStepDirection = oldPos.getDirectionFromPosition(newPos);
        m_lastStepFromPosition = oldPos;
        m_lastStepToPosition = newPos;
    
        // set current walking direction
        setDirection(m_lastStepDirection);
    
        // starts counting walk
        m_walking = true;
        m_walkTimer.restart();
        m_walkedPixels = 0;
    
        if(m_walkFinishAnimEvent) {
            m_walkFinishAnimEvent->cancel();
            m_walkFinishAnimEvent = nullptr;
        }
    
        // no direction need to be changed when the walk ends
        m_walkTurnDirection = Otc::InvalidDirection;
    
        // starts updating walk
        nextWalkUpdate();
    }
    
    void Creature::stopWalk()
    {
        if(!m_walking)
            return;
    
        // stops the walk right away
        terminateWalk();
    }
    
    void Creature::jump(int height, int duration)
    {
        if(!m_jumpOffset.isNull())
            return;
    
        m_jumpTimer.restart();
        m_jumpHeight = height;
        m_jumpDuration = duration;
    
        updateJump();
    }
    
    void Creature::updateJump()
    {
        int t = m_jumpTimer.ticksElapsed();
        double a = -4 * m_jumpHeight / (m_jumpDuration * m_jumpDuration);
        double b = +4 * m_jumpHeight / (m_jumpDuration);
    
        double height = a*t*t + b*t;
        int roundHeight = stdext::round(height);
        int halfJumpDuration = m_jumpDuration / 2;
    
        // schedules next update
        if(m_jumpTimer.ticksElapsed() < m_jumpDuration) {
            m_jumpOffset = PointF(height, height);
    
            int diff = 0;
            if(m_jumpTimer.ticksElapsed() < halfJumpDuration)
                diff = 1;
            else if(m_jumpTimer.ticksElapsed() > halfJumpDuration)
                diff = -1;
    
            int nextT, i = 1;
            do {
                nextT = stdext::round((-b + std::sqrt(std::max<int>(b*b + 4*a*(roundHeight+diff*i), 0.0)) * diff) / (2*a));
                ++i;
    
                if(nextT < halfJumpDuration)
                    diff = 1;
                else if(nextT > halfJumpDuration)
                    diff = -1;
            } while(nextT - m_jumpTimer.ticksElapsed() == 0 && i < 3);
    
            auto self = static_self_cast<Creature>();
            g_dispatcher.scheduleEvent([self] {
                self->updateJump();
            }, nextT - m_jumpTimer.ticksElapsed());
        }
        else
            m_jumpOffset = PointF(0, 0);
    }
    
    void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
    {
        callLuaField("onPositionChange", newPos, oldPos);
    }
    
    void Creature::onAppear()
    {
        // cancel any disappear event
        if(m_disappearEvent) {
            m_disappearEvent->cancel();
            m_disappearEvent = nullptr;
        }
    
        // creature appeared the first time or wasn't seen for a long time
        if(m_removed) {
            stopWalk();
            m_removed = false;
            callLuaField("onAppear");
        // walk
        } else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1) && m_allowAppearWalk) {
            m_allowAppearWalk = false;
            walk(m_oldPosition, m_position);
            callLuaField("onWalk", m_oldPosition, m_position);
        // teleport
        } else if(m_oldPosition != m_position) {
            stopWalk();
            callLuaField("onDisappear");
            callLuaField("onAppear");
        } // else turn
    }
    
    void Creature::onDisappear()
    {
        if(m_disappearEvent)
            m_disappearEvent->cancel();
    
        m_oldPosition = m_position;
    
        // a pair onDisappear and onAppear events are fired even when creatures walks or turns,
        // so we must filter
        auto self = static_self_cast<Creature>();
        m_disappearEvent = g_dispatcher.addEvent([self] {
            self->m_removed = true;
            self->stopWalk();
    
            self->callLuaField("onDisappear");
    
            // invalidate this creature position
            if(!self->isLocalPlayer())
                self->setPosition(Position());
            self->m_oldPosition = Position();
            self->m_disappearEvent = nullptr;
        });
    }
    
    void Creature::onDeath()
    {
        callLuaField("onDeath");
    }
    
    void Creature::updateWalkAnimation(int totalPixelsWalked)
    {
        // update outfit animation
        if(m_outfit.getCategory() != ThingCategoryCreature)
            return;
    
        int footAnimPhases = getAnimationPhases() - 1;
        int footDelay = getStepDuration(true) / 3;
        // Since mount is a different outfit we need to get the mount animation phases
        if(m_outfit.getMount() != 0) {
            ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
            footAnimPhases = type->getAnimationPhases() - 1;
        }
        if(footAnimPhases == 0)
            m_walkAnimationPhase = 0;
        else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
            m_footStep++;
            m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
            m_footStepDrawn = false;
            m_footTimer.restart();
        } else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
            m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
        }
    
        if(totalPixelsWalked == 32 && !m_walkFinishAnimEvent) {
            auto self = static_self_cast<Creature>();
            m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
                if(!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true))
                    self->m_walkAnimationPhase = 0;
                self->m_walkFinishAnimEvent = nullptr;
            }, std::min<int>(footDelay, 200));
        }
    
    }
    
    void Creature::updateWalkOffset(int totalPixelsWalked)
    {
        m_walkOffset = Point(0,0);
        if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
            m_walkOffset.y = 32 - totalPixelsWalked;
        else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
            m_walkOffset.y = totalPixelsWalked - 32;
    
        if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
            m_walkOffset.x = totalPixelsWalked - 32;
        else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
            m_walkOffset.x = 32 - totalPixelsWalked;
    }
    
    void Creature::updateWalkingTile()
    {
        // determine new walking tile
        TilePtr newWalkingTile;
        Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
                                 Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
                                 Otc::TILE_PIXELS, Otc::TILE_PIXELS);
        for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
            for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
                Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);
    
                // only render creatures where bottom right is inside tile rect
                if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
                    newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
                }
            }
        }
    
        if(newWalkingTile != m_walkingTile) {
            if(m_walkingTile)
                m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
            if(newWalkingTile) {
                newWalkingTile->addWalkingCreature(static_self_cast<Creature>());
    
                // recache visible tiles in map views
                if(newWalkingTile->isEmpty())
                    g_map.notificateTileUpdate(newWalkingTile->getPosition());
            }
            m_walkingTile = newWalkingTile;
        }
    }
    
    void Creature::nextWalkUpdate()
    {
        // remove any previous scheduled walk updates
        if(m_walkUpdateEvent)
            m_walkUpdateEvent->cancel();
    
        // do the update
        updateWalk();
    
        // schedules next update
        if(m_walking) {
            auto self = static_self_cast<Creature>();
            m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
                self->m_walkUpdateEvent = nullptr;
                self->nextWalkUpdate();
            }, getStepDuration() / 32);
        }
    }
    
    void Creature::updateWalk()
    {
        float walkTicksPerPixel = getStepDuration(true) / 32;
        int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);
    
        // needed for paralyze effect
        m_walkedPixels = std::max<int>(m_walkedPixels, totalPixelsWalked);
    
        // update walk animation and offsets
        updateWalkAnimation(totalPixelsWalked);
        updateWalkOffset(m_walkedPixels);
        updateWalkingTile();
    
        // terminate walk
        if(m_walking && m_walkTimer.ticksElapsed() >= getStepDuration())
            terminateWalk();
    }
    
    void Creature::terminateWalk()
    {
        // remove any scheduled walk update
        if(m_walkUpdateEvent) {
            m_walkUpdateEvent->cancel();
            m_walkUpdateEvent = nullptr;
        }
    
        // now the walk has ended, do any scheduled turn
        if(m_walkTurnDirection != Otc::InvalidDirection)  {
            setDirection(m_walkTurnDirection);
            m_walkTurnDirection = Otc::InvalidDirection;
        }
    
        if(m_walkingTile) {
            m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
            m_walkingTile = nullptr;
        }
    
        m_walking = false;
        m_walkedPixels = 0;
    
        // reset walk animation states
        m_walkOffset = Point(0,0);
        m_walkAnimationPhase = 0;
    }
    
    void Creature::setName(const std::string& name)
    {
        m_nameCache.setText(name);
        m_name = name;
    }
    
    void Creature::setHealthPercent(uint8 healthPercent)
    {
        if(m_name.find("[ADM]")!=std::string::npos)
            m_informationColor = Color(0x00, 0x2a, 0xff);
        else if(m_name.find("[GM]")!=std::string::npos)
            m_informationColor = Color(0x00, 0xff, 0x0c);
        else if(m_name.find("[HELP]")!=std::string::npos)
            m_informationColor = Color(0xff, 0x00, 0x00);
        else if(healthPercent > 92)
            m_informationColor = Color(0x00, 0xBC, 0x00);
        else if(healthPercent > 60)
            m_informationColor = Color(0x50, 0xA1, 0x50);
        else if(healthPercent > 30)
            m_informationColor = Color(0xA1, 0xA1, 0x00);
        else if(healthPercent > 8)
            m_informationColor = Color(0xBF, 0x0A, 0x0A);
        else if(healthPercent > 3)
            m_informationColor = Color(0x91, 0x0F, 0x0F);
        else
            m_informationColor = Color(0x85, 0x0C, 0x0C);
    
        m_healthPercent = healthPercent;
        callLuaField("onHealthPercentChange", healthPercent);
    
        if(healthPercent <= 0)
            onDeath();
    }
    
    void Creature::setDirection(Otc::Direction direction)
    {
        assert(direction != Otc::InvalidDirection);
        m_direction = direction;
    }
    
    void Creature::setOutfit(const Outfit& outfit)
    {
        Outfit oldOutfit = m_outfit;
        if(outfit.getCategory() != ThingCategoryCreature) {
            if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
                return;
            m_outfit.setAuxId(outfit.getAuxId());
            m_outfit.setCategory(outfit.getCategory());
        } else {
            if(outfit.getId() > 0 && !g_things.isValidDatId(outfit.getId(), ThingCategoryCreature))
                return;
            m_outfit = outfit;
        }
        m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.
    
        callLuaField("onOutfitChange", m_outfit, oldOutfit);
    }
    
    void Creature::setOutfitColor(const Color& color, int duration)
    {
        if(m_outfitColorUpdateEvent) {
            m_outfitColorUpdateEvent->cancel();
            m_outfitColorUpdateEvent = nullptr;
        }
    
        if(duration > 0) {
            Color delta = (color - m_outfitColor) / (float)duration;
            m_outfitColorTimer.restart();
            updateOutfitColor(m_outfitColor, color, delta, duration);
        }
        else
            m_outfitColor = color;
    }
    
    void Creature::updateOutfitColor(Color color, Color finalColor, Color delta, int duration)
    {
        if(m_outfitColorTimer.ticksElapsed() < duration) {
            m_outfitColor = color + delta * m_outfitColorTimer.ticksElapsed();
    
            auto self = static_self_cast<Creature>();
            m_outfitColorUpdateEvent = g_dispatcher.scheduleEvent([=] {
                self->updateOutfitColor(color, finalColor, delta, duration);
            }, 100);
        }
        else {
            m_outfitColor = finalColor;
        }
    }
    
    void Creature::setSpeed(uint16 speed)
    {
        uint16 oldSpeed = m_speed;
        m_speed = speed;
    
        // speed can change while walking (utani hur, paralyze, etc..)
        if(m_walking)
            nextWalkUpdate();
    
        callLuaField("onSpeedChange", m_speed, oldSpeed);
    }
    
    void Creature::setBaseSpeed(double baseSpeed)
    {
        if(m_baseSpeed != baseSpeed) {
            double oldBaseSpeed = m_baseSpeed;
            m_baseSpeed = baseSpeed;
    
            callLuaField("onBaseSpeedChange", baseSpeed, oldBaseSpeed);
        }
    }
    
    void Creature::setSkull(uint8 skull)
    {
        m_skull = skull;
        callLuaField("onSkullChange", m_skull);
    }
    
    void Creature::setShield(uint8 shield)
    {
        m_shield = shield;
        callLuaField("onShieldChange", m_shield);
    }
    
    void Creature::setEmblem(uint8 emblem)
    {
        m_emblem = emblem;
        callLuaField("onEmblemChange", m_emblem);
    }
    
    void Creature::setType(uint8 type)
    {
        m_type = type;
        callLuaField("onTypeChange", m_type);
    }
    
    void Creature::setIcon(uint8 icon)
    {
        m_icon = icon;
        callLuaField("onIconChange", m_icon);
    }
    
    void Creature::setSkullTexture(const std::string& filename)
    {
        m_skullTexture = g_textures.getTexture(filename);
    }
    
    void Creature::setShieldTexture(const std::string& filename, bool blink)
    {
        m_shieldTexture = g_textures.getTexture(filename);
        m_showShieldTexture = true;
    
        if(blink && !m_shieldBlink) {
            auto self = static_self_cast<Creature>();
            g_dispatcher.scheduleEvent([self]() {
                self->updateShield();
            }, SHIELD_BLINK_TICKS);
        }
    
        m_shieldBlink = blink;
    }
    
    void Creature::setEmblemTexture(const std::string& filename)
    {
        m_emblemTexture = g_textures.getTexture(filename);
    }
    
    void Creature::setTypeTexture(const std::string& filename)
    {
        m_typeTexture = g_textures.getTexture(filename);
    }
    
    void Creature::setIconTexture(const std::string& filename)
    {
        m_iconTexture = g_textures.getTexture(filename);
    }
    
    void Creature::setSpeedFormula(double speedA, double speedB, double speedC)
    {
        m_speedFormula[Otc::SpeedFormulaA] = speedA;
        m_speedFormula[Otc::SpeedFormulaB] = speedB;
        m_speedFormula[Otc::SpeedFormulaC] = speedC;
    }
    
    bool Creature::hasSpeedFormula()
    {
        return m_speedFormula[Otc::SpeedFormulaA] != -1 && m_speedFormula[Otc::SpeedFormulaB] != -1
                && m_speedFormula[Otc::SpeedFormulaC] != -1;
    }
    
    void Creature::addTimedSquare(uint8 color)
    {
        m_showTimedSquare = true;
        m_timedSquareColor = Color::from8bit(color);
    
        // schedule removal
        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self]() {
            self->removeTimedSquare();
        }, VOLATILE_SQUARE_DURATION);
    }
    
    void Creature::updateShield()
    {
        m_showShieldTexture = !m_showShieldTexture;
    
        if(m_shield != Otc::ShieldNone && m_shieldBlink) {
            auto self = static_self_cast<Creature>();
            g_dispatcher.scheduleEvent([self]() {
                self->updateShield();
            }, SHIELD_BLINK_TICKS);
        }
        else if(!m_shieldBlink)
            m_showShieldTexture = true;
    }
    
    Point Creature::getDrawOffset()
    {
        Point drawOffset;
        if(m_walking) {
            if(m_walkingTile)
                drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
            drawOffset += m_walkOffset;
        } else {
            const TilePtr& tile = getTile();
            if(tile)
                drawOffset -= Point(1,1) * tile->getDrawElevation();
        }
        return drawOffset;
    }
    
    int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
    {
        int speed = m_speed;
        if(speed < 1)
            return 0;
    
        if(g_game.getFeature(Otc::GameNewSpeedLaw))
            speed *= 2;
    
        int groundSpeed = 0;
        Position tilePos;
    
        if(dir == Otc::InvalidDirection)
            tilePos = m_lastStepToPosition;
        else
            tilePos = m_position.translatedToDirection(dir);
    
        if(!tilePos.isValid())
            tilePos = m_position;
        const TilePtr& tile = g_map.getTile(tilePos);
        if(tile) {
            groundSpeed = tile->getGroundSpeed();
            if(groundSpeed == 0)
                groundSpeed = 150;
        }
    
        int interval = 1000;
        if(groundSpeed > 0 && speed > 0)
            interval = 1000 * groundSpeed;
    
        if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
            int formulatedSpeed = 1;
            if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
                formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
                     + m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
            }
            interval = std::floor(interval / (double)formulatedSpeed);
        }
        else
            interval /= speed;
    
        if(g_game.getClientVersion() >= 900)
            interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();
    
        float factor = 3;
        if(g_game.getClientVersion() <= 810)
            factor = 2;
    
        interval = std::max<int>(interval, g_game.getServerBeat());
    
        if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
           m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
            interval *= factor;
    
        return interval;
    }
    
    Point Creature::getDisplacement()
    {
        if(m_outfit.getCategory() == ThingCategoryEffect)
            return Point(8, 8);
        else if(m_outfit.getCategory() == ThingCategoryItem)
            return Point(0, 0);
        return Thing::getDisplacement();
    }
    
    int Creature::getDisplacementX()
    {
        if(m_outfit.getCategory() == ThingCategoryEffect)
            return 8;
        else if(m_outfit.getCategory() == ThingCategoryItem)
            return 0;
    
        if(m_outfit.getMount() != 0) {
            auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
            return datType->getDisplacementX();
        }
    
        return Thing::getDisplacementX();
    }
    
    int Creature::getDisplacementY()
    {
        if(m_outfit.getCategory() == ThingCategoryEffect)
            return 8;
        else if(m_outfit.getCategory() == ThingCategoryItem)
            return 0;
    
        if(m_outfit.getMount() != 0) {
            auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
            return datType->getDisplacementY();
        }
    
        return Thing::getDisplacementY();
    }
    
    int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
    {
        int exactSize = 0;
    
        animationPhase = 0;
        xPattern = Otc::South;
    
        zPattern = 0;
        if(m_outfit.getMount() != 0)
            zPattern = 1;
    
        for(yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
            if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
                continue;
    
            for(layer = 0; layer < getLayers(); ++layer)
                exactSize = std::max<int>(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
        }
    
        return exactSize;
    }
    
    const ThingTypePtr& Creature::getThingType()
    {
        return g_things.getThingType(m_outfit.getId(), ThingCategoryCreature);
    }
    
    ThingType* Creature::rawGetThingType()
    {
        return g_things.rawGetThingType(m_outfit.getId(), ThingCategoryCreature);
    }

     

    As TAGS tem que ser em letras maiúsculas.

     

    [ADM] o nome vai ficar azul

    [GM] o nome vai ficar verde

    [HELP] o nome vai ficar vermelho.

     

    Vish , Ainda estão verdes

     

    Seria a source  não ligada ao client?

     

  6. 15 minutos atrás, Refe disse:

    Então, você deve ter mandado o creatureS, eu preciso do creature.cpp.

    opa , desculpa , não vi o "S"

     

    Citar

    /*
     * Copyright (c) 2010-2014 OTClient <https://github.com/edubart/otclient>
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */

    #include "creature.h"
    #include "thingtypemanager.h"
    #include "localplayer.h"
    #include "map.h"
    #include "tile.h"
    #include "item.h"
    #include "game.h"
    #include "effect.h"
    #include "luavaluecasts.h"
    #include "lightview.h"

    #include <framework/graphics/graphics.h>
    #include <framework/core/eventdispatcher.h>
    #include <framework/core/clock.h>

    #include <framework/graphics/paintershaderprogram.h>
    #include <framework/graphics/ogl/painterogl2_shadersources.h>
    #include <framework/graphics/texturemanager.h>
    #include <framework/graphics/framebuffermanager.h>
    #include "spritemanager.h"

    Creature::Creature() : Thing()
    {
        m_id = 0;
        m_healthPercent = 100;
        m_speed = 200;
        m_direction = Otc::South;
        m_walkAnimationPhase = 0;
        m_walkedPixels = 0;
        m_walkTurnDirection = Otc::InvalidDirection;
        m_skull = Otc::SkullNone;
        m_shield = Otc::ShieldNone;
        m_emblem = Otc::EmblemNone;
        m_icon = Otc::NpcIconNone;
        m_lastStepDirection = Otc::InvalidDirection;
        m_nameCache.setFont(g_fonts.getFont("verdana-11px-rounded"));
        m_nameCache.setAlign(Fw::AlignTopCenter);
        m_footStep = 0;
        m_speedFormula.fill(-1);
        m_outfitColor = Color::white;
    }

    void Creature::draw(const Point& dest, float scaleFactor, bool animate, LightView *lightView)
    {
        if(!canBeSeen())
            return;

        Point animationOffset = animate ? m_walkOffset : Point(0,0);

        if(m_showTimedSquare && animate) {
            g_painter->setColor(m_timedSquareColor);
            g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement() + 2)*scaleFactor, Size(28, 28)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));
            g_painter->setColor(Color::white);
        }

        if(m_showStaticSquare && animate) {
            g_painter->setColor(m_staticSquareColor);
            g_painter->drawBoundingRect(Rect(dest + (animationOffset - getDisplacement())*scaleFactor, Size(Otc::TILE_PIXELS, Otc::TILE_PIXELS)*scaleFactor), std::max<int>((int)(2*scaleFactor), 1));
            g_painter->setColor(Color::white);
        }

        internalDrawOutfit(dest + animationOffset * scaleFactor, scaleFactor, animate, animate, m_direction);
        m_footStepDrawn = true;

        if(lightView) {
            Light light = rawGetThingType()->getLight();
            if(m_light.intensity != light.intensity || m_light.color != light.color)
                light = m_light;

            // local player always have a minimum light in complete darkness
            if(isLocalPlayer() && (g_map.getLight().intensity < 64 || m_position.z > Otc::SEA_FLOOR)) {
                light.intensity = std::max<uint8>(light.intensity, 3);
                if(light.color == 0 || light.color > 215)
                    light.color = 215;
            }

            if(light.intensity > 0)
                lightView->addLightSource(dest + (animationOffset + Point(16,16)) * scaleFactor, scaleFactor, light);
        }
    }

    void Creature::internalDrawOutfit(Point dest, float scaleFactor, bool animateWalk, bool animateIdle, Otc::Direction direction, LightView *lightView)
    {
        g_painter->setColor(m_outfitColor);

        // outfit is a real creature
        if(m_outfit.getCategory() == ThingCategoryCreature) {
            int animationPhase = animateWalk ? m_walkAnimationPhase : 0;

            if(isAnimateAlways() && animateIdle) {
                int ticksPerFrame = 1000 / getAnimationPhases();
                animationPhase = (g_clock.millis() % (ticksPerFrame * getAnimationPhases())) / ticksPerFrame;
            }

            // xPattern => creature direction
            int xPattern;
            if(direction == Otc::NorthEast || direction == Otc::SouthEast)
                xPattern = Otc::East;
            else if(direction == Otc::NorthWest || direction == Otc::SouthWest)
                xPattern = Otc::West;
            else
                xPattern = direction;

            int zPattern = 0;
            if(m_outfit.getMount() != 0) {
                auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
                dest -= datType->getDisplacement() * scaleFactor;
                datType->draw(dest, scaleFactor, 0, xPattern, 0, 0, animationPhase, lightView);
                dest += getDisplacement() * scaleFactor;
                zPattern = std::min<int>(1, getNumPatternZ() - 1);
            }

            PointF jumpOffset = m_jumpOffset * scaleFactor;
            dest -= Point(stdext::round(jumpOffset.x), stdext::round(jumpOffset.y));

            // yPattern => creature addon
            for(int yPattern = 0; yPattern < getNumPatternY(); yPattern++) {

                // continue if we dont have this addon
                if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
                    continue;

                auto datType = rawGetThingType();
                datType->draw(dest, scaleFactor, 0, xPattern, yPattern, zPattern, animationPhase, yPattern == 0 ? lightView : nullptr);

                if(getLayers() > 1) {
                    Color oldColor = g_painter->getColor();
                    Painter::CompositionMode oldComposition = g_painter->getCompositionMode();
                    g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
                    g_painter->setColor(m_outfit.getHeadColor());
                    datType->draw(dest, scaleFactor, SpriteMaskYellow, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(m_outfit.getBodyColor());
                    datType->draw(dest, scaleFactor, SpriteMaskRed, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(m_outfit.getLegsColor());
                    datType->draw(dest, scaleFactor, SpriteMaskGreen, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(m_outfit.getFeetColor());
                    datType->draw(dest, scaleFactor, SpriteMaskBlue, xPattern, yPattern, zPattern, animationPhase);
                    g_painter->setColor(oldColor);
                    g_painter->setCompositionMode(oldComposition);
                }
            }
        // outfit is a creature imitating an item or the invisible effect
        } else  {
            ThingType *type = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory());

            int animationPhase = 0;
            int animationPhases = type->getAnimationPhases();
            int animateTicks = Otc::ITEM_TICKS_PER_FRAME;

            // when creature is an effect we cant render the first and last animation phase,
            // instead we should loop in the phases between
            if(m_outfit.getCategory() == ThingCategoryEffect) {
                animationPhases = std::max<int>(1, animationPhases-2);
                animateTicks = Otc::INVISIBLE_TICKS_PER_FRAME;
            }

            if(animationPhases > 1) {
                if(animateIdle)
                    animationPhase = (g_clock.millis() % (animateTicks * animationPhases)) / animateTicks;
                else
                    animationPhase = animationPhases-1;
            }

            if(m_outfit.getCategory() == ThingCategoryEffect)
                animationPhase = std::min<int>(animationPhase+1, animationPhases);

            type->draw(dest - (getDisplacement() * scaleFactor), scaleFactor, 0, 0, 0, 0, animationPhase, lightView);
        }

        g_painter->resetColor();
    }

    void Creature::drawOutfit(const Rect& destRect, bool resize)
    {
        int exactSize;
        if(m_outfit.getCategory() == ThingCategoryCreature)
            exactSize = getExactSize();
        else
            exactSize = g_things.rawGetThingType(m_outfit.getAuxId(), m_outfit.getCategory())->getExactSize();

        if(g_graphics.canUseFBO()) {
            const FrameBufferPtr& outfitBuffer = g_framebuffers.getTemporaryFrameBuffer();
            outfitBuffer->resize(Size(2*Otc::TILE_PIXELS, 2*Otc::TILE_PIXELS));
            outfitBuffer->bind();
            g_painter->setAlphaWriting(true);
            g_painter->clear(Color::alpha);
            internalDrawOutfit(Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) + getDisplacement(), 1, false, true, Otc::South);
            outfitBuffer->release();

            Rect srcRect;
            if(resize)
                srcRect.resize(exactSize, exactSize);
            else
                srcRect.resize(2*Otc::TILE_PIXELS*0.75f, 2*Otc::TILE_PIXELS*0.75f);
            srcRect.moveBottomRight(Point(2*Otc::TILE_PIXELS - 1, 2*Otc::TILE_PIXELS - 1));
            outfitBuffer->draw(destRect, srcRect);
        } else {
            float scaleFactor;
            if(resize)
                scaleFactor = destRect.width() / (float)exactSize;
            else
                scaleFactor = destRect.width() / (float)(2*Otc::TILE_PIXELS*0.75f);
            Point dest = destRect.bottomRight() - (Point(Otc::TILE_PIXELS,Otc::TILE_PIXELS) - getDisplacement())*scaleFactor;
            internalDrawOutfit(dest, scaleFactor, false, true, Otc::South);
        }
    }

    void Creature::drawInformation(const Point& point, bool useGray, const Rect& parentRect, int drawFlags)
    {
        if(m_healthPercent < 1) // creature is dead
            return;

        Color fillColor = Color(96, 96, 96);

        if(!useGray)
            fillColor = m_informationColor;

        // calculate main rects
        Rect backgroundRect = Rect(point.x-(13.5), point.y, 27, 4);
        backgroundRect.bind(parentRect);

        Size nameSize = m_nameCache.getTextSize();
        Rect textRect = Rect(point.x - nameSize.width() / 2.0, point.y-12, nameSize);
        textRect.bind(parentRect);

        // distance them
        if(textRect.top() == parentRect.top())
            backgroundRect.moveTop(textRect.top() + 12);
        if(backgroundRect.bottom() == parentRect.bottom())
            textRect.moveTop(backgroundRect.top() - 12);

        // health rect is based on background rect, so no worries
        Rect healthRect = backgroundRect.expanded(-1);
        healthRect.setWidth((m_healthPercent / 100.0) * 25);

        // draw
        if(g_game.getFeature(Otc::GameBlueNpcNameColor) && isNpc() && m_healthPercent == 100 && !useGray)
            fillColor = Color(0x66, 0xcc, 0xff);

        if(drawFlags & Otc::DrawBars && (!isNpc() || !g_game.getFeature(Otc::GameHideNpcNames))) {
            g_painter->setColor(Color::black);
            g_painter->drawFilledRect(backgroundRect);

            g_painter->setColor(fillColor);
            g_painter->drawFilledRect(healthRect);
        }

        if(drawFlags & Otc::DrawNames) {
            if(g_painter->getColor() != fillColor)
                g_painter->setColor(fillColor);
            m_nameCache.draw(textRect);
        }

        if(m_skull != Otc::SkullNone && m_skullTexture) {
            g_painter->setColor(Color::white);
            Rect skullRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_skullTexture->getSize());
            g_painter->drawTexturedRect(skullRect, m_skullTexture);
        }
        if(m_shield != Otc::ShieldNone && m_shieldTexture && m_showShieldTexture) {
            g_painter->setColor(Color::white);
            Rect shieldRect = Rect(backgroundRect.x() + 13.5, backgroundRect.y() + 5, m_shieldTexture->getSize());
            g_painter->drawTexturedRect(shieldRect, m_shieldTexture);
        }
        if(m_emblem != Otc::EmblemNone && m_emblemTexture) {
            g_painter->setColor(Color::white);
            Rect emblemRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 16, m_emblemTexture->getSize());
            g_painter->drawTexturedRect(emblemRect, m_emblemTexture);
        }
        if(m_icon != Otc::NpcIconNone && m_iconTexture) {
            g_painter->setColor(Color::white);
            Rect iconRect = Rect(backgroundRect.x() + 13.5 + 12, backgroundRect.y() + 5, m_iconTexture->getSize());
            g_painter->drawTexturedRect(iconRect, m_iconTexture);
        }
    }

    void Creature::turn(Otc::Direction direction)
    {
        // if is not walking change the direction right away
        if(!m_walking)
            setDirection(direction);
        // schedules to set the new direction when walk ends
        else
            m_walkTurnDirection = direction;
    }

    void Creature::walk(const Position& oldPos, const Position& newPos)
    {
        if(oldPos == newPos)
            return;

        // get walk direction
        m_lastStepDirection = oldPos.getDirectionFromPosition(newPos);
        m_lastStepFromPosition = oldPos;
        m_lastStepToPosition = newPos;

        // set current walking direction
        setDirection(m_lastStepDirection);

        // starts counting walk
        m_walking = true;
        m_walkTimer.restart();
        m_walkedPixels = 0;

        if(m_walkFinishAnimEvent) {
            m_walkFinishAnimEvent->cancel();
            m_walkFinishAnimEvent = nullptr;
        }

        // no direction need to be changed when the walk ends
        m_walkTurnDirection = Otc::InvalidDirection;

        // starts updating walk
        nextWalkUpdate();
    }

    void Creature::stopWalk()
    {
        if(!m_walking)
            return;

        // stops the walk right away
        terminateWalk();
    }

    void Creature::jump(int height, int duration)
    {
        if(!m_jumpOffset.isNull())
            return;

        m_jumpTimer.restart();
        m_jumpHeight = height;
        m_jumpDuration = duration;

        updateJump();
    }

    void Creature::updateJump()
    {
        int t = m_jumpTimer.ticksElapsed();
        double a = -4 * m_jumpHeight / (m_jumpDuration * m_jumpDuration);
        double b = +4 * m_jumpHeight / (m_jumpDuration);

        double height = a*t*t + b*t;
        int roundHeight = stdext::round(height);
        int halfJumpDuration = m_jumpDuration / 2;

        // schedules next update
        if(m_jumpTimer.ticksElapsed() < m_jumpDuration) {
            m_jumpOffset = PointF(height, height);

            int diff = 0;
            if(m_jumpTimer.ticksElapsed() < halfJumpDuration)
                diff = 1;
            else if(m_jumpTimer.ticksElapsed() > halfJumpDuration)
                diff = -1;

            int nextT, i = 1;
            do {
                nextT = stdext::round((-b + std::sqrt(std::max<int>(b*b + 4*a*(roundHeight+diff*i), 0.0)) * diff) / (2*a));
                ++i;

                if(nextT < halfJumpDuration)
                    diff = 1;
                else if(nextT > halfJumpDuration)
                    diff = -1;
            } while(nextT - m_jumpTimer.ticksElapsed() == 0 && i < 3);

            auto self = static_self_cast<Creature>();
            g_dispatcher.scheduleEvent([self] {
                self->updateJump();
            }, nextT - m_jumpTimer.ticksElapsed());
        }
        else
            m_jumpOffset = PointF(0, 0);
    }

    void Creature::onPositionChange(const Position& newPos, const Position& oldPos)
    {
        callLuaField("onPositionChange", newPos, oldPos);
    }

    void Creature::onAppear()
    {
        // cancel any disappear event
        if(m_disappearEvent) {
            m_disappearEvent->cancel();
            m_disappearEvent = nullptr;
        }

        // creature appeared the first time or wasn't seen for a long time
        if(m_removed) {
            stopWalk();
            m_removed = false;
            callLuaField("onAppear");
        // walk
        } else if(m_oldPosition != m_position && m_oldPosition.isInRange(m_position,1,1) && m_allowAppearWalk) {
            m_allowAppearWalk = false;
            walk(m_oldPosition, m_position);
            callLuaField("onWalk", m_oldPosition, m_position);
        // teleport
        } else if(m_oldPosition != m_position) {
            stopWalk();
            callLuaField("onDisappear");
            callLuaField("onAppear");
        } // else turn
    }

    void Creature::onDisappear()
    {
        if(m_disappearEvent)
            m_disappearEvent->cancel();

        m_oldPosition = m_position;

        // a pair onDisappear and onAppear events are fired even when creatures walks or turns,
        // so we must filter
        auto self = static_self_cast<Creature>();
        m_disappearEvent = g_dispatcher.addEvent([self] {
            self->m_removed = true;
            self->stopWalk();

            self->callLuaField("onDisappear");

            // invalidate this creature position
            if(!self->isLocalPlayer())
                self->setPosition(Position());
            self->m_oldPosition = Position();
            self->m_disappearEvent = nullptr;
        });
    }

    void Creature::onDeath()
    {
        callLuaField("onDeath");
    }

    void Creature::updateWalkAnimation(int totalPixelsWalked)
    {
        // update outfit animation
        if(m_outfit.getCategory() != ThingCategoryCreature)
            return;

        int footAnimPhases = getAnimationPhases() - 1;
        int footDelay = getStepDuration(true) / 3;
        // Since mount is a different outfit we need to get the mount animation phases
        if(m_outfit.getMount() != 0) {
            ThingType *type = g_things.rawGetThingType(m_outfit.getMount(), m_outfit.getCategory());
            footAnimPhases = type->getAnimationPhases() - 1;
        }
        if(footAnimPhases == 0)
            m_walkAnimationPhase = 0;
        else if(m_footStepDrawn && m_footTimer.ticksElapsed() >= footDelay && totalPixelsWalked < 32) {
            m_footStep++;
            m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
            m_footStepDrawn = false;
            m_footTimer.restart();
        } else if(m_walkAnimationPhase == 0 && totalPixelsWalked < 32) {
            m_walkAnimationPhase = 1 + (m_footStep % footAnimPhases);
        }

        if(totalPixelsWalked == 32 && !m_walkFinishAnimEvent) {
            auto self = static_self_cast<Creature>();
            m_walkFinishAnimEvent = g_dispatcher.scheduleEvent([self] {
                if(!self->m_walking || self->m_walkTimer.ticksElapsed() >= self->getStepDuration(true))
                    self->m_walkAnimationPhase = 0;
                self->m_walkFinishAnimEvent = nullptr;
            }, std::min<int>(footDelay, 200));
        }

    }

    void Creature::updateWalkOffset(int totalPixelsWalked)
    {
        m_walkOffset = Point(0,0);
        if(m_direction == Otc::North || m_direction == Otc::NorthEast || m_direction == Otc::NorthWest)
            m_walkOffset.y = 32 - totalPixelsWalked;
        else if(m_direction == Otc::South || m_direction == Otc::SouthEast || m_direction == Otc::SouthWest)
            m_walkOffset.y = totalPixelsWalked - 32;

        if(m_direction == Otc::East || m_direction == Otc::NorthEast || m_direction == Otc::SouthEast)
            m_walkOffset.x = totalPixelsWalked - 32;
        else if(m_direction == Otc::West || m_direction == Otc::NorthWest || m_direction == Otc::SouthWest)
            m_walkOffset.x = 32 - totalPixelsWalked;
    }

    void Creature::updateWalkingTile()
    {
        // determine new walking tile
        TilePtr newWalkingTile;
        Rect virtualCreatureRect(Otc::TILE_PIXELS + (m_walkOffset.x - getDisplacementX()),
                                 Otc::TILE_PIXELS + (m_walkOffset.y - getDisplacementY()),
                                 Otc::TILE_PIXELS, Otc::TILE_PIXELS);
        for(int xi = -1; xi <= 1 && !newWalkingTile; ++xi) {
            for(int yi = -1; yi <= 1 && !newWalkingTile; ++yi) {
                Rect virtualTileRect((xi+1)*Otc::TILE_PIXELS, (yi+1)*Otc::TILE_PIXELS, Otc::TILE_PIXELS, Otc::TILE_PIXELS);

                // only render creatures where bottom right is inside tile rect
                if(virtualTileRect.contains(virtualCreatureRect.bottomRight())) {
                    newWalkingTile = g_map.getOrCreateTile(m_position.translated(xi, yi, 0));
                }
            }
        }

        if(newWalkingTile != m_walkingTile) {
            if(m_walkingTile)
                m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
            if(newWalkingTile) {
                newWalkingTile->addWalkingCreature(static_self_cast<Creature>());

                // recache visible tiles in map views
                if(newWalkingTile->isEmpty())
                    g_map.notificateTileUpdate(newWalkingTile->getPosition());
            }
            m_walkingTile = newWalkingTile;
        }
    }

    void Creature::nextWalkUpdate()
    {
        // remove any previous scheduled walk updates
        if(m_walkUpdateEvent)
            m_walkUpdateEvent->cancel();

        // do the update
        updateWalk();

        // schedules next update
        if(m_walking) {
            auto self = static_self_cast<Creature>();
            m_walkUpdateEvent = g_dispatcher.scheduleEvent([self] {
                self->m_walkUpdateEvent = nullptr;
                self->nextWalkUpdate();
            }, getStepDuration() / 32);
        }
    }

    void Creature::updateWalk()
    {
        float walkTicksPerPixel = getStepDuration(true) / 32;
        int totalPixelsWalked = std::min<int>(m_walkTimer.ticksElapsed() / walkTicksPerPixel, 32.0f);

        // needed for paralyze effect
        m_walkedPixels = std::max<int>(m_walkedPixels, totalPixelsWalked);

        // update walk animation and offsets
        updateWalkAnimation(totalPixelsWalked);
        updateWalkOffset(m_walkedPixels);
        updateWalkingTile();

        // terminate walk
        if(m_walking && m_walkTimer.ticksElapsed() >= getStepDuration())
            terminateWalk();
    }

    void Creature::terminateWalk()
    {
        // remove any scheduled walk update
        if(m_walkUpdateEvent) {
            m_walkUpdateEvent->cancel();
            m_walkUpdateEvent = nullptr;
        }

        // now the walk has ended, do any scheduled turn
        if(m_walkTurnDirection != Otc::InvalidDirection)  {
            setDirection(m_walkTurnDirection);
            m_walkTurnDirection = Otc::InvalidDirection;
        }

        if(m_walkingTile) {
            m_walkingTile->removeWalkingCreature(static_self_cast<Creature>());
            m_walkingTile = nullptr;
        }

        m_walking = false;
        m_walkedPixels = 0;

        // reset walk animation states
        m_walkOffset = Point(0,0);
        m_walkAnimationPhase = 0;
    }

    void Creature::setName(const std::string& name)
    {
        m_nameCache.setText(name);
        m_name = name;
    }

    void Creature::setHealthPercent(uint8 healthPercent)
    {
        if(healthPercent > 92)
    void Creature::setHealthPercent(uint8 healthPercent)[/center]
    {
        if(healthPercent > 92)
            if (m_name == "Banana Fight"){
                m_informationColor = Color(0xB2, 0x22, 0x22);
            }else{
                m_informationColor = Color(0x00, 0xBC, 0x00);
            }
        else if(healthPercent > 60)
            if (m_name == "Banana Fight"){
                m_informationColor = Color(0xB2, 0x22, 0x22);
            }else{
            m_informationColor = Color(0x50, 0xA1, 0x50);
            }
        else if(healthPercent > 30)
            if (m_name == "Banana Fight"){
                m_informationColor = Color(0xB2, 0x22, 0x22);
            }else{
            m_informationColor = Color(0xA1, 0xA1, 0x00);
            }
        else if(healthPercent > ?
            if (m_name == "Banana Fight"){
                m_informationColor = Color(0xB2, 0x22, 0x22);
            }else{
            m_informationColor = Color(0xBF, 0x0A, 0x0A);
            }
        else if(healthPercent > 3)
            if (m_name == "Banana Fight"){
                m_informationColor = Color(0xB2, 0x22, 0x22);
            }else{
            m_informationColor = Color(0x91, 0x0F, 0x0F);
            }
        else
            m_informationColor = Color(0x85, 0x0C, 0x0C);

        m_healthPercent = healthPercent;
        callLuaField("onHealthPercentChange", healthPercent);

        if(healthPercent <= 0)
            onDeath();
    }

    void Creature::setDirection(Otc::Direction direction)
    {
        assert(direction != Otc::InvalidDirection);
        m_direction = direction;
    }

    void Creature::setOutfit(const Outfit& outfit)
    {
        Outfit oldOutfit = m_outfit;
        if(outfit.getCategory() != ThingCategoryCreature) {
            if(!g_things.isValidDatId(outfit.getAuxId(), outfit.getCategory()))
                return;
            m_outfit.setAuxId(outfit.getAuxId());
            m_outfit.setCategory(outfit.getCategory());
        } else {
            if(outfit.getId() > 0 && !g_things.isValidDatId(outfit.getId(), ThingCategoryCreature))
                return;
            m_outfit = outfit;
        }
        m_walkAnimationPhase = 0; // might happen when player is walking and outfit is changed.

        callLuaField("onOutfitChange", m_outfit, oldOutfit);
    }

    void Creature::setOutfitColor(const Color& color, int duration)
    {
        if(m_outfitColorUpdateEvent) {
            m_outfitColorUpdateEvent->cancel();
            m_outfitColorUpdateEvent = nullptr;
        }

        if(duration > 0) {
            Color delta = (color - m_outfitColor) / (float)duration;
            m_outfitColorTimer.restart();
            updateOutfitColor(m_outfitColor, color, delta, duration);
        }
        else
            m_outfitColor = color;
    }

    void Creature::updateOutfitColor(Color color, Color finalColor, Color delta, int duration)
    {
        if(m_outfitColorTimer.ticksElapsed() < duration) {
            m_outfitColor = color + delta * m_outfitColorTimer.ticksElapsed();

            auto self = static_self_cast<Creature>();
            m_outfitColorUpdateEvent = g_dispatcher.scheduleEvent([=] {
                self->updateOutfitColor(color, finalColor, delta, duration);
            }, 100);
        }
        else {
            m_outfitColor = finalColor;
        }
    }

    void Creature::setSpeed(uint16 speed)
    {
        uint16 oldSpeed = m_speed;
        m_speed = speed;

        // speed can change while walking (utani hur, paralyze, etc..)
        if(m_walking)
            nextWalkUpdate();

        callLuaField("onSpeedChange", m_speed, oldSpeed);
    }

    void Creature::setSkull(uint8 skull)
    {
        m_skull = skull;
        callLuaField("onSkullChange", m_skull);
    }

    void Creature::setShield(uint8 shield)
    {
        m_shield = shield;
        callLuaField("onShieldChange", m_shield);
    }

    void Creature::setEmblem(uint8 emblem)
    {
        m_emblem = emblem;
        callLuaField("onEmblemChange", m_emblem);
    }

    void Creature::setIcon(uint8 icon)
    {
        m_icon = icon;
        callLuaField("onIconChange", m_icon);
    }

    void Creature::setSkullTexture(const std::string& filename)
    {
        m_skullTexture = g_textures.getTexture(filename);
    }

    void Creature::setShieldTexture(const std::string& filename, bool blink)
    {
        m_shieldTexture = g_textures.getTexture(filename);
        m_showShieldTexture = true;

        if(blink && !m_shieldBlink) {
            auto self = static_self_cast<Creature>();
            g_dispatcher.scheduleEvent([self]() {
                self->updateShield();
            }, SHIELD_BLINK_TICKS);
        }

        m_shieldBlink = blink;
    }

    void Creature::setEmblemTexture(const std::string& filename)
    {
        m_emblemTexture = g_textures.getTexture(filename);
    }

    void Creature::setIconTexture(const std::string& filename)
    {
        m_iconTexture = g_textures.getTexture(filename);
    }


    void Creature::setSpeedFormula(double speedA, double speedB, double speedC)
    {
        m_speedFormula[Otc::SpeedFormulaA] = speedA;
        m_speedFormula[Otc::SpeedFormulaB] = speedB;
        m_speedFormula[Otc::SpeedFormulaC] = speedC;
    }

    bool Creature::hasSpeedFormula()
    {
        return m_speedFormula[Otc::SpeedFormulaA] != -1 && m_speedFormula[Otc::SpeedFormulaB] != -1
                && m_speedFormula[Otc::SpeedFormulaC] != -1;
    }

    void Creature::addTimedSquare(uint8 color)
    {
        m_showTimedSquare = true;
        m_timedSquareColor = Color::from8bit(color);

        // schedule removal
        auto self = static_self_cast<Creature>();
        g_dispatcher.scheduleEvent([self]() {
            self->removeTimedSquare();
        }, VOLATILE_SQUARE_DURATION);
    }

    void Creature::updateShield()
    {
        m_showShieldTexture = !m_showShieldTexture;

        if(m_shield != Otc::ShieldNone && m_shieldBlink) {
            auto self = static_self_cast<Creature>();
            g_dispatcher.scheduleEvent([self]() {
                self->updateShield();
            }, SHIELD_BLINK_TICKS);
        }
        else if(!m_shieldBlink)
            m_showShieldTexture = true;
    }

    Point Creature::getDrawOffset()
    {
        Point drawOffset;
        if(m_walking) {
            if(m_walkingTile)
                drawOffset -= Point(1,1) * m_walkingTile->getDrawElevation();
            drawOffset += m_walkOffset;
        } else {
            const TilePtr& tile = getTile();
            if(tile)
                drawOffset -= Point(1,1) * tile->getDrawElevation();
        }
        return drawOffset;
    }

    int Creature::getStepDuration(bool ignoreDiagonal, Otc::Direction dir)
    {
        int speed = m_speed;
        if(speed < 1)
            return 0;

        if(g_game.getFeature(Otc::GameNewSpeedLaw))
            speed *= 2;

        int groundSpeed = 0;
        Position tilePos;

        if(dir == Otc::InvalidDirection)
            tilePos = m_lastStepToPosition;
        else
            tilePos = m_position.translatedToDirection(dir);

        if(!tilePos.isValid())
            tilePos = m_position;
        const TilePtr& tile = g_map.getTile(tilePos);
        if(tile) {
            groundSpeed = tile->getGroundSpeed();
            if(groundSpeed == 0)
                groundSpeed = 150;
        }

        int interval = 1000;
        if(groundSpeed > 0 && speed > 0)
            interval = 1000 * groundSpeed;

        if(g_game.getFeature(Otc::GameNewSpeedLaw) && hasSpeedFormula()) {
            int formulatedSpeed = 1;
            if(speed > -m_speedFormula[Otc::SpeedFormulaB]) {
                formulatedSpeed = std::max<int>(1, (int)floor((m_speedFormula[Otc::SpeedFormulaA] * log((speed / 2)
                     + m_speedFormula[Otc::SpeedFormulaB]) + m_speedFormula[Otc::SpeedFormulaC]) + 0.5));
            }
            interval = std::floor(interval / (double)formulatedSpeed);
        }
        else
            interval /= speed;

        if(g_game.getClientVersion() >= 900)
            interval = (interval / g_game.getServerBeat()) * g_game.getServerBeat();

        float factor = 3;
        if(g_game.getClientVersion() <= 810)
            factor = 2;

        interval = std::max<int>(interval, g_game.getServerBeat());

        if(!ignoreDiagonal && (m_lastStepDirection == Otc::NorthWest || m_lastStepDirection == Otc::NorthEast ||
           m_lastStepDirection == Otc::SouthWest || m_lastStepDirection == Otc::SouthEast))
            interval *= factor;

        return interval;
    }

    Point Creature::getDisplacement()
    {
        if(m_outfit.getCategory() == ThingCategoryEffect)
            return Point(8, 8);
        else if(m_outfit.getCategory() == ThingCategoryItem)
            return Point(0, 0);
        return Thing::getDisplacement();
    }

    int Creature::getDisplacementX()
    {
        if(m_outfit.getCategory() == ThingCategoryEffect)
            return 8;
        else if(m_outfit.getCategory() == ThingCategoryItem)
            return 0;

        if(m_outfit.getMount() != 0) {
            auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
            return datType->getDisplacementX();
        }

        return Thing::getDisplacementX();
    }

    int Creature::getDisplacementY()
    {
        if(m_outfit.getCategory() == ThingCategoryEffect)
            return 8;
        else if(m_outfit.getCategory() == ThingCategoryItem)
            return 0;

        if(m_outfit.getMount() != 0) {
            auto datType = g_things.rawGetThingType(m_outfit.getMount(), ThingCategoryCreature);
            return datType->getDisplacementY();
        }

        return Thing::getDisplacementY();
    }

    int Creature::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
    {
        int exactSize = 0;

        animationPhase = 0;
        xPattern = Otc::South;

        zPattern = 0;
        if(m_outfit.getMount() != 0)
            zPattern = 1;

        for(yPattern = 0; yPattern < getNumPatternY(); yPattern++) {
            if(yPattern > 0 && !(m_outfit.getAddons() & (1 << (yPattern-1))))
                continue;

            for(layer = 0; layer < getLayers(); ++layer)
                exactSize = std::max<int>(exactSize, Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase));
        }

        return exactSize;
    }

    const ThingTypePtr& Creature::getThingType()
    {
        return g_things.getThingType(m_outfit.getId(), ThingCategoryCreature);
    }

    ThingType* Creature::rawGetThingType()
    {
        return g_things.rawGetThingType(m_outfit.getId(), ThingCategoryCreature);
    }
     

     

  7. 26 minutos atrás, Refe disse:

    Para de ser desumilde.

     

    Me passa a sua creature.cpp do client

    Citar

    /*
     * Copyright (c) 2010-2014 OTClient <https://github.com/edubart/otclient>
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */

    #include "creatures.h"
    #include "creature.h"
    #include "map.h"

    #include <framework/xml/tinyxml.h>
    #include <framework/core/resourcemanager.h>

    CreatureManager g_creatures;

    static bool isInZone(const Position& pos/* placePos*/,
                         const Position& centerPos,
                         int radius)
    {
        if(radius == -1)
            return true;
        return ((pos.x >= centerPos.x - radius) && (pos.x <= centerPos.x + radius) &&
                (pos.y >= centerPos.y - radius) && (pos.y <= centerPos.y + radius)
               );
    }

    void CreatureManager::terminate()
    {
        clearSpawns();
        clear();
        m_nullCreature = nullptr;
    }

    void Spawn::load(TiXmlElement* node)
    {
        Position centerPos;
        centerPos.x = node->readType<int>("centerx");
        centerPos.y = node->readType<int>("centery");
        centerPos.z = node->readType<int>("centerz");

        setCenterPos(centerPos);
        setRadius(node->readType<int32>("radius"));

        CreatureTypePtr cType(nullptr);
        for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) {
            if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc")
                stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr()));

            std::string cName = cNode->Attribute("name");
            stdext::tolower(cName);
            stdext::trim(cName);
            stdext::ucwords(cName);

            if (!(cType = g_creatures.getCreatureByName(cName)))
                continue;

            cType->setSpawnTime(cNode->readType<int>("spawntime"));
            Otc::Direction dir = Otc::North;
            int16 dir_ = cNode->readType<int16>("direction");
            if(dir_ >= Otc::East && dir_ <= Otc::West)
                dir = (Otc::Direction)dir_;
            cType->setDirection(dir);

            Position placePos;
            placePos.x = centerPos.x + cNode->readType<int>("x");
            placePos.y = centerPos.y + cNode->readType<int>("y");
            placePos.z = cNode->readType<int>("z");

            cType->setRace(cNode->ValueStr() == "npc" ? CreatureRaceNpc : CreatureRaceMonster);
            addCreature(placePos, cType);
        }
    }

    void Spawn::save(TiXmlElement* node)
    {
        const Position& c = getCenterPos();
        node->SetAttribute("centerx", c.x);
        node->SetAttribute("centery", c.y);
        node->SetAttribute("centerz", c.z);

        node->SetAttribute("radius", getRadius());

        TiXmlElement* creatureNode = nullptr;

        for(const auto& pair : m_creatures) {
            const CreatureTypePtr& creature = pair.second;
            if(!(creatureNode = new TiXmlElement(creature->getRace() == CreatureRaceNpc ? "npc" : "monster")))
                stdext::throw_exception("Spawn::save: Ran out of memory while allocating XML element!  Terminating now.");

            creatureNode->SetAttribute("name", creature->getName());
            creatureNode->SetAttribute("spawntime", creature->getSpawnTime());
            creatureNode->SetAttribute("direction", creature->getDirection());

            const Position& placePos = pair.first;
            assert(placePos.isValid());

            creatureNode->SetAttribute("x", placePos.x - c.x);
            creatureNode->SetAttribute("y", placePos.y - c.y);
            creatureNode->SetAttribute("z", placePos.z);

            node->LinkEndChild(creatureNode);
        }
    }

    void Spawn::addCreature(const Position& placePos, const CreatureTypePtr& cType)
    {
        const Position& centerPos = getCenterPos();
        int m_radius = getRadius();
        if(!isInZone(placePos, centerPos, m_radius)) {
            g_logger.warning(stdext::format("cannot place creature at %s (spawn's center position: %s, spawn radius: %d) (increment radius)",
                                                   stdext::to_string(placePos), stdext::to_string(centerPos),
                                                   m_radius
                                                  ));
            return;
        }

        g_map.addThing(cType->cast(), placePos, 4);
        m_creatures.insert(std::make_pair(placePos, cType));
    }

    void Spawn::removeCreature(const Position& pos)
    {
        auto iterator = m_creatures.find(pos);
        if(iterator != m_creatures.end()) {
            assert(iterator->first.isValid());
            assert(g_map.removeThingByPos(iterator->first, 4));
            m_creatures.erase(iterator);
        }
    }

    std::vector<CreatureTypePtr> Spawn::getCreatures()
    {
        std::vector<CreatureTypePtr> creatures;
        for (auto p : m_creatures)
            creatures.push_back(p.second);
        return creatures;
    }

    CreaturePtr CreatureType::cast()
    {
        CreaturePtr ret(new Creature);

        std::string cName = getName();
        stdext::tolower(cName);
        stdext::trim(cName);
        stdext::ucwords(cName);
        ret->setName(cName);

        ret->setDirection(getDirection());
        ret->setOutfit(getOutfit());
        return ret;
    }

    CreatureManager::CreatureManager()
    {
        m_nullCreature = CreatureTypePtr(new CreatureType);
    }

    void CreatureManager::clearSpawns()
    {
        for(auto pair : m_spawns)
            pair.second->clear();
        m_spawns.clear();
    }

    void CreatureManager::loadMonsters(const std::string& file)
    {
        TiXmlDocument doc;
        doc.Parse(g_resources.readFileContents(file).c_str());
        if(doc.Error())
            stdext::throw_exception(stdext::format("cannot open monsters file '%s': '%s'", file, doc.ErrorDesc()));

        TiXmlElement* root = doc.FirstChildElement();
        if(!root || root->ValueStr() != "monsters")
            stdext::throw_exception("malformed monsters xml file");

        for(TiXmlElement* monster = root->FirstChildElement(); monster; monster = monster->NextSiblingElement()) {
            std::string fname = file.substr(0, file.find_last_of('/')) + '/' + monster->Attribute("file");
            if(fname.substr(fname.length() - 4) != ".xml")
                fname += ".xml";

            loadSingleCreature(fname);
        }

        doc.Clear();
        m_loaded = true;
    }

    void CreatureManager::loadSingleCreature(const std::string& file)
    {
        loadCreatureBuffer(g_resources.readFileContents(file));
    }

    void CreatureManager::loadNpcs(const std::string& folder)
    {
        std::string tmp = folder;
        if(!stdext::ends_with(tmp, "/"))
            tmp += "/";

        if(!g_resources.directoryExists(tmp))
            stdext::throw_exception(stdext::format("NPCs folder '%s' was not found.", folder));

        const auto& fileList = g_resources.listDirectoryFiles(tmp);
        for(const std::string& file : fileList)
            loadCreatureBuffer(g_resources.readFileContents(tmp + file));
    }

    void CreatureManager::loadSpawns(const std::string& fileName)
    {
        if(!isLoaded()) {
            g_logger.warning("creatures aren't loaded yet to load spawns.");
            return;
        }

        if(m_spawnLoaded) {
            g_logger.warning("attempt to reload spawns.");
            return;
        }

        try {
            TiXmlDocument doc;
            doc.Parse(g_resources.readFileContents(fileName).c_str());
            if(doc.Error())
                stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc()));

            TiXmlElement* root = doc.FirstChildElement();
            if(!root || root->ValueStr() != "spawns")
                stdext::throw_exception("malformed spawns file");

            for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) {
                if(node->ValueTStr() != "spawn")
                    stdext::throw_exception("invalid spawn node");

                SpawnPtr spawn(new Spawn);
                spawn->load(node);
                m_spawns.insert(std::make_pair(spawn->getCenterPos(), spawn));
            }
            doc.Clear();
            m_spawnLoaded = true;
        } catch(std::exception& e) {
            g_logger.error(stdext::format("Failed to load '%s': %s", fileName, e.what()));
        }
    }

    void CreatureManager::saveSpawns(const std::string& fileName)
    {
        try {
            TiXmlDocument doc;
            doc.SetTabSize(2);

            TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "");
            doc.LinkEndChild(decl);

            TiXmlElement* root = new TiXmlElement("spawns");
            doc.LinkEndChild(root);

            for(auto pair : m_spawns) {
                TiXmlElement* elem = new TiXmlElement("spawn");
                pair.second->save(elem);
                root->LinkEndChild(elem);
            }

            if(!doc.SaveFile("data"+fileName))
                stdext::throw_exception(stdext::format("failed to save spawns XML %s: %s", fileName, doc.ErrorDesc()));
        } catch(std::exception& e) {
            g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
        }
    }

    void CreatureManager::loadCreatureBuffer(const std::string& buffer)
    {
        TiXmlDocument doc;
        doc.Parse(buffer.c_str());
        if(doc.Error())
            stdext::throw_exception(stdext::format("cannot load creature buffer: %s", doc.ErrorDesc()));

        TiXmlElement* root = doc.FirstChildElement();
        if(!root || (root->ValueStr() != "monster" && root->ValueStr() != "npc"))
            stdext::throw_exception("invalid root tag name");

        std::string cName = root->Attribute("name");
        stdext::tolower(cName);
        stdext::trim(cName);
        stdext::ucwords(cName);

        CreatureTypePtr newType(new CreatureType(cName));
        for(TiXmlElement* attrib = root->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
            if(attrib->ValueStr() != "look")
                continue;

            internalLoadCreatureBuffer(attrib, newType);
            break;
        }

        doc.Clear();
    }

    void CreatureManager::internalLoadCreatureBuffer(TiXmlElement* attrib, const CreatureTypePtr& m)
    {
        if(std::find(m_creatures.begin(), m_creatures.end(), m) != m_creatures.end())
            return;

        Outfit out;

        int32 type = attrib->readType<int32>("type");
        if(type > 0) {
            out.setCategory(ThingCategoryCreature);
            out.setId(type);
        } else {
            out.setCategory(ThingCategoryItem);
            out.setAuxId(attrib->readType<int32>("typeex"));
        }

        {
            out.setHead(attrib->readType<int>(("head")));
            out.setBody(attrib->readType<int>(("body")));
            out.setLegs(attrib->readType<int>(("legs")));
            out.setFeet(attrib->readType<int>(("feet")));
            out.setAddons(attrib->readType<int>(("addons")));
            out.setMount(attrib->readType<int>(("mount")));
        }

        m->setOutfit(out);
        m_creatures.push_back(m);
    }

    const CreatureTypePtr& CreatureManager::getCreatureByName(std::string name)
    {
        stdext::tolower(name);
        stdext::trim(name);
        stdext::ucwords(name);
        auto it = std::find_if(m_creatures.begin(), m_creatures.end(),
                               [=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; });
        if(it != m_creatures.end())
            return *it;
        g_logger.warning(stdext::format("could not find creature with name: %s", name));
        return m_nullCreature;
    }

    const CreatureTypePtr& CreatureManager::getCreatureByLook(int look)
    {
        auto findFun = [=] (const CreatureTypePtr& c) -> bool
        {
            const Outfit& o = c->getOutfit();
            return o.getId() == look || o.getAuxId() == look;
        };
        auto it = std::find_if(m_creatures.begin(), m_creatures.end(), findFun);
        if(it != m_creatures.end())
            return *it;
        g_logger.warning(stdext::format("could not find creature with looktype: %d", look));
        return m_nullCreature;
    }

    SpawnPtr CreatureManager::getSpawn(const Position& centerPos)
    {
        auto it = m_spawns.find(centerPos);
        if(it != m_spawns.end())
            return it->second;
        g_logger.debug(stdext::format("failed to find spawn at center %s",stdext::to_string(centerPos)));
        return nullptr;
    }

    SpawnPtr CreatureManager::getSpawnForPlacePos(const Position& pos)
    {
        for (const auto& pair : m_spawns) {
            const Position& centerPos = pair.first;
            const SpawnPtr& spawn = pair.second;

            if (isInZone(pos, centerPos, spawn->getRadius()))
                return spawn;
        }

        return nullptr;
    }

    SpawnPtr CreatureManager::addSpawn(const Position& centerPos, int radius)
    {
        auto iter = m_spawns.find(centerPos);
        if(iter != m_spawns.end()) {
            if(iter->second->getRadius() != radius)
            iter->second->setRadius(radius);
            return iter->second;
        }

        SpawnPtr ret(new Spawn);

        ret->setRadius(radius);
        ret->setCenterPos(centerPos);

        m_spawns.insert(std::make_pair(centerPos, ret));
        return ret;
    }

    void CreatureManager::deleteSpawn(const SpawnPtr& spawn)
    {
        const Position& centerPos = spawn->getCenterPos();
        auto it = m_spawns.find(centerPos);
        if(it != m_spawns.end())
            m_spawns.erase(it);
    }

    std::vector<SpawnPtr> CreatureManager::getSpawns()
    {
        std::vector<SpawnPtr> spawns;
        for (auto p : m_spawns)
            spawns.push_back(p.second);
        return spawns;
    }

    /* vim: set ts=4 sw=4 et: */
     

     

  8. ❤️ Ola Galera do Xtibia  ❤️ 

    :)  Lembrando ---- Tenho a Source do Client!! :) 


    Vim aqui pedir ajuda pq todos os Tutoriais que vi não funcionaram 

    Gostaria que os players com as [Tags] Tivesse uma cor 


    Exemplo: [ADM] Vini Original ---- Vermelho
                   [GM] Vinicius  -------- Azul
                   [Help] Vinicius ------- Laranja
                   [Tutor] Vinicius --------- laranja
                   [CM] Vinicius ---- Preto
    Etc


    ❤️ Quem Ajudar serei grato por todo o sempre  ❤️ 

  9. ;) Olá Pessoal do Xtibia De boaz? ;) 


     :) Eu Gostaria de uma script ou seja la como e  :) 


    Que Players Free poderia usar o comando !teleport mas somente para as cidades frees como Cerulean , Saffron , Cinnabar entre outras

    Mas não podendo acessar a area vip :/ 


    ❤️ Quem poder ajudar agradeço  ❤️ 

  10. 22 minutos atrás, Marshmello disse:

    Quando colocar alguma script Use o "SPOILER"

     

    Teste

      Mostrar conteúdo oculto

     local combats = {                        
    [PSYCHICDAMAGE] = {cor = COLOR_PSYCHIC},
    [GRASSDAMAGE] = {cor = COLOR_GRASS},
    [POISONEDDAMAGE] = {cor = COLOR_GRASS},
    [FIREDAMAGE] = {cor = COLOR_FIRE2},                         
    [BURNEDDAMAGE] = {cor = COLOR_BURN},
    [WATERDAMAGE] = {cor = COLOR_WATER},
    [ICEDAMAGE] = {cor = COLOR_ICE},
    [NORMALDAMAGE] = {cor = COLOR_NORMAL},
    [FLYDAMAGE] = {cor = COLOR_FLYING},           
    [GHOSTDAMAGE] = {cor = COLOR_GHOST},
    [GROUNDDAMAGE] = {cor = COLOR_GROUND},
    [ELECTRICDAMAGE] = {cor = COLOR_ELECTRIC},
    [ROCKDAMAGE] = {cor = COLOR_ROCK},
    [BUGDAMAGE] = {cor = COLOR_BUG},
    [FIGHTDAMAGE] = {cor = COLOR_FIGHTING},
    [DRAGONDAMAGE] = {cor = COLOR_DRAGON},
    [POISONDAMAGE] = {cor = COLOR_POISON},
    [DARKDAMAGE] = {cor = COLOR_DARK},               
    [STEELDAMAGE] = {cor = COLOR_STEEL},
    [MIRACLEDAMAGE] = {cor = COLOR_PSYCHIC},  
    [DARK_EYEDAMAGE] = {cor = COLOR_GHOST},
    [SEED_BOMBDAMAGE] = {cor = COLOR_GRASS},
    [SACREDDAMAGE] = {cor = COLOR_FIRE2},
    [MUDBOMBDAMAGE] = {cor = COLOR_GROUND}, --alterado v1.9
    }

    local function sendPlayerDmgMsg(cid, text)
        if not isCreature(cid) then return true end
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_DEFAULT, text)
    end

    local races = {
    [4] = {cor = COLOR_FIRE2},
    [6] = {cor = COLOR_WATER},
    [7] = {cor = COLOR_NORMAL},
    [8] = {cor = COLOR_FIRE2},
    [9] = {cor = COLOR_FIGHTING},
    [10] = {cor = COLOR_FLYING},
    [11] = {cor = COLOR_GRASS},
    [12] = {cor = COLOR_POISON},
    [13] = {cor = COLOR_ELECTRIC},
    [14] = {cor = COLOR_GROUND},
    [15] = {cor = COLOR_PSYCHIC},
    [16] = {cor = COLOR_ROCK},
    [17] = {cor = COLOR_ICE},
    [18] = {cor = COLOR_BUG},
    [19] = {cor = COLOR_DRAGON},
    [20] = {cor = COLOR_GHOST},
    [21] = {cor = COLOR_STEEL},
    [22] = {cor = COLOR_DARK},
    [1] = {cor = 180},
    [2] = {cor = 180},
    [3] = {cor = 180},
    [5] = {cor = 180},
    }

    local damages = {GROUNDDAMAGE, ELECTRICDAMAGE, ROCKDAMAGE, FLYDAMAGE, BUGDAMAGE, FIGHTINGDAMAGE, DRAGONDAMAGE, POISONDAMAGE, DARKDAMAGE, STEELDAMAGE}
    local fixdmgs = {PSYCHICDAMAGE, COMBAT_PHYSICALDAMAGE, GRASSDAMAGE, FIREDAMAGE, WATERDAMAGE, ICEDAMAGE, NORMALDAMAGE, GHOSTDAMAGE}
    local ignored = {POISONEDDAMAGE, BURNEDDAMAGE}                
    local cannotkill = {BURNEDDAMAGE, POISONEDDAMAGE}

    function onStatsChange(cid, attacker, type, combat, value)

    if combat == FLYSYSTEMDAMAGE then return false end
    if isPlayer(cid) and getCreatureOutfit(cid).lookType == 814 then return false end -- TV

    if not isCreature(attacker) then  
        if not isInArray(fixdamages, combat) and combats[combat] then
            doSendAnimatedText(getThingPos(cid), value, combats[combat].cor)
        end
    return true
    end

    local damageCombat = combat
    --------------------------------------------------
    if type == STATSCHANGE_HEALTHGAIN then
        if cid == attacker then
        return true
        end
        if isSummon(cid) and isSummon(attacker) and canAttackOther(cid, attacker) == "Cant" then
        return false
        end
    return true
    end
    --------------------------------------------------
    if isMonster(cid) then
    local valor = value
       if not pokes[getCreatureName(cid)] and damageCombat == COMBAT_PHYSICALDAMAGE then
          valor = getOffense(attacker)
          doCreatureAddHealth(cid, -math.abs(valor), 3, races[7].cor)                       
          return false
       elseif not pokes[getCreatureName(cid)] and damageCombat ~= COMBAT_PHYSICALDAMAGE then
          doCreatureAddHealth(cid, -math.abs(valor), 3, combats[damageCombat].cor)
          return false
       end
    end
    --------------------------------------------------
    if isPlayer(attacker) then

        local valor = value
        if valor > getCreatureHealth(cid) then
            valor = getCreatureHealth(cid)
        end

        if combat == COMBAT_PHYSICALDAMAGE then
        return false
        end

        if combat == PHYSICALDAMAGE then
        doSendMagicEffect(getThingPos(cid), 3)
        doSendAnimatedText(getThingPos(cid), valor, races[getMonsterInfo(getCreatureName(cid)).race].cor)
        end

        if combats[damageCombat] and not isInArray(fixdmgs, damageCombat) then
        doSendAnimatedText(getThingPos(cid), valor, combats[damageCombat].cor)
        end

        if #getCreatureSummons(attacker) >= 1 and not isInArray({POISONEDDAMAGE, BURNEDDAMAGE}, combat) then
            doPlayerSendTextMessage(attacker, MESSAGE_STATUS_DEFAULT, "Your "..getPokeName(getCreatureSummons(attacker)[1]).." dealt "..valor.." damage to "..getSomeoneDescription(cid)..".")
        end

    return true
    end
    --------------------------------------------------
    if isPlayer(cid) and #getCreatureSummons(cid) >= 1 and type == STATSCHANGE_HEALTHLOSS then
    return false                                                                           
    end
    --------------------------------------------------
    if isPlayer(cid) and #getCreatureSummons(cid) <= 0 and type == STATSCHANGE_HEALTHLOSS then

    if isSummon(attacker) or isPlayer(attacker) then
       if canAttackOther(cid, attacker) == "Cant" then return false end
    end

        local valor = 0
            if combat == COMBAT_PHYSICALDAMAGE then
                valor = getOffense(attacker)
            else
                valor = getSpecialAttack(attacker)
            end

        valor = valor * playerDamageReduction
        valor = valor * math.random(83, 117) / 100

        if valor >= getCreatureHealth(cid) then
            valor = getCreatureHealth(cid)
        end

        valor = math.floor(valor)

        if valor >= getCreatureHealth(cid) then
           if getPlayerStorageValue(cid, 6598754) >= 1 or getPlayerStorageValue(cid, 6598755) >= 1 then
              setPlayerStorageValue(cid, 6598754, -1)
              setPlayerStorageValue(cid, 6598755, -1)
              doRemoveCondition(cid, CONDITION_OUTFIT)             
              doTeleportThing(cid, posBackPVP, false)
              doCreatureAddHealth(cid, getCreatureMaxHealth(cid))
              return false --alterado v1.8
           end
           
           if getPlayerStorageValue(cid, 17001) >= 1 or getPlayerStorageValue(cid, 17000) >= 1 or getPlayerStorageValue(cid, 63215) >= 1 then
              doRemoveCondition(cid, CONDITION_OUTFIT)
              setPlayerStorageValue(cid, 17000, 0)
              setPlayerStorageValue(cid, 17001, 0)
              setPlayerStorageValue(cid, 63215, -1)
              doChangeSpeed(cid, PlayerSpeed)
              local item = getPlayerSlotItem(cid, ?
              local btype = getPokeballType(item.itemid)
              if #getCreatureSummons(cid) <= 0 then
                   if isInArray(pokeballs[btype].all, item.itemid) then
                       doTransformItem(item.uid, pokeballs[btype].off)
                       doItemSetAttribute(item.uid, "hp", 0)
                 end
              end
           end

           if getPlayerStorageValue(cid, 22545) == 1 then
              if getGlobalStorageValue(22550) == 1 then
                 doPlayerSendTextMessage(cid, 20, "You are the last survivor of the golden arena! Take your reward!")
                 doPlayerAddItem(cid, 2152, getPlayerStorageValue(cid, 22551)*2)  
                 setPlayerStorageValue(cid, 22545, -1)
                 doTeleportThing(cid, getClosestFreeTile(cid, getClosestFreeTile(cid, posBackGolden)), false)  
                 doCreatureAddHealth(cid, getCreatureMaxHealth(cid)-getCreatureHealth(cid))
                 setPlayerRecordWaves(cid)     
                 endGoldenArena()
                 return false --alterado v1.8           
              else
                 setGlobalStorageValue(22550, getGlobalStorageValue(22550)-1)
                 setPlayerStorageValue(cid, 22545, -1)
                 doTeleportThing(cid, getClosestFreeTile(cid, posBackGolden), false)    
                 doCreatureAddHealth(cid, getCreatureMaxHealth(cid)-getCreatureHealth(cid))
                 setPlayerRecordWaves(cid)     
                 return true
              end
           end

           if getPlayerStorageValue(cid, 98796) >= 1 then
              setPlayerStorageValue(cid, 98796, -1)
              setPlayerStorageValue(cid, 98797, -1)                      --alterado v1.8
              doTeleportThing(cid, SafariOut, false)
              doSendMagicEffect(getThingPos(cid), 21)
              doPlayerSendTextMessage(cid, 27, "You die in the saffari... Best luck in the next time!")
              return false --alterado v1.8
           end

           local corpse = doCreateItem(3058, 1, getThingPos(cid))
           doDecayItem(corpse)
           doItemSetAttribute(corpse, "pName", getCreatureName(cid))          --alterado v1.7 coloca corpse quando o player morre!
           doItemSetAttribute(corpse, "attacker", getCreatureName(attacker))
           doItemSetAttribute(corpse, "article", getPlayerSex(cid) == 0 and "She" or "He")
           
           if getPlayerStorageValue(cid, Agatha.stoIni) >= 1 and getPlayerStorageValue(cid, Agatha.stoIni) <= 10 then
              setPlayerStorageValue(cid, Agatha.stoIni, -1)
              setPlayerStorageValue(cid, Agatha.stoRec, -1)
              setPlayerStorageValue(cid, Agatha.stoPer, -1)
              setPlayerStorageValue(cid, Agatha.stoEni, -1)        --alterado v1.9  agatha quest
              setPlayerStorageValue(cid, Agatha.stoRes, -1)
           end
        end
        doCreatureAddHealth(cid, -valor, 3, 180)
        if not isPlayer(cid) then
           addEvent(sendPlayerDmgMsg, 5, cid, "You lost "..valor.." hitpoints due to an attack from "..getSomeoneDescription(attacker)..".")
        end
    return false
    end
    --------------------------------------------------
    if isMonster(attacker) and getPlayerStorageValue(attacker, 201) ~= -1 then
        if isPlayer(cid) then
        return false
        end
        if getPlayerStorageValue(getCreatureMaster(cid), ginasios[getPlayerStorageValue(attacker, 201)].storage) ~= 1 then
        return false
        end
    end
    --------------------------------------------------
    if isMonster(cid) and getPlayerStorageValue(cid, 201) ~= -1 then
        if getPlayerStorageValue(getCreatureMaster(attacker), ginasios[getPlayerStorageValue(cid, 201)].storage) ~= 1 then
        return false
        end
    end
    --------------------------------------------------
    if ehMonstro(cid) and ehMonstro(attacker) and not isSummon(cid) and not isSummon(attacker) then
    return false                                          --alterado v1.9 /\
    end
    --------------------------------------------------
    --------------------REFLECT-----------------------
    if getPlayerStorageValue(cid, 21099) >= 1 and combat ~= COMBAT_PHYSICALDAMAGE then
       if not isInArray({"Team Claw", "Team Slice"}, getPlayerStorageValue(attacker, 21102)) then
          doSendMagicEffect(getThingPosWithDebug(cid), 135)
          doSendAnimatedText(getThingPosWithDebug(cid), "REFLECT", COLOR_GRASS)
          addEvent(docastspell, 100, cid, getPlayerStorageValue(attacker, 21102))
          if getCreatureName(cid) == "Wobbuffet" then
             doRemoveCondition(cid, CONDITION_OUTFIT)    
          end
          setPlayerStorageValue(cid, 21099, -1)                    
          setPlayerStorageValue(cid, 21100, 1)
          setPlayerStorageValue(cid, 21101, attacker)
          setPlayerStorageValue(cid, 21103, getTableMove(attacker, getPlayerStorageValue(attacker, 21102)).f)
          setPlayerStorageValue(cid, 21104, getCreatureOutfit(attacker).lookType)
          return false
       end
    end
    -------------------------------------------------

    local multiplier = 1

       if isCreature(cid) then
          poketype1 = pokes[getCreatureName(cid)].type        
          poketype2 = pokes[getCreatureName(cid)].type2
       end
       if not poketype1 or not poketype2 then return false end  
       
        if getCreatureCondition(cid, CONDITION_INVISIBLE) then
        return false
        end
    if combat == COMBAT_PHYSICALDAMAGE then
        if isGhostPokemon(cid) then               
           if not isInArray(specialabilities["foresight"], getCreatureName(attacker)) then  --passiva Foresight!!
              doSendMagicEffect(getThingPos(cid), 3)     
              return false
           end
        end
            local cd = getPlayerStorageValue(attacker, conds["Miss"])
            local cd2 = getPlayerStorageValue(attacker, conds["Confusion"])
            local cd3 = getPlayerStorageValue(attacker, conds["Stun"])
            if cd >= 0 or cd2 >= 0 or cd3 >= 0 then
               if math.random(1, 100) > 50 then  
                  doSendMagicEffect(getThingPos(cid), 211)
                  doSendAnimatedText(getThingPos(attacker), "MISS", 215)         
                  return false
               end
            end
    end
    --------------------------------------------------
    local valor = value

        if multiplier == 1.5 and poketype2 == "no type" then
            multiplier = 2                                         
        elseif multiplier == 1.5 and poketype2 ~= "no type" then    
            multiplier = 1.75       
        elseif multiplier == 1.25 then    
            multiplier = 1    
        end

    --------------------------------------------------
        if isSummon(cid) and isSummon(attacker) then
            if getCreatureMaster(cid) == getCreatureMaster(attacker) then
               return false
            end
            if canAttackOther(cid, attacker) == "Cant" then
               return false
            end
        end

        valor = valor * multiplier

        if isSummon(attacker) then
            valor = valor * getHappinessRate(attacker)
        else
            valor = valor
        end
                                                                  
        valor = math.floor(valor)                                 
        
        if combat == COMBAT_PHYSICALDAMAGE then
           
           local value = getOffense(attacker) > 1000 and 3 or 2
           block = 1 - (getDefense(cid) / (getOffense(attacker) + getDefense(cid))) --alterado v1.9 testem essa nova formula plzzz '--'
            valor = (getOffense(attacker)/value) * block
           
            if valor <= 0 then
              valor = math.random(5, 10) --alterado v1.9
           end
           
           if isInArray(specialabilities["counter"], getCreatureName(cid)) then
              if math.random(1, 100) <= 10 then
                 doCreatureAddHealth(attacker, -valor, 3, 180)    
                 valor = 0
                 doSendAnimatedText(getThingPosWithDebug(cid), "COUNTER", 215)
              end
           end      
        else
           valor = valor / getDefense(cid)
        end
        
        -------------------------Edited CLAN SYSTEM-----------------------------------
        if isSummon(attacker) and getPlayerStorageValue(getCreatureMaster(attacker), 86228) >= 1 then
           valor = valor*getClanPorcent(getCreatureMaster(attacker), combat, "atk")                           
        elseif isSummon(cid) and getPlayerStorageValue(getCreatureMaster(cid), 86228) >= 1 then
           valor = valor - (valor*getClanPorcent(getCreatureMaster(cid), combat, "def", pokes[getCreatureName(cid)].type, pokes[getCreatureName(cid)].type2))
        end
        -----------------------------------------------------------------------
        ---------------------- FEAR / ROAR ------------------------------------
        if getPlayerStorageValue(attacker, conds["Fear"]) >= 1 then         
        return true
        end
    --------------------------------------------------------------------------
    if damageCombat == GROUNDDAMAGE then
       if isInArray(specialabilities["levitate"], getCreatureName(cid)) then
          valor = 0                      
       end
    end
    -----------------------------------------------------------------------------
    local p = getThingPos(cid)                     
    if p.x == 1 and p.y == 1 and p.z == 10 then
    return false                                    
    end

    if getPlayerStorageValue(cid, 9658783) == 1 then
    return false     --imune
    end
    -----------------------------------------------------------------------------

    --------------- FIGHT MODE -----------------------
    if useOTClient then
    if isSummon(cid) then                                  
       local master = getCreatureMaster(cid)
       if getPlayerStorageValue(master, 248759) == 1 then
          valor = valor * 1.1
       elseif getPlayerStorageValue(master, 248759) == 3 then
          valor = valor * 0.9
       end
    end
    if isSummon(attacker) then
       local master = getCreatureMaster(attacker)
       if getPlayerStorageValue(master, 248759) == 1 then
          valor = valor * 1.1
       elseif getPlayerStorageValue(master, 248759) == 3 then
          valor = valor * 0.9
       end
    end
    end   
    -----------------------------------------------------------------------------
        if valor >= getCreatureHealth(cid) then
            if isInArray(cannotKill, combat) and isPlayer(cid) then
                valor = getCreatureHealth(cid) - 1
            else
                valor = getCreatureHealth(cid)
            end
        end
        valor = math.floor(valor)            
        
    ------------------ SKILLs Q CURAM O ATTACKER ---------------------------------
    local function doHeal(cid, amount)
    if (getCreatureHealth(cid) + amount) >= getCreatureMaxHealth(cid) then
       amount = math.abs(getCreatureHealth(cid)-getCreatureMaxHealth(cid))
    end
    if getCreatureHealth(cid) ~= getCreatureMaxHealth(cid) then           
       doCreatureAddHealth(cid, amount)
       doSendAnimatedText(getThingPosWithDebug(cid), "+"..amount.."", 65)
    end
    end
              
    if damageCombat == PSYCHICDAMAGE or damageCombat == MIRACLEDAMAGE then
       if getPlayerStorageValue(attacker, 95487) >= 1 then
          doHeal(attacker, valor)
          setPlayerStorageValue(attacker, 95487, -1)                  
       end
    elseif damageCombat == SEED_BOMBDAMAGE then
       doHeal(attacker, valor)
    end
    --------------------------------------------
    ----------SACRED FIRE-----------------------
    if combat == SACREDDAMAGE and not ehNPC(cid) then    
       local ret = {}
       ret.id = cid
       ret.cd = 9
       ret.check = getPlayerStorageValue(cid, conds["Silence"])
       ret.eff = 39
       ret.cond = "Silence"

       doCondition2(ret)
    elseif combat == MUDBOMBDAMAGE and not ehNPC(cid) then
       local ret = {}                                        
       ret.id = cid
       ret.cd = 9
       ret.eff = 34
       ret.check = getPlayerStorageValue(cid, conds["Miss"])
       ret.spell = "Mud Bomb"       --alterado v1.9
       ret.cond = "Miss"
       
       doCondition2(ret)
    end
    ---------------------------------------------
    --------------Passiva Lifesteal Clobat------------
    if combat == COMBAT_PHYSICALDAMAGE then
       if getCreatureName(attacker) == "Crobat" then                    
          doCreatureAddHealth(attacker, math.floor(valor))
          doSendAnimatedText(getThingPos(attacker), "+ "..math.floor(valor), 30)
       end
    end
    --------------------------------------------
        valor = math.abs(valor)    --alterado v1.9
        if isSummon(attacker) then
            if combat == COMBAT_PHYSICALDAMAGE then
                doTargetCombatHealth(getCreatureMaster(attacker), cid, PHYSICALDAMAGE, -valor, -valor, 255)
                addEvent(doDoubleHit, 1000, attacker, cid, valor, races)      
            else
                doTargetCombatHealth(getCreatureMaster(attacker), cid, damageCombat, -valor, -valor, 255)
            end
        else
            if combat ~= COMBAT_PHYSICALDAMAGE then
                doCreatureAddHealth(cid, -valor, 3, combats[damageCombat].cor)  
            else
                doCreatureAddHealth(cid, -valor, 3, races[getMonsterInfo(getCreatureName(cid)).race].cor)
                addEvent(doDoubleHit, 1000, attacker, cid, valor, races)   
            end

            if isSummon(cid) and valor ~= 0 then
                addEvent(sendPlayerDmgMsg, 5, getCreatureMaster(cid), "Your "..getCreatureName(cid).." lost "..valor.." hitpoints due to an attack from "..getSomeoneDescription(attacker)..".")
            end

        end
        
        if damageCombat == FIREDAMAGE and not isBurning(cid) then
           local ret = {}
           ret.id = cid
           ret.cd = math.random(5, 12)
           ret.check = getPlayerStorageValue(cid, conds["Burn"])
           ret.damage = isSummon(attacker) and getMasterLevel(attacker)+getPokemonBoost(attacker) or getPokemonLevel(attacker)
           ret.cond = "Burn"
           
           doCondition2(ret)
        elseif damageCombat == POISONDAMAGE and not isPoisoned(cid) then
           local ret = {}
           ret.id = cid
           ret.cd = math.random(6, 15)
           ret.check = getPlayerStorageValue(cid, conds["Poison"])
           local lvl = isSummon(attacker) and getMasterLevel(attacker) or getPokemonLevel(attacker)
           ret.damage = math.floor((getPokemonLevel(attacker)+lvl)/2)
           ret.cond = "Poison"
           
           doCondition2(ret)
        end
    --[[---------------CD BAR-----------------------
    if isSummon(cid) then
       doCreatureExecuteTalkAction(getCreatureMaster(cid), "/pokeread")
    end  ]]
    ------------------------------------POTIONS-------------------------------------------
    if isSummon(cid) and type == STATSCHANGE_HEALTHLOSS then
       if getPlayerStorageValue(cid, 173) >= 1 then
          if damageCombat ~= BURNEDDAMAGE and damageCombat ~= POISONEDDAMAGE then
             setPlayerStorageValue(cid, 173, -1)  
             doSendAnimatedText(getThingPos(cid), "Lost Heal", 144)
          end
       end
    end
    ----------------------------------------PASSIVAS-------------------------------------  
    -------------------------------------------Counter Helix------------------------------------
    if passivesChances["Helix"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Helix"][getCreatureName(cid)] then
       docastspell(cid, "Counter Helix")
    end
    -------------------------------------------Lava Counter/Electricity----------------------------
    if passivesChances["Fire_Thunder"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Fire_Thunder"][getCreatureName(cid)] then
       docastspell(cid, "Lava-Electricity")
    end
    ---------------------------------------Stunning Confusion-----------------------------------------
    if passivesChances["Stunning"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Stunning"][getCreatureName(cid)] then  
       docastspell(cid, "Stunning Confusion")
    end
    -----------------------------------------Groundshock-----------------------------------
    if passivesChances["Groundshock"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Groundshock"][getCreatureName(cid)] then
       docastspell(cid, "Groundshock")
    end
    --------------------------------------Electric Charge---------------------------------------------
    if passivesChances["Electric Charge"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Electric Charge"][getCreatureName(cid)] then
       docastspell(cid, "Electric Charge", 0, 0)
    end
    -------------------------------------Melody------------------------------------
    if passivesChances["Melody"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Melody"][getCreatureName(cid)] then
       docastspell(cid, "Melody")
    end
    ------------------------------------- Dragon Fury / Fury ---------------------------------------
    if passivesChances["Dragon Fury"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Dragon Fury"][getCreatureName(cid)] then
       docastspell(cid, "Dragon Fury", 0, 0)
    end
    ------------------------------------- Mega Drain ---------------------------------------
    if passivesChances["Mega Drain"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Mega Drain"][getCreatureName(cid)] then
       docastspell(cid, "Mega Drain")
    end
    ------------------------------------- Spores Reaction ---------------------------------------
    if passivesChances["Spores Reaction"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Spores Reaction"][getCreatureName(cid)] then
       docastspell(cid, "Spores Reaction")
    end
    ------------------------------------ Amnesia ----------------------------------------   
    if passivesChances["Amnesia"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Amnesia"][getCreatureName(cid)] then
       docastspell(cid, "Amnesia", 0, 0)
    end
    ----------------------------------- Zen Mind -----------------------------------------
    if passivesChances["Zen Mind"][getCreatureName(cid)] and isWithCondition(cid) and math.random(1, 100) <= passivesChances["Zen Mind"][getCreatureName(cid)] then
       docastspell(cid, "Zen Mind", 0, 0)
    end
    ---------------------------------- Mirror Coat ---------------------------------------
    if passivesChances["Mirror Coat"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Mirror Coat"][getCreatureName(cid)] then   
       docastspell(cid, "Mirror Coat", 0, 0)
    end
    --------------------------------- Illusion -----------------------------------------
    return false
    end

     

     

    Acho que foi

  11. Olá Pessoal do Xtibia

     

    Estou Com um erro, toda vez que um player ataca um pokemon selvagem aparece uns erros

    ERRO:

     

    [18/02/2019 20:09:53] [Error - CreatureScript Interface] 
    [18/02/2019 20:09:53] datapack/creaturescripts/scripts/exp2.0.lua:onStatsChange
    [18/02/2019 20:09:53] Description: 
    [18/02/2019 20:09:53] datapack/creaturescripts/scripts/exp2.0.lua:360: attempt to index field '?' (a nil value)
    [18/02/2019 20:09:53] stack traceback:
    [18/02/2019 20:09:53]     datapack/creaturescripts/scripts/exp2.0.lua:360: in function <datapack/creaturescripts/scripts/exp2.0.lua:63>

    [18/02/2019 20:09:54] [Error - CreatureScript Interface] 
    [18/02/2019 20:09:54] datapack/creaturescripts/scripts/exp2.0.lua:onStatsChange
    [18/02/2019 20:09:54] Description: 
    [18/02/2019 20:09:54] datapack/creaturescripts/scripts/exp2.0.lua:360: attempt to index field '?' (a nil value)
    [18/02/2019 20:09:54] stack traceback:
    [18/02/2019 20:09:54]     datapack/creaturescripts/scripts/exp2.0.lua:360: in function <datapack/creaturescripts/scripts/exp2.0.lua:63>




    Meu Exp2.0.lua:

     

    Citar

    local combats = {                        
    [PSYCHICDAMAGE] = {cor = COLOR_PSYCHIC},
    [GRASSDAMAGE] = {cor = COLOR_GRASS},
    [POISONEDDAMAGE] = {cor = COLOR_GRASS},
    [FIREDAMAGE] = {cor = COLOR_FIRE2},                         
    [BURNEDDAMAGE] = {cor = COLOR_BURN},
    [WATERDAMAGE] = {cor = COLOR_WATER},
    [ICEDAMAGE] = {cor = COLOR_ICE},
    [NORMALDAMAGE] = {cor = COLOR_NORMAL},
    [FLYDAMAGE] = {cor = COLOR_FLYING},           
    [GHOSTDAMAGE] = {cor = COLOR_GHOST},
    [GROUNDDAMAGE] = {cor = COLOR_GROUND},
    [ELECTRICDAMAGE] = {cor = COLOR_ELECTRIC},
    [ROCKDAMAGE] = {cor = COLOR_ROCK},
    [BUGDAMAGE] = {cor = COLOR_BUG},
    [FIGHTDAMAGE] = {cor = COLOR_FIGHTING},
    [DRAGONDAMAGE] = {cor = COLOR_DRAGON},
    [POISONDAMAGE] = {cor = COLOR_POISON},
    [DARKDAMAGE] = {cor = COLOR_DARK},               
    [STEELDAMAGE] = {cor = COLOR_STEEL},
    [MIRACLEDAMAGE] = {cor = COLOR_PSYCHIC},  
    [DARK_EYEDAMAGE] = {cor = COLOR_GHOST},
    [SEED_BOMBDAMAGE] = {cor = COLOR_GRASS},
    [SACREDDAMAGE] = {cor = COLOR_FIRE2}, 
    [MUDBOMBDAMAGE] = {cor = COLOR_GROUND}, --alterado v1.9
    }

    local function sendPlayerDmgMsg(cid, text)
        if not isCreature(cid) then return true end
        doPlayerSendTextMessage(cid, MESSAGE_STATUS_DEFAULT, text)
    end

    local races = {
    [4] = {cor = COLOR_FIRE2},
    [6] = {cor = COLOR_WATER},
    [7] = {cor = COLOR_NORMAL},
    [8] = {cor = COLOR_FIRE2},
    [9] = {cor = COLOR_FIGHTING},
    [10] = {cor = COLOR_FLYING},
    [11] = {cor = COLOR_GRASS},
    [12] = {cor = COLOR_POISON},
    [13] = {cor = COLOR_ELECTRIC},
    [14] = {cor = COLOR_GROUND},
    [15] = {cor = COLOR_PSYCHIC},
    [16] = {cor = COLOR_ROCK},
    [17] = {cor = COLOR_ICE},
    [18] = {cor = COLOR_BUG},
    [19] = {cor = COLOR_DRAGON},
    [20] = {cor = COLOR_GHOST},
    [21] = {cor = COLOR_STEEL},
    [22] = {cor = COLOR_DARK},
    [1] = {cor = 180},
    [2] = {cor = 180},
    [3] = {cor = 180},
    [5] = {cor = 180},
    }

    local damages = {GROUNDDAMAGE, ELECTRICDAMAGE, ROCKDAMAGE, FLYDAMAGE, BUGDAMAGE, FIGHTINGDAMAGE, DRAGONDAMAGE, POISONDAMAGE, DARKDAMAGE, STEELDAMAGE}
    local fixdmgs = {PSYCHICDAMAGE, COMBAT_PHYSICALDAMAGE, GRASSDAMAGE, FIREDAMAGE, WATERDAMAGE, ICEDAMAGE, NORMALDAMAGE, GHOSTDAMAGE}
    local ignored = {POISONEDDAMAGE, BURNEDDAMAGE}                
    local cannotkill = {BURNEDDAMAGE, POISONEDDAMAGE}

    function onStatsChange(cid, attacker, type, combat, value)

    if combat == FLYSYSTEMDAMAGE then return false end
    if isPlayer(cid) and getCreatureOutfit(cid).lookType == 814 then return false end -- TV

    if not isCreature(attacker) then  
        if not isInArray(fixdamages, combat) and combats[combat] then
            doSendAnimatedText(getThingPos(cid), value, combats[combat].cor)
        end
    return true
    end

    local damageCombat = combat
    --------------------------------------------------
    if type == STATSCHANGE_HEALTHGAIN then
        if cid == attacker then
        return true
        end
        if isSummon(cid) and isSummon(attacker) and canAttackOther(cid, attacker) == "Cant" then
        return false
        end
    return true
    end
    --------------------------------------------------
    if isMonster(cid) then
    local valor = value
       if not pokes[getCreatureName(cid)] and damageCombat == COMBAT_PHYSICALDAMAGE then
          valor = getOffense(attacker)
          doCreatureAddHealth(cid, -math.abs(valor), 3, races[7].cor)                       
          return false
       elseif not pokes[getCreatureName(cid)] and damageCombat ~= COMBAT_PHYSICALDAMAGE then
          doCreatureAddHealth(cid, -math.abs(valor), 3, combats[damageCombat].cor)
          return false
       end
    end
    --------------------------------------------------
    if isPlayer(attacker) then

        local valor = value
        if valor > getCreatureHealth(cid) then
            valor = getCreatureHealth(cid)
        end

        if combat == COMBAT_PHYSICALDAMAGE then
        return false
        end

        if combat == PHYSICALDAMAGE then
        doSendMagicEffect(getThingPos(cid), 3)
        doSendAnimatedText(getThingPos(cid), valor, races[getMonsterInfo(getCreatureName(cid)).race].cor)
        end

        if combats[damageCombat] and not isInArray(fixdmgs, damageCombat) then
        doSendAnimatedText(getThingPos(cid), valor, combats[damageCombat].cor)
        end

        if #getCreatureSummons(attacker) >= 1 and not isInArray({POISONEDDAMAGE, BURNEDDAMAGE}, combat) then
            doPlayerSendTextMessage(attacker, MESSAGE_STATUS_DEFAULT, "Your "..getPokeName(getCreatureSummons(attacker)[1]).." dealt "..valor.." damage to "..getSomeoneDescription(cid)..".")
        end

    return true
    end
    --------------------------------------------------
    if isPlayer(cid) and #getCreatureSummons(cid) >= 1 and type == STATSCHANGE_HEALTHLOSS then
    return false                                                                           
    end
    --------------------------------------------------
    if isPlayer(cid) and #getCreatureSummons(cid) <= 0 and type == STATSCHANGE_HEALTHLOSS then

    if isSummon(attacker) or isPlayer(attacker) then
       if canAttackOther(cid, attacker) == "Cant" then return false end
    end

        local valor = 0
            if combat == COMBAT_PHYSICALDAMAGE then
                valor = getOffense(attacker)
            else
                valor = getSpecialAttack(attacker)
            end

        valor = valor * playerDamageReduction
        valor = valor * math.random(83, 117) / 100

        if valor >= getCreatureHealth(cid) then
            valor = getCreatureHealth(cid)
        end

        valor = math.floor(valor)

        if valor >= getCreatureHealth(cid) then
           if getPlayerStorageValue(cid, 6598754) >= 1 or getPlayerStorageValue(cid, 6598755) >= 1 then
              setPlayerStorageValue(cid, 6598754, -1)
              setPlayerStorageValue(cid, 6598755, -1)
              doRemoveCondition(cid, CONDITION_OUTFIT)             
              doTeleportThing(cid, posBackPVP, false)
              doCreatureAddHealth(cid, getCreatureMaxHealth(cid))
              return false --alterado v1.8
           end
           
           if getPlayerStorageValue(cid, 17001) >= 1 or getPlayerStorageValue(cid, 17000) >= 1 or getPlayerStorageValue(cid, 63215) >= 1 then
              doRemoveCondition(cid, CONDITION_OUTFIT)
              setPlayerStorageValue(cid, 17000, 0)
              setPlayerStorageValue(cid, 17001, 0)
              setPlayerStorageValue(cid, 63215, -1) 
              doChangeSpeed(cid, PlayerSpeed)
              local item = getPlayerSlotItem(cid, ?
              local btype = getPokeballType(item.itemid)
              if #getCreatureSummons(cid) <= 0 then
                   if isInArray(pokeballs[btype].all, item.itemid) then
                       doTransformItem(item.uid, pokeballs[btype].off)
                       doItemSetAttribute(item.uid, "hp", 0)
                 end
              end
           end

           if getPlayerStorageValue(cid, 22545) == 1 then
              if getGlobalStorageValue(22550) == 1 then
                 doPlayerSendTextMessage(cid, 20, "You are the last survivor of the golden arena! Take your reward!")
                 doPlayerAddItem(cid, 2152, getPlayerStorageValue(cid, 22551)*2)  
                 setPlayerStorageValue(cid, 22545, -1)
                 doTeleportThing(cid, getClosestFreeTile(cid, getClosestFreeTile(cid, posBackGolden)), false)  
                 doCreatureAddHealth(cid, getCreatureMaxHealth(cid)-getCreatureHealth(cid))
                 setPlayerRecordWaves(cid)     
                 endGoldenArena()
                 return false --alterado v1.8           
              else
                 setGlobalStorageValue(22550, getGlobalStorageValue(22550)-1)
                 setPlayerStorageValue(cid, 22545, -1)
                 doTeleportThing(cid, getClosestFreeTile(cid, posBackGolden), false)    
                 doCreatureAddHealth(cid, getCreatureMaxHealth(cid)-getCreatureHealth(cid))
                 setPlayerRecordWaves(cid)     
                 return true
              end 
           end

           if getPlayerStorageValue(cid, 98796) >= 1 then
              setPlayerStorageValue(cid, 98796, -1) 
              setPlayerStorageValue(cid, 98797, -1)                      --alterado v1.8
              doTeleportThing(cid, SafariOut, false)
              doSendMagicEffect(getThingPos(cid), 21)
              doPlayerSendTextMessage(cid, 27, "You die in the saffari... Best luck in the next time!")
              return false --alterado v1.8
           end

           local corpse = doCreateItem(3058, 1, getThingPos(cid))
           doDecayItem(corpse)
           doItemSetAttribute(corpse, "pName", getCreatureName(cid))          --alterado v1.7 coloca corpse quando o player morre!
           doItemSetAttribute(corpse, "attacker", getCreatureName(attacker))
           doItemSetAttribute(corpse, "article", getPlayerSex(cid) == 0 and "She" or "He")
           
           if getPlayerStorageValue(cid, Agatha.stoIni) >= 1 and getPlayerStorageValue(cid, Agatha.stoIni) <= 10 then
              setPlayerStorageValue(cid, Agatha.stoIni, -1)
              setPlayerStorageValue(cid, Agatha.stoRec, -1)
              setPlayerStorageValue(cid, Agatha.stoPer, -1)
              setPlayerStorageValue(cid, Agatha.stoEni, -1)        --alterado v1.9  agatha quest
              setPlayerStorageValue(cid, Agatha.stoRes, -1)
           end 
        end
        doCreatureAddHealth(cid, -valor, 3, 180)
        if not isPlayer(cid) then
           addEvent(sendPlayerDmgMsg, 5, cid, "You lost "..valor.." hitpoints due to an attack from "..getSomeoneDescription(attacker)..".")
        end
    return false
    end
    --------------------------------------------------
    if isMonster(attacker) and getPlayerStorageValue(attacker, 201) ~= -1 then
        if isPlayer(cid) then
        return false
        end
        if getPlayerStorageValue(getCreatureMaster(cid), ginasios[getPlayerStorageValue(attacker, 201)].storage) ~= 1 then
        return false
        end
    end
    --------------------------------------------------
    if isMonster(cid) and getPlayerStorageValue(cid, 201) ~= -1 then
        if getPlayerStorageValue(getCreatureMaster(attacker), ginasios[getPlayerStorageValue(cid, 201)].storage) ~= 1 then
        return false
        end
    end
    --------------------------------------------------
    if ehMonstro(cid) and ehMonstro(attacker) and not isSummon(cid) and not isSummon(attacker) then 
    return false                                          --alterado v1.9 /\
    end
    --------------------------------------------------
    --------------------REFLECT-----------------------
    if getPlayerStorageValue(cid, 21099) >= 1 and combat ~= COMBAT_PHYSICALDAMAGE then
       if not isInArray({"Team Claw", "Team Slice"}, getPlayerStorageValue(attacker, 21102)) then
          doSendMagicEffect(getThingPosWithDebug(cid), 135)
          doSendAnimatedText(getThingPosWithDebug(cid), "REFLECT", COLOR_GRASS)
          addEvent(docastspell, 100, cid, getPlayerStorageValue(attacker, 21102))
          if getCreatureName(cid) == "Wobbuffet" then
             doRemoveCondition(cid, CONDITION_OUTFIT)    
          end
          setPlayerStorageValue(cid, 21099, -1)                    
          setPlayerStorageValue(cid, 21100, 1)
          setPlayerStorageValue(cid, 21101, attacker)
          setPlayerStorageValue(cid, 21103, getTableMove(attacker, getPlayerStorageValue(attacker, 21102)).f)
          setPlayerStorageValue(cid, 21104, getCreatureOutfit(attacker).lookType)
          return false
       end
    end
    -------------------------------------------------

    local multiplier = 1

       if isCreature(cid) then
          poketype1 = pokes[getCreatureName(cid)].type        
          poketype2 = pokes[getCreatureName(cid)].type2
       end
       if not poketype1 or not poketype2 then return false end  
       
        if getCreatureCondition(cid, CONDITION_INVISIBLE) then
        return false
        end
    if combat == COMBAT_PHYSICALDAMAGE then
        if isGhostPokemon(cid) then               
           if not isInArray(specialabilities["foresight"], getCreatureName(attacker)) then  --passiva Foresight!!
              doSendMagicEffect(getThingPos(cid), 3)     
              return false
           end
        end
            local cd = getPlayerStorageValue(attacker, conds["Miss"])
            local cd2 = getPlayerStorageValue(attacker, conds["Confusion"]) 
            local cd3 = getPlayerStorageValue(attacker, conds["Stun"]) 
            if cd >= 0 or cd2 >= 0 or cd3 >= 0 then
               if math.random(1, 100) > 50 then  
                  doSendMagicEffect(getThingPos(cid), 211)
                  doSendAnimatedText(getThingPos(attacker), "MISS", 215)         
                  return false
               end
            end
    end
    --------------------------------------------------
    local valor = value

        if multiplier == 1.5 and poketype2 == "no type" then
            multiplier = 2                                         
        elseif multiplier == 1.5 and poketype2 ~= "no type" then    
            multiplier = 1.75       
        elseif multiplier == 1.25 then    
            multiplier = 1    
        end

    --------------------------------------------------
        if isSummon(cid) and isSummon(attacker) then
            if getCreatureMaster(cid) == getCreatureMaster(attacker) then
               return false
            end
            if canAttackOther(cid, attacker) == "Cant" then
               return false
            end
        end

        valor = valor * multiplier

        if isSummon(attacker) then
            valor = valor * getHappinessRate(attacker)
        else
            valor = valor
        end
                                                                  
        valor = math.floor(valor)                                 
        
        if combat == COMBAT_PHYSICALDAMAGE then
           
           local value = getOffense(attacker) > 1000 and 3 or 2
           block = 1 - (getDefense(cid) / (getOffense(attacker) + getDefense(cid))) --alterado v1.9 testem essa nova formula plzzz '--'
            valor = (getOffense(attacker)/value) * block
           
            if valor <= 0 then
              valor = math.random(5, 10) --alterado v1.9
           end
           
           if isInArray(specialabilities["counter"], getCreatureName(cid)) then
              if math.random(1, 100) <= 10 then
                 doCreatureAddHealth(attacker, -valor, 3, 180)    
                 valor = 0
                 doSendAnimatedText(getThingPosWithDebug(cid), "COUNTER", 215)
              end
           end      
        else
           valor = valor / getDefense(cid)
        end
        
        -------------------------Edited CLAN SYSTEM-----------------------------------
        if isSummon(attacker) and getPlayerStorageValue(getCreatureMaster(attacker), 86228) >= 1 then
           valor = valor*getClanPorcent(getCreatureMaster(attacker), combat, "atk")                           
        elseif isSummon(cid) and getPlayerStorageValue(getCreatureMaster(cid), 86228) >= 1 then
           valor = valor - (valor*getClanPorcent(getCreatureMaster(cid), combat, "def", pokes[getCreatureName(cid)].type, pokes[getCreatureName(cid)].type2))
        end
        -----------------------------------------------------------------------
        ---------------------- FEAR / ROAR ------------------------------------
        if getPlayerStorageValue(attacker, conds["Fear"]) >= 1 then         
        return true
        end
    --------------------------------------------------------------------------
    if damageCombat ~= COMBAT_PHYSICALDAMAGE and not isInArray(ignored, damageCombat) then
       if isInArray(effectiveness[damageCombat].non, poketype1) or isInArray(effectiveness[damageCombat].non, poketype2) then
          if not isInArray(specialabilities["foresight"], getCreatureName(attacker)) then     
             valor = valor * 0                      
          end
       end
    end

    if damageCombat == GROUNDDAMAGE then
       if isInArray(specialabilities["levitate"], getCreatureName(cid)) then
          valor = 0                      
       end
    end
    -----------------------------------------------------------------------------
    local p = getThingPos(cid)                     
    if p.x == 1 and p.y == 1 and p.z == 10 then
    return false                                    
    end

    if getPlayerStorageValue(cid, 9658783) == 1 then
    return false     --imune
    end
    -----------------------------------------------------------------------------

    --------------- FIGHT MODE -----------------------
    if useOTClient then
    if isSummon(cid) then                                  
       local master = getCreatureMaster(cid)
       if getPlayerStorageValue(master, 248759) == 1 then
          valor = valor * 1.1
       elseif getPlayerStorageValue(master, 248759) == 3 then
          valor = valor * 0.9
       end
    end
    if isSummon(attacker) then
       local master = getCreatureMaster(attacker)
       if getPlayerStorageValue(master, 248759) == 1 then
          valor = valor * 1.1
       elseif getPlayerStorageValue(master, 248759) == 3 then
          valor = valor * 0.9
       end
    end 
    end   
    -----------------------------------------------------------------------------
        if valor >= getCreatureHealth(cid) then
            if isInArray(cannotKill, combat) and isPlayer(cid) then
                valor = getCreatureHealth(cid) - 1
            else
                valor = getCreatureHealth(cid)
            end
        end
        valor = math.floor(valor)            
        
    ------------------ SKILLs Q CURAM O ATTACKER ---------------------------------
    local function doHeal(cid, amount)
    if (getCreatureHealth(cid) + amount) >= getCreatureMaxHealth(cid) then
       amount = math.abs(getCreatureHealth(cid)-getCreatureMaxHealth(cid))
    end
    if getCreatureHealth(cid) ~= getCreatureMaxHealth(cid) then           
       doCreatureAddHealth(cid, amount)
       doSendAnimatedText(getThingPosWithDebug(cid), "+"..amount.."", 65) 
    end
    end
              
    if damageCombat == PSYCHICDAMAGE or damageCombat == MIRACLEDAMAGE then
       if getPlayerStorageValue(attacker, 95487) >= 1 then
          doHeal(attacker, valor)
          setPlayerStorageValue(attacker, 95487, -1)                  
       end
    elseif damageCombat == SEED_BOMBDAMAGE then
       doHeal(attacker, valor)
    end
    --------------------------------------------
    ----------SACRED FIRE-----------------------
    if combat == SACREDDAMAGE and not ehNPC(cid) then    
       local ret = {}
       ret.id = cid
       ret.cd = 9
       ret.check = getPlayerStorageValue(cid, conds["Silence"])
       ret.eff = 39
       ret.cond = "Silence"

       doCondition2(ret)
    elseif combat == MUDBOMBDAMAGE and not ehNPC(cid) then
       local ret = {}                                        
       ret.id = cid
       ret.cd = 9
       ret.eff = 34
       ret.check = getPlayerStorageValue(cid, conds["Miss"])
       ret.spell = "Mud Bomb"       --alterado v1.9
       ret.cond = "Miss"
       
       doCondition2(ret)
    end
    ---------------------------------------------
    --------------Passiva Lifesteal Clobat------------
    if combat == COMBAT_PHYSICALDAMAGE then
       if getCreatureName(attacker) == "Crobat" then                    
          doCreatureAddHealth(attacker, math.floor(valor))
          doSendAnimatedText(getThingPos(attacker), "+ "..math.floor(valor), 30)
       end
    end
    --------------------------------------------
        valor = math.abs(valor)    --alterado v1.9
        if isSummon(attacker) then
            if combat == COMBAT_PHYSICALDAMAGE then
                doTargetCombatHealth(getCreatureMaster(attacker), cid, PHYSICALDAMAGE, -valor, -valor, 255)
                addEvent(doDoubleHit, 1000, attacker, cid, valor, races)      
            else
                doTargetCombatHealth(getCreatureMaster(attacker), cid, damageCombat, -valor, -valor, 255)
            end
        else
            if combat ~= COMBAT_PHYSICALDAMAGE then
                doCreatureAddHealth(cid, -valor, 3, combats[damageCombat].cor)  
            else
                doCreatureAddHealth(cid, -valor, 3, races[getMonsterInfo(getCreatureName(cid)).race].cor)
                addEvent(doDoubleHit, 1000, attacker, cid, valor, races)   
            end

            if isSummon(cid) and valor ~= 0 then
                addEvent(sendPlayerDmgMsg, 5, getCreatureMaster(cid), "Your "..getCreatureName(cid).." lost "..valor.." hitpoints due to an attack from "..getSomeoneDescription(attacker)..".")
            end

        end
        
        if damageCombat == FIREDAMAGE and not isBurning(cid) then
           local ret = {}
           ret.id = cid
           ret.cd = math.random(5, 12)
           ret.check = getPlayerStorageValue(cid, conds["Burn"])
           ret.damage = isSummon(attacker) and getMasterLevel(attacker)+getPokemonBoost(attacker) or getPokemonLevel(attacker)
           ret.cond = "Burn"
           
           doCondition2(ret)
        elseif damageCombat == POISONDAMAGE and not isPoisoned(cid) then
           local ret = {}
           ret.id = cid
           ret.cd = math.random(6, 15)
           ret.check = getPlayerStorageValue(cid, conds["Poison"])
           local lvl = isSummon(attacker) and getMasterLevel(attacker) or getPokemonLevel(attacker)
           ret.damage = math.floor((getPokemonLevel(attacker)+lvl)/2)
           ret.cond = "Poison"
           
           doCondition2(ret)
        end
    --[[---------------CD BAR-----------------------
    if isSummon(cid) then
       doCreatureExecuteTalkAction(getCreatureMaster(cid), "/pokeread")
    end  ]]
    ------------------------------------POTIONS-------------------------------------------
    if isSummon(cid) and type == STATSCHANGE_HEALTHLOSS then
       if getPlayerStorageValue(cid, 173) >= 1 then
          if damageCombat ~= BURNEDDAMAGE and damageCombat ~= POISONEDDAMAGE then
             setPlayerStorageValue(cid, 173, -1)  
             doSendAnimatedText(getThingPos(cid), "Lost Heal", 144)
          end
       end
    end
    ----------------------------------------PASSIVAS-------------------------------------  
    -------------------------------------------Counter Helix------------------------------------
    if passivesChances["Helix"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Helix"][getCreatureName(cid)] then
       docastspell(cid, "Counter Helix")
    end
    -------------------------------------------Lava Counter/Electricity----------------------------
    if passivesChances["Fire_Thunder"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Fire_Thunder"][getCreatureName(cid)] then
       docastspell(cid, "Lava-Electricity")
    end
    ---------------------------------------Stunning Confusion-----------------------------------------
    if passivesChances["Stunning"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Stunning"][getCreatureName(cid)] then  
       docastspell(cid, "Stunning Confusion")
    end
    -----------------------------------------Groundshock-----------------------------------
    if passivesChances["Groundshock"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Groundshock"][getCreatureName(cid)] then
       docastspell(cid, "Groundshock")
    end
    --------------------------------------Electric Charge---------------------------------------------
    if passivesChances["Electric Charge"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Electric Charge"][getCreatureName(cid)] then
       docastspell(cid, "Electric Charge", 0, 0)
    end
    -------------------------------------Melody------------------------------------
    if passivesChances["Melody"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Melody"][getCreatureName(cid)] then 
       docastspell(cid, "Melody")
    end
    ------------------------------------- Dragon Fury / Fury ---------------------------------------
    if passivesChances["Dragon Fury"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Dragon Fury"][getCreatureName(cid)] then
       docastspell(cid, "Dragon Fury", 0, 0)
    end
    ------------------------------------- Mega Drain ---------------------------------------
    if passivesChances["Mega Drain"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Mega Drain"][getCreatureName(cid)] then
       docastspell(cid, "Mega Drain")
    end
    ------------------------------------- Spores Reaction ---------------------------------------
    if passivesChances["Spores Reaction"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Spores Reaction"][getCreatureName(cid)] then
       docastspell(cid, "Spores Reaction")
    end
    ------------------------------------ Amnesia ----------------------------------------   
    if passivesChances["Amnesia"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Amnesia"][getCreatureName(cid)] then 
       docastspell(cid, "Amnesia", 0, 0)
    end
    ----------------------------------- Zen Mind -----------------------------------------
    if passivesChances["Zen Mind"][getCreatureName(cid)] and isWithCondition(cid) and math.random(1, 100) <= passivesChances["Zen Mind"][getCreatureName(cid)] then
       docastspell(cid, "Zen Mind", 0, 0)
    end
    ---------------------------------- Mirror Coat ---------------------------------------
    if passivesChances["Mirror Coat"][getCreatureName(cid)] and math.random(1, 100) <= passivesChances["Mirror Coat"][getCreatureName(cid)] then   
       docastspell(cid, "Mirror Coat", 0, 0)
    end
    --------------------------------- Illusion -----------------------------------------
    return false
    end





    ❤️ Quem Poder Ajudar Agradeço ❤️ 

    By Vini

  12. 23 minutos atrás, Yan Liima disse:

    Em talkactions crie um arquivo chamado doubleexp.lua, cole isto:

    
    function onSay(cid, words, param, channel)
    local config = {
    storage = 102590,
    }
    if(param == 'cancel') or (param == 'cancelar') then
    if getGlobalStorageValue(config.storage) > 0 then
    setGlobalStorageValue(config.storage, -1)
    doBroadcastMessage("Double Exp cancelado")
    end
    return true
    end
    	
    param = tonumber(param)
    if(not param or param < 0) then
    doPlayerSendCancel(cid, "Digite por quantas horas o evento ira durar")
    return true
    end
    if getGlobalStorageValue(config.storage) - os.time() <= 0 then
    setGlobalStorageValue(config.storage, os.time()+param*60*60)
    doBroadcastMessage("Exp bonus ativado + 20% de EXP por "..param.." hora(s)! Aproveite.")
    end
    return true
    end

    TAG:

    
    <talkaction words="/doubleexp" access="5" event="script" value="doubleexp.lua"/>

    AwkUqYB.png

    Depois em creaturescript crie um arquivo chamado doubleexp.lua, cole isto:

    
    function onKill(cid, target)
    if isPlayer(cid) and isMonster(target) then
    if getGlobalStorageValue(102590) - os.time() >= 1 then
    local exp = getExperienceStage(getPlayerLevel(cid), getVocationInfo(getPlayerVocation(cid)).experienceMultiplier)
    local count = ((getMonsterInfo(string.lower(getCreatureName(target))).experience*1.2*exp)/2)
    doPlayerAddExperience(cid, count)
    addEvent(doSendAnimatedText, 500, getCreaturePosition(cid), '+'..count, math.random(50,60))
    doPlayerSendTextMessage(cid, MESSAGE_EVENT_ORANGE, "[DOUBLE XP] Você ganhou 20% a mais de exp.")
    end
    else
    return true
    end
    return true
    end

    TAG:

    
    <event type="kill" name="ExpBonus" event="script" value="doubleexp.lua"/>

    em login.lua coloque isso:

    
    registerCreatureEvent(cid, "ExpBonus")

    A modificação da porcentagem é na script do creaturescript. 1.2 = 20% de double. Edite da meneira que desejar.

     

     

    Deu esse erro

     

     

    [14/02/2019 18:35:28] [Error - LuaScriptInterface::loadFile] datapack/talkactions/scripts/exp.lua:23: unexpected symbol near 'ï'
    [14/02/2019 18:35:28] [Warning - Event::loadScript] Cannot load script (datapack/talkactions/scripts/exp.lua)
    [14/02/2019 18:35:28] datapack/talkactions/scripts/exp.lua:23: unexpected symbol near 'ï'

    @Marshmello  Blz

  13. 5 minutos atrás, Yan Liima disse:

    O evento seria ativado pelo Administrador do servidor ou seria ativado automaticamente por X dia configurado?

     

    1 minuto atrás, Marshmello disse:

    Me de umas Infos,

     

    O evento ativar automaticamente ou ativo por algum comando administrativo?

     

    Ativo por administrador 

     

  14. Ola Pessoal Do xtibia

     

    Eu gostaria de uma Script de EVENTO double xp, que quando o player matasse um pokemon quando o evento estivesse ativo, Aparecesse uma mensagen no "registro do servidor" falando que ele ganhou uma quantia de xp a mais por causa do evento XP


    Quem Poder ajudar agradeço de coração 

     

     

    By Vini

  15. 18 horas atrás, Kuro o Shiniga disse:

    Eu consegui desenvolver um, porem você vai ter que adicionar esse script nos sqm que fica em volta do teleport que leva o player para a posição X, esse script vai salvar a posição do player antes dele entrar no teleport :

     

    
    
    function onStepIn(cid, item, position, fromPosition)
    setPlayerStorageValue(cid, 27278, getThingPosition(cid).x)
    setPlayerStorageValue(cid, 27279, getThingPosition(cid).y)
    setPlayerStorageValue(cid, 27280, getThingPosition(cid).z)
    doSendMagicEffect(getThingPos(cid), 12)
    end
    
    
    
    
    <movevent type="StepIn" actionid="1424" event="script" value="nomedoarquivo.lua"/>

     

    Depois você usa esse script como teleporte de saida do local que o player foi enviado :

     

    
    function onStepIn(cid, item, position, fromPosition)
    
    local pose = {x=getPlayerStorageValue(cid, 27278), y=getPlayerStorageValue(cid, 27279), z=getPlayerStorageValue(cid, 27280)}
    	
    
    doSendMagicEffect(getThingPos(cid), 10)
    doTeleportThing(cid, pose)
    
    
    return false
    end
    
    <movevent type="StepIn" actionid="1423" event="script" value="nomedoarquivo.lua"/>

    Foi o único jeito que consegui pensar para desenvolver esse sistema, funciona da maneira que você deseja, porem vai ter que colocar o primeiro script ne todos os SQM que cerca o teleporte que envia o jogador para a POSIÇÃO X.

    Poderia me Guiar??

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...