virtual CFixedVector3D GetPreviousPosition() { if (!m_InWorld) { LOGERROR(L"CCmpPosition::GetPreviousPosition called on entity when IsInWorld is false"); return CFixedVector3D(); } entity_pos_t baseY; if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) baseY = cmpTerrain->GetGroundLevel(m_PrevX, m_PrevZ); if (m_Floating) { CmpPtr<ICmpWaterManager> cmpWaterMan(GetSimContext(), SYSTEM_ENTITY); if (cmpWaterMan) baseY = std::max(baseY, cmpWaterMan->GetWaterLevel(m_PrevX, m_PrevZ)); } } return CFixedVector3D(m_PrevX, baseY + m_YOffset, m_PrevZ); }
virtual std::vector<entity_id_t> GetConstructionCollisions() { std::vector<entity_id_t> ret; CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); if (cmpPosition.null()) return ret; // error if (!cmpPosition->IsInWorld()) return ret; // no obstruction CFixedVector2D pos = cmpPosition->GetPosition2D(); CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (cmpObstructionManager.null()) return ret; // error // Ignore collisions with self, or with non-construction-blocking obstructions SkipTagFlagsObstructionFilter filter(m_Tag, ICmpObstructionManager::FLAG_BLOCK_CONSTRUCTION); if (m_Type == STATIC) cmpObstructionManager->TestStaticShape(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, &ret); else cmpObstructionManager->TestUnitShape(filter, pos.X, pos.Y, m_Size0, &ret); return ret; }
/* * Must be called whenever the size of m_Sprites changes, * to determine whether we need to respond to rendering messages. */ void UpdateMessageSubscriptions() { bool needRender = !m_Sprites.empty(); GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_Interpolate, this, needRender); GetSimContext().GetComponentManager().DynamicSubscriptionNonsync(MT_RenderSubmit, this, needRender); }
virtual bool CheckFoundation(std::string className) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); if (cmpPosition.null()) return false; // error if (!cmpPosition->IsInWorld()) return false; // no obstruction CFixedVector2D pos = cmpPosition->GetPosition2D(); CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY); if (cmpPathfinder.null()) return false; // error // Get passability class ICmpPathfinder::pass_class_t passClass = cmpPathfinder->GetPassabilityClass(className); // Ignore collisions with self, or with non-foundation-blocking obstructions SkipTagFlagsObstructionFilter filter(m_Tag, ICmpObstructionManager::FLAG_BLOCK_FOUNDATION); if (m_Type == STATIC) return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass); else return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Size0, passClass); }
void ConstructShape(float frameOffset) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); if (!cmpPosition) return; if (!cmpPosition->IsInWorld()) return; float x, z, rotY; cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, rotY); CmpPtr<ICmpFootprint> cmpFootprint(GetSimContext(), GetEntityId()); if (!cmpFootprint) { // Default (this probably shouldn't happen) - just render an arbitrary-sized circle SimRender::ConstructCircleOnGround(GetSimContext(), x, z, 2.f, m_Overlay, cmpPosition->IsFloating()); } else { ICmpFootprint::EShape shape; entity_pos_t size0, size1, height; cmpFootprint->GetShape(shape, size0, size1, height); if (shape == ICmpFootprint::SQUARE) SimRender::ConstructSquareOnGround(GetSimContext(), x, z, size0.ToFloat(), size1.ToFloat(), rotY, m_Overlay, cmpPosition->IsFloating()); else SimRender::ConstructCircleOnGround(GetSimContext(), x, z, size0.ToFloat(), m_Overlay, cmpPosition->IsFloating()); } }
ICmpObstruction::EFoundationCheck CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h, entity_id_t id, pass_class_t passClass, bool onlyCenterPoint) { // Check unit obstruction CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (!cmpObstructionManager) return ICmpObstruction::FOUNDATION_CHECK_FAIL_ERROR; if (cmpObstructionManager->TestStaticShape(filter, x, z, a, w, h, NULL)) return ICmpObstruction::FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION; // Test against terrain: UpdateGrid(); ICmpObstructionManager::ObstructionSquare square; CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), id); if (!cmpObstruction || !cmpObstruction->GetObstructionSquare(square)) return ICmpObstruction::FOUNDATION_CHECK_FAIL_NO_OBSTRUCTION; if (onlyCenterPoint) { u16 i, j; NearestTile(x, z, i, j); if (IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS; } // Expand bounds by 1/sqrt(2) tile (multiply by TERRAIN_TILE_SIZE since we want world coordinates) entity_pos_t expand = entity_pos_t::FromInt(2).Sqrt().Multiply(entity_pos_t::FromInt(TERRAIN_TILE_SIZE / 2)); CFixedVector2D halfSize(square.hw + expand, square.hh + expand); CFixedVector2D halfBound = Geometry::GetHalfBoundingBox(square.u, square.v, halfSize); u16 i0, j0, i1, j1; NearestTile(square.x - halfBound.X, square.z - halfBound.Y, i0, j0); NearestTile(square.x + halfBound.X, square.z + halfBound.Y, i1, j1); for (u16 j = j0; j <= j1; ++j) { for (u16 i = i0; i <= i1; ++i) { entity_pos_t x, z; TileCenter(i, j, x, z); if (Geometry::PointIsInSquare(CFixedVector2D(x - square.x, z - square.z), square.u, square.v, halfSize) && !IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) { return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS; } } } return ICmpObstruction::FOUNDATION_CHECK_SUCCESS; }
// Check whether the entity is either a settlement or territory influence; // ignore any others void MakeDirtyIfRelevantEntity(entity_id_t ent) { CmpPtr<ICmpSettlement> cmpSettlement(GetSimContext(), ent); if (cmpSettlement) MakeDirty(); CmpPtr<ICmpTerritoryInfluence> cmpTerritoryInfluence(GetSimContext(), ent); if (cmpTerritoryInfluence) MakeDirty(); }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_PositionChanged: { if (!m_Active) break; const CMessagePositionChanged& data = static_cast<const CMessagePositionChanged&> (msg); if (!data.inWorld && !m_Tag.valid()) break; // nothing needs to change CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (!cmpObstructionManager) break; // error if (data.inWorld && m_Tag.valid()) { cmpObstructionManager->MoveShape(m_Tag, data.x, data.z, data.a); } else if (data.inWorld && !m_Tag.valid()) { // Need to create a new pathfinder shape: if (m_Type == STATIC) m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(), data.x, data.z, data.a, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2); else m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(), data.x, data.z, m_Size0, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup); } else if (!data.inWorld && m_Tag.valid()) { cmpObstructionManager->RemoveShape(m_Tag); m_Tag = tag_t(); } break; } case MT_Destroy: { if (m_Tag.valid()) { CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (!cmpObstructionManager) break; // error cmpObstructionManager->RemoveShape(m_Tag); m_Tag = tag_t(); } break; } } }
virtual void Init(const CParamNode& paramNode) { m_PreviouslyRendered = false; m_Unit = NULL; m_Visibility = ICmpRangeManager::VIS_HIDDEN; m_R = m_G = m_B = fixed::FromInt(1); if (!GetSimContext().HasUnitManager()) return; // do nothing further if graphics are disabled // TODO: we should do some fancy animation of under-construction buildings rising from the ground, // but for now we'll just use the foundation actor and ignore the normal one if (paramNode.GetChild("Foundation").IsOk() && paramNode.GetChild("FoundationActor").IsOk()) m_ActorName = paramNode.GetChild("FoundationActor").ToString(); else m_ActorName = paramNode.GetChild("Actor").ToString(); std::set<CStr> selections; m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections); if (m_Unit) { CModelAbstract& model = m_Unit->GetModel(); if (model.ToCModel()) { u32 modelFlags = 0; if (paramNode.GetChild("SilhouetteDisplay").ToBool()) modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY; if (paramNode.GetChild("SilhouetteOccluder").ToBool()) modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER; CmpPtr<ICmpVision> cmpVision(GetSimContext(), GetEntityId()); if (cmpVision && cmpVision->GetAlwaysVisible()) modelFlags |= MODELFLAG_IGNORE_LOS; model.ToCModel()->AddFlagsRec(modelFlags); } // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just // initialize the selection shape descriptor on-demand. InitSelectionShapeDescriptor(model, paramNode); m_Unit->SetID(GetEntityId()); } SelectAnimation("idle", false, fixed::FromInt(1), L""); }
virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating) { if (!m_InWorld) { LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); CMatrix3D m; m.SetIdentity(); return m; } float x, z, rotY; GetInterpolatedPosition2D(frameOffset, x, z, rotY); float baseY = 0; if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) baseY = cmpTerrain->GetExactGroundLevel(x, z); if (m_Floating || forceFloating) { CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); if (cmpWaterManager) baseY = std::max(baseY, cmpWaterManager->GetExactWaterLevel(x, z)); } } float y = baseY + m_YOffset.ToFloat(); // TODO: do something with m_AnchorType CMatrix3D m; CMatrix3D mXZ; float Cos = cosf(rotY); float Sin = sinf(rotY); m.SetIdentity(); m._11 = -Cos; m._13 = -Sin; m._31 = Sin; m._33 = -Cos; mXZ.SetIdentity(); mXZ.SetXRotation(m_RotX.ToFloat()); mXZ.RotateZ(m_RotZ.ToFloat()); // TODO: is this all done in the correct order? mXZ = m * mXZ; mXZ.Translate(CVector3D(x, y, z)); return mXZ; }
void CCmpPathfinder::ComputeTerrainPassabilityGrid(const Grid<u16>& shoreGrid) { PROFILE3("terrain passability"); CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); CTerrain& terrain = GetSimContext().GetTerrain(); // Compute initial terrain-dependent passability for (int j = 0; j < m_MapSize * Pathfinding::NAVCELLS_PER_TILE; ++j) { for (int i = 0; i < m_MapSize * Pathfinding::NAVCELLS_PER_TILE; ++i) { // World-space coordinates for this navcell fixed x, z; Pathfinding::NavcellCenter(i, j, x, z); // Terrain-tile coordinates for this navcell int itile = i / Pathfinding::NAVCELLS_PER_TILE; int jtile = j / Pathfinding::NAVCELLS_PER_TILE; // Gather all the data potentially needed to determine passability: fixed height = terrain.GetExactGroundLevelFixed(x, z); fixed water; if (cmpWaterManager) water = cmpWaterManager->GetWaterLevel(x, z); fixed depth = water - height; //fixed slope = terrain.GetExactSlopeFixed(x, z); // Exact slopes give kind of weird output, so just use rough tile-based slopes fixed slope = terrain.GetSlopeFixed(itile, jtile); // Get world-space coordinates from shoreGrid (which uses terrain tiles) fixed shoredist = fixed::FromInt(shoreGrid.get(itile, jtile)).MultiplyClamp(TERRAIN_TILE_SIZE); // Compute the passability for every class for this cell: NavcellData t = 0; for (PathfinderPassability& passability : m_PassClasses) { if (!passability.IsPassable(depth, slope, shoredist)) t |= passability.m_Mask; } m_Grid->set(i, j, t); } } }
virtual void PlaySoundGroup(std::wstring name, entity_id_t source) { #if CONFIG2_AUDIO // Make sure the sound group is loaded CSoundGroup* group; if (m_SoundGroups.find(name) == m_SoundGroups.end()) { group = new CSoundGroup(); if (!group->LoadSoundGroup(L"audio/" + name)) { LOGERROR(L"Failed to load sound group '%ls'", name.c_str()); delete group; group = NULL; } // Cache the sound group (or the null, if it failed) m_SoundGroups[name] = group; } else { group = m_SoundGroups[name]; } // Failed to load group -> do nothing if (!group) return; // Only play the sound if the entity is visible CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY); ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(source, GetSimContext().GetCurrentDisplayedPlayer()); if (vis == ICmpRangeManager::VIS_VISIBLE) { // Find the source's position, if possible // (TODO: we should do something more sensible if there's no position available) CVector3D sourcePos(0, 0, 0); if (source != INVALID_ENTITY) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), source); if (cmpPosition && cmpPosition->IsInWorld()) sourcePos = CVector3D(cmpPosition->GetPosition()); } group->PlayNext(sourcePos); } #else // !CONFIG2_AUDIO UNUSED2(name); UNUSED2(source); #endif // !CONFIG2_AUDIO }
virtual void PostNetworkCommand(JS::HandleValue cmd1) { JSContext* cx = GetSimContext().GetScriptInterface().GetContext(); JSAutoRequest rq(cx); // TODO: This is a workaround because we need to pass a MutableHandle to StringifyJSON. JS::RootedValue cmd(cx, cmd1.get()); PROFILE2_EVENT("post net command"); PROFILE2_ATTR("command: %s", GetSimContext().GetScriptInterface().StringifyJSON(&cmd, false).c_str()); // TODO: would be nicer to not use globals if (g_Game && g_Game->GetTurnManager()) g_Game->GetTurnManager()->PostCommand(cmd); }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_PositionChanged: { const CMessagePositionChanged& data = static_cast<const CMessagePositionChanged&> (msg); if (data.inWorld) { m_Active = true; m_X = data.x; m_Z = data.z; } else { m_Active = false; } break; } case MT_OwnershipChanged: { if (!m_UsePlayerColour) break; const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); // If there's no new owner (e.g. the unit is dying) then don't try updating the colour if (msgData.to == -1) break; // Find the new player's colour CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); if (cmpPlayerManager.null()) break; CmpPtr<ICmpPlayer> cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(msgData.to)); if (cmpPlayer.null()) break; CColor colour = cmpPlayer->GetColour(); m_R = (int)(colour.r*255.0); m_G = (int)(colour.g*255.0); m_B = (int)(colour.b*255.0); break; } } }
virtual void PushLocalCommand(player_id_t player, JS::HandleValue cmd) { JSContext* cx = GetSimContext().GetScriptInterface().GetContext(); JSAutoRequest rq(cx); m_LocalQueue.emplace_back(SimulationCommand(player, cx, cmd)); }
virtual void UpdateTurretPosition() { if (m_TurretParent == INVALID_ENTITY) return; CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); if (!cmpPosition) { LOGERROR("Turret with parent without position component"); return; } if (!cmpPosition->IsInWorld()) MoveOutOfWorld(); else { CFixedVector2D rotatedPosition = CFixedVector2D(m_TurretPosition.X, m_TurretPosition.Z); rotatedPosition = rotatedPosition.Rotate(cmpPosition->GetRotation().Y); CFixedVector2D rootPosition = cmpPosition->GetPosition2D(); entity_pos_t x = rootPosition.X + rotatedPosition.X; entity_pos_t z = rootPosition.Y + rotatedPosition.Y; if (!m_InWorld || m_X != x || m_Z != z) MoveTo(x, z); entity_pos_t y = cmpPosition->GetHeightOffset() + m_TurretPosition.Y; if (!m_InWorld || GetHeightOffset() != y) SetHeightOffset(y); m_InWorld = true; } }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_Interpolate: { const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); if (CRenderer::IsInitialised()) g_Renderer.GetWaterManager()->m_WaterTexTimer += msgData.deltaSimTime; break; } case MT_TerrainChanged: { // Tell the renderer to redraw the map. if (CRenderer::IsInitialised()) { const CMessageTerrainChanged& msgData = static_cast<const CMessageTerrainChanged&> (msg); g_Renderer.GetWaterManager()->m_NeedInfoUpdate = true; g_Renderer.GetWaterManager()->m_updatei0 = msgData.i0; g_Renderer.GetWaterManager()->m_updatej0 = msgData.j0; g_Renderer.GetWaterManager()->m_updatei1 = msgData.i1; g_Renderer.GetWaterManager()->m_updatej1 = msgData.j1; GetSimContext().GetTerrain().MakeDirty(msgData.i0,msgData.j0,msgData.i1,msgData.j1,RENDERDATA_UPDATE_VERTICES); } break; } } }
void RenderSubmit(SceneCollector& collector) { // (This is only called if a > 0) collector.Submit(&m_Overlay); if (ICmpSelectable::ms_EnableDebugOverlays) { // allocate debug overlays on-demand if (!m_DebugBoundingBoxOverlay) m_DebugBoundingBoxOverlay = new SOverlayLine; if (!m_DebugSelectionBoxOverlay) m_DebugSelectionBoxOverlay = new SOverlayLine; CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), GetEntityId()); if (cmpVisual) { SimRender::ConstructBoxOutline(cmpVisual->GetBounds(), *m_DebugBoundingBoxOverlay); m_DebugBoundingBoxOverlay->m_Thickness = 2; m_DebugBoundingBoxOverlay->m_Color = CColor(1.f, 0.f, 0.f, 1.f); SimRender::ConstructBoxOutline(cmpVisual->GetSelectionBox(), *m_DebugSelectionBoxOverlay); m_DebugSelectionBoxOverlay->m_Thickness = 2; m_DebugSelectionBoxOverlay->m_Color = CColor(0.f, 1.f, 0.f, 1.f); collector.Submit(m_DebugBoundingBoxOverlay); collector.Submit(m_DebugSelectionBoxOverlay); } } else { // reclaim debug overlay line memory when no longer debugging (and make sure to set to zero after deletion) if (m_DebugBoundingBoxOverlay) SAFE_DELETE(m_DebugBoundingBoxOverlay); if (m_DebugSelectionBoxOverlay) SAFE_DELETE(m_DebugSelectionBoxOverlay); } }
bool CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass) { // Check unit obstruction CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (cmpObstructionManager.null()) return false; if (cmpObstructionManager->TestUnitShape(filter, x, z, r, NULL)) return false; // Test against terrain: UpdateGrid(); u16 i0, j0, i1, j1; NearestTile(x - r, z - r, i0, j0); NearestTile(x + r, z + r, i1, j1); for (u16 j = j0; j <= j1; ++j) { for (u16 i = i0; i <= i1; ++i) { if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass)) { return false; } } } return true; }
virtual void SetWaterLevel(entity_pos_t h) { m_WaterHeight = h; // Tell the terrain it'll need to recompute its cached render data GetSimContext().GetTerrain().MakeDirty(RENDERDATA_UPDATE_VERTICES); }
virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) { Init(paramNode); u32 oldSeed = GetActorSeed(); SerializeCommon(deserialize); // If we serialized a different seed, reload actor if (oldSeed != GetActorSeed()) ReloadActor(); fixed repeattime = m_AnimSyncRepeatTime; // save because SelectAnimation overwrites it if (m_AnimRunThreshold.IsZero()) SelectAnimation(m_AnimName, m_AnimOnce, m_AnimSpeed, m_SoundGroup); else SelectMovementAnimation(m_AnimRunThreshold); SetAnimationSyncRepeat(repeattime); if (m_Unit) { CmpPtr<ICmpOwnership> cmpOwnership(GetSimContext(), GetEntityId()); if (cmpOwnership) m_Unit->GetModel().SetPlayerID(cmpOwnership->GetOwner()); } }
virtual void SetActive(bool active) { if (active && !m_Active) { m_Active = true; // Construct the obstruction shape CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (!cmpObstructionManager) return; // error CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); if (!cmpPosition) return; // error if (!cmpPosition->IsInWorld()) return; // don't need an obstruction // TODO: code duplication from message handlers CFixedVector2D pos = cmpPosition->GetPosition2D(); if (m_Type == STATIC) m_Tag = cmpObstructionManager->AddStaticShape(GetEntityId(), pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, m_Flags, m_ControlGroup, m_ControlGroup2); else m_Tag = cmpObstructionManager->AddUnitShape(GetEntityId(), pos.X, pos.Y, m_Size0, (flags_t)(m_Flags | (m_Moving ? ICmpObstructionManager::FLAG_MOVING : 0)), m_ControlGroup); } else if (!active && m_Active) { m_Active = false; // Delete the obstruction shape // TODO: code duplication from message handlers if (m_Tag.valid()) { CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (!cmpObstructionManager) return; // error cmpObstructionManager->RemoveShape(m_Tag); m_Tag = tag_t(); } } // else we didn't change the active status }
virtual void Deinit() { if (m_Unit) { GetSimContext().GetUnitManager().DeleteUnit(m_Unit); m_Unit = NULL; } }
virtual void Init(const CParamNode& UNUSED(paramNode)) { m_DisableValidation = false; m_Validator.LoadGrammar(GetSimContext().GetComponentManager().GenerateSchema()); // TODO: handle errors loading the grammar here? // TODO: support hotloading changes to the grammar }
virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_OwnershipChanged: { const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); MakeDirtyIfRelevantEntity(msgData.entity); break; } case MT_PositionChanged: { const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg); MakeDirtyIfRelevantEntity(msgData.entity); break; } case MT_ValueModification: { const CMessageValueModification& msgData = static_cast<const CMessageValueModification&> (msg); if (msgData.component == L"TerritoryInfluence") MakeDirty(); break; } case MT_ObstructionMapShapeChanged: case MT_TerrainChanged: case MT_WaterChanged: { // also recalculate the cost grid to support atlas changes SAFE_DELETE(m_CostGrid); MakeDirty(); break; } case MT_Update: { if (m_TriggerEvent) { m_TriggerEvent = false; CMessageTerritoriesChanged msg; GetSimContext().GetComponentManager().BroadcastMessage(msg); } break; } case MT_Interpolate: { const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); Interpolate(msgData.deltaSimTime, msgData.offset); break; } case MT_RenderSubmit: { const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); RenderSubmit(msgData.collector); break; } } }
virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating) { if (!m_InWorld) { LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); CMatrix3D m; m.SetIdentity(); return m; } float x, z, rotY; GetInterpolatedPosition2D(frameOffset, x, z, rotY); float baseY = 0; if (m_RelativeToGround) { CmpPtr<ICmpTerrain> cmpTerrain(GetSimContext(), SYSTEM_ENTITY); if (cmpTerrain) baseY = cmpTerrain->GetExactGroundLevel(x, z); if (m_Floating || forceFloating) { CmpPtr<ICmpWaterManager> cmpWaterManager(GetSimContext(), SYSTEM_ENTITY); if (cmpWaterManager) baseY = std::max(baseY, cmpWaterManager->GetExactWaterLevel(x, z)); } } float y = baseY + m_YOffset.ToFloat(); CMatrix3D m; // linear interpolation is good enough (for RotX/Z). // As you always stay close to zero angle. m.SetXRotation(Interpolate(m_LastInterpolatedRotX, m_InterpolatedRotX, frameOffset)); m.RotateZ(Interpolate(m_LastInterpolatedRotZ, m_InterpolatedRotZ, frameOffset)); m.RotateY(rotY + (float)M_PI); m.Translate(CVector3D(x, y, z)); return m; }
virtual void SetMovingFlag(bool enabled) { m_Moving = enabled; if (m_Tag.valid() && m_Type == UNIT) { CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (cmpObstructionManager) cmpObstructionManager->SetUnitMovingFlag(m_Tag, m_Moving); } }
virtual void SetTurretParent(entity_id_t id, const CFixedVector3D& offset) { if (m_TurretParent != INVALID_ENTITY) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); if (cmpPosition) cmpPosition->GetTurrets()->erase(GetEntityId()); } m_TurretParent = id; m_TurretPosition = offset; if (m_TurretParent != INVALID_ENTITY) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); if (cmpPosition) cmpPosition->GetTurrets()->insert(GetEntityId()); } UpdateTurretPosition(); }
virtual bool GetObstructionSquare(ICmpObstructionManager::ObstructionSquare& out) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId()); if (!cmpPosition) return false; // error CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY); if (!cmpObstructionManager) return false; // error if (!cmpPosition->IsInWorld()) return false; // no obstruction square CFixedVector2D pos = cmpPosition->GetPosition2D(); if (m_Type == STATIC) out = cmpObstructionManager->GetStaticShapeObstruction(pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1); else out = cmpObstructionManager->GetUnitShapeObstruction(pos.X, pos.Y, m_Size0); return true; }
virtual CFixedVector3D GetRotation() { entity_angle_t y = m_RotY; if (m_TurretParent != INVALID_ENTITY) { CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), m_TurretParent); if (cmpPosition) y += cmpPosition->GetRotation().Y; } return CFixedVector3D(m_RotX, y, m_RotZ); }