[+] Added "position-autocast" field for "autocast" spell section, allowing to set up autocast for position spells

This commit is contained in:
cybermind 2014-05-31 18:41:18 +06:00
parent cacc4ce874
commit d4924e8c3b
17 changed files with 101 additions and 42 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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.
**

View file

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

View file

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

View file

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

View file

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

View file

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