mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-05-03 11:09:19 +02:00
403 lines
12 KiB
C++
403 lines
12 KiB
C++
/**
|
|
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
|
|
* Copyright (C) 2019 Sabrehaven and Mark Samman <mark.samman@gmail.com>
|
|
*
|
|
* 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 2 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, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
|
|
#ifndef FS_COMBAT_H_B02CE79230FC43708699EE91FCC8F7CC
|
|
#define FS_COMBAT_H_B02CE79230FC43708699EE91FCC8F7CC
|
|
|
|
#include "thing.h"
|
|
#include "condition.h"
|
|
#include "map.h"
|
|
#include "baseevents.h"
|
|
|
|
class Condition;
|
|
class Creature;
|
|
class Item;
|
|
|
|
struct Position;
|
|
|
|
//for luascript callback
|
|
class ValueCallback final : public CallBack
|
|
{
|
|
public:
|
|
explicit ValueCallback(formulaType_t type): type(type) {}
|
|
void getMinMaxValues(Player* player, CombatDamage& damage, bool useCharges) const;
|
|
|
|
protected:
|
|
formulaType_t type;
|
|
};
|
|
|
|
class TileCallback final : public CallBack
|
|
{
|
|
public:
|
|
void onTileCombat(Creature* creature, Tile* tile) const;
|
|
|
|
protected:
|
|
formulaType_t type;
|
|
};
|
|
|
|
class TargetCallback final : public CallBack
|
|
{
|
|
public:
|
|
void onTargetCombat(Creature* creature, Creature* target) const;
|
|
|
|
protected:
|
|
formulaType_t type;
|
|
};
|
|
|
|
struct CombatParams {
|
|
std::forward_list<std::unique_ptr<const Condition>> conditionList;
|
|
|
|
std::unique_ptr<ValueCallback> valueCallback;
|
|
std::unique_ptr<TileCallback> tileCallback;
|
|
std::unique_ptr<TargetCallback> targetCallback;
|
|
|
|
uint16_t itemId = 0;
|
|
uint16_t decreaseDamage = 0;
|
|
uint16_t maximumDecreasedDamage = 0;
|
|
|
|
ConditionType_t dispelType = CONDITION_NONE;
|
|
CombatType_t combatType = COMBAT_NONE;
|
|
CombatOrigin origin = ORIGIN_SPELL;
|
|
|
|
uint8_t impactEffect = CONST_ME_NONE;
|
|
uint8_t distanceEffect = CONST_ANI_NONE;
|
|
|
|
bool blockedByArmor = false;
|
|
bool blockedByShield = false;
|
|
bool targetCasterOrTopMost = false;
|
|
bool aggressive = true;
|
|
bool useCharges = false;
|
|
};
|
|
|
|
struct Impact
|
|
{
|
|
Creature* actor = nullptr;
|
|
|
|
virtual void handleCreature(Creature*) {
|
|
//
|
|
}
|
|
};
|
|
|
|
struct DamageImpact : Impact
|
|
{
|
|
CombatParams params;
|
|
CombatDamage damage;
|
|
|
|
void handleCreature(Creature* target) final;
|
|
};
|
|
|
|
struct SpeedImpact : Impact
|
|
{
|
|
int32_t percent = 0;
|
|
int32_t duration = 0;
|
|
|
|
void handleCreature(Creature* target) final;
|
|
};
|
|
|
|
struct DunkenImpact : Impact
|
|
{
|
|
int32_t duration = 0;
|
|
|
|
void handleCreature(Creature* target) final;
|
|
};
|
|
|
|
typedef void(*COMBATFUNC)(Creature*, Creature*, const CombatParams&, CombatDamage*);
|
|
|
|
class MatrixArea
|
|
{
|
|
public:
|
|
MatrixArea(uint32_t rows, uint32_t cols): centerX(0), 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];
|
|
}
|
|
}
|
|
}
|
|
|
|
~MatrixArea() {
|
|
for (uint32_t row = 0; row < rows; ++row) {
|
|
delete[] data_[row];
|
|
}
|
|
|
|
delete[] data_;
|
|
}
|
|
|
|
// non-assignable
|
|
MatrixArea& operator=(const MatrixArea&) = delete;
|
|
|
|
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(uint32_t y, uint32_t x) {
|
|
centerX = x;
|
|
centerY = y;
|
|
}
|
|
void getCenter(uint32_t& y, uint32_t& x) const {
|
|
x = centerX;
|
|
y = centerY;
|
|
}
|
|
|
|
uint32_t getRows() const {
|
|
return rows;
|
|
}
|
|
uint32_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:
|
|
uint32_t centerX;
|
|
uint32_t centerY;
|
|
|
|
uint32_t rows;
|
|
uint32_t cols;
|
|
bool** data_;
|
|
};
|
|
|
|
class AreaCombat
|
|
{
|
|
public:
|
|
AreaCombat() = default;
|
|
|
|
AreaCombat(const AreaCombat& rhs);
|
|
~AreaCombat() {
|
|
clear();
|
|
}
|
|
|
|
// non-assignable
|
|
AreaCombat& operator=(const AreaCombat&) = delete;
|
|
|
|
void getList(const Position& centerPos, const Position& targetPos, std::forward_list<Tile*>& list) const;
|
|
|
|
void setupArea(const std::list<uint32_t>& list, uint32_t rows);
|
|
void setupArea(int32_t length, int32_t spread);
|
|
void setupArea(int32_t radius);
|
|
void setupExtArea(const std::list<uint32_t>& 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<uint32_t>& 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 = Position::getOffsetX(targetPos, centerPos);
|
|
int32_t dy = Position::getOffsetY(targetPos, centerPos);
|
|
|
|
Direction dir;
|
|
if (dx < 0) {
|
|
dir = DIRECTION_WEST;
|
|
} else if (dx > 0) {
|
|
dir = DIRECTION_EAST;
|
|
} else if (dy < 0) {
|
|
dir = DIRECTION_NORTH;
|
|
} else {
|
|
dir = DIRECTION_SOUTH;
|
|
}
|
|
|
|
if (hasExtArea) {
|
|
if (dx < 0 && dy < 0) {
|
|
dir = DIRECTION_NORTHWEST;
|
|
} else if (dx > 0 && dy < 0) {
|
|
dir = DIRECTION_NORTHEAST;
|
|
} else if (dx < 0 && dy > 0) {
|
|
dir = DIRECTION_SOUTHWEST;
|
|
} else if (dx > 0 && dy > 0) {
|
|
dir = DIRECTION_SOUTHEAST;
|
|
}
|
|
}
|
|
|
|
auto it = areas.find(dir);
|
|
if (it == areas.end()) {
|
|
return nullptr;
|
|
}
|
|
return it->second;
|
|
}
|
|
|
|
std::map<Direction, MatrixArea*> areas;
|
|
bool hasExtArea = false;
|
|
};
|
|
|
|
class Combat
|
|
{
|
|
public:
|
|
Combat() = default;
|
|
|
|
// non-copyable
|
|
Combat(const Combat&) = delete;
|
|
Combat& operator=(const Combat&) = delete;
|
|
|
|
static int32_t computeDamage(Creature* creature, int32_t strength, int32_t variation);
|
|
static int32_t getTotalDamage(int32_t attackSkill, int32_t attackValue, fightMode_t fightMode);
|
|
|
|
static bool attack(Creature* attacker, Creature* target);
|
|
static bool closeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
|
|
static bool rangeAttack(Creature* attacker, Creature* target, fightMode_t fightMode);
|
|
|
|
static void circleShapeSpell(Creature* attacker, const Position& toPos, int32_t range, int32_t animation, int32_t radius, DamageImpact* impact, int32_t effect);
|
|
|
|
static void getAttackValue(Creature* creature, uint32_t& attackValue, uint32_t& skillValue, uint8_t& skill);
|
|
|
|
static bool doCombatHealth(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
|
|
static void doCombatHealth(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
|
|
|
|
static void doCombatMana(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
|
|
static void doCombatMana(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
|
|
|
|
static void doCombatCondition(Creature* caster, Creature* target, const CombatParams& params);
|
|
static void doCombatCondition(Creature* caster, const Position& position, const AreaCombat* area, const CombatParams& params);
|
|
|
|
static void doCombatDispel(Creature* caster, Creature* target, const CombatParams& params);
|
|
static void doCombatDispel(Creature* caster, const Position& position, const AreaCombat* area, const CombatParams& params);
|
|
|
|
static void getCombatArea(const Position& centerPos, const Position& targetPos, const AreaCombat* area, std::forward_list<Tile*>& list);
|
|
|
|
static bool isInPvpZone(const Creature* attacker, const Creature* target);
|
|
static bool isProtected(const Player* attacker, const Player* target);
|
|
static bool isPlayerCombat(const Creature* target);
|
|
static CombatType_t ConditionToDamageType(ConditionType_t type);
|
|
static ConditionType_t DamageToConditionType(CombatType_t type);
|
|
static ReturnValue canTargetCreature(Player* attacker, Creature* target);
|
|
static ReturnValue canDoCombat(Creature* caster, Tile* tile, bool aggressive);
|
|
static ReturnValue canDoCombat(Creature* attacker, Creature* target);
|
|
static void postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params);
|
|
|
|
static void addDistanceEffect(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) {
|
|
this->area.reset(area);
|
|
}
|
|
bool hasArea() const {
|
|
return area != nullptr;
|
|
}
|
|
void setCondition(const Condition* condition) {
|
|
params.conditionList.emplace_front(condition);
|
|
}
|
|
void setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb);
|
|
void postCombatEffects(Creature* caster, const Position& pos) const {
|
|
postCombatEffects(caster, pos, params);
|
|
}
|
|
|
|
void setOrigin(CombatOrigin origin) {
|
|
params.origin = origin;
|
|
}
|
|
|
|
protected:
|
|
static bool canUseWeapon(Player* player, Item* weapon);
|
|
static void postWeaponEffects(Player* player, Item* weapon);
|
|
|
|
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, CombatDamage* data);
|
|
|
|
static void CombatHealthFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
|
static void CombatManaFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* damage);
|
|
static void CombatConditionFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
|
static void CombatDispelFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
|
static void CombatNullFunc(Creature* caster, Creature* target, const CombatParams& params, CombatDamage* data);
|
|
|
|
static void combatTileEffects(const SpectatorVec& list, Creature* caster, Tile* tile, const CombatParams& params);
|
|
CombatDamage getCombatDamage(Creature* creature) const;
|
|
|
|
//configureable
|
|
CombatParams params;
|
|
|
|
//formula variables
|
|
formulaType_t formulaType = COMBAT_FORMULA_UNDEFINED;
|
|
double mina = 0.0;
|
|
double minb = 0.0;
|
|
double maxa = 0.0;
|
|
double maxb = 0.0;
|
|
|
|
std::unique_ptr<AreaCombat> area;
|
|
};
|
|
|
|
class MagicField final : public Item
|
|
{
|
|
public:
|
|
explicit MagicField(uint16_t type) : Item(type), createTime(OTSYS_TIME()) {}
|
|
|
|
MagicField* getMagicField() final {
|
|
return this;
|
|
}
|
|
const MagicField* getMagicField() const final {
|
|
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);
|
|
|
|
private:
|
|
int64_t createTime;
|
|
};
|
|
|
|
#endif
|