[*] Correct Death Coil spell casting

This commit is contained in:
cybermind 2014-05-25 10:40:56 +06:00
parent 446a0a9454
commit d47fdf52bd
5 changed files with 87 additions and 39 deletions

View file

@ -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 {

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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");

View file

@ -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)
{