mirror of
https://github.com/diasurgical/DevilutionX.git
synced 2026-10-12 02:13:06 +00:00
453 lines
15 KiB
C++
453 lines
15 KiB
C++
/**
|
|
* @file missiles.h
|
|
*
|
|
* Interface of missile functionality.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <list>
|
|
#include <optional>
|
|
|
|
#include "engine.h"
|
|
#include "engine/point.hpp"
|
|
#include "engine/world_tile.hpp"
|
|
#include "misdat.h"
|
|
#include "monster.h"
|
|
#include "player.h"
|
|
#include "spelldat.h"
|
|
|
|
namespace devilution {
|
|
|
|
constexpr WorldTilePosition GolemHoldingCell = Point { 1, 0 };
|
|
|
|
struct MissilePosition {
|
|
/** Sprite's pixel offset from tile. */
|
|
Displacement offset;
|
|
/** Pixel velocity while moving */
|
|
Displacement velocity;
|
|
/** Pixels traveled as a numerator of 65,536. */
|
|
Displacement traveled;
|
|
|
|
WorldTilePosition tile;
|
|
/** Start position */
|
|
WorldTilePosition start;
|
|
|
|
/**
|
|
* @brief Specifies the location (tile) while rendering
|
|
*/
|
|
WorldTilePosition tileForRendering;
|
|
/**
|
|
* @brief Specifies the location (offset) while rendering
|
|
*/
|
|
Displacement offsetForRendering;
|
|
|
|
/**
|
|
* @brief Stops the missile (set velocity to zero and set offset to last renderer location; shouldn't matter cause the missile don't move anymore)
|
|
*/
|
|
void StopMissile()
|
|
{
|
|
velocity = {};
|
|
if (tileForRendering == tile)
|
|
offset = offsetForRendering;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Represent a more fine-grained direction than the 8 value Direction enum.
|
|
*
|
|
* This is used when rendering projectiles like arrows which have additional sprites for "half-winds" on a 16-point compass.
|
|
* The sprite sheets are typically 0-indexed and use the following layout (relative to the screen projection)
|
|
*
|
|
* W WSW SW SSW S
|
|
* ^
|
|
* WNW | SSE
|
|
* |
|
|
* NW -------+------> SE
|
|
* |
|
|
* NNW | ESE
|
|
* |
|
|
* N NNE NE ENE E
|
|
*/
|
|
enum class Direction16 : uint8_t {
|
|
South,
|
|
South_SouthWest,
|
|
SouthWest,
|
|
West_SouthWest,
|
|
West,
|
|
West_NorthWest,
|
|
NorthWest,
|
|
North_NorthWest,
|
|
North,
|
|
North_NorthEast,
|
|
NorthEast,
|
|
East_NorthEast,
|
|
East,
|
|
East_SouthEast,
|
|
SouthEast,
|
|
South_SouthEast,
|
|
};
|
|
|
|
enum class MissileSource : uint8_t {
|
|
Player,
|
|
Monster,
|
|
Trap,
|
|
};
|
|
|
|
struct Missile {
|
|
/** Type of projectile */
|
|
MissileID _mitype;
|
|
MissilePosition position;
|
|
int _mimfnum; // The direction of the missile (direction enum)
|
|
int _mispllvl;
|
|
bool _miDelFlag; // Indicate whether the missile should be deleted
|
|
MissileGraphicID _miAnimType;
|
|
MissileGraphicsFlags _miAnimFlags;
|
|
OptionalClxSpriteList _miAnimData;
|
|
int _miAnimDelay; // Tick length of each frame in the current animation
|
|
int _miAnimLen; // Number of frames in current animation
|
|
|
|
// TODO: This field is no longer used and is always equal to
|
|
// (*_miAnimData)[0].width()
|
|
uint16_t _miAnimWidth;
|
|
|
|
int16_t _miAnimWidth2;
|
|
int _miAnimCnt; // Increases by one each game tick, counting how close we are to _pAnimDelay
|
|
int _miAnimAdd;
|
|
int _miAnimFrame; // Current frame of animation + 1.
|
|
bool _miDrawFlag;
|
|
bool _miLightFlag;
|
|
bool _miPreFlag;
|
|
uint32_t _miUniqTrans;
|
|
int _mirange; // Time to live for the missile in game ticks, oncs 0 the missile will be marked for deletion via _miDelFlag
|
|
int _misource;
|
|
mienemy_type _micaster;
|
|
int _midam;
|
|
bool _miHitFlag;
|
|
int _midist; // Used for arrows to measure distance travelled (increases by 1 each game tick). Higher value is a penalty for accuracy calculation when hitting enemy
|
|
int _mlid;
|
|
int _mirnd;
|
|
int var1;
|
|
int var2;
|
|
int var3;
|
|
int var4;
|
|
int var5;
|
|
int var6;
|
|
int var7;
|
|
bool limitReached;
|
|
/**
|
|
* @brief For moving missiles lastCollisionTargetHash contains the last entity (player or monster) that was checked in CheckMissileCol (needed to avoid multiple hits for a entity at the same tile).
|
|
*/
|
|
int16_t lastCollisionTargetHash;
|
|
|
|
/** @brief Was the missile generated by a trap? */
|
|
[[nodiscard]] bool IsTrap() const
|
|
{
|
|
return _misource == -1;
|
|
}
|
|
|
|
[[nodiscard]] Player *sourcePlayer()
|
|
{
|
|
if (IsNoneOf(_micaster, TARGET_BOTH, TARGET_MONSTERS) || _misource == -1)
|
|
return nullptr;
|
|
return &Players[_misource];
|
|
}
|
|
|
|
[[nodiscard]] Monster *sourceMonster()
|
|
{
|
|
if (_micaster != TARGET_PLAYERS || _misource == -1)
|
|
return nullptr;
|
|
return &Monsters[_misource];
|
|
}
|
|
|
|
[[nodiscard]] bool isSameSource(Missile &missile)
|
|
{
|
|
return sourceType() == missile.sourceType() && _misource == missile._misource;
|
|
}
|
|
|
|
MissileSource sourceType()
|
|
{
|
|
if (_misource == -1)
|
|
return MissileSource::Trap;
|
|
if (_micaster == TARGET_PLAYERS)
|
|
return MissileSource::Monster;
|
|
return MissileSource::Player;
|
|
}
|
|
};
|
|
|
|
extern std::list<Missile> Missiles;
|
|
extern bool MissilePreFlag;
|
|
|
|
struct DamageRange {
|
|
int min;
|
|
int max;
|
|
};
|
|
DamageRange GetDamageAmt(SpellID spell, int spellLevel);
|
|
|
|
/**
|
|
* @brief Returns the direction a vector from p1(x1, y1) to p2(x2, y2) is pointing to.
|
|
*
|
|
* @code{.unparsed}
|
|
* W sW SW Sw S
|
|
* ^
|
|
* nW | Se
|
|
* |
|
|
* NW ------+-----> SE
|
|
* |
|
|
* Nw | sE
|
|
* |
|
|
* N Ne NE nE E
|
|
* @endcode
|
|
*
|
|
* @param p1 The point from which the vector starts.
|
|
* @param p2 The point from which the vector ends.
|
|
* @return the direction of the p1->p2 vector
|
|
*/
|
|
Direction16 GetDirection16(Point p1, Point p2);
|
|
bool MonsterTrapHit(int monsterId, int mindam, int maxdam, int dist, MissileID t, DamageType damageType, bool shift);
|
|
bool PlayerMHit(int pnum, Monster *monster, int dist, int mind, int maxd, MissileID mtype, DamageType damageType, bool shift, DeathReason deathReason, bool *blocked);
|
|
|
|
/**
|
|
* @brief Could the missile collide with solid objects? (like walls or closed doors)
|
|
*/
|
|
bool IsMissileBlockedByTile(Point position);
|
|
|
|
/**
|
|
* @brief Sets the missile sprite to the given sheet frame
|
|
* @param missile this object
|
|
* @param dir Sprite frame, typically representing a direction but there are some exceptions (arrows being 1 indexed, directionless spells)
|
|
*/
|
|
void SetMissDir(Missile &missile, int dir);
|
|
|
|
/**
|
|
* @brief Sets the sprite for this missile so it matches the given Direction
|
|
* @param missile this object
|
|
* @param dir Desired facing
|
|
*/
|
|
inline void SetMissDir(Missile &missile, Direction dir)
|
|
{
|
|
SetMissDir(missile, static_cast<int>(dir));
|
|
}
|
|
|
|
/**
|
|
* @brief Sets the sprite for this missile so it matches the given Direction16
|
|
* @param missile this object
|
|
* @param dir Desired facing at a 22.8125 degree resolution
|
|
*/
|
|
inline void SetMissDir(Missile &missile, Direction16 dir)
|
|
{
|
|
SetMissDir(missile, static_cast<int>(dir));
|
|
}
|
|
|
|
void InitMissiles();
|
|
|
|
struct AddMissileParameter {
|
|
WorldTilePosition dst;
|
|
Direction midir;
|
|
Missile *pParent;
|
|
bool spellFizzled;
|
|
};
|
|
|
|
void AddOpenNest(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRuneOfFire(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRuneOfLight(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRuneOfNova(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRuneOfImmolation(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRuneOfStone(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddReflect(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddBerserk(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: Direction to place the spawn
|
|
*/
|
|
void AddHorkSpawn(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddJester(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddStealPotions(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddStealMana(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddSpectralArrow(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddWarp(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddLightningWall(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddBigExplosion(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddImmolation(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddLightningBow(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddMana(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddMagi(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRingOfFire(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddSearch(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddChargedBoltBow(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddElementalArrow(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddArrow(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddPhasing(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddFirebolt(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddMagmaBall(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddTeleport(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddNovaBall(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddFireWall(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the missile-light
|
|
* var2: Y coordinate of the missile-light
|
|
* var4: X coordinate of the missile-light
|
|
* var5: Y coordinate of the missile-light
|
|
*/
|
|
void AddFireball(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the missile
|
|
* var2: Y coordinate of the missile
|
|
*/
|
|
void AddLightningControl(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddLightning(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddMissileExplosion(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddWeaponExplosion(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: Animation
|
|
*/
|
|
void AddTownPortal(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddFlashBottom(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddFlashTop(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddManaShield(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddFlameWave(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: Animation
|
|
* var3: Light strength
|
|
*/
|
|
void AddGuardian(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the destination
|
|
* var2: Y coordinate of the destination
|
|
*/
|
|
void AddChainLightning(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRhino(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the missile-light
|
|
* var2: Y coordinate of the missile-light
|
|
*/
|
|
void AddGenericMagicMissile(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the missile-light
|
|
* var2: Y coordinate of the missile-light
|
|
*/
|
|
void AddAcid(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddAcidPuddle(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: mmode of the monster
|
|
* var2: mnum of the monster
|
|
*/
|
|
void AddStoneCurse(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddGolem(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddApocalypseBoom(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddHealing(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddHealOther(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the missile-light
|
|
* var2: Y coordinate of the missile-light
|
|
* var4: X coordinate of the destination
|
|
* var5: Y coordinate of the destination
|
|
*/
|
|
void AddElemental(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddIdentify(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the first wave
|
|
* var2: Y coordinate of the first wave
|
|
* var3: Direction of the first wave
|
|
* var4: Direction of the second wave
|
|
* var5: X coordinate of the second wave
|
|
* var6: Y coordinate of the second wave
|
|
*/
|
|
void AddFireWallControl(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddInfravision(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: X coordinate of the destination
|
|
* var2: Y coordinate of the destination
|
|
*/
|
|
void AddFlameWaveControl(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddNova(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRage(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddItemRepair(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddStaffRecharge(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddTrapDisarm(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddApocalypse(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddInferno(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddInfernoControl(Missile &missile, AddMissileParameter ¶meter);
|
|
|
|
/**
|
|
* var1: Light strength
|
|
* var2: Base direction
|
|
*/
|
|
void AddChargedBolt(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddHolyBolt(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddResurrect(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddResurrectBeam(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddTelekinesis(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddBoneSpirit(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddRedPortal(Missile &missile, AddMissileParameter ¶meter);
|
|
void AddDiabloApocalypse(Missile &missile, AddMissileParameter ¶meter);
|
|
Missile *AddMissile(WorldTilePosition src, WorldTilePosition dst, Direction midir, MissileID mitype,
|
|
mienemy_type micaster, int id, int midam, int spllvl,
|
|
Missile *parent = nullptr, std::optional<_sfx_id> lSFX = std::nullopt);
|
|
void ProcessElementalArrow(Missile &missile);
|
|
void ProcessArrow(Missile &missile);
|
|
void ProcessGenericProjectile(Missile &missile);
|
|
void ProcessNovaBall(Missile &missilei);
|
|
void ProcessAcidPuddle(Missile &missile);
|
|
void ProcessFireWall(Missile &missile);
|
|
void ProcessFireball(Missile &missile);
|
|
void ProcessHorkSpawn(Missile &missile);
|
|
void ProcessRune(Missile &missile);
|
|
void ProcessLightningWall(Missile &missile);
|
|
void ProcessBigExplosion(Missile &missile);
|
|
void ProcessLightningBow(Missile &missile);
|
|
void ProcessRingOfFire(Missile &missile);
|
|
void ProcessSearch(Missile &missile);
|
|
void ProcessLightningWallControl(Missile &missile);
|
|
void ProcessImmolation(Missile &missile);
|
|
void ProcessSpectralArrow(Missile &missile);
|
|
void ProcessLightningControl(Missile &missile);
|
|
void ProcessLightning(Missile &missile);
|
|
void ProcessTownPortal(Missile &missile);
|
|
void ProcessFlashBottom(Missile &missile);
|
|
void ProcessFlashTop(Missile &missile);
|
|
void ProcessFlameWave(Missile &missile);
|
|
void ProcessGuardian(Missile &missile);
|
|
void ProcessChainLightning(Missile &missile);
|
|
void ProcessWeaponExplosion(Missile &missile);
|
|
void ProcessMissileExplosion(Missile &missile);
|
|
void ProcessAcidSplate(Missile &missile);
|
|
void ProcessTeleport(Missile &missile);
|
|
void ProcessStoneCurse(Missile &missile);
|
|
void ProcessApocalypseBoom(Missile &missile);
|
|
void ProcessRhino(Missile &missile);
|
|
void ProcessFireWallControl(Missile &missile);
|
|
void ProcessInfravision(Missile &missile);
|
|
void ProcessApocalypse(Missile &missile);
|
|
void ProcessFlameWaveControl(Missile &missile);
|
|
void ProcessNova(Missile &missile);
|
|
void ProcessRage(Missile &missile);
|
|
void ProcessInferno(Missile &missile);
|
|
void ProcessInfernoControl(Missile &missile);
|
|
void ProcessChargedBolt(Missile &missile);
|
|
void ProcessHolyBolt(Missile &missile);
|
|
void ProcessElemental(Missile &missile);
|
|
void ProcessBoneSpirit(Missile &missile);
|
|
void ProcessResurrectBeam(Missile &missile);
|
|
void ProcessRedPortal(Missile &missile);
|
|
void ProcessMissiles();
|
|
void missiles_process_charge();
|
|
void RedoMissileFlags();
|
|
|
|
#ifdef BUILD_TESTING
|
|
void TestRotateBlockedMissile(Missile &missile);
|
|
#endif
|
|
|
|
} // namespace devilution
|