[*] Correct Death Coil spell casting
This commit is contained in:
parent
446a0a9454
commit
d47fdf52bd
5 changed files with 87 additions and 39 deletions
|
@ -167,6 +167,7 @@ enum {
|
|||
NONSOLID_INDEX,
|
||||
WALL_INDEX,
|
||||
NORANDOMPLACING_INDEX,
|
||||
ORGANIC_INDEX,
|
||||
NBARALREADYDEFINED
|
||||
};
|
||||
|
||||
|
@ -565,6 +566,7 @@ public:
|
|||
unsigned NonSolid : 1; /// Unit can be entered by other units.
|
||||
unsigned Wall : 1; /// Use special logic for Direction field.
|
||||
unsigned NoRandomPlacing : 1; /// Don't use random frame rotation
|
||||
unsigned Organic : 1; /// Organic unit (used for death coil spell)
|
||||
|
||||
CUnitStats DefaultStat;
|
||||
struct BoolFlags {
|
||||
|
|
|
@ -53,6 +53,9 @@ void MissileDeathCoil::Action()
|
|||
if (PointToPointMissile(*this) == false) {
|
||||
return;
|
||||
}
|
||||
if (this->NextMissileFrame(1, 0) == false) {
|
||||
return;
|
||||
}
|
||||
Assert(this->SourceUnit != NULL);
|
||||
CUnit &source = *this->SourceUnit;
|
||||
|
||||
|
@ -63,36 +66,12 @@ void MissileDeathCoil::Action()
|
|||
//
|
||||
// Target unit still exists and casted on a special target
|
||||
//
|
||||
if (this->TargetUnit && !this->TargetUnit->Destroyed
|
||||
&& this->TargetUnit->CurrentAction() == UnitActionDie) {
|
||||
if (this->TargetUnit && this->TargetUnit->IsAlive()) {
|
||||
HitUnit(&source, *this->TargetUnit, this->Damage);
|
||||
if (source.CurrentAction() != UnitActionDie) {
|
||||
source.Variable[HP_INDEX].Value += this->Damage;
|
||||
source.Variable[HP_INDEX].Value = std::min(source.Variable[HP_INDEX].Max, source.Variable[HP_INDEX].Value);
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// No target unit -- try enemies in range 5x5 // Must be parametrable
|
||||
//
|
||||
std::vector<CUnit *> table;
|
||||
const Vec2i destPos = Map.MapPixelPosToTilePos(this->destination);
|
||||
const Vec2i range(2, 2);
|
||||
Select(destPos - range, destPos + range, table, IsEnemyWith(*source.Player));
|
||||
|
||||
if (table.empty()) {
|
||||
return;
|
||||
}
|
||||
const size_t n = table.size(); // enemy count
|
||||
const int damage = std::min<int>(1, this->Damage / n);
|
||||
|
||||
// disperse damage between them
|
||||
for (size_t i = 0; i != n; ++i) {
|
||||
HitUnit(&source, *table[i], damage);
|
||||
}
|
||||
if (source.CurrentAction() != UnitActionDie) {
|
||||
source.Variable[HP_INDEX].Value += this->Damage;
|
||||
source.Variable[HP_INDEX].Value = std::min(source.Variable[HP_INDEX].Max, source.Variable[HP_INDEX].Value);
|
||||
}
|
||||
}
|
||||
this->TTL = 0;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,24 @@
|
|||
#include "missile.h"
|
||||
#include "script.h"
|
||||
#include "unit.h"
|
||||
#include "unit_find.h"
|
||||
|
||||
|
||||
|
||||
struct CompareUnitDistance {
|
||||
const CUnit *referenceunit;
|
||||
CompareUnitDistance(const CUnit &unit): referenceunit(&unit) {}
|
||||
bool operator()(const CUnit *c1, const CUnit *c2)
|
||||
{
|
||||
int d1 = c1->MapDistanceTo(*referenceunit);
|
||||
int d2 = c2->MapDistanceTo(*referenceunit);
|
||||
if (d1 == d2) {
|
||||
return UnitNumber(*c1) < UnitNumber(*c2);
|
||||
} else {
|
||||
return d1 < d2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
** Parse the missile location description for a spell action.
|
||||
|
@ -166,20 +184,65 @@ static void EvaluateMissileLocation(const SpellActionMissileLocation &location,
|
|||
PixelPos startPos;
|
||||
PixelPos endPos;
|
||||
|
||||
EvaluateMissileLocation(this->StartPoint, caster, target, goalPos, &startPos);
|
||||
EvaluateMissileLocation(this->EndPoint, caster, target, goalPos, &endPos);
|
||||
/*
|
||||
hardcoded, will be done with Lua when it's possible
|
||||
*/
|
||||
const Vec2i &spellPos = target ? target->tilePos : goalPos;
|
||||
if (this->Missile->Class == MissileClassDeathCoil) {
|
||||
const Vec2i offset(2, 2);
|
||||
std::vector<CUnit *> table;
|
||||
Select(goalPos - offset, goalPos + offset, table);
|
||||
int count = 0;
|
||||
for (std::vector<CUnit *>::iterator it = table.begin(); it != table.end(); ++it) {
|
||||
CUnit &unit = **it;
|
||||
|
||||
::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;
|
||||
if (unit.Type->BoolFlag[ORGANIC_INDEX].value && unit.IsEnemy(caster)) {
|
||||
table[count++] = &unit;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
std::sort(table.begin(), table.begin() + count, CompareUnitDistance(caster));
|
||||
int damageLeft = this->Damage;
|
||||
for (std::vector<CUnit *>::iterator it = table.begin(); it != table.begin() + count && damageLeft > 0; ++it) {
|
||||
CUnit &unit = **it;
|
||||
if (unit.IsAliveOnMap()) {
|
||||
EvaluateMissileLocation(this->StartPoint, caster, &unit, unit.tilePos, &startPos);
|
||||
EvaluateMissileLocation(this->EndPoint, caster, &unit, unit.tilePos, &endPos);
|
||||
::Missile *missile = MakeMissile(*this->Missile, startPos, endPos);
|
||||
missile->TTL = this->TTL;
|
||||
missile->Delay = this->Delay;
|
||||
if (it + 1 == table.begin() + count) {
|
||||
missile->Damage = damageLeft;
|
||||
damageLeft = 0;
|
||||
} else {
|
||||
missile->Damage = std::min(damageLeft, unit.Variable[HP_INDEX].Value);
|
||||
damageLeft -= unit.Variable[HP_INDEX].Value;
|
||||
}
|
||||
missile->SourceUnit = &caster;
|
||||
missile->TargetUnit = &unit;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
missile->TargetUnit = target;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ static const char SAVECARGO_KEY[] = "LoseCargo";
|
|||
static const char NONSOLID_KEY[] = "NonSolid";
|
||||
static const char WALL_KEY[] = "Wall";
|
||||
static const char NORANDOMPLACING_KEY[] = "NoRandomPlacing";
|
||||
static const char ORGANIC_KEY[] = "organic";
|
||||
|
||||
// names of the variable.
|
||||
static const char HITPOINTS_KEY[] = "HitPoints";
|
||||
|
@ -145,7 +146,7 @@ CUnitTypeVar::CBoolKeys::CBoolKeys()
|
|||
SHOREBUILDING_KEY, CANATTACK_KEY, BUILDEROUTSIDE_KEY,
|
||||
BUILDERLOST_KEY, CANHARVEST_KEY, HARVESTER_KEY, SELECTABLEBYRECTANGLE_KEY,
|
||||
ISNOTSELECTABLE_KEY, DECORATION_KEY, INDESTRUCTIBLE_KEY, TELEPORTER_KEY, SHIELDPIERCE_KEY,
|
||||
SAVECARGO_KEY, NONSOLID_KEY, WALL_KEY, NORANDOMPLACING_KEY
|
||||
SAVECARGO_KEY, NONSOLID_KEY, WALL_KEY, NORANDOMPLACING_KEY, ORGANIC_KEY
|
||||
};
|
||||
|
||||
for (int i = 0; i < NBARALREADYDEFINED; ++i) {
|
||||
|
@ -338,6 +339,7 @@ static void UpdateDefaultBoolFlags(CUnitType &type)
|
|||
type.BoolFlag[NONSOLID_INDEX].value = type.NonSolid;
|
||||
type.BoolFlag[WALL_INDEX].value = type.Wall;
|
||||
type.BoolFlag[NORANDOMPLACING_INDEX].value = type.NoRandomPlacing;
|
||||
type.BoolFlag[ORGANIC_INDEX].value = type.Organic;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -980,6 +982,8 @@ static int CclDefineUnitType(lua_State *l)
|
|||
type->Wall = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "NoRandomPlacing")) {
|
||||
type->NoRandomPlacing = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "organic")) {
|
||||
type->Organic = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "Sounds")) {
|
||||
if (!lua_istable(l, -1)) {
|
||||
LuaError(l, "incorrect argument");
|
||||
|
|
|
@ -630,7 +630,7 @@ CUnitType::CUnitType() :
|
|||
BuilderOutside(0), BuilderLost(0), CanHarvest(0), Harvester(0),
|
||||
Neutral(0), SelectableByRectangle(0), IsNotSelectable(0), Decoration(0),
|
||||
Indestructible(0), Teleporter(0), SaveCargo(0),
|
||||
NonSolid(0), Wall(0), NoRandomPlacing(0),
|
||||
NonSolid(0), Wall(0), NoRandomPlacing(0), Organic(0),
|
||||
GivesResource(0), Supply(0), Demand(0), PoisonDrain(0), FieldFlags(0), MovementMask(0),
|
||||
Sprite(NULL), ShadowSprite(NULL)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue