Ticket #515: TripleClick.2.patch

File TripleClick.2.patch, 12.9 KB (added by evans, 19 months ago)
  • source/gui/scripting/ScriptFunctions.cpp

     
    128128    return EntitySelection::PickEntitiesInRect(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), x0, y0, x1, y1, player); 
    129129} 
    130130 
     131std::vector<entity_id_t> PickSimilarFriendlyEntities(void* UNUSED(cbdata), std::string templateName, bool onScreenOnly) 
     132{ 
     133    return EntitySelection::PickSimilarEntities(*g_Game->GetSimulation2(), *g_Game->GetView()->GetCamera(), templateName, g_Game->GetPlayerID(), onScreenOnly); 
     134} 
     135 
    131136CFixedVector3D GetTerrainAtPoint(void* UNUSED(cbdata), int x, int y) 
    132137{ 
    133138    CVector3D pos = g_Game->GetView()->GetCamera()->GetWorldCoordinates(x, y, true); 
     
    374379    // Entity picking 
    375380    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, &PickEntitiesAtPoint>("PickEntitiesAtPoint"); 
    376381    scriptInterface.RegisterFunction<std::vector<entity_id_t>, int, int, int, int, int, &PickFriendlyEntitiesInRect>("PickFriendlyEntitiesInRect"); 
     382    scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, &PickSimilarFriendlyEntities>("PickSimilarFriendlyEntities"); 
    377383    scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtPoint>("GetTerrainAtPoint"); 
    378384 
    379385    // Network / game setup functions 
  • source/simulation2/helpers/Selection.cpp

     
    2323#include "simulation2/Simulation2.h" 
    2424#include "simulation2/components/ICmpOwnership.h" 
    2525#include "simulation2/components/ICmpRangeManager.h" 
     26#include "simulation2/components/ICmpTemplateManager.h" 
    2627#include "simulation2/components/ICmpSelectable.h" 
    2728#include "simulation2/components/ICmpVisual.h" 
    2829 
     
    130131 
    131132    return hitEnts; 
    132133} 
     134 
     135std::vector<entity_id_t> EntitySelection::PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, std::string templateName, int owner, bool onScreenOnly) 
     136{ 
     137    CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY); 
     138    CmpPtr<ICmpRangeManager> cmpRangeManager(simulation, SYSTEM_ENTITY); 
     139 
     140    std::vector<entity_id_t> hitEnts; 
     141 
     142    std::vector<entity_id_t> entities = cmpTemplateManager->GetEntitiesUsingTemplate(templateName); 
     143    for (std::vector<entity_id_t>::iterator it = entities.begin(); it != entities.end(); ++it) 
     144    { 
     145        entity_id_t ent = *it; 
     146        // Ignore entities not owned by 'owner' 
     147        CmpPtr<ICmpOwnership> cmpOwnership(simulation.GetSimContext(), ent); 
     148        if (cmpOwnership.null() || cmpOwnership->GetOwner() != owner) 
     149            continue; 
     150 
     151        if (onScreenOnly) 
     152        { 
     153            // Find the current interpolated model position. 
     154            // (We just use the centre position and not the whole bounding box, because maybe 
     155            // that's better for users trying to select objects in busy areas) 
     156            CmpPtr<ICmpVisual> cmpVisual(simulation.GetSimContext(), ent); 
     157            if (cmpVisual.null()) 
     158                continue; 
     159            CVector3D position = cmpVisual->GetPosition(); 
     160 
     161            // Ignore entities hidden by LOS (or otherwise hidden, e.g. when not IsInWorld) 
     162            // In this case, the checking is done to avoid selecting garrisoned units 
     163            if (cmpRangeManager->GetLosVisibility(ent, owner) == ICmpRangeManager::VIS_HIDDEN) 
     164                continue; 
     165 
     166            // Reject if it's not on-screen (e.g. it's behind the camera) 
     167            if (!camera.GetFrustum().IsPointVisible(position)) 
     168                continue; 
     169        } 
     170 
     171        hitEnts.push_back(ent); 
     172    } 
     173    return hitEnts; 
     174} 
  • source/simulation2/helpers/Selection.h

     
    4747 */ 
    4848std::vector<entity_id_t> PickEntitiesInRect(CSimulation2& simulation, const CCamera& camera, int sx0, int sy0, int sx1, int sy1, int owner); 
    4949 
     50/** 
     51 * Finds a selectable entity under the given screen coordinate 
     52 * and returns all units with the same visualActors short name, 
     53 * when onScreenOnly is set, only Units on screen are returned. 
     54 */ 
     55std::vector<entity_id_t> PickSimilarEntities(CSimulation2& simulation, const CCamera& camera, std::string templateName, int owner, bool onScreenOnly); 
     56 
    5057} // namespace 
    5158 
    5259#endif // INCLUDED_SELECTION 
  • source/simulation2/components/ICmpTemplateManager.h

     
    8080    virtual std::string GetCurrentTemplateName(entity_id_t ent) = 0; 
    8181 
    8282    /** 
     83     * Returns the list of entities having the specified template 
     84     */ 
     85    virtual std::vector<entity_id_t> GetEntitiesUsingTemplate(std::string templateName) = 0; 
     86    /** 
    8387     * Returns a list of strings that could be validly passed as @c templateName to LoadTemplate. 
    8488     * (This includes "actor|foo" etc names). 
    8589     * Intended for use by the map editor. This is likely to be quite slow. 
  • source/simulation2/components/CCmpTemplateManager.cpp

     
    131131 
    132132    virtual std::vector<std::wstring> FindAllTemplates(); 
    133133 
     134    virtual std::vector<entity_id_t> GetEntitiesUsingTemplate(std::string templateName); 
     135 
    134136private: 
    135137    // Entity template XML validator 
    136138    RelaxNGValidator m_Validator; 
     
    405407    return templates; 
    406408} 
    407409 
     410/** 
     411 * Get the list of entities using the specified template 
     412 */ 
     413std::vector<entity_id_t> CCmpTemplateManager::GetEntitiesUsingTemplate(std::string templateName) 
     414{ 
     415    std::vector<entity_id_t> entities; 
     416    for (std::map<entity_id_t, std::string>::const_iterator it = m_LatestTemplates.begin(); it != m_LatestTemplates.end(); ++it) 
     417    { 
     418        if(it->second == templateName) 
     419            entities.push_back(it->first); 
     420    } 
     421    return entities; 
     422} 
     423 
    408424void CCmpTemplateManager::CopyPreviewSubset(CParamNode& out, const CParamNode& in, bool corpse) 
    409425{ 
    410426    // We only want to include components which are necessary (for the visual previewing of an entity) 
  • source/simulation2/components/ICmpTemplateManager.cpp

     
    2525DEFINE_INTERFACE_METHOD_1("GetTemplate", const CParamNode*, ICmpTemplateManager, GetTemplate, std::string) 
    2626DEFINE_INTERFACE_METHOD_1("GetCurrentTemplateName", std::string, ICmpTemplateManager, GetCurrentTemplateName, entity_id_t) 
    2727DEFINE_INTERFACE_METHOD_0("FindAllTemplates", std::vector<std::wstring>, ICmpTemplateManager, FindAllTemplates) 
     28DEFINE_INTERFACE_METHOD_1("GetEntitiesUsingTemplate", std::vector<entity_id_t>, ICmpTemplateManager, GetEntitiesUsingTemplate, std::string) 
    2829END_INTERFACE_WRAPPER(TemplateManager) 
  • binaries/data/mods/public/gui/session_new/input.js

     
    3838specialKeyStates[SDLK_RALT] = 0; 
    3939specialKeyStates[SDLK_LALT] = 0; 
    4040 
     41//Number of pixels the mouse can move before the action is considered a drag 
     42var maxDragDelta = 4; 
     43 
     44//Time in milliseconds in which a double click is recognized  
     45const doubleClickTime = 500;   
     46var doubleClickTimer = 0; 
     47var doubleClicked = false; 
     48//Store the previously clicked entity - ensure a double/triple click happens on the same entity 
     49var prevClickedEntity = 0; 
    4150// (TODO: maybe we should fix the hotkey system to be usable in this situation, 
    4251// rather than hardcoding Shift into this code?) 
    4352 
     
    125134            var playerOwned = ((targetState.player == entState.player)? true : false); 
    126135            var enemyOwned = ((targetState.player != entState.player)? true : false); 
    127136            var gaiaOwned = ((targetState.player == 0)? true : false); 
    128  
    129137             
    130138            if (targetState.garrisonHolder && playerOwned && ctrlPressed) 
    131139            { 
     
    571579            // If the mouse moved further than a limit, switch to bandbox mode 
    572580            var dragDeltaX = ev.x - dragStart[0]; 
    573581            var dragDeltaY = ev.y - dragStart[1]; 
    574             var maxDragDelta = 4; 
     582             
    575583            if (Math.abs(dragDeltaX) >= maxDragDelta || Math.abs(dragDeltaY) >= maxDragDelta) 
    576584            { 
    577585                inputState = INPUT_BANDBOXING; 
     
    586594            if (ev.button == SDL_BUTTON_LEFT) 
    587595            { 
    588596                var ents = Engine.PickEntitiesAtPoint(ev.x, ev.y); 
     597                var selectedEntity; 
     598                var onScreenOnly; 
     599                 
     600                var now = new Date(); 
    589601                if (!ents.length) 
    590602                { 
    591603                    g_Selection.reset(); 
    592604                    inputState = INPUT_NORMAL; 
    593605                    return true; 
    594606                } 
     607                else 
     608                { 
     609                    selectedEntity = ents[0]; 
     610                } 
     611                if ((now.getTime() - doubleClickTimer < doubleClickTime) && (selectedEntity == prevClickedEntity)) 
     612                { 
     613                    //Double click or triple click has occured 
     614                     
     615                    //Check for double click or triple click 
     616                    if (!doubleClicked) 
     617                    { 
     618                        //If double click hasn't already occured 
     619                        //It's a double click 
     620                        //Select only similar on-screen units 
     621                        onScreenOnly = true; 
     622                        doubleClicked = true; 
     623                    } 
     624                    else 
     625                    { 
     626                        //Double click has already occured 
     627                        //This is a triple click 
     628                        //Select all similar units whether they are on-screen or not 
     629                        onScreenOnly = false; 
     630                    } 
     631                     
     632                    var templateToMatch = Engine.GuiInterfaceCall("GetEntityState", selectedEntity).template; 
     633                     
     634                    ents = Engine.PickSimilarFriendlyEntities(templateToMatch, onScreenOnly); 
     635                } 
     636                else 
     637                { 
     638                    //It's single click right now but it may become double or triple click 
     639                    doubleClicked = false; 
     640                    doubleClickTimer = now.getTime(); 
     641                    prevClickedEntity = selectedEntity; 
     642                } 
    595643 
    596644                // If shift is pressed, don't reset the selection, but allow units to be added to the existing selection 
    597645                var addition = (specialKeyStates[SDLK_RSHIFT] || specialKeyStates[SDLK_LSHIFT]);  
    598646                if (!addition) 
    599                     g_Selection.reset();  
    600  
    601                 g_Selection.addList([ents[0]]); 
     647                    g_Selection.reset(); 
     648                if (doubleClicked) 
     649                { 
     650                    //Either double clicked or triple clicked 
     651                    //So we add all picked units to the selection 
     652                    g_Selection.addList(ents); 
     653                } 
     654                else 
     655                { 
     656                    //We add only the first picked unit to the selection 
     657                    g_Selection.addList([ents[0]]); 
     658                } 
     659                 
    602660                inputState = INPUT_NORMAL; 
    603661                return true; 
    604662            } 
  • binaries/data/mods/public/simulation/components/GarrisonHolder.js

     
    5656}; 
    5757 
    5858/** 
    59  * Garrison a unit inside. 
    60  * Returns true if successful, false if not 
    61  * The timer for AutoHeal is started here 
     59 * Checks if an entity can be allowed to garrison in the building 
     60 * based on it's class 
    6261 */ 
    63 GarrisonHolder.prototype.Garrison = function(entity) 
     62GarrisonHolder.prototype.AllowedToGarrison = function(entity) 
    6463{ 
    65     var entityPopCost = (Engine.QueryInterface(entity, IID_Cost)).GetPopCost(); 
     64    var allowedClasses = this.GetAllowedClassesList(); 
    6665    var entityClasses = (Engine.QueryInterface(entity, IID_Identity)).GetClassesList(); 
    67     var allowedClasses = this.GetAllowedClassesList(); 
    6866    var classNotAllowed = true; 
    69  
    70     if (!this.HasEnoughHealth()) 
    71         return false; 
    72  
    7367    // Check if the unit is allowed to be garrisoned inside the building 
    7468    for each (var allowedClass in allowedClasses) 
    7569    { 
    7670        if (entityClasses.indexOf(allowedClass) != -1) 
    7771        { 
    78             classNotAllowed = false; 
    79             break; 
     72            return true; 
    8073        } 
    8174    } 
    8275 
    83     if (classNotAllowed) 
     76    return false; 
     77}; 
     78 
     79/** 
     80 * Garrison a unit inside. 
     81 * Returns true if successful, false if not 
     82 * The timer for AutoHeal is started here 
     83 */ 
     84GarrisonHolder.prototype.Garrison = function(entity) 
     85{ 
     86    var entityPopCost = (Engine.QueryInterface(entity, IID_Cost)).GetPopCost(); 
     87     
     88     
     89     
     90 
     91    if (!this.HasEnoughHealth()) 
    8492        return false; 
    8593 
     94    if(!this.AllowedToGarrison(entity)) 
     95        return false; 
     96 
    8697    if (this.GetCapacity() < this.spaceOccupied + 1) 
    8798        return false; 
    8899 
  • binaries/data/mods/public/simulation/components/UnitAI.js

     
    11221122    var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); 
    11231123    if (!cmpGarrisonHolder) 
    11241124        return false; 
    1125      
    1126     return true; 
     1125    return cmpGarrisonHolder.AllowedToGarrison(this.entity); 
    11271126}; 
    11281127 
    11291128UnitAI.prototype.CanGather = function(target)