Ir para conteúdo

Featured Replies

Postado
Agora, poko360 disse:

@WooX me ajuda plos =/

 

Vou ajudar, to ocupado pra mexer com isso agora, mas vou fazer pra você.

 

 

 

Nós somos aquilo que fazemos repetidamente. Excelência, não é um modo de agir, mas um hábito.

                                                                                                                                                                                                                                        Aristóteles 

  • Respostas 15
  • Visualizações 3.4k
  • Created
  • Última resposta

Top Posters In This Topic

Most Popular Posts

  • Da pra fazer um script mas o correto é alterar a sources. Se mesmo sabendo disso você quiser o script avisa que faço.

  • Volta seu combat.cpp para o original pro dano voltar a pegar. Pra não pegar target nos summons faz essa alteração.   Em monster.cpp onde está: bool Monster::isTarget(Creature* creature)

Postado

Agora to com tempo pra fazer, me envia seu combat.cpp

 

 

 

Nós somos aquilo que fazemos repetidamente. Excelência, não é um modo de agir, mas um hábito.

                                                                                                                                                                                                                                        Aristóteles 

Postado
  • Autor

@WooX
 

Spoiler

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "const.h"

#include "combat.h"
#include "tools.h"

#include "game.h"
#include "configmanager.h"

#include "creature.h"
#include "player.h"
#include "weapons.h"

extern Game g_game;
extern Weapons* g_weapons;
extern ConfigManager g_config;

Combat::Combat()
{
    params.valueCallback = NULL;
    params.tileCallback = NULL;
    params.targetCallback = NULL;
    area = NULL;

    formulaType = FORMULA_UNDEFINED;
    mina = minb = maxa = maxb = minl = maxl = minm = maxm = minc = maxc = 0;
}

Combat::~Combat()
{
    for(std::list<const Condition*>::iterator it = params.conditionList.begin(); it != params.conditionList.end(); ++it)
        delete (*it);

    params.conditionList.clear();
    delete area;

    delete params.valueCallback;
    delete params.tileCallback;
    delete params.targetCallback;
}

bool Combat::getMinMaxValues(Creature* creature, Creature* target, int32_t& min, int32_t& max) const
{
    if(creature)
    {
        if(creature->getCombatValues(min, max))
            return true;

        if(Player* player = creature->getPlayer())
        {
            if(params.valueCallback)
            {
                params.valueCallback->getMinMaxValues(player, min, max, params.useCharges);
                return true;
            }

            min = max = 0;
            switch(formulaType)
            {
                case FORMULA_LEVELMAGIC:
                {
                    min = (int32_t)((player->getLevel() / minl + player->getMagicLevel() * minm) * 1. * mina + minb);
                    max = (int32_t)((player->getLevel() / maxl + player->getMagicLevel() * maxm) * 1. * maxa + maxb);
                    if(minc && std::abs(min) < std::abs(minc))
                        min = minc;

                    if(maxc && std::abs(max) < std::abs(maxc))
                        max = maxc;

                    player->increaseCombatValues(min, max, params.useCharges, true);
                    return true;
                }

                case FORMULA_SKILL:
                {
                    Item* item = player->getWeapon(false);
                    if(const Weapon* weapon = g_weapons->getWeapon(item))
                    {
                        max = (int32_t)(weapon->getWeaponDamage(player, target, item, true) * maxa + maxb);
                        if(params.useCharges && item->hasCharges() && g_config.getBool(ConfigManager::REMOVE_WEAPON_CHARGES))
                            g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getCharges()) - 1));
                    }
                    else
                        max = (int32_t)maxb;

                    min = (int32_t)minb;
                    if(maxc && std::abs(max) < std::abs(maxc))
                        max = maxc;

                    return true;
                }

                case FORMULA_VALUE:
                {
                    min = (int32_t)minb;
                    max = (int32_t)maxb;
                    return true;
                }

                default:
                    break;
            }

            return false;
        }
    }

    if(formulaType != FORMULA_VALUE)
        return false;

    min = (int32_t)mina;
    max = (int32_t)maxa;
    return true;
}

void Combat::getCombatArea(const Position& centerPos, const Position& targetPos, const CombatArea* area, std::list<Tile*>& list)
{
    if(area)
        area->getList(centerPos, targetPos, list);
    else if(targetPos.z < MAP_MAX_LAYERS)
    {
        Tile* tile = g_game.getTile(targetPos);
        if(!tile)
        {
            tile = new StaticTile(targetPos.x, targetPos.y, targetPos.z);
            g_game.setTile(tile);
        }

        list.push_back(tile);
    }
}

CombatType_t Combat::ConditionToDamageType(ConditionType_t type)
{
    switch(type)
    {
        case CONDITION_FIRE:
            return COMBAT_FIREDAMAGE;

        case CONDITION_ENERGY:
            return COMBAT_ENERGYDAMAGE;

        case CONDITION_POISON:
            return COMBAT_EARTHDAMAGE;

        case CONDITION_FREEZING:
            return COMBAT_ICEDAMAGE;

        case CONDITION_DAZZLED:
            return COMBAT_HOLYDAMAGE;

        case CONDITION_CURSED:
            return COMBAT_DEATHDAMAGE;

        case CONDITION_DROWN:
            return COMBAT_DROWNDAMAGE;

        case CONDITION_PHYSICAL:
            return COMBAT_PHYSICALDAMAGE;

        default:
            break;
    }

    return COMBAT_NONE;
}

ConditionType_t Combat::DamageToConditionType(CombatType_t type)
{
    switch(type)
    {
        case COMBAT_FIREDAMAGE:
            return CONDITION_FIRE;

        case COMBAT_ENERGYDAMAGE:
            return CONDITION_ENERGY;

        case COMBAT_EARTHDAMAGE:
            return CONDITION_POISON;

        case COMBAT_ICEDAMAGE:
            return CONDITION_FREEZING;

        case COMBAT_HOLYDAMAGE:
            return CONDITION_DAZZLED;

        case COMBAT_DEATHDAMAGE:
            return CONDITION_CURSED;

        case COMBAT_PHYSICALDAMAGE:
            return CONDITION_PHYSICAL;

        default:
            break;
    }

    return CONDITION_NONE;
}

ReturnValue Combat::canDoCombat(const Creature* caster, const Tile* tile, bool isAggressive)
{
    if(tile->hasProperty(BLOCKPROJECTILE) || tile->floorChange() || tile->getTeleportItem())
        return RET_NOTENOUGHROOM;

    if(caster)
    {
        bool success = true;
        CreatureEventList combatAreaEvents = const_cast<Creature*>(caster)->getCreatureEvents(CREATURE_EVENT_COMBAT_AREA);
        for(CreatureEventList::iterator it = combatAreaEvents.begin(); it != combatAreaEvents.end(); ++it)
        {
            if(!(*it)->executeCombatArea(const_cast<Creature*>(caster), const_cast<Tile*>(tile), isAggressive) && success)
                success = false;
        }

        if(!success)
            return RET_NOTPOSSIBLE;

        if(caster->getPosition().z < tile->getPosition().z)
            return RET_FIRSTGODOWNSTAIRS;

        if(caster->getPosition().z > tile->getPosition().z)
            return RET_FIRSTGOUPSTAIRS;

        if(!isAggressive)
            return RET_NOERROR;

        const Player* player = caster->getPlayer();
        if(player && player->hasFlag(PlayerFlag_IgnoreProtectionZone))
            return RET_NOERROR;
    }

    return isAggressive && tile->hasFlag(TILESTATE_PROTECTIONZONE) ?
        RET_ACTIONNOTPERMITTEDINPROTECTIONZONE : RET_NOERROR;
}

ReturnValue Combat::canDoCombat(const Creature* attacker, const Creature* target)
{
    if(!attacker)
        return RET_NOERROR;

    bool success = true;
    CreatureEventList combatEvents = const_cast<Creature*>(attacker)->getCreatureEvents(CREATURE_EVENT_COMBAT);
    for(CreatureEventList::iterator it = combatEvents.begin(); it != combatEvents.end(); ++it)
    {
        if(!(*it)->executeCombat(const_cast<Creature*>(attacker), const_cast<Creature*>(target)) && success)
            success = false;
    }

    if(!success)
        return RET_NOTPOSSIBLE;

    bool checkZones = false;
    if(const Player* targetPlayer = target->getPlayer())
    {
        if(!targetPlayer->isAttackable())
            return RET_YOUMAYNOTATTACKTHISPLAYER;

        const Player* attackerPlayer = NULL;
        if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster()))
        {
            checkZones = true;
            if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target)
                && !attackerPlayer->isEnemy(targetPlayer, true)
                ) || isProtected(const_cast<Player*>(attackerPlayer), const_cast<Player*>(targetPlayer))
                || (g_config.getBool(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET)
                && attackerPlayer->getDefaultOutfit().lookFeet == targetPlayer->getDefaultOutfit().lookFeet)
                || !attackerPlayer->canSeeCreature(targetPlayer))
                return RET_YOUMAYNOTATTACKTHISPLAYER;
        }
    }
    else if(target->getMonster())
    {
        if(!target->isAttackable())
            return RET_YOUMAYNOTATTACKTHISCREATURE;

        const Player* attackerPlayer = NULL;
        if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster()))
        {
            if(attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster))
                return RET_YOUMAYNOTATTACKTHISCREATURE;

            if(target->isPlayerSummon())
            {
                checkZones = true;
                if(g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target)
                    && !attackerPlayer->isEnemy(target->getPlayerMaster(), true)
                )
                    return RET_YOUMAYNOTATTACKTHISCREATURE;
            }
        }
    }

    return checkZones && (target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) ||
        (attacker->getTile()->hasFlag(TILESTATE_OPTIONALZONE)
        && !target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) &&
        !target->getTile()->hasFlag(TILESTATE_PROTECTIONZONE))) ?
        RET_ACTIONNOTPERMITTEDINANOPVPZONE : RET_NOERROR;
}

ReturnValue Combat::canTargetCreature(const Player* player, const Creature* target)
{
    if(player == target)
        return RET_YOUMAYNOTATTACKTHISPLAYER;

    Player* tmpPlayer = const_cast<Player*>(player);
    CreatureEventList targetEvents = tmpPlayer->getCreatureEvents(CREATURE_EVENT_TARGET);

    bool deny = false;
    for(CreatureEventList::iterator it = targetEvents.begin(); it != targetEvents.end(); ++it)
    {
        if(!(*it)->executeTarget(tmpPlayer, const_cast<Creature*>(target)))
            deny = true;
    }

    if(deny)
        return RET_DONTSHOWMESSAGE;

    if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone))
    {
        if(player->getZone() == ZONE_PROTECTION)
            return RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE;

        if(target->getZone() == ZONE_PROTECTION)
            return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;

        if(target->getPlayer() || target->isPlayerSummon())
        {
            if(player->getZone() == ZONE_OPTIONAL)
                return RET_ACTIONNOTPERMITTEDINANOPVPZONE;

            if(target->getZone() == ZONE_OPTIONAL)
                return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;
        }
    }

    if(player->hasFlag(PlayerFlag_CannotUseCombat) || !target->isAttackable())
        return target->getPlayer() ? RET_YOUMAYNOTATTACKTHISPLAYER : RET_YOUMAYNOTATTACKTHISCREATURE;

    if(target->getPlayer() && !Combat::isInPvpZone(player, target) && player->getSkullType(target->getPlayer()) == SKULL_NONE)
    {
        if(player->getSecureMode() == SECUREMODE_ON)
            return RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS;

        if(player->getSkull() == SKULL_BLACK)
            return RET_YOUMAYNOTATTACKTHISPLAYER;
    }

    return Combat::canDoCombat(player, target);
}

bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
{
    return attacker->getZone() == ZONE_HARDCORE && target->getZone() == ZONE_HARDCORE;
}

bool Combat::isProtected(Player* attacker, Player* target)
{
    if(attacker->hasFlag(PlayerFlag_CannotAttackPlayer) || !target->isAttackable())
        return true;

    if(attacker->getZone() == ZONE_HARDCORE && target->getZone() == ZONE_HARDCORE && g_config.getBool(ConfigManager::PVP_TILE_IGNORE_PROTECTION))
        return false;

    if(attacker->hasCustomFlag(PlayerCustomFlag_IsProtected) || target->hasCustomFlag(PlayerCustomFlag_IsProtected))
        return true;

    uint32_t protectionLevel = g_config.getNumber(ConfigManager::PROTECTION_LEVEL);
    if(target->getLevel() < protectionLevel || attacker->getLevel() < protectionLevel)
        return true;

    if(!attacker->getVocation()->isAttackable() || !target->getVocation()->isAttackable())
        return true;

    return attacker->checkLoginDelay(target->getID());
}

void Combat::setPlayerCombatValues(formulaType_t _type, double _mina, double _minb, double _maxa, double _maxb, double _minl, double _maxl, double _minm, double _maxm, int32_t _minc, int32_t _maxc)
{
    formulaType = _type; mina = _mina; minb = _minb; maxa = _maxa; maxb = _maxb;
    minl = _minl; maxl = _maxl; minm = _minm; maxm = _maxm; minc = _minc; maxc = _maxc;
}

bool Combat::setParam(CombatParam_t param, uint32_t value)
{
    switch(param)
    {
        case COMBATPARAM_COMBATTYPE:
            params.combatType = (CombatType_t)value;
            return true;

        case COMBATPARAM_EFFECT:
            params.effects.impact = (MagicEffect_t)value;
            return true;

        case COMBATPARAM_DISTANCEEFFECT:
            params.effects.distance = (ShootEffect_t)value;
            return true;

        case COMBATPARAM_BLOCKEDBYARMOR:
            params.blockedByArmor = (value != 0);
            return true;

        case COMBATPARAM_BLOCKEDBYSHIELD:
            params.blockedByShield = (value != 0);
            return true;

        case COMBATPARAM_TARGETCASTERORTOPMOST:
            params.targetCasterOrTopMost = (value != 0);
            return true;

        case COMBATPARAM_TARGETPLAYERSORSUMMONS:
            params.targetPlayersOrSummons = (value != 0);
            return true;

        case COMBATPARAM_DIFFERENTAREADAMAGE:
            params.differentAreaDamage = (value != 0);
            return true;

        case COMBATPARAM_CREATEITEM:
            params.itemId = value;
            return true;

        case COMBATPARAM_AGGRESSIVE:
            params.isAggressive = (value != 0);
            return true;

        case COMBATPARAM_DISPEL:
            params.dispelType = (ConditionType_t)value;
            return true;

        case COMBATPARAM_USECHARGES:
            params.useCharges = (value != 0);
            return true;

        case COMBATPARAM_HITEFFECT:
            params.effects.hit = (MagicEffect_t)value;
            return true;

        case COMBATPARAM_HITCOLOR:
            params.effects.color = (Color_t)value;
            return true;

        default:
            break;
    }

    return false;
}

bool Combat::setCallback(CallBackParam_t key)
{
    switch(key)
    {
        case CALLBACKPARAM_LEVELMAGICVALUE:
        {
            delete params.valueCallback;
            params.valueCallback = new ValueCallback(FORMULA_LEVELMAGIC);
            return true;
        }

        case CALLBACKPARAM_SKILLVALUE:
        {
            delete params.valueCallback;
            params.valueCallback = new ValueCallback(FORMULA_SKILL);
            return true;
        }

        case CALLBACKPARAM_TARGETTILECALLBACK:
        {
            delete params.tileCallback;
            params.tileCallback = new TileCallback();
            break;
        }

        case CALLBACKPARAM_TARGETCREATURECALLBACK:
        {
            delete params.targetCallback;
            params.targetCallback = new TargetCallback();
            break;
        }

        default:
            std::clog << "Combat::setCallback - Unknown callback type: " << (uint32_t)key << std::endl;
            break;
    }

    return false;
}

CallBack* Combat::getCallback(CallBackParam_t key)
{
    switch(key)
    {
        case CALLBACKPARAM_LEVELMAGICVALUE:
        case CALLBACKPARAM_SKILLVALUE:
            return params.valueCallback;

        case CALLBACKPARAM_TARGETTILECALLBACK:
            return params.tileCallback;

        case CALLBACKPARAM_TARGETCREATURECALLBACK:
            return params.targetCallback;

        default:
            break;
    }

    return NULL;
}

bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, void* data)
{
    int32_t change = 0;
    if(Combat2Var* var = (Combat2Var*)data)
    {
        change = var->change;
        if(!change)
            change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
    }

    if(g_game.combatBlockHit(params.combatType, caster, target, change, params.blockedByShield, params.blockedByArmor))
        return false;

    if(change < 0 && caster && caster->getPlayer() && target->getPlayer() && target->getPlayer()->getSkull() != SKULL_BLACK)
        change = change / 2;

    if(!g_game.combatChangeHealth(params.combatType, caster, target, change, params.effects.hit, params.effects.color))
        return false;

    CombatConditionFunc(caster, target, params, NULL);
    CombatDispelFunc(caster, target, params, NULL);
    return true;
}

bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, void* data)
{
    int32_t change = 0;
    if(Combat2Var* var = (Combat2Var*)data)
    {
        change = var->change;
        if(!change)
            change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
    }

    if(change < 0 && caster && caster->getPlayer() && target->getPlayer() && target->getPlayer()->getSkull() != SKULL_BLACK)
        change = change / 2;

    if(!g_game.combatChangeMana(caster, target, change))
        return false;

    CombatConditionFunc(caster, target, params, NULL);
    CombatDispelFunc(caster, target, params, NULL);
    return true;
}

bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
{
    if(params.conditionList.empty())
        return false;

    bool result = true;
    for(std::list<const Condition*>::const_iterator it = params.conditionList.begin(); it != params.conditionList.end(); ++it)
    {
        if(caster != target && target->isImmune((*it)->getType()))
            continue;

        Condition* tmp = (*it)->clone();
        if(caster)
            tmp->setParam(CONDITIONPARAM_OWNER, caster->getID());

        //TODO: infight condition until all aggressive conditions has ended
        if(!target->addCombatCondition(tmp) && result)
            result = false;
    }

    return result;
}

bool Combat::CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
{
    if(!target->hasCondition(params.dispelType))
        return false;

    target->removeCondition(caster, params.dispelType);
    return true;
}

bool Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
{
    CombatConditionFunc(caster, target, params, NULL);
    CombatDispelFunc(caster, target, params, NULL);
    return true;
}

void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params)
{
    if(params.itemId)
    {
        Player* player = NULL;
        if(caster)
        {
            if(caster->getPlayer())
                player = caster->getPlayer();
            else if(caster->isPlayerSummon())
                player = caster->getPlayerMaster();
        }

        uint32_t itemId = params.itemId;
        if(player)
        {
            bool pzLock = true;
            if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !tile->hasFlag(
                TILESTATE_HARDCOREZONE)) || tile->hasFlag(TILESTATE_OPTIONALZONE))
            {
                switch(itemId)
                {
                    case ITEM_FIREFIELD:
                        itemId = ITEM_FIREFIELD_SAFE;
                        break;
                    case ITEM_POISONFIELD:
                        itemId = ITEM_POISONFIELD_SAFE;
                        break;
                    case ITEM_ENERGYFIELD:
                        itemId = ITEM_ENERGYFIELD_SAFE;
                        break;
                    case ITEM_MAGICWALL:
                        itemId = ITEM_MAGICWALL_SAFE;
                        break;
                    case ITEM_WILDGROWTH:
                        itemId = ITEM_WILDGROWTH_SAFE;
                        break;
                    default:
                        break;
                }
            }
            else if(params.isAggressive && !Item::items[itemId].blockPathFind)
                pzLock = true;

            player->addInFightTicks(pzLock);
        }

        if(Item* item = Item::CreateItem(itemId))
        {
            if(caster)
                item->setOwner(caster->getID());

            if(g_game.internalAddItem(caster, tile, item) == RET_NOERROR)
                g_game.startDecay(item);
            else
                delete item;
        }
    }

    if(params.tileCallback)
        params.tileCallback->onTileCombat(caster, tile);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(list, tile->getPosition(), params.effects.impact);
}

void Combat::postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params)
{
    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), pos, params.effects.distance);
}

void Combat::addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, ShootEffect_t effect)
{
    if(effect == SHOOT_EFFECT_WEAPONTYPE)
    {
        switch(caster->getWeaponType())
        {
            case WEAPON_AXE:
                effect = SHOOT_EFFECT_WHIRLWINDAXE;
                break;

            case WEAPON_SWORD:
                effect = SHOOT_EFFECT_WHIRLWINDSWORD;
                break;

            case WEAPON_CLUB:
                effect = SHOOT_EFFECT_WHIRLWINDCLUB;
                break;

            case WEAPON_FIST:
                effect = SHOOT_EFFECT_LARGEROCK;
                break;

            default:
                effect = SHOOT_EFFECT_NONE;
                break;
        }
    }

    if(caster && effect != SHOOT_EFFECT_NONE)
        g_game.addDistanceEffect(fromPos, toPos, effect);
}

void Combat::CombatFunc(Creature* caster, const Position& pos, const CombatArea* area,
    const CombatParams& params, COMBATFUNC func, void* data)
{
    std::list<Tile*> tileList;
    if(caster)
        getCombatArea(caster->getPosition(), pos, area, tileList);
    else
        getCombatArea(pos, pos, area, tileList);

    Combat2Var* var = (Combat2Var*)data;
    if(var && !params.differentAreaDamage)
        var->change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);

    uint32_t maxX = 0, maxY = 0, diff;
    //calculate the max viewable range
    for(std::list<Tile*>::iterator it = tileList.begin(); it != tileList.end(); ++it)
    {
        diff = std::abs((*it)->getPosition().x - pos.x);
        if(diff > maxX)
            maxX = diff;

        diff = std::abs((*it)->getPosition().y - pos.y);
        if(diff > maxY)
            maxY = diff;
    }

    SpectatorVec list;
    g_game.getSpectators(list, pos, false, true, maxX + Map::maxViewportX, maxX + Map::maxViewportX,
        maxY + Map::maxViewportY, maxY + Map::maxViewportY);

    Tile* tile = NULL;
    for(std::list<Tile*>::iterator it = tileList.begin(); it != tileList.end(); ++it)
    {
        if(!(tile = (*it)) || canDoCombat(caster, (*it), params.isAggressive) != RET_NOERROR)
            continue;

        bool skip = true;
        if(CreatureVector* creatures = tile->getCreatures())
        {
            for(CreatureVector::iterator cit = creatures->begin(), cend = creatures->end(); skip && cit != cend; ++cit)
            {
                if(params.targetPlayersOrSummons && !(*cit)->getPlayer() && !(*cit)->isPlayerSummon())
                    continue;

                if(params.targetCasterOrTopMost)
                {
                    if(caster && caster->getTile() == tile)
                    {
                        if((*cit) == caster)
                            skip = false;
                    }
                    else if((*cit) == tile->getTopCreature())
                        skip = false;

                    if(skip)
                        continue;
                }

                if(!params.isAggressive || (caster != (*cit) && Combat::canDoCombat(caster, (*cit)) == RET_NOERROR))
                {
                    func(caster, (*cit), params, (void*)var);
                    if(params.targetCallback)
                        params.targetCallback->onTargetCombat(caster, (*cit));
                }
            }
        }

        combatTileEffects(list, caster, tile, params);
    }

    postCombatEffects(caster, pos, params);
}

void Combat::doCombat(Creature* caster, Creature* target) const
{
    //target combat callback function
    if(params.combatType != COMBAT_NONE)
    {
        int32_t minChange = 0, maxChange = 0;
        getMinMaxValues(caster, target, minChange, maxChange);
        if(params.combatType != COMBAT_MANADRAIN)
            doCombatHealth(caster, target, minChange, maxChange, params);
        else
            doCombatMana(caster, target, minChange, maxChange, params);
    }
    else
        doCombatDefault(caster, target, params);
}

void Combat::doCombat(Creature* caster, const Position& pos) const
{
    //area combat callback function
    if(params.combatType != COMBAT_NONE)
    {
        int32_t minChange = 0, maxChange = 0;
        getMinMaxValues(caster, NULL, minChange, maxChange);
        if(params.combatType != COMBAT_MANADRAIN)
            doCombatHealth(caster, pos, area, minChange, maxChange, params);
        else
            doCombatMana(caster, pos, area, minChange, maxChange, params);
    }
    else
        CombatFunc(caster, pos, area, params, CombatNullFunc, NULL);
}

void Combat::doCombatHealth(Creature* caster, Creature* target, int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;

    CombatHealthFunc(caster, target, params, (void*)&var);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatHealth(Creature* caster, const Position& pos, const CombatArea* area,
    int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;
    CombatFunc(caster, pos, area, params, CombatHealthFunc, (void*)&var);
}

void Combat::doCombatMana(Creature* caster, Creature* target, int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;

    CombatManaFunc(caster, target, params, (void*)&var);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatMana(Creature* caster, const Position& pos, const CombatArea* area,
    int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;
    CombatFunc(caster, pos, area, params, CombatManaFunc, (void*)&var);
}

void Combat::doCombatCondition(Creature* caster, const Position& pos, const CombatArea* area,
    const CombatParams& params)
{
    CombatFunc(caster, pos, area, params, CombatConditionFunc, NULL);
}

void Combat::doCombatCondition(Creature* caster, Creature* target, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    CombatConditionFunc(caster, target, params, NULL);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatDispel(Creature* caster, const Position& pos, const CombatArea* area,
    const CombatParams& params)
{
    CombatFunc(caster, pos, area, params, CombatDispelFunc, NULL);
}

void Combat::doCombatDispel(Creature* caster, Creature* target, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    CombatDispelFunc(caster, target, params, NULL);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatDefault(Creature* caster, Creature* target, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    const SpectatorVec& list = g_game.getSpectators(target->getTile()->getPosition());
    CombatNullFunc(caster, target, params, NULL);

    combatTileEffects(list, caster, target->getTile(), params);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

//**********************************************************

void ValueCallback::getMinMaxValues(Player* player, int32_t& min, int32_t& max, bool useCharges) const
{
    //"onGetPlayerMinMaxValues"(cid, ...)
    if(!m_interface->reserveEnv())
    {
        std::clog << "[Error - ValueCallback::getMinMaxValues] Callstack overflow." << std::endl;
        return;
    }

    ScriptEnviroment* env = m_interface->getEnv();
    if(!env->setCallbackId(m_scriptId, m_interface))
        return;

    m_interface->pushFunction(m_scriptId);
    lua_State* L = m_interface->getState();
    lua_pushnumber(L, env->addThing(player));

    int32_t parameters = 1;
    switch(type)
    {
        case FORMULA_LEVELMAGIC:
        {
            //"onGetPlayerMinMaxValues"(cid, level, magLevel)
            lua_pushnumber(L, player->getLevel());
            lua_pushnumber(L, player->getMagicLevel());

            parameters += 2;
            break;
        }

        case FORMULA_SKILL:
        {
            //"onGetPlayerMinMaxValues"(cid, level, skill, attack, factor)
            lua_pushnumber(L, player->getLevel());
            if(Item* weapon = player->getWeapon(false))
            {
                lua_pushnumber(L, player->getWeaponSkill(weapon));
                if(useCharges && weapon->hasCharges() && g_config.getBool(ConfigManager::REMOVE_WEAPON_CHARGES))
                    g_game.transformItem(weapon, weapon->getID(), std::max(0, weapon->getCharges() - 1));

                lua_pushnumber(L, weapon->getAttack() + weapon->getExtraAttack());
            }
            else
            {
                lua_pushnumber(L, player->getSkill(SKILL_FIST, SKILL_LEVEL));
                lua_pushnumber(L, g_config.getNumber(ConfigManager::FIST_BASE_ATTACK));
            }

            lua_pushnumber(L, player->getAttackFactor());
            parameters += 4;
            break;
        }

        default:
        {
            std::clog << "[Warning - ValueCallback::getMinMaxValues] Unknown callback type" << std::endl;
            return;
        }
    }

    int32_t params = lua_gettop(L);
    if(!lua_pcall(L, parameters, 2, 0))
    {
        min = LuaInterface::popNumber(L);
        max = LuaInterface::popNumber(L);
        player->increaseCombatValues(min, max, useCharges, type != FORMULA_SKILL);
    }
    else
        LuaInterface::error(NULL, std::string(LuaInterface::popString(L)));

    if((lua_gettop(L) + parameters + 1) != params)
        LuaInterface::error(__FUNCTION__, "Stack size changed!");

    env->resetCallback();
    m_interface->releaseEnv();
}

//**********************************************************

void TileCallback::onTileCombat(Creature* creature, Tile* tile) const
{
    //"onTileCombat"(cid, pos)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(!env->setCallbackId(m_scriptId, m_interface))
            return;

        m_interface->pushFunction(m_scriptId);
        lua_State* L = m_interface->getState();

        lua_pushnumber(L, creature ? env->addThing(creature) : 0);
        m_interface->pushPosition(L, tile->getPosition(), 0);

        m_interface->callFunction(2);
        env->resetCallback();
        m_interface->releaseEnv();
    }
    else
        std::clog << "[Error - TileCallback::onTileCombat] Call stack overflow." << std::endl;
}

//**********************************************************

void TargetCallback::onTargetCombat(Creature* creature, Creature* target) const
{
    //"onTargetCombat"(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(!env->setCallbackId(m_scriptId, m_interface))
            return;

        uint32_t cid = 0;
        if(creature)
            cid = env->addThing(creature);

        m_interface->pushFunction(m_scriptId);
        lua_State* L = m_interface->getState();

        lua_pushnumber(L, cid);
        lua_pushnumber(L, env->addThing(target));

        int32_t size = lua_gettop(L);
        if(lua_pcall(L, 2, 0 /*nReturnValues*/, 0) != 0)
            LuaInterface::error(NULL, std::string(LuaInterface::popString(L)));

        if((lua_gettop(L) + 2 /*nParams*/ + 1) != size)
            LuaInterface::error(__FUNCTION__, "Stack size changed!");

        env->resetCallback();
        m_interface->releaseEnv();
    }
    else
    {
        std::clog << "[Error - TargetCallback::onTargetCombat] Call stack overflow." << std::endl;
        return;
    }
}

//**********************************************************

void CombatArea::clear()
{
    for(CombatAreas::iterator it = areas.begin(); it != areas.end(); ++it)
        delete it->second;

    areas.clear();
}

CombatArea::CombatArea(const CombatArea& rhs)
{
    hasExtArea = rhs.hasExtArea;
    for(CombatAreas::const_iterator it = rhs.areas.begin(); it != rhs.areas.end(); ++it)
        areas[it->first] = new MatrixArea(*it->second);
}

bool CombatArea::getList(const Position& centerPos, const Position& targetPos, std::list<Tile*>& list) const
{
    Tile* tile = g_game.getTile(targetPos);
    const MatrixArea* area = getArea(centerPos, targetPos);
    if(!area)
        return false;

    uint16_t tmpX = targetPos.x, tmpY = targetPos.y, centerY = 0, centerX = 0;
    size_t cols = area->getCols(), rows = area->getRows();
    area->getCenter(centerY, centerX);

    tmpX -= centerX;
    tmpY -= centerY;
    for(size_t y = 0; y < rows; ++y)
    {
        for(size_t x = 0; x < cols; ++x)
        {
            if(area->getValue(y, x) != 0)
            {
                if(targetPos.z < MAP_MAX_LAYERS && g_game.isSightClear(targetPos, Position(tmpX, tmpY, targetPos.z), true))
                {
                    if(!(tile = g_game.getTile(tmpX, tmpY, targetPos.z)))
                    {
                        tile = new StaticTile(tmpX, tmpY, targetPos.z);
                        g_game.setTile(tile);
                    }

                    list.push_back(tile);
                }
            }

            tmpX++;
        }

        tmpX -= cols;
        tmpY++;
    }

    return true;
}

void CombatArea::copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op) const
{
    uint16_t centerY, centerX;
    input->getCenter(centerY, centerX);
    if(op == MATRIXOPERATION_COPY)
    {
        for(uint32_t y = 0; y < input->getRows(); ++y)
        {
            for(uint32_t x = 0; x < input->getCols(); ++x)
                (*output)[y][x] = (*input)[y][x];
        }

        output->setCenter(centerY, centerX);
    }
    else if(op == MATRIXOPERATION_MIRROR)
    {
        for(uint32_t y = 0; y < input->getRows(); ++y)
        {
            int32_t rx = 0;
            for(int32_t x = input->getCols() - 1; x >= 0; --x)
                (*output)[y][rx++] = (*input)[y][x];
        }

        output->setCenter(centerY, (input->getRows() - 1) - centerX);
    }
    else if(op == MATRIXOPERATION_FLIP)
    {
        for(uint32_t x = 0; x < input->getCols(); ++x)
        {
            int32_t ry = 0;
            for(int32_t y = input->getRows() - 1; y >= 0; --y)
                (*output)[ry++][x] = (*input)[y][x];
        }

        output->setCenter((input->getCols() - 1) - centerY, centerX);
    }
    else //rotation
    {
        uint16_t centerX, centerY;
        input->getCenter(centerY, centerX);

        int32_t rotateCenterX = (output->getCols() / 2) - 1, rotateCenterY = (output->getRows() / 2) - 1, angle = 0;
        switch(op)
        {
            case MATRIXOPERATION_ROTATE90:
                angle = 90;
                break;

            case MATRIXOPERATION_ROTATE180:
                angle = 180;
                break;

            case MATRIXOPERATION_ROTATE270:
                angle = 270;
                break;

            default:
                angle = 0;
                break;
        }

        double angleRad = 3.1416 * angle / 180.0;
        float a = std::cos(angleRad), b = -std::sin(angleRad);
        float c = std::sin(angleRad), d = std::cos(angleRad);

        for(int32_t x = 0; x < (long)input->getCols(); ++x)
        {
            for(int32_t y = 0; y < (long)input->getRows(); ++y)
            {
                //calculate new coordinates using rotation center
                int32_t newX = x - centerX, newY = y - centerY,
                    rotatedX = round(newX * a + newY * b),
                    rotatedY = round(newX * c + newY * d);
                //write in the output matrix using rotated coordinates
                (*output)[rotatedY + rotateCenterY][rotatedX + rotateCenterX] = (*input)[y][x];
            }
        }

        output->setCenter(rotateCenterY, rotateCenterX);
    }
}

MatrixArea* CombatArea::createArea(const std::list<uint32_t>& list, uint32_t rows)
{
    uint32_t cols = list.size() / rows;
    MatrixArea* area = new MatrixArea(rows, cols);

    uint16_t x = 0, y = 0;
    for(std::list<uint32_t>::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if(*it == 1 || *it == 3)
            area->setValue(y, x, true);

        if(*it == 2 || *it == 3)
            area->setCenter(y, x);

        ++x;
        if(cols != x)
            continue;

        x = 0;
        ++y;
    }

    return area;
}

void CombatArea::setupArea(const std::list<uint32_t>& list, uint32_t rows)
{
    //NORTH
    MatrixArea* area = createArea(list, rows);
    areas[NORTH] = area;
    uint32_t maxOutput = std::max(area->getCols(), area->getRows()) * 2;

    //SOUTH
    MatrixArea* southArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, southArea, MATRIXOPERATION_ROTATE180);
    areas[SOUTH] = southArea;

    //EAST
    MatrixArea* eastArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, eastArea, MATRIXOPERATION_ROTATE90);
    areas[EAST] = eastArea;

    //WEST
    MatrixArea* westArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, westArea, MATRIXOPERATION_ROTATE270);
    areas[WEST] = westArea;
}

void CombatArea::setupArea(int32_t length, int32_t spread)
{
    std::list<uint32_t> list;
    uint32_t rows = length;

    int32_t cols = 1;
    if(spread != 0)
        cols = ((length - length % spread) / spread) * 2 + 1;

    int32_t colSpread = cols;
    for(uint32_t y = 1; y <= rows; ++y)
    {
        int32_t mincol = cols - colSpread + 1, maxcol = cols - (cols - colSpread);
        for(int32_t x = 1; x <= cols; ++x)
        {
            if(y == rows && x == ((cols - cols % 2) / 2) + 1)
                list.push_back(3);
            else if(x >= mincol && x <= maxcol)
                list.push_back(1);
            else
                list.push_back(0);
        }

        if(spread > 0 && y % spread == 0)
            --colSpread;
    }

    setupArea(list, rows);
}

void CombatArea::setupArea(int32_t radius)
{
    int32_t area[13][13] =
    {
        {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
        {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
        {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
        {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
        {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
        {8, 7, 6, 5, 4, 2, 1, 2, 4, 5, 6, 7, 8},
        {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
        {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
        {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
        {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
        {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0}
    };

    std::list<uint32_t> list;
    for(int32_t y = 0; y < 13; ++y)
    {
        for(int32_t x = 0; x < 13; ++x)
        {
            if(area[y][x] == 1)
                list.push_back(3);
            else if(area[y][x] > 0 && area[y][x] <= radius)
                list.push_back(1);
            else
                list.push_back(0);
        }
    }

    setupArea(list, 13);
}

void CombatArea::setupExtArea(const std::list<uint32_t>& list, uint32_t rows)
{
    if(list.empty())
        return;

    //NORTH-WEST
    MatrixArea* area = createArea(list, rows);
    areas[NORTHWEST] = area;
    uint32_t maxOutput = std::max(area->getCols(), area->getRows()) * 2;

    //NORTH-EAST
    MatrixArea* neArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, neArea, MATRIXOPERATION_MIRROR);
    areas[NORTHEAST] = neArea;

    //SOUTH-WEST
    MatrixArea* swArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, swArea, MATRIXOPERATION_FLIP);
    areas[SOUTHWEST] = swArea;

    //SOUTH-EAST
    MatrixArea* seArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(swArea, seArea, MATRIXOPERATION_MIRROR);
    areas[SOUTHEAST] = seArea;

    hasExtArea = true;
}

//**********************************************************

bool MagicField::isBlocking(const Creature* creature) const
{
    if(!isUnstepable())
        return Item::isBlocking(creature);

    if(!creature || !creature->getPlayer())
        return true;

    uint32_t ownerId = getOwner();
    if(!ownerId)
        return false;

    if(Creature* owner = g_game.getCreatureByID(ownerId))
        return creature->getPlayer()->getGuildEmblem(owner) != EMBLEM_NONE;

    return false;
}

void MagicField::onStepInField(Creature* creature, bool purposeful/* = true*/)
{

    if(!purposeful)
        return;

    const ItemType& it = items[id];
    if(!it.condition)
        return;

    uint32_t ownerId = getOwner();
    Condition* condition = it.condition->clone();
    if(ownerId && !getTile()->hasFlag(TILESTATE_HARDCOREZONE))
    {
        if(Creature* owner = g_game.getCreatureByID(ownerId))
        {
            bool harmful = true;
            if((g_game.getWorldType() == WORLDTYPE_OPTIONAL || getTile()->hasFlag(TILESTATE_OPTIONALZONE))
                && (owner->getPlayer() || owner->isPlayerSummon()))
                harmful = false;
            else if(Player* targetPlayer = creature->getPlayer())
            {
                if(owner->getPlayer() && Combat::isProtected(owner->getPlayer(), targetPlayer))
                    harmful = false;
            }

            if(!harmful || (OTSYS_TIME() - createTime) <= (uint32_t)g_config.getNumber(
                ConfigManager::FIELD_OWNERSHIP) || creature->hasBeenAttacked(ownerId))
                condition->setParam(CONDITIONPARAM_OWNER, ownerId);
        }
    }

    creature->addCondition(condition);
}
 

 

Postado

Testa ai.

 

Spoiler

////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////
#include "otpch.h"
#include "const.h"

#include "combat.h"
#include "tools.h"

#include "game.h"
#include "configmanager.h"

#include "creature.h"
#include "player.h"
#include "weapons.h"

extern Game g_game;
extern Weapons* g_weapons;
extern ConfigManager g_config;

Combat::Combat()
{
    params.valueCallback = NULL;
    params.tileCallback = NULL;
    params.targetCallback = NULL;
    area = NULL;

    formulaType = FORMULA_UNDEFINED;
    mina = minb = maxa = maxb = minl = maxl = minm = maxm = minc = maxc = 0;
}

Combat::~Combat()
{
    for(std::list<const Condition*>::iterator it = params.conditionList.begin(); it != params.conditionList.end(); ++it)
        delete (*it);

    params.conditionList.clear();
    delete area;

    delete params.valueCallback;
    delete params.tileCallback;
    delete params.targetCallback;
}

bool Combat::getMinMaxValues(Creature* creature, Creature* target, int32_t& min, int32_t& max) const
{
    if(creature)
    {
        if(creature->getCombatValues(min, max))
            return true;

        if(Player* player = creature->getPlayer())
        {
            if(params.valueCallback)
            {
                params.valueCallback->getMinMaxValues(player, min, max, params.useCharges);
                return true;
            }

            min = max = 0;
            switch(formulaType)
            {
                case FORMULA_LEVELMAGIC:
                {
                    min = (int32_t)((player->getLevel() / minl + player->getMagicLevel() * minm) * 1. * mina + minb);
                    max = (int32_t)((player->getLevel() / maxl + player->getMagicLevel() * maxm) * 1. * maxa + maxb);
                    if(minc && std::abs(min) < std::abs(minc))
                        min = minc;

                    if(maxc && std::abs(max) < std::abs(maxc))
                        max = maxc;

                    player->increaseCombatValues(min, max, params.useCharges, true);
                    return true;
                }

                case FORMULA_SKILL:
                {
                    Item* item = player->getWeapon(false);
                    if(const Weapon* weapon = g_weapons->getWeapon(item))
                    {
                        max = (int32_t)(weapon->getWeaponDamage(player, target, item, true) * maxa + maxb);
                        if(params.useCharges && item->hasCharges() && g_config.getBool(ConfigManager::REMOVE_WEAPON_CHARGES))
                            g_game.transformItem(item, item->getID(), std::max((int32_t)0, ((int32_t)item->getCharges()) - 1));
                    }
                    else
                        max = (int32_t)maxb;

                    min = (int32_t)minb;
                    if(maxc && std::abs(max) < std::abs(maxc))
                        max = maxc;

                    return true;
                }

                case FORMULA_VALUE:
                {
                    min = (int32_t)minb;
                    max = (int32_t)maxb;
                    return true;
                }

                default:
                    break;
            }

            return false;
        }
    }

    if(formulaType != FORMULA_VALUE)
        return false;

    min = (int32_t)mina;
    max = (int32_t)maxa;
    return true;
}

void Combat::getCombatArea(const Position& centerPos, const Position& targetPos, const CombatArea* area, std::list<Tile*>& list)
{
    if(area)
        area->getList(centerPos, targetPos, list);
    else if(targetPos.z < MAP_MAX_LAYERS)
    {
        Tile* tile = g_game.getTile(targetPos);
        if(!tile)
        {
            tile = new StaticTile(targetPos.x, targetPos.y, targetPos.z);
            g_game.setTile(tile);
        }

        list.push_back(tile);
    }
}

CombatType_t Combat::ConditionToDamageType(ConditionType_t type)
{
    switch(type)
    {
        case CONDITION_FIRE:
            return COMBAT_FIREDAMAGE;

        case CONDITION_ENERGY:
            return COMBAT_ENERGYDAMAGE;

        case CONDITION_POISON:
            return COMBAT_EARTHDAMAGE;

        case CONDITION_FREEZING:
            return COMBAT_ICEDAMAGE;

        case CONDITION_DAZZLED:
            return COMBAT_HOLYDAMAGE;

        case CONDITION_CURSED:
            return COMBAT_DEATHDAMAGE;

        case CONDITION_DROWN:
            return COMBAT_DROWNDAMAGE;

        case CONDITION_PHYSICAL:
            return COMBAT_PHYSICALDAMAGE;

        default:
            break;
    }

    return COMBAT_NONE;
}

ConditionType_t Combat::DamageToConditionType(CombatType_t type)
{
    switch(type)
    {
        case COMBAT_FIREDAMAGE:
            return CONDITION_FIRE;

        case COMBAT_ENERGYDAMAGE:
            return CONDITION_ENERGY;

        case COMBAT_EARTHDAMAGE:
            return CONDITION_POISON;

        case COMBAT_ICEDAMAGE:
            return CONDITION_FREEZING;

        case COMBAT_HOLYDAMAGE:
            return CONDITION_DAZZLED;

        case COMBAT_DEATHDAMAGE:
            return CONDITION_CURSED;

        case COMBAT_PHYSICALDAMAGE:
            return CONDITION_PHYSICAL;

        default:
            break;
    }

    return CONDITION_NONE;
}

ReturnValue Combat::canDoCombat(const Creature* caster, const Tile* tile, bool isAggressive)
{
    if(tile->hasProperty(BLOCKPROJECTILE) || tile->floorChange() || tile->getTeleportItem())
        return RET_NOTENOUGHROOM;

    if(caster)
    {
        bool success = true;
        CreatureEventList combatAreaEvents = const_cast<Creature*>(caster)->getCreatureEvents(CREATURE_EVENT_COMBAT_AREA);
        for(CreatureEventList::iterator it = combatAreaEvents.begin(); it != combatAreaEvents.end(); ++it)
        {
            if(!(*it)->executeCombatArea(const_cast<Creature*>(caster), const_cast<Tile*>(tile), isAggressive) && success)
                success = false;
        }

        if(!success)
            return RET_NOTPOSSIBLE;

        if(caster->getPosition().z < tile->getPosition().z)
            return RET_FIRSTGODOWNSTAIRS;

        if(caster->getPosition().z > tile->getPosition().z)
            return RET_FIRSTGOUPSTAIRS;

        if(!isAggressive)
            return RET_NOERROR;

        const Player* player = caster->getPlayer();
        if(player && player->hasFlag(PlayerFlag_IgnoreProtectionZone))
            return RET_NOERROR;
    }

    return isAggressive && tile->hasFlag(TILESTATE_PROTECTIONZONE) ?
        RET_ACTIONNOTPERMITTEDINPROTECTIONZONE : RET_NOERROR;
}

ReturnValue Combat::canDoCombat(const Creature* attacker, const Creature* target)
{
    if(!attacker)
        return RET_NOERROR;

    bool success = true;
    CreatureEventList combatEvents = const_cast<Creature*>(attacker)->getCreatureEvents(CREATURE_EVENT_COMBAT);
    for(CreatureEventList::iterator it = combatEvents.begin(); it != combatEvents.end(); ++it)
    {
        if(!(*it)->executeCombat(const_cast<Creature*>(attacker), const_cast<Creature*>(target)) && success)
            success = false;
    }

    if(!success)
        return RET_NOTPOSSIBLE;

    bool checkZones = false;
    if(const Player* targetPlayer = target->getPlayer())
    {
        if(!targetPlayer->isAttackable())
            return RET_YOUMAYNOTATTACKTHISPLAYER;

        const Player* attackerPlayer = NULL;
        if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster()))
        {
            checkZones = true;
            if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !Combat::isInPvpZone(attacker, target)
                && !attackerPlayer->isEnemy(targetPlayer, true)
                ) || isProtected(const_cast<Player*>(attackerPlayer), const_cast<Player*>(targetPlayer))
                || (g_config.getBool(ConfigManager::CANNOT_ATTACK_SAME_LOOKFEET)
                && attackerPlayer->getDefaultOutfit().lookFeet == targetPlayer->getDefaultOutfit().lookFeet)
                || !attackerPlayer->canSeeCreature(targetPlayer))
                return RET_YOUMAYNOTATTACKTHISPLAYER;
        }
    }
    else if(target->getMonster())
    {
        if(!target->isAttackable())
            return RET_YOUMAYNOTATTACKTHISCREATURE;

        const Player* attackerPlayer = NULL;
        if((attackerPlayer = attacker->getPlayer()) || (attackerPlayer = attacker->getPlayerMaster()))
        {
            if(attackerPlayer->hasFlag(PlayerFlag_CannotAttackMonster))
                return RET_YOUMAYNOTATTACKTHISCREATURE;

            if(target->isPlayerSummon())
            {
                return RET_YOUMAYNOTATTACKTHISCREATURE;
            }
        }
    }

    return checkZones && (target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) ||
        (attacker->getTile()->hasFlag(TILESTATE_OPTIONALZONE)
        && !target->getTile()->hasFlag(TILESTATE_OPTIONALZONE) &&
        !target->getTile()->hasFlag(TILESTATE_PROTECTIONZONE))) ?
        RET_ACTIONNOTPERMITTEDINANOPVPZONE : RET_NOERROR;
}

ReturnValue Combat::canTargetCreature(const Player* player, const Creature* target)
{
    if(player == target)
        return RET_YOUMAYNOTATTACKTHISPLAYER;

    Player* tmpPlayer = const_cast<Player*>(player);
    CreatureEventList targetEvents = tmpPlayer->getCreatureEvents(CREATURE_EVENT_TARGET);

    bool deny = false;
    for(CreatureEventList::iterator it = targetEvents.begin(); it != targetEvents.end(); ++it)
    {
        if(!(*it)->executeTarget(tmpPlayer, const_cast<Creature*>(target)))
            deny = true;
    }

    if(deny)
        return RET_DONTSHOWMESSAGE;

    if(!player->hasFlag(PlayerFlag_IgnoreProtectionZone))
    {
        if(player->getZone() == ZONE_PROTECTION)
            return RET_YOUMAYNOTATTACKAPERSONWHILEINPROTECTIONZONE;

        if(target->getZone() == ZONE_PROTECTION)
            return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;

        if(target->getPlayer() || target->isPlayerSummon())
        {
            if(player->getZone() == ZONE_OPTIONAL)
                return RET_ACTIONNOTPERMITTEDINANOPVPZONE;

            if(target->getZone() == ZONE_OPTIONAL)
                return RET_YOUMAYNOTATTACKAPERSONINPROTECTIONZONE;
        }
    }

    if(player->hasFlag(PlayerFlag_CannotUseCombat) || !target->isAttackable() || target->isPlayerSummon())
        return target->getPlayer() ? RET_YOUMAYNOTATTACKTHISPLAYER : RET_YOUMAYNOTATTACKTHISCREATURE;

    if(target->getPlayer() && !Combat::isInPvpZone(player, target) && player->getSkullType(target->getPlayer()) == SKULL_NONE)
    {
        if(player->getSecureMode() == SECUREMODE_ON)
            return RET_TURNSECUREMODETOATTACKUNMARKEDPLAYERS;

        if(player->getSkull() == SKULL_BLACK)
            return RET_YOUMAYNOTATTACKTHISPLAYER;
    }

    return Combat::canDoCombat(player, target);
}

bool Combat::isInPvpZone(const Creature* attacker, const Creature* target)
{
    return attacker->getZone() == ZONE_HARDCORE && target->getZone() == ZONE_HARDCORE;
}

bool Combat::isProtected(Player* attacker, Player* target)
{
    if(attacker->hasFlag(PlayerFlag_CannotAttackPlayer) || !target->isAttackable())
        return true;

    if(attacker->getZone() == ZONE_HARDCORE && target->getZone() == ZONE_HARDCORE && g_config.getBool(ConfigManager::PVP_TILE_IGNORE_PROTECTION))
        return false;

    if(attacker->hasCustomFlag(PlayerCustomFlag_IsProtected) || target->hasCustomFlag(PlayerCustomFlag_IsProtected))
        return true;

    uint32_t protectionLevel = g_config.getNumber(ConfigManager::PROTECTION_LEVEL);
    if(target->getLevel() < protectionLevel || attacker->getLevel() < protectionLevel)
        return true;

    if(!attacker->getVocation()->isAttackable() || !target->getVocation()->isAttackable())
        return true;

    return attacker->checkLoginDelay(target->getID());
}

void Combat::setPlayerCombatValues(formulaType_t _type, double _mina, double _minb, double _maxa, double _maxb, double _minl, double _maxl, double _minm, double _maxm, int32_t _minc, int32_t _maxc)
{
    formulaType = _type; mina = _mina; minb = _minb; maxa = _maxa; maxb = _maxb;
    minl = _minl; maxl = _maxl; minm = _minm; maxm = _maxm; minc = _minc; maxc = _maxc;
}

bool Combat::setParam(CombatParam_t param, uint32_t value)
{
    switch(param)
    {
        case COMBATPARAM_COMBATTYPE:
            params.combatType = (CombatType_t)value;
            return true;

        case COMBATPARAM_EFFECT:
            params.effects.impact = (MagicEffect_t)value;
            return true;

        case COMBATPARAM_DISTANCEEFFECT:
            params.effects.distance = (ShootEffect_t)value;
            return true;

        case COMBATPARAM_BLOCKEDBYARMOR:
            params.blockedByArmor = (value != 0);
            return true;

        case COMBATPARAM_BLOCKEDBYSHIELD:
            params.blockedByShield = (value != 0);
            return true;

        case COMBATPARAM_TARGETCASTERORTOPMOST:
            params.targetCasterOrTopMost = (value != 0);
            return true;

        case COMBATPARAM_TARGETPLAYERSORSUMMONS:
            params.targetPlayersOrSummons = (value != 0);
            return true;

        case COMBATPARAM_DIFFERENTAREADAMAGE:
            params.differentAreaDamage = (value != 0);
            return true;

        case COMBATPARAM_CREATEITEM:
            params.itemId = value;
            return true;

        case COMBATPARAM_AGGRESSIVE:
            params.isAggressive = (value != 0);
            return true;

        case COMBATPARAM_DISPEL:
            params.dispelType = (ConditionType_t)value;
            return true;

        case COMBATPARAM_USECHARGES:
            params.useCharges = (value != 0);
            return true;

        case COMBATPARAM_HITEFFECT:
            params.effects.hit = (MagicEffect_t)value;
            return true;

        case COMBATPARAM_HITCOLOR:
            params.effects.color = (Color_t)value;
            return true;

        default:
            break;
    }

    return false;
}

bool Combat::setCallback(CallBackParam_t key)
{
    switch(key)
    {
        case CALLBACKPARAM_LEVELMAGICVALUE:
        {
            delete params.valueCallback;
            params.valueCallback = new ValueCallback(FORMULA_LEVELMAGIC);
            return true;
        }

        case CALLBACKPARAM_SKILLVALUE:
        {
            delete params.valueCallback;
            params.valueCallback = new ValueCallback(FORMULA_SKILL);
            return true;
        }

        case CALLBACKPARAM_TARGETTILECALLBACK:
        {
            delete params.tileCallback;
            params.tileCallback = new TileCallback();
            break;
        }

        case CALLBACKPARAM_TARGETCREATURECALLBACK:
        {
            delete params.targetCallback;
            params.targetCallback = new TargetCallback();
            break;
        }

        default:
            std::clog << "Combat::setCallback - Unknown callback type: " << (uint32_t)key << std::endl;
            break;
    }

    return false;
}

CallBack* Combat::getCallback(CallBackParam_t key)
{
    switch(key)
    {
        case CALLBACKPARAM_LEVELMAGICVALUE:
        case CALLBACKPARAM_SKILLVALUE:
            return params.valueCallback;

        case CALLBACKPARAM_TARGETTILECALLBACK:
            return params.tileCallback;

        case CALLBACKPARAM_TARGETCREATURECALLBACK:
            return params.targetCallback;

        default:
            break;
    }

    return NULL;
}

bool Combat::CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, void* data)
{
    int32_t change = 0;
    if(Combat2Var* var = (Combat2Var*)data)
    {
        change = var->change;
        if(!change)
            change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
    }

    if(g_game.combatBlockHit(params.combatType, caster, target, change, params.blockedByShield, params.blockedByArmor))
        return false;

    if(change < 0 && caster && caster->getPlayer() && target->getPlayer() && target->getPlayer()->getSkull() != SKULL_BLACK)
        change = change / 2;

    if(!g_game.combatChangeHealth(params.combatType, caster, target, change, params.effects.hit, params.effects.color))
        return false;

    CombatConditionFunc(caster, target, params, NULL);
    CombatDispelFunc(caster, target, params, NULL);
    return true;
}

bool Combat::CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, void* data)
{
    int32_t change = 0;
    if(Combat2Var* var = (Combat2Var*)data)
    {
        change = var->change;
        if(!change)
            change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);
    }

    if(change < 0 && caster && caster->getPlayer() && target->getPlayer() && target->getPlayer()->getSkull() != SKULL_BLACK)
        change = change / 2;

    if(!g_game.combatChangeMana(caster, target, change))
        return false;

    CombatConditionFunc(caster, target, params, NULL);
    CombatDispelFunc(caster, target, params, NULL);
    return true;
}

bool Combat::CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
{
    if(params.conditionList.empty())
        return false;

    bool result = true;
    for(std::list<const Condition*>::const_iterator it = params.conditionList.begin(); it != params.conditionList.end(); ++it)
    {
        if(caster != target && target->isImmune((*it)->getType()))
            continue;

        Condition* tmp = (*it)->clone();
        if(caster)
            tmp->setParam(CONDITIONPARAM_OWNER, caster->getID());

        //TODO: infight condition until all aggressive conditions has ended
        if(!target->addCombatCondition(tmp) && result)
            result = false;
    }

    return result;
}

bool Combat::CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
{
    if(!target->hasCondition(params.dispelType))
        return false;

    target->removeCondition(caster, params.dispelType);
    return true;
}

bool Combat::CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, void*)
{
    CombatConditionFunc(caster, target, params, NULL);
    CombatDispelFunc(caster, target, params, NULL);
    return true;
}

void Combat::combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params)
{
    if(params.itemId)
    {
        Player* player = NULL;
        if(caster)
        {
            if(caster->getPlayer())
                player = caster->getPlayer();
            else if(caster->isPlayerSummon())
                player = caster->getPlayerMaster();
        }

        uint32_t itemId = params.itemId;
        if(player)
        {
            bool pzLock = true;
            if((g_game.getWorldType() == WORLDTYPE_OPTIONAL && !tile->hasFlag(
                TILESTATE_HARDCOREZONE)) || tile->hasFlag(TILESTATE_OPTIONALZONE))
            {
                switch(itemId)
                {
                    case ITEM_FIREFIELD:
                        itemId = ITEM_FIREFIELD_SAFE;
                        break;
                    case ITEM_POISONFIELD:
                        itemId = ITEM_POISONFIELD_SAFE;
                        break;
                    case ITEM_ENERGYFIELD:
                        itemId = ITEM_ENERGYFIELD_SAFE;
                        break;
                    case ITEM_MAGICWALL:
                        itemId = ITEM_MAGICWALL_SAFE;
                        break;
                    case ITEM_WILDGROWTH:
                        itemId = ITEM_WILDGROWTH_SAFE;
                        break;
                    default:
                        break;
                }
            }
            else if(params.isAggressive && !Item::items[itemId].blockPathFind)
                pzLock = true;

            player->addInFightTicks(pzLock);
        }

        if(Item* item = Item::CreateItem(itemId))
        {
            if(caster)
                item->setOwner(caster->getID());

            if(g_game.internalAddItem(caster, tile, item) == RET_NOERROR)
                g_game.startDecay(item);
            else
                delete item;
        }
    }

    if(params.tileCallback)
        params.tileCallback->onTileCombat(caster, tile);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(list, tile->getPosition(), params.effects.impact);
}

void Combat::postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params)
{
    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), pos, params.effects.distance);
}

void Combat::addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, ShootEffect_t effect)
{
    if(effect == SHOOT_EFFECT_WEAPONTYPE)
    {
        switch(caster->getWeaponType())
        {
            case WEAPON_AXE:
                effect = SHOOT_EFFECT_WHIRLWINDAXE;
                break;

            case WEAPON_SWORD:
                effect = SHOOT_EFFECT_WHIRLWINDSWORD;
                break;

            case WEAPON_CLUB:
                effect = SHOOT_EFFECT_WHIRLWINDCLUB;
                break;

            case WEAPON_FIST:
                effect = SHOOT_EFFECT_LARGEROCK;
                break;

            default:
                effect = SHOOT_EFFECT_NONE;
                break;
        }
    }

    if(caster && effect != SHOOT_EFFECT_NONE)
        g_game.addDistanceEffect(fromPos, toPos, effect);
}

void Combat::CombatFunc(Creature* caster, const Position& pos, const CombatArea* area,
    const CombatParams& params, COMBATFUNC func, void* data)
{
    std::list<Tile*> tileList;
    if(caster)
        getCombatArea(caster->getPosition(), pos, area, tileList);
    else
        getCombatArea(pos, pos, area, tileList);

    Combat2Var* var = (Combat2Var*)data;
    if(var && !params.differentAreaDamage)
        var->change = random_range(var->minChange, var->maxChange, DISTRO_NORMAL);

    uint32_t maxX = 0, maxY = 0, diff;
    //calculate the max viewable range
    for(std::list<Tile*>::iterator it = tileList.begin(); it != tileList.end(); ++it)
    {
        diff = std::abs((*it)->getPosition().x - pos.x);
        if(diff > maxX)
            maxX = diff;

        diff = std::abs((*it)->getPosition().y - pos.y);
        if(diff > maxY)
            maxY = diff;
    }

    SpectatorVec list;
    g_game.getSpectators(list, pos, false, true, maxX + Map::maxViewportX, maxX + Map::maxViewportX,
        maxY + Map::maxViewportY, maxY + Map::maxViewportY);

    Tile* tile = NULL;
    for(std::list<Tile*>::iterator it = tileList.begin(); it != tileList.end(); ++it)
    {
        if(!(tile = (*it)) || canDoCombat(caster, (*it), params.isAggressive) != RET_NOERROR)
            continue;

        bool skip = true;
        if(CreatureVector* creatures = tile->getCreatures())
        {
            for(CreatureVector::iterator cit = creatures->begin(), cend = creatures->end(); skip && cit != cend; ++cit)
            {
                if(params.targetPlayersOrSummons && !(*cit)->getPlayer() && !(*cit)->isPlayerSummon())
                    continue;

                if(params.targetCasterOrTopMost)
                {
                    if(caster && caster->getTile() == tile)
                    {
                        if((*cit) == caster)
                            skip = false;
                    }
                    else if((*cit) == tile->getTopCreature())
                        skip = false;

                    if(skip)
                        continue;
                }

                if(!params.isAggressive || (caster != (*cit) && Combat::canDoCombat(caster, (*cit)) == RET_NOERROR))
                {
                    func(caster, (*cit), params, (void*)var);
                    if(params.targetCallback)
                        params.targetCallback->onTargetCombat(caster, (*cit));
                }
            }
        }

        combatTileEffects(list, caster, tile, params);
    }

    postCombatEffects(caster, pos, params);
}

void Combat::doCombat(Creature* caster, Creature* target) const
{
    //target combat callback function
    if(params.combatType != COMBAT_NONE)
    {
        int32_t minChange = 0, maxChange = 0;
        getMinMaxValues(caster, target, minChange, maxChange);
        if(params.combatType != COMBAT_MANADRAIN)
            doCombatHealth(caster, target, minChange, maxChange, params);
        else
            doCombatMana(caster, target, minChange, maxChange, params);
    }
    else
        doCombatDefault(caster, target, params);
}

void Combat::doCombat(Creature* caster, const Position& pos) const
{
    //area combat callback function
    if(params.combatType != COMBAT_NONE)
    {
        int32_t minChange = 0, maxChange = 0;
        getMinMaxValues(caster, NULL, minChange, maxChange);
        if(params.combatType != COMBAT_MANADRAIN)
            doCombatHealth(caster, pos, area, minChange, maxChange, params);
        else
            doCombatMana(caster, pos, area, minChange, maxChange, params);
    }
    else
        CombatFunc(caster, pos, area, params, CombatNullFunc, NULL);
}

void Combat::doCombatHealth(Creature* caster, Creature* target, int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;

    CombatHealthFunc(caster, target, params, (void*)&var);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatHealth(Creature* caster, const Position& pos, const CombatArea* area,
    int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;
    CombatFunc(caster, pos, area, params, CombatHealthFunc, (void*)&var);
}

void Combat::doCombatMana(Creature* caster, Creature* target, int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;

    CombatManaFunc(caster, target, params, (void*)&var);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatMana(Creature* caster, const Position& pos, const CombatArea* area,
    int32_t minChange, int32_t maxChange, const CombatParams& params)
{
    Combat2Var var;
    var.minChange = minChange;
    var.maxChange = maxChange;
    CombatFunc(caster, pos, area, params, CombatManaFunc, (void*)&var);
}

void Combat::doCombatCondition(Creature* caster, const Position& pos, const CombatArea* area,
    const CombatParams& params)
{
    CombatFunc(caster, pos, area, params, CombatConditionFunc, NULL);
}

void Combat::doCombatCondition(Creature* caster, Creature* target, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    CombatConditionFunc(caster, target, params, NULL);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatDispel(Creature* caster, const Position& pos, const CombatArea* area,
    const CombatParams& params)
{
    CombatFunc(caster, pos, area, params, CombatDispelFunc, NULL);
}

void Combat::doCombatDispel(Creature* caster, Creature* target, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    CombatDispelFunc(caster, target, params, NULL);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

void Combat::doCombatDefault(Creature* caster, Creature* target, const CombatParams& params)
{
    if(params.isAggressive && (caster == target || Combat::canDoCombat(caster, target) != RET_NOERROR))
        return;

    const SpectatorVec& list = g_game.getSpectators(target->getTile()->getPosition());
    CombatNullFunc(caster, target, params, NULL);

    combatTileEffects(list, caster, target->getTile(), params);
    if(params.targetCallback)
        params.targetCallback->onTargetCombat(caster, target);

    if(params.effects.impact != MAGIC_EFFECT_NONE && (!caster || !caster->isGhost()
        || g_config.getBool(ConfigManager::GHOST_SPELL_EFFECTS)))
        g_game.addMagicEffect(target->getPosition(), params.effects.impact);

    if(caster && params.effects.distance != SHOOT_EFFECT_NONE)
        addDistanceEffect(caster, caster->getPosition(), target->getPosition(), params.effects.distance);
}

//**********************************************************

void ValueCallback::getMinMaxValues(Player* player, int32_t& min, int32_t& max, bool useCharges) const
{
    //"onGetPlayerMinMaxValues"(cid, ...)
    if(!m_interface->reserveEnv())
    {
        std::clog << "[Error - ValueCallback::getMinMaxValues] Callstack overflow." << std::endl;
        return;
    }

    ScriptEnviroment* env = m_interface->getEnv();
    if(!env->setCallbackId(m_scriptId, m_interface))
        return;

    m_interface->pushFunction(m_scriptId);
    lua_State* L = m_interface->getState();
    lua_pushnumber(L, env->addThing(player));

    int32_t parameters = 1;
    switch(type)
    {
        case FORMULA_LEVELMAGIC:
        {
            //"onGetPlayerMinMaxValues"(cid, level, magLevel)
            lua_pushnumber(L, player->getLevel());
            lua_pushnumber(L, player->getMagicLevel());

            parameters += 2;
            break;
        }

        case FORMULA_SKILL:
        {
            //"onGetPlayerMinMaxValues"(cid, level, skill, attack, factor)
            lua_pushnumber(L, player->getLevel());
            if(Item* weapon = player->getWeapon(false))
            {
                lua_pushnumber(L, player->getWeaponSkill(weapon));
                if(useCharges && weapon->hasCharges() && g_config.getBool(ConfigManager::REMOVE_WEAPON_CHARGES))
                    g_game.transformItem(weapon, weapon->getID(), std::max(0, weapon->getCharges() - 1));

                lua_pushnumber(L, weapon->getAttack() + weapon->getExtraAttack());
            }
            else
            {
                lua_pushnumber(L, player->getSkill(SKILL_FIST, SKILL_LEVEL));
                lua_pushnumber(L, g_config.getNumber(ConfigManager::FIST_BASE_ATTACK));
            }

            lua_pushnumber(L, player->getAttackFactor());
            parameters += 4;
            break;
        }

        default:
        {
            std::clog << "[Warning - ValueCallback::getMinMaxValues] Unknown callback type" << std::endl;
            return;
        }
    }

    int32_t params = lua_gettop(L);
    if(!lua_pcall(L, parameters, 2, 0))
    {
        min = LuaInterface::popNumber(L);
        max = LuaInterface::popNumber(L);
        player->increaseCombatValues(min, max, useCharges, type != FORMULA_SKILL);
    }
    else
        LuaInterface::error(NULL, std::string(LuaInterface::popString(L)));

    if((lua_gettop(L) + parameters + 1) != params)
        LuaInterface::error(__FUNCTION__, "Stack size changed!");

    env->resetCallback();
    m_interface->releaseEnv();
}

//**********************************************************

void TileCallback::onTileCombat(Creature* creature, Tile* tile) const
{
    //"onTileCombat"(cid, pos)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(!env->setCallbackId(m_scriptId, m_interface))
            return;

        m_interface->pushFunction(m_scriptId);
        lua_State* L = m_interface->getState();

        lua_pushnumber(L, creature ? env->addThing(creature) : 0);
        m_interface->pushPosition(L, tile->getPosition(), 0);

        m_interface->callFunction(2);
        env->resetCallback();
        m_interface->releaseEnv();
    }
    else
        std::clog << "[Error - TileCallback::onTileCombat] Call stack overflow." << std::endl;
}

//**********************************************************

void TargetCallback::onTargetCombat(Creature* creature, Creature* target) const
{
    //"onTargetCombat"(cid, target)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(!env->setCallbackId(m_scriptId, m_interface))
            return;

        uint32_t cid = 0;
        if(creature)
            cid = env->addThing(creature);

        m_interface->pushFunction(m_scriptId);
        lua_State* L = m_interface->getState();

        lua_pushnumber(L, cid);
        lua_pushnumber(L, env->addThing(target));

        int32_t size = lua_gettop(L);
        if(lua_pcall(L, 2, 0 /*nReturnValues*/, 0) != 0)
            LuaInterface::error(NULL, std::string(LuaInterface::popString(L)));

        if((lua_gettop(L) + 2 /*nParams*/ + 1) != size)
            LuaInterface::error(__FUNCTION__, "Stack size changed!");

        env->resetCallback();
        m_interface->releaseEnv();
    }
    else
    {
        std::clog << "[Error - TargetCallback::onTargetCombat] Call stack overflow." << std::endl;
        return;
    }
}

//**********************************************************

void CombatArea::clear()
{
    for(CombatAreas::iterator it = areas.begin(); it != areas.end(); ++it)
        delete it->second;

    areas.clear();
}

CombatArea::CombatArea(const CombatArea& rhs)
{
    hasExtArea = rhs.hasExtArea;
    for(CombatAreas::const_iterator it = rhs.areas.begin(); it != rhs.areas.end(); ++it)
        areas[it->first] = new MatrixArea(*it->second);
}

bool CombatArea::getList(const Position& centerPos, const Position& targetPos, std::list<Tile*>& list) const
{
    Tile* tile = g_game.getTile(targetPos);
    const MatrixArea* area = getArea(centerPos, targetPos);
    if(!area)
        return false;

    uint16_t tmpX = targetPos.x, tmpY = targetPos.y, centerY = 0, centerX = 0;
    size_t cols = area->getCols(), rows = area->getRows();
    area->getCenter(centerY, centerX);

    tmpX -= centerX;
    tmpY -= centerY;
    for(size_t y = 0; y < rows; ++y)
    {
        for(size_t x = 0; x < cols; ++x)
        {
            if(area->getValue(y, x) != 0)
            {
                if(targetPos.z < MAP_MAX_LAYERS && g_game.isSightClear(targetPos, Position(tmpX, tmpY, targetPos.z), true))
                {
                    if(!(tile = g_game.getTile(tmpX, tmpY, targetPos.z)))
                    {
                        tile = new StaticTile(tmpX, tmpY, targetPos.z);
                        g_game.setTile(tile);
                    }

                    list.push_back(tile);
                }
            }

            tmpX++;
        }

        tmpX -= cols;
        tmpY++;
    }

    return true;
}

void CombatArea::copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op) const
{
    uint16_t centerY, centerX;
    input->getCenter(centerY, centerX);
    if(op == MATRIXOPERATION_COPY)
    {
        for(uint32_t y = 0; y < input->getRows(); ++y)
        {
            for(uint32_t x = 0; x < input->getCols(); ++x)
                (*output)[y][x] = (*input)[y][x];
        }

        output->setCenter(centerY, centerX);
    }
    else if(op == MATRIXOPERATION_MIRROR)
    {
        for(uint32_t y = 0; y < input->getRows(); ++y)
        {
            int32_t rx = 0;
            for(int32_t x = input->getCols() - 1; x >= 0; --x)
                (*output)[y][rx++] = (*input)[y][x];
        }

        output->setCenter(centerY, (input->getRows() - 1) - centerX);
    }
    else if(op == MATRIXOPERATION_FLIP)
    {
        for(uint32_t x = 0; x < input->getCols(); ++x)
        {
            int32_t ry = 0;
            for(int32_t y = input->getRows() - 1; y >= 0; --y)
                (*output)[ry++][x] = (*input)[y][x];
        }

        output->setCenter((input->getCols() - 1) - centerY, centerX);
    }
    else //rotation
    {
        uint16_t centerX, centerY;
        input->getCenter(centerY, centerX);

        int32_t rotateCenterX = (output->getCols() / 2) - 1, rotateCenterY = (output->getRows() / 2) - 1, angle = 0;
        switch(op)
        {
            case MATRIXOPERATION_ROTATE90:
                angle = 90;
                break;

            case MATRIXOPERATION_ROTATE180:
                angle = 180;
                break;

            case MATRIXOPERATION_ROTATE270:
                angle = 270;
                break;

            default:
                angle = 0;
                break;
        }

        double angleRad = 3.1416 * angle / 180.0;
        float a = std::cos(angleRad), b = -std::sin(angleRad);
        float c = std::sin(angleRad), d = std::cos(angleRad);

        for(int32_t x = 0; x < (long)input->getCols(); ++x)
        {
            for(int32_t y = 0; y < (long)input->getRows(); ++y)
            {
                //calculate new coordinates using rotation center
                int32_t newX = x - centerX, newY = y - centerY,
                    rotatedX = round(newX * a + newY * b),
                    rotatedY = round(newX * c + newY * d);
                //write in the output matrix using rotated coordinates
                (*output)[rotatedY + rotateCenterY][rotatedX + rotateCenterX] = (*input)[y][x];
            }
        }

        output->setCenter(rotateCenterY, rotateCenterX);
    }
}

MatrixArea* CombatArea::createArea(const std::list<uint32_t>& list, uint32_t rows)
{
    uint32_t cols = list.size() / rows;
    MatrixArea* area = new MatrixArea(rows, cols);

    uint16_t x = 0, y = 0;
    for(std::list<uint32_t>::const_iterator it = list.begin(); it != list.end(); ++it)
    {
        if(*it == 1 || *it == 3)
            area->setValue(y, x, true);

        if(*it == 2 || *it == 3)
            area->setCenter(y, x);

        ++x;
        if(cols != x)
            continue;

        x = 0;
        ++y;
    }

    return area;
}

void CombatArea::setupArea(const std::list<uint32_t>& list, uint32_t rows)
{
    //NORTH
    MatrixArea* area = createArea(list, rows);
    areas[NORTH] = area;
    uint32_t maxOutput = std::max(area->getCols(), area->getRows()) * 2;

    //SOUTH
    MatrixArea* southArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, southArea, MATRIXOPERATION_ROTATE180);
    areas[SOUTH] = southArea;

    //EAST
    MatrixArea* eastArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, eastArea, MATRIXOPERATION_ROTATE90);
    areas[EAST] = eastArea;

    //WEST
    MatrixArea* westArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, westArea, MATRIXOPERATION_ROTATE270);
    areas[WEST] = westArea;
}

void CombatArea::setupArea(int32_t length, int32_t spread)
{
    std::list<uint32_t> list;
    uint32_t rows = length;

    int32_t cols = 1;
    if(spread != 0)
        cols = ((length - length % spread) / spread) * 2 + 1;

    int32_t colSpread = cols;
    for(uint32_t y = 1; y <= rows; ++y)
    {
        int32_t mincol = cols - colSpread + 1, maxcol = cols - (cols - colSpread);
        for(int32_t x = 1; x <= cols; ++x)
        {
            if(y == rows && x == ((cols - cols % 2) / 2) + 1)
                list.push_back(3);
            else if(x >= mincol && x <= maxcol)
                list.push_back(1);
            else
                list.push_back(0);
        }

        if(spread > 0 && y % spread == 0)
            --colSpread;
    }

    setupArea(list, rows);
}

void CombatArea::setupArea(int32_t radius)
{
    int32_t area[13][13] =
    {
        {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
        {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
        {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
        {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
        {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
        {8, 7, 6, 5, 4, 2, 1, 2, 4, 5, 6, 7, 8},
        {0, 8, 6, 5, 4, 3, 2, 3, 4, 5, 6, 8, 0},
        {0, 8, 7, 6, 5, 4, 4, 4, 5, 6, 7, 8, 0},
        {0, 0, 8, 7, 6, 5, 5, 5, 6, 7, 8, 0, 0},
        {0, 0, 0, 8, 7, 6, 6, 6, 7, 8, 0, 0, 0},
        {0, 0, 0, 0, 8, 8, 7, 8, 8, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0}
    };

    std::list<uint32_t> list;
    for(int32_t y = 0; y < 13; ++y)
    {
        for(int32_t x = 0; x < 13; ++x)
        {
            if(area[y][x] == 1)
                list.push_back(3);
            else if(area[y][x] > 0 && area[y][x] <= radius)
                list.push_back(1);
            else
                list.push_back(0);
        }
    }

    setupArea(list, 13);
}

void CombatArea::setupExtArea(const std::list<uint32_t>& list, uint32_t rows)
{
    if(list.empty())
        return;

    //NORTH-WEST
    MatrixArea* area = createArea(list, rows);
    areas[NORTHWEST] = area;
    uint32_t maxOutput = std::max(area->getCols(), area->getRows()) * 2;

    //NORTH-EAST
    MatrixArea* neArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, neArea, MATRIXOPERATION_MIRROR);
    areas[NORTHEAST] = neArea;

    //SOUTH-WEST
    MatrixArea* swArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(area, swArea, MATRIXOPERATION_FLIP);
    areas[SOUTHWEST] = swArea;

    //SOUTH-EAST
    MatrixArea* seArea = new MatrixArea(maxOutput, maxOutput);
    copyArea(swArea, seArea, MATRIXOPERATION_MIRROR);
    areas[SOUTHEAST] = seArea;

    hasExtArea = true;
}

//**********************************************************

bool MagicField::isBlocking(const Creature* creature) const
{
    if(!isUnstepable())
        return Item::isBlocking(creature);

    if(!creature || !creature->getPlayer())
        return true;

    uint32_t ownerId = getOwner();
    if(!ownerId)
        return false;

    if(Creature* owner = g_game.getCreatureByID(ownerId))
        return creature->getPlayer()->getGuildEmblem(owner) != EMBLEM_NONE;

    return false;
}

void MagicField::onStepInField(Creature* creature, bool purposeful/* = true*/)
{

    if(!purposeful)
        return;

    const ItemType& it = items[id];
    if(!it.condition)
        return;

    uint32_t ownerId = getOwner();
    Condition* condition = it.condition->clone();
    if(ownerId && !getTile()->hasFlag(TILESTATE_HARDCOREZONE))
    {
        if(Creature* owner = g_game.getCreatureByID(ownerId))
        {
            bool harmful = true;
            if((g_game.getWorldType() == WORLDTYPE_OPTIONAL || getTile()->hasFlag(TILESTATE_OPTIONALZONE))
                && (owner->getPlayer() || owner->isPlayerSummon()))
                harmful = false;
            else if(Player* targetPlayer = creature->getPlayer())
            {
                if(owner->getPlayer() && Combat::isProtected(owner->getPlayer(), targetPlayer))
                    harmful = false;
            }

            if(!harmful || (OTSYS_TIME() - createTime) <= (uint32_t)g_config.getNumber(
                ConfigManager::FIELD_OWNERSHIP) || creature->hasBeenAttacked(ownerId))
                condition->setParam(CONDITIONPARAM_OWNER, ownerId);
        }
    }

    creature->addCondition(condition);
}

 

 

 

 

 

Nós somos aquilo que fazemos repetidamente. Excelência, não é um modo de agir, mas um hábito.

                                                                                                                                                                                                                                        Aristóteles 

Participe da conversa

Você pode postar agora e se cadastrar mais tarde. Se você tem uma conta, faça o login para postar com sua conta.

Visitante
Responder

Quem Está Navegando 0

  • Nenhum usuário registrado visualizando esta página.

Estatísticas dos Fóruns

  • Tópicos 96.9k
  • Posts 519.6k

Informação Importante

Confirmação de Termo