Split spell by SpellActionType.
This commit is contained in:
parent
d6da2d2c21
commit
abfe3f2086
14 changed files with 997 additions and 593 deletions
|
@ -226,12 +226,6 @@ set(pathfinder_SRCS
|
|||
)
|
||||
source_group(pathfinder FILES ${pathfinder_SRCS})
|
||||
|
||||
set(spell_SRCS
|
||||
src/spell/script_spell.cpp
|
||||
src/spell/spells.cpp
|
||||
)
|
||||
source_group(spell FILES ${spell_SRCS})
|
||||
|
||||
set(sound_SRCS
|
||||
src/sound/mikmod.cpp
|
||||
src/sound/music.cpp
|
||||
|
@ -245,6 +239,22 @@ set(sound_SRCS
|
|||
)
|
||||
source_group(sound FILES ${sound_SRCS})
|
||||
|
||||
set(spell_SRCS
|
||||
src/spell/script_spell.cpp
|
||||
src/spell/spell_adjustvariable.cpp
|
||||
src/spell/spell_adjustvital.cpp
|
||||
src/spell/spell_areaadjustvital.cpp
|
||||
src/spell/spell_areabombardment.cpp
|
||||
src/spell/spell_capture.cpp
|
||||
src/spell/spell_demolish.cpp
|
||||
src/spell/spell_polymorph.cpp
|
||||
src/spell/spell_spawnmissile.cpp
|
||||
src/spell/spell_spawnportal.cpp
|
||||
src/spell/spell_summon.cpp
|
||||
src/spell/spells.cpp
|
||||
)
|
||||
source_group(spell FILES ${spell_SRCS})
|
||||
|
||||
set(stratagusmain_SRCS
|
||||
src/stratagus/construct.cpp
|
||||
src/stratagus/groups.cpp
|
||||
|
@ -349,8 +359,8 @@ set(stratagus_SRCS
|
|||
${network_SRCS}
|
||||
${particle_SRCS}
|
||||
${pathfinder_SRCS}
|
||||
${spell_SRCS}
|
||||
${sound_SRCS}
|
||||
${spell_SRCS}
|
||||
${stratagusmain_SRCS}
|
||||
${ui_SRCS}
|
||||
${unit_SRCS}
|
||||
|
|
|
@ -138,10 +138,10 @@ public:
|
|||
// Specific spells.
|
||||
//
|
||||
|
||||
class AreaAdjustVitals : public SpellActionType
|
||||
class AreaAdjustVital : public SpellActionType
|
||||
{
|
||||
public:
|
||||
AreaAdjustVitals() : HP(0), Mana(0) {};
|
||||
AreaAdjustVital() : HP(0), Mana(0) {};
|
||||
virtual int Cast(CUnit &caster, const SpellType &spell,
|
||||
CUnit *target, const Vec2i &goalPos);
|
||||
|
||||
|
@ -214,10 +214,10 @@ public:
|
|||
SpellActionTypeAdjustVariable *Var;
|
||||
};
|
||||
|
||||
class AdjustVitals : public SpellActionType
|
||||
class AdjustVital : public SpellActionType
|
||||
{
|
||||
public:
|
||||
AdjustVitals() : SpellActionType(1), HP(0), Mana(0), MaxMultiCast(0) {};
|
||||
AdjustVital() : SpellActionType(1), HP(0), Mana(0), MaxMultiCast(0) {};
|
||||
virtual int Cast(CUnit &caster, const SpellType &spell,
|
||||
CUnit *target, const Vec2i &goalPos);
|
||||
|
||||
|
|
|
@ -179,7 +179,7 @@ static SpellActionType *CclSpellAction(lua_State *l)
|
|||
}
|
||||
return spellaction;
|
||||
} else if (!strcmp(value, "area-adjust-vitals")) {
|
||||
AreaAdjustVitals *spellaction = new AreaAdjustVitals;
|
||||
AreaAdjustVital *spellaction = new AreaAdjustVital;
|
||||
for (; j < args; ++j) {
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
value = LuaToString(l, -1);
|
||||
|
@ -439,7 +439,7 @@ static SpellActionType *CclSpellAction(lua_State *l)
|
|||
}
|
||||
return spellaction;
|
||||
} else if (!strcmp(value, "adjust-vitals")) {
|
||||
AdjustVitals *spellaction = new AdjustVitals;
|
||||
AdjustVital *spellaction = new AdjustVital;
|
||||
for (; j < args; ++j) {
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
value = LuaToString(l, -1);
|
||||
|
|
89
src/spell/spell_adjustvariable.cpp
Normal file
89
src/spell/spell_adjustvariable.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_adjustvariable.cpp - The spell AdjustVariable. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
|
||||
/**
|
||||
** Adjust User Variables.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int AdjustVariable::Cast(CUnit &caster, const SpellType &, CUnit *target, const Vec2i &/*goalPos*/)
|
||||
{
|
||||
for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) {
|
||||
CUnit *unit = (this->Var[i].TargetIsCaster) ? &caster : target;
|
||||
|
||||
if (!unit) {
|
||||
continue;
|
||||
}
|
||||
// Enable flag.
|
||||
if (this->Var[i].ModifEnable) {
|
||||
unit->Variable[i].Enable = this->Var[i].Enable;
|
||||
}
|
||||
unit->Variable[i].Enable ^= this->Var[i].InvertEnable;
|
||||
|
||||
// Max field
|
||||
if (this->Var[i].ModifMax) {
|
||||
unit->Variable[i].Max = this->Var[i].Max;
|
||||
}
|
||||
unit->Variable[i].Max += this->Var[i].AddMax;
|
||||
|
||||
// Increase field
|
||||
if (this->Var[i].ModifIncrease) {
|
||||
unit->Variable[i].Increase = this->Var[i].Increase;
|
||||
}
|
||||
unit->Variable[i].Increase += this->Var[i].AddIncrease;
|
||||
|
||||
// Value field
|
||||
if (this->Var[i].ModifValue) {
|
||||
unit->Variable[i].Value = this->Var[i].Value;
|
||||
}
|
||||
unit->Variable[i].Value += this->Var[i].AddValue;
|
||||
unit->Variable[i].Value += this->Var[i].IncreaseTime * unit->Variable[i].Increase;
|
||||
|
||||
clamp(&unit->Variable[i].Value, 0, unit->Variable[i].Max);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//@}
|
122
src/spell/spell_adjustvital.cpp
Normal file
122
src/spell/spell_adjustvital.cpp
Normal file
|
@ -0,0 +1,122 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_adjustvital.cpp - The spell AdjustVital. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
|
||||
/**
|
||||
** Cast healing. (or exorcism)
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int AdjustVital::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &/*goalPos*/)
|
||||
{
|
||||
if (!target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int hp = this->HP;
|
||||
const int mana = this->Mana;
|
||||
const int manacost = spell.ManaCost;
|
||||
int diffHP;
|
||||
int diffMana;
|
||||
|
||||
// Healing and harming
|
||||
if (hp > 0) {
|
||||
diffHP = target->Variable[HP_INDEX].Max - target->Variable[HP_INDEX].Value;
|
||||
} else {
|
||||
diffHP = target->Variable[HP_INDEX].Value;
|
||||
}
|
||||
if (mana > 0) {
|
||||
diffMana = target->Stats->Variables[MANA_INDEX].Max - target->Variable[MANA_INDEX].Value;
|
||||
} else {
|
||||
diffMana = target->Variable[MANA_INDEX].Value;
|
||||
}
|
||||
|
||||
// When harming cast again to send the hp to negative values.
|
||||
// Carefull, a perfect 0 target hp kills too.
|
||||
// Avoid div by 0 errors too!
|
||||
int castcount = 1;
|
||||
if (hp) {
|
||||
castcount = std::max<int>(castcount,
|
||||
diffHP / abs(hp) + (((hp < 0) && (diffHP % (-hp) > 0)) ? 1 : 0));
|
||||
}
|
||||
if (mana) {
|
||||
castcount = std::max<int>(castcount,
|
||||
diffMana / abs(mana) + (((mana < 0) && (diffMana % (-mana) > 0)) ? 1 : 0));
|
||||
}
|
||||
if (manacost) {
|
||||
castcount = std::min<int>(castcount, caster.Variable[MANA_INDEX].Value / manacost);
|
||||
}
|
||||
if (this->MaxMultiCast) {
|
||||
castcount = std::min<int>(castcount, this->MaxMultiCast);
|
||||
}
|
||||
|
||||
caster.Variable[MANA_INDEX].Value -= castcount * manacost;
|
||||
if (hp < 0) {
|
||||
if (&caster != target) {
|
||||
HitUnit(&caster, *target, -(castcount * hp));
|
||||
} else {
|
||||
target->Variable[HP_INDEX].Value += castcount * hp;
|
||||
if (target->Variable[HP_INDEX].Value < 0) {
|
||||
target->Variable[HP_INDEX].Value = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target->Variable[HP_INDEX].Value += castcount * hp;
|
||||
if (target->Variable[HP_INDEX].Value > target->Variable[HP_INDEX].Max) {
|
||||
target->Variable[HP_INDEX].Value = target->Variable[HP_INDEX].Max;
|
||||
}
|
||||
}
|
||||
target->Variable[MANA_INDEX].Value += castcount * mana;
|
||||
if (target->Variable[MANA_INDEX].Value < 0) {
|
||||
target->Variable[MANA_INDEX].Value = 0;
|
||||
}
|
||||
if (target->Variable[MANA_INDEX].Value > target->Variable[MANA_INDEX].Max) {
|
||||
target->Variable[MANA_INDEX].Value = target->Variable[MANA_INDEX].Max;
|
||||
}
|
||||
if (spell.RepeatCast) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//@}
|
87
src/spell/spell_areaadjustvital.cpp
Normal file
87
src/spell/spell_areaadjustvital.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_areaadjustvital.cpp - The spell AreaAdjustVital. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "unit.h"
|
||||
|
||||
|
||||
/**
|
||||
** Cast Area Adjust Vital on all valid units in range.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int AreaAdjustVital::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
const Vec2i range(spell.Range, spell.Range);
|
||||
const Vec2i typeSize(caster.Type->Width, caster.Type->Height);
|
||||
std::vector<CUnit *> units;
|
||||
|
||||
// Get all the units around the unit
|
||||
Map.Select(goalPos - range, goalPos + typeSize + range, units);
|
||||
int hp = this->HP;
|
||||
int mana = this->Mana;
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
for (size_t j = 0; j != units.size(); ++j) {
|
||||
target = units[j];
|
||||
// if (!PassCondition(caster, spell, target, goalPos) {
|
||||
if (!CanCastSpell(caster, spell, target, goalPos)) {
|
||||
continue;
|
||||
}
|
||||
if (hp < 0) {
|
||||
HitUnit(&caster, *target, -hp);
|
||||
} else {
|
||||
target->Variable[HP_INDEX].Value += hp;
|
||||
if (target->Variable[HP_INDEX].Value > target->Variable[HP_INDEX].Max) {
|
||||
target->Variable[HP_INDEX].Value = target->Variable[HP_INDEX].Max;
|
||||
}
|
||||
}
|
||||
target->Variable[MANA_INDEX].Value += mana;
|
||||
if (target->Variable[MANA_INDEX].Value < 0) {
|
||||
target->Variable[MANA_INDEX].Value = 0;
|
||||
}
|
||||
if (target->Variable[MANA_INDEX].Value > target->Variable[MANA_INDEX].Max) {
|
||||
target->Variable[MANA_INDEX].Value = target->Variable[MANA_INDEX].Max;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//@}
|
91
src/spell/spell_areabombardment.cpp
Normal file
91
src/spell/spell_areabombardment.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_areabombardment.cpp - The spell AreaBombardment. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "missile.h"
|
||||
#include "unit.h"
|
||||
|
||||
/**
|
||||
** Cast area bombardment.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
** @internal: vladi: blizzard differs than original in this way:
|
||||
** original: launches 50 shards at 5 random spots x 10 for 25 mana.
|
||||
*/
|
||||
int AreaBombardment::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
|
||||
{
|
||||
int fields = this->Fields;
|
||||
const int shards = this->Shards;
|
||||
const int damage = this->Damage;
|
||||
const PixelDiff offset(this->StartOffsetX, this->StartOffsetY);
|
||||
const MissileType *missile = this->Missile;
|
||||
|
||||
while (fields--) {
|
||||
Vec2i dpos;
|
||||
|
||||
// FIXME: radius configurable...
|
||||
do {
|
||||
// find new destination in the map
|
||||
dpos.x = goalPos.x + SyncRand() % 5 - 2;
|
||||
dpos.y = goalPos.y + SyncRand() % 5 - 2;
|
||||
} while (!Map.Info.IsPointOnMap(dpos));
|
||||
|
||||
const PixelPos dest = Map.TilePosToMapPixelPos_Center(dpos);
|
||||
const PixelPos start = dest + offset;
|
||||
for (int i = 0; i < shards; ++i) {
|
||||
::Missile *mis = MakeMissile(*missile, start, dest);
|
||||
// FIXME: This is just patched up, it works, but I have no idea why.
|
||||
// FIXME: What is the reasoning behind all this?
|
||||
if (mis->Type->Speed) {
|
||||
mis->Delay = i * mis->Type->Sleep * 2 * PixelTileSize.x / mis->Type->Speed;
|
||||
} else {
|
||||
mis->Delay = i * mis->Type->Sleep * mis->Type->G->NumFrames;
|
||||
}
|
||||
mis->Damage = damage;
|
||||
// FIXME: not correct -- blizzard should continue even if mage is
|
||||
// destroyed (though it will be quite short time...)
|
||||
mis->SourceUnit = &caster;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//@}
|
99
src/spell/spell_capture.cpp
Normal file
99
src/spell/spell_capture.cpp
Normal file
|
@ -0,0 +1,99 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_capture.cpp - The spell Capture. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
/**
|
||||
** Cast capture.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Capture::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &/*goalPos*/)
|
||||
{
|
||||
if (!target || caster.Player == target->Player) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this->DamagePercent) {
|
||||
if ((100 * target->Variable[HP_INDEX].Value) /
|
||||
target->Variable[HP_INDEX].Max > this->DamagePercent &&
|
||||
target->Variable[HP_INDEX].Value > this->Damage) {
|
||||
HitUnit(&caster, *target, this->Damage);
|
||||
if (this->SacrificeEnable) {
|
||||
// No corpse.
|
||||
caster.Remove(NULL);
|
||||
UnitLost(caster);
|
||||
UnitClearOrders(caster);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
caster.Player->Score += target->Variable[POINTS_INDEX].Value;
|
||||
if (caster.IsEnemy(*target)) {
|
||||
if (target->Type->Building) {
|
||||
caster.Player->TotalRazings++;
|
||||
} else {
|
||||
caster.Player->TotalKills++;
|
||||
}
|
||||
if (UseHPForXp) {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value;
|
||||
} else {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value;
|
||||
}
|
||||
caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max;
|
||||
caster.Variable[KILL_INDEX].Value++;
|
||||
caster.Variable[KILL_INDEX].Max++;
|
||||
caster.Variable[KILL_INDEX].Enable = 1;
|
||||
}
|
||||
target->ChangeOwner(*caster.Player);
|
||||
if (this->SacrificeEnable) {
|
||||
// No corpse.
|
||||
caster.Remove(NULL);
|
||||
UnitLost(caster);
|
||||
UnitClearOrders(caster);
|
||||
} else {
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
}
|
||||
UnitClearOrders(*target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//@}
|
98
src/spell/spell_demolish.cpp
Normal file
98
src/spell/spell_demolish.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_demolish.cpp - The spell demolish. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "map.h"
|
||||
|
||||
/**
|
||||
** Cast demolish
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos tilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Demolish::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
|
||||
{
|
||||
// Allow error margins. (Lame, I know)
|
||||
const Vec2i offset(this->Range + 2, this->Range + 2);
|
||||
Vec2i minpos = goalPos - offset;
|
||||
Vec2i maxpos = goalPos + offset;
|
||||
|
||||
Map.FixSelectionArea(minpos, maxpos);
|
||||
|
||||
//
|
||||
// Terrain effect of the explosion
|
||||
//
|
||||
Vec2i ipos;
|
||||
for (ipos.x = minpos.x; ipos.x <= maxpos.x; ++ipos.x) {
|
||||
for (ipos.y = minpos.y; ipos.y <= maxpos.y; ++ipos.y) {
|
||||
const int flag = Map.Field(ipos)->Flags;
|
||||
if (SquareDistance(ipos, goalPos) > square(this->Range)) {
|
||||
// Not in circle range
|
||||
continue;
|
||||
} else if (flag & MapFieldWall) {
|
||||
Map.RemoveWall(ipos);
|
||||
} else if (flag & MapFieldRocks) {
|
||||
Map.ClearTile(MapFieldRocks, ipos);
|
||||
} else if (flag & MapFieldForest) {
|
||||
Map.ClearTile(MapFieldForest, ipos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Effect of the explosion on units. Don't bother if damage is 0
|
||||
//
|
||||
if (this->Damage) {
|
||||
std::vector<CUnit *> table;
|
||||
Map.SelectFixed(minpos, maxpos, table);
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
CUnit &unit = *table[i];
|
||||
if (unit.Type->UnitType != UnitTypeFly && unit.IsAlive()
|
||||
&& unit.MapDistanceTo(goalPos) <= this->Range) {
|
||||
// Don't hit flying units!
|
||||
HitUnit(&caster, unit, this->Damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//@}
|
101
src/spell/spell_polymorph.cpp
Normal file
101
src/spell/spell_polymorph.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_polymorph.cpp - The spell Polymorph. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "unit.h"
|
||||
|
||||
/**
|
||||
** Cast polymorph.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Polymorph::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
if (!target) {
|
||||
return 0;
|
||||
}
|
||||
CUnitType &type = *this->NewForm;
|
||||
const Vec2i pos(goalPos - type.GetHalfTileSize());
|
||||
|
||||
caster.Player->Score += target->Variable[POINTS_INDEX].Value;
|
||||
if (caster.IsEnemy(*target)) {
|
||||
if (target->Type->Building) {
|
||||
caster.Player->TotalRazings++;
|
||||
} else {
|
||||
caster.Player->TotalKills++;
|
||||
}
|
||||
if (UseHPForXp) {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value;
|
||||
} else {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value;
|
||||
}
|
||||
caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max;
|
||||
caster.Variable[KILL_INDEX].Value++;
|
||||
caster.Variable[KILL_INDEX].Max++;
|
||||
caster.Variable[KILL_INDEX].Enable = 1;
|
||||
}
|
||||
|
||||
// as said somewhere else -- no corpses :)
|
||||
target->Remove(NULL);
|
||||
Vec2i offset;
|
||||
for (offset.x = 0; offset.x < type.TileWidth; ++offset.x) {
|
||||
for (offset.y = 0; offset.y < type.TileHeight; ++offset.y) {
|
||||
if (!UnitTypeCanBeAt(type, pos + offset)) {
|
||||
target->Place(target->tilePos);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
if (this->PlayerNeutral == 1) {
|
||||
MakeUnitAndPlace(pos, type, Players + PlayerNumNeutral);
|
||||
} else if (this->PlayerNeutral == 2) {
|
||||
MakeUnitAndPlace(pos, type, caster.Player);
|
||||
} else {
|
||||
MakeUnitAndPlace(pos, type, target->Player);
|
||||
}
|
||||
UnitLost(*target);
|
||||
UnitClearOrders(*target);
|
||||
target->Release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
//@}
|
106
src/spell/spell_spawnmissile.cpp
Normal file
106
src/spell/spell_spawnmissile.cpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_spawnmissile.cpp - The spell SpawnMissile. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "map.h"
|
||||
#include "missile.h"
|
||||
#include "unit.h"
|
||||
|
||||
|
||||
/**
|
||||
** Evaluate missile location description.
|
||||
**
|
||||
** @param location Parameters for location.
|
||||
** @param caster Unit that casts the spell
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
** @param res pointer to PixelPos of the result
|
||||
*/
|
||||
static void EvaluateMissileLocation(const SpellActionMissileLocation &location,
|
||||
CUnit &caster, CUnit *target, const Vec2i &goalPos, PixelPos *res)
|
||||
{
|
||||
if (location.Base == LocBaseCaster) {
|
||||
*res = caster.GetMapPixelPosCenter();
|
||||
} else {
|
||||
if (target) {
|
||||
*res = target->GetMapPixelPosCenter();
|
||||
} else {
|
||||
*res = Map.TilePosToMapPixelPos_Center(goalPos);
|
||||
}
|
||||
}
|
||||
res->x += location.AddX;
|
||||
if (location.AddRandX) {
|
||||
res->x += SyncRand() % location.AddRandX;
|
||||
}
|
||||
res->y += location.AddY;
|
||||
if (location.AddRandY) {
|
||||
res->y += SyncRand() % location.AddRandY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast spawn missile.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int SpawnMissile::Cast(CUnit &caster, const SpellType &, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
PixelPos startPos;
|
||||
PixelPos endPos;
|
||||
|
||||
EvaluateMissileLocation(this->StartPoint, caster, target, goalPos, &startPos);
|
||||
EvaluateMissileLocation(this->EndPoint, caster, target, goalPos, &endPos);
|
||||
|
||||
::Missile *missile = MakeMissile(*this->Missile, startPos, endPos);
|
||||
missile->TTL = this->TTL;
|
||||
missile->Delay = this->Delay;
|
||||
missile->Damage = this->Damage;
|
||||
if (this->UseUnitVar) {
|
||||
missile->Damage = 0;
|
||||
missile->SourceUnit = &caster;
|
||||
} else if (missile->Damage != 0) {
|
||||
missile->SourceUnit = &caster;
|
||||
}
|
||||
missile->TargetUnit = target;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//@}
|
68
src/spell/spell_spawnportal.cpp
Normal file
68
src/spell/spell_spawnportal.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_spawnportal.cpp - The spell SpawnPortal. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
/**
|
||||
** Cast circle of power.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos tilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int SpawnPortal::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
|
||||
{
|
||||
// FIXME: vladi: cop should be placed only on explored land
|
||||
CUnit *portal = caster.Goal;
|
||||
|
||||
DebugPrint("Spawning a portal exit.\n");
|
||||
if (portal) {
|
||||
portal->MoveToXY(goalPos);
|
||||
} else {
|
||||
portal = MakeUnitAndPlace(goalPos, *this->PortalType, &Players[PlayerNumNeutral]);
|
||||
}
|
||||
// Goal is used to link to destination circle of power
|
||||
caster.Goal = portal;
|
||||
//FIXME: setting destination circle of power should use mana
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//@}
|
112
src/spell/spell_summon.cpp
Normal file
112
src/spell/spell_summon.cpp
Normal file
|
@ -0,0 +1,112 @@
|
|||
// _________ __ __
|
||||
// / _____// |_____________ _/ |______ ____ __ __ ______
|
||||
// \_____ \\ __\_ __ \__ \\ __\__ \ / ___\| | \/ ___/
|
||||
// / \| | | | \// __ \| | / __ \_/ /_/ > | /\___ |
|
||||
// /_______ /|__| |__| (____ /__| (____ /\___ /|____//____ >
|
||||
// \/ \/ \//_____/ \/
|
||||
// ______________________ ______________________
|
||||
// T H E W A R B E G I N S
|
||||
// Stratagus - A free fantasy real time strategy game engine
|
||||
//
|
||||
/**@name spell_summon.cpp - The spell Summon. */
|
||||
//
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// 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; only version 2 of the License.
|
||||
//
|
||||
// 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., 59 Temple Place - Suite 330, Boston, MA
|
||||
// 02111-1307, USA.
|
||||
//
|
||||
|
||||
//@{
|
||||
|
||||
#include "stratagus.h"
|
||||
|
||||
#include "spells.h"
|
||||
|
||||
#include "actions.h"
|
||||
#include "map.h"
|
||||
#include "unit.h"
|
||||
|
||||
class IsDyingAndNotABuilding
|
||||
{
|
||||
public:
|
||||
bool operator()(const CUnit *unit) const {
|
||||
return unit->CurrentAction() == UnitActionDie && !unit->Type->Building;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** Cast summon spell.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Summon::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
Vec2i pos = goalPos;
|
||||
bool cansummon;
|
||||
CUnitType &unittype = *this->UnitType;
|
||||
int ttl = this->TTL;
|
||||
|
||||
if (this->RequireCorpse) {
|
||||
const Vec2i offset(1, 1);
|
||||
const Vec2i minPos = pos - offset;
|
||||
const Vec2i maxPos = pos + offset;
|
||||
|
||||
CUnit *unit = Map.Find_If(minPos, maxPos, IsDyingAndNotABuilding());
|
||||
cansummon = false;
|
||||
|
||||
if (unit != NULL) { // Found a corpse. eliminate it and proceed to summoning.
|
||||
pos = unit->tilePos;
|
||||
unit->Remove(NULL);
|
||||
unit->Release();
|
||||
cansummon = true;
|
||||
}
|
||||
} else {
|
||||
cansummon = true;
|
||||
}
|
||||
|
||||
if (cansummon) {
|
||||
DebugPrint("Summoning a %s\n" _C_ unittype.Name.c_str());
|
||||
|
||||
//
|
||||
// Create units.
|
||||
// FIXME: do summoned units count on food?
|
||||
//
|
||||
target = MakeUnit(unittype, caster.Player);
|
||||
if (target != NULL) {
|
||||
target->tilePos = pos;
|
||||
DropOutOnSide(*target, LookingW, NULL);
|
||||
//
|
||||
// set life span. ttl=0 results in a permanent unit.
|
||||
//
|
||||
if (ttl) {
|
||||
target->TTL = GameCycle + ttl;
|
||||
}
|
||||
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
} else {
|
||||
DebugPrint("Unable to allocate Unit");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//@}
|
|
@ -10,7 +10,7 @@
|
|||
//
|
||||
/**@name spells.cpp - The spell cast action. */
|
||||
//
|
||||
// (c) Copyright 1998-2006 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// (c) Copyright 1998-2012 by Vladi Belperchinov-Shabanski, Lutz Sammer,
|
||||
// Jimmy Salmon, and Joris DAUPHIN
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
|
@ -38,10 +38,6 @@
|
|||
|
||||
//@{
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Notes
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Includes
|
||||
----------------------------------------------------------------------------*/
|
||||
|
@ -50,14 +46,9 @@
|
|||
|
||||
#include "spells.h"
|
||||
|
||||
#include "actions.h"
|
||||
#include "commands.h"
|
||||
#include "map.h"
|
||||
#include "missile.h"
|
||||
#include "sound.h"
|
||||
#include "tileset.h"
|
||||
#include "ui.h"
|
||||
#include "unittype.h"
|
||||
#include "upgrade.h"
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
@ -74,576 +65,6 @@ std::vector<SpellType *> SpellTypeTable;
|
|||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
// ****************************************************************************
|
||||
// Cast the Spell
|
||||
// ****************************************************************************
|
||||
|
||||
/**
|
||||
** Cast demolish
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos tilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Demolish::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
|
||||
{
|
||||
// Allow error margins. (Lame, I know)
|
||||
const Vec2i offset(this->Range + 2, this->Range + 2);
|
||||
Vec2i minpos = goalPos - offset;
|
||||
Vec2i maxpos = goalPos + offset;
|
||||
|
||||
Map.FixSelectionArea(minpos, maxpos);
|
||||
|
||||
//
|
||||
// Terrain effect of the explosion
|
||||
//
|
||||
Vec2i ipos;
|
||||
for (ipos.x = minpos.x; ipos.x <= maxpos.x; ++ipos.x) {
|
||||
for (ipos.y = minpos.y; ipos.y <= maxpos.y; ++ipos.y) {
|
||||
const int flag = Map.Field(ipos)->Flags;
|
||||
if (SquareDistance(ipos, goalPos) > square(this->Range)) {
|
||||
// Not in circle range
|
||||
continue;
|
||||
} else if (flag & MapFieldWall) {
|
||||
Map.RemoveWall(ipos);
|
||||
} else if (flag & MapFieldRocks) {
|
||||
Map.ClearTile(MapFieldRocks, ipos);
|
||||
} else if (flag & MapFieldForest) {
|
||||
Map.ClearTile(MapFieldForest, ipos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Effect of the explosion on units. Don't bother if damage is 0
|
||||
//
|
||||
if (this->Damage) {
|
||||
std::vector<CUnit *> table;
|
||||
Map.SelectFixed(minpos, maxpos, table);
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
CUnit &unit = *table[i];
|
||||
if (unit.Type->UnitType != UnitTypeFly && unit.IsAlive()
|
||||
&& unit.MapDistanceTo(goalPos) <= this->Range) {
|
||||
// Don't hit flying units!
|
||||
HitUnit(&caster, unit, this->Damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast circle of power.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos tilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int SpawnPortal::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
|
||||
{
|
||||
// FIXME: vladi: cop should be placed only on explored land
|
||||
CUnit *portal = caster.Goal;
|
||||
|
||||
DebugPrint("Spawning a portal exit.\n");
|
||||
if (portal) {
|
||||
portal->MoveToXY(goalPos);
|
||||
} else {
|
||||
portal = MakeUnitAndPlace(goalPos, *this->PortalType, &Players[PlayerNumNeutral]);
|
||||
}
|
||||
// Goal is used to link to destination circle of power
|
||||
caster.Goal = portal;
|
||||
//FIXME: setting destination circle of power should use mana
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast Area Adjust Vitals on all valid units in range.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int AreaAdjustVitals::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
const Vec2i range(spell.Range, spell.Range);
|
||||
const Vec2i typeSize(caster.Type->Width, caster.Type->Height);
|
||||
std::vector<CUnit *> units;
|
||||
|
||||
// Get all the units around the unit
|
||||
Map.Select(goalPos - range, goalPos + typeSize + range, units);
|
||||
int hp = this->HP;
|
||||
int mana = this->Mana;
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
for (size_t j = 0; j != units.size(); ++j) {
|
||||
target = units[j];
|
||||
// if (!PassCondition(caster, spell, target, goalPos) {
|
||||
if (!CanCastSpell(caster, spell, target, goalPos)) {
|
||||
continue;
|
||||
}
|
||||
if (hp < 0) {
|
||||
HitUnit(&caster, *target, -hp);
|
||||
} else {
|
||||
target->Variable[HP_INDEX].Value += hp;
|
||||
if (target->Variable[HP_INDEX].Value > target->Variable[HP_INDEX].Max) {
|
||||
target->Variable[HP_INDEX].Value = target->Variable[HP_INDEX].Max;
|
||||
}
|
||||
}
|
||||
target->Variable[MANA_INDEX].Value += mana;
|
||||
if (target->Variable[MANA_INDEX].Value < 0) {
|
||||
target->Variable[MANA_INDEX].Value = 0;
|
||||
}
|
||||
if (target->Variable[MANA_INDEX].Value > target->Variable[MANA_INDEX].Max) {
|
||||
target->Variable[MANA_INDEX].Value = target->Variable[MANA_INDEX].Max;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast area bombardment.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
** @internal: vladi: blizzard differs than original in this way:
|
||||
** original: launches 50 shards at 5 random spots x 10 for 25 mana.
|
||||
*/
|
||||
int AreaBombardment::Cast(CUnit &caster, const SpellType &, CUnit *, const Vec2i &goalPos)
|
||||
{
|
||||
int fields = this->Fields;
|
||||
const int shards = this->Shards;
|
||||
const int damage = this->Damage;
|
||||
const PixelDiff offset(this->StartOffsetX, this->StartOffsetY);
|
||||
const MissileType *missile = this->Missile;
|
||||
|
||||
while (fields--) {
|
||||
Vec2i dpos;
|
||||
|
||||
// FIXME: radius configurable...
|
||||
do {
|
||||
// find new destination in the map
|
||||
dpos.x = goalPos.x + SyncRand() % 5 - 2;
|
||||
dpos.y = goalPos.y + SyncRand() % 5 - 2;
|
||||
} while (!Map.Info.IsPointOnMap(dpos));
|
||||
|
||||
const PixelPos dest = Map.TilePosToMapPixelPos_Center(dpos);
|
||||
const PixelPos start = dest + offset;
|
||||
for (int i = 0; i < shards; ++i) {
|
||||
::Missile *mis = MakeMissile(*missile, start, dest);
|
||||
// FIXME: This is just patched up, it works, but I have no idea why.
|
||||
// FIXME: What is the reasoning behind all this?
|
||||
if (mis->Type->Speed) {
|
||||
mis->Delay = i * mis->Type->Sleep * 2 * PixelTileSize.x / mis->Type->Speed;
|
||||
} else {
|
||||
mis->Delay = i * mis->Type->Sleep * mis->Type->G->NumFrames;
|
||||
}
|
||||
mis->Damage = damage;
|
||||
// FIXME: not correct -- blizzard should continue even if mage is
|
||||
// destroyed (though it will be quite short time...)
|
||||
mis->SourceUnit = &caster;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Evaluate missile location description.
|
||||
**
|
||||
** @param location Parameters for location.
|
||||
** @param caster Unit that casts the spell
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
** @param res pointer to PixelPos of the result
|
||||
*/
|
||||
static void EvaluateMissileLocation(const SpellActionMissileLocation &location,
|
||||
CUnit &caster, CUnit *target, const Vec2i &goalPos, PixelPos *res)
|
||||
{
|
||||
if (location.Base == LocBaseCaster) {
|
||||
*res = caster.GetMapPixelPosCenter();
|
||||
} else {
|
||||
if (target) {
|
||||
*res = target->GetMapPixelPosCenter();
|
||||
} else {
|
||||
*res = Map.TilePosToMapPixelPos_Center(goalPos);
|
||||
}
|
||||
}
|
||||
res->x += location.AddX;
|
||||
if (location.AddRandX) {
|
||||
res->x += SyncRand() % location.AddRandX;
|
||||
}
|
||||
res->y += location.AddY;
|
||||
if (location.AddRandY) {
|
||||
res->y += SyncRand() % location.AddRandY;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast spawn missile.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos TilePos of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int SpawnMissile::Cast(CUnit &caster, const SpellType &, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
PixelPos startPos;
|
||||
PixelPos endPos;
|
||||
|
||||
EvaluateMissileLocation(this->StartPoint, caster, target, goalPos, &startPos);
|
||||
EvaluateMissileLocation(this->EndPoint, caster, target, goalPos, &endPos);
|
||||
|
||||
::Missile *missile = MakeMissile(*this->Missile, startPos, endPos);
|
||||
missile->TTL = this->TTL;
|
||||
missile->Delay = this->Delay;
|
||||
missile->Damage = this->Damage;
|
||||
if (this->UseUnitVar) {
|
||||
missile->Damage = 0;
|
||||
missile->SourceUnit = &caster;
|
||||
} else if (missile->Damage != 0) {
|
||||
missile->SourceUnit = &caster;
|
||||
}
|
||||
missile->TargetUnit = target;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Adjust User Variables.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int AdjustVariable::Cast(CUnit &caster, const SpellType &, CUnit *target, const Vec2i &/*goalPos*/)
|
||||
{
|
||||
for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) {
|
||||
CUnit *unit = (this->Var[i].TargetIsCaster) ? &caster : target;
|
||||
|
||||
if (!unit) {
|
||||
continue;
|
||||
}
|
||||
// Enable flag.
|
||||
if (this->Var[i].ModifEnable) {
|
||||
unit->Variable[i].Enable = this->Var[i].Enable;
|
||||
}
|
||||
unit->Variable[i].Enable ^= this->Var[i].InvertEnable;
|
||||
|
||||
// Max field
|
||||
if (this->Var[i].ModifMax) {
|
||||
unit->Variable[i].Max = this->Var[i].Max;
|
||||
}
|
||||
unit->Variable[i].Max += this->Var[i].AddMax;
|
||||
|
||||
// Increase field
|
||||
if (this->Var[i].ModifIncrease) {
|
||||
unit->Variable[i].Increase = this->Var[i].Increase;
|
||||
}
|
||||
unit->Variable[i].Increase += this->Var[i].AddIncrease;
|
||||
|
||||
// Value field
|
||||
if (this->Var[i].ModifValue) {
|
||||
unit->Variable[i].Value = this->Var[i].Value;
|
||||
}
|
||||
unit->Variable[i].Value += this->Var[i].AddValue;
|
||||
unit->Variable[i].Value += this->Var[i].IncreaseTime * unit->Variable[i].Increase;
|
||||
|
||||
clamp(&unit->Variable[i].Value, 0, unit->Variable[i].Max);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** Cast healing. (or exorcism)
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int AdjustVitals::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &/*goalPos*/)
|
||||
{
|
||||
if (!target) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int hp = this->HP;
|
||||
const int mana = this->Mana;
|
||||
const int manacost = spell.ManaCost;
|
||||
int diffHP;
|
||||
int diffMana;
|
||||
|
||||
// Healing and harming
|
||||
if (hp > 0) {
|
||||
diffHP = target->Variable[HP_INDEX].Max - target->Variable[HP_INDEX].Value;
|
||||
} else {
|
||||
diffHP = target->Variable[HP_INDEX].Value;
|
||||
}
|
||||
if (mana > 0) {
|
||||
diffMana = target->Stats->Variables[MANA_INDEX].Max - target->Variable[MANA_INDEX].Value;
|
||||
} else {
|
||||
diffMana = target->Variable[MANA_INDEX].Value;
|
||||
}
|
||||
|
||||
// When harming cast again to send the hp to negative values.
|
||||
// Carefull, a perfect 0 target hp kills too.
|
||||
// Avoid div by 0 errors too!
|
||||
int castcount = 1;
|
||||
if (hp) {
|
||||
castcount = std::max<int>(castcount,
|
||||
diffHP / abs(hp) + (((hp < 0) && (diffHP % (-hp) > 0)) ? 1 : 0));
|
||||
}
|
||||
if (mana) {
|
||||
castcount = std::max<int>(castcount,
|
||||
diffMana / abs(mana) + (((mana < 0) && (diffMana % (-mana) > 0)) ? 1 : 0));
|
||||
}
|
||||
if (manacost) {
|
||||
castcount = std::min<int>(castcount, caster.Variable[MANA_INDEX].Value / manacost);
|
||||
}
|
||||
if (this->MaxMultiCast) {
|
||||
castcount = std::min<int>(castcount, this->MaxMultiCast);
|
||||
}
|
||||
|
||||
caster.Variable[MANA_INDEX].Value -= castcount * manacost;
|
||||
if (hp < 0) {
|
||||
if (&caster != target) {
|
||||
HitUnit(&caster, *target, -(castcount * hp));
|
||||
} else {
|
||||
target->Variable[HP_INDEX].Value += castcount * hp;
|
||||
if (target->Variable[HP_INDEX].Value < 0) {
|
||||
target->Variable[HP_INDEX].Value = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
target->Variable[HP_INDEX].Value += castcount * hp;
|
||||
if (target->Variable[HP_INDEX].Value > target->Variable[HP_INDEX].Max) {
|
||||
target->Variable[HP_INDEX].Value = target->Variable[HP_INDEX].Max;
|
||||
}
|
||||
}
|
||||
target->Variable[MANA_INDEX].Value += castcount * mana;
|
||||
if (target->Variable[MANA_INDEX].Value < 0) {
|
||||
target->Variable[MANA_INDEX].Value = 0;
|
||||
}
|
||||
if (target->Variable[MANA_INDEX].Value > target->Variable[MANA_INDEX].Max) {
|
||||
target->Variable[MANA_INDEX].Value = target->Variable[MANA_INDEX].Max;
|
||||
}
|
||||
if (spell.RepeatCast) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast polymorph.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Polymorph::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
if (!target) {
|
||||
return 0;
|
||||
}
|
||||
CUnitType &type = *this->NewForm;
|
||||
const Vec2i pos(goalPos - type.GetHalfTileSize());
|
||||
|
||||
caster.Player->Score += target->Variable[POINTS_INDEX].Value;
|
||||
if (caster.IsEnemy(*target)) {
|
||||
if (target->Type->Building) {
|
||||
caster.Player->TotalRazings++;
|
||||
} else {
|
||||
caster.Player->TotalKills++;
|
||||
}
|
||||
if (UseHPForXp) {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value;
|
||||
} else {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value;
|
||||
}
|
||||
caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max;
|
||||
caster.Variable[KILL_INDEX].Value++;
|
||||
caster.Variable[KILL_INDEX].Max++;
|
||||
caster.Variable[KILL_INDEX].Enable = 1;
|
||||
}
|
||||
|
||||
// as said somewhere else -- no corpses :)
|
||||
target->Remove(NULL);
|
||||
Vec2i offset;
|
||||
for (offset.x = 0; offset.x < type.TileWidth; ++offset.x) {
|
||||
for (offset.y = 0; offset.y < type.TileHeight; ++offset.y) {
|
||||
if (!UnitTypeCanBeAt(type, pos + offset)) {
|
||||
target->Place(target->tilePos);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
if (this->PlayerNeutral == 1) {
|
||||
MakeUnitAndPlace(pos, type, Players + PlayerNumNeutral);
|
||||
} else if (this->PlayerNeutral == 2) {
|
||||
MakeUnitAndPlace(pos, type, caster.Player);
|
||||
} else {
|
||||
MakeUnitAndPlace(pos, type, target->Player);
|
||||
}
|
||||
UnitLost(*target);
|
||||
UnitClearOrders(*target);
|
||||
target->Release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
** Cast capture.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Capture::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &/*goalPos*/)
|
||||
{
|
||||
if (!target || caster.Player == target->Player) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (this->DamagePercent) {
|
||||
if ((100 * target->Variable[HP_INDEX].Value) /
|
||||
target->Variable[HP_INDEX].Max > this->DamagePercent &&
|
||||
target->Variable[HP_INDEX].Value > this->Damage) {
|
||||
HitUnit(&caster, *target, this->Damage);
|
||||
if (this->SacrificeEnable) {
|
||||
// No corpse.
|
||||
caster.Remove(NULL);
|
||||
UnitLost(caster);
|
||||
UnitClearOrders(caster);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
caster.Player->Score += target->Variable[POINTS_INDEX].Value;
|
||||
if (caster.IsEnemy(*target)) {
|
||||
if (target->Type->Building) {
|
||||
caster.Player->TotalRazings++;
|
||||
} else {
|
||||
caster.Player->TotalKills++;
|
||||
}
|
||||
if (UseHPForXp) {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[HP_INDEX].Value;
|
||||
} else {
|
||||
caster.Variable[XP_INDEX].Max += target->Variable[POINTS_INDEX].Value;
|
||||
}
|
||||
caster.Variable[XP_INDEX].Value = caster.Variable[XP_INDEX].Max;
|
||||
caster.Variable[KILL_INDEX].Value++;
|
||||
caster.Variable[KILL_INDEX].Max++;
|
||||
caster.Variable[KILL_INDEX].Enable = 1;
|
||||
}
|
||||
target->ChangeOwner(*caster.Player);
|
||||
if (this->SacrificeEnable) {
|
||||
// No corpse.
|
||||
caster.Remove(NULL);
|
||||
UnitLost(caster);
|
||||
UnitClearOrders(caster);
|
||||
} else {
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
}
|
||||
UnitClearOrders(*target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
class IsDyingAndNotABuilding
|
||||
{
|
||||
public:
|
||||
bool operator()(const CUnit *unit) const {
|
||||
return unit->CurrentAction() == UnitActionDie && !unit->Type->Building;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
** Cast summon spell.
|
||||
**
|
||||
** @param caster Unit that casts the spell
|
||||
** @param spell Spell-type pointer
|
||||
** @param target Target unit that spell is addressed to
|
||||
** @param goalPos coord of target spot when/if target does not exist
|
||||
**
|
||||
** @return =!0 if spell should be repeated, 0 if not
|
||||
*/
|
||||
int Summon::Cast(CUnit &caster, const SpellType &spell, CUnit *target, const Vec2i &goalPos)
|
||||
{
|
||||
Vec2i pos = goalPos;
|
||||
bool cansummon;
|
||||
CUnitType &unittype = *this->UnitType;
|
||||
int ttl = this->TTL;
|
||||
|
||||
if (this->RequireCorpse) {
|
||||
const Vec2i offset(1, 1);
|
||||
const Vec2i minPos = pos - offset;
|
||||
const Vec2i maxPos = pos + offset;
|
||||
|
||||
CUnit *unit = Map.Find_If(minPos, maxPos, IsDyingAndNotABuilding());
|
||||
cansummon = false;
|
||||
|
||||
if (unit != NULL) { // Found a corpse. eliminate it and proceed to summoning.
|
||||
pos = unit->tilePos;
|
||||
unit->Remove(NULL);
|
||||
unit->Release();
|
||||
cansummon = true;
|
||||
}
|
||||
} else {
|
||||
cansummon = true;
|
||||
}
|
||||
|
||||
if (cansummon) {
|
||||
DebugPrint("Summoning a %s\n" _C_ unittype.Name.c_str());
|
||||
|
||||
//
|
||||
// Create units.
|
||||
// FIXME: do summoned units count on food?
|
||||
//
|
||||
target = MakeUnit(unittype, caster.Player);
|
||||
if (target != NULL) {
|
||||
target->tilePos = pos;
|
||||
DropOutOnSide(*target, LookingW, NULL);
|
||||
//
|
||||
// set life span. ttl=0 results in a permanent unit.
|
||||
//
|
||||
if (ttl) {
|
||||
target->TTL = GameCycle + ttl;
|
||||
}
|
||||
|
||||
caster.Variable[MANA_INDEX].Value -= spell.ManaCost;
|
||||
} else {
|
||||
DebugPrint("Unable to allocate Unit");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Target constructor
|
||||
// ****************************************************************************
|
||||
|
|
Loading…
Reference in a new issue