[+] Added CUnit flag Summoned to mark units which are summoned by spells

[*] Summoned units don't bother AI when attacked and join into AI attack forces to help in attack wave
[*] Some animation code clean-up
This commit is contained in:
cybermind 2013-05-12 21:09:02 +06:00
parent a5d5580115
commit 13ffa1d0b3
27 changed files with 219 additions and 123 deletions

View file

@ -670,7 +670,7 @@ void AiHelpMe(const CUnit *attacker, CUnit &defender)
return;
}
// Summoned unit, don't help
if (defender.GroupId == -1) {
if (defender.Summoned) {
return;
}

View file

@ -467,6 +467,30 @@ unsigned int AiForceManager::FindFreeForce(AiForceRole role, int begin)
return f;
}
/**
** Find unit in force
**
** @param unit Unit to search for.
**
** @return Force number, or -1 if not found
*/
int AiForceManager::GetForce(const CUnit &unit)
{
for (unsigned int i = 0; i < forces.size(); ++i) {
AiForce &force = forces[i];
for (unsigned int j = 0; j < force.Units.size(); ++j) {
CUnit &aiunit = *force.Units[j];
if (UnitNumber(unit) == UnitNumber(aiunit)) {
return i;
}
}
}
return -1;
}
/**
** Cleanup units in forces.
*/

View file

@ -159,12 +159,12 @@ public:
void ReturnToHome();
bool NewRallyPoint(const Vec2i &startPos, Vec2i *resultPos);
void Insert(CUnit &unit);
private:
void CountTypes(unsigned int *counter, const size_t len);
bool IsBelongsTo(const CUnitType &type);
void Insert(CUnit &unit);
void Update();
static void InternalRemoveUnit(CUnit *unit);
@ -220,6 +220,7 @@ public:
return script[index];
}
int GetForce(const CUnit &unit);
void RemoveDeadUnit();
bool Assign(CUnit &unit);
void Update();

View file

@ -134,17 +134,17 @@ static int ParseAnimPlayer(const CUnit &unit, const char *parseint)
** @return The parsed value.
*/
int ParseAnimInt(const CUnit *unit, const char *parseint)
int ParseAnimInt(const CUnit &unit, const char *parseint)
{
char s[100];
const CUnit *goal = unit;
const CUnit *goal = &unit;
strcpy(s, parseint);
char *cur = &s[2];
if ((s[0] == 'v' || s[0] == 't') && unit != NULL) { //unit variable detected
if (s[0] == 'v' || s[0] == 't') { //unit variable detected
if (s[0] == 't') {
if (unit->CurrentOrder()->HasGoal()) {
goal = unit->CurrentOrder()->GetGoal();
if (unit.CurrentOrder()->HasGoal()) {
goal = unit.CurrentOrder()->GetGoal();
} else {
return 0;
}
@ -152,7 +152,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
char *next = strchr(cur, '.');
if (next == NULL) {
fprintf(stderr, "Need also specify the variable '%s' tag \n", cur);
Exit(1);
ExitFatal(1);
} else {
*next = '\0';
}
@ -164,7 +164,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return goal->Resource.Active;
}
fprintf(stderr, "Bad variable name '%s'\n", cur);
Exit(1);
ExitFatal(1);
}
if (!strcmp(next + 1, "Value")) {
return goal->Variable[index].Value;
@ -178,10 +178,10 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return goal->Variable[index].Value * 100 / goal->Variable[index].Max;
}
return 0;
} else if ((s[0] == 'b' || s[0] == 'g') && unit != NULL) { //unit bool flag detected
} else if (s[0] == 'b' || s[0] == 'g') { //unit bool flag detected
if (s[0] == 'g') {
if (unit->CurrentOrder()->HasGoal()) {
goal = unit->CurrentOrder()->GetGoal();
if (unit.CurrentOrder()->HasGoal()) {
goal = unit.CurrentOrder()->GetGoal();
} else {
return 0;
}
@ -189,11 +189,10 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
const int index = UnitTypeVar.BoolFlagNameLookup[cur];// User bool flags
if (index == -1) {
fprintf(stderr, "Bad bool-flag name '%s'\n", cur);
Exit(1);
return 0;
ExitFatal(1);
}
return goal->Type->BoolFlag[index].value;
} else if ((s[0] == 's') && unit != NULL) { //spell type detected
} else if (s[0] == 's') { //spell type detected
Assert(goal->CurrentAction() == UnitActionSpellCast);
const COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
const SpellType &spell = order.GetSpell();
@ -201,11 +200,11 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return 1;
}
return 0;
} else if (s[0] == 'p' && unit != NULL) { //player variable detected
} else if (s[0] == 'p') { //player variable detected
char *next = strchr(cur, '.');
if (next == NULL) {
fprintf(stderr, "Need also specify the %s player's property\n", cur);
Exit(1);
ExitFatal(1);
} else {
*next = '\0';
}
@ -213,7 +212,7 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
if (arg != NULL) {
*arg = '\0';
}
return GetPlayerData(ParseAnimPlayer(*unit, cur), next + 1, arg + 1);
return GetPlayerData(ParseAnimPlayer(unit, cur), next + 1, arg + 1);
} else if (s[0] == 'r') { //random value
char *next = strchr(cur, '.');
if (next == NULL) {
@ -224,12 +223,72 @@ int ParseAnimInt(const CUnit *unit, const char *parseint)
return min + SyncRand(atoi(next + 1) - min + 1);
}
} else if (s[0] == 'l') { //player number
return ParseAnimPlayer(*unit, cur);
return ParseAnimPlayer(unit, cur);
}
return atoi(parseint);
}
/**
** Parse flags list in animation frame.
**
** @param unit Unit of the animation.
** @param parseflag Flag list to parse.
**
** @return The parsed value.
*/
int ParseAnimFlags(const CUnit &unit, const char *parseflag)
{
char s[100];
int flags = 0;
strcpy(s, parseflag);
char *cur = s;
char *next = s;
while (next) {
next = strchr(cur, '.');
if (next) {
*next = '\0';
++next;
}
if (unit.Anim.Anim->Type == AnimationSpawnMissile) {
if (!strcmp(cur, "none")) {
flags = SM_None;
return flags;
} else if (!strcmp(cur, "damage")) {
flags |= SM_Damage;
} else if (!strcmp(cur, "totarget")) {
flags |= SM_ToTarget;
} else if (!strcmp(cur, "pixel")) {
flags |= SM_Pixel;
} else if (!strcmp(cur, "reltarget")) {
flags |= SM_RelTarget;
} else if (!strcmp(cur, "ranged")) {
flags |= SM_Ranged;
} else if (!strcmp(cur, "setdirection")) {
flags |= SM_SetDirection;
} else {
fprintf(stderr, "Unknown animation flag: %s\n", cur);
ExitFatal(1);
}
} else if (unit.Anim.Anim->Type == AnimationSpawnUnit) {
if (!strcmp(cur, "none")) {
flags = SU_None;
return flags;
} else if (!strcmp(cur, "summoned")) {
flags |= SU_Summoned;
} else if (!strcmp(cur, "jointoai")) {
flags |= SU_JoinToAIForce;
} else {
fprintf(stderr, "Unknown animation flag: %s\n", cur);
ExitFatal(1);
}
}
cur = next;
}
return flags;
}
/**
** Show unit animation.

View file

@ -52,7 +52,11 @@
int CAnimation_ExactFrame::ParseAnimInt(const CUnit *unit) const
{
return ::ParseAnimInt(unit, this->frame.c_str());
if (unit == NULL) {
return atoi(this->frame.c_str());
} else {
return ::ParseAnimInt(*unit, this->frame.c_str());
}
}
//@}

View file

@ -53,7 +53,11 @@
int CAnimation_Frame::ParseAnimInt(const CUnit *unit) const
{
return ::ParseAnimInt(unit, this->frame.c_str());
if (unit == NULL) {
return atoi(this->frame.c_str());
} else {
return ::ParseAnimInt(*unit, this->frame.c_str());
}
}
//@}

View file

@ -61,8 +61,8 @@ static bool returnFalse(int, int) { return false; }
{
Assert(unit.Anim.Anim == this);
const int lop = ParseAnimInt(&unit, this->leftVar.c_str());
const int rop = ParseAnimInt(&unit, this->rightVar.c_str());
const int lop = ParseAnimInt(unit, this->leftVar.c_str());
const int rop = ParseAnimInt(unit, this->rightVar.c_str());
const bool cond = this->binOpFunc(lop, rop);
if (cond) {

View file

@ -50,7 +50,7 @@
for (std::vector<std::string>::const_iterator it = cbArgs.begin(); it != cbArgs.end(); ++it) {
const std::string str = *it;
const int arg = ParseAnimInt(&unit, str.c_str());
const int arg = ParseAnimInt(unit, str.c_str());
cb->pushInteger(arg);
}
cb->run();

View file

@ -44,7 +44,7 @@
Assert(unit.Anim.Anim == this);
Assert(!move);
move = ParseAnimInt(&unit, this->moveStr.c_str());
move = ParseAnimInt(unit, this->moveStr.c_str());
}
/* virtual */ void CAnimation_Move::Init(const char *s, lua_State *)

View file

@ -43,7 +43,7 @@
{
Assert(unit.Anim.Anim == this);
if (SyncRand() % 100 < ParseAnimInt(&unit, this->randomStr.c_str())) {
if (SyncRand() % 100 < ParseAnimInt(unit, this->randomStr.c_str())) {
unit.Anim.Anim = this->gotoLabel;
}
}

View file

@ -45,9 +45,9 @@
Assert(unit.Anim.Anim == this);
if ((SyncRand() >> 8) & 1) {
UnitRotate(unit, -ParseAnimInt(&unit, this->rotateStr.c_str()));
UnitRotate(unit, -ParseAnimInt(unit, this->rotateStr.c_str()));
} else {
UnitRotate(unit, ParseAnimInt(&unit, this->rotateStr.c_str()));
UnitRotate(unit, ParseAnimInt(unit, this->rotateStr.c_str()));
}
}

View file

@ -43,8 +43,8 @@
{
Assert(unit.Anim.Anim == this);
const int arg1 = ParseAnimInt(&unit, this->minWait.c_str());
const int arg2 = ParseAnimInt(&unit, this->maxWait.c_str());
const int arg1 = ParseAnimInt(unit, this->minWait.c_str());
const int arg2 = ParseAnimInt(unit, this->maxWait.c_str());
unit.Anim.Wait = arg1 + SyncRand() % (arg2 - arg1 + 1);
}

View file

@ -66,7 +66,7 @@ void UnitRotate(CUnit &unit, int rotate)
const Vec2i pos = target.tilePos + target.Type->GetHalfTileSize() - unit.tilePos;
UnitHeadingFromDeltaXY(unit, pos);
} else {
UnitRotate(unit, ParseAnimInt(&unit, this->rotateStr.c_str()));
UnitRotate(unit, ParseAnimInt(unit, this->rotateStr.c_str()));
}
}

View file

@ -178,8 +178,8 @@ static void SetPlayerData(const int player, const char *prop, const char *arg, i
const char *var = this->varStr.c_str();
const char *arg = this->argStr.c_str();
const int playerId = ParseAnimInt(&unit, this->playerStr.c_str());
int rop = ParseAnimInt(&unit, this->valueStr.c_str());
const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
int rop = ParseAnimInt(unit, this->valueStr.c_str());
int data = GetPlayerData(playerId, var, arg);
switch (this->mod) {

View file

@ -95,7 +95,7 @@
return;
}
const int rop = ParseAnimInt(&unit, this->valueStr.c_str());
const int rop = ParseAnimInt(unit, this->valueStr.c_str());
int value = 0;
if (!strcmp(next + 1, "Value")) {
value = goal->Variable[index].Value;

View file

@ -46,68 +46,17 @@
#include "pathfinder.h"
#include "unit.h"
//SpawnMissile flags
#define ANIM_SM_DAMAGE 1
#define ANIM_SM_TOTARGET 2
#define ANIM_SM_PIXEL 4
#define ANIM_SM_RELTARGET 8
#define ANIM_SM_RANGED 16
#define ANIM_SM_SETDIRECTION 32
/**
** Parse flags list in animation frame.
**
** @param unit Unit of the animation.
** @param parseflag Flag list to parse.
**
** @return The parsed value.
*/
static int ParseAnimFlags(CUnit &unit, const char *parseflag)
{
char s[100];
int flags = 0;
strcpy(s, parseflag);
char *cur = s;
char *next = s;
while (next) {
next = strchr(cur, '.');
if (next) {
*next = '\0';
++next;
}
if (unit.Anim.Anim->Type == AnimationSpawnMissile) {
if (!strcmp(cur, "damage")) {
flags |= ANIM_SM_DAMAGE;
} else if (!strcmp(cur, "totarget")) {
flags |= ANIM_SM_TOTARGET;
} else if (!strcmp(cur, "pixel")) {
flags |= ANIM_SM_PIXEL;
} else if (!strcmp(cur, "reltarget")) {
flags |= ANIM_SM_RELTARGET;
} else if (!strcmp(cur, "ranged")) {
flags |= ANIM_SM_RANGED;
} else if (!strcmp(cur, "setdirection")) {
flags |= ANIM_SM_SETDIRECTION;
}
}
cur = next;
}
return flags;
}
/* virtual */ void CAnimation_SpawnMissile::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
{
Assert(unit.Anim.Anim == this);
const int startx = ParseAnimInt(&unit, this->startXStr.c_str());
const int starty = ParseAnimInt(&unit, this->startYStr.c_str());
const int destx = ParseAnimInt(&unit, this->destXStr.c_str());
const int desty = ParseAnimInt(&unit, this->destYStr.c_str());
const int flags = ParseAnimFlags(unit, this->flagsStr.c_str());
const int offsetnum = ParseAnimInt(&unit, this->offsetNumStr.c_str());
const CUnit *goal = flags & ANIM_SM_RELTARGET ? unit.CurrentOrder()->GetGoal() : &unit;
const int startx = ParseAnimInt(unit, this->startXStr.c_str());
const int starty = ParseAnimInt(unit, this->startYStr.c_str());
const int destx = ParseAnimInt(unit, this->destXStr.c_str());
const int desty = ParseAnimInt(unit, this->destYStr.c_str());
const SpawnMissile_Flags flags = (SpawnMissile_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));
const int offsetnum = ParseAnimInt(unit, this->offsetNumStr.c_str());
const CUnit *goal = flags & SM_RelTarget ? unit.CurrentOrder()->GetGoal() : &unit;
const int dir = ((goal->Direction + NextDirection / 2) & 0xFF) / NextDirection;
const PixelPos moff = goal->Type->MissileOffsets[dir][!offsetnum ? 0 : offsetnum - 1];
PixelPos start;
@ -120,14 +69,14 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
if (!goal || goal->Destroyed) {
return;
}
if ((flags & ANIM_SM_PIXEL)) {
if ((flags & SM_Pixel)) {
start.x = goal->tilePos.x * PixelTileSize.x + goal->IX + moff.x + startx;
start.y = goal->tilePos.y * PixelTileSize.y + goal->IY + moff.y + starty;
} else {
start.x = (goal->tilePos.x + startx) * PixelTileSize.x + PixelTileSize.x / 2 + moff.x;
start.y = (goal->tilePos.y + starty) * PixelTileSize.y + PixelTileSize.y / 2 + moff.y;
}
if ((flags & ANIM_SM_TOTARGET)) {
if ((flags & SM_ToTarget)) {
CUnit *target = goal->CurrentOrder()->GetGoal();
if (!target || target->Destroyed) {
Assert(!mtype->AlwaysFire || mtype->Range);
@ -143,14 +92,14 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
COrder_SpellCast &order = *static_cast<COrder_SpellCast *>(goal->CurrentOrder());
dest = Map.TilePosToMapPixelPos_Center(order.GetGoalPos());
}
if (flags & ANIM_SM_PIXEL) {
if (flags & SM_Pixel) {
dest.x += destx;
dest.y += desty;
} else {
dest.x += destx * PixelTileSize.x;
dest.y += desty * PixelTileSize.y;
}
} else if (flags & ANIM_SM_PIXEL) {
} else if (flags & SM_Pixel) {
dest.x = target->GetMapPixelPosCenter().x + destx;
dest.y = target->GetMapPixelPosCenter().y + desty;
} else {
@ -159,7 +108,7 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
dest += target->Type->GetPixelSize() / 2;
}
} else {
if ((flags & ANIM_SM_PIXEL)) {
if ((flags & SM_Pixel)) {
dest.x = goal->GetMapPixelPosCenter().x + destx;
dest.y = goal->GetMapPixelPosCenter().y + desty;
} else {
@ -170,22 +119,22 @@ static int ParseAnimFlags(CUnit &unit, const char *parseflag)
}
Vec2i destTilePos = Map.MapPixelPosToTilePos(dest);
const int dist = goal->MapDistanceTo(destTilePos);
if ((flags & ANIM_SM_RANGED) && !(flags & ANIM_SM_PIXEL)
if ((flags & SM_Ranged) && !(flags & SM_Pixel)
&& dist > goal->Stats->Variables[ATTACKRANGE_INDEX].Max
&& dist < goal->Type->MinAttackRange) {
} else {
Missile *missile = MakeMissile(*mtype, start, dest);
if (flags & ANIM_SM_SETDIRECTION) {
if (flags & SM_SetDirection) {
PixelPos posd;
posd.x = Heading2X[goal->Direction / NextDirection];
posd.y = Heading2Y[goal->Direction / NextDirection];
missile->MissileNewHeadingFromXY(posd);
}
if (flags & ANIM_SM_DAMAGE) {
if (flags & SM_Damage) {
missile->SourceUnit = &unit;
}
CUnit *target = goal->CurrentOrder()->GetGoal();
if (flags & ANIM_SM_TOTARGET && target && target->IsAlive()) {
if (flags & SM_ToTarget && target && target->IsAlive()) {
missile->TargetUnit = target;
}
}

View file

@ -37,6 +37,9 @@
#include "animation/animation_spawnunit.h"
#include "../ai/ai_local.h"
#include "commands.h"
#include "map.h"
#include "unit.h"
@ -104,10 +107,12 @@ found:
{
Assert(unit.Anim.Anim == this);
const int offX = ParseAnimInt(&unit, this->offXStr.c_str());
const int offY = ParseAnimInt(&unit, this->offYStr.c_str());
const int range = ParseAnimInt(&unit, this->rangeStr.c_str());
const int playerId = ParseAnimInt(&unit, this->playerStr.c_str());
const int offX = ParseAnimInt(unit, this->offXStr.c_str());
const int offY = ParseAnimInt(unit, this->offYStr.c_str());
const int range = ParseAnimInt(unit, this->rangeStr.c_str());
const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
const SpawnUnit_Flags flags = (SpawnUnit_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));
CPlayer &player = Players[playerId];
const Vec2i pos(unit.tilePos.x + offX, unit.tilePos.y + offY);
CUnitType *type = UnitTypeByIdent(this->unitTypeStr.c_str());
@ -120,6 +125,17 @@ found:
if (target != NULL) {
target->tilePos = resPos;
target->Place(resPos);
if (flags & SU_Summoned) {
target->Summoned = 1;
}
if ((flags & SU_JoinToAIForce) && unit.Player->AiEnabled) {
int force = unit.Player->Ai->Force.GetForce(unit);
if (force != -1) {
unit.Player->Ai->Force[force].Insert(*target);
target->GroupId = unit.GroupId;
CommandDefend(*target, unit, FlushCommands);
}
}
//DropOutOnSide(*target, LookingW, NULL);
} else {
DebugPrint("Unable to allocate Unit");
@ -128,7 +144,7 @@ found:
}
/*
** s = "unitType offX offY range player"
** s = "unitType offX offY range player flags"
*/
/* virtual */ void CAnimation_SpawnUnit::Init(const char *s, lua_State *)
{
@ -154,6 +170,10 @@ found:
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
this->playerStr.assign(str, begin, end - begin);
begin = std::min(len, str.find_first_not_of(' ', end));
end = std::min(len, str.find(' ', begin));
this->flagsStr.assign(str, begin, end - begin);
}
//@}

View file

@ -42,7 +42,7 @@
/* virtual */ void CAnimation_Wait::Action(CUnit &unit, int &/*move*/, int scale) const
{
Assert(unit.Anim.Anim == this);
unit.Anim.Wait = ParseAnimInt(&unit, this->wait.c_str()) << scale >> 8;
unit.Anim.Wait = ParseAnimInt(unit, this->wait.c_str()) << scale >> 8;
if (unit.Variable[SLOW_INDEX].Value) { // unit is slowed down
unit.Anim.Wait <<= 1;
}

View file

@ -167,7 +167,8 @@ extern int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scal
extern int UnitShowAnimation(CUnit &unit, const CAnimation *anim);
extern int ParseAnimInt(const CUnit *unit, const char *parseint);
extern int ParseAnimInt(const CUnit &unit, const char *parseint);
extern int ParseAnimFlags(const CUnit &unit, const char *parseflag);
extern void FindLabelLater(CAnimation **anim, const std::string &name);

View file

@ -35,6 +35,18 @@
#include <string>
#include "animation.h"
//SpawnMissile flags
enum SpawnMissile_Flags {
SM_None = 0, /// Clears all flags
SM_Damage = 1, /// Missile deals damage to units
SM_ToTarget = 2, /// Missile is directed to unit's target
SM_Pixel = 4, /// Missile's offsets are calculated in pixels rather than tiles
SM_RelTarget = 8, /// All calculations are relative to unit's target
SM_Ranged = 16, /// Missile can't be shot if current range between unit and it's target
/// is bigger than unit's attack range
SM_SetDirection = 32 /// Missile takes the same direction as spawner
};
class CAnimation_SpawnMissile : public CAnimation
{
public:

View file

@ -35,6 +35,13 @@
#include <string>
#include "animation.h"
//SpawnUnit flags
enum SpawnUnit_Flags {
SU_None = 0, /// Clears all flags
SU_Summoned = 1, /// Unit is marked as "summoned"
SU_JoinToAIForce = 2 /// Unit is included into spawner's AI force, if available
};
class CAnimation_SpawnUnit : public CAnimation
{
public:
@ -49,6 +56,7 @@ private:
std::string offYStr;
std::string rangeStr;
std::string playerStr;
std::string flagsStr;
};
//@}

View file

@ -339,21 +339,23 @@ public:
int ResourcesHeld; /// Resources Held by a unit
unsigned char DamagedType; /// Index of damage type of unit which damaged this unit
unsigned long Attacked; /// gamecycle unit was last attacked
unsigned Blink : 3; /// Let selection rectangle blink
unsigned Moving : 1; /// The unit is moving
unsigned ReCast : 1; /// Recast again next cycle
unsigned AutoRepair : 1; /// True if unit tries to repair on still action.
unsigned long Attacked; /// gamecycle unit was last attacked
unsigned Blink : 3; /// Let selection rectangle blink
unsigned Moving : 1; /// The unit is moving
unsigned ReCast : 1; /// Recast again next cycle
unsigned AutoRepair : 1; /// True if unit tries to repair on still action.
unsigned Burning : 1; /// unit is burning
unsigned Destroyed : 1; /// unit is destroyed pending reference
unsigned Removed : 1; /// unit is removed (not on map)
unsigned Selected : 1; /// unit is selected
unsigned Burning : 1; /// unit is burning
unsigned Destroyed : 1; /// unit is destroyed pending reference
unsigned Removed : 1; /// unit is removed (not on map)
unsigned Selected : 1; /// unit is selected
unsigned Constructed : 1; /// Unit is in construction
unsigned Active : 1; /// Unit is active for AI
unsigned Boarded : 1; /// Unit is on board a transporter.
unsigned CacheLock : 1; /// Unit is on lock by unitcache operations.
unsigned CacheLock : 1; /// Unit is on lock by unitcache operations.
unsigned Summoned : 1; /// Unit is summoned using spells.
unsigned TeamSelected; /// unit is selected by a team member.
CPlayer *RescuedFrom; /// The original owner of a rescued unit.

View file

@ -85,6 +85,7 @@
} else {
portal = MakeUnitAndPlace(goalPos, *this->PortalType,
CurrentPlayer ? caster.Player : &Players[PlayerNumNeutral]);
portal->Summoned = 1;
}
portal->TTL = GameCycle + this->TTL;
// Goal is used to link to destination circle of power

View file

@ -36,6 +36,8 @@
#include "spell/spell_summon.h"
#include "../ai/ai_local.h"
#include "actions.h"
#include "commands.h"
#include "script.h"
@ -124,6 +126,8 @@ public:
if (target != NULL) {
target->tilePos = pos;
DropOutOnSide(*target, LookingW, NULL);
// To avoid defending summoned unit for AI
target->Summoned = 1;
//
// set life span. ttl=0 results in a permanent unit.
//
@ -131,13 +135,13 @@ public:
target->TTL = GameCycle + ttl;
}
// To avoid defending summoned unit for AI
// Insert summoned unit to AI force so it will help them in battle
if (caster.Player->AiEnabled) {
if (caster.GroupId) {
int force = caster.Player->Ai->Force.GetForce(caster);
if (force != -1) {
caster.Player->Ai->Force[force].Insert(*target);
target->GroupId = caster.GroupId;
CommandDefend(*target, caster, FlushCommands);
} else {
target->GroupId = -1;
}
}

View file

@ -377,6 +377,9 @@ static int CclUnit(lua_State *l)
} else if (!strcmp(value, "selected")) {
unit->Selected = 1;
--j;
} else if (!strcmp(value, "summoned")) {
unit->Summoned = 1;
--j;
} else if (!strcmp(value, "rescued-from")) {
unit->RescuedFrom = &Players[LuaToNumber(l, 2, j + 1)];
} else if (!strcmp(value, "seen-by-player")) {

View file

@ -453,6 +453,7 @@ void CUnit::Init()
Moving = 0;
ReCast = 0;
CacheLock = 0;
Summoned = 0;
memset(&Anim, 0, sizeof(Anim));
CurrentResource = 0;
Orders.clear();

View file

@ -177,6 +177,9 @@ void SaveUnit(const CUnit &unit, CFile &file)
if (unit.Selected) {
file.printf(" \"selected\",");
}
if (unit.Summoned) {
file.printf(" \"summoned\",");
}
if (unit.RescuedFrom) {
file.printf(" \"rescued-from\", %d,", unit.RescuedFrom->Index);
}