////////////////////////////////////////////////////////////////////////
// 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 .
////////////////////////////////////////////////////////////////////////
#ifndef __COMBAT__
#define __COMBAT__
#include "otsystem.h"
#include "baseevents.h"
#include "condition.h"
#include "map.h"
class Condition;
class Creature;
class Position;
class Item;
//for luascript callback
class ValueCallback : public CallBack
{
public:
ValueCallback(formulaType_t _type) {type = _type;}
void getMinMaxValues(Player* player, int32_t& min, int32_t& max, bool useCharges) const;
protected:
formulaType_t type;
};
class TileCallback : public CallBack
{
public:
TileCallback() {}
void onTileCombat(Creature* creature, Tile* tile) const;
protected:
formulaType_t type;
};
class TargetCallback : public CallBack
{
public:
TargetCallback() {}
void onTargetCombat(Creature* creature, Creature* target) const;
protected:
formulaType_t type;
};
struct CombatParams
{
CombatParams()
{
blockedByArmor = blockedByShield = targetCasterOrTopMost = targetPlayersOrSummons = useCharges = false;
impactEffect = distanceEffect = NM_ME_NONE;
dispelType = CONDITION_NONE;
combatType = COMBAT_NONE;
isAggressive = true;
itemId = 0;
targetCallback = NULL;
valueCallback = NULL;
tileCallback = NULL;
}
bool blockedByArmor, blockedByShield, targetCasterOrTopMost, targetPlayersOrSummons, useCharges, isAggressive;
uint8_t impactEffect, distanceEffect;
ConditionType_t dispelType;
CombatType_t combatType;
uint32_t itemId;
TargetCallback* targetCallback;
ValueCallback* valueCallback;
TileCallback* tileCallback;
std::list conditionList;
};
struct Combat2Var
{
int32_t minChange, maxChange;
};
typedef bool (*COMBATFUNC)(Creature*, Creature*, const CombatParams&, void*);
class MatrixArea
{
public:
MatrixArea(uint32_t _rows, uint32_t _cols)
{
centerX = centerY = 0;
rows = _rows;
cols = _cols;
data_ = new bool*[rows];
for(uint32_t row = 0; row < rows; ++row)
{
data_[row] = new bool[cols];
for(uint32_t col = 0; col < cols; ++col)
data_[row][col] = 0;
}
}
MatrixArea(const MatrixArea& rhs)
{
centerX = rhs.centerX;
centerY = rhs.centerY;
rows = rhs.rows;
cols = rhs.cols;
data_ = new bool*[rows];
for(uint32_t row = 0; row < rows; ++row)
{
data_[row] = new bool[cols];
for(uint32_t col = 0; col < cols; ++col)
data_[row][col] = rhs.data_[row][col];
}
}
virtual ~MatrixArea()
{
for(uint32_t row = 0; row < rows; ++row)
delete[] data_[row];
delete[] data_;
}
void setValue(uint32_t row, uint32_t col, bool value) const {data_[row][col] = value;}
bool getValue(uint32_t row, uint32_t col) const {return data_[row][col];}
void setCenter(uint16_t y, uint16_t x) {centerX = x; centerY = y;}
void getCenter(uint16_t& y, uint16_t& x) const {x = centerX; y = centerY;}
size_t getRows() const {return rows;}
size_t getCols() const {return cols;}
inline const bool* operator[](uint32_t i) const { return data_[i]; }
inline bool* operator[](uint32_t i) { return data_[i]; }
protected:
uint16_t centerX, centerY;
uint32_t rows, cols;
bool** data_;
};
typedef std::map AreaCombatMap;
class AreaCombat
{
public:
AreaCombat() {hasExtArea = false;}
virtual ~AreaCombat() {clear();}
AreaCombat(const AreaCombat& rhs);
ReturnValue doCombat(Creature* attacker, const Position& pos, const Combat& combat) const;
bool getList(const Position& centerPos, const Position& targetPos, std::list& list) const;
void setupArea(const std::list& list, uint32_t rows);
void setupArea(int32_t length, int32_t spread);
void setupArea(int32_t radius);
void setupExtArea(const std::list& list, uint32_t rows);
void clear();
protected:
enum MatrixOperation_t
{
MATRIXOPERATION_COPY,
MATRIXOPERATION_MIRROR,
MATRIXOPERATION_FLIP,
MATRIXOPERATION_ROTATE90,
MATRIXOPERATION_ROTATE180,
MATRIXOPERATION_ROTATE270,
};
MatrixArea* createArea(const std::list& list, uint32_t rows);
void copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op) const;
MatrixArea* getArea(const Position& centerPos, const Position& targetPos) const
{
int32_t dx = targetPos.x - centerPos.x, dy = targetPos.y - centerPos.y;
Direction dir = NORTH;
if(dx < 0)
dir = WEST;
else if(dx > 0)
dir = EAST;
else if(dy < 0)
dir = NORTH;
else
dir = SOUTH;
if(hasExtArea)
{
if(dx < 0 && dy < 0)
dir = NORTHWEST;
else if(dx > 0 && dy < 0)
dir = NORTHEAST;
else if(dx < 0 && dy > 0)
dir = SOUTHWEST;
else if(dx > 0 && dy > 0)
dir = SOUTHEAST;
}
AreaCombatMap::const_iterator it = areas.find(dir);
if(it != areas.end())
return it->second;
return NULL;
}
AreaCombatMap areas;
bool hasExtArea;
};
class Combat
{
public:
Combat();
virtual ~Combat();
static void doCombatHealth(Creature* caster, Creature* target,
int32_t minChange, int32_t maxChange, const CombatParams& params);
static void doCombatHealth(Creature* caster, const Position& pos,
const AreaCombat* area, int32_t minChange, int32_t maxChange, const CombatParams& params);
static void doCombatMana(Creature* caster, Creature* target,
int32_t minChange, int32_t maxChange, const CombatParams& params);
static void doCombatMana(Creature* caster, const Position& pos,
const AreaCombat* area, int32_t minChange, int32_t maxChange, const CombatParams& params);
static void doCombatCondition(Creature* caster, Creature* target,
const CombatParams& params);
static void doCombatCondition(Creature* caster, const Position& pos,
const AreaCombat* area, const CombatParams& params);
static void doCombatDispel(Creature* caster, Creature* target,
const CombatParams& params);
static void doCombatDispel(Creature* caster, const Position& pos,
const AreaCombat* area, const CombatParams& params);
static void getCombatArea(const Position& centerPos, const Position& targetPos,
const AreaCombat* area, std::list& list);
static bool isInPvpZone(const Creature* attacker, const Creature* target);
static bool isProtected(Player* attacker, Player* target);
static CombatType_t ConditionToDamageType(ConditionType_t type);
static ConditionType_t DamageToConditionType(CombatType_t type);
static ReturnValue canTargetCreature(const Player* attacker, const Creature* target);
static ReturnValue canDoCombat(const Creature* caster, const Tile* tile, bool isAggressive);
static ReturnValue canDoCombat(const Creature* attacker, const Creature* target);
static void postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params);
static void addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, uint8_t effect);
void doCombat(Creature* caster, Creature* target) const;
void doCombat(Creature* caster, const Position& pos) const;
bool setCallback(CallBackParam_t key);
CallBack* getCallback(CallBackParam_t key);
bool setParam(CombatParam_t param, uint32_t value);
void setArea(AreaCombat* _area)
{
if(area)
delete area;
area = _area;
}
bool hasArea() const {return area != NULL;}
void setCondition(const Condition* _condition) {params.conditionList.push_back(_condition);}
void setPlayerCombatValues(formulaType_t _type, double _mina, double _minb, double _maxa, double _maxb);
void postCombatEffects(Creature* caster, const Position& pos) const {Combat::postCombatEffects(caster, pos, params);}
protected:
static void doCombatDefault(Creature* caster, Creature* target, const CombatParams& params);
static void CombatFunc(Creature* caster, const Position& pos,
const AreaCombat* area, const CombatParams& params, COMBATFUNC func, void* data);
static bool CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, void* data);
static bool CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, void* data);
static bool CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, void* data);
static bool CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, void* data);
static bool CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, void* data);
static void combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params);
bool getMinMaxValues(Creature* creature, Creature* target, int32_t& min, int32_t& max) const;
//configureable
CombatParams params;
//formula variables
formulaType_t formulaType;
double mina, minb, maxa, maxb;
AreaCombat* area;
};
class MagicField : public Item
{
public:
MagicField(uint16_t _type) : Item(_type) {createTime = OTSYS_TIME();}
virtual ~MagicField() {}
virtual MagicField* getMagicField() {return this;}
virtual const MagicField* getMagicField() const {return this;}
bool isReplaceable() const {return Item::items[getID()].replaceable;}
CombatType_t getCombatType() const
{
const ItemType& it = items[getID()];
return it.combatType;
}
void onStepInField(Creature* creature, bool purposeful = true);
private:
uint64_t createTime;
};
#endif