You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

402 lines
14 KiB

/**
* @file missiles.h
*
* Interface of missile functionality.
*/
#pragma once
#include <cstdint>
#include <list>
#include "engine.h"
#include "engine/point.hpp"
#include "miniwin/miniwin.h"
#include "misdat.h"
#include "monster.h"
#include "spelldat.h"
namespace devilution {
constexpr Point GolemHoldingCell = Point { 1, 0 };
struct MissilePosition {
Point tile;
/** Sprite's pixel offset from tile. */
Displacement offset;
/** Pixel velocity while moving */
Displacement velocity;
/** Start position */
Point start;
/** Start position */
Displacement traveled;
/**
* @brief Specifies the location (tile) while rendering
*/
Point 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 {
South,
South_SouthWest,
SouthWest,
West_SouthWest,
West,
West_NorthWest,
NorthWest,
North_NorthWest,
North,
North_NorthEast,
NorthEast,
East_NorthEast,
East,
East_SouthEast,
SouthEast,
South_SouthEast,
};
struct Missile {
/** Type of projectile */
missile_id _mitype;
MissilePosition position;
int _mimfnum; // The direction of the missile (direction enum)
int _mispllvl;
5 years ago
bool _miDelFlag; // Indicate whether the missile should be deleted
uint8_t _miAnimType;
MissileDataFlags _miAnimFlags;
const byte *_miAnimData;
int _miAnimDelay; // Tick length of each frame in the current animation
int _miAnimLen; // Number of frames in current animation
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;
4 years ago
/** @brief Was the missile generated by a trap? */
4 years ago
[[nodiscard]] bool IsTrap() const
{
return _misource == -1;
}
};
extern std::list<Missile> Missiles;
extern bool MissilePreFlag;
void GetDamageAmt(int i, int *mind, int *maxd);
4 years ago
int GetSpellLevel(size_t playerId, spell_id sn);
/**
* @brief Returns the direction a vector from p1(x1, y1) to p2(x2, y2) is pointing to.
*
* W sW SW Sw S
* ^
* nW | Se
* |
* NW ------+-----> SE
* |
* Nw | sE
* |
* N Ne NE nE E
*
* @param x1 the x coordinate of p1
* @param y1 the y coordinate of p1
* @param x2 the x coordinate of p2
* @param y2 the y coordinate of p2
* @return the direction of the p1->p2 vector
*/
Direction16 GetDirection16(Point p1, Point p2);
bool MonsterTrapHit(int m, int mindam, int maxdam, int dist, missile_id t, bool shift);
4 years ago
bool PlayerMHit(size_t pnum, Monster *monster, int dist, int mind, int maxd, missile_id mtype, bool shift, int earflag, 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 {
Point dst;
Direction midir;
Missile *pParent;
};
void AddHiveExplosion(Missile &missile, const AddMissileParameter &parameter);
void AddFireRune(Missile &missile, const AddMissileParameter &parameter);
void AddLightningRune(Missile &missile, const AddMissileParameter &parameter);
void AddGreatLightningRune(Missile &missile, const AddMissileParameter &parameter);
void AddImmolationRune(Missile &missile, const AddMissileParameter &parameter);
void AddStoneRune(Missile &missile, const AddMissileParameter &parameter);
void AddReflection(Missile &missile, const AddMissileParameter &parameter);
void AddBerserk(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: Direction to place the spawn
*/
void AddHorkSpawn(Missile &missile, const AddMissileParameter &parameter);
void AddJester(Missile &missile, const AddMissileParameter &parameter);
void AddStealPotions(Missile &missile, const AddMissileParameter &parameter);
void AddManaTrap(Missile &missile, const AddMissileParameter &parameter);
void AddSpecArrow(Missile &missile, const AddMissileParameter &parameter);
void AddWarp(Missile &missile, const AddMissileParameter &parameter);
void AddLightningWall(Missile &missile, const AddMissileParameter &parameter);
void AddRuneExplosion(Missile &missile, const AddMissileParameter &parameter);
void AddFireNova(Missile &missile, const AddMissileParameter &parameter);
void AddLightningArrow(Missile &missile, const AddMissileParameter &parameter);
void AddMana(Missile &missile, const AddMissileParameter &parameter);
void AddMagi(Missile &missile, const AddMissileParameter &parameter);
void AddRing(Missile &missile, const AddMissileParameter &parameter);
void AddSearch(Missile &missile, const AddMissileParameter &parameter);
void AddCboltArrow(Missile &missile, const AddMissileParameter &parameter);
void AddLArrow(Missile &missile, const AddMissileParameter &parameter);
void AddArrow(Missile &missile, const AddMissileParameter &parameter);
void AddRndTeleport(Missile &missile, const AddMissileParameter &parameter);
void AddFirebolt(Missile &missile, const AddMissileParameter &parameter);
void AddMagmaball(Missile &missile, const AddMissileParameter &parameter);
void AddTeleport(Missile &missile, const AddMissileParameter &parameter);
void AddLightball(Missile &missile, const AddMissileParameter &parameter);
void AddFirewall(Missile &missile, const AddMissileParameter &parameter);
/**
* 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, const AddMissileParameter &parameter);
/**
* var1: X coordinate of the missile
* var2: Y coordinate of the missile
*/
void AddLightctrl(Missile &missile, const AddMissileParameter &parameter);
void AddLightning(Missile &missile, const AddMissileParameter &parameter);
void AddMisexp(Missile &missile, const AddMissileParameter &parameter);
void AddWeapexp(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: Animation
*/
void AddTown(Missile &missile, const AddMissileParameter &parameter);
void AddFlash(Missile &missile, const AddMissileParameter &parameter);
void AddFlash2(Missile &missile, const AddMissileParameter &parameter);
void AddManashield(Missile &missile, const AddMissileParameter &parameter);
void AddFiremove(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: Animation
* var3: Light strength
*/
void AddGuardian(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: X coordinate of the destination
* var2: Y coordinate of the destination
*/
void AddChain(Missile &missile, const AddMissileParameter &parameter);
void AddRhino(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: X coordinate of the missile-light
* var2: Y coordinate of the missile-light
*/
void AddFlare(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: X coordinate of the missile-light
* var2: Y coordinate of the missile-light
*/
void AddAcid(Missile &missile, const AddMissileParameter &parameter);
void AddAcidpud(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: mmode of the monster
* var2: mnum of the monster
*/
void AddStone(Missile &missile, const AddMissileParameter &parameter);
void AddGolem(Missile &missile, const AddMissileParameter &parameter);
void AddBoom(Missile &missile, const AddMissileParameter &parameter);
void AddHeal(Missile &missile, const AddMissileParameter &parameter);
void AddHealOther(Missile &missile, const AddMissileParameter &parameter);
/**
* 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 AddElement(Missile &missile, const AddMissileParameter &parameter);
void AddIdentify(Missile &missile, const AddMissileParameter &parameter);
/**
* 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 AddFirewallC(Missile &missile, const AddMissileParameter &parameter);
void AddInfra(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: X coordinate of the destination
* var2: Y coordinate of the destination
*/
void AddWave(Missile &missile, const AddMissileParameter &parameter);
void AddNova(Missile &missile, const AddMissileParameter &parameter);
void AddBlodboil(Missile &missile, const AddMissileParameter &parameter);
void AddRepair(Missile &missile, const AddMissileParameter &parameter);
void AddRecharge(Missile &missile, const AddMissileParameter &parameter);
void AddDisarm(Missile &missile, const AddMissileParameter &parameter);
void AddApoca(Missile &missile, const AddMissileParameter &parameter);
void AddFlame(Missile &missile, const AddMissileParameter &parameter);
void AddFlamec(Missile &missile, const AddMissileParameter &parameter);
/**
* var1: Light strength
* var2: Base direction
*/
void AddCbolt(Missile &missile, const AddMissileParameter &parameter);
void AddHbolt(Missile &missile, const AddMissileParameter &parameter);
void AddResurrect(Missile &missile, const AddMissileParameter &parameter);
void AddResurrectBeam(Missile &missile, const AddMissileParameter &parameter);
void AddTelekinesis(Missile &missile, const AddMissileParameter &parameter);
void AddBoneSpirit(Missile &missile, const AddMissileParameter &parameter);
void AddRportal(Missile &missile, const AddMissileParameter &parameter);
void AddDiabApoca(Missile &missile, const AddMissileParameter &parameter);
Missile *AddMissile(Point src, Point dst, Direction midir, missile_id mitype, mienemy_type micaster, int id, int midam, int spllvl, Missile *pParent = nullptr);
void MI_LArrow(Missile &missile);
void MI_Arrow(Missile &missile);
void MI_Firebolt(Missile &missile);
void MI_Lightball(Missile &missilei);
void MI_Acidpud(Missile &missile);
void MI_Firewall(Missile &missile);
void MI_Fireball(Missile &missile);
void MI_HorkSpawn(Missile &missile);
void MI_Rune(Missile &missile);
void MI_LightningWall(Missile &missile);
void MI_HiveExplode(Missile &missile);
void MI_LightningArrow(Missile &missile);
void MI_FireRing(Missile &missile);
void MI_Search(Missile &missile);
void MI_LightningWallC(Missile &missile);
void MI_FireNova(Missile &missile);
void MI_SpecArrow(Missile &missile);
void MI_Lightctrl(Missile &missile);
void MI_Lightning(Missile &missile);
void MI_Town(Missile &missile);
void MI_Flash(Missile &missile);
void MI_Flash2(Missile &missile);
void MI_Firemove(Missile &missile);
void MI_Guardian(Missile &missile);
void MI_Chain(Missile &missile);
void MI_Weapexp(Missile &missile);
void MI_Misexp(Missile &missile);
void MI_Acidsplat(Missile &missile);
void MI_Teleport(Missile &missile);
void MI_Stone(Missile &missile);
void MI_Boom(Missile &missile);
void MI_Rhino(Missile &missile);
void MI_FirewallC(Missile &missile);
void MI_Infra(Missile &missile);
void MI_Apoca(Missile &missile);
void MI_Wave(Missile &missile);
void MI_Nova(Missile &missile);
void MI_Blodboil(Missile &missile);
void MI_Flame(Missile &missile);
void MI_Flamec(Missile &missile);
void MI_Cbolt(Missile &missile);
void MI_Hbolt(Missile &missile);
void MI_Element(Missile &missile);
void MI_Bonespirit(Missile &missile);
void MI_ResurrectBeam(Missile &missile);
void MI_Rportal(Missile &missile);
void ProcessMissiles();
void missiles_process_charge();
void RedoMissileFlags();
} // namespace devilution