[+] Added "position-autocast" field for "autocast" spell section, allowing to set up autocast for position spells
This commit is contained in:
parent
cacc4ce874
commit
d4924e8c3b
17 changed files with 101 additions and 42 deletions
|
@ -184,7 +184,7 @@ class UnitTypePrioritySorter_Decreasing
|
|||
public:
|
||||
bool operator()(int lhs, int rhs) const
|
||||
{
|
||||
return UnitTypes[lhs]->Priority > UnitTypes[rhs]->Priority;
|
||||
return UnitTypes[lhs]->DefaultStat.Variables[PRIORITY_INDEX].Value > UnitTypes[rhs]->DefaultStat.Variables[PRIORITY_INDEX].Value;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ public:
|
|||
return;
|
||||
}
|
||||
// Choose the best target.
|
||||
if (!*best || (*best)->Type->Priority < type.Priority) {
|
||||
if (!*best || (*best)->Variable[PRIORITY_INDEX].Value < unit->Variable[PRIORITY_INDEX].Value) {
|
||||
*best = unit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ public:
|
|||
~LuaCallback();
|
||||
void pushPreamble();
|
||||
void pushInteger(int value);
|
||||
void pushIntegers(int count, int *array);
|
||||
void pushString(const std::string &eventId);
|
||||
void run(int results = 0);
|
||||
bool popBoolean();
|
||||
|
|
|
@ -386,6 +386,7 @@ public:
|
|||
int StartDelay; /// missile start delay
|
||||
int Sleep; /// missile sleep
|
||||
int Speed; /// missile speed
|
||||
int BlizzardSpeed; /// speed for blizzard shards
|
||||
int TTL; /// missile time-to-live
|
||||
int ReduceFactor; /// Multiplier for reduce or increase damage dealt to the next unit
|
||||
int SmokePrecision; /// How frequently the smoke missile will generate itself
|
||||
|
|
|
@ -174,8 +174,12 @@ public:
|
|||
#define ACP_NOVALUE -1
|
||||
#define ACP_DISTANCE -2
|
||||
AutoCastInfo() : Range(0), MinRange(0), PriorytyVar(ACP_NOVALUE), ReverseSort(false), Condition(NULL),
|
||||
Combat(0), Attacker(0) {};
|
||||
~AutoCastInfo() { delete Condition; };
|
||||
Combat(0), Attacker(0), PositionAutoCast(NULL) {};
|
||||
~AutoCastInfo()
|
||||
{
|
||||
delete Condition;
|
||||
delete PositionAutoCast;
|
||||
};
|
||||
/// @todo this below is SQUARE!!!
|
||||
int Range; /// Max range of the target.
|
||||
int MinRange; /// Min range of the target.
|
||||
|
@ -190,8 +194,8 @@ public:
|
|||
int Combat; /// If it should be casted in combat
|
||||
int Attacker; /// If it should be casted on unit which attacks
|
||||
|
||||
/// @todo Add stuff here for target preference.
|
||||
/// @todo Heal units with the lowest hit points first.
|
||||
// Position autocast callback
|
||||
LuaCallback *PositionAutoCast;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -212,6 +212,7 @@ enum {
|
|||
SHIELDPIERCING_INDEX,
|
||||
ISALIVE_INDEX,
|
||||
PLAYER_INDEX,
|
||||
PRIORITY_INDEX,
|
||||
NVARALREADYDEFINED
|
||||
};
|
||||
|
||||
|
@ -505,7 +506,6 @@ public:
|
|||
int MinAttackRange; /// Minimal attack range
|
||||
int ReactRangeComputer; /// Reacts on enemy for computer
|
||||
int ReactRangePerson; /// Reacts on enemy for person player
|
||||
int Priority; /// Priority value / AI Treatment
|
||||
int BurnPercent; /// Burning percent.
|
||||
int BurnDamageRate; /// HP burn rate per sec
|
||||
int RepairRange; /// Units repair range.
|
||||
|
|
|
@ -1325,7 +1325,7 @@ MissileType::MissileType(const std::string &ident) :
|
|||
CorrectSphashDamage(false), Flip(false), CanHitOwner(false), FriendlyFire(false),
|
||||
AlwaysFire(false), Pierce(false), PierceOnce(false), IgnoreWalls(true), KillFirstUnit(false),
|
||||
Class(), NumBounces(0), ParabolCoefficient(2048), StartDelay(0),
|
||||
Sleep(0), Speed(0), TTL(-1), ReduceFactor(100), SmokePrecision(0),
|
||||
Sleep(0), Speed(0), BlizzardSpeed(0), TTL(-1), ReduceFactor(100), SmokePrecision(0),
|
||||
MissileStopFlags(0), Damage(NULL), Range(0), SplashFactor(0),
|
||||
ImpactParticle(NULL), SmokeParticle(NULL), OnImpact(NULL),
|
||||
G(NULL)
|
||||
|
|
|
@ -139,6 +139,8 @@ void MissileType::Load(lua_State *l)
|
|||
this->Sleep = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "Speed")) {
|
||||
this->Speed = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "BlizzardSpeed")) {
|
||||
this->BlizzardSpeed = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "TTL")) {
|
||||
this->TTL = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "Damage")) {
|
||||
|
|
|
@ -241,6 +241,10 @@ static void CclSpellAutocast(lua_State *l, AutoCastInfo *autocast)
|
|||
autocast->Range = LuaToNumber(l, -1, j + 1);
|
||||
} else if (!strcmp(value, "min-range")) {
|
||||
autocast->MinRange = LuaToNumber(l, -1, j + 1);
|
||||
} else if (!strcmp(value, "position-autocast")) {
|
||||
lua_rawgeti(l, -1, j + 1);
|
||||
autocast->PositionAutoCast = new LuaCallback(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(value, "combat")) {
|
||||
autocast->Combat = Ccl2Condition(l, LuaToString(l, -1, j + 1));
|
||||
} else if (!strcmp(value, "attacker")) {
|
||||
|
|
|
@ -106,9 +106,9 @@
|
|||
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) {
|
||||
if (mis->Type->BlizzardSpeed) {
|
||||
mis->Delay = i * mis->Type->Sleep * 2 * PixelTileSize.x / mis->Type->BlizzardSpeed;
|
||||
} else 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;
|
||||
|
|
|
@ -295,14 +295,37 @@ static Target *SelectTargetUnitsOfAutoCast(CUnit &caster, const SpellType &spell
|
|||
return NewTargetUnit(caster);
|
||||
}
|
||||
return NULL;
|
||||
case TargetPosition:
|
||||
case TargetPosition: {
|
||||
if (autocast->PositionAutoCast && table.empty() == false) {
|
||||
int count = 0;
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
if (PassCondition(caster, spell, table[i], pos, spell.Condition)
|
||||
&& PassCondition(caster, spell, table[i], pos, autocast->Condition)) {
|
||||
table[count++] = table[i];
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
if (autocast->PriorytyVar != ACP_NOVALUE) {
|
||||
std::sort(table.begin(), table.begin() + count,
|
||||
AutoCastPrioritySort(caster, autocast->PriorytyVar, autocast->ReverseSort));
|
||||
}
|
||||
int *array = new int[count + 1];
|
||||
for (size_t i = 1; i != count + 1; ++i) {
|
||||
array[i] = UnitNumber(*table[i - 1]);
|
||||
}
|
||||
array[0] = UnitNumber(caster);
|
||||
autocast->PositionAutoCast->pushPreamble();
|
||||
autocast->PositionAutoCast->pushIntegers(count + 1, array);
|
||||
autocast->PositionAutoCast->run(2);
|
||||
Vec2i resPos(autocast->PositionAutoCast->popInteger(), autocast->PositionAutoCast->popInteger());
|
||||
if (Map.Info.IsPointOnMap(resPos)) {
|
||||
Target *target = new Target(TargetPosition, NULL, resPos);
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
// Autocast with a position? That's hard
|
||||
// Possibilities: cast reveal-map on a dark region
|
||||
// Cast raise dead on a bunch of corpses. That would rule.
|
||||
// Cast summon until out of mana in the heat of battle. Trivial?
|
||||
// Find a tight group of units and cast area-damage spells. HARD,
|
||||
// but it is a must-have for AI. What about area-heal?
|
||||
}
|
||||
case TargetUnit: {
|
||||
// The units are already selected.
|
||||
// Check every unit if it is a possible target
|
||||
|
|
|
@ -75,6 +75,23 @@ void LuaCallback::pushInteger(int value)
|
|||
arguments++;
|
||||
}
|
||||
|
||||
/**
|
||||
** Push a array of integers from callback to stack
|
||||
**
|
||||
** @param value the integer to push on the stack
|
||||
*/
|
||||
void LuaCallback::pushIntegers(int count, int *array)
|
||||
{
|
||||
lua_newtable(luastate);
|
||||
int c = lua_gettop(luastate);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
lua_pushnumber(luastate, i + 1);
|
||||
lua_pushnumber(luastate, array[i]);
|
||||
lua_settable(luastate, -3);
|
||||
}
|
||||
arguments++;
|
||||
}
|
||||
|
||||
/**
|
||||
** Push a string argument for the callback on the stack.
|
||||
**
|
||||
|
|
|
@ -191,23 +191,23 @@ void CIcon::DrawUnitIcon(const ButtonStyle &style, unsigned flags,
|
|||
s.Default.BorderColor = 0;
|
||||
}
|
||||
if (Preference.IconsShift) {
|
||||
// Left and top edge of Icon
|
||||
Video.DrawHLine(ColorWhite, pos.x - 1, pos.y - 1, 49);
|
||||
Video.DrawVLine(ColorWhite, pos.x - 1, pos.y, 40);
|
||||
Video.DrawVLine(ColorWhite, pos.x, pos.y + 38, 2);
|
||||
Video.DrawHLine(ColorWhite, pos.x + 46, pos.y, 2);
|
||||
|
||||
// Bottom and Right edge of Icon
|
||||
Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 38, 47);
|
||||
Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 39, 47);
|
||||
Video.DrawVLine(ColorGray, pos.x + 46, pos.y + 1, 37);
|
||||
Video.DrawVLine(ColorGray, pos.x + 47, pos.y + 1, 37);
|
||||
|
||||
Video.DrawRectangle(ColorBlack, pos.x - 3, pos.y - 3, 52, 44);
|
||||
Video.DrawRectangle(ColorBlack, pos.x - 4, pos.y - 4, 54, 46);
|
||||
|
||||
if (flags & IconClicked) {
|
||||
DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player);
|
||||
// Left and top edge of Icon
|
||||
Video.DrawHLine(ColorWhite, pos.x - 1, pos.y - 1, 49);
|
||||
Video.DrawVLine(ColorWhite, pos.x - 1, pos.y, 40);
|
||||
Video.DrawVLine(ColorWhite, pos.x, pos.y + 38, 2);
|
||||
Video.DrawHLine(ColorWhite, pos.x + 46, pos.y, 2);
|
||||
|
||||
// Bottom and Right edge of Icon
|
||||
Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 38, 47);
|
||||
Video.DrawHLine(ColorGray, pos.x + 1, pos.y + 39, 47);
|
||||
Video.DrawVLine(ColorGray, pos.x + 46, pos.y + 1, 37);
|
||||
Video.DrawVLine(ColorGray, pos.x + 47, pos.y + 1, 37);
|
||||
|
||||
Video.DrawRectangle(ColorBlack, pos.x - 3, pos.y - 3, 52, 44);
|
||||
Video.DrawRectangle(ColorBlack, pos.x - 4, pos.y - 4, 54, 46);
|
||||
|
||||
if (flags & IconClicked) {
|
||||
DrawUIButton(&s, flags, pos.x + 1, pos.y + 1, text, player);
|
||||
} else {
|
||||
DrawUIButton(&s, flags, pos.x, pos.y, text, player);
|
||||
}
|
||||
|
|
|
@ -132,6 +132,7 @@ static const char SHIELDPERMEABILITY_KEY[] = "ShieldPermeability";
|
|||
static const char SHIELDPIERCING_KEY[] = "ShieldPiercing";
|
||||
static const char ISALIVE_KEY[] = "IsAlive";
|
||||
static const char PLAYER_KEY[] = "Player";
|
||||
static const char PRIORITY_KEY[] = "Priority";
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
|
@ -168,7 +169,8 @@ CUnitTypeVar::CVariableKeys::CVariableKeys()
|
|||
BASICDAMAGE_KEY, POSX_KEY, POSY_KEY, TARGETPOSX_KEY, TARGETPOSY_KEY, RADARRANGE_KEY,
|
||||
RADARJAMMERRANGE_KEY, AUTOREPAIRRANGE_KEY, BLOODLUST_KEY, HASTE_KEY,
|
||||
SLOW_KEY, INVISIBLE_KEY, UNHOLYARMOR_KEY, SLOT_KEY, SHIELD_KEY, POINTS_KEY,
|
||||
MAXHARVESTERS_KEY, POISON_KEY, SHIELDPERMEABILITY_KEY, SHIELDPIERCING_KEY, ISALIVE_KEY, PLAYER_KEY
|
||||
MAXHARVESTERS_KEY, POISON_KEY, SHIELDPERMEABILITY_KEY, SHIELDPIERCING_KEY, ISALIVE_KEY, PLAYER_KEY,
|
||||
PRIORITY_KEY
|
||||
};
|
||||
|
||||
for (int i = 0; i < NVARALREADYDEFINED; ++i) {
|
||||
|
@ -546,7 +548,8 @@ static int CclDefineUnitType(lua_State *l)
|
|||
type->DefaultStat.Variables[MAXHARVESTERS_INDEX].Value = LuaToNumber(l, -1);
|
||||
type->DefaultStat.Variables[MAXHARVESTERS_INDEX].Max = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "Priority")) {
|
||||
type->Priority = LuaToNumber(l, -1);
|
||||
type->DefaultStat.Variables[PRIORITY_INDEX].Value = LuaToNumber(l, -1);
|
||||
type->DefaultStat.Variables[PRIORITY_INDEX].Max = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "AnnoyComputerFactor")) {
|
||||
type->AnnoyComputerFactor = LuaToNumber(l, -1);
|
||||
} else if (!strcmp(value, "AiAdjacentRange")) {
|
||||
|
@ -1610,6 +1613,10 @@ void UpdateUnitVariables(CUnit &unit)
|
|||
unit.Variable[ATTACKRANGE_INDEX].Value = type->DefaultStat.Variables[ATTACKRANGE_INDEX].Max;
|
||||
unit.Variable[ATTACKRANGE_INDEX].Max = unit.Stats->Variables[ATTACKRANGE_INDEX].Max;
|
||||
|
||||
// Priority
|
||||
unit.Variable[PRIORITY_INDEX].Value = type->DefaultStat.Variables[PRIORITY_INDEX].Max;
|
||||
unit.Variable[PRIORITY_INDEX].Max = unit.Stats->Variables[PRIORITY_INDEX].Max;
|
||||
|
||||
// Position
|
||||
unit.Variable[POSX_INDEX].Value = unit.tilePos.x;
|
||||
unit.Variable[POSX_INDEX].Max = Map.Info.MapWidth;
|
||||
|
|
|
@ -2368,7 +2368,7 @@ int ThreatCalculate(const CUnit &unit, const CUnit &dest)
|
|||
}
|
||||
|
||||
// Priority 0-255
|
||||
cost -= dtype.Priority * PRIORITY_FACTOR;
|
||||
cost -= dtype.DefaultStat.Variables[PRIORITY_INDEX].Value * PRIORITY_FACTOR;
|
||||
// Remaining HP (Health) 0-65535
|
||||
cost += dest.Variable[HP_INDEX].Value * 100 / dest.Variable[HP_INDEX].Max * HEALTH_FACTOR;
|
||||
|
||||
|
|
|
@ -615,7 +615,7 @@ CUnit *TargetOnMap(const CUnit &source, const Vec2i &pos1, const Vec2i &pos2)
|
|||
}
|
||||
|
||||
// Choose the best target.
|
||||
if (!best || best->Type->Priority < unit.Type->Priority) {
|
||||
if (!best || best->Variable[PRIORITY_INDEX].Value < unit.Variable[PRIORITY_INDEX].Value) {
|
||||
best = &unit;
|
||||
}
|
||||
}
|
||||
|
@ -737,7 +737,7 @@ private:
|
|||
int cost = 0;
|
||||
|
||||
// Priority 0-255
|
||||
cost -= dtype.Priority * PRIORITY_FACTOR;
|
||||
cost -= dtype.DefaultStat.Variables[PRIORITY_INDEX].Value * PRIORITY_FACTOR;
|
||||
// Remaining HP (Health) 0-65535
|
||||
cost += dest->Variable[HP_INDEX].Value * 100 / dest->Variable[HP_INDEX].Max * HEALTH_FACTOR;
|
||||
|
||||
|
@ -871,7 +871,7 @@ public:
|
|||
cost = -cost;
|
||||
} else {
|
||||
// Priority 0-255
|
||||
cost += dtype.Priority * PRIORITY_FACTOR;
|
||||
cost += dtype.DefaultStat.Variables[PRIORITY_INDEX].Value * PRIORITY_FACTOR;
|
||||
|
||||
for (unsigned int i = 0; i < UnitTypeVar.GetNumberBoolFlag(); i++) {
|
||||
if (type.BoolFlag[i].AiPriorityTarget != CONDITION_TRUE) {
|
||||
|
|
|
@ -615,7 +615,7 @@ CUnitType::CUnitType() :
|
|||
TeleportCost(0), TeleportEffectIn(NULL), TeleportEffectOut(NULL),
|
||||
CorpseType(NULL), Construction(NULL), RepairHP(0), TileWidth(0), TileHeight(0),
|
||||
BoxWidth(0), BoxHeight(0), BoxOffsetX(0), BoxOffsetY(0), NumDirections(0),
|
||||
MinAttackRange(0), ReactRangeComputer(0), ReactRangePerson(0), Priority(0),
|
||||
MinAttackRange(0), ReactRangeComputer(0), ReactRangePerson(0),
|
||||
BurnPercent(0), BurnDamageRate(0), RepairRange(0),
|
||||
CanCastSpell(NULL), AutoCastActive(NULL),
|
||||
AutoBuildRate(0), RandomMovementProbability(0), ClicksToExplode(0),
|
||||
|
|
Loading…
Reference in a new issue