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)