Index: binaries/data/mods/public/art/actors/props/units/weapons/rock_explosion.xml =================================================================== --- binaries/data/mods/public/art/actors/props/units/weapons/rock_explosion.xml +++ binaries/data/mods/public/art/actors/props/units/weapons/rock_explosion.xml @@ -0,0 +1,15 @@ + + + + + + props/onager_projectile.dae + + + + + + + + + Index: binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_onager.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_onager.xml +++ binaries/data/mods/public/simulation/templates/template_unit_mechanical_siege_onager.xml @@ -1,5 +1,10 @@ + + props/units/weapons/rock_flaming.xml + props/units/weapons/rock_explosion.xml + 0.1 + 0.0 Index: source/simulation2/TypeList.h =================================================================== --- source/simulation2/TypeList.h +++ source/simulation2/TypeList.h @@ -141,6 +141,9 @@ INTERFACE(Position) COMPONENT(Position) // must be before VisualActor +INTERFACE(Projectile) +COMPONENT(Projectile) + INTERFACE(ProjectileManager) COMPONENT(ProjectileManager) Index: source/simulation2/components/CCmpProjectile.cpp =================================================================== --- source/simulation2/components/CCmpProjectile.cpp +++ source/simulation2/components/CCmpProjectile.cpp @@ -0,0 +1,93 @@ +/* Copyright (C) 2017 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 "simulation2/system/Component.h" +#include "ICmpProjectile.h" + +/** +* Basic ICmpProjectile implementation. +*/ +class CCmpProjectile : public ICmpProjectile +{ +private: + std::wstring actor; + std::wstring hitActor; + float hitAnimationTime; + +public: + + static void ClassInit(CComponentManager& componentManager) + { + } + + DEFAULT_COMPONENT_ALLOCATOR(Projectile) + + + static std::string GetSchema() + { + return + "" + "" + "" + "" + "" + "" + "" + "" + "" + ; + } + + virtual void Init(const CParamNode& paramNode) + { + actor = paramNode.GetChild("Actor").ToString(); + hitActor = paramNode.GetChild("HitActor").ToString(); + hitAnimationTime = paramNode.GetChild("HitAnimationTime").ToFixed().ToFloat(); + } + + virtual void Deinit() + { + } + + virtual void Serialize(ISerializer& serialize) + { + } + + virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) + { + } + + virtual std::wstring GetActor() const + { + return actor; + } + + virtual std::wstring GetHitActor() const + { + return hitActor; + } + + virtual float GetHitAnimationTime() const + { + return hitAnimationTime; + } + +}; + +REGISTER_COMPONENT_TYPE(Projectile) Index: source/simulation2/components/CCmpProjectileManager.cpp =================================================================== --- source/simulation2/components/CCmpProjectileManager.cpp +++ source/simulation2/components/CCmpProjectileManager.cpp @@ -26,6 +26,7 @@ #include "ICmpRangeManager.h" #include "ICmpTerrain.h" #include "ICmpVisual.h" +#include "ICmpProjectile.h" #include "simulation2/MessageTypes.h" #include "graphics/Frustum.h" @@ -114,6 +115,9 @@ virtual void RemoveProjectile(uint32_t); + virtual void RenderModel(CModelAbstract& model, CVector3D& position, SceneCollector& collector, const CFrustum& frustum, bool culling, + CmpPtr cmpRangeManager, int player, ICmpRangeManager::CLosQuerier los, bool losRevealAll) const; + private: struct Projectile { @@ -126,6 +130,8 @@ float gravity; bool stopped; uint32_t id; + std::wstring hitName; + float hitAnimationTime; CVector3D position(float t) { @@ -141,8 +147,16 @@ } }; + struct ProjectileHitAnimation { + CUnit* unit; + CVector3D pos; + float time; + }; + std::vector m_Projectiles; + std::vector m_ProjectileHitAnimations; + uint32_t m_ActorSeed; uint32_t m_NextId; @@ -166,25 +180,35 @@ if (!GetSimContext().HasUnitManager()) return currentId; // do nothing if graphics are disabled - CmpPtr cmpSourceVisual(GetSimContext(), source); - if (!cmpSourceVisual) - return currentId; - - std::wstring name = cmpSourceVisual->GetProjectileActor(); - if (name.empty()) - { - // If the actor was actually loaded, complain that it doesn't have a projectile - if (!cmpSourceVisual->GetActorShortName().empty()) - LOGERROR("Unit with actor '%s' launched a projectile but has no actor on 'projectile' attachpoint", utf8_from_wstring(cmpSourceVisual->GetActorShortName())); - return currentId; - } - Projectile projectile; projectile.id = currentId; projectile.time = 0.f; projectile.stopped = false; projectile.gravity = gravity.ToFloat(); + CmpPtr cmpSourceVisual(GetSimContext(), source); + if (!cmpSourceVisual) + return currentId; + + std::wstring name; + CmpPtr cmpProjectile(GetSimContext(), source); + if (cmpProjectile) { + name = cmpProjectile->GetActor(); + projectile.hitName = cmpProjectile->GetHitActor(); + projectile.hitAnimationTime = cmpProjectile->GetHitAnimationTime(); + } + else { + // TODO: remove this fallback to the cpmSourceVisual when all the templates are updated with the projectile property + name = cmpSourceVisual->GetProjectileActor(); + if (name.empty()) + { + // If the actor was actually loaded, complain that it doesn't have a projectile + if (!cmpSourceVisual->GetActorShortName().empty()) + LOGERROR("Unit with actor '%s' launched a projectile but has no actor on 'projectile' attachpoint", utf8_from_wstring(cmpSourceVisual->GetActorShortName())); + return currentId; + } + } + projectile.origin = cmpSourceVisual->GetProjectileLaunchPoint(); if (!projectile.origin) { @@ -286,7 +310,26 @@ // Those hitting the ground stay for a while, because it looks pretty. if (m_Projectiles[i].stopped) { - if (m_Projectiles[i].time - m_Projectiles[i].timeHit > PROJECTILE_DECAY_TIME) + if (!m_Projectiles[i].hitName.empty()) + { + ProjectileHitAnimation projectileHitAnimation; + CMatrix3D transform; + CQuaternion quat; + quat.ToMatrix(transform); + transform.Translate(m_Projectiles[i].pos); + + std::set selections; + CUnit* unit = GetSimContext().GetUnitManager().CreateUnit(m_Projectiles[i].hitName, m_ActorSeed++, selections); + unit->GetModel().SetTransform(transform); + + projectileHitAnimation.unit = unit; + projectileHitAnimation.time = m_Projectiles[i].hitAnimationTime; + projectileHitAnimation.pos = m_Projectiles[i].pos; + m_ProjectileHitAnimations.push_back(projectileHitAnimation); + } + + // TODO: rethink this hardcoded decay time and animation as part of #1912 + //if (m_Projectiles[i].time - m_Projectiles[i].timeHit > PROJECTILE_DECAY_TIME) { // Delete in-place by swapping with the last in the list std::swap(m_Projectiles[i], m_Projectiles.back()); @@ -298,6 +341,21 @@ ++i; } + + for (size_t i = 0; i < m_ProjectileHitAnimations.size();) + { + if (m_ProjectileHitAnimations[i].time > 0) + { + m_ProjectileHitAnimations[i].time -= frameTime; + ++i; + } + else + { + std::swap(m_ProjectileHitAnimations[i], m_ProjectileHitAnimations.back()); + GetSimContext().GetUnitManager().DeleteUnit(m_ProjectileHitAnimations.back().unit); + m_ProjectileHitAnimations.pop_back(); + } + } } void CCmpProjectileManager::RemoveProjectile(uint32_t id) @@ -316,6 +374,24 @@ } } +void CCmpProjectileManager::RenderModel(CModelAbstract& model, CVector3D& position, SceneCollector& collector, const CFrustum& frustum, bool culling, + CmpPtr cmpRangeManager, int player, ICmpRangeManager::CLosQuerier los, bool losRevealAll) const { + // Don't display objects outside the visible area + ssize_t posi = (ssize_t)(0.5f + position.X / TERRAIN_TILE_SIZE); + ssize_t posj = (ssize_t)(0.5f + position.Z / TERRAIN_TILE_SIZE); + if (!losRevealAll && !los.IsVisible(posi, posj)) + return; + + model.ValidatePosition(); + + if (culling && !frustum.IsBoxVisible(model.GetWorldBoundsRec())) + return; + + // TODO: do something about LOS (copy from CCmpVisualActor) + + collector.SubmitRecursive(&model); +} + void CCmpProjectileManager::RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling) const { CmpPtr cmpRangeManager(GetSystemEntity()); @@ -323,23 +399,31 @@ ICmpRangeManager::CLosQuerier los(cmpRangeManager->GetLosQuerier(player)); bool losRevealAll = cmpRangeManager->GetLosRevealAll(player); - for (size_t i = 0; i < m_Projectiles.size(); ++i) + for (Projectile projectile : m_Projectiles) { - // Don't display projectiles outside the visible area - ssize_t posi = (ssize_t)(0.5f + m_Projectiles[i].pos.X / TERRAIN_TILE_SIZE); - ssize_t posj = (ssize_t)(0.5f + m_Projectiles[i].pos.Z / TERRAIN_TILE_SIZE); - if (!losRevealAll && !los.IsVisible(posi, posj)) - continue; - - CModelAbstract& model = m_Projectiles[i].unit->GetModel(); - - model.ValidatePosition(); - - if (culling && !frustum.IsBoxVisible(model.GetWorldBoundsRec())) - continue; - - // TODO: do something about LOS (copy from CCmpVisualActor) - - collector.SubmitRecursive(&model); + RenderModel( + projectile.unit->GetModel(), + projectile.pos, + collector, + frustum, + culling, + cmpRangeManager, + player, + los, + losRevealAll); + } + + for (ProjectileHitAnimation projectileHitAnimation : m_ProjectileHitAnimations) + { + RenderModel( + projectileHitAnimation.unit->GetModel(), + projectileHitAnimation.pos, + collector, + frustum, + culling, + cmpRangeManager, + player, + los, + losRevealAll); } } Index: source/simulation2/components/ICmpProjectile.h =================================================================== --- source/simulation2/components/ICmpProjectile.h +++ source/simulation2/components/ICmpProjectile.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2017 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_ICMPPROJECTILE +#define INCLUDED_ICMPPROJECTILE + +#include "simulation2/system/Interface.h" + +/** +* Provides the actor information for projectile and projectile hit animations. +*/ +class ICmpProjectile : public IComponent +{ +public: + /** + * Returns the actor name + */ + virtual std::wstring GetActor() const = 0; + + /** + * Returns the hit actor name + */ + virtual std::wstring GetHitActor() const = 0; + + /** + * Returns the hit animation length + */ + virtual float GetHitAnimationTime() const = 0; + + DECLARE_INTERFACE_TYPE(Projectile) +}; + +#endif // INCLUDED_ICMPPROJECTILE Index: source/simulation2/components/ICmpProjectile.cpp =================================================================== --- source/simulation2/components/ICmpProjectile.cpp +++ source/simulation2/components/ICmpProjectile.cpp @@ -0,0 +1,25 @@ +/* Copyright (C) 2017 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 "ICmpProjectile.h" + +#include "simulation2/system/InterfaceScripted.h" + +BEGIN_INTERFACE_WRAPPER(Projectile) +END_INTERFACE_WRAPPER(Projectile)