diff --git a/src/action/action_attack.cpp b/src/action/action_attack.cpp index dcb538009a..337f904a59 100644 --- a/src/action/action_attack.cpp +++ b/src/action/action_attack.cpp @@ -87,14 +87,14 @@ void AnimateActionAttack(CUnit &unit, COrder &order) // No animation. // So direct fire missile. // FIXME : wait a little. - if (unit.Type->Animations && unit.Type->Animations->RangedAttack && unit.IsAttackRanged(order.GetGoal(), order.GetGoalPos())) { - UnitShowAnimation(unit, unit.Type->Animations->RangedAttack); + if (unit.Type->Animations && !unit.Type->Animations->RangedAttack.empty() && unit.IsAttackRanged(order.GetGoal(), order.GetGoalPos())) { + UnitShowAnimation(unit, &unit.Type->Animations->RangedAttack); } else { - if (!unit.Type->Animations || !unit.Type->Animations->Attack) { + if (!unit.Type->Animations || unit.Type->Animations->Attack.empty()) { order.OnAnimationAttack(unit); return; } - UnitShowAnimation(unit, unit.Type->Animations->Attack); + UnitShowAnimation(unit, &unit.Type->Animations->Attack); } } diff --git a/src/action/action_board.cpp b/src/action/action_board.cpp index 09ac330738..1dbb527460 100644 --- a/src/action/action_board.cpp +++ b/src/action/action_board.cpp @@ -256,7 +256,7 @@ void COrder_Board::Execute(CUnit &unit) /* override */ if (this->WaitForTransporter(unit)) { this->State = State_EnterTransporter; } else { - UnitShowAnimation(unit, unit.Type->Animations->Still); + UnitShowAnimation(unit, &unit.Type->Animations->Still); } break; diff --git a/src/action/action_build.cpp b/src/action/action_build.cpp index 58860ece86..24497193ee 100644 --- a/src/action/action_build.cpp +++ b/src/action/action_build.cpp @@ -381,7 +381,7 @@ bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop) // We need somebody to work on it. if (!type.BoolFlag[BUILDEROUTSIDE_INDEX].value) { - UnitShowAnimation(unit, unit.Type->Animations->Still); + UnitShowAnimation(unit, &unit.Type->Animations->Still); unit.Remove(build); this->State = State_BuildFromInside; if (unit.Selected) { @@ -402,10 +402,10 @@ static void AnimateActionBuild(CUnit &unit) if (animations == nullptr) { return ; } - if (animations->Build) { - UnitShowAnimation(unit, animations->Build); - } else if (animations->Repair) { - UnitShowAnimation(unit, animations->Repair); + if (!animations->Build.empty()) { + UnitShowAnimation(unit, &animations->Build); + } else if (!animations->Repair.empty()) { + UnitShowAnimation(unit, &animations->Repair); } } diff --git a/src/action/action_die.cpp b/src/action/action_die.cpp index 2141162e74..7705b7f997 100644 --- a/src/action/action_die.cpp +++ b/src/action/action_die.cpp @@ -86,11 +86,11 @@ static bool AnimateActionDie(CUnit &unit) if (animations == nullptr) { return false; } - if (animations->Death[unit.DamagedType]) { - UnitShowAnimation(unit, animations->Death[unit.DamagedType]); + if (!animations->Death[unit.DamagedType].empty()) { + UnitShowAnimation(unit, &animations->Death[unit.DamagedType]); return true; - } else if (animations->Death[ANIMATIONS_DEATHTYPES]) { - UnitShowAnimation(unit, animations->Death[ANIMATIONS_DEATHTYPES]); + } else if (!animations->Death[ANIMATIONS_DEATHTYPES].empty()) { + UnitShowAnimation(unit, &animations->Death[ANIMATIONS_DEATHTYPES]); return true; } return false; diff --git a/src/action/action_move.cpp b/src/action/action_move.cpp index 26567da140..cc2e65a2f5 100644 --- a/src/action/action_move.cpp +++ b/src/action/action_move.cpp @@ -156,10 +156,10 @@ int DoActionMove(CUnit &unit) Vec2i posd; // movement in tile. int d; - if (unit.Moving != 1 && (unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) { + if (unit.Moving != 1 && (&unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) { if (unit.Anim.Unbreakable && unit.Moving > 1) { // subtile movement, we're finished, but inside an unbreakable animation that we have to finish - int m = UnitShowAnimationScaled(unit, unit.Type->Animations->Move, 1) >> 1; + int m = UnitShowAnimationScaled(unit, &unit.Type->Animations->Move, 1) >> 1; applyResidualDisplacementCorrection(&unit.IX, m); applyResidualDisplacementCorrection(&unit.IY, m); if (unit.Anim.Unbreakable) { @@ -248,7 +248,7 @@ int DoActionMove(CUnit &unit) } unit.pathFinderData->output.Cycles++;// reset have to be manualy controlled by caller. - int move = UnitShowAnimationScaled(unit, unit.Type->Animations->Move, Map.Field(unit.Offset)->getCost()); + int move = UnitShowAnimationScaled(unit, &unit.Type->Animations->Move, Map.Field(unit.Offset)->getCost()); bool reached_next_tile = false; if (posd.x) { diff --git a/src/action/action_repair.cpp b/src/action/action_repair.cpp index 1c0d6678eb..6a38b4f55d 100644 --- a/src/action/action_repair.cpp +++ b/src/action/action_repair.cpp @@ -235,7 +235,7 @@ bool COrder_Repair::RepairUnit(const CUnit &unit, CUnit &goal) */ static void AnimateActionRepair(CUnit &unit) { - UnitShowAnimation(unit, unit.Type->Animations->Repair); + UnitShowAnimation(unit, &unit.Type->Animations->Repair); } void COrder_Repair::Execute(CUnit &unit) /* override */ diff --git a/src/action/action_research.cpp b/src/action/action_research.cpp index e72db7946f..45d476c3ea 100644 --- a/src/action/action_research.cpp +++ b/src/action/action_research.cpp @@ -125,7 +125,7 @@ void COrder_Research::Execute(CUnit &unit) /* override */ const CUnitType &type = *unit.Type; - UnitShowAnimation(unit, type.Animations->Research ? type.Animations->Research : type.Animations->Still); + UnitShowAnimation(unit, !type.Animations->Research.empty() ? &type.Animations->Research : &type.Animations->Still); if (unit.Wait) { unit.Wait--; return ; diff --git a/src/action/action_resource.cpp b/src/action/action_resource.cpp index dafcefe9a3..8b3ef870f3 100644 --- a/src/action/action_resource.cpp +++ b/src/action/action_resource.cpp @@ -614,8 +614,8 @@ int COrder_Resource::StartGathering(CUnit &unit) */ static void AnimateActionHarvest(CUnit &unit) { - Assert(unit.Type->Animations->Harvest[unit.CurrentResource]); - UnitShowAnimation(unit, unit.Type->Animations->Harvest[unit.CurrentResource]); + Assert(!unit.Type->Animations->Harvest[unit.CurrentResource].empty()); + UnitShowAnimation(unit, &unit.Type->Animations->Harvest[unit.CurrentResource]); } /** diff --git a/src/action/action_spellcast.cpp b/src/action/action_spellcast.cpp index a4fd8549be..c60d0ebf15 100644 --- a/src/action/action_spellcast.cpp +++ b/src/action/action_spellcast.cpp @@ -213,15 +213,15 @@ static void AnimateActionSpellCast(CUnit &unit, COrder_SpellCast &order) { const CAnimations *animations = unit.Type->Animations; - if (!animations || (!animations->Attack && !animations->SpellCast)) { + if (!animations || (animations->Attack.empty() && animations->SpellCast.empty())) { // if don't have animations just cast spell order.OnAnimationAttack(unit); return; } - if (animations->SpellCast) { - UnitShowAnimation(unit, animations->SpellCast); + if (!animations->SpellCast.empty()) { + UnitShowAnimation(unit, &animations->SpellCast); } else { - UnitShowAnimation(unit, animations->Attack); + UnitShowAnimation(unit, &animations->Attack); } } diff --git a/src/action/action_still.cpp b/src/action/action_still.cpp index b7e4a4f37d..3d1ac75bfb 100644 --- a/src/action/action_still.cpp +++ b/src/action/action_still.cpp @@ -386,14 +386,15 @@ void COrder_Still::Execute(CUnit &unit) /* override */ { // If unit is not bunkered and removed, wait if (unit.Removed - && (unit.Container == nullptr || unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value == false)) { - return ; + && (unit.Container == nullptr + || unit.Container->Type->BoolFlag[ATTACKFROMTRANSPORTER_INDEX].value == false)) { + return; } this->Finished = false; switch (this->State) { case SUB_STILL_STANDBY: - UnitShowAnimation(unit, unit.Type->Animations->Still); + UnitShowAnimation(unit, &unit.Type->Animations->Still); break; case SUB_STILL_ATTACK: // attacking unit in attack range. AnimateActionAttack(unit, *this); diff --git a/src/action/action_train.cpp b/src/action/action_train.cpp index 7fb1a9f067..e8d90377e5 100644 --- a/src/action/action_train.cpp +++ b/src/action/action_train.cpp @@ -170,10 +170,10 @@ static bool CanHandleOrder(const CUnit &unit, COrder *order) static void AnimateActionTrain(CUnit &unit) { - if (unit.Type->Animations->Train) { - UnitShowAnimation(unit, unit.Type->Animations->Train); + if (!unit.Type->Animations->Train.empty()) { + UnitShowAnimation(unit, &unit.Type->Animations->Train); } else { - UnitShowAnimation(unit, unit.Type->Animations->Still); + UnitShowAnimation(unit, &unit.Type->Animations->Still); } } diff --git a/src/action/action_upgradeto.cpp b/src/action/action_upgradeto.cpp index 35aaa8a180..28be0a7115 100644 --- a/src/action/action_upgradeto.cpp +++ b/src/action/action_upgradeto.cpp @@ -278,7 +278,7 @@ static void AnimateActionUpgradeTo(CUnit &unit) { CAnimations &animations = *unit.Type->Animations; - UnitShowAnimation(unit, animations.Upgrade ? animations.Upgrade : animations.Still); + UnitShowAnimation(unit, !animations.Upgrade.empty() ? &animations.Upgrade : &animations.Still); } void COrder_UpgradeTo::Execute(CUnit &unit) /* override */ diff --git a/src/action/actions.cpp b/src/action/actions.cpp index 522c613399..273739b334 100644 --- a/src/action/actions.cpp +++ b/src/action/actions.cpp @@ -117,7 +117,7 @@ bool COrder::IsWaiting(CUnit &unit) unit.Waiting = 1; unit.WaitBackup = unit.Anim; } - UnitShowAnimation(unit, unit.Type->Animations->Still); + UnitShowAnimation(unit, &unit.Type->Animations->Still); unit.Wait--; return true; } diff --git a/src/animation/animation.cpp b/src/animation/animation.cpp index cde3afa3b8..b3a7c2e194 100644 --- a/src/animation/animation.cpp +++ b/src/animation/animation.cpp @@ -73,23 +73,15 @@ #include "unittype.h" #include "pathfinder.h" -struct LabelsStruct { - CAnimation *Anim; - std::string Name; -}; -static std::vector Labels; - struct LabelsLaterStruct { - CAnimation **Anim; + std::size_t *Index; std::string Name; }; static std::vector LabelsLater; -static std::vector AnimationsArray; - +static std::vector>*> AnimationsArray; static std::map, std::less<>> AnimationMap;/// Animation map - /*---------------------------------------------------------------------------- -- Animation ----------------------------------------------------------------------------*/ @@ -157,7 +149,7 @@ void modifyValue(SetVar_ModifyTypes mod, int &value, int rop) ** ** @return The flags of the current script step. */ -int UnitShowAnimation(CUnit &unit, const CAnimation *anim) +int UnitShowAnimation(CUnit &unit, const std::vector> *anim) { return UnitShowAnimationScaled(unit, anim, 8); } @@ -351,13 +343,14 @@ int ParseAnimInt(const CUnit &unit, const std::string_view s) ** ** @return The flags of the current script step. */ -int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale) +int UnitShowAnimationScaled(CUnit &unit, const std::vector> *anim, int scale) { // Changing animations - if (anim && unit.Anim.CurrAnim != anim) { + if (anim && !anim->empty() && unit.Anim.CurrAnim != anim) { // Assert fails when transforming unit (upgrade-to). Assert(!unit.Anim.Unbreakable || unit.Waiting); - unit.Anim.Anim = unit.Anim.CurrAnim = anim; + unit.Anim.CurrAnim = anim; + unit.Anim.Anim = 0; unit.Anim.Wait = 0; } @@ -379,23 +372,23 @@ int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale) --unit.Anim.Wait; if (!unit.Anim.Wait) { // Advance to next frame - unit.Anim.Anim = unit.Anim.Anim->Next; + unit.Anim.Anim = (unit.Anim.Anim + 1) % unit.Anim.CurrAnim->size(); } return 0; } int move = 0; while (!unit.Anim.Wait) { - unit.Anim.Anim->Action(unit, move, scale); + (*unit.Anim.CurrAnim)[unit.Anim.Anim]->Action(unit, move, scale); if (!unit.Anim.Wait) { // Advance to next frame - unit.Anim.Anim = unit.Anim.Anim->Next; + unit.Anim.Anim = (unit.Anim.Anim + 1) % unit.Anim.CurrAnim->size(); } } --unit.Anim.Wait; if (!unit.Anim.Wait) { // Advance to next frame - unit.Anim.Anim = unit.Anim.Anim->Next; + unit.Anim.Anim = (unit.Anim.Anim + 1) % unit.Anim.CurrAnim->size(); } return move; } @@ -424,54 +417,30 @@ void FreeAnimations() AnimationsArray.clear(); } -static int GetAdvanceIndex(const CAnimation *base, const CAnimation *anim) +namespace { - if (base == anim) { - return 0; - } - int i = 1; - for (const CAnimation *it = base->Next; it != base; it = it->Next) { - if (it == anim) { - return i; - } - ++i; - } - return -1; -} - - -/* static */ void CAnimations::SaveUnitAnim(CFile &file, const CUnit &unit) +void SaveUnitUnitAnim(CFile &file, std::string_view name, const CUnit::_unit_anim_ &anim) { - file.printf("\"anim-data\", {"); - file.printf("\"anim-wait\", %d,", unit.Anim.Wait); - if (auto it = ranges::find(AnimationsArray, unit.Anim.CurrAnim); it != AnimationsArray.end()) { - file.printf("\"curr-anim\", %d,", static_cast(std::distance(AnimationsArray.begin(), it))); - file.printf("\"anim\", %d,", GetAdvanceIndex(unit.Anim.CurrAnim, unit.Anim.Anim)); - } - if (unit.Anim.Unbreakable) { - file.printf(" \"unbreakable\","); - } - file.printf("}, "); - // Wait backup info - file.printf("\"wait-anim-data\", {"); - file.printf("\"anim-wait\", %d,", unit.WaitBackup.Wait); - if (auto it = ranges::find(AnimationsArray, unit.WaitBackup.CurrAnim); it != AnimationsArray.end()) { - file.printf("\"curr-anim\", %d,", static_cast(std::distance(AnimationsArray.begin(), it))); - file.printf("\"anim\", %d,", GetAdvanceIndex(unit.WaitBackup.CurrAnim, unit.WaitBackup.Anim)); - } - if (unit.WaitBackup.Unbreakable) { + file.printf("\"%s\", {", name.data()); + file.printf("\"anim-wait\", %d,", anim.Wait); + if (auto it = ranges::find(AnimationsArray, anim.CurrAnim); it != AnimationsArray.end()) { + file.printf("\"curr-anim\", %d,", + static_cast(std::distance(AnimationsArray.begin(), it))); + file.printf("\"anim\", %d,", static_cast(anim.Anim)); + } + if (anim.Unbreakable) { file.printf(" \"unbreakable\","); } file.printf("}"); } +} -static const CAnimation *Advance(const CAnimation *anim, int n) +/* static */ void CAnimations::SaveUnitAnim(CFile &file, const CUnit &unit) { - for (int i = 0; i < n; ++i) { - anim = anim->Next; - } - return anim; + SaveUnitUnitAnim(file, "anim-data", unit.Anim); + file.printf(", "); + SaveUnitUnitAnim(file, "wait-anim-data", unit.WaitBackup); } static void LoadUnitUnitAnim(lua_State *l, int luaIndex, CUnit::_unit_anim_ &anim) @@ -492,7 +461,7 @@ static void LoadUnitUnitAnim(lua_State *l, int luaIndex, CUnit::_unit_anim_ &ani anim.CurrAnim = AnimationsArray[animIndex]; } else if (value == "anim") { const int animIndex = LuaToNumber(l, luaIndex, j + 1); - anim.Anim = Advance(anim.CurrAnim, animIndex); + anim.Anim = animIndex; } else if (value == "unbreakable") { anim.Unbreakable = true; --j; @@ -513,40 +482,32 @@ static void LoadUnitUnitAnim(lua_State *l, int luaIndex, CUnit::_unit_anim_ &ani LoadUnitUnitAnim(l, luaIndex, unit.WaitBackup); } -/** -** Add a label -*/ -static void AddLabel(CAnimation *anim, const std::string &name) -{ - LabelsStruct label; - - label.Anim = anim; - label.Name = name; - Labels.push_back(label); -} - /** ** Find a label */ -static CAnimation *FindLabel(lua_State *l, const std::string &name) +static std::size_t FindLabel(lua_State *l, const std::vector>& anims, const std::string &name) { - for (auto &label : Labels) { - if (label.Name == name) { - return label.Anim; + const auto is_wanted_label = [&](const auto& anim) { + if (const auto* p = dynamic_cast(anim.get())) { + return p->name == name; } + return false; + }; + auto it = ranges::find_if(anims, is_wanted_label); + if (it == anims.end()) { + LuaError(l, "Label not found: %s", name.c_str()); } - LuaError(l, "Label not found: %s", name.c_str()); - return nullptr; + return std::distance(anims.begin(), it); } /** ** Find a label later */ -void FindLabelLater(CAnimation **anim, std::string name) +void FindLabelLater(std::size_t *index, std::string name) { LabelsLaterStruct label; - label.Anim = anim; + label.Index = index; label.Name = std::move(name); LabelsLater.push_back(std::move(label)); } @@ -554,10 +515,10 @@ void FindLabelLater(CAnimation **anim, std::string name) /** ** Fix labels */ -static void FixLabels(lua_State *l) +static void FixLabels(lua_State *l, const std::vector>& anims) { for (auto &labelLater : LabelsLater) { - *labelLater.Anim = FindLabel(l, labelLater.Name); + *labelLater.Index = FindLabel(l, anims, labelLater.Name); } } @@ -567,7 +528,8 @@ static void FixLabels(lua_State *l) ** ** @param str string formated as "animationType extraArgs" */ -static CAnimation *ParseAnimationFrame(lua_State *l, std::string_view str) +static std::unique_ptr +ParseAnimationFrame(lua_State *l, std::string_view str) { const std::string all(str); const size_t len = all.size(); @@ -576,52 +538,51 @@ static CAnimation *ParseAnimationFrame(lua_State *l, std::string_view str) size_t begin = std::min(len, all.find_first_not_of(' ', end)); const std::string extraArg(all, begin); - CAnimation *anim = nullptr; + std::unique_ptr anim; if (op1 == "frame") { - anim = new CAnimation_Frame; + anim = std::make_unique(); } else if (op1 == "exact-frame") { - anim = new CAnimation_ExactFrame; + anim = std::make_unique(); } else if (op1 == "wait") { - anim = new CAnimation_Wait; + anim = std::make_unique(); } else if (op1 == "random-wait") { - anim = new CAnimation_RandomWait; + anim = std::make_unique(); } else if (op1 == "sound") { - anim = new CAnimation_Sound; + anim = std::make_unique(); } else if (op1 == "random-sound") { - anim = new CAnimation_RandomSound; + anim = std::make_unique(); } else if (op1 == "attack") { - anim = new CAnimation_Attack; + anim = std::make_unique(); } else if (op1 == "spawn-missile") { - anim = new CAnimation_SpawnMissile; + anim = std::make_unique(); } else if (op1 == "spawn-unit") { - anim = new CAnimation_SpawnUnit; + anim = std::make_unique(); } else if (op1 == "if-var") { - anim = new CAnimation_IfVar; + anim = std::make_unique(); } else if (op1 == "set-var") { - anim = new CAnimation_SetVar; + anim = std::make_unique(); } else if (op1 == "set-player-var") { - anim = new CAnimation_SetPlayerVar; + anim = std::make_unique(); } else if (op1 == "die") { - anim = new CAnimation_Die(); + anim = std::make_unique(); } else if (op1 == "rotate") { - anim = new CAnimation_Rotate; + anim = std::make_unique(); } else if (op1 == "random-rotate") { - anim = new CAnimation_RandomRotate; + anim = std::make_unique(); } else if (op1 == "move") { - anim = new CAnimation_Move; + anim = std::make_unique(); } else if (op1 == "unbreakable") { - anim = new CAnimation_Unbreakable; + anim = std::make_unique(); } else if (op1 == "label") { - anim = new CAnimation_Label; - AddLabel(anim, extraArg); + anim = std::make_unique(); } else if (op1 == "goto") { - anim = new CAnimation_Goto; + anim = std::make_unique(); } else if (op1 == "random-goto") { - anim = new CAnimation_RandomGoto; + anim = std::make_unique(); } else if (op1 == "lua-callback") { - anim = new CAnimation_LuaCallback; + anim = std::make_unique(); } else if (op1 == "wiggle") { - anim = new CAnimation_Wiggle; + anim = std::make_unique(); } else { LuaError(l, "Unknown animation: %s", op1.c_str()); } @@ -632,7 +593,7 @@ static CAnimation *ParseAnimationFrame(lua_State *l, std::string_view str) /** ** Parse an animation */ -static CAnimation *ParseAnimation(lua_State *l, int idx) +static std::vector> ParseAnimation(lua_State *l, int idx) { if (!lua_istable(l, idx)) { LuaError(l, "incorrect argument"); @@ -640,35 +601,29 @@ static CAnimation *ParseAnimation(lua_State *l, int idx) const int args = lua_rawlen(l, idx); if (args == 0) { - return nullptr; + return {}; } - Labels.clear(); LabelsLater.clear(); - const std::string_view str = LuaToString(l, idx, 1); - - CAnimation *firstAnim = ParseAnimationFrame(l, str); - CAnimation *prev = firstAnim; - for (int j = 1; j < args; ++j) { - const std::string_view str = LuaToString(l, idx, j + 1); - CAnimation *anim = ParseAnimationFrame(l, str); - prev->Next = anim; - prev = anim; + std::vector> animations; + for (int i = 0; i != args; ++i) { + const std::string_view str = LuaToString(l, idx, 1 + i); + animations.emplace_back(ParseAnimationFrame(l, str)); } - prev->Next = firstAnim; - FixLabels(l); - return firstAnim; + + FixLabels(l, animations); + return animations; } /** ** Add animation to AnimationsArray */ -static void AddAnimationToArray(CAnimation *anim) +static void AddAnimationToArray(std::vector> *anims) { - if (!anim) { + if (!anims) { return; } - AnimationsArray.push_back(anim); + AnimationsArray.push_back(anims); } /** @@ -736,19 +691,19 @@ static int CclDefineAnimations(lua_State *l) lua_pop(l, 1); } // Must add to array in a fixed order for save games - AddAnimationToArray(anims->Start); - AddAnimationToArray(anims->Still); + AddAnimationToArray(&anims->Start); + AddAnimationToArray(&anims->Still); for (int i = 0; i != ANIMATIONS_DEATHTYPES + 1; ++i) { - AddAnimationToArray(anims->Death[i]); - } - AddAnimationToArray(anims->Attack); - AddAnimationToArray(anims->RangedAttack); - AddAnimationToArray(anims->SpellCast); - AddAnimationToArray(anims->Move); - AddAnimationToArray(anims->Repair); - AddAnimationToArray(anims->Train); + AddAnimationToArray(&anims->Death[i]); + } + AddAnimationToArray(&anims->Attack); + AddAnimationToArray(&anims->RangedAttack); + AddAnimationToArray(&anims->SpellCast); + AddAnimationToArray(&anims->Move); + AddAnimationToArray(&anims->Repair); + AddAnimationToArray(&anims->Train); for (int i = 0; i != MaxCosts; ++i) { - AddAnimationToArray(anims->Harvest[i]); + AddAnimationToArray(&anims->Harvest[i]); } return 0; } diff --git a/src/animation/animation_attack.cpp b/src/animation/animation_attack.cpp index 6c4ae60aa3..b2cb035829 100644 --- a/src/animation/animation_attack.cpp +++ b/src/animation/animation_attack.cpp @@ -42,7 +42,8 @@ void CAnimation_Attack::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); unit.CurrentOrder()->OnAnimationAttack(unit); } diff --git a/src/animation/animation_die.cpp b/src/animation/animation_die.cpp index dc6a9b8011..53e843ee74 100644 --- a/src/animation/animation_die.cpp +++ b/src/animation/animation_die.cpp @@ -43,7 +43,8 @@ void CAnimation_Die::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if (unit.Anim.Unbreakable) { ErrorPrint("Can't call \"die\" action in unbreakable section\n"); Exit(1); diff --git a/src/animation/animation_exactframe.cpp b/src/animation/animation_exactframe.cpp index 8b530ff3a7..18e22ddb0c 100644 --- a/src/animation/animation_exactframe.cpp +++ b/src/animation/animation_exactframe.cpp @@ -41,7 +41,8 @@ void CAnimation_ExactFrame::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); unit.Frame = ParseAnimInt(&unit); } diff --git a/src/animation/animation_frame.cpp b/src/animation/animation_frame.cpp index 19b75b16c3..91a76e4592 100644 --- a/src/animation/animation_frame.cpp +++ b/src/animation/animation_frame.cpp @@ -42,7 +42,8 @@ void CAnimation_Frame::Action(CUnit &unit, int &/*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if (unit.Type->Building && unit.Type->NumDirections == 1 && FancyBuildings && unit.Type->BoolFlag[NORANDOMPLACING_INDEX].value == false && unit.Frame < 0) { } else { unit.Frame = ParseAnimInt(&unit); diff --git a/src/animation/animation_goto.cpp b/src/animation/animation_goto.cpp index dc7574f9d4..8bdc860ca6 100644 --- a/src/animation/animation_goto.cpp +++ b/src/animation/animation_goto.cpp @@ -41,7 +41,8 @@ void CAnimation_Goto::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); unit.Anim.Anim = this->gotoLabel; } diff --git a/src/animation/animation_ifvar.cpp b/src/animation/animation_ifvar.cpp index 5046b7e2f6..266e53ba50 100644 --- a/src/animation/animation_ifvar.cpp +++ b/src/animation/animation_ifvar.cpp @@ -69,7 +69,8 @@ static bool returnFalse(int, int) { return false; } void CAnimation_IfVar::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); const int lop = ParseAnimInt(unit, this->leftVar); const int rop = ParseAnimInt(unit, this->rightVar); diff --git a/src/animation/animation_label.cpp b/src/animation/animation_label.cpp index 42670478c5..71245d68d8 100644 --- a/src/animation/animation_label.cpp +++ b/src/animation/animation_label.cpp @@ -41,11 +41,13 @@ void CAnimation_Label::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); } void CAnimation_Label::Init(std::string_view s, lua_State *) /* override */ { + name = s; } //@} diff --git a/src/animation/animation_luacallback.cpp b/src/animation/animation_luacallback.cpp index e31d1bdef8..ac7105204f 100644 --- a/src/animation/animation_luacallback.cpp +++ b/src/animation/animation_luacallback.cpp @@ -45,7 +45,8 @@ void CAnimation_LuaCallback::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); Assert(cb); cb->pushPreamble(); diff --git a/src/animation/animation_move.cpp b/src/animation/animation_move.cpp index 58fbe8988a..4abd1257f3 100644 --- a/src/animation/animation_move.cpp +++ b/src/animation/animation_move.cpp @@ -41,7 +41,8 @@ void CAnimation_Move::Action(CUnit &unit, int &move, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); Assert(!move); move = ParseAnimInt(unit, this->moveStr); diff --git a/src/animation/animation_randomgoto.cpp b/src/animation/animation_randomgoto.cpp index ed365138b7..f71439116a 100644 --- a/src/animation/animation_randomgoto.cpp +++ b/src/animation/animation_randomgoto.cpp @@ -43,7 +43,8 @@ void CAnimation_RandomGoto::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if (SyncRand() % 100 < ParseAnimInt(unit, this->randomStr)) { unit.Anim.Anim = this->gotoLabel; diff --git a/src/animation/animation_randomrotate.cpp b/src/animation/animation_randomrotate.cpp index e70e7d57a6..ade3683cb8 100644 --- a/src/animation/animation_randomrotate.cpp +++ b/src/animation/animation_randomrotate.cpp @@ -44,7 +44,8 @@ void CAnimation_RandomRotate::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if ((SyncRand() >> 8) & 1) { UnitRotate(unit, -ParseAnimInt(unit, this->rotateStr)); diff --git a/src/animation/animation_randomsound.cpp b/src/animation/animation_randomsound.cpp index c8fc7725c5..4fae3af1cb 100644 --- a/src/animation/animation_randomsound.cpp +++ b/src/animation/animation_randomsound.cpp @@ -46,7 +46,8 @@ void CAnimation_RandomSound::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if (unit.IsVisible(*ThisPlayer) || ReplayRevealMap) { const size_t index = MyRand() % this->sounds.size(); diff --git a/src/animation/animation_randomwait.cpp b/src/animation/animation_randomwait.cpp index b7c27805a4..09cda2cdea 100644 --- a/src/animation/animation_randomwait.cpp +++ b/src/animation/animation_randomwait.cpp @@ -43,7 +43,8 @@ void CAnimation_RandomWait::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); const int arg1 = ParseAnimInt(unit, this->minWait); const int arg2 = ParseAnimInt(unit, this->maxWait); diff --git a/src/animation/animation_rotate.cpp b/src/animation/animation_rotate.cpp index 295eef2701..9ff0fc8744 100644 --- a/src/animation/animation_rotate.cpp +++ b/src/animation/animation_rotate.cpp @@ -56,7 +56,8 @@ void UnitRotate(CUnit &unit, int rotate) void CAnimation_Rotate::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if (this->rotateStr == "target") { COrder *order = unit.CurrentOrder(); diff --git a/src/animation/animation_setplayervar.cpp b/src/animation/animation_setplayervar.cpp index e83c695c17..97c240ce7d 100644 --- a/src/animation/animation_setplayervar.cpp +++ b/src/animation/animation_setplayervar.cpp @@ -182,7 +182,8 @@ void CAnimation_SetPlayerVar::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); const int playerId = ParseAnimInt(unit, this->playerStr); const int rop = ParseAnimInt(unit, this->valueStr); diff --git a/src/animation/animation_setvar.cpp b/src/animation/animation_setvar.cpp index 965ea158b0..d6340ad019 100644 --- a/src/animation/animation_setvar.cpp +++ b/src/animation/animation_setvar.cpp @@ -47,7 +47,8 @@ void CAnimation_SetVar::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); CUnit *goal = &unit; if (this->unitSlotStr.empty() == false) { diff --git a/src/animation/animation_sound.cpp b/src/animation/animation_sound.cpp index 4af113fb78..2c5b3c7be0 100644 --- a/src/animation/animation_sound.cpp +++ b/src/animation/animation_sound.cpp @@ -43,7 +43,8 @@ void CAnimation_Sound::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); if (unit.IsVisible(*ThisPlayer) || ReplayRevealMap) { PlayUnitSound(unit, this->sound.Sound); } diff --git a/src/animation/animation_spawnmissile.cpp b/src/animation/animation_spawnmissile.cpp index 3aa285e294..d7cabc4b1b 100644 --- a/src/animation/animation_spawnmissile.cpp +++ b/src/animation/animation_spawnmissile.cpp @@ -100,7 +100,8 @@ SpawnMissile_Flags ParseAnimFlags(const std::string_view &parseflag) void CAnimation_SpawnMissile::Action(CUnit &unit, int &/*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); const int startx = ParseAnimInt(unit, this->startXStr); const int starty = ParseAnimInt(unit, this->startYStr); diff --git a/src/animation/animation_spawnunit.cpp b/src/animation/animation_spawnunit.cpp index 87700fcf79..8884083da4 100644 --- a/src/animation/animation_spawnunit.cpp +++ b/src/animation/animation_spawnunit.cpp @@ -83,7 +83,8 @@ SpawnUnit_Flags ParseAnimFlags(const std::string_view &parseflag) void CAnimation_SpawnUnit::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); const int offX = ParseAnimInt(unit, this->offXStr); const int offY = ParseAnimInt(unit, this->offYStr); diff --git a/src/animation/animation_unbreakable.cpp b/src/animation/animation_unbreakable.cpp index 80bab0748f..77343642bb 100644 --- a/src/animation/animation_unbreakable.cpp +++ b/src/animation/animation_unbreakable.cpp @@ -41,7 +41,8 @@ void CAnimation_Unbreakable::Action(CUnit &unit, int & /*move*/, int /*scale*/) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); Assert(unit.Anim.Unbreakable ^ this->state); unit.Anim.Unbreakable = this->state; diff --git a/src/animation/animation_wait.cpp b/src/animation/animation_wait.cpp index 149787a712..d2c95f09c0 100644 --- a/src/animation/animation_wait.cpp +++ b/src/animation/animation_wait.cpp @@ -41,7 +41,8 @@ void CAnimation_Wait::Action(CUnit &unit, int & /*move*/, int scale) const /* override */ { - Assert(unit.Anim.Anim == this); + Assert(unit.Anim.CurrAnim); + Assert((*unit.Anim.CurrAnim)[unit.Anim.Anim].get() == this); unit.Anim.Wait = ParseAnimInt(unit, this->wait) << 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 21d6b9aa22..f76dd58d79 100644 --- a/src/include/animation.h +++ b/src/include/animation.h @@ -81,65 +81,35 @@ class CAnimation virtual void Init(std::string_view s, lua_State *l = nullptr) {} virtual void MapSound() {} virtual std::optional GetStillFrame(const CUnitType &type) { return std::nullopt; } - - CAnimation *Next = nullptr; }; class CAnimations { public: - CAnimations() : Attack(nullptr), RangedAttack(nullptr), Build(nullptr), hasDeathAnimation(false), - Move(nullptr), Repair(nullptr), - Research(nullptr), SpellCast(nullptr), Start(nullptr), Still(nullptr), - Train(nullptr), Upgrade(nullptr) - { - memset(Death, 0, sizeof(Death)); - memset(Harvest, 0, sizeof(Harvest)); - } - - ~CAnimations() - { - delete Attack; - delete RangedAttack; - delete Build; - for (auto *p : Death) { - delete p; - } - for (auto *p : Harvest) { - delete p; - } - delete Move; - delete Repair; - delete Research; - delete SpellCast; - delete Start; - delete Still; - delete Train; - delete Upgrade; - } + CAnimations() = default; + ~CAnimations() = default; static void SaveUnitAnim(CFile &file, const CUnit &unit); static void LoadUnitAnim(lua_State *l, CUnit &unit, int luaIndex); static void LoadWaitUnitAnim(lua_State *l, CUnit &unit, int luaIndex); public: - CAnimation *Attack; - CAnimation *RangedAttack; - CAnimation *Build; - bool hasDeathAnimation; - CAnimation *Death[ANIMATIONS_DEATHTYPES + 1]; - CAnimation *Harvest[MaxCosts]; - CAnimation *Move; - CAnimation *Repair; - CAnimation *Research; - CAnimation *SpellCast; - CAnimation *Start; - CAnimation *Still; - CAnimation *Train; - CAnimation *Upgrade; + std::vector> Attack; + std::vector> RangedAttack; + std::vector> Build; + bool hasDeathAnimation = false; + std::vector> Death[ANIMATIONS_DEATHTYPES + 1]; + std::vector> Harvest[MaxCosts]; + std::vector> Move; + std::vector> Repair; + std::vector> Research; + std::vector> SpellCast; + std::vector> Start; + std::vector> Still; + std::vector> Train; + std::vector> Upgrade; }; - /*---------------------------------------------------------------------------- -- Functions ----------------------------------------------------------------------------*/ @@ -150,14 +120,16 @@ extern CAnimations &AnimationsByIdent(std::string_view ident); extern void AnimationCclRegister(); /// Handle the animation of a unit -extern int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scale); +extern int UnitShowAnimationScaled(CUnit &unit, + const std::vector> *anims, + int scale); /// Handle the animation of a unit -extern int UnitShowAnimation(CUnit &unit, const CAnimation *anim); +extern int UnitShowAnimation(CUnit &unit, const std::vector> *anims); extern int ParseAnimInt(const CUnit &unit, std::string_view parseint); -extern void FindLabelLater(CAnimation **anim, std::string name); +extern void FindLabelLater(std::size_t *labelIndex, std::string name); extern void FreeAnimations(); diff --git a/src/include/animation/animation_goto.h b/src/include/animation/animation_goto.h index 6b4ffa6167..2332704604 100644 --- a/src/include/animation/animation_goto.h +++ b/src/include/animation/animation_goto.h @@ -42,7 +42,7 @@ class CAnimation_Goto : public CAnimation void Init(std::string_view s, lua_State *l) override; private: - CAnimation *gotoLabel = nullptr; + std::size_t gotoLabel = 0; }; //@} diff --git a/src/include/animation/animation_ifvar.h b/src/include/animation/animation_ifvar.h index 1da92838b9..17be2caa82 100644 --- a/src/include/animation/animation_ifvar.h +++ b/src/include/animation/animation_ifvar.h @@ -48,7 +48,7 @@ class CAnimation_IfVar : public CAnimation std::string leftVar; std::string rightVar; BinOpFunc *binOpFunc = nullptr; - CAnimation *gotoLabel = nullptr; + std::size_t gotoLabel = 0; }; //@} diff --git a/src/include/animation/animation_label.h b/src/include/animation/animation_label.h index e76e7c9074..8108f0d2ab 100644 --- a/src/include/animation/animation_label.h +++ b/src/include/animation/animation_label.h @@ -39,6 +39,9 @@ class CAnimation_Label : public CAnimation public: void Action(CUnit &unit, int &move, int scale) const override; void Init(std::string_view s, lua_State *l) override; + +public: + std::string name; }; //@} diff --git a/src/include/animation/animation_randomgoto.h b/src/include/animation/animation_randomgoto.h index 7278211306..07d9f89297 100644 --- a/src/include/animation/animation_randomgoto.h +++ b/src/include/animation/animation_randomgoto.h @@ -43,7 +43,7 @@ class CAnimation_RandomGoto : public CAnimation private: std::string randomStr; - CAnimation *gotoLabel = nullptr; + std::size_t gotoLabel = 0; }; //@} diff --git a/src/include/animation/animation_wiggle.h b/src/include/animation/animation_wiggle.h index a34db4d809..69ab18b81b 100644 --- a/src/include/animation/animation_wiggle.h +++ b/src/include/animation/animation_wiggle.h @@ -47,7 +47,7 @@ class CAnimation_Wiggle : public CAnimation bool isHeading = false; bool isZDisplacement = false; std::string speed; - CAnimation *ifNotReached = nullptr; + std::size_t ifNotReached = 0; }; //@} diff --git a/src/include/unit.h b/src/include/unit.h index 1130be663c..2596b5bb92 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -417,8 +417,8 @@ class CUnit int UnderAttack = 0; /// The counter while small ai can ignore non aggressive targets if searching attacker. struct _unit_anim_ { - const CAnimation *Anim = nullptr; /// Anim - const CAnimation *CurrAnim = nullptr; /// CurrAnim + const std::vector>* CurrAnim = nullptr; /// CurrAnim + std::size_t Anim = 0; /// Anim short Wait = 0; /// Wait time signed char Rotate = 0; /// Rotation target and direction bool Unbreakable = false; /// Unbreakable diff --git a/src/missile/missile.cpp b/src/missile/missile.cpp index 008c2082ba..368fb6ea16 100644 --- a/src/missile/missile.cpp +++ b/src/missile/missile.cpp @@ -317,9 +317,12 @@ void FireMissile(CUnit &unit, CUnit *goal, const Vec2i &goalPos) } // No missile hits immediately! - if ( - unit.Type->Missile.Missile->Class == MissileClass::Nothing - || (unit.Type->Animations && unit.Type->Animations->Attack && unit.Type->Animations->RangedAttack && !unit.IsAttackRanged(goal, goalPos)) // treat melee attacks from units that have both attack and ranged attack animations as having missile class none + if (unit.Type->Missile.Missile->Class == MissileClass::Nothing + || (unit.Type->Animations && !unit.Type->Animations->Attack.empty() + && !unit.Type->Animations->RangedAttack.empty() + && !unit.IsAttackRanged( + goal, + goalPos)) // treat melee attacks from units that have both attack and ranged attack animations as having missile class none ) { // No goal, take target coordinates if (!goal) { diff --git a/src/sound/unitsound.cpp b/src/sound/unitsound.cpp index da061cc477..9729a57815 100644 --- a/src/sound/unitsound.cpp +++ b/src/sound/unitsound.cpp @@ -84,14 +84,10 @@ void LoadUnitSounds() /** ** Map animation sounds */ -static void MapAnimSounds2(CAnimation *anim) +static void MapAnimSounds2(std::vector>& anims) { - if (anim == nullptr) { - return ; - } - anim->MapSound(); - for (CAnimation *it = anim->Next; it != anim; it = it->Next) { - it->MapSound(); + for (auto &anim : anims) { + anim->MapSound(); } } diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp index 2d7d23636b..2782ab6388 100644 --- a/src/unit/unittype.cpp +++ b/src/unit/unittype.cpp @@ -575,7 +575,7 @@ bool CUnitType::CheckUserBoolFlags(const std::vector &BoolFlags) con bool CUnitType::CanMove() const { - return Animations && Animations->Move; + return Animations && !Animations->Move.empty(); } bool CUnitType::CanSelect(EGroupSelectionMode mode) const @@ -872,14 +872,11 @@ void DrawUnitType(const CUnitType &type, CPlayerColorGraphic *sprite, int colorI */ static int GetStillFrame(const CUnitType &type) { - CAnimation *anim = type.Animations->Still; - - while (anim) { + for (auto& anim : type.Animations->Still) { auto frame = anim->GetStillFrame(type); if (frame) { return *frame; } - anim = anim->Next; } return type.NumDirections / 2; }