Index: binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/Attack.js +++ binaries/data/mods/public/simulation/components/Attack.js @@ -403,15 +403,22 @@ return aPreference - bPreference; }; -Attack.prototype.GetTimers = function(type) +Attack.prototype.GetRepeatTime = function(type) { - let prepare = +(this.template[type].PrepareTime || 0); - prepare = ApplyValueModificationsToEntity("Attack/" + type + "/PrepareTime", prepare, this.entity); + let repeatTime = 1000; + + if (this.template[type] && this.template[type].RepeatTime) + repeatTime = +this.template[type].RepeatTime; - let repeat = +(this.template[type].RepeatTime || 1000); - repeat = ApplyValueModificationsToEntity("Attack/" + type + "/RepeatTime", repeat, this.entity); + return ApplyValueModificationsToEntity("Attack/" + type + "/RepeatTime", repeatTime, this.entity); +}; - return { "prepare": prepare, "repeat": repeat }; +Attack.prototype.GetTimers = function(type) +{ + return { + "prepare": ApplyValueModificationsToEntity("Attack/" + type + "/PrepareTime", +this.template[type].PrepareTime || 0, this.entity), + "repeat": this.GetRepeatTime(type) + }; }; Attack.prototype.GetSplashData = function(type) Index: binaries/data/mods/public/simulation/components/interfaces/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/interfaces/Attack.js +++ binaries/data/mods/public/simulation/components/interfaces/Attack.js @@ -1,5 +1,3 @@ -Engine.RegisterInterface("Attack"); - /** * Message of the form { "attacker": number, "target": number, "type": string, "damage": number, "attackerOwner": number } * sent from Attack component and by Damage component to the target entity, each time the target is attacked or damaged. Index: binaries/data/mods/public/simulation/components/tests/test_Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/tests/test_Attack.js +++ binaries/data/mods/public/simulation/components/tests/test_Attack.js @@ -180,11 +180,16 @@ "repeat": 500 }); + + TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetRepeatTime("Ranged"), 500); + TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetTimers("Capture"), { "prepare": 0, "repeat": 1000 }); + TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetRepeatTime("Capture"), 1000); + TS_ASSERT_UNEVAL_EQUALS(cmpAttack.GetSplashData("Ranged"), { "attackData": { "Damage": { Index: source/simulation2/TypeList.h =================================================================== --- source/simulation2/TypeList.h +++ source/simulation2/TypeList.h @@ -79,6 +79,9 @@ INTERFACE(AIManager) COMPONENT(AIManager) +INTERFACE(Attack) +COMPONENT(AttackScripted) + INTERFACE(CinemaManager) COMPONENT(CinemaManager) Index: source/simulation2/components/ICmpAttack.h =================================================================== --- /dev/null +++ source/simulation2/components/ICmpAttack.h @@ -0,0 +1,30 @@ +/* Copyright (C) 2020 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_ICMPATTACK +#define INCLUDED_ICMPATTACK + +#include "simulation2/system/Interface.h" + +class ICmpAttack : public IComponent +{ +public: + virtual float GetRepeatTime(std::string type) = 0; + DECLARE_INTERFACE_TYPE(Attack) +}; + +#endif // INCLUDED_ICMPATTACK Index: source/simulation2/components/ICmpAttack.cpp =================================================================== --- /dev/null +++ source/simulation2/components/ICmpAttack.cpp @@ -0,0 +1,40 @@ +/* Copyright (C) 2020 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "ICmpAttack.h" + +#include "simulation2/system/InterfaceScripted.h" +#include "simulation2/scripting/ScriptComponent.h" + + +BEGIN_INTERFACE_WRAPPER(Attack) +END_INTERFACE_WRAPPER(Attack) + +class CCmpAttackScripted : public ICmpAttack +{ +public: + DEFAULT_SCRIPT_WRAPPER(AttackScripted) + + virtual float GetRepeatTime(std::string type) + { + return m_Script.Call("GetRepeatTime", type); + } +}; + +REGISTER_COMPONENT_SCRIPT_WRAPPER(AttackScripted) Index: source/tools/atlas/GameInterface/ActorViewer.cpp =================================================================== --- source/tools/atlas/GameInterface/ActorViewer.cpp +++ source/tools/atlas/GameInterface/ActorViewer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2020 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -48,6 +48,7 @@ #include "renderer/WaterManager.h" #include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" +#include "simulation2/components/ICmpAttack.h" #include "simulation2/components/ICmpOwnership.h" #include "simulation2/components/ICmpPosition.h" #include "simulation2/components/ICmpRangeManager.h" @@ -213,6 +214,8 @@ void UpdatePropList(); void UpdatePropListRecursive(CModelAbstract* model); +private: + float GetRepeatTime(std::string type) const; }; void ActorViewerImpl::UpdatePropList() @@ -377,11 +380,14 @@ if (needsAnimReload) { + // Emulate the typical simulation animation behaviour. CStr anim = animation.LowerCase(); + CStr sound = anim; - // Emulate the typical simulation animation behaviour - float speed; - float repeattime = 0.f; + // Speed will be ignored if we have a repeat time. + float speed = 1.f; + float repeattime = 0.0f; + m.CurrentSpeed = speed; if (anim == "walk") { CmpPtr cmpUnitMotion(m.Simulation2, m.Entity); @@ -402,29 +408,15 @@ m.CurrentSpeed = speed; } - else if (anim == "melee") - { - speed = 1.f; // speed will be ignored if we have a repeattime - m.CurrentSpeed = 0.f; - - CStr code = "var cmp = Engine.QueryInterface("+CStr::FromUInt(m.Entity)+", IID_Attack); " + - "if (cmp) cmp.GetTimers(cmp.GetBestAttack()).repeat; else 0;"; - m.Simulation2.GetScriptInterface().Eval(code.c_str(), repeattime); - } - else - { - // Play the animation at normal speed, but movement speed is zero - speed = 1.f; - m.CurrentSpeed = 0.f; - } + else if (anim == "attack_melee") + repeattime = GetRepeatTime("Melee"); + else if (anim == "attack_ranged") + repeattime = GetRepeatTime("Ranged"); + else if (anim == "attack_slaughter") + repeattime = GetRepeatTime("Slaugther"); + else if (anim == "attack_capture") + repeattime = GetRepeatTime("Capture"); - CStr sound; - if (anim == "melee") - sound = "attack"; - else if (anim == "build") - sound = "build"; - else if (anim.Find("gather_") == 0) - sound = anim; CmpPtr cmpVisual(m.Simulation2, m.Entity); if (cmpVisual) @@ -496,6 +488,15 @@ g_ProfileViewer.ShowTable(""); } +float ActorViewer::GetRepeatTime(std::string type) const +{ + CmpPtr cmpAttack(m.Simulation2, m.Entity); + if (cmpAttack) + return cmpAttack->GetRepeatTime(type); + + return 0.0f; +} + void ActorViewer::Render() { m.Terrain.MakeDirty(RENDERDATA_UPDATE_COLOR);