Index: binaries/data/mods/public/globalscripts/Templates.js =================================================================== --- binaries/data/mods/public/globalscripts/Templates.js +++ binaries/data/mods/public/globalscripts/Templates.js @@ -452,6 +452,8 @@ "maxTowerOverlap": +template.WallSet.MaxTowerOverlap, "minTowerOverlap": +template.WallSet.MinTowerOverlap }; + if (template.WallSet.TowerSlot) + ret.wallSet.towerSlot = template.WallSet.TowerSlot; if (template.WallSet.Templates.WallEnd) ret.wallSet.templates.end = template.WallSet.Templates.WallEnd; if (template.WallSet.Templates.WallCurves) 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 @@ -191,12 +191,16 @@ true, // require exact template match true // include foundations ); - + placementSupport.wallSlots = null; + if (placementSupport.wallSet.towerSlot) { + placementSupport.wallSlots = Engine.GuiInterfaceCall("getSlots", {"player": g_ViewedPlayer}); + } return Engine.GuiInterfaceCall("SetWallPlacementPreview", { "wallSet": placementSupport.wallSet, "start": placementSupport.position, "end": placementSupport.wallEndPosition, "snapEntities": placementSupport.wallSnapEntities, // snapping entities (towers) for starting a wall segment + "snapSlots": placementSupport.wallSlots }); } } @@ -294,7 +298,7 @@ return false; } - var selection = g_Selection.toList(); + let selection = g_Selection.toList(); Engine.PostNetworkCommand({ "type": "construct", @@ -326,7 +330,7 @@ return false; } - var wallPlacementInfo = updateBuildingPlacementPreview(); // entities making up the wall (wall segments, towers, ...) + let wallPlacementInfo = updateBuildingPlacementPreview(); // entities making up the wall (wall segments, towers, ...) if (!(wallPlacementInfo === false || typeof(wallPlacementInfo) === "object")) { error("Invalid updateBuildingPlacementPreview return value: " + uneval(wallPlacementInfo)); @@ -336,8 +340,8 @@ if (!wallPlacementInfo) return false; - var selection = g_Selection.toList(); - var cmd = { + let selection = g_Selection.toList(); + let cmd = { "type": "construct-wall", "autorepair": true, "autocontinue": true, @@ -347,12 +351,13 @@ "pieces": wallPlacementInfo.pieces, "startSnappedEntity": wallPlacementInfo.startSnappedEnt, "endSnappedEntity": wallPlacementInfo.endSnappedEnt, + "rebuildStartTower": wallPlacementInfo.rebuildStartTower }; // make sure that there's at least one non-tower entity getting built, to prevent silly edge cases where the start and end // point are too close together for the algorithm to place a wall segment inbetween, and only the towers are being previewed // (this is somewhat non-ideal and hardcode-ish) - var hasWallSegment = false; + let hasWallSegment = false; for (let piece of cmd.pieces) { if (piece.template != cmd.wallSet.templates.tower) // TODO: hardcode-ish :( @@ -362,7 +367,7 @@ } } - if (hasWallSegment) + if (hasWallSegment || cmd.rebuildStartTower) { Engine.PostNetworkCommand(cmd); Engine.GuiInterfaceCall("PlaySound", { "name": "order_repair", "entity": selection[0] }); @@ -683,6 +688,7 @@ { placementSupport.Reset(); inputState = INPUT_NORMAL; + Engine.GuiInterfaceCall("SetSlotVisibility", {"player": g_ViewedPlayer, "active": false}); } } else @@ -693,6 +699,8 @@ } else if (ev.button == SDL_BUTTON_RIGHT) { + + Engine.GuiInterfaceCall("SetSlotVisibility", {"player": g_ViewedPlayer, "active": false}); // reset to normal input mode placementSupport.Reset(); updateBuildingPlacementPreview(); @@ -1096,6 +1104,7 @@ else if (ev.button == SDL_BUTTON_RIGHT) { // Cancel building + Engine.GuiInterfaceCall("SetSlotVisibility", {"player": g_ViewedPlayer, "active": false}); placementSupport.Reset(); inputState = INPUT_NORMAL; return true; @@ -1303,12 +1312,13 @@ placementSupport.Reset(); // find out if we're building a wall, and change the entity appropriately if so - var templateData = GetTemplateData(buildTemplate); + let templateData = GetTemplateData(buildTemplate); if (templateData.wallSet) { placementSupport.mode = "wall"; placementSupport.wallSet = templateData.wallSet; inputState = INPUT_BUILDING_PLACEMENT; + Engine.GuiInterfaceCall("SetSlotVisibility", {"player": g_ViewedPlayer, "active": true}); } else { Index: binaries/data/mods/public/simulation/components/Foundation.js =================================================================== --- binaries/data/mods/public/simulation/components/Foundation.js +++ binaries/data/mods/public/simulation/components/Foundation.js @@ -39,6 +39,10 @@ this.maxProgress = 0; this.initialised = true; + + let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); + for (let ent of cmpObstruction.GetEntitiesDeletedUponConstruction()) + Engine.DestroyEntity(ent); }; /** Index: binaries/data/mods/public/simulation/components/GuiInterface.js =================================================================== --- binaries/data/mods/public/simulation/components/GuiInterface.js +++ binaries/data/mods/public/simulation/components/GuiInterface.js @@ -1133,6 +1133,7 @@ "angle": 0, "snapped": false, // did the start position snap to anything? "snappedEnt": INVALID_ENTITY, // if we snapped, was it to an entity? if yes, holds that entity's ID + "snappedSlot": false, }; let end = { @@ -1140,6 +1141,7 @@ "angle": 0, "snapped": false, // did the start position snap to anything? "snappedEnt": INVALID_ENTITY, // if we snapped, was it to an entity? if yes, holds that entity's ID + "snappedSlot": false, }; // -------------------------------------------------------------------------------- @@ -1205,6 +1207,32 @@ if (end.pos && (start.pos.x === end.pos.x && start.pos.z === end.pos.z)) end.pos = undefined; + let startSlotGroup = null; + // Try to snap existing slots + if (cmd.snapSlots) + { + let snapRadius = this.placementWallEntities[wallSet.templates.tower].templateData.wallPiece.length * 0.5; // determined through trial and error + let startSnapData = this.GetFoundationSnapData(player, { + "x": start.pos.x, + "z": start.pos.z, + "template": wallSet.templates.tower, + "snapEntities": cmd.snapSlots, + "snapRadius": snapRadius, + }); + + if (startSnapData) + { + start.pos.x = startSnapData.x; + start.pos.z = startSnapData.z; + start.angle = startSnapData.angle; + start.snapped = true; + start.snappedSlot = true; + + if (startSnapData.ent) + start.snappedEnt = startSnapData.ent; + } + } + // See if we need to snap the start and/or end coordinates to any of our list of snap entities. Note that, despite the list // of snapping candidate entities, it might still snap to e.g. terrain features. Use the "ent" key in the returned snapping // data to determine whether it snapped to an entity (if any), and to which one (see GetFoundationSnapData). @@ -1252,6 +1280,7 @@ } } } + // clear the single-building preview entity (we'll be rolling our own) this.SetBuildingPlacementPreview(player, { "template": "" }); @@ -1287,8 +1316,18 @@ // Additionally, in the situation that we're snapping to merely a foundation of a tower instead of a fully // constructed one, we'll need an extra preview entity for the starting tower, which also must not be obstructed // by the foundation it snaps to. - - if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY) + if (start.snappedSlot) + { + let slotEntityObstruction = Engine.QueryInterface(start.snappedEnt, IID_Obstruction); + previewEntities.unshift({ + "template": wallSet.templates.tower, + "pos": start.pos, + "angle": start.angle, + "controlGroups": [slotEntityObstruction.GetControlGroup()], + "slot": true + }); + } + else if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY) { let startEntObstruction = Engine.QueryInterface(start.snappedEnt, IID_Obstruction); if (previewEntities.length > 0 && startEntObstruction) @@ -1394,8 +1433,12 @@ let allPiecesValid = true; let numRequiredPieces = 0; // number of entities that are required to build the entire wall, regardless of validity - - for (let i = 0; i < previewEntities.length; ++i) + + let lengt = previewEntities.length; + if (previewEntities.length && previewEntities[0].slot) + lengt = 1; + + for (let i = 0; i < lengt; ++i) { let entInfo = previewEntities[i]; @@ -1504,14 +1547,16 @@ // TODO: Handle results of CheckPlacement validPlacement = cmpBuildRestrictions && cmpBuildRestrictions.CheckPlacement().success; - + // If a wall piece has two control groups, it's likely a segment that spans // between two existing towers. To avoid placing a duplicate wall segment, // check for collisions with entities that share both control groups. if (validPlacement && entInfo.controlGroups && entInfo.controlGroups.length > 1) validPlacement = cmpObstruction.CheckDuplicateFoundation(); + + if (entInfo.slot) + validPlacement = true; } - allPiecesValid = allPiecesValid && validPlacement; // The requirement below that all pieces so far have to have valid positions, rather than only this single one, @@ -1568,6 +1613,7 @@ if (start.snappedEnt && start.snappedEnt != INVALID_ENTITY) result.startSnappedEnt = start.snappedEnt; + result.rebuildStartTower = start.snappedSlot; // We should only return that we snapped to an entity if all pieces up until that entity can be validly constructed, // i.e. are included in result.pieces (see docs for the result object). if (end.pos && end.snappedEnt && end.snappedEnt != INVALID_ENTITY && allPiecesValid) @@ -1850,6 +1896,38 @@ Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager).SetDebugOverlay(enabled); }; +GuiInterface.prototype.getSlots = function(player) +{ + let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); + let entities = cmpRangeManager.GetEntitiesByPlayer(player); + let res = []; + for (let ent of entities) { + let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); + if (!cmpIdentity || !cmpIdentity.HasClass("Slot")) + continue; + res.push(ent); + + } + return res; +} + +GuiInterface.prototype.SetSlotVisibility = function(player, data) +{ + let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); + let entities = cmpRangeManager.GetEntitiesByPlayer(player); + let res = []; + for (let ent of entities) { + let cmpIdentity = Engine.QueryInterface(ent, IID_Identity); + if (!cmpIdentity || !cmpIdentity.HasClass("Slot")) + continue; + let cmpVisibility = Engine.QueryInterface(ent, IID_Visibility); + if (cmpVisibility.IsHidden() != !data.active) { + cmpVisibility.SetHidden(!data.active); + cmpRangeManager.RequestVisibilityUpdate(ent); + } + } +} + GuiInterface.prototype.GetTraderNumber = function(player) { let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); @@ -1961,7 +2039,10 @@ "GetTraderNumber": 1, "GetTradingGoods": 1, "IsTemplateModified": 1, - "ResetTemplateModified": 1 + "ResetTemplateModified": 1, + + "getSlots": 1, + "SetSlotVisibility": 1, }; GuiInterface.prototype.ScriptCall = function(player, name, args) Index: binaries/data/mods/public/simulation/components/Health.js =================================================================== --- binaries/data/mods/public/simulation/components/Health.js +++ binaries/data/mods/public/simulation/components/Health.js @@ -47,6 +47,11 @@ "" + "" + "" + + "" + + "" + + "" + + "" + + "" + "" + "" + ""; @@ -208,6 +213,8 @@ if (this.template.SpawnEntityOnDeath) this.CreateDeathSpawnedEntity(); + if (this.template.SpawnSlotOnDeath) + this.CreateSlotOnDeath(); switch (this.template.DeathType) { @@ -314,6 +321,55 @@ return corpse; }; +Health.prototype.CreateSlotOnDeath = function() +{ + // If the unit died while not in the world, don't spawn a death entity for it + // since there's nowhere for it to be placed + let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); + if (!cmpPosition.IsInWorld()) + return INVALID_ENTITY; + + // Create SpawnEntityOnDeath entity + let spawnedEntity = Engine.AddEntity(this.template.SpawnSlotOnDeath); + + // Move to same position + let cmpSpawnedPosition = Engine.QueryInterface(spawnedEntity, IID_Position); + if (cmpSpawnedPosition) { + let pos = cmpPosition.GetPosition(); + let rot = cmpPosition.GetRotation(); + cmpSpawnedPosition.JumpTo(pos.x, pos.z); + cmpSpawnedPosition.SetYRotation(rot.y); + cmpSpawnedPosition.SetXZRotation(rot.x, rot.z); + } else { + error("entity " + this.template.SpawnSlotOnDeath + " has not position"); + } + + let cmpVisual = Engine.QueryInterface(spawnedEntity, IID_Visual); + if (cmpVisual) { + cmpVisual.SetShadingColor(0, 1, 0, 1); + } + + let cmpVisibility = Engine.QueryInterface(spawnedEntity, IID_Visibility); + if (cmpVisibility) { + cmpVisibility.SetActivated(true); + cmpVisibility.SetHidden(true); + } + + let cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); + let cmpSpawnedObstruction = Engine.QueryInterface(spawnedEntity, IID_Obstruction); + if (cmpObstruction && cmpSpawnedObstruction) { + cmpSpawnedObstruction.SetControlGroup(cmpObstruction.GetControlGroup()); + } + + let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); + let cmpSpawnedOwnership = Engine.QueryInterface(spawnedEntity, IID_Ownership); + if (cmpOwnership && cmpSpawnedOwnership) { + cmpSpawnedOwnership.SetOwner(cmpOwnership.GetOwner()); + } + + return spawnedEntity; +} + Health.prototype.CreateDeathSpawnedEntity = function() { // If the unit died while not in the world, don't spawn a death entity for it @@ -337,7 +393,6 @@ let cmpSpawnedOwnership = Engine.QueryInterface(spawnedEntity, IID_Ownership); if (cmpOwnership && cmpSpawnedOwnership) cmpSpawnedOwnership.SetOwner(cmpOwnership.GetOwner()); - return spawnedEntity; }; Index: binaries/data/mods/public/simulation/components/Visibility.js =================================================================== --- binaries/data/mods/public/simulation/components/Visibility.js +++ binaries/data/mods/public/simulation/components/Visibility.js @@ -16,7 +16,8 @@ "" + "" + "" + - ""; + "" + ; Visibility.prototype.Init = function() { @@ -26,6 +27,7 @@ this.preview = this.template.Preview == "true"; this.activated = false; + this.hidden = false; if (this.preview || this.corpse) this.SetActivated(true); @@ -60,6 +62,9 @@ */ Visibility.prototype.GetVisibility = function(player, isVisible, isExplored) { + if (this.hidden) + return VIS_HIDDEN; + if (this.preview) { // For the owner only, mock the "RetainInFog" behavior @@ -80,10 +85,20 @@ // For others, regular displaying return isVisible ? VIS_VISIBLE : VIS_HIDDEN; } - + return VIS_VISIBLE; }; +Visibility.prototype.SetHidden = function(hidden) +{ + this.hidden = hidden; +} + +Visibility.prototype.IsHidden = function() +{ + return this.hidden; +} + Visibility.prototype.GetRetainInFog = function() { return this.retainInFog; Index: binaries/data/mods/public/simulation/components/WallSet.js =================================================================== --- binaries/data/mods/public/simulation/components/WallSet.js +++ binaries/data/mods/public/simulation/components/WallSet.js @@ -4,6 +4,11 @@ "" + "" + "" + + "" + + "" + + "" + + "" + + "" + "" + "" + "" + 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 @@ -1196,13 +1196,14 @@ if (cmd.pieces.length <= 0) return; - if (cmd.startSnappedEntity && cmd.pieces[0].template == cmd.wallSet.templates.tower) + if (!cmd.rebuildStartTower && cmd.startSnappedEntity && cmd.pieces[0].template == cmd.wallSet.templates.tower) { + error(cmd.startSnappedEntity); error("[TryConstructWall] Starting wall piece cannot be a tower (" + cmd.wallSet.templates.tower + ") when snapping at the starting side"); return; } - if (cmd.endSnappedEntity && cmd.pieces[cmd.pieces.length - 1].template == cmd.wallSet.templates.tower) + if (!cmd.rebuildEndTower && cmd.endSnappedEntity && cmd.pieces[cmd.pieces.length - 1].template == cmd.wallSet.templates.tower) { error("[TryConstructWall] Ending wall piece cannot be a tower (" + cmd.wallSet.templates.tower + ") when snapping at the ending side"); return; @@ -1238,14 +1239,14 @@ // first pass; L -> R - var lastTowerIndex = -1; // index of the last tower we've encountered in cmd.pieces - var lastTowerControlGroup = null; // control group of the last tower we've encountered, to assign to non-tower pieces + let lastTowerIndex = -1; // index of the last tower we've encountered in cmd.pieces + let lastTowerControlGroup = null; // control group of the last tower we've encountered, to assign to non-tower pieces // If we're snapping to an existing entity at the starting end, set lastTowerControlGroup to its control group ID so that // the first wall piece can be built while overlapping it. if (cmd.startSnappedEntity) { - var cmpSnappedStartObstruction = Engine.QueryInterface(cmd.startSnappedEntity, IID_Obstruction); + let cmpSnappedStartObstruction = Engine.QueryInterface(cmd.startSnappedEntity, IID_Obstruction); if (!cmpSnappedStartObstruction) { error("[TryConstructWall] Snapped entity on starting side does not have an obstruction component"); @@ -1253,15 +1254,19 @@ } lastTowerControlGroup = cmpSnappedStartObstruction.GetControlGroup(); - //warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup); + // set different control group to delete upon construction + if (cmd.rebuildStartTower) { + cmpSnappedStartObstruction.SetControlGroup(0); + } + // warn("setting lastTowerControlGroup to control group of start snapped entity " + cmd.startSnappedEntity + ": " + lastTowerControlGroup); } - var i = 0; - var queued = cmd.queued; - var pieces = clone(cmd.pieces); + let i = 0; + let queued = cmd.queued; + let pieces = clone(cmd.pieces); for (; i < pieces.length; ++i) { - var piece = pieces[i]; + let piece = pieces[i]; // All wall pieces after the first must be queued. if (i > 0 && !queued) @@ -1278,7 +1283,7 @@ } } - var constructPieceCmd = { + let constructPieceCmd = { "type": "construct", "entities": cmd.entities, "template": piece.template, @@ -1298,12 +1303,12 @@ // while overlapping the snapped entity. if (i == pieces.length - 1 && cmd.endSnappedEntity) { - var cmpEndSnappedObstruction = Engine.QueryInterface(cmd.endSnappedEntity, IID_Obstruction); + let cmpEndSnappedObstruction = Engine.QueryInterface(cmd.endSnappedEntity, IID_Obstruction); if (cmpEndSnappedObstruction) constructPieceCmd.obstructionControlGroup2 = cmpEndSnappedObstruction.GetControlGroup(); } - var pieceEntityId = TryConstructBuilding(player, cmpPlayer, controlAllUnits, constructPieceCmd); + let pieceEntityId = TryConstructBuilding(player, cmpPlayer, controlAllUnits, constructPieceCmd); if (pieceEntityId) { // wall piece foundation successfully built, save the entity ID in the piece info object so we can reference it later @@ -1312,21 +1317,22 @@ // if we built a tower, do the control group dance (see outline above) and update lastTowerControlGroup and lastTowerIndex if (piece.template == cmd.wallSet.templates.tower) { - var cmpTowerObstruction = Engine.QueryInterface(pieceEntityId, IID_Obstruction); - var newTowerControlGroup = pieceEntityId; + let cmpTowerObstruction = Engine.QueryInterface(pieceEntityId, IID_Obstruction); + let newTowerControlGroup = pieceEntityId; if (i > 0) { - //warn(" updating previous wall piece's secondary control group to " + newTowerControlGroup); - var cmpPreviousObstruction = Engine.QueryInterface(pieces[i-1].ent, IID_Obstruction); - // TODO: ensure that cmpPreviousObstruction exists + // warn(" updating previous wall piece's secondary control group to " + newTowerControlGroup); + let cmpPreviousObstruction = Engine.QueryInterface(pieces[i-1].ent, IID_Obstruction); + if(cmpPreviousObstruction) // TODO: ensure that the previous obstruction does not yet have a secondary control group set - cmpPreviousObstruction.SetControlGroup2(newTowerControlGroup); + cmpPreviousObstruction.SetControlGroup2(newTowerControlGroup); } - // TODO: ensure that cmpTowerObstruction exists - cmpTowerObstruction.SetControlGroup(newTowerControlGroup); // give the tower its own unique control group - + // give the tower its unique control group if not rebuildings + if (!cmd.rebuildStartTower && cmpTowerObstruction) { + cmpTowerObstruction.SetControlGroup(newTowerControlGroup); + } lastTowerIndex = i; lastTowerControlGroup = newTowerControlGroup; } @@ -1335,8 +1341,8 @@ break; } - var lastBuiltPieceIndex = i - 1; - var wallComplete = (lastBuiltPieceIndex == pieces.length - 1); + let lastBuiltPieceIndex = i - 1; + let wallComplete = (lastBuiltPieceIndex == pieces.length - 1); // At this point, 'i' is the index of the last wall piece that was successfully constructed (which may or may not be a tower). // Now do the second pass going right-to-left, registering the control groups of the towers to the right of each piece (if any) @@ -1347,7 +1353,7 @@ // only start off with the ending side's snapped tower's control group if we were able to build the entire wall if (cmd.endSnappedEntity && wallComplete) { - var cmpSnappedEndObstruction = Engine.QueryInterface(cmd.endSnappedEntity, IID_Obstruction); + let cmpSnappedEndObstruction = Engine.QueryInterface(cmd.endSnappedEntity, IID_Obstruction); if (!cmpSnappedEndObstruction) { error("[TryConstructWall] Snapped entity on ending side does not have an obstruction component"); @@ -1357,9 +1363,9 @@ lastTowerControlGroup = cmpSnappedEndObstruction.GetControlGroup(); } - for (var j = lastBuiltPieceIndex; j >= 0; --j) + for (let j = lastBuiltPieceIndex; j >= 0; --j) { - var piece = pieces[j]; + let piece = pieces[j]; if (!piece.ent) { @@ -1367,7 +1373,7 @@ continue; } - var cmpPieceObstruction = Engine.QueryInterface(piece.ent, IID_Obstruction); + let cmpPieceObstruction = Engine.QueryInterface(piece.ent, IID_Obstruction); if (!cmpPieceObstruction) { error("[TryConstructWall] Wall piece of template '" + piece.template + "' has no Obstruction component"); @@ -1385,7 +1391,7 @@ // Note that the wall piece may already have its secondary control group set to the tower's entity ID from a control group // dance during the first pass, in which case we should validate it against 'lastTowerControlGroup'. - var existingSecondaryControlGroup = cmpPieceObstruction.GetControlGroup2(); + let existingSecondaryControlGroup = cmpPieceObstruction.GetControlGroup2(); if (existingSecondaryControlGroup == INVALID_ENTITY) { if (lastTowerControlGroup != null && lastTowerControlGroup != INVALID_ENTITY) Index: binaries/data/mods/public/simulation/templates/other/palisades_rocks_tower.xml =================================================================== --- binaries/data/mods/public/simulation/templates/other/palisades_rocks_tower.xml +++ binaries/data/mods/public/simulation/templates/other/palisades_rocks_tower.xml @@ -18,6 +18,7 @@ 0.25 + slots/slot_palisade_tower other/wallset_palisade Index: binaries/data/mods/public/simulation/templates/other/wallset_palisade.xml =================================================================== --- binaries/data/mods/public/simulation/templates/other/wallset_palisade.xml +++ binaries/data/mods/public/simulation/templates/other/wallset_palisade.xml @@ -8,6 +8,7 @@ phase_village + slots/slot_palisade_tower other/palisades_rocks_tower other/palisades_rocks_gate Index: binaries/data/mods/public/simulation/templates/slots/slot_palisade_tower.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/templates/slots/slot_palisade_tower.xml @@ -0,0 +1,6 @@ + + + + props/special/palisade_rocks_tower.xml + + Index: binaries/data/mods/public/simulation/templates/slots/slot_wall_tower.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/templates/slots/slot_wall_tower.xml @@ -0,0 +1,6 @@ + + + + structures/hellenes/wall_tower.xml + + Index: binaries/data/mods/public/simulation/templates/template_building_slot.xml =================================================================== --- /dev/null +++ binaries/data/mods/public/simulation/templates/template_building_slot.xml @@ -0,0 +1,58 @@ + + + + false + false + 0.0 + 0.0 + 0 + + + 0 + upright + false + 0.0 + 6.0 + + + 1 + 0 + 0 + + + false + false + false + true + + + 0 + + + structures/destruct_stone_3x3.xml + false + false + false + + + + Slot + Slot + true + + + + + true + false + false + false + false + false + false + true + + + 1 + + Index: binaries/data/mods/public/simulation/templates/template_structure_defensive_wall_tower.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_structure_defensive_wall_tower.xml +++ binaries/data/mods/public/simulation/templates/template_structure_defensive_wall_tower.xml @@ -54,6 +54,7 @@ 4000 decay|rubble/rubble_stone_wall_tower + slots/slot_wall_tower Wall Turret Index: binaries/data/mods/public/simulation/templates/template_wallset.xml =================================================================== --- binaries/data/mods/public/simulation/templates/template_wallset.xml +++ binaries/data/mods/public/simulation/templates/template_wallset.xml @@ -14,6 +14,7 @@ true + slots/slot_wall_tower 0.85 0.05 Index: source/simulation2/components/CCmpRangeManager.cpp =================================================================== --- source/simulation2/components/CCmpRangeManager.cpp +++ source/simulation2/components/CCmpRangeManager.cpp @@ -1601,15 +1601,6 @@ int i = (pos.X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest(); int j = (pos.Y / (int)TERRAIN_TILE_SIZE).ToInt_RoundToNearest(); - // Reveal flag makes all positioned entities visible and all mirages useless - if (GetLosRevealAll(player)) - { - if (LosIsOffWorld(i, j) || cmpMirage) - return VIS_HIDDEN; - else - return VIS_VISIBLE; - } - // Get visible regions CLosQuerier los(GetSharedLosMask(player), m_LosState, m_TerrainVerticesPerSide); @@ -1630,6 +1621,15 @@ // Else, default behavior + // Reveal flag makes all positioned entities visible and all mirages useless + if (GetLosRevealAll(player)) + { + if (LosIsOffWorld(i, j) || cmpMirage) + return VIS_HIDDEN; + else + return VIS_VISIBLE; + } + if (los.IsVisible(i, j)) { if (cmpMirage)