devilutionX/Source/spells.cpp
Anders Jenbo 20621a0642
add all.h and use in place of diablo.h (#2005)
Now diablo.h is treated in the same way as all other header files of
Source, as it only contains the declarations of global variables and
functions of diablo.cpp.

Besides consistency, this also enables mods to include diablo.h just
like any other header file without having to include every header file
(and without having to include C++ specific aspects of the now all.h).
2020-02-14 13:12:54 +01:00

282 lines
5.5 KiB
C++

#include "all.h"
int GetManaAmount(int id, int sn)
{
int ma; // mana amount
// mana adjust
int adj = 0;
// spell level
int sl = plr[id]._pSplLvl[sn] + plr[id]._pISplLvlAdd - 1;
if (sl < 0) {
sl = 0;
}
if (sl > 0) {
adj = sl * spelldata[sn].sManaAdj;
}
if (sn == SPL_FIREBOLT) {
adj >>= 1;
}
if (sn == SPL_RESURRECT && sl > 0) {
adj = sl * (spelldata[SPL_RESURRECT].sManaCost / 8);
}
if (spelldata[sn].sManaCost == 255) {
ma = ((BYTE)plr[id]._pMaxManaBase - adj);
} else {
ma = (spelldata[sn].sManaCost - adj);
}
ma <<= 6;
if (sn == SPL_HEAL) {
ma = (spelldata[SPL_HEAL].sManaCost + 2 * plr[id]._pLevel - adj) << 6;
}
if (sn == SPL_HEALOTHER) {
ma = (spelldata[SPL_HEAL].sManaCost + 2 * plr[id]._pLevel - adj) << 6;
}
if (plr[id]._pClass == PC_ROGUE) {
ma -= ma >> 2;
}
if (spelldata[sn].sMinMana > ma >> 6) {
ma = spelldata[sn].sMinMana << 6;
}
return ma * (100 - plr[id]._pISplCost) / 100;
}
void UseMana(int id, int sn)
{
int ma; // mana cost
if (id == myplr) {
switch (plr[id]._pSplType) {
case RSPLTYPE_SKILL:
case RSPLTYPE_INVALID:
break;
case RSPLTYPE_SCROLL:
RemoveScroll(id);
break;
case RSPLTYPE_CHARGES:
UseStaffCharge(id);
break;
case RSPLTYPE_SPELL:
#ifdef _DEBUG
if (!debug_mode_key_inverted_v) {
#endif
ma = GetManaAmount(id, sn);
plr[id]._pMana -= ma;
plr[id]._pManaBase -= ma;
drawmanaflag = TRUE;
#ifdef _DEBUG
}
#endif
break;
}
}
}
BOOL CheckSpell(int id, int sn, char st, BOOL manaonly)
{
BOOL result;
#ifdef _DEBUG
if (debug_mode_key_inverted_v)
return TRUE;
#endif
result = TRUE;
if (!manaonly && pcurs != 1) {
result = FALSE;
} else {
if (st != RSPLTYPE_SKILL) {
if (GetSpellLevel(id, sn) <= 0) {
result = FALSE;
} else {
result = plr[id]._pMana >= GetManaAmount(id, sn);
}
}
}
return result;
}
void CastSpell(int id, int spl, int sx, int sy, int dx, int dy, int caster, int spllvl)
{
int i;
int dir; // missile direction
switch (caster) {
case 1:
dir = monster[id]._mdir;
break;
case 0:
// caster must be 0 already in this case, but oh well,
// it's needed to generate the right code
caster = 0;
dir = plr[id]._pdir;
if (spl == SPL_FIREWALL) {
dir = plr[id]._pVar3;
}
break;
}
for (i = 0; spelldata[spl].sMissiles[i] != MIS_ARROW && i < 3; i++) {
AddMissile(sx, sy, dx, dy, dir, spelldata[spl].sMissiles[i], caster, id, 0, spllvl);
}
if (spelldata[spl].sMissiles[0] == MIS_TOWN) {
UseMana(id, SPL_TOWN);
}
if (spelldata[spl].sMissiles[0] == MIS_CBOLT) {
UseMana(id, SPL_CBOLT);
for (i = (spllvl >> 1) + 3; i > 0; i--) {
AddMissile(sx, sy, dx, dy, dir, MIS_CBOLT, caster, id, 0, spllvl);
}
}
}
static void PlacePlayer(int pnum)
{
int nx, ny, max, min, x, y;
DWORD i;
BOOL done;
if (plr[pnum].plrlevel == currlevel) {
for (i = 0; i < 8; i++) {
nx = plr[pnum].WorldX + plrxoff2[i];
ny = plr[pnum].WorldY + plryoff2[i];
if (PosOkPlayer(pnum, nx, ny)) {
break;
}
}
if (!PosOkPlayer(pnum, nx, ny)) {
done = FALSE;
for (max = 1, min = -1; min > -50 && !done; max++, min--) {
for (y = min; y <= max && !done; y++) {
ny = plr[pnum].WorldY + y;
for (x = min; x <= max && !done; x++) {
nx = plr[pnum].WorldX + x;
if (PosOkPlayer(pnum, nx, ny)) {
done = TRUE;
}
}
}
}
}
plr[pnum].WorldX = nx;
plr[pnum].WorldY = ny;
dPlayer[nx][ny] = pnum + 1;
if (pnum == myplr) {
ViewX = nx;
ViewY = ny;
}
}
}
/**
* @param pnum player index
* @param rid target player index
*/
void DoResurrect(int pnum, int rid)
{
int hp;
if ((char)rid != -1) {
AddMissile(plr[rid].WorldX, plr[rid].WorldY, plr[rid].WorldX, plr[rid].WorldY, 0, MIS_RESURRECTBEAM, 0, pnum, 0, 0);
}
if (pnum == myplr) {
NewCursor(CURSOR_HAND);
}
if ((char)rid != -1 && plr[rid]._pHitPoints == 0) {
if (rid == myplr) {
deathflag = FALSE;
gamemenu_off();
drawhpflag = TRUE;
drawmanaflag = TRUE;
}
ClrPlrPath(rid);
plr[rid].destAction = ACTION_NONE;
plr[rid]._pInvincible = FALSE;
PlacePlayer(rid);
hp = 640;
if (plr[rid]._pMaxHPBase < 640) {
hp = plr[rid]._pMaxHPBase;
}
SetPlayerHitPoints(rid, hp);
plr[rid]._pHPBase = plr[rid]._pHitPoints + (plr[rid]._pMaxHPBase - plr[rid]._pMaxHP);
plr[rid]._pMana = 0;
plr[rid]._pManaBase = plr[rid]._pMana + (plr[rid]._pMaxManaBase - plr[rid]._pMaxMana);
CalcPlrInv(rid, TRUE);
if (plr[rid].plrlevel == currlevel) {
StartStand(rid, plr[rid]._pdir);
} else {
plr[rid]._pmode = PM_STAND;
}
}
}
void DoHealOther(int pnum, int rid)
{
int i, j, hp;
if (pnum == myplr) {
NewCursor(CURSOR_HAND);
}
if ((char)rid != -1 && (plr[rid]._pHitPoints >> 6) > 0) {
hp = (random_(57, 10) + 1) << 6;
for (i = 0; i < plr[pnum]._pLevel; i++) {
hp += (random_(57, 4) + 1) << 6;
}
for (j = 0; j < GetSpellLevel(pnum, SPL_HEALOTHER); ++j) {
hp += (random_(57, 6) + 1) << 6;
}
if (plr[pnum]._pClass == PC_WARRIOR) {
hp <<= 1;
}
if (plr[pnum]._pClass == PC_ROGUE) {
hp += hp >> 1;
}
plr[rid]._pHitPoints += hp;
if (plr[rid]._pHitPoints > plr[rid]._pMaxHP) {
plr[rid]._pHitPoints = plr[rid]._pMaxHP;
}
plr[rid]._pHPBase += hp;
if (plr[rid]._pHPBase > plr[rid]._pMaxHPBase) {
plr[rid]._pHPBase = plr[rid]._pMaxHPBase;
}
drawhpflag = TRUE;
}
}