/* Copyright (C) 2013 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 "ICmpMinimap.h" #include "simulation2/components/ICmpPlayerManager.h" #include "simulation2/components/ICmpPlayer.h" #include "simulation2/components/ICmpOwnership.h" #include "simulation2/MessageTypes.h" #include "ps/Shapes.h" class CCmpMinimap : public ICmpMinimap { public: static void ClassInit(CComponentManager& componentManager) { componentManager.SubscribeToMessageType(MT_PositionChanged); componentManager.SubscribeToMessageType(MT_OwnershipChanged); componentManager.SubscribeToMessageType(MT_MinimapPing); } DEFAULT_COMPONENT_ALLOCATOR(Minimap) // Template state: bool m_UsePlayerColor; u8 m_R, m_G, m_B; // static template state if m_UsePlayerColor false; dynamic state if true // Dynamic state: bool m_Active; entity_pos_t m_X, m_Z; // cache the latest position for more efficient rendering; only valid when m_Active true // Not serialized (based on renderer timing): // TODO: eventually ping state should be serialized and tied into simulation time, but currently lag causes too many problems double m_PingEndTime; bool m_IsPinging; static std::string GetSchema() { return "" "" "food" "wood" "stone" "metal" "structure" "settlement" "unit" "support" "hero" "" "" "" "" "" "0255" "" "" "0255" "" "" "0255" "" "" ""; } virtual void Init(const CParamNode& paramNode) { m_Active = true; m_IsPinging = false; m_PingEndTime = 0.0; const CParamNode& color = paramNode.GetChild("Color"); if (color.IsOk()) { m_UsePlayerColor = false; m_R = (u8)color.GetChild("@r").ToInt(); m_G = (u8)color.GetChild("@g").ToInt(); m_B = (u8)color.GetChild("@b").ToInt(); } else { m_UsePlayerColor = true; // Choose a bogus color which will get replaced once we have an owner m_R = 255; m_G = 0; m_B = 255; } } virtual void Deinit() { } template void SerializeCommon(S& serialize) { if (m_UsePlayerColor) { serialize.NumberU8_Unbounded("r", m_R); serialize.NumberU8_Unbounded("g", m_G); serialize.NumberU8_Unbounded("b", m_B); } serialize.Bool("active", m_Active); if (m_Active) { serialize.NumberFixed_Unbounded("x", m_X); serialize.NumberFixed_Unbounded("z", m_Z); } } virtual void Serialize(ISerializer& serialize) { SerializeCommon(serialize); } virtual void Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) { Init(paramNode); SerializeCommon(deserialize); } virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) { switch (msg.GetType()) { case MT_PositionChanged: { const CMessagePositionChanged& data = static_cast (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_UsePlayerColor) break; const CMessageOwnershipChanged& msgData = static_cast (msg); // If there's no new owner (e.g. the unit is dying) then don't try updating the color if (msgData.to == -1) break; // Find the new player's color CmpPtr cmpPlayerManager(GetSystemEntity()); if (!cmpPlayerManager) break; CmpPtr cmpPlayer(GetSimContext(), cmpPlayerManager->GetPlayerByID(msgData.to)); if (!cmpPlayer) break; CColor color = cmpPlayer->GetColor(); m_R = (u8)(color.r*255.0); m_G = (u8)(color.g*255.0); m_B = (u8)(color.b*255.0); // TODO: probably should avoid using floating-point here break; } case MT_MinimapPing: { CmpPtr cmpOwnership(GetSimContext(), GetEntityId()); if (!cmpOwnership || cmpOwnership->GetOwner() != (player_id_t)GetSimContext().GetCurrentDisplayedPlayer()) break; // This depends on the viewing player, so don't alter the synchronized simulation state m_IsPinging = true; m_PingEndTime = 0.0; break; } } } virtual bool GetRenderData(u8& r, u8& g, u8& b, entity_pos_t& x, entity_pos_t& z) { if (!m_Active) return false; r = m_R; g = m_G; b = m_B; x = m_X; z = m_Z; return true; } virtual bool CheckPing(double currentTime, double pingDuration) { if (!m_Active || !m_IsPinging) return false; // We're currently pinging if (m_PingEndTime == 0.0) m_PingEndTime = currentTime + pingDuration; else if (currentTime > m_PingEndTime) { m_IsPinging = false; m_PingEndTime = 0; } return m_IsPinging; } }; REGISTER_COMPONENT_TYPE(Minimap)