Index: binaries/data/config/default.cfg =================================================================== --- binaries/data/config/default.cfg +++ binaries/data/config/default.cfg @@ -327,6 +327,7 @@ rotate.ccw = LeftBracket ; Rotate building placement preview anticlockwise snaptoedges = Ctrl ; Modifier to align new structures with nearby existing structure toggledefaultformation = "" ; Switch between null default formation and the last default formation used (defaults to "box") +flare = K ; Modifier to send a flare to your allies ; Overlays showstatusbars = Tab ; Toggle display of status bars devcommands.toggle = "Alt+D" ; Toggle developer commands panel Index: binaries/data/mods/public/art/textures/cursors/action-flare.txt =================================================================== --- /dev/null +++ binaries/data/mods/public/art/textures/cursors/action-flare.txt @@ -0,0 +1 @@ +1 1 Index: binaries/data/mods/public/gui/manual/intro.txt =================================================================== --- binaries/data/mods/public/gui/manual/intro.txt +++ binaries/data/mods/public/gui/manual/intro.txt @@ -114,6 +114,7 @@ hotkey.session.attackmove + Right Click with unit(s) selected – Attack move (by default all enemy units and structures along the way are targeted) hotkey.session.attackmoveUnit + Right Click with unit(s) selected – Attack move, only units along the way are targeted hotkey.session.snaptoedges + Mouse Move near structures – Align the new structure with an existing nearby structure + K + Right Click – Send a flare to your allies [font="sans-bold-14"]Overlays[font="sans-14"] hotkey.session.gui.toggle – Toggle the GUI Index: binaries/data/mods/public/gui/session/input.js =================================================================== --- binaries/data/mods/public/gui/session/input.js +++ binaries/data/mods/public/gui/session/input.js @@ -17,6 +17,7 @@ const ACTION_REPAIR = 2; const ACTION_GUARD = 3; const ACTION_PATROL = 4; +const ACTION_FLARE = 5; var preSelectedAction = ACTION_NONE; const INPUT_NORMAL = 0; @@ -78,6 +79,16 @@ */ var clickedEntity = INVALID_ENTITY; +/** + * Store the last time the flare functionality was used to prevent overusage. + */ +var g_LastFlareTime; + +/** + * The duration in ms for which we disable flaring after each flare to prevent overusage. + */ +const g_FlareCooldown = 1000; + // Same double-click behaviour for hotkey presses. const doublePressTime = 500; var doublePressTimer = 0; @@ -202,6 +213,10 @@ */ function determineAction(x, y, fromMiniMap) { + let r = g_MiniMapPanel.preSelectedActionCheck() || g_MiniMapPanel.hotkeyActionCheck(); + if (r) + return r; + let selection = g_Selection.toList(); if (!selection.length) { @@ -235,7 +250,7 @@ for (let action of g_UnitActionsSortedKeys) if (g_UnitActions[action].preSelectedActionCheck) { - let r = g_UnitActions[action].preSelectedActionCheck(target, selection); + r = g_UnitActions[action].preSelectedActionCheck(target, selection); if (r) return r; } @@ -1223,6 +1238,21 @@ function handleUnitAction(target, action) { + if (action.type == "flare") + { + let now = Date.now(); + if (g_LastFlareTime && now < g_LastFlareTime + g_FlareCooldown) + return false; + + g_LastFlareTime = now; + displayFlare(target, Engine.GetPlayerID()); + Engine.PlayUISound("audio/interface/alarm/alarmally_1.ogg", false); + Engine.PostNetworkCommand({ + "type": "map-flare", + "target": target + }); + return true; + } if (!g_UnitActions[action.type] || !g_UnitActions[action.type].execute) { error("Invalid action.type " + action.type); Index: binaries/data/mods/public/gui/session/messages.js =================================================================== --- binaries/data/mods/public/gui/session/messages.js +++ binaries/data/mods/public/gui/session/messages.js @@ -267,6 +267,17 @@ } global.music.setLocked(notification.lock); + }, + "map-flare": function(notification, player) + { + // Don't display for the player that did the flare because they will see it immediately + if (player != Engine.GetPlayerID() && g_Players[player].isMutualAlly[Engine.GetPlayerID()]) + { + displayFlare(notification.target, player); + + // TODO: Create a new sound and play it here + Engine.PlayUISound("audio/interface/alarm/alarmally_1.ogg", false); + } } }; Index: binaries/data/mods/public/gui/session/minimap/MiniMap.js =================================================================== --- binaries/data/mods/public/gui/session/minimap/MiniMap.js +++ binaries/data/mods/public/gui/session/minimap/MiniMap.js @@ -6,9 +6,10 @@ { constructor() { - Engine.GetGUIObjectByName("minimap").onWorldClick = this.onWorldClick.bind(this); - Engine.GetGUIObjectByName("minimap").onMouseEnter = this.onMouseEnter.bind(this); - Engine.GetGUIObjectByName("minimap").onMouseLeave = this.onMouseLeave.bind(this); + this.miniMap = Engine.GetGUIObjectByName("minimap"); + this.miniMap.onWorldClick = this.onWorldClick.bind(this); + this.miniMap.onMouseEnter = this.onMouseEnter.bind(this); + this.miniMap.onMouseLeave = this.onMouseLeave.bind(this); this.mouseIsOverMiniMap = false; } @@ -64,4 +65,9 @@ { return this.mouseIsOverMiniMap; } + + flare(target, playerID) + { + return this.miniMap.flare([target.x, target.z], g_DiplomacyColors.getPlayerColor(playerID)); + } } Index: binaries/data/mods/public/gui/session/minimap/MiniMap.xml =================================================================== --- binaries/data/mods/public/gui/session/minimap/MiniMap.xml +++ binaries/data/mods/public/gui/session/minimap/MiniMap.xml @@ -33,4 +33,14 @@ tooltip_style="sessionToolTip" hotkey="session.diplomacycolors" /> + + + Index: binaries/data/mods/public/gui/session/minimap/MiniMapFlareButton.js =================================================================== --- /dev/null +++ binaries/data/mods/public/gui/session/minimap/MiniMapFlareButton.js @@ -0,0 +1,50 @@ +/** + * If the button that this class manages is pressed, an idle unit having one of the given classes is selected. + */ +class MiniMapFlareButton +{ + constructor() + { + this.flareButton = Engine.GetGUIObjectByName("flareButton"); + this.flareButton.onPress = this.onPress.bind(this); + registerHotkeyChangeHandler(this.onHotkeyChange.bind(this)); + } + + onHotkeyChange() + { + this.flareButton.tooltip = + colorizeHotkey("%(hotkey)s" + " ", "session.flare") + + translate(this.Tooltip); + } + + onPress() + { + inputState = INPUT_PRESELECTEDACTION; + preSelectedAction = ACTION_FLARE; + } + + getAction(target) + { + return { + "type": "flare", + "cursor": "action-flare", + "target": target + }; + } + + hotkeyActionCheck(target, selection) + { + if (!Engine.HotkeyIsPressed("session.flare")) + return false; + return this.getAction(target); + } + + preSelectedActionCheck(target, selection) + { + if (preSelectedAction != ACTION_FLARE) + return false; + return this.getAction(target); + } +} + +MiniMapFlareButton.prototype.Tooltip = markForTranslation("Send a flare to your allies"); Index: binaries/data/mods/public/gui/session/minimap/MiniMapPanel.js =================================================================== --- binaries/data/mods/public/gui/session/minimap/MiniMapPanel.js +++ binaries/data/mods/public/gui/session/minimap/MiniMapPanel.js @@ -7,9 +7,25 @@ { this.diplomacyColorsButton = new MiniMapDiplomacyColorsButton(diplomacyColors); this.idleWorkerButton = new MiniMapIdleWorkerButton(playerViewControl, idleWorkerClasses); + this.flareButton = new MiniMapFlareButton(); this.miniMap = new MiniMap(); } + hotkeyActionCheck(target, selection) + { + return this.flareButton.hotkeyActionCheck(target, selection); + } + + preSelectedActionCheck(target, selection) + { + return this.flareButton.preSelectedActionCheck(target, selection); + } + + flare(target, playerID) + { + return this.miniMap.flare(target, playerID); + } + isMouseOverMiniMap() { return this.miniMap.isMouseOverMiniMap(); Index: binaries/data/mods/public/gui/session/unit_actions.js =================================================================== --- binaries/data/mods/public/gui/session/unit_actions.js +++ binaries/data/mods/public/gui/session/unit_actions.js @@ -3,7 +3,9 @@ * given a command type. */ var g_TargetMarker = { - "move": "special/target_marker" + "move": "special/target_marker", + // TODO: Add proper marker + "map_flare": "special/target_marker" }; /** @@ -1585,6 +1587,16 @@ }); } +function displayFlare(target, playerID) +{ + Engine.GuiInterfaceCall("AddTargetMarker", { + "template": g_TargetMarker.map_flare, + "x": target.x, + "z": target.z + }); + g_MiniMapPanel.flare(target, playerID); +} + function getCommandInfo(command, entStates) { return entStates && g_EntityCommands[command] && Index: binaries/data/mods/public/shaders/arb/minimap.fp =================================================================== --- binaries/data/mods/public/shaders/arb/minimap.fp +++ binaries/data/mods/public/shaders/arb/minimap.fp @@ -34,6 +34,17 @@ MOV result.color.a, 1.0; #endif +#if MINIMAP_FLARE + PARAM color = program.local[1]; + TEMP texColor; + TEX texColor, fragment.texcoord[0], texture[0], 2D; +#if MINIMAP_MASK + MUL texColor.a, texColor.a, mask.a; +#endif + MUL texColor, texColor, color; + MOV result.color, texColor; +#endif + #if MINIMAP_LINE PARAM color = program.local[1]; MOV result.color, color; Index: binaries/data/mods/public/shaders/arb/minimap.vp =================================================================== --- binaries/data/mods/public/shaders/arb/minimap.vp +++ binaries/data/mods/public/shaders/arb/minimap.vp @@ -19,12 +19,12 @@ DP4 result.position.z, transform[2], position; DP4 result.position.w, transform[3], position; -#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_MASK +#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_MASK || MINIMAP_FLARE TEMP tex; MOV tex, vertex.texcoord; #endif -#if MINIMAP_BASE || MINIMAP_LOS +#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_FLARE DP4 v_tex.x, textureTransform[0], tex; DP4 v_tex.y, textureTransform[1], tex; DP4 v_tex.z, textureTransform[2], tex; Index: binaries/data/mods/public/shaders/arb/minimap.xml =================================================================== --- binaries/data/mods/public/shaders/arb/minimap.xml +++ binaries/data/mods/public/shaders/arb/minimap.xml @@ -3,7 +3,7 @@ - + @@ -12,8 +12,8 @@ - - + + Index: binaries/data/mods/public/shaders/glsl/minimap.fs =================================================================== --- binaries/data/mods/public/shaders/glsl/minimap.fs +++ binaries/data/mods/public/shaders/glsl/minimap.fs @@ -1,6 +1,6 @@ #version 110 -#if MINIMAP_BASE || MINIMAP_LOS +#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_FLARE uniform sampler2D baseTex; varying vec2 v_tex; #endif @@ -14,7 +14,7 @@ varying vec3 color; #endif -#if MINIMAP_LINE +#if MINIMAP_LINE || MINIMAP_FLARE uniform vec4 color; #endif @@ -42,6 +42,10 @@ gl_FragColor = vec4(color, 1.0); #endif + #if MINIMAP_FLARE + gl_FragColor = texture2D(baseTex, v_tex) * color; + #endif + #if MINIMAP_LINE gl_FragColor = color; #endif Index: binaries/data/mods/public/shaders/glsl/minimap.vs =================================================================== --- binaries/data/mods/public/shaders/glsl/minimap.vs +++ binaries/data/mods/public/shaders/glsl/minimap.vs @@ -9,12 +9,12 @@ varying vec2 v_maskUV; #endif -#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_MASK +#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_MASK || MINIMAP_FLARE attribute vec3 a_vertex; attribute vec2 a_uv0; #endif -#if MINIMAP_BASE || MINIMAP_LOS +#if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_FLARE varying vec2 v_tex; #endif @@ -30,7 +30,7 @@ void main() { - #if MINIMAP_BASE || MINIMAP_LOS + #if MINIMAP_BASE || MINIMAP_LOS || MINIMAP_FLARE gl_Position = transform * vec4(a_vertex, 1.0); v_tex = (textureTransform * vec4(a_uv0, 0.0, 1.0)).xy; #endif Index: binaries/data/mods/public/shaders/glsl/minimap.xml =================================================================== --- binaries/data/mods/public/shaders/glsl/minimap.xml +++ binaries/data/mods/public/shaders/glsl/minimap.xml @@ -6,7 +6,7 @@ - + Index: binaries/data/mods/public/simulation/helpers/Commands.js =================================================================== --- binaries/data/mods/public/simulation/helpers/Commands.js +++ binaries/data/mods/public/simulation/helpers/Commands.js @@ -834,6 +834,16 @@ cmpResourceDropsite.SetSharing(cmd.shared); } }, + + "map-flare": function(player, cmd, data) + { + let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); + cmpGuiInterface.PushNotification({ + "type": "map-flare", + "players": [player], + "target": cmd.target + }); + }, }; /** Index: source/gui/GUIObjectTypes.cpp =================================================================== --- source/gui/GUIObjectTypes.cpp +++ source/gui/GUIObjectTypes.cpp @@ -40,6 +40,7 @@ m_ProxyData.insert(JSI_GUIProxy::CreateData(*m_ScriptInterface)); m_ProxyData.insert(JSI_GUIProxy::CreateData(*m_ScriptInterface)); m_ProxyData.insert(JSI_GUIProxy::CreateData(*m_ScriptInterface)); + m_ProxyData.insert(JSI_GUIProxy::CreateData(*m_ScriptInterface)); m_ProxyData.insert(JSI_GUIProxy::CreateData(*m_ScriptInterface)); AddObjectType("button", &CButton::ConstructObject); Index: source/gui/ObjectTypes/CMiniMap.h =================================================================== --- source/gui/ObjectTypes/CMiniMap.h +++ source/gui/ObjectTypes/CMiniMap.h @@ -19,16 +19,19 @@ #define INCLUDED_MINIMAP #include "graphics/ShaderProgramPtr.h" +#include "graphics/Texture.h" #include "gui/ObjectBases/IGUIObject.h" #include "renderer/VertexArray.h" class CCamera; class CMatrix3D; class CTerrain; +class CVector2D; class CMiniMap : public IGUIObject { GUI_OBJECT(CMiniMap) + public: CMiniMap(CGUI& pGUI); virtual ~CMiniMap(); @@ -38,9 +41,20 @@ */ static float GetShallowPassageHeight(); + bool Flare(const CVector2D& pos, const CColor& color); + protected: + struct MapFlare + { + CPos pos; + CColor color; + double time; + }; + virtual void Draw(); + virtual void CreateJSObject(); + /** * @see IGUIObject#HandleMessage() */ @@ -74,9 +88,14 @@ //Whether or not the mouse is currently down bool m_Clicking; + std::deque m_MapFlares; + // minimap texture handles GLuint m_TerrainTexture; + static const int FLARE_TEXTURE_SIZE = 16; + CTexturePtr m_FlareTextures[FLARE_TEXTURE_SIZE]; + // texture data u32* m_TerrainData; @@ -104,10 +123,14 @@ void DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const; - void DrawViewRect(CMatrix3D transform) const; + void DrawViewRect(const CMatrix3D& transform) const; + + void DrawFlare(CShaderProgramPtr shader, const MapFlare& flare, double cur_time) const; void GetMouseWorldCoordinates(float& x, float& z) const; + CPos GetMapCoordinates(float x, float z) const; + float GetAngle() const; VertexIndexArray m_IndexArray; Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -29,10 +29,12 @@ #include "gui/CGUI.h" #include "gui/GUIManager.h" #include "gui/GUIMatrix.h" +#include "gui/Scripting/JSInterface_GUIProxy.h" #include "lib/bits.h" #include "lib/external_libraries/libsdl.h" #include "lib/ogl.h" #include "lib/timer.h" +#include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/Filesystem.h" #include "ps/Game.h" @@ -131,6 +133,12 @@ CFG_GET_VAL("gui.session.minimap.blinkduration", blinkDuration); } m_HalfBlinkDuration = blinkDuration/2; + + for (int i = 0; i < FLARE_TEXTURE_SIZE; ++i) + { + CTextureProperties textureProps(L"art/textures/animated/minimap-flare/frame" + CStr(fmt::sprintf("%02d", i)).FromUTF8() + L".png"); + m_FlareTextures[i] = g_Renderer.GetTextureManager().CreateTexture(textureProps); + } } CMiniMap::~CMiniMap() @@ -221,6 +229,14 @@ z = TERRAIN_TILE_SIZE * m_MapSize * (m_MapScale * (cos(angle)*(py-0.5) + sin(angle)*(px-0.5)) + 0.5); } +CPos CMiniMap::GetMapCoordinates(float x, float z) const +{ + const float width = m_CachedActualSize.GetWidth(); + const float height = m_CachedActualSize.GetHeight(); + const float invTileMapSize = 1.0f / (TERRAIN_TILE_SIZE * m_MapSize); + return CPos(width * x * invTileMapSize, height * z * invTileMapSize); +} + void CMiniMap::SetCameraPos() { CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); @@ -259,14 +275,13 @@ // This sets up and draws the rectangle on the minimap // which represents the view of the camera in the world. -void CMiniMap::DrawViewRect(CMatrix3D transform) const +void CMiniMap::DrawViewRect(const CMatrix3D& transform) const { // Compute the camera frustum intersected with a fixed-height plane. // Use the water height as a fixed base height, which should be the lowest we can go float h = g_Renderer.GetWaterManager()->m_WaterHeight; const float width = m_CachedActualSize.GetWidth(); const float height = m_CachedActualSize.GetHeight(); - const float invTileMapSize = 1.0f / float(TERRAIN_TILE_SIZE * m_MapSize); CVector3D hitPt[4]; hitPt[0] = m_Camera->GetWorldCoordinates(0, g_Renderer.GetHeight(), h); @@ -274,19 +289,16 @@ hitPt[2] = m_Camera->GetWorldCoordinates(g_Renderer.GetWidth(), 0, h); hitPt[3] = m_Camera->GetWorldCoordinates(0, 0, h); - float ViewRect[4][2]; + CPos ViewRect[4]; for (int i = 0; i < 4; ++i) - { // convert to minimap space - ViewRect[i][0] = (width * hitPt[i].X * invTileMapSize); - ViewRect[i][1] = (height * hitPt[i].Z * invTileMapSize); - } + ViewRect[i] = GetMapCoordinates(hitPt[i].X, hitPt[i].Z); float viewVerts[] = { - ViewRect[0][0], -ViewRect[0][1], - ViewRect[1][0], -ViewRect[1][1], - ViewRect[2][0], -ViewRect[2][1], - ViewRect[3][0], -ViewRect[3][1] + ViewRect[0].x, -ViewRect[0].y, + ViewRect[1].x, -ViewRect[1].y, + ViewRect[2].x, -ViewRect[2].y, + ViewRect[3].x, -ViewRect[3].y }; // Enable Scissoring to restrict the rectangle to only the minimap. @@ -318,6 +330,56 @@ glDisable(GL_SCISSOR_TEST); } +void CMiniMap::DrawFlare(CShaderProgramPtr shader, const MapFlare& flare, double cur_time) const +{ + float textureSize = 32.0; + float x = flare.pos.x + textureSize; + float y = -flare.pos.y - textureSize; + float x2 = flare.pos.x - textureSize; + float y2 = -flare.pos.y + textureSize; + float z = 0; + + float quadTex[] = { + 0, 1, + 1, 1, + 1, 0, + + 1, 0, + 0, 0, + 0, 1 + }; + float quadVerts[] = { + x, y, z, + x2, y, z, + x2, y2, z, + + x2, y2, z, + x, y2, z, + x, y, z + }; + + float animationSpeed = 7; + int flooredStep = floor((cur_time - flare.time) * animationSpeed); + + shader->Uniform(str_color, flare.color); + shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, quadTex); + shader->VertexPointer(3, GL_FLOAT, 0, quadVerts); + shader->AssertPointersBound(); + + if (g_Renderer.m_SkipSubmit) + return; + + shader->BindTexture(str_baseTex, m_FlareTextures[flooredStep % FLARE_TEXTURE_SIZE]); + glDrawArrays(GL_TRIANGLES, 0, 6); + + // Draw a second circle if the first has reached half of the animation + if (flooredStep >= FLARE_TEXTURE_SIZE / 2) + { + shader->BindTexture(str_baseTex, m_FlareTextures[(flooredStep - FLARE_TEXTURE_SIZE / 2) % FLARE_TEXTURE_SIZE]); + glDrawArrays(GL_TRIANGLES, 0, 6); + } +} + struct MinimapUnitVertex { // This struct is copyable for convenience and because to move is to copy for primitives. @@ -342,7 +404,6 @@ ++attrPos; } - void CMiniMap::DrawTexture(CShaderProgramPtr shader, float coordMax, float angle, float x, float y, float x2, float y2, float z) const { // Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m) @@ -513,7 +574,7 @@ glDisable(GL_BLEND); - PROFILE_START("minimap units"); + PROFILE_START("minimap units and flares"); CShaderDefines pointDefines; pointDefines.Add(str_MINIMAP_POINT, str_1); @@ -633,7 +694,35 @@ DrawViewRect(unitMatrix); - PROFILE_END("minimap units"); + while (!m_MapFlares.empty() && 6 + m_MapFlares.front().time < cur_time) + m_MapFlares.pop_front(); + + glEnable(GL_BLEND); + + const float width = m_CachedActualSize.GetWidth(); + const float height = m_CachedActualSize.GetHeight(); + glScissor( + m_CachedActualSize.left * g_GuiScale, + g_Renderer.GetHeight() - m_CachedActualSize.bottom * g_GuiScale, + width * g_GuiScale, + height * g_GuiScale); + glEnable(GL_SCISSOR_TEST); + + CShaderDefines flareDefines; + flareDefines.Add(str_MINIMAP_FLARE, str_1); + tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, g_Renderer.GetSystemShaderDefines(), flareDefines); + tech->BeginPass(); + shader = tech->GetShader(); + + shader->Uniform(str_transform, unitMatrix); + shader->Uniform(str_textureTransform, baseTextureTransform); + for (const MapFlare& flare : m_MapFlares) + DrawFlare(shader, flare, cur_time); + tech->EndPass(); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + PROFILE_END("minimap units and flares"); // Reset depth mask glDepthMask(1); @@ -729,6 +818,20 @@ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_MapSize - 1, m_MapSize - 1, GL_RGBA, GL_UNSIGNED_BYTE, m_TerrainData); } +bool CMiniMap::Flare(const CVector2D& pos, const CColor& color) +{ + m_MapFlares.push_back({GetMapCoordinates(pos.X, pos.Y), color, timer_Time()}); + return true; +} + +void CMiniMap::CreateJSObject() +{ + ScriptRequest rq(m_pGUI.GetScriptInterface()); + + using ProxyHandler = JSI_GUIProxy>; + ProxyHandler::CreateJSObject(rq, this, GetGUI().GetProxyData(&ProxyHandler::Singleton()), m_JSObject); +} + void CMiniMap::Destroy() { if (m_TerrainTexture) Index: source/gui/Scripting/JSInterface_CMiniMap.cpp =================================================================== --- /dev/null +++ source/gui/Scripting/JSInterface_CMiniMap.cpp @@ -0,0 +1,68 @@ +/* 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 "JSInterface_GUIProxy_impl.h" + +#include "gui/ObjectTypes/CMiniMap.h" +#include "maths/Vector2D.h" +#include "ps/CLogger.h" + +bool CMiniMap_Flare(JSContext* cx, uint argc, JS::Value* vp) +{ + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); + CMiniMap* obj = static_cast(js::GetProxyPrivate(args.thisv().toObjectOrNull()).toPrivate()); + if (!obj) + return false; + + if (args.length() != 2) + { + LOGERROR("CMiniMap::Flare: Got %d arguments, but expected 2.", args.length()); + return false; + } + + ScriptInterface& scriptInterface = *ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface; + ScriptRequest rq(scriptInterface); + CVector2D pos; + CStr colorStr; + CColor color; + if (!(ScriptInterface::FromJSVal(rq, args.get(0), pos) && + ScriptInterface::FromJSVal(rq, args.get(1), colorStr) && + color.ParseString(colorStr))) + return false; + + bool ret = obj->Flare(pos, color); + args.rval().set(JS::BooleanValue(ret)); + return true; +} + +using GUIObjectType = CMiniMap; + +template <> +void JSI_GUIProxy::CreateFunctions(const ScriptRequest& rq, GUIProxyProps* cache) +{ +#define func(class, func) &JSInterface_GUIProxy::apply_to + cache->setFunction(rq, "toString", func(IGUIObject, toString), 0); + cache->setFunction(rq, "focus", func(IGUIObject, focus), 0); + cache->setFunction(rq, "blur", func(IGUIObject, blur), 0); + cache->setFunction(rq, "getComputedSize", func(IGUIObject, getComputedSize), 0); +#undef func + cache->setFunction(rq, "flare", CMiniMap_Flare, 1); +} + +template class JSI_GUIProxy; Index: source/ps/CStrInternStatic.h =================================================================== --- source/ps/CStrInternStatic.h +++ source/ps/CStrInternStatic.h @@ -39,6 +39,7 @@ X(DISABLE_RECEIVE_SHADOWS) X(IGNORE_LOS) X(MINIMAP_BASE) +X(MINIMAP_FLARE) X(MINIMAP_LINE) X(MINIMAP_LOS) X(MINIMAP_MASK)