Server upload

RD Core / Commit #2

Commit Server upload

Alex Alex committed 18/10/2026 23:38 main Patch
1,106 files +223,404 -0
A src/combat.h +340-0 View file
@@ -0,0 +1,340 @@
1+/**
2+ * The Forgotten Server - a free and open-source MMORPG server emulator
3+ * Copyright (C) 2019 Mark Samman <mark.samman@gmail.com>
4+ *
5+ * This program is free software; you can redistribute it and/or modify
6+ * it under the terms of the GNU General Public License as published by
7+ * the Free Software Foundation; either version 2 of the License, or
8+ * (at your option) any later version.
9+ *
10+ * This program is distributed in the hope that it will be useful,
11+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
12+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+ * GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program; if not, write to the Free Software Foundation, Inc.,
17+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18+ */
19+
20+#ifndef FS_COMBAT_H_B02CE79230FC43708699EE91FCC8F7CC
21+#define FS_COMBAT_H_B02CE79230FC43708699EE91FCC8F7CC
22+
23+#include "thing.h"
24+#include "condition.h"
25+#include "map.h"
26+#include "baseevents.h"
27+
28+class Condition;
29+class Creature;
30+class Item;
31+
32+struct Position;
33+
34+//for luascript callback
35+class ValueCallback final : public CallBack
36+{
37+ public:
38+ explicit ValueCallback(formulaType_t type): type(type) {}
39+ void getMinMaxValues(Player* player, CombatDamage& damage) const;
40+
41+ private:
42+ formulaType_t type;
43+};
44+
45+class TileCallback final : public CallBack
46+{
47+ public:
48+ void onTileCombat(Creature* creature, Tile* tile) const;
49+};
50+
51+class TargetCallback final : public CallBack
52+{
53+ public:
54+ void onTargetCombat(Creature* creature, Creature* target) const;
55+};
56+
57+struct CombatParams {
58+ std::forward_list<std::unique_ptr<const Condition>> conditionList;
59+
60+ std::unique_ptr<ValueCallback> valueCallback;
61+ std::unique_ptr<TileCallback> tileCallback;
62+ std::unique_ptr<TargetCallback> targetCallback;
63+
64+ uint16_t itemId = 0;
65+
66+ ConditionType_t dispelType = CONDITION_NONE;
67+ CombatType_t combatType = COMBAT_NONE;
68+ CombatOrigin origin = ORIGIN_SPELL;
69+
70+ uint16_t impactEffect = CONST_ME_NONE;
71+ uint8_t distanceEffect = CONST_ANI_NONE;
72+
73+ bool blockedByArmor = false;
74+ bool blockedByShield = false;
75+ bool targetCasterOrTopMost = false;
76+ bool aggressive = true;
77+ bool useCharges = false;
78+};
79+
80+class MatrixArea
81+{
82+ public:
83+ MatrixArea(uint32_t rows, uint32_t cols): centerX(0), centerY(0), rows(rows), cols(cols) {
84+ data_ = new bool*[rows];
85+
86+ for (uint32_t row = 0; row < rows; ++row) {
87+ data_[row] = new bool[cols];
88+
89+ for (uint32_t col = 0; col < cols; ++col) {
90+ data_[row][col] = 0;
91+ }
92+ }
93+ }
94+
95+ MatrixArea(const MatrixArea& rhs) {
96+ centerX = rhs.centerX;
97+ centerY = rhs.centerY;
98+ rows = rhs.rows;
99+ cols = rhs.cols;
100+
101+ data_ = new bool*[rows];
102+
103+ for (uint32_t row = 0; row < rows; ++row) {
104+ data_[row] = new bool[cols];
105+
106+ for (uint32_t col = 0; col < cols; ++col) {
107+ data_[row][col] = rhs.data_[row][col];
108+ }
109+ }
110+ }
111+
112+ ~MatrixArea() {
113+ for (uint32_t row = 0; row < rows; ++row) {
114+ delete[] data_[row];
115+ }
116+
117+ delete[] data_;
118+ }
119+
120+ // non-assignable
121+ MatrixArea& operator=(const MatrixArea&) = delete;
122+
123+ void setValue(uint32_t row, uint32_t col, bool value) const {
124+ data_[row][col] = value;
125+ }
126+ bool getValue(uint32_t row, uint32_t col) const {
127+ return data_[row][col];
128+ }
129+
130+ void setCenter(uint32_t y, uint32_t x) {
131+ centerX = x;
132+ centerY = y;
133+ }
134+ void getCenter(uint32_t& y, uint32_t& x) const {
135+ x = centerX;
136+ y = centerY;
137+ }
138+
139+ uint32_t getRows() const {
140+ return rows;
141+ }
142+ uint32_t getCols() const {
143+ return cols;
144+ }
145+
146+ const bool* operator[](uint32_t i) const {
147+ return data_[i];
148+ }
149+ bool* operator[](uint32_t i) {
150+ return data_[i];
151+ }
152+
153+ private:
154+ uint32_t centerX;
155+ uint32_t centerY;
156+
157+ uint32_t rows;
158+ uint32_t cols;
159+ bool** data_;
160+};
161+
162+class AreaCombat
163+{
164+ public:
165+ AreaCombat() = default;
166+
167+ AreaCombat(const AreaCombat& rhs);
168+ ~AreaCombat() {
169+ clear();
170+ }
171+
172+ // non-assignable
173+ AreaCombat& operator=(const AreaCombat&) = delete;
174+
175+ void getList(const Position& centerPos, const Position& targetPos, std::forward_list<Tile*>& list) const;
176+
177+ void setupArea(const std::list<uint32_t>& list, uint32_t rows);
178+ void setupArea(int32_t length, int32_t spread);
179+ void setupArea(int32_t radius);
180+ void setupExtArea(const std::list<uint32_t>& list, uint32_t rows);
181+ void clear();
182+
183+ private:
184+ enum MatrixOperation_t {
185+ MATRIXOPERATION_COPY,
186+ MATRIXOPERATION_MIRROR,
187+ MATRIXOPERATION_FLIP,
188+ MATRIXOPERATION_ROTATE90,
189+ MATRIXOPERATION_ROTATE180,
190+ MATRIXOPERATION_ROTATE270,
191+ };
192+
193+ MatrixArea* createArea(const std::list<uint32_t>& list, uint32_t rows);
194+ static void copyArea(const MatrixArea* input, MatrixArea* output, MatrixOperation_t op);
195+
196+ MatrixArea* getArea(const Position& centerPos, const Position& targetPos) const {
197+ int32_t dx = Position::getOffsetX(targetPos, centerPos);
198+ int32_t dy = Position::getOffsetY(targetPos, centerPos);
199+
200+ Direction dir;
201+ if (dx < 0) {
202+ dir = DIRECTION_WEST;
203+ } else if (dx > 0) {
204+ dir = DIRECTION_EAST;
205+ } else if (dy < 0) {
206+ dir = DIRECTION_NORTH;
207+ } else {
208+ dir = DIRECTION_SOUTH;
209+ }
210+
211+ if (hasExtArea) {
212+ if (dx < 0 && dy < 0) {
213+ dir = DIRECTION_NORTHWEST;
214+ } else if (dx > 0 && dy < 0) {
215+ dir = DIRECTION_NORTHEAST;
216+ } else if (dx < 0 && dy > 0) {
217+ dir = DIRECTION_SOUTHWEST;
218+ } else if (dx > 0 && dy > 0) {
219+ dir = DIRECTION_SOUTHEAST;
220+ }
221+ }
222+
223+ auto it = areas.find(dir);
224+ if (it == areas.end()) {
225+ return nullptr;
226+ }
227+ return it->second;
228+ }
229+
230+ std::map<Direction, MatrixArea*> areas;
231+ bool hasExtArea = false;
232+};
233+
234+class Combat
235+{
236+ public:
237+ Combat() = default;
238+
239+ // non-copyable
240+ Combat(const Combat&) = delete;
241+ Combat& operator=(const Combat&) = delete;
242+
243+ static void getCombatArea(const Position& centerPos, const Position& targetPos, const AreaCombat* area, std::forward_list<Tile*>& list);
244+
245+ static bool isInPvpZone(const Creature* attacker, const Creature* target);
246+ static bool isProtected(const Player* attacker, const Player* target);
247+ static bool isPlayerCombat(const Creature* target);
248+ static CombatType_t ConditionToDamageType(ConditionType_t type);
249+ static ConditionType_t DamageToConditionType(CombatType_t type);
250+ static ReturnValue canTargetCreature(Player* attacker, Creature* target);
251+ static ReturnValue canDoCombat(Creature* caster, Tile* tile, bool aggressive);
252+ static ReturnValue canDoCombat(Creature* attacker, Creature* target);
253+ static void postCombatEffects(Creature* caster, const Position& pos, const CombatParams& params);
254+
255+ static void addDistanceEffect(Creature* caster, const Position& fromPos, const Position& toPos, uint8_t effect);
256+
257+ void doCombat(Creature* caster, Creature* target) const;
258+ void doCombat(Creature* caster, const Position& position) const;
259+
260+ static void doTargetCombat(Creature* caster, Creature* target, CombatDamage& damage, const CombatParams& params);
261+ static void doAreaCombat(Creature* caster, const Position& position, const AreaCombat* area, CombatDamage& damage, const CombatParams& params);
262+
263+ static void checkCriticalHit(Player* caster, CombatDamage& damage);
264+ static void checkLeech(Player* caster, CombatDamage& damage);
265+
266+ bool setCallback(CallBackParam_t key);
267+ CallBack* getCallback(CallBackParam_t key);
268+
269+ bool setParam(CombatParam_t param, uint32_t value);
270+ void setArea(AreaCombat* area) {
271+ this->area.reset(area);
272+ }
273+ bool hasArea() const {
274+ return area != nullptr;
275+ }
276+ void addCondition(const Condition* condition) {
277+ params.conditionList.emplace_front(condition);
278+ }
279+ void clearConditions() {
280+ params.conditionList.clear();
281+ }
282+ void setPlayerCombatValues(formulaType_t formulaType, double mina, double minb, double maxa, double maxb);
283+ void postCombatEffects(Creature* caster, const Position& pos) const {
284+ postCombatEffects(caster, pos, params);
285+ }
286+
287+ void setOrigin(CombatOrigin origin) {
288+ params.origin = origin;
289+ }
290+
291+ private:
292+ static void combatTileEffects(const SpectatorVec& spectators, Creature* caster, Tile* tile, const CombatParams& params);
293+ CombatDamage getCombatDamage(Creature* creature, Creature* target) const;
294+
295+ //configureable
296+ CombatParams params;
297+
298+ //formula variables
299+ formulaType_t formulaType = COMBAT_FORMULA_UNDEFINED;
300+ double mina = 0.0;
301+ double minb = 0.0;
302+ double maxa = 0.0;
303+ double maxb = 0.0;
304+
305+ std::unique_ptr<AreaCombat> area;
306+};
307+
308+class MagicField final : public Item
309+{
310+ public:
311+ explicit MagicField(uint16_t type) : Item(type), createTime(OTSYS_TIME()) {}
312+
313+ MagicField* getMagicField() override {
314+ return this;
315+ }
316+ const MagicField* getMagicField() const override {
317+ return this;
318+ }
319+
320+ bool isReplaceable() const {
321+ return Item::items[getID()].replaceable;
322+ }
323+ CombatType_t getCombatType() const {
324+ const ItemType& it = items[getID()];
325+ return it.combatType;
326+ }
327+ int32_t getDamage() const {
328+ const ItemType& it = items[getID()];
329+ if (it.conditionDamage) {
330+ return it.conditionDamage->getTotalDamage();
331+ }
332+ return 0;
333+ }
334+ void onStepInField(Creature* creature);
335+
336+ private:
337+ int64_t createTime;
338+};
339+
340+#endif
Top