Ticket #921: building-placement-notifications-02222013.patch

File building-placement-notifications-02222013.patch, 28.6 KB (added by historic_bruno, 11 years ago)
  • binaries/data/mods/public/gui/session/input.js

     
    8282    if (!tooltipSet)
    8383        informationTooltip.hidden = true;
    8484   
    85     var wallDragTooltip = getGUIObjectByName("wallDragTooltip");
    86     if (placementSupport.wallDragTooltip)
     85    var placementTooltip = getGUIObjectByName("placementTooltip");
     86    if (placementSupport.tooltipMessage)
    8787    {
    88         wallDragTooltip.caption = placementSupport.wallDragTooltip;
    89         wallDragTooltip.hidden = false;
     88        placementTooltip.caption = placementSupport.tooltipMessage;
     89        placementTooltip.hidden = false;
    9090    }
    9191    else
    9292    {
    93         wallDragTooltip.caption = "";
    94         wallDragTooltip.hidden = true;
     93        placementTooltip.caption = "";
     94        placementTooltip.hidden = true;
    9595    }
    9696}
    9797
     
    105105    {
    106106        if (placementSupport.template && placementSupport.position)
    107107        {
    108             return Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {
     108            var result = Engine.GuiInterfaceCall("SetBuildingPlacementPreview", {
    109109                "template": placementSupport.template,
    110110                "x": placementSupport.position.x,
    111111                "z": placementSupport.position.z,
    112112                "angle": placementSupport.angle,
    113113                "actorSeed": placementSupport.actorSeed
    114114            });
     115
     116            // Show placement info tooltip if invalid position
     117            placementSupport.tooltipMessage = result.success ? "" : result.message;
     118            return result.success;
    115119        }
    116120    }
    117121    else if (placementSupport.mode === "wall")
     
    862866               
    863867                if (result && result.cost)
    864868                {
    865                     placementSupport.wallDragTooltip = getEntityCostTooltip(result);
     869                    placementSupport.tooltipMessage = getEntityCostTooltip(result);
    866870                    var neededResources = Engine.GuiInterfaceCall("GetNeededResources", result.cost);
    867871                    if (neededResources)
    868                         placementSupport.wallDragTooltip += getNeededResourcesTooltip(neededResources);
     872                        placementSupport.tooltipMessage += getNeededResourcesTooltip(neededResources);
    869873                }
    870874               
    871875                break;
     
    892896                    }
    893897                    else
    894898                    {
    895                         placementSupport.wallDragTooltip = "Cannot build wall here!";
     899                        placementSupport.tooltipMessage = "Cannot build wall here!";
    896900                    }
    897901                   
    898902                    updateBuildingPlacementPreview();
  • binaries/data/mods/public/gui/session/placement.js

     
    1313    this.mode = null;
    1414    this.position = null;
    1515    this.template = null;
     16    this.tooltipMessage = "";        // tooltip text to show while the user is placing a building
    1617    this.wallSet = null;             // maps types of wall pieces ("tower", "long", "short", ...) to template names
    1718    this.wallSnapEntities = null;    // list of candidate entities to snap the starting and (!) ending positions to when building walls
    1819    this.wallEndPosition = null;
    1920    this.wallSnapEntitiesIncludeOffscreen = false; // should the next update of the snap candidate list include offscreen towers?
    20     this.wallDragTooltip = null;     // tooltip text while the user is draggin the wall. Used to indicate the current cost to build the wall.
    2121   
    2222    this.SetDefaultAngle();
    2323    this.RandomizeActorSeed();
  • binaries/data/mods/public/gui/session/session.xml

     
    688688    <object name="informationTooltip" type="tooltip" independent="true" style="informationTooltip"/>
    689689
    690690    <!-- ================================  ================================ -->
    691     <!-- Wall-dragging tooltip. Shows the total cost of building a wall while the player is dragging it. -->
     691    <!-- Building placement info tooltip                                    -->
    692692    <!-- ================================  ================================ -->
    693     <object name="wallDragTooltip" type="tooltip" independent="true" style="informationTooltip"/>
     693    <object name="placementTooltip" type="tooltip" independent="true" style="informationTooltip"/>
    694694
    695695    <!-- ================================  ================================ -->
    696696    <!-- START of BOTTOM PANEL -->
  • binaries/data/mods/public/simulation/components/BuildRestrictions.js

     
    7575 */
    7676BuildRestrictions.prototype.CheckPlacement = function()
    7777{
    78     // TODO: Return error code for invalid placement, which can be handled by the UI
     78    var cmpIdentity = Engine.QueryInterface(this.entity, IID_Identity);
     79    var name = cmpIdentity ? cmpIdentity.GetGenericName() : "Building";
    7980
     81    var result = {
     82        "success": false,
     83        "message": name+" cannot be built due to unknown error",
     84    };
     85
     86    // Check whether it's in a visible or fogged region
     87    // tell GetLosVisibility to force RetainInFog because preview entities set this to false,
     88    // which would show them as hidden instead of fogged
     89    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     90    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     91    if (!cmpRangeManager || !cmpOwnership)
     92        return result; // Fail
     93
     94    var explored = (cmpRangeManager.GetLosVisibility(this.entity, cmpOwnership.GetOwner(), true) != "hidden");
     95    if (!explored)
     96    {
     97        result.message = name+" cannot be built in unexplored area";
     98        return result; // Fail
     99    }
     100
    80101    // Check obstructions and terrain passability
    81102    var passClassName = "";
    82103    switch (this.template.PlacementType)
     
    91112    }
    92113
    93114    var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction);
    94     if (!cmpObstruction || !cmpObstruction.CheckFoundation(passClassName))
     115    if (!cmpObstruction)
     116        return result; // Fail
     117
     118    var ret = cmpObstruction.CheckFoundation(passClassName);
     119    if (ret != "success")
    95120    {
    96         return false;   // Fail
     121        switch (ret)
     122        {
     123        case "fail_error":
     124        case "fail_no_obstruction":
     125            error("CheckPlacement: Error returned from CheckFoundation");
     126            break;
     127        case "fail_obstructs_foundation":
     128            result.message = name+" cannot be built on another building or resource";
     129            break;
     130        case "fail_terrain_class":
     131            // TODO: list valid terrain?
     132            result.message = name+" cannot be built on invalid terrain";
     133        }
     134        return result; // Fail
    97135    }
    98    
     136
    99137    // Check territory restrictions
    100138    var cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
    101139    var cmpPlayer = QueryOwnerInterface(this.entity, IID_Player);
    102140    var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
    103141    if (!(cmpTerritoryManager && cmpPlayer && cmpPosition && cmpPosition.IsInWorld()))
    104     {
    105         return false;   // Fail
    106     }
    107    
     142        return result;  // Fail
     143
    108144    var pos = cmpPosition.GetPosition2D();
    109145    var tileOwner = cmpTerritoryManager.GetOwner(pos.x, pos.y);
    110146    var isOwn = (tileOwner == cmpPlayer.GetPlayerID());
     
    112148    var isAlly = !isOwn && cmpPlayer.IsAlly(tileOwner);
    113149    // We count neutral players as enemies, so you can't build in their territory.
    114150    var isEnemy = !isNeutral && (cmpPlayer.IsEnemy(tileOwner) || cmpPlayer.IsNeutral(tileOwner));
    115    
    116     if ((isAlly && !this.HasTerritory("ally"))
    117         || (isOwn && !this.HasTerritory("own"))
    118         || (isNeutral && !this.HasTerritory("neutral"))
    119         || (isEnemy && !this.HasTerritory("enemy")))
     151
     152    var territoryFail = true;
     153    var territoryType = "";
     154    if (isAlly && !this.HasTerritory("ally"))
     155        territoryType = "ally";
     156    else if (isOwn && !this.HasTerritory("own"))
     157        territoryType = "own";
     158    else if (isNeutral && !this.HasTerritory("neutral"))
     159        territoryType = "neutral";
     160    else if (isEnemy && !this.HasTerritory("enemy"))
     161        territoryType = "enemy";
     162    else
     163        territoryFail = false
     164
     165    if (territoryFail)
    120166    {
    121         return false;   // Fail
     167        result.message = name+" cannot be built in "+territoryType+" territory. Valid territories: " + this.GetTerritories().join(", ");
     168        return result;  // Fail
    122169    }
    123    
     170
    124171    // Check special requirements
    125172    if (this.template.Category == "Dock")
    126173    {
     
    130177        //  so it's correct even if the criteria changes for these units
    131178        var cmpFootprint = Engine.QueryInterface(this.entity, IID_Footprint);
    132179        if (!cmpFootprint)
    133         {
    134             return false;   // Fail
    135         }
    136        
     180            return result;  // Fail
     181
    137182        // Get building's footprint
    138183        var shape = cmpFootprint.GetShape();
    139184        var halfSize = 0;
    140185        if (shape.type == "square")
    141         {
    142186            halfSize = shape.depth/2;
    143         }
    144187        else if (shape.type == "circle")
    145         {
    146188            halfSize = shape.radius;
    147         }
    148        
     189
    149190        var cmpTerrain = Engine.QueryInterface(SYSTEM_ENTITY, IID_Terrain);
    150191        var cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);
    151192        if (!cmpTerrain || !cmpWaterManager)
    152         {
    153             return false;   // Fail
    154         }
    155        
     193            return result;  // Fail
     194
    156195        var ang = cmpPosition.GetRotation().y;
    157196        var sz = halfSize * Math.sin(ang);
    158197        var cz = halfSize * Math.cos(ang);
    159198        if ((cmpWaterManager.GetWaterLevel(pos.x + sz, pos.y + cz) - cmpTerrain.GetGroundLevel(pos.x + sz, pos.y + cz)) < 1.0 // front
    160199            || (cmpWaterManager.GetWaterLevel(pos.x - sz, pos.y - cz) - cmpTerrain.GetGroundLevel(pos.x - sz, pos.y - cz)) > 2.0) // back
    161200        {
    162             return false;   // Fail
     201            result.message = name+" must be built on a valid shoreline";
     202            return result;  // Fail
    163203        }
    164204    }
    165    
     205
    166206    // Check distance restriction
    167207    if (this.template.Distance)
    168208    {
     
    189229                }
    190230            }
    191231        }
    192        
    193         if ((this.template.Distance.MinDistance && nearest < this.template.Distance.MinDistance)
    194             || (this.template.Distance.MaxDistance && nearest > this.template.Distance.MaxDistance))
     232
     233        if (this.template.Distance.MinDistance && nearest < +this.template.Distance.MinDistance)
    195234        {
    196             return false;   // Fail
     235            result.message = name+" too close to a "+cmpBuildRestrictions.GetCategory()+", must be at least "+ +this.template.Distance.MinDistance+" meters away";
     236            return result;  // Fail
    197237        }
     238        else if (this.template.Distance.MaxDistance && nearest > +this.template.Distance.MaxDistance)
     239        {
     240            result.message = name+" too far away from a "+cmpBuildRestrictions.GetCategory()+", must be within "+ +this.template.Distance.MaxDistance+" meters";
     241            return result;  // Fail
     242        }
    198243    }
    199    
     244
    200245    // Success
    201     return true;
     246    result.success = true;
     247    result.message = "";
     248    return result;
    202249};
    203250
    204251BuildRestrictions.prototype.GetCategory = function()
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    798798 * cmd.template is the name of the entity template, or "" to disable the preview.
    799799 * cmd.x, cmd.z, cmd.angle give the location.
    800800 *
    801  * Returns true if the placement is okay (everything is valid and the entity is not obstructed by others).
     801 * Returns result object:
     802 *  {
     803 *      "success":  true if the placement is okay (everything is valid and the entity is not obstructed by others)
     804 *      "message":  message to display in UI, if invalid placement
     805 *  }
    802806 */
    803807GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd)
    804808{
     809    var result = {
     810        "success": false,
     811        "message": "",
     812    }
     813
    805814    // See if we're changing template
    806815    if (!this.placementEntity || this.placementEntity[0] != cmd.template)
    807816    {
     
    832841            pos.SetYRotation(cmd.angle);
    833842        }
    834843
    835         // Check whether it's in a visible or fogged region
    836         //  tell GetLosVisibility to force RetainInFog because preview entities set this to false,
    837         //  which would show them as hidden instead of fogged
    838         var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    839         var visible = (cmpRangeManager && cmpRangeManager.GetLosVisibility(ent, player, true) != "hidden");
    840844        var validPlacement = false;
    841 
    842845        var cmpOwnership = Engine.QueryInterface(ent, IID_Ownership);
    843846        cmpOwnership.SetOwner(player);
    844847
    845         if (visible)
    846         {   // Check whether it's obstructed by other entities or invalid terrain
    847             var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions);
    848             if (!cmpBuildRestrictions)
    849                 error("cmpBuildRestrictions not defined");
    850 
    851             validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement());
     848        // Check whether it's obstructed by other entities or invalid terrain
     849        var cmpBuildRestrictions = Engine.QueryInterface(ent, IID_BuildRestrictions);
     850        if (!cmpBuildRestrictions)
     851            error("cmpBuildRestrictions not defined");
     852        else
     853        {
     854            result = cmpBuildRestrictions.CheckPlacement();
     855            validPlacement = result.success;
    852856        }
    853857
    854         var ok = (visible && validPlacement);
    855 
    856858        // Set it to a red shade if this is an invalid location
    857859        var cmpVisual = Engine.QueryInterface(ent, IID_Visual);
    858860        if (cmpVisual)
    859861        {
    860862            if (cmd.actorSeed !== undefined)
    861863                cmpVisual.SetActorSeed(cmd.actorSeed);
    862        
    863             if (!ok)
     864
     865            if (!validPlacement)
    864866                cmpVisual.SetShadingColour(1.4, 0.4, 0.4, 1);
    865867            else
    866868                cmpVisual.SetShadingColour(1, 1, 1, 1);
    867869        }
    868 
    869         return ok;
    870870    }
    871871
    872     return false;
     872    return result;
    873873};
    874874
    875875/**
     
    13171317                continue;
    13181318            }
    13191319           
    1320             validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement());
     1320            // TODO: Handle results of CheckPlacement
     1321            validPlacement = (cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success);
    13211322
    13221323            // If a wall piece has two control groups, it's likely a segment that spans
    13231324            // between two existing towers. To avoid placing a duplicate wall segment,
  • binaries/data/mods/public/simulation/components/Identity.js

     
    133133    return (this.template.SelectionGroupName || "");
    134134};
    135135
     136Identity.prototype.GetGenericName = function()
     137{
     138    return this.template.GenericName;
     139};
     140
    136141Engine.RegisterComponentType(IID_Identity, "Identity", Identity);
  • source/simulation2/components/CCmpFootprint.cpp

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    186186                    CFixedVector3D pos (initialPos.X + s.Multiply(radius), fixed::Zero(), initialPos.Y + c.Multiply(radius));
    187187
    188188                    SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
    189                     if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, spawnedPass))
     189                    if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Z, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
    190190                        return pos; // this position is okay, so return it
    191191                }
    192192            }
     
    241241                        CFixedVector2D pos (center + dir*i);
    242242
    243243                        SkipTagObstructionFilter filter(spawnedTag); // ignore collisions with the spawned entity
    244                         if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass))
     244                        if (cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, spawnedRadius, spawnedPass) == ICmpObstruction::FOUNDATION_CHECK_SUCCESS)
    245245                            return CFixedVector3D(pos.X, fixed::Zero(), pos.Y); // this position is okay, so return it
    246246                    }
    247247                }
  • source/simulation2/components/CCmpObstruction.cpp

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    478478        return m_ControlPersist;
    479479    }
    480480
    481     virtual bool CheckFoundation(std::string className)
     481    virtual EFoundationCheck CheckFoundation(std::string className)
    482482    {
    483483        CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), GetEntityId());
    484484        if (!cmpPosition)
    485             return false; // error
     485            return FOUNDATION_CHECK_FAIL_ERROR; // error
    486486
    487487        if (!cmpPosition->IsInWorld())
    488             return false; // no obstruction
     488            return FOUNDATION_CHECK_FAIL_NO_OBSTRUCTION; // no obstruction
    489489
    490490        CFixedVector2D pos = cmpPosition->GetPosition2D();
    491491
    492492        CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY);
    493493        if (!cmpPathfinder)
    494             return false; // error
     494            return FOUNDATION_CHECK_FAIL_ERROR; // error
    495495
    496496        // required precondition to use SkipControlGroupsRequireFlagObstructionFilter
    497497        if (m_ControlGroup == INVALID_ENTITY)
    498498        {
    499499            LOGERROR(L"[CmpObstruction] Cannot test for foundation obstructions; primary control group must be valid");
    500             return false;
     500            return FOUNDATION_CHECK_FAIL_ERROR;
    501501        }
    502502
    503503        // Get passability class
     
    509509        SkipControlGroupsRequireFlagObstructionFilter filter(m_ControlGroup, m_ControlGroup2,
    510510            ICmpObstructionManager::FLAG_BLOCK_FOUNDATION);
    511511
    512         if (m_Type == STATIC)
    513             return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass);
    514         else if (m_Type == UNIT)
     512        if (m_Type == UNIT)
    515513            return cmpPathfinder->CheckUnitPlacement(filter, pos.X, pos.Y, m_Size0, passClass);
    516         else 
     514        else
    517515            return cmpPathfinder->CheckBuildingPlacement(filter, pos.X, pos.Y, cmpPosition->GetRotation().Y, m_Size0, m_Size1, GetEntityId(), passClass);
    518516    }
    519517
  • source/simulation2/components/CCmpPathfinder.cpp

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    656656    }
    657657}
    658658
    659 bool CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter,
     659ICmpObstruction::EFoundationCheck CCmpPathfinder::CheckUnitPlacement(const IObstructionTestFilter& filter,
    660660    entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass)
    661661{
    662662    // Check unit obstruction
    663663    CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
    664664    if (!cmpObstructionManager)
    665         return false;
     665        return ICmpObstruction::FOUNDATION_CHECK_FAIL_ERROR;
    666666
    667667    if (cmpObstructionManager->TestUnitShape(filter, x, z, r, NULL))
    668         return false;
     668        return ICmpObstruction::FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION;
    669669
    670670    // Test against terrain:
    671671
     
    680680        {
    681681            if (!IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
    682682            {
    683                 return false;
     683                return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS;
    684684            }
    685685        }
    686686    }
    687     return true;
     687    return ICmpObstruction::FOUNDATION_CHECK_SUCCESS;
    688688}
    689689
    690 bool CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter,
     690ICmpObstruction::EFoundationCheck CCmpPathfinder::CheckBuildingPlacement(const IObstructionTestFilter& filter,
    691691    entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w,
    692692    entity_pos_t h, entity_id_t id, pass_class_t passClass)
    693693{
    694694    // Check unit obstruction
    695695    CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
    696696    if (!cmpObstructionManager)
    697         return false;
     697        return ICmpObstruction::FOUNDATION_CHECK_FAIL_ERROR;
    698698
    699699    if (cmpObstructionManager->TestStaticShape(filter, x, z, a, w, h, NULL))
    700         return false;
     700        return ICmpObstruction::FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION;
    701701
    702702    // Test against terrain:
    703703
    704704    UpdateGrid();
    705705
     706    ICmpObstructionManager::ObstructionSquare square;
    706707    CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), id);
    707     if (!cmpObstruction)
    708         return false;
     708    if (!cmpObstruction || !cmpObstruction->GetObstructionSquare(square))
     709        return ICmpObstruction::FOUNDATION_CHECK_FAIL_NO_OBSTRUCTION;
    709710
    710     ICmpObstructionManager::ObstructionSquare square;
    711     if (!cmpObstruction->GetObstructionSquare(square))
    712         return false;
    713 
    714711    // Expand bounds by 1/sqrt(2) tile (multiply by TERRAIN_TILE_SIZE since we want world coordinates)
    715712    entity_pos_t expand = entity_pos_t::FromInt(2).Sqrt().Multiply(entity_pos_t::FromInt(TERRAIN_TILE_SIZE / 2));
    716713    CFixedVector2D halfSize(square.hw + expand, square.hh + expand);
     
    728725            if (Geometry::PointIsInSquare(CFixedVector2D(x - square.x, z - square.z), square.u, square.v, halfSize)
    729726                && !IS_TERRAIN_PASSABLE(m_Grid->get(i,j), passClass))
    730727            {
    731                 return false;
     728                return ICmpObstruction::FOUNDATION_CHECK_FAIL_TERRAIN_CLASS;
    732729            }
    733730        }
    734731    }
    735732
    736     return true;
     733    return ICmpObstruction::FOUNDATION_CHECK_SUCCESS;
    737734}
  • source/simulation2/components/CCmpPathfinder_Common.h

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    260260
    261261    virtual bool CheckMovement(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, pass_class_t passClass);
    262262
    263     virtual bool CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass);
     263    virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass);
    264264
    265     virtual bool 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);
     265    virtual ICmpObstruction::EFoundationCheck 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);
    266266
    267267    virtual void FinishAsyncRequests();
    268268
  • source/simulation2/components/CCmpTemplateManager.cpp

     
    501501    // and safe (i.e. won't do anything that affects the synchronised simulation state), so additions
    502502    // to this list should be carefully considered
    503503    std::set<std::string> permittedComponentTypes;
     504    permittedComponentTypes.insert("Identity");
    504505    permittedComponentTypes.insert("Ownership");
    505506    permittedComponentTypes.insert("Position");
    506507    permittedComponentTypes.insert("VisualActor");
  • source/simulation2/components/ICmpObstruction.cpp

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    2121
    2222#include "simulation2/system/InterfaceScripted.h"
    2323
     24#include "simulation2/system/SimContext.h"
     25
     26std::string ICmpObstruction::CheckFoundation_wrapper(std::string className)
     27{
     28    EFoundationCheck check = CheckFoundation(className);
     29
     30    switch (check)
     31    {
     32    case FOUNDATION_CHECK_SUCCESS:
     33        return "success";
     34    case FOUNDATION_CHECK_FAIL_ERROR:
     35        return "fail_error";
     36    case FOUNDATION_CHECK_FAIL_NO_OBSTRUCTION:
     37        return "fail_no_obstruction";
     38    case FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION:
     39        return "fail_obstructs_foundation";
     40    case FOUNDATION_CHECK_FAIL_TERRAIN_CLASS:
     41        return "fail_terrain_class";
     42    default:
     43        debug_warn(L"Unexpected result from CheckFoundation");
     44        return "";
     45    }
     46}
     47
    2448BEGIN_INTERFACE_WRAPPER(Obstruction)
    2549DEFINE_INTERFACE_METHOD_0("GetUnitRadius", entity_pos_t, ICmpObstruction, GetUnitRadius)
    26 DEFINE_INTERFACE_METHOD_1("CheckFoundation", bool, ICmpObstruction, CheckFoundation, std::string)
     50DEFINE_INTERFACE_METHOD_1("CheckFoundation", std::string, ICmpObstruction, CheckFoundation_wrapper, std::string)
    2751DEFINE_INTERFACE_METHOD_0("CheckDuplicateFoundation", bool, ICmpObstruction, CheckDuplicateFoundation)
    2852DEFINE_INTERFACE_METHOD_2("GetEntityCollisions", std::vector<entity_id_t>, ICmpObstruction, GetEntityCollisions, bool, bool)
    2953DEFINE_INTERFACE_METHOD_1("SetActive", void, ICmpObstruction, SetActive, bool)
  • source/simulation2/components/ICmpObstruction.h

     
    1 /* Copyright (C) 2012 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    3030{
    3131public:
    3232
     33    enum EFoundationCheck {
     34        FOUNDATION_CHECK_SUCCESS,
     35        FOUNDATION_CHECK_FAIL_ERROR,
     36        FOUNDATION_CHECK_FAIL_NO_OBSTRUCTION,
     37        FOUNDATION_CHECK_FAIL_OBSTRUCTS_FOUNDATION,
     38        FOUNDATION_CHECK_FAIL_TERRAIN_CLASS
     39    };
     40
    3341    virtual ICmpObstructionManager::tag_t GetObstruction() = 0;
    3442
    3543    /**
     
    4755     * Test whether this entity is colliding with any obstruction that are set to
    4856     * block the creation of foundations.
    4957     * @param ignoredEntities List of entities to ignore during the test.
    50      * @return true if foundation is valid (not obstructed)
     58     * @return FOUNDATION_CHECK_SUCCESS if check passes, else an EFoundationCheck
     59     *  value describing the type of failure.
    5160     */
    52     virtual bool CheckFoundation(std::string className) = 0;
     61    virtual EFoundationCheck CheckFoundation(std::string className) = 0;
    5362
    5463    /**
     64     * CheckFoundation wrapper for script calls, to return friendly strings instead of an EFoundationCheck.
     65     * @return "success" if check passes, else a string describing the type of failure.
     66     */
     67    virtual std::string CheckFoundation_wrapper(std::string className);
     68
     69    /**
    5570     * Test whether this entity is colliding with any obstructions that share its
    5671     * control groups and block the creation of foundations.
    5772     * @return true if foundation is valid (not obstructed)
  • source/simulation2/components/ICmpPathfinder.h

     
    1 /* Copyright (C) 2011 Wildfire Games.
     1/* Copyright (C) 2013 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    2020
    2121#include "simulation2/system/Interface.h"
    2222
     23#include "simulation2/components/ICmpObstruction.h"
    2324#include "simulation2/helpers/Position.h"
    2425
    2526#include "maths/FixedVector2D.h"
     
    152153    /**
    153154     * Check whether a unit placed here is valid and doesn't hit any obstructions
    154155     * or impassable terrain.
    155      * Returns true if the placement is okay.
     156     * @return ICmpObstruction::FOUNDATION_CHECK_SUCCESS if the placement is okay, else
     157     *  a value describing the type of failure.
    156158     */
    157     virtual bool CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass) = 0;
     159    virtual ICmpObstruction::EFoundationCheck CheckUnitPlacement(const IObstructionTestFilter& filter, entity_pos_t x, entity_pos_t z, entity_pos_t r, pass_class_t passClass) = 0;
    158160
    159161    /**
    160162     * Check whether a building placed here is valid and doesn't hit any obstructions
    161163     * or impassable terrain.
    162      * Returns true if the placement is okay.
     164     * @return ICmpObstruction::FOUNDATION_CHECK_SUCCESS if the placement is okay, else
     165     *  a value describing the type of failure.
    163166     */
    164     virtual bool 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) = 0;
     167    virtual ICmpObstruction::EFoundationCheck 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) = 0;
    165168
    166169    /**
    167170     * Toggle the storage and rendering of debug info.