diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 7e6508d2c..f137fa812 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -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; } diff --git a/src/ai/ai_force.cpp b/src/ai/ai_force.cpp index 60e0e8eec..6cd69d8ab 100644 --- a/src/ai/ai_force.cpp +++ b/src/ai/ai_force.cpp @@ -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. */ diff --git a/src/ai/ai_local.h b/src/ai/ai_local.h index 89bb29ac8..ba8e9474f 100644 --- a/src/ai/ai_local.h +++ b/src/ai/ai_local.h @@ -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(); diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp index 0088b5ba8..4163caec2 100644 --- a/src/animation/animation.cpp +++ b/src/animation/animation.cpp @@ -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. diff --git a/src/animation/animation_exactframe.cpp b/src/animation/animation_exactframe.cpp index f2e1f8ccf..f03bf2790 100644 --- a/src/animation/animation_exactframe.cpp +++ b/src/animation/animation_exactframe.cpp @@ -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()); + } } //@} diff --git a/src/animation/animation_frame.cpp b/src/animation/animation_frame.cpp index 1d3c9a731..57c94ef7e 100644 --- a/src/animation/animation_frame.cpp +++ b/src/animation/animation_frame.cpp @@ -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()); + } } //@} diff --git a/src/animation/animation_ifvar.cpp b/src/animation/animation_ifvar.cpp index 1dc5e4fab..7eb6da399 100644 --- a/src/animation/animation_ifvar.cpp +++ b/src/animation/animation_ifvar.cpp @@ -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) { diff --git a/src/animation/animation_luacallback.cpp b/src/animation/animation_luacallback.cpp index 18f9f778f..055498b5c 100644 --- a/src/animation/animation_luacallback.cpp +++ b/src/animation/animation_luacallback.cpp @@ -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(); diff --git a/src/animation/animation_move.cpp b/src/animation/animation_move.cpp index 3e37de3bd..88d9c034f 100644 --- a/src/animation/animation_move.cpp +++ b/src/animation/animation_move.cpp @@ -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 *) diff --git a/src/animation/animation_randomgoto.cpp b/src/animation/animation_randomgoto.cpp index 3aef2a086..7467e1cb6 100644 --- a/src/animation/animation_randomgoto.cpp +++ b/src/animation/animation_randomgoto.cpp @@ -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; } } diff --git a/src/animation/animation_randomrotate.cpp b/src/animation/animation_randomrotate.cpp index c0d10b7fe..f6969c90f 100644 --- a/src/animation/animation_randomrotate.cpp +++ b/src/animation/animation_randomrotate.cpp @@ -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())); } } diff --git a/src/animation/animation_randomwait.cpp b/src/animation/animation_randomwait.cpp index 1336f7436..341a58c61 100644 --- a/src/animation/animation_randomwait.cpp +++ b/src/animation/animation_randomwait.cpp @@ -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); } diff --git a/src/animation/animation_rotate.cpp b/src/animation/animation_rotate.cpp index 963f94652..b15eab44b 100644 --- a/src/animation/animation_rotate.cpp +++ b/src/animation/animation_rotate.cpp @@ -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())); } } diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp index e41d528a2..80981a7c4 100644 --- a/src/animation/animation_setplayervar.cpp +++ b/src/animation/animation_setplayervar.cpp @@ -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) { diff --git a/src/animation/animation_setvar.cpp b/src/animation/animation_setvar.cpp index b6b4369bd..0f7957170 100644 --- a/src/animation/animation_setvar.cpp +++ b/src/animation/animation_setvar.cpp @@ -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; diff --git a/src/animation/animation_spawnmissile.cpp b/src/animation/animation_spawnmissile.cpp index 2535e0735..b3e22d49a 100644 --- a/src/animation/animation_spawnmissile.cpp +++ b/src/animation/animation_spawnmissile.cpp @@ -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; } } diff --git a/src/animation/animation_spawnunit.cpp b/src/animation/animation_spawnunit.cpp index e96fa7b55..b150dfb78 100644 --- a/src/animation/animation_spawnunit.cpp +++ b/src/animation/animation_spawnunit.cpp @@ -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); } //@} diff --git a/src/animation/animation_wait.cpp b/src/animation/animation_wait.cpp index 7b65d2097..f4609c592 100644 --- a/src/animation/animation_wait.cpp +++ b/src/animation/animation_wait.cpp @@ -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; } diff --git a/src/include/animation.h b/src/include/animation.h index 91a931940..bab6db85c 100644 --- a/src/include/animation.h +++ b/src/include/animation.h @@ -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); diff --git a/src/include/animation/animation_spawnmissile.h b/src/include/animation/animation_spawnmissile.h index bb938d8e6..f1e461ec0 100644 --- a/src/include/animation/animation_spawnmissile.h +++ b/src/include/animation/animation_spawnmissile.h @@ -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: diff --git a/src/include/animation/animation_spawnunit.h b/src/include/animation/animation_spawnunit.h index c3ff2c456..7e4e5dd8c 100644 --- a/src/include/animation/animation_spawnunit.h +++ b/src/include/animation/animation_spawnunit.h @@ -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; }; //@} diff --git a/src/include/unit.h b/src/include/unit.h index 8570613bf..95e567e2b 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -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. diff --git a/src/spell/spell_spawnportal.cpp b/src/spell/spell_spawnportal.cpp index b444dacf7..b730f94ea 100644 --- a/src/spell/spell_spawnportal.cpp +++ b/src/spell/spell_spawnportal.cpp @@ -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 diff --git a/src/spell/spell_summon.cpp b/src/spell/spell_summon.cpp index 2033c9349..08670643d 100644 --- a/src/spell/spell_summon.cpp +++ b/src/spell/spell_summon.cpp @@ -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; } } diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index 319887e59..07bc18d7b 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -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")) { diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index e3ccdb745..d8f63cb09 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -453,6 +453,7 @@ void CUnit::Init() Moving = 0; ReCast = 0; CacheLock = 0; + Summoned = 0; memset(&Anim, 0, sizeof(Anim)); CurrentResource = 0; Orders.clear(); diff --git a/src/unit/unit_save.cpp b/src/unit/unit_save.cpp index a6a12b8d6..66cb15323 100644 --- a/src/unit/unit_save.cpp +++ b/src/unit/unit_save.cpp @@ -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); }